Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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