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
 114static struct screen_info smtc_scr_info;
 115
 116static char *mode_option;
 117
 118/* process command line options, get vga parameter */
 119static void __init sm7xx_vga_setup(char *options)
 120{
 121        int i;
 122
 123        if (!options || !*options)
 124                return;
 125
 126        smtc_scr_info.lfb_width = 0;
 127        smtc_scr_info.lfb_height = 0;
 128        smtc_scr_info.lfb_depth = 0;
 129
 130        pr_debug("sm7xx_vga_setup = %s\n", options);
 131
 132        for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) {
 133                if (strstr(options, vesa_mode_table[i].index)) {
 134                        smtc_scr_info.lfb_width  = vesa_mode_table[i].lfb_width;
 135                        smtc_scr_info.lfb_height =
 136                                                vesa_mode_table[i].lfb_height;
 137                        smtc_scr_info.lfb_depth  = vesa_mode_table[i].lfb_depth;
 138                        return;
 139                }
 140        }
 141}
 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
 262                                val = chan_to_field(red, &sfb->fb.var.red);
 263                                val |= chan_to_field(green, &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
 277                                val = chan_to_field(red, &sfb->fb.var.red);
 278                                val |= chan_to_field(green, &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#ifdef __BIG_ENDIAN
 303static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, size_t
 304                                count, loff_t *ppos)
 305{
 306        unsigned long p = *ppos;
 307
 308        u32 *buffer, *dst;
 309        u32 __iomem *src;
 310        int c, i, cnt = 0, err = 0;
 311        unsigned long total_size;
 312
 313        if (!info || !info->screen_base)
 314                return -ENODEV;
 315
 316        if (info->state != FBINFO_STATE_RUNNING)
 317                return -EPERM;
 318
 319        total_size = info->screen_size;
 320
 321        if (total_size == 0)
 322                total_size = info->fix.smem_len;
 323
 324        if (p >= total_size)
 325                return 0;
 326
 327        if (count >= total_size)
 328                count = total_size;
 329
 330        if (count + p > total_size)
 331                count = total_size - p;
 332
 333        buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
 334        if (!buffer)
 335                return -ENOMEM;
 336
 337        src = (u32 __iomem *) (info->screen_base + p);
 338
 339        if (info->fbops->fb_sync)
 340                info->fbops->fb_sync(info);
 341
 342        while (count) {
 343                c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
 344                dst = buffer;
 345                for (i = c >> 2; i--;) {
 346                        *dst = fb_readl(src++);
 347                        *dst =
 348                            (*dst & 0xff00ff00 >> 8) |
 349                            (*dst & 0x00ff00ff << 8);
 350                        dst++;
 351                }
 352                if (c & 3) {
 353                        u8 *dst8 = (u8 *)dst;
 354                        u8 __iomem *src8 = (u8 __iomem *)src;
 355
 356                        for (i = c & 3; i--;) {
 357                                if (i & 1) {
 358                                        *dst8++ = fb_readb(++src8);
 359                                } else {
 360                                        *dst8++ = fb_readb(--src8);
 361                                        src8 += 2;
 362                                }
 363                        }
 364                        src = (u32 __iomem *)src8;
 365                }
 366
 367                if (copy_to_user(buf, buffer, c)) {
 368                        err = -EFAULT;
 369                        break;
 370                }
 371                *ppos += c;
 372                buf += c;
 373                cnt += c;
 374                count -= c;
 375        }
 376
 377        kfree(buffer);
 378
 379        return (err) ? err : cnt;
 380}
 381
 382static ssize_t
 383smtcfb_write(struct fb_info *info, const char __user *buf, size_t count,
 384             loff_t *ppos)
 385{
 386        unsigned long p = *ppos;
 387
 388        u32 *buffer, *src;
 389        u32 __iomem *dst;
 390        int c, i, cnt = 0, err = 0;
 391        unsigned long total_size;
 392
 393        if (!info || !info->screen_base)
 394                return -ENODEV;
 395
 396        if (info->state != FBINFO_STATE_RUNNING)
 397                return -EPERM;
 398
 399        total_size = info->screen_size;
 400
 401        if (total_size == 0)
 402                total_size = info->fix.smem_len;
 403
 404        if (p > total_size)
 405                return -EFBIG;
 406
 407        if (count > total_size) {
 408                err = -EFBIG;
 409                count = total_size;
 410        }
 411
 412        if (count + p > total_size) {
 413                if (!err)
 414                        err = -ENOSPC;
 415
 416                count = total_size - p;
 417        }
 418
 419        buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
 420        if (!buffer)
 421                return -ENOMEM;
 422
 423        dst = (u32 __iomem *) (info->screen_base + p);
 424
 425        if (info->fbops->fb_sync)
 426                info->fbops->fb_sync(info);
 427
 428        while (count) {
 429                c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
 430                src = buffer;
 431
 432                if (copy_from_user(src, buf, c)) {
 433                        err = -EFAULT;
 434                        break;
 435                }
 436
 437                for (i = c >> 2; i--;) {
 438                        fb_writel((*src & 0xff00ff00 >> 8) |
 439                                  (*src & 0x00ff00ff << 8), dst++);
 440                        src++;
 441                }
 442                if (c & 3) {
 443                        u8 *src8 = (u8 *)src;
 444                        u8 __iomem *dst8 = (u8 __iomem *)dst;
 445
 446                        for (i = c & 3; i--;) {
 447                                if (i & 1) {
 448                                        fb_writeb(*src8++, ++dst8);
 449                                } else {
 450                                        fb_writeb(*src8++, --dst8);
 451                                        dst8 += 2;
 452                                }
 453                        }
 454                        dst = (u32 __iomem *)dst8;
 455                }
 456
 457                *ppos += c;
 458                buf += c;
 459                cnt += c;
 460                count -= c;
 461        }
 462
 463        kfree(buffer);
 464
 465        return (cnt) ? cnt : err;
 466}
 467#endif  /* ! __BIG_ENDIAN */
 468
 469static void sm7xx_set_timing(struct smtcfb_info *sfb)
 470{
 471        int i = 0, j = 0;
 472        u32 m_nscreenstride;
 473
 474        dev_dbg(&sfb->pdev->dev,
 475                "sfb->width=%d sfb->height=%d sfb->fb.var.bits_per_pixel=%d sfb->hz=%d\n",
 476                sfb->width, sfb->height, sfb->fb.var.bits_per_pixel, sfb->hz);
 477
 478        for (j = 0; j < numvgamodes; j++) {
 479                if (vgamode[j].mmsizex == sfb->width &&
 480                    vgamode[j].mmsizey == sfb->height &&
 481                    vgamode[j].bpp == sfb->fb.var.bits_per_pixel &&
 482                    vgamode[j].hz == sfb->hz) {
 483                        dev_dbg(&sfb->pdev->dev,
 484                                "vgamode[j].mmsizex=%d vgamode[j].mmSizeY=%d vgamode[j].bpp=%d vgamode[j].hz=%d\n",
 485                                vgamode[j].mmsizex, vgamode[j].mmsizey,
 486                                vgamode[j].bpp, vgamode[j].hz);
 487
 488                        dev_dbg(&sfb->pdev->dev, "vgamode index=%d\n", j);
 489
 490                        smtc_mmiowb(0x0, 0x3c6);
 491
 492                        smtc_seqw(0, 0x1);
 493
 494                        smtc_mmiowb(vgamode[j].init_misc, 0x3c2);
 495
 496                        /* init SEQ register SR00 - SR04 */
 497                        for (i = 0; i < SIZE_SR00_SR04; i++)
 498                                smtc_seqw(i, vgamode[j].init_sr00_sr04[i]);
 499
 500                        /* init SEQ register SR10 - SR24 */
 501                        for (i = 0; i < SIZE_SR10_SR24; i++)
 502                                smtc_seqw(i + 0x10,
 503                                          vgamode[j].init_sr10_sr24[i]);
 504
 505                        /* init SEQ register SR30 - SR75 */
 506                        for (i = 0; i < SIZE_SR30_SR75; i++)
 507                                if ((i + 0x30) != 0x62 &&
 508                                    (i + 0x30) != 0x6a &&
 509                                    (i + 0x30) != 0x6b)
 510                                        smtc_seqw(i + 0x30,
 511                                                  vgamode[j].init_sr30_sr75[i]);
 512
 513                        /* init SEQ register SR80 - SR93 */
 514                        for (i = 0; i < SIZE_SR80_SR93; i++)
 515                                smtc_seqw(i + 0x80,
 516                                          vgamode[j].init_sr80_sr93[i]);
 517
 518                        /* init SEQ register SRA0 - SRAF */
 519                        for (i = 0; i < SIZE_SRA0_SRAF; i++)
 520                                smtc_seqw(i + 0xa0,
 521                                          vgamode[j].init_sra0_sraf[i]);
 522
 523                        /* init Graphic register GR00 - GR08 */
 524                        for (i = 0; i < SIZE_GR00_GR08; i++)
 525                                smtc_grphw(i, vgamode[j].init_gr00_gr08[i]);
 526
 527                        /* init Attribute register AR00 - AR14 */
 528                        for (i = 0; i < SIZE_AR00_AR14; i++)
 529                                smtc_attrw(i, vgamode[j].init_ar00_ar14[i]);
 530
 531                        /* init CRTC register CR00 - CR18 */
 532                        for (i = 0; i < SIZE_CR00_CR18; i++)
 533                                smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]);
 534
 535                        /* init CRTC register CR30 - CR4D */
 536                        for (i = 0; i < SIZE_CR30_CR4D; i++)
 537                                smtc_crtcw(i + 0x30,
 538                                           vgamode[j].init_cr30_cr4d[i]);
 539
 540                        /* init CRTC register CR90 - CRA7 */
 541                        for (i = 0; i < SIZE_CR90_CRA7; i++)
 542                                smtc_crtcw(i + 0x90,
 543                                           vgamode[j].init_cr90_cra7[i]);
 544                }
 545        }
 546        smtc_mmiowb(0x67, 0x3c2);
 547
 548        /* set VPR registers */
 549        writel(0x0, sfb->vp_regs + 0x0C);
 550        writel(0x0, sfb->vp_regs + 0x40);
 551
 552        /* set data width */
 553        m_nscreenstride =
 554                (sfb->width * sfb->fb.var.bits_per_pixel) / 64;
 555        switch (sfb->fb.var.bits_per_pixel) {
 556        case 8:
 557                writel(0x0, sfb->vp_regs + 0x0);
 558                break;
 559        case 16:
 560                writel(0x00020000, sfb->vp_regs + 0x0);
 561                break;
 562        case 24:
 563                writel(0x00040000, sfb->vp_regs + 0x0);
 564                break;
 565        case 32:
 566                writel(0x00030000, sfb->vp_regs + 0x0);
 567                break;
 568        }
 569        writel((u32) (((m_nscreenstride + 2) << 16) | m_nscreenstride),
 570               sfb->vp_regs + 0x10);
 571}
 572
 573static void smtc_set_timing(struct smtcfb_info *sfb)
 574{
 575        switch (sfb->chip_id) {
 576        case 0x710:
 577        case 0x712:
 578        case 0x720:
 579                sm7xx_set_timing(sfb);
 580                break;
 581        }
 582}
 583
 584static void smtcfb_setmode(struct smtcfb_info *sfb)
 585{
 586        switch (sfb->fb.var.bits_per_pixel) {
 587        case 32:
 588                sfb->fb.fix.visual       = FB_VISUAL_TRUECOLOR;
 589                sfb->fb.fix.line_length  = sfb->fb.var.xres * 4;
 590                sfb->fb.var.red.length   = 8;
 591                sfb->fb.var.green.length = 8;
 592                sfb->fb.var.blue.length  = 8;
 593                sfb->fb.var.red.offset   = 16;
 594                sfb->fb.var.green.offset = 8;
 595                sfb->fb.var.blue.offset  = 0;
 596                break;
 597        case 24:
 598                sfb->fb.fix.visual       = FB_VISUAL_TRUECOLOR;
 599                sfb->fb.fix.line_length  = sfb->fb.var.xres * 3;
 600                sfb->fb.var.red.length   = 8;
 601                sfb->fb.var.green.length = 8;
 602                sfb->fb.var.blue.length  = 8;
 603                sfb->fb.var.red.offset   = 16;
 604                sfb->fb.var.green.offset = 8;
 605                sfb->fb.var.blue.offset  = 0;
 606                break;
 607        case 8:
 608                sfb->fb.fix.visual       = FB_VISUAL_PSEUDOCOLOR;
 609                sfb->fb.fix.line_length  = sfb->fb.var.xres;
 610                sfb->fb.var.red.length   = 3;
 611                sfb->fb.var.green.length = 3;
 612                sfb->fb.var.blue.length  = 2;
 613                sfb->fb.var.red.offset   = 5;
 614                sfb->fb.var.green.offset = 2;
 615                sfb->fb.var.blue.offset  = 0;
 616                break;
 617        case 16:
 618        default:
 619                sfb->fb.fix.visual       = FB_VISUAL_TRUECOLOR;
 620                sfb->fb.fix.line_length  = sfb->fb.var.xres * 2;
 621                sfb->fb.var.red.length   = 5;
 622                sfb->fb.var.green.length = 6;
 623                sfb->fb.var.blue.length  = 5;
 624                sfb->fb.var.red.offset   = 11;
 625                sfb->fb.var.green.offset = 5;
 626                sfb->fb.var.blue.offset  = 0;
 627                break;
 628        }
 629
 630        sfb->width  = sfb->fb.var.xres;
 631        sfb->height = sfb->fb.var.yres;
 632        sfb->hz = 60;
 633        smtc_set_timing(sfb);
 634}
 635
 636static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 637{
 638        /* sanity checks */
 639        if (var->xres_virtual < var->xres)
 640                var->xres_virtual = var->xres;
 641
 642        if (var->yres_virtual < var->yres)
 643                var->yres_virtual = var->yres;
 644
 645        /* set valid default bpp */
 646        if ((var->bits_per_pixel != 8)  && (var->bits_per_pixel != 16) &&
 647            (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32))
 648                var->bits_per_pixel = 16;
 649
 650        return 0;
 651}
 652
 653static int smtc_set_par(struct fb_info *info)
 654{
 655        smtcfb_setmode(info->par);
 656
 657        return 0;
 658}
 659
 660static struct fb_ops smtcfb_ops = {
 661        .owner        = THIS_MODULE,
 662        .fb_check_var = smtc_check_var,
 663        .fb_set_par   = smtc_set_par,
 664        .fb_setcolreg = smtc_setcolreg,
 665        .fb_blank     = smtc_blank,
 666        .fb_fillrect  = cfb_fillrect,
 667        .fb_imageblit = cfb_imageblit,
 668        .fb_copyarea  = cfb_copyarea,
 669#ifdef __BIG_ENDIAN
 670        .fb_read      = smtcfb_read,
 671        .fb_write     = smtcfb_write,
 672#endif
 673};
 674
 675/*
 676 * alloc struct smtcfb_info and assign default values
 677 */
 678static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *pdev)
 679{
 680        struct smtcfb_info *sfb;
 681
 682        sfb = kzalloc(sizeof(*sfb), GFP_KERNEL);
 683
 684        if (!sfb)
 685                return NULL;
 686
 687        sfb->pdev = pdev;
 688
 689        sfb->fb.flags          = FBINFO_FLAG_DEFAULT;
 690        sfb->fb.fbops          = &smtcfb_ops;
 691        sfb->fb.fix            = smtcfb_fix;
 692        sfb->fb.var            = smtcfb_var;
 693        sfb->fb.pseudo_palette = sfb->colreg;
 694        sfb->fb.par            = sfb;
 695
 696        return sfb;
 697}
 698
 699/*
 700 * free struct smtcfb_info
 701 */
 702static void smtc_free_fb_info(struct smtcfb_info *sfb)
 703{
 704        kfree(sfb);
 705}
 706
 707/*
 708 * Unmap in the memory mapped IO registers
 709 */
 710
 711static void smtc_unmap_mmio(struct smtcfb_info *sfb)
 712{
 713        if (sfb && smtc_regbaseaddress)
 714                smtc_regbaseaddress = NULL;
 715}
 716
 717/*
 718 * Map in the screen memory
 719 */
 720
 721static int smtc_map_smem(struct smtcfb_info *sfb,
 722                         struct pci_dev *pdev, u_long smem_len)
 723{
 724        sfb->fb.fix.smem_start = pci_resource_start(pdev, 0);
 725
 726#ifdef __BIG_ENDIAN
 727        if (sfb->fb.var.bits_per_pixel == 32)
 728                sfb->fb.fix.smem_start += 0x800000;
 729#endif
 730
 731        sfb->fb.fix.smem_len = smem_len;
 732
 733        sfb->fb.screen_base = sfb->lfb;
 734
 735        if (!sfb->fb.screen_base) {
 736                dev_err(&pdev->dev,
 737                        "%s: unable to map screen memory\n", sfb->fb.fix.id);
 738                return -ENOMEM;
 739        }
 740
 741        return 0;
 742}
 743
 744/*
 745 * Unmap in the screen memory
 746 *
 747 */
 748static void smtc_unmap_smem(struct smtcfb_info *sfb)
 749{
 750        if (sfb && sfb->fb.screen_base) {
 751                iounmap(sfb->fb.screen_base);
 752                sfb->fb.screen_base = NULL;
 753        }
 754}
 755
 756/*
 757 * We need to wake up the device and make sure its in linear memory mode.
 758 */
 759static inline void sm7xx_init_hw(void)
 760{
 761        outb_p(0x18, 0x3c4);
 762        outb_p(0x11, 0x3c5);
 763}
 764
 765static int smtcfb_pci_probe(struct pci_dev *pdev,
 766                            const struct pci_device_id *ent)
 767{
 768        struct smtcfb_info *sfb;
 769        u_long smem_size = 0x00800000;  /* default 8MB */
 770        int err;
 771        unsigned long mmio_base;
 772
 773        dev_info(&pdev->dev, "Silicon Motion display driver.");
 774
 775        err = pci_enable_device(pdev);  /* enable SMTC chip */
 776        if (err)
 777                return err;
 778
 779        err = pci_request_region(pdev, 0, "sm7xxfb");
 780        if (err < 0) {
 781                dev_err(&pdev->dev, "cannot reserve framebuffer region\n");
 782                goto failed_regions;
 783        }
 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_release_region(pdev, 0);
 915
 916failed_regions:
 917        pci_disable_device(pdev);
 918
 919        return err;
 920}
 921
 922/*
 923 * 0x710 (LynxEM)
 924 * 0x712 (LynxEM+)
 925 * 0x720 (Lynx3DM, Lynx3DM+)
 926 */
 927static const struct pci_device_id smtcfb_pci_table[] = {
 928        { PCI_DEVICE(0x126f, 0x710), },
 929        { PCI_DEVICE(0x126f, 0x712), },
 930        { PCI_DEVICE(0x126f, 0x720), },
 931        {0,}
 932};
 933
 934MODULE_DEVICE_TABLE(pci, smtcfb_pci_table);
 935
 936static void smtcfb_pci_remove(struct pci_dev *pdev)
 937{
 938        struct smtcfb_info *sfb;
 939
 940        sfb = pci_get_drvdata(pdev);
 941        smtc_unmap_smem(sfb);
 942        smtc_unmap_mmio(sfb);
 943        unregister_framebuffer(&sfb->fb);
 944        smtc_free_fb_info(sfb);
 945        pci_release_region(pdev, 0);
 946        pci_disable_device(pdev);
 947}
 948
 949#ifdef CONFIG_PM
 950static int smtcfb_pci_suspend(struct device *device)
 951{
 952        struct pci_dev *pdev = to_pci_dev(device);
 953        struct smtcfb_info *sfb;
 954
 955        sfb = pci_get_drvdata(pdev);
 956
 957        /* set the hw in sleep mode use external clock and self memory refresh
 958         * so that we can turn off internal PLLs later on
 959         */
 960        smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
 961        smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
 962
 963        console_lock();
 964        fb_set_suspend(&sfb->fb, 1);
 965        console_unlock();
 966
 967        /* additionally turn off all function blocks including internal PLLs */
 968        smtc_seqw(0x21, 0xff);
 969
 970        return 0;
 971}
 972
 973static int smtcfb_pci_resume(struct device *device)
 974{
 975        struct pci_dev *pdev = to_pci_dev(device);
 976        struct smtcfb_info *sfb;
 977
 978        sfb = pci_get_drvdata(pdev);
 979
 980        /* reinit hardware */
 981        sm7xx_init_hw();
 982        switch (sfb->chip_id) {
 983        case 0x710:
 984        case 0x712:
 985                /* set MCLK = 14.31818 *  (0x16 / 0x2) */
 986                smtc_seqw(0x6a, 0x16);
 987                smtc_seqw(0x6b, 0x02);
 988                smtc_seqw(0x62, 0x3e);
 989                /* enable PCI burst */
 990                smtc_seqw(0x17, 0x20);
 991#ifdef __BIG_ENDIAN
 992                if (sfb->fb.var.bits_per_pixel == 32)
 993                        smtc_seqw(0x17, 0x30);
 994#endif
 995                break;
 996        case 0x720:
 997                smtc_seqw(0x62, 0xff);
 998                smtc_seqw(0x6a, 0x0d);
 999                smtc_seqw(0x6b, 0x02);
1000                break;
1001        }
1002
1003        smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
1004        smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
1005
1006        smtcfb_setmode(sfb);
1007
1008        console_lock();
1009        fb_set_suspend(&sfb->fb, 0);
1010        console_unlock();
1011
1012        return 0;
1013}
1014
1015static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume);
1016#define SM7XX_PM_OPS (&sm7xx_pm_ops)
1017
1018#else  /* !CONFIG_PM */
1019
1020#define SM7XX_PM_OPS NULL
1021
1022#endif /* !CONFIG_PM */
1023
1024static struct pci_driver smtcfb_driver = {
1025        .name = "smtcfb",
1026        .id_table = smtcfb_pci_table,
1027        .probe = smtcfb_pci_probe,
1028        .remove = smtcfb_pci_remove,
1029        .driver.pm  = SM7XX_PM_OPS,
1030};
1031
1032static int __init sm712fb_init(void)
1033{
1034#ifndef MODULE
1035        char *option = NULL;
1036
1037        if (fb_get_options("sm712fb", &option))
1038                return -ENODEV;
1039        if (option && *option)
1040                mode_option = option;
1041#endif
1042        sm7xx_vga_setup(mode_option);
1043
1044        return pci_register_driver(&smtcfb_driver);
1045}
1046
1047module_init(sm712fb_init);
1048
1049static void __exit sm712fb_exit(void)
1050{
1051        pci_unregister_driver(&smtcfb_driver);
1052}
1053
1054module_exit(sm712fb_exit);
1055
1056MODULE_AUTHOR("Siliconmotion ");
1057MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
1058MODULE_LICENSE("GPL");
1059