2 * i740fb - framebuffer driver for Intel740
3 * Copyright (c) 2011 Ondrej Zary
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,
11 * i740fb by Patrick LERDA, v0.9
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/errno.h>
17 #include <linux/string.h>
19 #include <linux/slab.h>
20 #include <linux/delay.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>
36 static char *mode_option __devinitdata
;
39 static int mtrr __devinitdata
= 1;
43 unsigned char __iomem
*regs
;
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
;
62 /* i740 specific registers */
69 u8 video_clk2_mn_msbs
;
70 u8 video_clk2_div_sel
;
77 u8 ext_vert_sync_start
;
78 u8 ext_vert_blank_start
;
83 u32 lmi_fifo_watermark
;
89 #define DACSPEED16 163
90 #define DACSPEED24_SG 136
91 #define DACSPEED24_SD 128
94 static struct fb_fix_screeninfo i740fb_fix __devinitdata
= {
96 .type
= FB_TYPE_PACKED_PIXELS
,
97 .visual
= FB_VISUAL_TRUECOLOR
,
100 .accel
= FB_ACCEL_NONE
,
103 static inline void i740outb(struct i740fb_par
*par
, u16 port
, u8 val
)
105 vga_mm_w(par
->regs
, port
, val
);
107 static inline u8
i740inb(struct i740fb_par
*par
, u16 port
)
109 return vga_mm_r(par
->regs
, port
);
111 static inline void i740outreg(struct i740fb_par
*par
, u16 port
, u8 reg
, u8 val
)
113 vga_mm_w_fast(par
->regs
, port
, reg
, val
);
115 static inline u8
i740inreg(struct i740fb_par
*par
, u16 port
, u8 reg
)
117 vga_mm_w(par
->regs
, port
, reg
);
118 return vga_mm_r(par
->regs
, port
+1);
120 static inline void i740outreg_mask(struct i740fb_par
*par
, u16 port
, u8 reg
,
123 vga_mm_w_fast(par
->regs
, port
, reg
, (val
& mask
)
124 | (i740inreg(par
, port
, reg
) & ~mask
));
127 #define REG_DDC_DRIVE 0x62
128 #define REG_DDC_STATE 0x63
129 #define DDC_SCL (1 << 3)
130 #define DDC_SDA (1 << 2)
132 static void i740fb_ddc_setscl(void *data
, int val
)
134 struct i740fb_par
*par
= data
;
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
);
140 static void i740fb_ddc_setsda(void *data
, int val
)
142 struct i740fb_par
*par
= data
;
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
);
148 static int i740fb_ddc_getscl(void *data
)
150 struct i740fb_par
*par
= data
;
152 i740outreg_mask(par
, XRX
, REG_DDC_DRIVE
, 0, DDC_SCL
);
154 return !!(i740inreg(par
, XRX
, REG_DDC_STATE
) & DDC_SCL
);
157 static int i740fb_ddc_getsda(void *data
)
159 struct i740fb_par
*par
= data
;
161 i740outreg_mask(par
, XRX
, REG_DDC_DRIVE
, 0, DDC_SDA
);
163 return !!(i740inreg(par
, XRX
, REG_DDC_STATE
) & DDC_SDA
);
166 static int __devinit
i740fb_setup_ddc_bus(struct fb_info
*info
)
168 struct i740fb_par
*par
= info
->par
;
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
;
184 i2c_set_adapdata(&par
->ddc_adapter
, par
);
186 return i2c_bit_add_bus(&par
->ddc_adapter
);
189 static int i740fb_open(struct fb_info
*info
, int user
)
191 struct i740fb_par
*par
= info
->par
;
193 mutex_lock(&(par
->open_lock
));
195 mutex_unlock(&(par
->open_lock
));
200 static int i740fb_release(struct fb_info
*info
, int user
)
202 struct i740fb_par
*par
= info
->par
;
204 mutex_lock(&(par
->open_lock
));
205 if (par
->ref_count
== 0) {
206 printk(KERN_ERR
"fb%d: release called with zero refcount\n",
208 mutex_unlock(&(par
->open_lock
));
213 mutex_unlock(&(par
->open_lock
));
218 static u32
i740_calc_fifo(struct i740fb_par
*par
, u32 freq
, int bpp
)
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.
243 if (par
->has_sgram
) {
280 if (par
->has_sgram
) {
315 if (par
->has_sgram
) {
344 /* clock calculation from i740fb by Patrick LERDA */
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 */
353 static void i740_calc_vclk(u32 freq
, struct i740fb_par
*par
)
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
;
359 int m_best
= 0, n_best
= 0, p_best
= 0, d_best
= 0;
362 p_best
= min(15, ilog2(I740_MAX_VCO_FREQ
/ (freq
/ I740_RFREQ_FIX
)));
364 f_vco
= (freq
* (1 << p_best
)) / I740_RFREQ_FIX
;
365 freq
= freq
/ I740_RFREQ_FIX
;
370 m
= ((f_vco
* n
) / I740_REF_FREQ
+ 2) / 4;
376 u32 f_out
= (((m
* I740_REF_FREQ
* (4 << 2 * d_best
))
377 / n
) + ((1 << p_best
) / 2)) / (1 << p_best
);
379 f_err
= (freq
- f_out
);
381 if (abs(f_err
) < err_max
) {
387 } while ((abs(f_err
) >= err_target
) &&
388 ((n
<= TARGET_MAX_N
) || (abs(err_best
) > err_max
)));
390 if (abs(f_err
) < err_target
) {
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
);
403 static int i740fb_decode_var(const struct fb_var_screeninfo
*var
,
404 struct i740fb_par
*par
, struct fb_info
*info
)
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.
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
;
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
,
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
,
432 bpp
= var
->bits_per_pixel
;
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
);
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
);
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
);
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
);
472 xres
= ALIGN(var
->xres
, 8);
473 vxres
= ALIGN(var
->xres_virtual
, 16);
477 xoffset
= ALIGN(var
->xoffset
, 8);
478 if (xres
+ xoffset
> vxres
)
479 xoffset
= vxres
- xres
;
481 left
= ALIGN(var
->left_margin
, 8);
482 right
= ALIGN(var
->right_margin
, 8);
483 hslen
= ALIGN(var
->hsync_len
, 8);
486 vyres
= var
->yres_virtual
;
490 yoffset
= var
->yoffset
;
491 if (yres
+ yoffset
> vyres
)
492 yoffset
= vyres
- yres
;
494 lower
= var
->lower_margin
;
495 vslen
= var
->vsync_len
;
496 upper
= var
->upper_margin
;
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);
505 if (yoffset
+ yres
> vyres
)
506 yoffset
= vyres
- yres
;
508 xtotal
= xres
+ right
+ hslen
+ left
;
509 ytotal
= yres
+ lower
+ vslen
+ upper
;
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)
520 par
->crtc
[VGA_CRTC_V_TOTAL
] = ytotal
- 2;
522 r7
= 0x10; /* disable linecompare */
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)
539 if ((yres
-1) & 0x200)
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)
546 if ((yres
+ lower
- 1) & 0x200) {
547 par
->crtc
[VGA_CRTC_MAX_SCAN
] |= 0x20;
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;
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
;
562 par
->vss
= 0x00; /* 3DA */
564 for (i
= 0x00; i
< 0x10; 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;
572 if (var
->sync
& FB_SYNC_HOR_HIGH_ACT
)
574 if (var
->sync
& FB_SYNC_VERT_HIGH_ACT
)
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;
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;
592 base
= (yoffset
* vxres
+ (xoffset
& ~7)) >> 2;
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
;
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
;
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. */
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 */
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;
632 par
->pixelpipe_cfg0
= DAC_8_BIT
;
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
;
639 /* Set the MCLK freq */
640 par
->pll_cntl
= PLL_MEMCLK_100000KHZ
; /* 100 MHz -- use as default */
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;
650 par
->interlace_cntl
= INTERLACE_DISABLE
;
652 /* Set the overscan color to 0. (NOTE: This only affects >8bpp mode) */
653 par
->atc
[VGA_ATC_OVERSCAN
] = 0;
655 /* Calculate VCLK that most closely matches the requested dot clock */
656 i740_calc_vclk((((u32
)1e9
) / var
->pixclock
) * (u32
)(1e3
), par
);
658 /* Since we program the clocks ourselves, always use VCLK2. */
661 /* Calculate the FIFO Watermark and Burst Length. */
662 par
->lmi_fifo_watermark
=
663 i740_calc_fifo(par
, 1000000 / var
->pixclock
, bpp
);
668 static int i740fb_check_var(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
670 switch (var
->bits_per_pixel
) {
672 var
->red
.offset
= var
->green
.offset
= var
->blue
.offset
= 0;
673 var
->red
.length
= var
->green
.length
= var
->blue
.length
= 8;
676 switch (var
->green
.length
) {
679 var
->red
.offset
= 10;
680 var
->green
.offset
= 5;
681 var
->blue
.offset
= 0;
683 var
->green
.length
= 5;
684 var
->blue
.length
= 5;
687 var
->red
.offset
= 11;
688 var
->green
.offset
= 5;
689 var
->blue
.offset
= 0;
690 var
->red
.length
= var
->blue
.length
= 5;
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;
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;
712 if (var
->xres
> var
->xres_virtual
)
713 var
->xres_virtual
= var
->xres
;
715 if (var
->yres
> var
->yres_virtual
)
716 var
->yres_virtual
= var
->yres
;
718 if (info
->monspecs
.hfmax
&& info
->monspecs
.vfmax
&&
719 info
->monspecs
.dclkmax
&& fb_validate_mode(var
, info
) < 0)
725 static void vga_protect(struct i740fb_par
*par
)
727 /* disable the display */
728 i740outreg_mask(par
, VGA_SEQ_I
, VGA_SEQ_CLOCK_MODE
, 0x20, 0x20);
731 i740outb(par
, VGA_ATT_W
, 0x00); /* enable palette access */
734 static void vga_unprotect(struct i740fb_par
*par
)
736 /* reenable display */
737 i740outreg_mask(par
, VGA_SEQ_I
, VGA_SEQ_CLOCK_MODE
, 0, 0x20);
740 i740outb(par
, VGA_ATT_W
, 0x20); /* disable palette access */
743 static int i740fb_set_par(struct fb_info
*info
)
745 struct i740fb_par
*par
= info
->par
;
749 i
= i740fb_decode_var(&info
->var
, par
, info
);
753 memset(info
->screen_base
, 0, info
->screen_size
);
757 i740outreg(par
, XRX
, DRAM_EXT_CNTL
, DRAM_REFRESH_DISABLE
);
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
);
766 i740outreg_mask(par
, XRX
, PIXPIPE_CONFIG_0
,
767 par
->pixelpipe_cfg0
& DAC_8_BIT
, 0x80);
770 i740outb(par
, 0x3C0, 0x00);
772 /* update misc output register */
773 i740outb(par
, VGA_MIS_W
, par
->misc
| 0x01);
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
]);
783 /* synchronous reset off */
784 i740outreg(par
, VGA_SEQ_I
, VGA_SEQ_RESET
, 0x03);
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
]);
790 /* write CRT registers */
791 for (i
= 0; i
< VGA_CRT_C
; i
++)
792 i740outreg(par
, VGA_CRT_IC
, i
, par
->crtc
[i
]);
794 /* write graphics controller registers */
795 for (i
= 0; i
< VGA_GFX_C
; i
++)
796 i740outreg(par
, VGA_GFX_I
, i
, par
->gdc
[i
]);
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
]);
805 i740inb(par
, VGA_IS1_RC
);
806 i740outb(par
, VGA_ATT_IW
, 0x20);
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
);
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);
829 i740outreg(par
, XRX
, PLL_CNTL
, par
->pll_cntl
);
831 i740outreg_mask(par
, XRX
, PIXPIPE_CONFIG_1
,
832 par
->pixelpipe_cfg1
, DISPLAY_COLOR_MODE
);
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
);
839 i740outreg(par
, XRX
, DRAM_EXT_CNTL
, DRAM_REFRESH_60HZ
);
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
);
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
);
856 /* Wait for screen to stabilize. */
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
;
865 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
870 static int i740fb_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
871 unsigned blue
, unsigned transp
,
872 struct fb_info
*info
)
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
);
879 switch (info
->fix
.visual
) {
880 case FB_VISUAL_PSEUDOCOLOR
:
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);
888 case FB_VISUAL_TRUECOLOR
:
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
;
906 static int i740fb_pan_display(struct fb_var_screeninfo
*var
,
907 struct fb_info
*info
)
909 struct i740fb_par
*par
= info
->par
;
910 u32 base
= (var
->yoffset
* info
->var
.xres_virtual
911 + (var
->xoffset
& ~7)) >> 2;
913 dev_dbg(info
->device
, "pan_display: xoffset: %i yoffset: %i base: %i\n",
914 var
->xoffset
, var
->yoffset
, base
);
916 switch (info
->var
.bits_per_pixel
) {
925 * The last bit does not seem to have any effect on the start
926 * address register in 24bpp mode, so...
928 base
&= 0xFFFFFFFE; /* ...ignore the last bit. */
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
;
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
);
953 static int i740fb_blank(int blank_mode
, struct fb_info
*info
)
955 struct i740fb_par
*par
= info
->par
;
960 switch (blank_mode
) {
961 case FB_BLANK_UNBLANK
:
962 case FB_BLANK_NORMAL
:
964 DPMSSyncSelect
= HSYNC_ON
| VSYNC_ON
;
966 case FB_BLANK_VSYNC_SUSPEND
:
968 DPMSSyncSelect
= HSYNC_ON
| VSYNC_OFF
;
970 case FB_BLANK_HSYNC_SUSPEND
:
972 DPMSSyncSelect
= HSYNC_OFF
| VSYNC_ON
;
974 case FB_BLANK_POWERDOWN
:
976 DPMSSyncSelect
= HSYNC_OFF
| VSYNC_OFF
;
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
);
987 /* Set the DPMS mode */
988 i740outreg(par
, XRX
, DPMS_SYNC_SELECT
, DPMSSyncSelect
);
990 /* Let fbcon do a soft blank for us */
991 return (blank_mode
== FB_BLANK_NORMAL
) ? 1 : 0;
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
,
1008 /* ------------------------------------------------------------------------- */
1010 static int __devinit
i740fb_probe(struct pci_dev
*dev
,
1011 const struct pci_device_id
*ent
)
1013 struct fb_info
*info
;
1014 struct i740fb_par
*par
;
1019 info
= framebuffer_alloc(sizeof(struct i740fb_par
), &(dev
->dev
));
1021 dev_err(&(dev
->dev
), "cannot allocate framebuffer\n");
1026 mutex_init(&par
->open_lock
);
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
;
1033 ret
= pci_enable_device(dev
);
1035 dev_err(info
->device
, "cannot enable PCI device\n");
1036 goto err_enable_device
;
1039 ret
= pci_request_regions(dev
, info
->fix
.id
);
1041 dev_err(info
->device
, "error requesting regions\n");
1042 goto err_request_regions
;
1045 info
->screen_base
= pci_ioremap_bar(dev
, 0);
1046 if (!info
->screen_base
) {
1047 dev_err(info
->device
, "error remapping base\n");
1052 par
->regs
= pci_ioremap_bar(dev
, 1);
1054 dev_err(info
->device
, "error remapping MMIO\n");
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
);
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
));
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");
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
;
1082 if (i740fb_setup_ddc_bus(info
) == 0) {
1083 par
->ddc_registered
= true;
1084 edid
= fb_ddc_read(&par
->ddc_adapter
);
1086 fb_edid_to_monspecs(edid
, &info
->monspecs
);
1088 if (!info
->monspecs
.modedb
)
1089 dev_err(info
->device
,
1090 "error getting mode database\n");
1092 const struct fb_videomode
*m
;
1094 fb_videomode_to_modelist(
1095 info
->monspecs
.modedb
,
1096 info
->monspecs
.modedb_len
,
1098 m
= fb_find_best_display(&info
->monspecs
,
1101 fb_videomode_to_var(&info
->var
, m
);
1102 /* fill all other info->var's fields */
1103 if (!i740fb_check_var(&info
->var
, info
))
1110 if (!mode_option
&& !found
)
1111 mode_option
= "640x480-8@60";
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",
1125 fb_destroy_modedb(info
->monspecs
.modedb
);
1126 info
->monspecs
.modedb
= NULL
;
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
);
1135 ret
= fb_alloc_cmap(&info
->cmap
, 256, 0);
1137 dev_err(info
->device
, "cannot allocate colormap\n");
1138 goto err_alloc_cmap
;
1141 ret
= register_framebuffer(info
);
1143 dev_err(info
->device
, "error registering framebuffer\n");
1144 goto err_reg_framebuffer
;
1147 printk(KERN_INFO
"fb%d: %s frame buffer device\n",
1148 info
->node
, info
->fix
.id
);
1149 pci_set_drvdata(dev
, info
);
1153 par
->mtrr_reg
= mtrr_add(info
->fix
.smem_start
,
1154 info
->fix
.smem_len
, MTRR_TYPE_WRCOMB
, 1);
1159 err_reg_framebuffer
:
1160 fb_dealloc_cmap(&info
->cmap
);
1163 if (par
->ddc_registered
)
1164 i2c_del_adapter(&par
->ddc_adapter
);
1165 pci_iounmap(dev
, par
->regs
);
1167 pci_iounmap(dev
, info
->screen_base
);
1169 pci_release_regions(dev
);
1170 err_request_regions
:
1171 /* pci_disable_device(dev); */
1173 framebuffer_release(info
);
1177 static void __devexit
i740fb_remove(struct pci_dev
*dev
)
1179 struct fb_info
*info
= pci_get_drvdata(dev
);
1182 struct i740fb_par
*par
= info
->par
;
1185 if (par
->mtrr_reg
>= 0) {
1186 mtrr_del(par
->mtrr_reg
, 0, 0);
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
);
1204 static int i740fb_suspend(struct pci_dev
*dev
, pm_message_t state
)
1206 struct fb_info
*info
= pci_get_drvdata(dev
);
1207 struct i740fb_par
*par
= info
->par
;
1209 /* don't disable console during hibernation and wakeup from it */
1210 if (state
.event
== PM_EVENT_FREEZE
|| state
.event
== PM_EVENT_PRETHAW
)
1214 mutex_lock(&(par
->open_lock
));
1216 /* do nothing if framebuffer is not active */
1217 if (par
->ref_count
== 0) {
1218 mutex_unlock(&(par
->open_lock
));
1223 fb_set_suspend(info
, 1);
1225 pci_save_state(dev
);
1226 pci_disable_device(dev
);
1227 pci_set_power_state(dev
, pci_choose_state(dev
, state
));
1229 mutex_unlock(&(par
->open_lock
));
1235 static int i740fb_resume(struct pci_dev
*dev
)
1237 struct fb_info
*info
= pci_get_drvdata(dev
);
1238 struct i740fb_par
*par
= info
->par
;
1241 mutex_lock(&(par
->open_lock
));
1243 if (par
->ref_count
== 0)
1246 pci_set_power_state(dev
, PCI_D0
);
1247 pci_restore_state(dev
);
1248 if (pci_enable_device(dev
))
1251 i740fb_set_par(info
);
1252 fb_set_suspend(info
, 0);
1255 mutex_unlock(&(par
->open_lock
));
1260 #define i740fb_suspend NULL
1261 #define i740fb_resume NULL
1262 #endif /* CONFIG_PM */
1264 #define I740_ID_PCI 0x00d1
1265 #define I740_ID_AGP 0x7800
1267 static 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
) },
1272 MODULE_DEVICE_TABLE(pci
, i740fb_id_table
);
1274 static struct pci_driver i740fb_driver
= {
1276 .id_table
= i740fb_id_table
,
1277 .probe
= i740fb_probe
,
1278 .remove
= __devexit_p(i740fb_remove
),
1279 .suspend
= i740fb_suspend
,
1280 .resume
= i740fb_resume
,
1284 static int __init
i740fb_setup(char *options
)
1288 if (!options
|| !*options
)
1291 while ((opt
= strsep(&options
, ",")) != NULL
) {
1295 else if (!strncmp(opt
, "mtrr:", 5))
1296 mtrr
= simple_strtoul(opt
+ 5, NULL
, 0);
1306 int __init
i740fb_init(void)
1309 char *option
= NULL
;
1311 if (fb_get_options("i740fb", &option
))
1313 i740fb_setup(option
);
1316 return pci_register_driver(&i740fb_driver
);
1319 static void __exit
i740fb_exit(void)
1321 pci_unregister_driver(&i740fb_driver
);
1324 module_init(i740fb_init
);
1325 module_exit(i740fb_exit
);
1327 MODULE_AUTHOR("(c) 2011 Ondrej Zary <linux@rainbow-software.org>");
1328 MODULE_LICENSE("GPL");
1329 MODULE_DESCRIPTION("fbdev driver for Intel740");
1331 module_param(mode_option
, charp
, 0444);
1332 MODULE_PARM_DESC(mode_option
, "Default video mode ('640x480-8@60', etc)");
1335 module_param(mtrr
, int, 0444);
1336 MODULE_PARM_DESC(mtrr
, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");