Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
i740fb.c
Go to the documentation of this file.
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 <[email protected]>
6  * which was partially based on:
7  * VGA 16-color framebuffer driver (c) 1999 Ben Pfaff <[email protected]>
8  * and Petr Vandrovec <[email protected]>
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 
36 static char *mode_option __devinitdata;
37 
38 #ifdef CONFIG_MTRR
39 static int mtrr __devinitdata = 1;
40 #endif
41 
42 struct i740fb_par {
43  unsigned char __iomem *regs;
44  bool has_sgram;
45 #ifdef CONFIG_MTRR
46  int mtrr_reg;
47 #endif
52  struct mutex open_lock;
53  unsigned int ref_count;
54 
61 
62  /* i740 specific registers */
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 
94 static 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 
103 static inline void i740outb(struct i740fb_par *par, u16 port, u8 val)
104 {
105  vga_mm_w(par->regs, port, val);
106 }
107 static inline u8 i740inb(struct i740fb_par *par, u16 port)
108 {
109  return vga_mm_r(par->regs, port);
110 }
111 static 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 }
115 static 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 }
120 static 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 
132 static 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 
140 static 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 
148 static 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 
157 static 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 
166 static 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 
189 static 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 
200 static 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 
218 static 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 
353 static 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 
403 static 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;
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) ?
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;
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;
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 
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 
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 
668 static 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 
725 static 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 
734 static 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 
743 static 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,
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,
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,
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,
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 
870 static 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) {
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 
906 static 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 
953 static 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;
967  SEQ01 = 0x20;
968  DPMSSyncSelect = HSYNC_ON | VSYNC_OFF;
969  break;
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 
994 static 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 
1010 static 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;
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 
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 
1159 err_reg_framebuffer:
1160  fb_dealloc_cmap(&info->cmap);
1161 err_alloc_cmap:
1162 err_find_mode:
1163  if (par->ddc_registered)
1165  pci_iounmap(dev, par->regs);
1166 err_ioremap_2:
1167  pci_iounmap(dev, info->screen_base);
1168 err_ioremap_1:
1169  pci_release_regions(dev);
1170 err_request_regions:
1171 /* pci_disable_device(dev); */
1172 err_enable_device:
1173  framebuffer_release(info);
1174  return ret;
1175 }
1176 
1177 static 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)
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
1204 static 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 
1235 static 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 
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 
1254 fail:
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 
1267 static DEFINE_PCI_DEVICE_TABLE(i740fb_id_table) = {
1270  { 0 }
1271 };
1272 MODULE_DEVICE_TABLE(pci, i740fb_id_table);
1273 
1274 static 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
1284 static 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 
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 
1319 static void __exit i740fb_exit(void)
1320 {
1321  pci_unregister_driver(&i740fb_driver);
1322 }
1323 
1325 module_exit(i740fb_exit);
1326 
1327 MODULE_AUTHOR("(c) 2011 Ondrej Zary <[email protected]>");
1328 MODULE_LICENSE("GPL");
1329 MODULE_DESCRIPTION("fbdev driver for Intel740");
1330 
1331 module_param(mode_option, charp, 0444);
1332 MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)");
1333 
1334 #ifdef CONFIG_MTRR
1335 module_param(mtrr, int, 0444);
1336 MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");
1337 #endif