linux/drivers/video/fbdev/i740fb.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * i740fb - framebuffer driver for Intel740
   4 * Copyright (c) 2011 Ondrej Zary
   5 *
   6 * Based on old i740fb driver (c) 2001-2002 Andrey Ulanov <drey@rt.mipt.ru>
   7 * which was partially based on:
   8 *  VGA 16-color framebuffer driver (c) 1999 Ben Pfaff <pfaffben@debian.org>
   9 *      and Petr Vandrovec <VANDROVE@vc.cvut.cz>
  10 *  i740 driver from XFree86 (c) 1998-1999 Precision Insight, Inc., Cedar Park,
  11 *      Texas.
  12 *  i740fb by Patrick LERDA, v0.9
  13 */
  14
  15#include <linux/module.h>
  16#include <linux/kernel.h>
  17#include <linux/errno.h>
  18#include <linux/string.h>
  19#include <linux/mm.h>
  20#include <linux/slab.h>
  21#include <linux/delay.h>
  22#include <linux/fb.h>
  23#include <linux/init.h>
  24#include <linux/pci.h>
  25#include <linux/pci_ids.h>
  26#include <linux/i2c.h>
  27#include <linux/i2c-algo-bit.h>
  28#include <linux/console.h>
  29#include <video/vga.h>
  30
  31#include "i740_reg.h"
  32
  33static char *mode_option;
  34static int mtrr = 1;
  35
  36struct i740fb_par {
  37        unsigned char __iomem *regs;
  38        bool has_sgram;
  39        int wc_cookie;
  40        bool ddc_registered;
  41        struct i2c_adapter ddc_adapter;
  42        struct i2c_algo_bit_data ddc_algo;
  43        u32 pseudo_palette[16];
  44        struct mutex open_lock;
  45        unsigned int ref_count;
  46
  47        u8 crtc[VGA_CRT_C];
  48        u8 atc[VGA_ATT_C];
  49        u8 gdc[VGA_GFX_C];
  50        u8 seq[VGA_SEQ_C];
  51        u8 misc;
  52        u8 vss;
  53
  54        /* i740 specific registers */
  55        u8 display_cntl;
  56        u8 pixelpipe_cfg0;
  57        u8 pixelpipe_cfg1;
  58        u8 pixelpipe_cfg2;
  59        u8 video_clk2_m;
  60        u8 video_clk2_n;
  61        u8 video_clk2_mn_msbs;
  62        u8 video_clk2_div_sel;
  63        u8 pll_cntl;
  64        u8 address_mapping;
  65        u8 io_cntl;
  66        u8 bitblt_cntl;
  67        u8 ext_vert_total;
  68        u8 ext_vert_disp_end;
  69        u8 ext_vert_sync_start;
  70        u8 ext_vert_blank_start;
  71        u8 ext_horiz_total;
  72        u8 ext_horiz_blank;
  73        u8 ext_offset;
  74        u8 interlace_cntl;
  75        u32 lmi_fifo_watermark;
  76        u8 ext_start_addr;
  77        u8 ext_start_addr_hi;
  78};
  79
  80#define DACSPEED8       203
  81#define DACSPEED16      163
  82#define DACSPEED24_SG   136
  83#define DACSPEED24_SD   128
  84#define DACSPEED32      86
  85
  86static const struct fb_fix_screeninfo i740fb_fix = {
  87        .id =           "i740fb",
  88        .type =         FB_TYPE_PACKED_PIXELS,
  89        .visual =       FB_VISUAL_TRUECOLOR,
  90        .xpanstep =     8,
  91        .ypanstep =     1,
  92        .accel =        FB_ACCEL_NONE,
  93};
  94
  95static inline void i740outb(struct i740fb_par *par, u16 port, u8 val)
  96{
  97        vga_mm_w(par->regs, port, val);
  98}
  99static inline u8 i740inb(struct i740fb_par *par, u16 port)
 100{
 101        return vga_mm_r(par->regs, port);
 102}
 103static inline void i740outreg(struct i740fb_par *par, u16 port, u8 reg, u8 val)
 104{
 105        vga_mm_w_fast(par->regs, port, reg, val);
 106}
 107static inline u8 i740inreg(struct i740fb_par *par, u16 port, u8 reg)
 108{
 109        vga_mm_w(par->regs, port, reg);
 110        return vga_mm_r(par->regs, port+1);
 111}
 112static inline void i740outreg_mask(struct i740fb_par *par, u16 port, u8 reg,
 113                                   u8 val, u8 mask)
 114{
 115        vga_mm_w_fast(par->regs, port, reg, (val & mask)
 116                | (i740inreg(par, port, reg) & ~mask));
 117}
 118
 119#define REG_DDC_DRIVE   0x62
 120#define REG_DDC_STATE   0x63
 121#define DDC_SCL         (1 << 3)
 122#define DDC_SDA         (1 << 2)
 123
 124static void i740fb_ddc_setscl(void *data, int val)
 125{
 126        struct i740fb_par *par = data;
 127
 128        i740outreg_mask(par, XRX, REG_DDC_DRIVE, DDC_SCL, DDC_SCL);
 129        i740outreg_mask(par, XRX, REG_DDC_STATE, val ? DDC_SCL : 0, DDC_SCL);
 130}
 131
 132static void i740fb_ddc_setsda(void *data, int val)
 133{
 134        struct i740fb_par *par = data;
 135
 136        i740outreg_mask(par, XRX, REG_DDC_DRIVE, DDC_SDA, DDC_SDA);
 137        i740outreg_mask(par, XRX, REG_DDC_STATE, val ? DDC_SDA : 0, DDC_SDA);
 138}
 139
 140static int i740fb_ddc_getscl(void *data)
 141{
 142        struct i740fb_par *par = data;
 143
 144        i740outreg_mask(par, XRX, REG_DDC_DRIVE, 0, DDC_SCL);
 145
 146        return !!(i740inreg(par, XRX, REG_DDC_STATE) & DDC_SCL);
 147}
 148
 149static int i740fb_ddc_getsda(void *data)
 150{
 151        struct i740fb_par *par = data;
 152
 153        i740outreg_mask(par, XRX, REG_DDC_DRIVE, 0, DDC_SDA);
 154
 155        return !!(i740inreg(par, XRX, REG_DDC_STATE) & DDC_SDA);
 156}
 157
 158static int i740fb_setup_ddc_bus(struct fb_info *info)
 159{
 160        struct i740fb_par *par = info->par;
 161
 162        strlcpy(par->ddc_adapter.name, info->fix.id,
 163                sizeof(par->ddc_adapter.name));
 164        par->ddc_adapter.owner          = THIS_MODULE;
 165        par->ddc_adapter.class          = I2C_CLASS_DDC;
 166        par->ddc_adapter.algo_data      = &par->ddc_algo;
 167        par->ddc_adapter.dev.parent     = info->device;
 168        par->ddc_algo.setsda            = i740fb_ddc_setsda;
 169        par->ddc_algo.setscl            = i740fb_ddc_setscl;
 170        par->ddc_algo.getsda            = i740fb_ddc_getsda;
 171        par->ddc_algo.getscl            = i740fb_ddc_getscl;
 172        par->ddc_algo.udelay            = 10;
 173        par->ddc_algo.timeout           = 20;
 174        par->ddc_algo.data              = par;
 175
 176        i2c_set_adapdata(&par->ddc_adapter, par);
 177
 178        return i2c_bit_add_bus(&par->ddc_adapter);
 179}
 180
 181static int i740fb_open(struct fb_info *info, int user)
 182{
 183        struct i740fb_par *par = info->par;
 184
 185        mutex_lock(&(par->open_lock));
 186        par->ref_count++;
 187        mutex_unlock(&(par->open_lock));
 188
 189        return 0;
 190}
 191
 192static int i740fb_release(struct fb_info *info, int user)
 193{
 194        struct i740fb_par *par = info->par;
 195
 196        mutex_lock(&(par->open_lock));
 197        if (par->ref_count == 0) {
 198                fb_err(info, "release called with zero refcount\n");
 199                mutex_unlock(&(par->open_lock));
 200                return -EINVAL;
 201        }
 202
 203        par->ref_count--;
 204        mutex_unlock(&(par->open_lock));
 205
 206        return 0;
 207}
 208
 209static u32 i740_calc_fifo(struct i740fb_par *par, u32 freq, int bpp)
 210{
 211        /*
 212         * Would like to calculate these values automatically, but a generic
 213         * algorithm does not seem possible.  Note: These FIFO water mark
 214         * values were tested on several cards and seem to eliminate the
 215         * all of the snow and vertical banding, but fine adjustments will
 216         * probably be required for other cards.
 217         */
 218
 219        u32 wm;
 220
 221        switch (bpp) {
 222        case 8:
 223                if      (freq > 200)
 224                        wm = 0x18120000;
 225                else if (freq > 175)
 226                        wm = 0x16110000;
 227                else if (freq > 135)
 228                        wm = 0x120E0000;
 229                else
 230                        wm = 0x100D0000;
 231                break;
 232        case 15:
 233        case 16:
 234                if (par->has_sgram) {
 235                        if      (freq > 140)
 236                                wm = 0x2C1D0000;
 237                        else if (freq > 120)
 238                                wm = 0x2C180000;
 239                        else if (freq > 100)
 240                                wm = 0x24160000;
 241                        else if (freq >  90)
 242                                wm = 0x18120000;
 243                        else if (freq >  50)
 244                                wm = 0x16110000;
 245                        else if (freq >  32)
 246                                wm = 0x13100000;
 247                        else
 248                                wm = 0x120E0000;
 249                } else {
 250                        if      (freq > 160)
 251                                wm = 0x28200000;
 252                        else if (freq > 140)
 253                                wm = 0x2A1E0000;
 254                        else if (freq > 130)
 255                                wm = 0x2B1A0000;
 256                        else if (freq > 120)
 257                                wm = 0x2C180000;
 258                        else if (freq > 100)
 259                                wm = 0x24180000;
 260                        else if (freq >  90)
 261                                wm = 0x18120000;
 262                        else if (freq >  50)
 263                                wm = 0x16110000;
 264                        else if (freq >  32)
 265                                wm = 0x13100000;
 266                        else
 267                                wm = 0x120E0000;
 268                }
 269                break;
 270        case 24:
 271                if (par->has_sgram) {
 272                        if      (freq > 130)
 273                                wm = 0x31200000;
 274                        else if (freq > 120)
 275                                wm = 0x2E200000;
 276                        else if (freq > 100)
 277                                wm = 0x2C1D0000;
 278                        else if (freq >  80)
 279                                wm = 0x25180000;
 280                        else if (freq >  64)
 281                                wm = 0x24160000;
 282                        else if (freq >  49)
 283                                wm = 0x18120000;
 284                        else if (freq >  32)
 285                                wm = 0x16110000;
 286                        else
 287                                wm = 0x13100000;
 288                } else {
 289                        if      (freq > 120)
 290                                wm = 0x311F0000;
 291                        else if (freq > 100)
 292                                wm = 0x2C1D0000;
 293                        else if (freq >  80)
 294                                wm = 0x25180000;
 295                        else if (freq >  64)
 296                                wm = 0x24160000;
 297                        else if (freq >  49)
 298                                wm = 0x18120000;
 299                        else if (freq >  32)
 300                                wm = 0x16110000;
 301                        else
 302                                wm = 0x13100000;
 303                }
 304                break;
 305        case 32:
 306                if (par->has_sgram) {
 307                        if      (freq >  80)
 308                                wm = 0x2A200000;
 309                        else if (freq >  60)
 310                                wm = 0x281A0000;
 311                        else if (freq >  49)
 312                                wm = 0x25180000;
 313                        else if (freq >  32)
 314                                wm = 0x18120000;
 315                        else
 316                                wm = 0x16110000;
 317                } else {
 318                        if      (freq >  80)
 319                                wm = 0x29200000;
 320                        else if (freq >  60)
 321                                wm = 0x281A0000;
 322                        else if (freq >  49)
 323                                wm = 0x25180000;
 324                        else if (freq >  32)
 325                                wm = 0x18120000;
 326                        else
 327                                wm = 0x16110000;
 328                }
 329                break;
 330        }
 331
 332        return wm;
 333}
 334
 335/* clock calculation from i740fb by Patrick LERDA */
 336
 337#define I740_RFREQ              1000000
 338#define TARGET_MAX_N            30
 339#define I740_FFIX               (1 << 8)
 340#define I740_RFREQ_FIX          (I740_RFREQ / I740_FFIX)
 341#define I740_REF_FREQ           (6667 * I740_FFIX / 100)        /* 66.67 MHz */
 342#define I740_MAX_VCO_FREQ       (450 * I740_FFIX)               /* 450 MHz */
 343
 344static void i740_calc_vclk(u32 freq, struct i740fb_par *par)
 345{
 346        const u32 err_max    = freq / (200  * I740_RFREQ / I740_FFIX);
 347        const u32 err_target = freq / (1000 * I740_RFREQ / I740_FFIX);
 348        u32 err_best = 512 * I740_FFIX;
 349        u32 f_err, f_vco;
 350        int m_best = 0, n_best = 0, p_best = 0;
 351        int m, n;
 352
 353        p_best = min(15, ilog2(I740_MAX_VCO_FREQ / (freq / I740_RFREQ_FIX)));
 354        f_vco = (freq * (1 << p_best)) / I740_RFREQ_FIX;
 355        freq = freq / I740_RFREQ_FIX;
 356
 357        n = 2;
 358        do {
 359                n++;
 360                m = ((f_vco * n) / I740_REF_FREQ + 2) / 4;
 361
 362                if (m < 3)
 363                        m = 3;
 364
 365                {
 366                        u32 f_out = (((m * I740_REF_FREQ * 4)
 367                                 / n) + ((1 << p_best) / 2)) / (1 << p_best);
 368
 369                        f_err = (freq - f_out);
 370
 371                        if (abs(f_err) < err_max) {
 372                                m_best = m;
 373                                n_best = n;
 374                                err_best = f_err;
 375                        }
 376                }
 377        } while ((abs(f_err) >= err_target) &&
 378                 ((n <= TARGET_MAX_N) || (abs(err_best) > err_max)));
 379
 380        if (abs(f_err) < err_target) {
 381                m_best = m;
 382                n_best = n;
 383        }
 384
 385        par->video_clk2_m = (m_best - 2) & 0xFF;
 386        par->video_clk2_n = (n_best - 2) & 0xFF;
 387        par->video_clk2_mn_msbs = ((((n_best - 2) >> 4) & VCO_N_MSBS)
 388                                 | (((m_best - 2) >> 8) & VCO_M_MSBS));
 389        par->video_clk2_div_sel = ((p_best << 4) | REF_DIV_1);
 390}
 391
 392static int i740fb_decode_var(const struct fb_var_screeninfo *var,
 393                             struct i740fb_par *par, struct fb_info *info)
 394{
 395        /*
 396         * Get the video params out of 'var'.
 397         * If a value doesn't fit, round it up, if it's too big, return -EINVAL.
 398         */
 399
 400        u32 xres, right, hslen, left, xtotal;
 401        u32 yres, lower, vslen, upper, ytotal;
 402        u32 vxres, xoffset, vyres, yoffset;
 403        u32 bpp, base, dacspeed24, mem;
 404        u8 r7;
 405        int i;
 406
 407        dev_dbg(info->device, "decode_var: xres: %i, yres: %i, xres_v: %i, xres_v: %i\n",
 408                  var->xres, var->yres, var->xres_virtual, var->xres_virtual);
 409        dev_dbg(info->device, " xoff: %i, yoff: %i, bpp: %i, graysc: %i\n",
 410                  var->xoffset, var->yoffset, var->bits_per_pixel,
 411                  var->grayscale);
 412        dev_dbg(info->device, " activate: %i, nonstd: %i, vmode: %i\n",
 413                  var->activate, var->nonstd, var->vmode);
 414        dev_dbg(info->device, " pixclock: %i, hsynclen:%i, vsynclen:%i\n",
 415                  var->pixclock, var->hsync_len, var->vsync_len);
 416        dev_dbg(info->device, " left: %i, right: %i, up:%i, lower:%i\n",
 417                  var->left_margin, var->right_margin, var->upper_margin,
 418                  var->lower_margin);
 419
 420
 421        bpp = var->bits_per_pixel;
 422        switch (bpp) {
 423        case 1 ... 8:
 424                bpp = 8;
 425                if ((1000000 / var->pixclock) > DACSPEED8) {
 426                        dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 8bpp)\n",
 427                                1000000 / var->pixclock, DACSPEED8);
 428                        return -EINVAL;
 429                }
 430                break;
 431        case 9 ... 15:
 432                bpp = 15;
 433                fallthrough;
 434        case 16:
 435                if ((1000000 / var->pixclock) > DACSPEED16) {
 436                        dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 15/16bpp)\n",
 437                                1000000 / var->pixclock, DACSPEED16);
 438                        return -EINVAL;
 439                }
 440                break;
 441        case 17 ... 24:
 442                bpp = 24;
 443                dacspeed24 = par->has_sgram ? DACSPEED24_SG : DACSPEED24_SD;
 444                if ((1000000 / var->pixclock) > dacspeed24) {
 445                        dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 24bpp)\n",
 446                                1000000 / var->pixclock, dacspeed24);
 447                        return -EINVAL;
 448                }
 449                break;
 450        case 25 ... 32:
 451                bpp = 32;
 452                if ((1000000 / var->pixclock) > DACSPEED32) {
 453                        dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 32bpp)\n",
 454                                1000000 / var->pixclock, DACSPEED32);
 455                        return -EINVAL;
 456                }
 457                break;
 458        default:
 459                return -EINVAL;
 460        }
 461
 462        xres = ALIGN(var->xres, 8);
 463        vxres = ALIGN(var->xres_virtual, 16);
 464        if (vxres < xres)
 465                vxres = xres;
 466
 467        xoffset = ALIGN(var->xoffset, 8);
 468        if (xres + xoffset > vxres)
 469                xoffset = vxres - xres;
 470
 471        left = ALIGN(var->left_margin, 8);
 472        right = ALIGN(var->right_margin, 8);
 473        hslen = ALIGN(var->hsync_len, 8);
 474
 475        yres = var->yres;
 476        vyres = var->yres_virtual;
 477        if (yres > vyres)
 478                vyres = yres;
 479
 480        yoffset = var->yoffset;
 481        if (yres + yoffset > vyres)
 482                yoffset = vyres - yres;
 483
 484        lower = var->lower_margin;
 485        vslen = var->vsync_len;
 486        upper = var->upper_margin;
 487
 488        mem = vxres * vyres * ((bpp + 1) / 8);
 489        if (mem > info->screen_size) {
 490                dev_err(info->device, "not enough video memory (%d KB requested, %ld KB available)\n",
 491                        mem >> 10, info->screen_size >> 10);
 492                return -ENOMEM;
 493        }
 494
 495        if (yoffset + yres > vyres)
 496                yoffset = vyres - yres;
 497
 498        xtotal = xres + right + hslen + left;
 499        ytotal = yres + lower + vslen + upper;
 500
 501        par->crtc[VGA_CRTC_H_TOTAL] = (xtotal >> 3) - 5;
 502        par->crtc[VGA_CRTC_H_DISP] = (xres >> 3) - 1;
 503        par->crtc[VGA_CRTC_H_BLANK_START] = ((xres + right) >> 3) - 1;
 504        par->crtc[VGA_CRTC_H_SYNC_START] = (xres + right) >> 3;
 505        par->crtc[VGA_CRTC_H_SYNC_END] = (((xres + right + hslen) >> 3) & 0x1F)
 506                | ((((xres + right + hslen) >> 3) & 0x20) << 2);
 507        par->crtc[VGA_CRTC_H_BLANK_END] = ((xres + right + hslen) >> 3 & 0x1F)
 508                | 0x80;
 509
 510        par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;
 511
 512        r7 = 0x10;      /* disable linecompare */
 513        if (ytotal & 0x100)
 514                r7 |= 0x01;
 515        if (ytotal & 0x200)
 516                r7 |= 0x20;
 517
 518        par->crtc[VGA_CRTC_PRESET_ROW] = 0;
 519        par->crtc[VGA_CRTC_MAX_SCAN] = 0x40;    /* 1 scanline, no linecmp */
 520        if (var->vmode & FB_VMODE_DOUBLE)
 521                par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;
 522        par->crtc[VGA_CRTC_CURSOR_START] = 0x00;
 523        par->crtc[VGA_CRTC_CURSOR_END] = 0x00;
 524        par->crtc[VGA_CRTC_CURSOR_HI] = 0x00;
 525        par->crtc[VGA_CRTC_CURSOR_LO] = 0x00;
 526        par->crtc[VGA_CRTC_V_DISP_END] = yres-1;
 527        if ((yres-1) & 0x100)
 528                r7 |= 0x02;
 529        if ((yres-1) & 0x200)
 530                r7 |= 0x40;
 531
 532        par->crtc[VGA_CRTC_V_BLANK_START] = yres + lower - 1;
 533        par->crtc[VGA_CRTC_V_SYNC_START] = yres + lower - 1;
 534        if ((yres + lower - 1) & 0x100)
 535                r7 |= 0x0C;
 536        if ((yres + lower - 1) & 0x200) {
 537                par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20;
 538                r7 |= 0x80;
 539        }
 540
 541        /* disabled IRQ */
 542        par->crtc[VGA_CRTC_V_SYNC_END] =
 543                ((yres + lower - 1 + vslen) & 0x0F) & ~0x10;
 544        /* 0x7F for VGA, but some SVGA chips require all 8 bits to be set */
 545        par->crtc[VGA_CRTC_V_BLANK_END] = (yres + lower - 1 + vslen) & 0xFF;
 546
 547        par->crtc[VGA_CRTC_UNDERLINE] = 0x00;
 548        par->crtc[VGA_CRTC_MODE] = 0xC3 ;
 549        par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF;
 550        par->crtc[VGA_CRTC_OVERFLOW] = r7;
 551
 552        par->vss = 0x00;        /* 3DA */
 553
 554        for (i = 0x00; i < 0x10; i++)
 555                par->atc[i] = i;
 556        par->atc[VGA_ATC_MODE] = 0x81;
 557        par->atc[VGA_ATC_OVERSCAN] = 0x00;      /* 0 for EGA, 0xFF for VGA */
 558        par->atc[VGA_ATC_PLANE_ENABLE] = 0x0F;
 559        par->atc[VGA_ATC_COLOR_PAGE] = 0x00;
 560
 561        par->misc = 0xC3;
 562        if (var->sync & FB_SYNC_HOR_HIGH_ACT)
 563                par->misc &= ~0x40;
 564        if (var->sync & FB_SYNC_VERT_HIGH_ACT)
 565                par->misc &= ~0x80;
 566
 567        par->seq[VGA_SEQ_CLOCK_MODE] = 0x01;
 568        par->seq[VGA_SEQ_PLANE_WRITE] = 0x0F;
 569        par->seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
 570        par->seq[VGA_SEQ_MEMORY_MODE] = 0x06;
 571
 572        par->gdc[VGA_GFX_SR_VALUE] = 0x00;
 573        par->gdc[VGA_GFX_SR_ENABLE] = 0x00;
 574        par->gdc[VGA_GFX_COMPARE_VALUE] = 0x00;
 575        par->gdc[VGA_GFX_DATA_ROTATE] = 0x00;
 576        par->gdc[VGA_GFX_PLANE_READ] = 0;
 577        par->gdc[VGA_GFX_MODE] = 0x02;
 578        par->gdc[VGA_GFX_MISC] = 0x05;
 579        par->gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
 580        par->gdc[VGA_GFX_BIT_MASK] = 0xFF;
 581
 582        base = (yoffset * vxres + (xoffset & ~7)) >> 2;
 583        switch (bpp) {
 584        case 8:
 585                par->crtc[VGA_CRTC_OFFSET] = vxres >> 3;
 586                par->ext_offset = vxres >> 11;
 587                par->pixelpipe_cfg1 = DISPLAY_8BPP_MODE;
 588                par->bitblt_cntl = COLEXP_8BPP;
 589                break;
 590        case 15: /* 0rrrrrgg gggbbbbb */
 591        case 16: /* rrrrrggg gggbbbbb */
 592                par->pixelpipe_cfg1 = (var->green.length == 6) ?
 593                        DISPLAY_16BPP_MODE : DISPLAY_15BPP_MODE;
 594                par->crtc[VGA_CRTC_OFFSET] = vxres >> 2;
 595                par->ext_offset = vxres >> 10;
 596                par->bitblt_cntl = COLEXP_16BPP;
 597                base *= 2;
 598                break;
 599        case 24:
 600                par->crtc[VGA_CRTC_OFFSET] = (vxres * 3) >> 3;
 601                par->ext_offset = (vxres * 3) >> 11;
 602                par->pixelpipe_cfg1 = DISPLAY_24BPP_MODE;
 603                par->bitblt_cntl = COLEXP_24BPP;
 604                base &= 0xFFFFFFFE; /* ...ignore the last bit. */
 605                base *= 3;
 606                break;
 607        case 32:
 608                par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;
 609                par->ext_offset = vxres >> 9;
 610                par->pixelpipe_cfg1 = DISPLAY_32BPP_MODE;
 611                par->bitblt_cntl = COLEXP_RESERVED; /* Unimplemented on i740 */
 612                base *= 4;
 613                break;
 614        }
 615
 616        par->crtc[VGA_CRTC_START_LO] = base & 0x000000FF;
 617        par->crtc[VGA_CRTC_START_HI] = (base & 0x0000FF00) >>  8;
 618        par->ext_start_addr =
 619                ((base & 0x003F0000) >> 16) | EXT_START_ADDR_ENABLE;
 620        par->ext_start_addr_hi = (base & 0x3FC00000) >> 22;
 621
 622        par->pixelpipe_cfg0 = DAC_8_BIT;
 623
 624        par->pixelpipe_cfg2 = DISPLAY_GAMMA_ENABLE | OVERLAY_GAMMA_ENABLE;
 625        par->io_cntl = EXTENDED_CRTC_CNTL;
 626        par->address_mapping = LINEAR_MODE_ENABLE | PAGE_MAPPING_ENABLE;
 627        par->display_cntl = HIRES_MODE;
 628
 629        /* Set the MCLK freq */
 630        par->pll_cntl = PLL_MEMCLK_100000KHZ; /* 100 MHz -- use as default */
 631
 632        /* Calculate the extended CRTC regs */
 633        par->ext_vert_total = (ytotal - 2) >> 8;
 634        par->ext_vert_disp_end = (yres - 1) >> 8;
 635        par->ext_vert_sync_start = (yres + lower) >> 8;
 636        par->ext_vert_blank_start = (yres + lower) >> 8;
 637        par->ext_horiz_total = ((xtotal >> 3) - 5) >> 8;
 638        par->ext_horiz_blank = (((xres + right) >> 3) & 0x40) >> 6;
 639
 640        par->interlace_cntl = INTERLACE_DISABLE;
 641
 642        /* Set the overscan color to 0. (NOTE: This only affects >8bpp mode) */
 643        par->atc[VGA_ATC_OVERSCAN] = 0;
 644
 645        /* Calculate VCLK that most closely matches the requested dot clock */
 646        i740_calc_vclk((((u32)1e9) / var->pixclock) * (u32)(1e3), par);
 647
 648        /* Since we program the clocks ourselves, always use VCLK2. */
 649        par->misc |= 0x0C;
 650
 651        /* Calculate the FIFO Watermark and Burst Length. */
 652        par->lmi_fifo_watermark =
 653                i740_calc_fifo(par, 1000000 / var->pixclock, bpp);
 654
 655        return 0;
 656}
 657
 658static int i740fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 659{
 660        if (!var->pixclock)
 661                return -EINVAL;
 662
 663        switch (var->bits_per_pixel) {
 664        case 8:
 665                var->red.offset = var->green.offset = var->blue.offset = 0;
 666                var->red.length = var->green.length = var->blue.length = 8;
 667                break;
 668        case 16:
 669                switch (var->green.length) {
 670                default:
 671                case 5:
 672                        var->red.offset = 10;
 673                        var->green.offset = 5;
 674                        var->blue.offset = 0;
 675                        var->red.length = 5;
 676                        var->green.length = 5;
 677                        var->blue.length = 5;
 678                        break;
 679                case 6:
 680                        var->red.offset = 11;
 681                        var->green.offset = 5;
 682                        var->blue.offset = 0;
 683                        var->red.length = var->blue.length = 5;
 684                        break;
 685                }
 686                break;
 687        case 24:
 688                var->red.offset = 16;
 689                var->green.offset = 8;
 690                var->blue.offset = 0;
 691                var->red.length = var->green.length = var->blue.length = 8;
 692                break;
 693        case 32:
 694                var->transp.offset = 24;
 695                var->red.offset = 16;
 696                var->green.offset = 8;
 697                var->blue.offset = 0;
 698                var->transp.length = 8;
 699                var->red.length = var->green.length = var->blue.length = 8;
 700                break;
 701        default:
 702                return -EINVAL;
 703        }
 704
 705        if (var->xres > var->xres_virtual)
 706                var->xres_virtual = var->xres;
 707
 708        if (var->yres > var->yres_virtual)
 709                var->yres_virtual = var->yres;
 710
 711        if (info->monspecs.hfmax && info->monspecs.vfmax &&
 712            info->monspecs.dclkmax && fb_validate_mode(var, info) < 0)
 713                return -EINVAL;
 714
 715        return 0;
 716}
 717
 718static void vga_protect(struct i740fb_par *par)
 719{
 720        /* disable the display */
 721        i740outreg_mask(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE, 0x20, 0x20);
 722
 723        i740inb(par, 0x3DA);
 724        i740outb(par, VGA_ATT_W, 0x00); /* enable palette access */
 725}
 726
 727static void vga_unprotect(struct i740fb_par *par)
 728{
 729        /* reenable display */
 730        i740outreg_mask(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE, 0, 0x20);
 731
 732        i740inb(par, 0x3DA);
 733        i740outb(par, VGA_ATT_W, 0x20); /* disable palette access */
 734}
 735
 736static int i740fb_set_par(struct fb_info *info)
 737{
 738        struct i740fb_par *par = info->par;
 739        u32 itemp;
 740        int i;
 741
 742        i = i740fb_decode_var(&info->var, par, info);
 743        if (i)
 744                return i;
 745
 746        memset_io(info->screen_base, 0, info->screen_size);
 747
 748        vga_protect(par);
 749
 750        i740outreg(par, XRX, DRAM_EXT_CNTL, DRAM_REFRESH_DISABLE);
 751
 752        mdelay(1);
 753
 754        i740outreg(par, XRX, VCLK2_VCO_M, par->video_clk2_m);
 755        i740outreg(par, XRX, VCLK2_VCO_N, par->video_clk2_n);
 756        i740outreg(par, XRX, VCLK2_VCO_MN_MSBS, par->video_clk2_mn_msbs);
 757        i740outreg(par, XRX, VCLK2_VCO_DIV_SEL, par->video_clk2_div_sel);
 758
 759        i740outreg_mask(par, XRX, PIXPIPE_CONFIG_0,
 760                        par->pixelpipe_cfg0 & DAC_8_BIT, 0x80);
 761
 762        i740inb(par, 0x3DA);
 763        i740outb(par, 0x3C0, 0x00);
 764
 765        /* update misc output register */
 766        i740outb(par, VGA_MIS_W, par->misc | 0x01);
 767
 768        /* synchronous reset on */
 769        i740outreg(par, VGA_SEQ_I, VGA_SEQ_RESET, 0x01);
 770        /* write sequencer registers */
 771        i740outreg(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE,
 772                        par->seq[VGA_SEQ_CLOCK_MODE] | 0x20);
 773        for (i = 2; i < VGA_SEQ_C; i++)
 774                i740outreg(par, VGA_SEQ_I, i, par->seq[i]);
 775
 776        /* synchronous reset off */
 777        i740outreg(par, VGA_SEQ_I, VGA_SEQ_RESET, 0x03);
 778
 779        /* deprotect CRT registers 0-7 */
 780        i740outreg(par, VGA_CRT_IC, VGA_CRTC_V_SYNC_END,
 781                        par->crtc[VGA_CRTC_V_SYNC_END]);
 782
 783        /* write CRT registers */
 784        for (i = 0; i < VGA_CRT_C; i++)
 785                i740outreg(par, VGA_CRT_IC, i, par->crtc[i]);
 786
 787        /* write graphics controller registers */
 788        for (i = 0; i < VGA_GFX_C; i++)
 789                i740outreg(par, VGA_GFX_I, i, par->gdc[i]);
 790
 791        /* write attribute controller registers */
 792        for (i = 0; i < VGA_ATT_C; i++) {
 793                i740inb(par, VGA_IS1_RC);               /* reset flip-flop */
 794                i740outb(par, VGA_ATT_IW, i);
 795                i740outb(par, VGA_ATT_IW, par->atc[i]);
 796        }
 797
 798        i740inb(par, VGA_IS1_RC);
 799        i740outb(par, VGA_ATT_IW, 0x20);
 800
 801        i740outreg(par, VGA_CRT_IC, EXT_VERT_TOTAL, par->ext_vert_total);
 802        i740outreg(par, VGA_CRT_IC, EXT_VERT_DISPLAY, par->ext_vert_disp_end);
 803        i740outreg(par, VGA_CRT_IC, EXT_VERT_SYNC_START,
 804                        par->ext_vert_sync_start);
 805        i740outreg(par, VGA_CRT_IC, EXT_VERT_BLANK_START,
 806                        par->ext_vert_blank_start);
 807        i740outreg(par, VGA_CRT_IC, EXT_HORIZ_TOTAL, par->ext_horiz_total);
 808        i740outreg(par, VGA_CRT_IC, EXT_HORIZ_BLANK, par->ext_horiz_blank);
 809        i740outreg(par, VGA_CRT_IC, EXT_OFFSET, par->ext_offset);
 810        i740outreg(par, VGA_CRT_IC, EXT_START_ADDR_HI, par->ext_start_addr_hi);
 811        i740outreg(par, VGA_CRT_IC, EXT_START_ADDR, par->ext_start_addr);
 812
 813        i740outreg_mask(par, VGA_CRT_IC, INTERLACE_CNTL,
 814                        par->interlace_cntl, INTERLACE_ENABLE);
 815        i740outreg_mask(par, XRX, ADDRESS_MAPPING, par->address_mapping, 0x1F);
 816        i740outreg_mask(par, XRX, BITBLT_CNTL, par->bitblt_cntl, COLEXP_MODE);
 817        i740outreg_mask(par, XRX, DISPLAY_CNTL,
 818                        par->display_cntl, VGA_WRAP_MODE | GUI_MODE);
 819        i740outreg_mask(par, XRX, PIXPIPE_CONFIG_0, par->pixelpipe_cfg0, 0x9B);
 820        i740outreg_mask(par, XRX, PIXPIPE_CONFIG_2, par->pixelpipe_cfg2, 0x0C);
 821
 822        i740outreg(par, XRX, PLL_CNTL, par->pll_cntl);
 823
 824        i740outreg_mask(par, XRX, PIXPIPE_CONFIG_1,
 825                        par->pixelpipe_cfg1, DISPLAY_COLOR_MODE);
 826
 827        itemp = readl(par->regs + FWATER_BLC);
 828        itemp &= ~(LMI_BURST_LENGTH | LMI_FIFO_WATERMARK);
 829        itemp |= par->lmi_fifo_watermark;
 830        writel(itemp, par->regs + FWATER_BLC);
 831
 832        i740outreg(par, XRX, DRAM_EXT_CNTL, DRAM_REFRESH_60HZ);
 833
 834        i740outreg_mask(par, MRX, COL_KEY_CNTL_1, 0, BLANK_DISP_OVERLAY);
 835        i740outreg_mask(par, XRX, IO_CTNL,
 836                        par->io_cntl, EXTENDED_ATTR_CNTL | EXTENDED_CRTC_CNTL);
 837
 838        if (par->pixelpipe_cfg1 != DISPLAY_8BPP_MODE) {
 839                i740outb(par, VGA_PEL_MSK, 0xFF);
 840                i740outb(par, VGA_PEL_IW, 0x00);
 841                for (i = 0; i < 256; i++) {
 842                        itemp = (par->pixelpipe_cfg0 & DAC_8_BIT) ? i : i >> 2;
 843                        i740outb(par, VGA_PEL_D, itemp);
 844                        i740outb(par, VGA_PEL_D, itemp);
 845                        i740outb(par, VGA_PEL_D, itemp);
 846                }
 847        }
 848
 849        /* Wait for screen to stabilize. */
 850        mdelay(50);
 851        vga_unprotect(par);
 852
 853        info->fix.line_length =
 854                        info->var.xres_virtual * info->var.bits_per_pixel / 8;
 855        if (info->var.bits_per_pixel == 8)
 856                info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
 857        else
 858                info->fix.visual = FB_VISUAL_TRUECOLOR;
 859
 860        return 0;
 861}
 862
 863static int i740fb_setcolreg(unsigned regno, unsigned red, unsigned green,
 864                           unsigned blue, unsigned transp,
 865                           struct fb_info *info)
 866{
 867        u32 r, g, b;
 868
 869        dev_dbg(info->device, "setcolreg: regno: %i, red=%d, green=%d, blue=%d, transp=%d, bpp=%d\n",
 870                regno, red, green, blue, transp, info->var.bits_per_pixel);
 871
 872        switch (info->fix.visual) {
 873        case FB_VISUAL_PSEUDOCOLOR:
 874                if (regno >= 256)
 875                        return -EINVAL;
 876                i740outb(info->par, VGA_PEL_IW, regno);
 877                i740outb(info->par, VGA_PEL_D, red >> 8);
 878                i740outb(info->par, VGA_PEL_D, green >> 8);
 879                i740outb(info->par, VGA_PEL_D, blue >> 8);
 880                break;
 881        case FB_VISUAL_TRUECOLOR:
 882                if (regno >= 16)
 883                        return -EINVAL;
 884                r = (red >> (16 - info->var.red.length))
 885                        << info->var.red.offset;
 886                b = (blue >> (16 - info->var.blue.length))
 887                        << info->var.blue.offset;
 888                g = (green >> (16 - info->var.green.length))
 889                        << info->var.green.offset;
 890                ((u32 *) info->pseudo_palette)[regno] = r | g | b;
 891                break;
 892        default:
 893                return -EINVAL;
 894        }
 895
 896        return 0;
 897}
 898
 899static int i740fb_pan_display(struct fb_var_screeninfo *var,
 900                                 struct fb_info *info)
 901{
 902        struct i740fb_par *par = info->par;
 903        u32 base = (var->yoffset * info->var.xres_virtual
 904                 + (var->xoffset & ~7)) >> 2;
 905
 906        dev_dbg(info->device, "pan_display: xoffset: %i yoffset: %i base: %i\n",
 907                var->xoffset, var->yoffset, base);
 908
 909        switch (info->var.bits_per_pixel) {
 910        case 8:
 911                break;
 912        case 15:
 913        case 16:
 914                base *= 2;
 915                break;
 916        case 24:
 917                /*
 918                 * The last bit does not seem to have any effect on the start
 919                 * address register in 24bpp mode, so...
 920                 */
 921                base &= 0xFFFFFFFE; /* ...ignore the last bit. */
 922                base *= 3;
 923                break;
 924        case 32:
 925                base *= 4;
 926                break;
 927        }
 928
 929        par->crtc[VGA_CRTC_START_LO] = base & 0x000000FF;
 930        par->crtc[VGA_CRTC_START_HI] = (base & 0x0000FF00) >>  8;
 931        par->ext_start_addr_hi = (base & 0x3FC00000) >> 22;
 932        par->ext_start_addr =
 933                        ((base & 0x003F0000) >> 16) | EXT_START_ADDR_ENABLE;
 934
 935        i740outreg(par, VGA_CRT_IC, VGA_CRTC_START_LO,  base & 0x000000FF);
 936        i740outreg(par, VGA_CRT_IC, VGA_CRTC_START_HI,
 937                        (base & 0x0000FF00) >> 8);
 938        i740outreg(par, VGA_CRT_IC, EXT_START_ADDR_HI,
 939                        (base & 0x3FC00000) >> 22);
 940        i740outreg(par, VGA_CRT_IC, EXT_START_ADDR,
 941                        ((base & 0x003F0000) >> 16) | EXT_START_ADDR_ENABLE);
 942
 943        return 0;
 944}
 945
 946static int i740fb_blank(int blank_mode, struct fb_info *info)
 947{
 948        struct i740fb_par *par = info->par;
 949
 950        unsigned char SEQ01;
 951        int DPMSSyncSelect;
 952
 953        switch (blank_mode) {
 954        case FB_BLANK_UNBLANK:
 955        case FB_BLANK_NORMAL:
 956                SEQ01 = 0x00;
 957                DPMSSyncSelect = HSYNC_ON | VSYNC_ON;
 958                break;
 959        case FB_BLANK_VSYNC_SUSPEND:
 960                SEQ01 = 0x20;
 961                DPMSSyncSelect = HSYNC_ON | VSYNC_OFF;
 962                break;
 963        case FB_BLANK_HSYNC_SUSPEND:
 964                SEQ01 = 0x20;
 965                DPMSSyncSelect = HSYNC_OFF | VSYNC_ON;
 966                break;
 967        case FB_BLANK_POWERDOWN:
 968                SEQ01 = 0x20;
 969                DPMSSyncSelect = HSYNC_OFF | VSYNC_OFF;
 970                break;
 971        default:
 972                return -EINVAL;
 973        }
 974        /* Turn the screen on/off */
 975        i740outb(par, SRX, 0x01);
 976        SEQ01 |= i740inb(par, SRX + 1) & ~0x20;
 977        i740outb(par, SRX, 0x01);
 978        i740outb(par, SRX + 1, SEQ01);
 979
 980        /* Set the DPMS mode */
 981        i740outreg(par, XRX, DPMS_SYNC_SELECT, DPMSSyncSelect);
 982
 983        /* Let fbcon do a soft blank for us */
 984        return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
 985}
 986
 987static const struct fb_ops i740fb_ops = {
 988        .owner          = THIS_MODULE,
 989        .fb_open        = i740fb_open,
 990        .fb_release     = i740fb_release,
 991        .fb_check_var   = i740fb_check_var,
 992        .fb_set_par     = i740fb_set_par,
 993        .fb_setcolreg   = i740fb_setcolreg,
 994        .fb_blank       = i740fb_blank,
 995        .fb_pan_display = i740fb_pan_display,
 996        .fb_fillrect    = cfb_fillrect,
 997        .fb_copyarea    = cfb_copyarea,
 998        .fb_imageblit   = cfb_imageblit,
 999};
