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

Resurrect Intel740 driver: i740fb

This is a resurrection of an old (like 2.4.19) out-of-tree driver for
Intel740 graphics cards and adaptation for recent kernels. The old driver by
Andrey Ulanov is located at: http://sourceforge.net/projects/i740fbdev/files/

This is a new driver based on skeletonfb, using most of the low level HW code
from the old driver. The DDC code is completely new.

The driver was tested on two 8MB cards: Protac AG240D and Diamond Stealth II
G460.

Signed-off-by: Ondrej Zary <linux@rainbow-software.org>
Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>

authored by

Ondrej Zary and committed by
Florian Tobias Schandinat
5350c65f e9474be4

+1659
+12
drivers/video/Kconfig
··· 1123 1123 help 1124 1124 Say Y here if you want to control the backlight of your display. 1125 1125 1126 + config FB_I740 1127 + tristate "Intel740 support (EXPERIMENTAL)" 1128 + depends on EXPERIMENTAL && FB && PCI 1129 + select FB_MODE_HELPERS 1130 + select FB_CFB_FILLRECT 1131 + select FB_CFB_COPYAREA 1132 + select FB_CFB_IMAGEBLIT 1133 + select VGASTATE 1134 + select FB_DDC 1135 + help 1136 + This driver supports graphics cards based on Intel740 chip. 1137 + 1126 1138 config FB_I810 1127 1139 tristate "Intel 810/815 support (EXPERIMENTAL)" 1128 1140 depends on EXPERIMENTAL && FB && PCI && X86_32 && AGP_INTEL
+1
drivers/video/Makefile
··· 39 39 obj-$(CONFIG_FB_PM2) += pm2fb.o 40 40 obj-$(CONFIG_FB_PM3) += pm3fb.o 41 41 42 + obj-$(CONFIG_FB_I740) += i740fb.o 42 43 obj-$(CONFIG_FB_MATROX) += matrox/ 43 44 obj-$(CONFIG_FB_RIVA) += riva/ 44 45 obj-$(CONFIG_FB_NVIDIA) += nvidia/
+309
drivers/video/i740_reg.h
··· 1 + /************************************************************************** 2 + 3 + Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. 4 + All Rights Reserved. 5 + 6 + Permission is hereby granted, free of charge, to any person obtaining a 7 + copy of this software and associated documentation files (the 8 + "Software"), to deal in the Software without restriction, including 9 + without limitation the rights to use, copy, modify, merge, publish, 10 + distribute, sub license, and/or sell copies of the Software, and to 11 + permit persons to whom the Software is furnished to do so, subject to 12 + the following conditions: 13 + 14 + The above copyright notice and this permission notice (including the 15 + next paragraph) shall be included in all copies or substantial portions 16 + of the Software. 17 + 18 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 + IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR 22 + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 + 26 + **************************************************************************/ 27 + 28 + /* 29 + * Authors: 30 + * Kevin E. Martin <kevin@precisioninsight.com> 31 + */ 32 + 33 + /* I/O register offsets */ 34 + #define SRX VGA_SEQ_I 35 + #define GRX VGA_GFX_I 36 + #define ARX VGA_ATT_IW 37 + #define XRX 0x3D6 38 + #define MRX 0x3D2 39 + 40 + /* VGA Color Palette Registers */ 41 + #define DACMASK 0x3C6 42 + #define DACSTATE 0x3C7 43 + #define DACRX 0x3C7 44 + #define DACWX 0x3C8 45 + #define DACDATA 0x3C9 46 + 47 + /* CRT Controller Registers (CRX) */ 48 + #define START_ADDR_HI 0x0C 49 + #define START_ADDR_LO 0x0D 50 + #define VERT_SYNC_END 0x11 51 + #define EXT_VERT_TOTAL 0x30 52 + #define EXT_VERT_DISPLAY 0x31 53 + #define EXT_VERT_SYNC_START 0x32 54 + #define EXT_VERT_BLANK_START 0x33 55 + #define EXT_HORIZ_TOTAL 0x35 56 + #define EXT_HORIZ_BLANK 0x39 57 + #define EXT_START_ADDR 0x40 58 + #define EXT_START_ADDR_ENABLE 0x80 59 + #define EXT_OFFSET 0x41 60 + #define EXT_START_ADDR_HI 0x42 61 + #define INTERLACE_CNTL 0x70 62 + #define INTERLACE_ENABLE 0x80 63 + #define INTERLACE_DISABLE 0x00 64 + 65 + /* Miscellaneous Output Register */ 66 + #define MSR_R 0x3CC 67 + #define MSR_W 0x3C2 68 + #define IO_ADDR_SELECT 0x01 69 + 70 + #define MDA_BASE 0x3B0 71 + #define CGA_BASE 0x3D0 72 + 73 + /* System Configuration Extension Registers (XRX) */ 74 + #define IO_CTNL 0x09 75 + #define EXTENDED_ATTR_CNTL 0x02 76 + #define EXTENDED_CRTC_CNTL 0x01 77 + 78 + #define ADDRESS_MAPPING 0x0A 79 + #define PACKED_MODE_ENABLE 0x04 80 + #define LINEAR_MODE_ENABLE 0x02 81 + #define PAGE_MAPPING_ENABLE 0x01 82 + 83 + #define BITBLT_CNTL 0x20 84 + #define COLEXP_MODE 0x30 85 + #define COLEXP_8BPP 0x00 86 + #define COLEXP_16BPP 0x10 87 + #define COLEXP_24BPP 0x20 88 + #define COLEXP_RESERVED 0x30 89 + #define CHIP_RESET 0x02 90 + #define BITBLT_STATUS 0x01 91 + 92 + #define DISPLAY_CNTL 0x40 93 + #define VGA_WRAP_MODE 0x02 94 + #define VGA_WRAP_AT_256KB 0x00 95 + #define VGA_NO_WRAP 0x02 96 + #define GUI_MODE 0x01 97 + #define STANDARD_VGA_MODE 0x00 98 + #define HIRES_MODE 0x01 99 + 100 + #define DRAM_ROW_TYPE 0x50 101 + #define DRAM_ROW_0 0x07 102 + #define DRAM_ROW_0_SDRAM 0x00 103 + #define DRAM_ROW_0_EMPTY 0x07 104 + #define DRAM_ROW_1 0x38 105 + #define DRAM_ROW_1_SDRAM 0x00 106 + #define DRAM_ROW_1_EMPTY 0x38 107 + #define DRAM_ROW_CNTL_LO 0x51 108 + #define DRAM_CAS_LATENCY 0x10 109 + #define DRAM_RAS_TIMING 0x08 110 + #define DRAM_RAS_PRECHARGE 0x04 111 + #define DRAM_ROW_CNTL_HI 0x52 112 + #define DRAM_EXT_CNTL 0x53 113 + #define DRAM_REFRESH_RATE 0x03 114 + #define DRAM_REFRESH_DISABLE 0x00 115 + #define DRAM_REFRESH_60HZ 0x01 116 + #define DRAM_REFRESH_FAST_TEST 0x02 117 + #define DRAM_REFRESH_RESERVED 0x03 118 + #define DRAM_TIMING 0x54 119 + #define DRAM_ROW_BNDRY_0 0x55 120 + #define DRAM_ROW_BNDRY_1 0x56 121 + 122 + #define DPMS_SYNC_SELECT 0x61 123 + #define VSYNC_CNTL 0x08 124 + #define VSYNC_ON 0x00 125 + #define VSYNC_OFF 0x08 126 + #define HSYNC_CNTL 0x02 127 + #define HSYNC_ON 0x00 128 + #define HSYNC_OFF 0x02 129 + 130 + #define PIXPIPE_CONFIG_0 0x80 131 + #define DAC_8_BIT 0x80 132 + #define DAC_6_BIT 0x00 133 + #define HW_CURSOR_ENABLE 0x10 134 + #define EXTENDED_PALETTE 0x01 135 + 136 + #define PIXPIPE_CONFIG_1 0x81 137 + #define DISPLAY_COLOR_MODE 0x0F 138 + #define DISPLAY_VGA_MODE 0x00 139 + #define DISPLAY_8BPP_MODE 0x02 140 + #define DISPLAY_15BPP_MODE 0x04 141 + #define DISPLAY_16BPP_MODE 0x05 142 + #define DISPLAY_24BPP_MODE 0x06 143 + #define DISPLAY_32BPP_MODE 0x07 144 + 145 + #define PIXPIPE_CONFIG_2 0x82 146 + #define DISPLAY_GAMMA_ENABLE 0x08 147 + #define DISPLAY_GAMMA_DISABLE 0x00 148 + #define OVERLAY_GAMMA_ENABLE 0x04 149 + #define OVERLAY_GAMMA_DISABLE 0x00 150 + 151 + #define CURSOR_CONTROL 0xA0 152 + #define CURSOR_ORIGIN_SCREEN 0x00 153 + #define CURSOR_ORIGIN_DISPLAY 0x10 154 + #define CURSOR_MODE 0x07 155 + #define CURSOR_MODE_DISABLE 0x00 156 + #define CURSOR_MODE_32_4C_AX 0x01 157 + #define CURSOR_MODE_128_2C 0x02 158 + #define CURSOR_MODE_128_1C 0x03 159 + #define CURSOR_MODE_64_3C 0x04 160 + #define CURSOR_MODE_64_4C_AX 0x05 161 + #define CURSOR_MODE_64_4C 0x06 162 + #define CURSOR_MODE_RESERVED 0x07 163 + #define CURSOR_BASEADDR_LO 0xA2 164 + #define CURSOR_BASEADDR_HI 0xA3 165 + #define CURSOR_X_LO 0xA4 166 + #define CURSOR_X_HI 0xA5 167 + #define CURSOR_X_POS 0x00 168 + #define CURSOR_X_NEG 0x80 169 + #define CURSOR_Y_LO 0xA6 170 + #define CURSOR_Y_HI 0xA7 171 + #define CURSOR_Y_POS 0x00 172 + #define CURSOR_Y_NEG 0x80 173 + 174 + #define VCLK2_VCO_M 0xC8 175 + #define VCLK2_VCO_N 0xC9 176 + #define VCLK2_VCO_MN_MSBS 0xCA 177 + #define VCO_N_MSBS 0x30 178 + #define VCO_M_MSBS 0x03 179 + #define VCLK2_VCO_DIV_SEL 0xCB 180 + #define POST_DIV_SELECT 0x70 181 + #define POST_DIV_1 0x00 182 + #define POST_DIV_2 0x10 183 + #define POST_DIV_4 0x20 184 + #define POST_DIV_8 0x30 185 + #define POST_DIV_16 0x40 186 + #define POST_DIV_32 0x50 187 + #define VCO_LOOP_DIV_BY_4M 0x00 188 + #define VCO_LOOP_DIV_BY_16M 0x04 189 + #define REF_CLK_DIV_BY_5 0x02 190 + #define REF_DIV_4 0x00 191 + #define REF_DIV_1 0x01 192 + 193 + #define PLL_CNTL 0xCE 194 + #define PLL_MEMCLK_SEL 0x03 195 + #define PLL_MEMCLK__66667KHZ 0x00 196 + #define PLL_MEMCLK__75000KHZ 0x01 197 + #define PLL_MEMCLK__88889KHZ 0x02 198 + #define PLL_MEMCLK_100000KHZ 0x03 199 + 200 + /* Multimedia Extension Registers (MRX) */ 201 + #define ACQ_CNTL_1 0x02 202 + #define ACQ_CNTL_2 0x03 203 + #define FRAME_CAP_MODE 0x01 204 + #define CONT_CAP_MODE 0x00 205 + #define SINGLE_CAP_MODE 0x01 206 + #define ACQ_CNTL_3 0x04 207 + #define COL_KEY_CNTL_1 0x3C 208 + #define BLANK_DISP_OVERLAY 0x20 209 + 210 + /* FIFOs */ 211 + #define LP_FIFO 0x1000 212 + #define HP_FIFO 0x2000 213 + #define INSTPNT 0x3040 214 + #define LP_FIFO_COUNT 0x3040 215 + #define HP_FIFO_COUNT 0x3041 216 + 217 + /* FIFO Commands */ 218 + #define CLIENT 0xE0000000 219 + #define CLIENT_2D 0x60000000 220 + 221 + /* Command Parser Mode Register */ 222 + #define COMPARS 0x3038 223 + #define TWO_D_INST_DISABLE 0x08 224 + #define THREE_D_INST_DISABLE 0x04 225 + #define STATE_VAR_UPDATE_DISABLE 0x02 226 + #define PAL_STIP_DISABLE 0x01 227 + 228 + /* Interrupt Control Registers */ 229 + #define IER 0x3030 230 + #define IIR 0x3032 231 + #define IMR 0x3034 232 + #define ISR 0x3036 233 + #define VMIINTB_EVENT 0x2000 234 + #define GPIO4_INT 0x1000 235 + #define DISP_FLIP_EVENT 0x0800 236 + #define DVD_PORT_DMA 0x0400 237 + #define DISP_VBLANK 0x0200 238 + #define FIFO_EMPTY_DMA_DONE 0x0100 239 + #define INST_PARSER_ERROR 0x0080 240 + #define USER_DEFINED 0x0040 241 + #define BREAKPOINT 0x0020 242 + #define DISP_HORIZ_COUNT 0x0010 243 + #define DISP_VSYNC 0x0008 244 + #define CAPTURE_HORIZ_COUNT 0x0004 245 + #define CAPTURE_VSYNC 0x0002 246 + #define THREE_D_PIPE_FLUSHED 0x0001 247 + 248 + /* FIFO Watermark and Burst Length Control Register */ 249 + #define FWATER_BLC 0x00006000 250 + #define LMI_BURST_LENGTH 0x7F000000 251 + #define LMI_FIFO_WATERMARK 0x003F0000 252 + #define AGP_BURST_LENGTH 0x00007F00 253 + #define AGP_FIFO_WATERMARK 0x0000003F 254 + 255 + /* BitBLT Registers */ 256 + #define SRC_DST_PITCH 0x00040000 257 + #define DST_PITCH 0x1FFF0000 258 + #define SRC_PITCH 0x00001FFF 259 + #define COLEXP_BG_COLOR 0x00040004 260 + #define COLEXP_FG_COLOR 0x00040008 261 + #define MONO_SRC_CNTL 0x0004000C 262 + #define MONO_USE_COLEXP 0x00000000 263 + #define MONO_USE_SRCEXP 0x08000000 264 + #define MONO_DATA_ALIGN 0x07000000 265 + #define MONO_BIT_ALIGN 0x01000000 266 + #define MONO_BYTE_ALIGN 0x02000000 267 + #define MONO_WORD_ALIGN 0x03000000 268 + #define MONO_DWORD_ALIGN 0x04000000 269 + #define MONO_QWORD_ALIGN 0x05000000 270 + #define MONO_SRC_INIT_DSCRD 0x003F0000 271 + #define MONO_SRC_RIGHT_CLIP 0x00003F00 272 + #define MONO_SRC_LEFT_CLIP 0x0000003F 273 + #define BITBLT_CONTROL 0x00040010 274 + #define BLTR_STATUS 0x80000000 275 + #define DYN_DEPTH 0x03000000 276 + #define DYN_DEPTH_8BPP 0x00000000 277 + #define DYN_DEPTH_16BPP 0x01000000 278 + #define DYN_DEPTH_24BPP 0x02000000 279 + #define DYN_DEPTH_32BPP 0x03000000 /* Unimplemented on the i740 */ 280 + #define DYN_DEPTH_ENABLE 0x00800000 281 + #define PAT_VERT_ALIGN 0x00700000 282 + #define SOLID_PAT_SELECT 0x00080000 283 + #define PAT_IS_IN_COLOR 0x00000000 284 + #define PAT_IS_MONO 0x00040000 285 + #define MONO_PAT_TRANSP 0x00020000 286 + #define COLOR_TRANSP_ROP 0x00000000 287 + #define COLOR_TRANSP_DST 0x00008000 288 + #define COLOR_TRANSP_EQ 0x00000000 289 + #define COLOR_TRANSP_NOT_EQ 0x00010000 290 + #define COLOR_TRANSP_ENABLE 0x00004000 291 + #define MONO_SRC_TRANSP 0x00002000 292 + #define SRC_IS_IN_COLOR 0x00000000 293 + #define SRC_IS_MONO 0x00001000 294 + #define SRC_USE_SRC_ADDR 0x00000000 295 + #define SRC_USE_BLTDATA 0x00000400 296 + #define BLT_TOP_TO_BOT 0x00000000 297 + #define BLT_BOT_TO_TOP 0x00000200 298 + #define BLT_LEFT_TO_RIGHT 0x00000000 299 + #define BLT_RIGHT_TO_LEFT 0x00000100 300 + #define BLT_ROP 0x000000FF 301 + #define BLT_PAT_ADDR 0x00040014 302 + #define BLT_SRC_ADDR 0x00040018 303 + #define BLT_DST_ADDR 0x0004001C 304 + #define BLT_DST_H_W 0x00040020 305 + #define BLT_DST_HEIGHT 0x1FFF0000 306 + #define BLT_DST_WIDTH 0x00001FFF 307 + #define SRCEXP_BG_COLOR 0x00040024 308 + #define SRCEXP_FG_COLOR 0x00040028 309 + #define BLTDATA 0x00050000
+1337
drivers/video/i740fb.c
··· 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 + 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 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 + 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 avaliable)\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 + 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 pallete 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 pallete 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, 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 + 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) { 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 + 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; 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 + 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; 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 + 1159 + err_reg_framebuffer: 1160 + fb_dealloc_cmap(&info->cmap); 1161 + err_alloc_cmap: 1162 + err_find_mode: 1163 + if (par->ddc_registered) 1164 + i2c_del_adapter(&par->ddc_adapter); 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 + #ifdef CONFIG_MTRR 1183 + struct i740fb_par *par = info->par; 1184 + 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 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 + 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 + 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) = { 1268 + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, I740_ID_PCI) }, 1269 + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, I740_ID_AGP) }, 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 + 1306 + int __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 + 1319 + static void __exit i740fb_exit(void) 1320 + { 1321 + pci_unregister_driver(&i740fb_driver); 1322 + } 1323 + 1324 + module_init(i740fb_init); 1325 + module_exit(i740fb_exit); 1326 + 1327 + MODULE_AUTHOR("(c) 2011 Ondrej Zary <linux@rainbow-software.org>"); 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