1000
1001/* ------------------------------------------------------------------------- */
1002
1003static int i740fb_probe(struct pci_dev *dev, const struct pci_device_id *ent)
1004{
1005        struct fb_info *info;
1006        struct i740fb_par *par;
1007        int ret, tmp;
1008        bool found = false;
1009        u8 *edid;
1010
1011        info = framebuffer_alloc(sizeof(struct i740fb_par), &(dev->dev));
1012        if (!info)
1013                return -ENOMEM;
1014
1015        par = info->par;
1016        mutex_init(&par->open_lock);
1017
1018        info->var.activate = FB_ACTIVATE_NOW;
1019        info->var.bits_per_pixel = 8;
1020        info->fbops = &i740fb_ops;
1021        info->pseudo_palette = par->pseudo_palette;
1022
1023        ret = pci_enable_device(dev);
1024        if (ret) {
1025                dev_err(info->device, "cannot enable PCI device\n");
1026                goto err_enable_device;
1027        }
1028
1029        ret = pci_request_regions(dev, info->fix.id);
1030        if (ret) {
1031                dev_err(info->device, "error requesting regions\n");
1032                goto err_request_regions;
1033        }
1034
1035        info->screen_base = pci_ioremap_wc_bar(dev, 0);
1036        if (!info->screen_base) {
1037                dev_err(info->device, "error remapping base\n");
1038                ret = -ENOMEM;
1039                goto err_ioremap_1;
1040        }
1041
1042        par->regs = pci_ioremap_bar(dev, 1);
1043        if (!par->regs) {
1044                dev_err(info->device, "error remapping MMIO\n");
1045                ret = -ENOMEM;
1046                goto err_ioremap_2;
1047        }
1048
1049        /* detect memory size */
1050        if ((i740inreg(par, XRX, DRAM_ROW_TYPE) & DRAM_ROW_1)
1051                                                        == DRAM_ROW_1_SDRAM)
1052                i740outb(par, XRX, DRAM_ROW_BNDRY_1);
1053        else
1054                i740outb(par, XRX, DRAM_ROW_BNDRY_0);
1055        info->screen_size = i740inb(par, XRX + 1) * 1024 * 1024;
1056        /* detect memory type */
1057        tmp = i740inreg(par, XRX, DRAM_ROW_CNTL_LO);
1058        par->has_sgram = !((tmp & DRAM_RAS_TIMING) ||
1059                           (tmp & DRAM_RAS_PRECHARGE));
1060
1061        fb_info(info, "Intel740 on %s, %ld KB %s\n",
1062                pci_name(dev), info->screen_size >> 10,
1063                par->has_sgram ? "SGRAM" : "SDRAM");
1064
1065        info->fix = i740fb_fix;
1066        info->fix.mmio_start = pci_resource_start(dev, 1);
1067        info->fix.mmio_len = pci_resource_len(dev, 1);
1068        info->fix.smem_start = pci_resource_start(dev, 0);
1069        info->fix.smem_len = info->screen_size;
1070        info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1071
1072        if (i740fb_setup_ddc_bus(info) == 0) {
1073                par->ddc_registered = true;
1074                edid = fb_ddc_read(&par->ddc_adapter);
1075                if (edid) {
1076                        fb_edid_to_monspecs(edid, &info->monspecs);
1077                        kfree(edid);
1078                        if (!info->monspecs.modedb)
1079                                dev_err(info->device,
1080                                        "error getting mode database\n");
1081                        else {
1082                                const struct fb_videomode *m;
1083
1084                                fb_videomode_to_modelist(
1085                                        info->monspecs.modedb,
1086                                        info->monspecs.modedb_len,
1087                                        &info->modelist);
1088                                m = fb_find_best_display(&info->monspecs,
1089                                                         &info->modelist);
1090                                if (m) {
1091                                        fb_videomode_to_var(&info->var, m);
1092                                        /* fill all other info->var's fields */
1093                                        if (!i740fb_check_var(&info->var, info))
1094                                                found = true;
1095                                }
1096                        }
1097                }
1098        }
1099
1100        if (!mode_option && !found)
1101                mode_option = "640x480-8@60";
1102
1103        if (mode_option) {
1104                ret = fb_find_mode(&info->var, info, mode_option,
1105                                   info->monspecs.modedb,
1106                                   info->monspecs.modedb_len,
1107                                   NULL, info->var.bits_per_pixel);
1108                if (!ret || ret == 4) {
1109                        dev_err(info->device, "mode %s not found\n",
1110                                mode_option);
1111                        ret = -EINVAL;
1112                }
1113        }
1114
1115        fb_destroy_modedb(info->monspecs.modedb);
1116        info->monspecs.modedb = NULL;
1117
1118        /* maximize virtual vertical size for fast scrolling */
1119        info->var.yres_virtual = info->fix.smem_len * 8 /
1120                        (info->var.bits_per_pixel * info->var.xres_virtual);
1121
1122        if (ret == -EINVAL)
1123                goto err_find_mode;
1124
1125        ret = fb_alloc_cmap(&info->cmap, 256, 0);
1126        if (ret) {
1127                dev_err(info->device, "cannot allocate colormap\n");
1128                goto err_alloc_cmap;
1129        }
1130
1131        ret = register_framebuffer(info);
1132        if (ret) {
1133                dev_err(info->device, "error registering framebuffer\n");
1134                goto err_reg_framebuffer;
1135        }
1136
1137        fb_info(info, "%s frame buffer device\n", info->fix.id);
1138        pci_set_drvdata(dev, info);
1139        if (mtrr)
1140                par->wc_cookie = arch_phys_wc_add(info->fix.smem_start,
1141                                                  info->fix.smem_len);
1142        return 0;
1143
1144err_reg_framebuffer:
1145        fb_dealloc_cmap(&info->cmap);
1146err_alloc_cmap:
1147err_find_mode:
1148        if (par->ddc_registered)
1149                i2c_del_adapter(&par->ddc_adapter);
1150        pci_iounmap(dev, par->regs);
1151err_ioremap_2:
1152        pci_iounmap(dev, info->screen_base);
1153err_ioremap_1:
1154        pci_release_regions(dev);
1155err_request_regions:
1156/*      pci_disable_device(dev); */
1157err_enable_device:
1158        framebuffer_release(info);
1159        return ret;
1160}
1161
1162static void i740fb_remove(struct pci_dev *dev)
1163{
1164        struct fb_info *info = pci_get_drvdata(dev);
1165
1166        if (info) {
1167                struct i740fb_par *par = info->par;
1168                arch_phys_wc_del(par->wc_cookie);
1169                unregister_framebuffer(info);
1170                fb_dealloc_cmap(&info->cmap);
1171                if (par->ddc_registered)
1172                        i2c_del_adapter(&par->ddc_adapter);
1173                pci_iounmap(dev, par->regs);
1174                pci_iounmap(dev, info->screen_base);
1175                pci_release_regions(dev);
1176/*              pci_disable_device(dev); */
1177                framebuffer_release(info);
1178        }
1179}
1180
1181static int __maybe_unused i740fb_suspend(struct device *dev)
1182{
1183        struct fb_info *info = dev_get_drvdata(dev);
1184        struct i740fb_par *par = info->par;
1185
1186        console_lock();
1187        mutex_lock(&(par->open_lock));
1188
1189        /* do nothing if framebuffer is not active */
1190        if (par->ref_count == 0) {
1191                mutex_unlock(&(par->open_lock));
1192                console_unlock();
1193                return 0;
1194        }
1195
1196        fb_set_suspend(info, 1);
1197
1198        mutex_unlock(&(par->open_lock));
1199        console_unlock();
1200
1201        return 0;
1202}
1203
1204static int __maybe_unused i740fb_resume(struct device *dev)
1205{
1206        struct fb_info *info = dev_get_drvdata(dev);
1207        struct i740fb_par *par = info->par;
1208
1209        console_lock();
1210        mutex_lock(&(par->open_lock));
1211
1212        if (par->ref_count == 0)
1213                goto fail;
1214
1215        i740fb_set_par(info);
1216        fb_set_suspend(info, 0);
1217
1218fail:
1219        mutex_unlock(&(par->open_lock));
1220        console_unlock();
1221        return 0;
1222}
1223
1224static const struct dev_pm_ops i740fb_pm_ops = {
1225#ifdef CONFIG_PM_SLEEP
1226        .suspend        = i740fb_suspend,
1227        .resume         = i740fb_resume,
1228        .freeze         = NULL,
1229        .thaw           = i740fb_resume,
1230        .poweroff       = i740fb_suspend,
1231        .restore        = i740fb_resume,
1232#endif /* CONFIG_PM_SLEEP */
1233};
1234
1235#define I740_ID_PCI 0x00d1
1236#define I740_ID_AGP 0x7800
1237
1238static const struct pci_device_id i740fb_id_table[] = {
1239        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, I740_ID_PCI) },
1240        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, I740_ID_AGP) },
1241        { 0 }
1242};
1243MODULE_DEVICE_TABLE(pci, i740fb_id_table);
1244
1245static struct pci_driver i740fb_driver = {
1246        .name           = "i740fb",
1247        .id_table       = i740fb_id_table,
1248        .probe          = i740fb_probe,
1249        .remove         = i740fb_remove,
1250        .driver.pm      = &i740fb_pm_ops,
1251};
1252
1253#ifndef MODULE
1254static int  __init i740fb_setup(char *options)
1255{
1256        char *opt;
1257
1258        if (!options || !*options)
1259                return 0;
1260
1261        while ((opt = strsep(&options, ",")) != NULL) {
1262                if (!*opt)
1263                        continue;
1264                else if (!strncmp(opt, "mtrr:", 5))
1265                        mtrr = simple_strtoul(opt + 5, NULL, 0);
1266                else
1267                        mode_option = opt;
1268        }
1269
1270        return 0;
1271}
1272#endif
1273
1274static int __init i740fb_init(void)
1275{
1276#ifndef MODULE
1277        char *option = NULL;
1278
1279        if (fb_get_options("i740fb", &option))
1280                return -ENODEV;
1281        i740fb_setup(option);
1282#endif
1283
1284        return pci_register_driver(&i740fb_driver);
1285}
1286
1287static void __exit i740fb_exit(void)
1288{
1289        pci_unregister_driver(&i740fb_driver);
1290}
1291
1292module_init(i740fb_init);
1293module_exit(i740fb_exit);
1294
1295MODULE_AUTHOR("(c) 2011 Ondrej Zary <linux@rainbow-software.org>");
1296MODULE_LICENSE("GPL");
1297MODULE_DESCRIPTION("fbdev driver for Intel740");
1298
1299module_param(mode_option, charp, 0444);
1300MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)");
1301
1302module_param(mtrr, int, 0444);
1303MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");
1304