aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOndrej Zary <linux@rainbow-software.org>2012-02-10 12:59:17 -0500
committerFlorian Tobias Schandinat <FlorianSchandinat@gmx.de>2012-02-14 23:31:21 -0500
commit5350c65f4f15bbc111ffa629130d3f32cdd4ccf6 (patch)
tree4b1c24c9175376195b0a883f46b76dd9304ea3b0
parente9474be4eb6918c91cb0d296f9744e8ec0e08c11 (diff)
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>
-rw-r--r--drivers/video/Kconfig12
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/i740_reg.h309
-rw-r--r--drivers/video/i740fb.c1337
4 files changed, 1659 insertions, 0 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index e61d7ce35595..8951cbd2d2fc 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1123,6 +1123,18 @@ config FB_RIVA_BACKLIGHT
1123 help 1123 help
1124 Say Y here if you want to control the backlight of your display. 1124 Say Y here if you want to control the backlight of your display.
1125 1125
1126config 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
1126config FB_I810 1138config FB_I810
1127 tristate "Intel 810/815 support (EXPERIMENTAL)" 1139 tristate "Intel 810/815 support (EXPERIMENTAL)"
1128 depends on EXPERIMENTAL && FB && PCI && X86_32 && AGP_INTEL 1140 depends on EXPERIMENTAL && FB && PCI && X86_32 && AGP_INTEL
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 274b04ebedec..9356add945b3 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_FB_GRVGA) += grvga.o
39obj-$(CONFIG_FB_PM2) += pm2fb.o 39obj-$(CONFIG_FB_PM2) += pm2fb.o
40obj-$(CONFIG_FB_PM3) += pm3fb.o 40obj-$(CONFIG_FB_PM3) += pm3fb.o
41 41
42obj-$(CONFIG_FB_I740) += i740fb.o
42obj-$(CONFIG_FB_MATROX) += matrox/ 43obj-$(CONFIG_FB_MATROX) += matrox/
43obj-$(CONFIG_FB_RIVA) += riva/ 44obj-$(CONFIG_FB_RIVA) += riva/
44obj-$(CONFIG_FB_NVIDIA) += nvidia/ 45obj-$(CONFIG_FB_NVIDIA) += nvidia/
diff --git a/drivers/video/i740_reg.h b/drivers/video/i740_reg.h
new file mode 100644
index 000000000000..91bac76549d7
--- /dev/null
+++ b/drivers/video/i740_reg.h
@@ -0,0 +1,309 @@
1/**************************************************************************
2
3Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
4All Rights Reserved.
5
6Permission is hereby granted, free of charge, to any person obtaining a
7copy of this software and associated documentation files (the
8"Software"), to deal in the Software without restriction, including
9without limitation the rights to use, copy, modify, merge, publish,
10distribute, sub license, and/or sell copies of the Software, and to
11permit persons to whom the Software is furnished to do so, subject to
12the following conditions:
13
14The above copyright notice and this permission notice (including the
15next paragraph) shall be included in all copies or substantial portions
16of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
22ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24SOFTWARE 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
diff --git a/drivers/video/i740fb.c b/drivers/video/i740fb.c
new file mode 100644
index 000000000000..8be030221343
--- /dev/null
+++ b/drivers/video/i740fb.c
@@ -0,0 +1,1337 @@
1/*
2 * i740fb - framebuffer driver for Intel740
3 * Copyright (c) 2011 Ondrej Zary
4 *
5 * Based on old i740fb driver (c) 2001-2002 Andrey Ulanov <drey@rt.mipt.ru>
6 * which was partially based on:
7 * VGA 16-color framebuffer driver (c) 1999 Ben Pfaff <pfaffben@debian.org>
8 * and Petr Vandrovec <VANDROVE@vc.cvut.cz>
9 * i740 driver from XFree86 (c) 1998-1999 Precision Insight, Inc., Cedar Park,
10 * Texas.
11 * i740fb by Patrick LERDA, v0.9
12 */
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/errno.h>
17#include <linux/string.h>
18#include <linux/mm.h>
19#include <linux/slab.h>
20#include <linux/delay.h>
21#include <linux/fb.h>
22#include <linux/init.h>
23#include <linux/pci.h>
24#include <linux/pci_ids.h>
25#include <linux/i2c.h>
26#include <linux/i2c-algo-bit.h>
27#include <linux/console.h>
28#include <video/vga.h>
29
30#ifdef CONFIG_MTRR
31#include <asm/mtrr.h>
32#endif
33
34#include "i740_reg.h"
35
36static char *mode_option __devinitdata;
37
38#ifdef CONFIG_MTRR
39static int mtrr __devinitdata = 1;
40#endif
41
42struct i740fb_par {
43 unsigned char __iomem *regs;
44 bool has_sgram;
45#ifdef CONFIG_MTRR
46 int mtrr_reg;
47#endif
48 bool ddc_registered;
49 struct i2c_adapter ddc_adapter;
50 struct i2c_algo_bit_data ddc_algo;
51 u32 pseudo_palette[16];
52 struct mutex open_lock;
53 unsigned int ref_count;
54
55 u8 crtc[VGA_CRT_C];
56 u8 atc[VGA_ATT_C];
57 u8 gdc[VGA_GFX_C];
58 u8 seq[VGA_SEQ_C];
59 u8 misc;
60 u8 vss;
61
62 /* i740 specific registers */
63 u8 display_cntl;
64 u8 pixelpipe_cfg0;
65 u8 pixelpipe_cfg1;
66 u8 pixelpipe_cfg2;
67 u8 video_clk2_m;
68 u8 video_clk2_n;
69 u8 video_clk2_mn_msbs;
70 u8 video_clk2_div_sel;
71 u8 pll_cntl;
72 u8 address_mapping;
73 u8 io_cntl;
74 u8 bitblt_cntl;
75 u8 ext_vert_total;
76 u8 ext_vert_disp_end;
77 u8 ext_vert_sync_start;
78 u8 ext_vert_blank_start;
79 u8 ext_horiz_total;
80 u8 ext_horiz_blank;
81 u8 ext_offset;
82 u8 interlace_cntl;
83 u32 lmi_fifo_watermark;
84 u8 ext_start_addr;
85 u8 ext_start_addr_hi;
86};
87
88#define DACSPEED8 203
89#define DACSPEED16 163
90#define DACSPEED24_SG 136
91#define DACSPEED24_SD 128
92#define DACSPEED32 86
93
94static struct fb_fix_screeninfo i740fb_fix __devinitdata = {
95 .id = "i740fb",
96 .type = FB_TYPE_PACKED_PIXELS,
97 .visual = FB_VISUAL_TRUECOLOR,
98 .xpanstep = 8,
99 .ypanstep = 1,
100 .accel = FB_ACCEL_NONE,
101};
102
103static inline void i740outb(struct i740fb_par *par, u16 port, u8 val)
104{
105 vga_mm_w(par->regs, port, val);
106}
107static inline u8 i740inb(struct i740fb_par *par, u16 port)
108{
109 return vga_mm_r(par->regs, port);
110}
111static inline void i740outreg(struct i740fb_par *par, u16 port, u8 reg, u8 val)
112{
113 vga_mm_w_fast(par->regs, port, reg, val);
114}
115static inline u8 i740inreg(struct i740fb_par *par, u16 port, u8 reg)
116{
117 vga_mm_w(par->regs, port, reg);
118 return vga_mm_r(par->regs, port+1);
119}
120static inline void i740outreg_mask(struct i740fb_par *par, u16 port, u8 reg,
121 u8 val, u8 mask)
122{
123 vga_mm_w_fast(par->regs, port, reg, (val & mask)
124 | (i740inreg(par, port, reg) & ~mask));
125}
126
127#define REG_DDC_DRIVE 0x62
128#define REG_DDC_STATE 0x63
129#define DDC_SCL (1 << 3)
130#define DDC_SDA (1 << 2)
131
132static void i740fb_ddc_setscl(void *data, int val)
133{
134 struct i740fb_par *par = data;
135
136 i740outreg_mask(par, XRX, REG_DDC_DRIVE, DDC_SCL, DDC_SCL);
137 i740outreg_mask(par, XRX, REG_DDC_STATE, val ? DDC_SCL : 0, DDC_SCL);
138}
139
140static void i740fb_ddc_setsda(void *data, int val)
141{
142 struct i740fb_par *par = data;
143
144 i740outreg_mask(par, XRX, REG_DDC_DRIVE, DDC_SDA, DDC_SDA);
145 i740outreg_mask(par, XRX, REG_DDC_STATE, val ? DDC_SDA : 0, DDC_SDA);
146}
147
148static int i740fb_ddc_getscl(void *data)
149{
150 struct i740fb_par *par = data;
151
152 i740outreg_mask(par, XRX, REG_DDC_DRIVE, 0, DDC_SCL);
153
154 return !!(i740inreg(par, XRX, REG_DDC_STATE) & DDC_SCL);
155}
156
157static int i740fb_ddc_getsda(void *data)
158{
159 struct i740fb_par *par = data;
160
161 i740outreg_mask(par, XRX, REG_DDC_DRIVE, 0, DDC_SDA);
162
163 return !!(i740inreg(par, XRX, REG_DDC_STATE) & DDC_SDA);
164}
165
166static int __devinit i740fb_setup_ddc_bus(struct fb_info *info)
167{
168 struct i740fb_par *par = info->par;
169
170 strlcpy(par->ddc_adapter.name, info->fix.id,
171 sizeof(par->ddc_adapter.name));
172 par->ddc_adapter.owner = THIS_MODULE;
173 par->ddc_adapter.class = I2C_CLASS_DDC;
174 par->ddc_adapter.algo_data = &par->ddc_algo;
175 par->ddc_adapter.dev.parent = info->device;
176 par->ddc_algo.setsda = i740fb_ddc_setsda;
177 par->ddc_algo.setscl = i740fb_ddc_setscl;
178 par->ddc_algo.getsda = i740fb_ddc_getsda;
179 par->ddc_algo.getscl = i740fb_ddc_getscl;
180 par->ddc_algo.udelay = 10;
181 par->ddc_algo.timeout = 20;
182 par->ddc_algo.data = par;
183
184 i2c_set_adapdata(&par->ddc_adapter, par);
185
186 return i2c_bit_add_bus(&par->ddc_adapter);
187}
188
189static int i740fb_open(struct fb_info *info, int user)
190{
191 struct i740fb_par *par = info->par;
192
193 mutex_lock(&(par->open_lock));
194 par->ref_count++;
195 mutex_unlock(&(par->open_lock));
196
197 return 0;
198}
199
200static int i740fb_release(struct fb_info *info, int user)
201{
202 struct i740fb_par *par = info->par;
203
204 mutex_lock(&(par->open_lock));
205 if (par->ref_count == 0) {
206 printk(KERN_ERR "fb%d: release called with zero refcount\n",
207 info->node);
208 mutex_unlock(&(par->open_lock));
209 return -EINVAL;
210 }
211
212 par->ref_count--;
213 mutex_unlock(&(par->open_lock));
214
215 return 0;
216}
217
218static u32 i740_calc_fifo(struct i740fb_par *par, u32 freq, int bpp)
219{
220 /*
221 * Would like to calculate these values automatically, but a generic
222 * algorithm does not seem possible. Note: These FIFO water mark
223 * values were tested on several cards and seem to eliminate the
224 * all of the snow and vertical banding, but fine adjustments will
225 * probably be required for other cards.
226 */
227
228 u32 wm;
229
230 switch (bpp) {
231 case 8:
232 if (freq > 200)
233 wm = 0x18120000;
234 else if (freq > 175)
235 wm = 0x16110000;
236 else if (freq > 135)
237 wm = 0x120E0000;
238 else
239 wm = 0x100D0000;
240 break;
241 case 15:
242 case 16:
243 if (par->has_sgram) {
244 if (freq > 140)
245 wm = 0x2C1D0000;
246 else if (freq > 120)
247 wm = 0x2C180000;
248 else if (freq > 100)
249 wm = 0x24160000;
250 else if (freq > 90)
251 wm = 0x18120000;
252 else if (freq > 50)
253 wm = 0x16110000;
254 else if (freq > 32)
255 wm = 0x13100000;
256 else
257 wm = 0x120E0000;
258 } else {
259 if (freq > 160)
260 wm = 0x28200000;
261 else if (freq > 140)
262 wm = 0x2A1E0000;
263 else if (freq > 130)
264 wm = 0x2B1A0000;
265 else if (freq > 120)
266 wm = 0x2C180000;
267 else if (freq > 100)
268 wm = 0x24180000;
269 else if (freq > 90)
270 wm = 0x18120000;
271 else if (freq > 50)
272 wm = 0x16110000;
273 else if (freq > 32)
274 wm = 0x13100000;
275 else
276 wm = 0x120E0000;
277 }
278 break;
279 case 24:
280 if (par->has_sgram) {
281 if (freq > 130)
282 wm = 0x31200000;
283 else if (freq > 120)
284 wm = 0x2E200000;
285 else if (freq > 100)
286 wm = 0x2C1D0000;
287 else if (freq > 80)
288 wm = 0x25180000;
289 else if (freq > 64)
290 wm = 0x24160000;
291 else if (freq > 49)
292 wm = 0x18120000;
293 else if (freq > 32)
294 wm = 0x16110000;
295 else
296 wm = 0x13100000;
297 } else {
298 if (freq > 120)
299 wm = 0x311F0000;
300 else if (freq > 100)
301 wm = 0x2C1D0000;
302 else if (freq > 80)
303 wm = 0x25180000;
304 else if (freq > 64)
305 wm = 0x24160000;
306 else if (freq > 49)
307 wm = 0x18120000;
308 else if (freq > 32)
309 wm = 0x16110000;
310 else
311 wm = 0x13100000;
312 }
313 break;
314 case 32:
315 if (par->has_sgram) {
316 if (freq > 80)
317 wm = 0x2A200000;
318 else if (freq > 60)
319 wm = 0x281A0000;
320 else if (freq > 49)
321 wm = 0x25180000;
322 else if (freq > 32)
323 wm = 0x18120000;
324 else
325 wm = 0x16110000;
326 } else {
327 if (freq > 80)
328 wm = 0x29200000;
329 else if (freq > 60)
330 wm = 0x281A0000;
331 else if (freq > 49)
332 wm = 0x25180000;
333 else if (freq > 32)
334 wm = 0x18120000;
335 else
336 wm = 0x16110000;
337 }
338 break;
339 }
340
341 return wm;
342}
343
344/* clock calculation from i740fb by Patrick LERDA */
345
346#define I740_RFREQ 1000000
347#define TARGET_MAX_N 30
348#define I740_FFIX (1 << 8)
349#define I740_RFREQ_FIX (I740_RFREQ / I740_FFIX)
350#define I740_REF_FREQ (6667 * I740_FFIX / 100) /* 66.67 MHz */
351#define I740_MAX_VCO_FREQ (450 * I740_FFIX) /* 450 MHz */
352
353static void i740_calc_vclk(u32 freq, struct i740fb_par *par)
354{
355 const u32 err_max = freq / (200 * I740_RFREQ / I740_FFIX);
356 const u32 err_target = freq / (1000 * I740_RFREQ / I740_FFIX);
357 u32 err_best = 512 * I740_FFIX;
358 u32 f_err, f_vco;
359 int m_best = 0, n_best = 0, p_best = 0, d_best = 0;
360 int m, n;
361
362 p_best = min(15, ilog2(I740_MAX_VCO_FREQ / (freq / I740_RFREQ_FIX)));
363 d_best = 0;
364 f_vco = (freq * (1 << p_best)) / I740_RFREQ_FIX;
365 freq = freq / I740_RFREQ_FIX;
366
367 n = 2;
368 do {
369 n++;
370 m = ((f_vco * n) / I740_REF_FREQ + 2) / 4;
371
372 if (m < 3)
373 m = 3;
374
375 {
376 u32 f_out = (((m * I740_REF_FREQ * (4 << 2 * d_best))
377 / n) + ((1 << p_best) / 2)) / (1 << p_best);
378
379 f_err = (freq - f_out);
380
381 if (abs(f_err) < err_max) {
382 m_best = m;
383 n_best = n;
384 err_best = f_err;
385 }
386 }
387 } while ((abs(f_err) >= err_target) &&
388 ((n <= TARGET_MAX_N) || (abs(err_best) > err_max)));
389
390 if (abs(f_err) < err_target) {
391 m_best = m;
392 n_best = n;
393 }
394
395 par->video_clk2_m = (m_best - 2) & 0xFF;
396 par->video_clk2_n = (n_best - 2) & 0xFF;
397 par->video_clk2_mn_msbs = ((((n_best - 2) >> 4) & VCO_N_MSBS)
398 | (((m_best - 2) >> 8) & VCO_M_MSBS));
399 par->video_clk2_div_sel =
400 ((p_best << 4) | (d_best ? 4 : 0) | REF_DIV_1);
401}
402
403static int i740fb_decode_var(const struct fb_var_screeninfo *var,
404 struct i740fb_par *par, struct fb_info *info)
405{
406 /*
407 * Get the video params out of 'var'.
408 * If a value doesn't fit, round it up, if it's too big, return -EINVAL.
409 */
410
411 u32 xres, right, hslen, left, xtotal;
412 u32 yres, lower, vslen, upper, ytotal;
413 u32 vxres, xoffset, vyres, yoffset;
414 u32 bpp, base, dacspeed24, mem;
415 u8 r7;
416 int i;
417
418 dev_dbg(info->device, "decode_var: xres: %i, yres: %i, xres_v: %i, xres_v: %i\n",
419 var->xres, var->yres, var->xres_virtual, var->xres_virtual);
420 dev_dbg(info->device, " xoff: %i, yoff: %i, bpp: %i, graysc: %i\n",
421 var->xoffset, var->yoffset, var->bits_per_pixel,
422 var->grayscale);
423 dev_dbg(info->device, " activate: %i, nonstd: %i, vmode: %i\n",
424 var->activate, var->nonstd, var->vmode);
425 dev_dbg(info->device, " pixclock: %i, hsynclen:%i, vsynclen:%i\n",
426 var->pixclock, var->hsync_len, var->vsync_len);
427 dev_dbg(info->device, " left: %i, right: %i, up:%i, lower:%i\n",
428 var->left_margin, var->right_margin, var->upper_margin,
429 var->lower_margin);
430
431
432 bpp = var->bits_per_pixel;
433 switch (bpp) {
434 case 1 ... 8:
435 bpp = 8;
436 if ((1000000 / var->pixclock) > DACSPEED8) {
437 dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 8bpp)\n",
438 1000000 / var->pixclock, DACSPEED8);
439 return -EINVAL;
440 }
441 break;
442 case 9 ... 15:
443 bpp = 15;
444 case 16:
445 if ((1000000 / var->pixclock) > DACSPEED16) {
446 dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 15/16bpp)\n",
447 1000000 / var->pixclock, DACSPEED16);
448 return -EINVAL;
449 }
450 break;
451 case 17 ... 24:
452 bpp = 24;
453 dacspeed24 = par->has_sgram ? DACSPEED24_SG : DACSPEED24_SD;
454 if ((1000000 / var->pixclock) > dacspeed24) {
455 dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 24bpp)\n",
456 1000000 / var->pixclock, dacspeed24);
457 return -EINVAL;
458 }
459 break;
460 case 25 ... 32:
461 bpp = 32;
462 if ((1000000 / var->pixclock) > DACSPEED32) {
463 dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 32bpp)\n",
464 1000000 / var->pixclock, DACSPEED32);
465 return -EINVAL;
466 }
467 break;
468 default:
469 return -EINVAL;
470 }
471
472 xres = ALIGN(var->xres, 8);
473 vxres = ALIGN(var->xres_virtual, 16);
474 if (vxres < xres)
475 vxres = xres;
476
477 xoffset = ALIGN(var->xoffset, 8);
478 if (xres + xoffset > vxres)
479 xoffset = vxres - xres;
480
481 left = ALIGN(var->left_margin, 8);
482 right = ALIGN(var->right_margin, 8);
483 hslen = ALIGN(var->hsync_len, 8);
484
485 yres = var->yres;
486 vyres = var->yres_virtual;
487 if (yres > vyres)
488 vyres = yres;
489
490 yoffset = var->yoffset;
491 if (yres + yoffset > vyres)
492 yoffset = vyres - yres;
493
494 lower = var->lower_margin;
495 vslen = var->vsync_len;
496 upper = var->upper_margin;
497
498 mem = vxres * vyres * ((bpp + 1) / 8);
499 if (mem > info->screen_size) {
500 dev_err(info->device, "not enough video memory (%d KB requested, %ld KB 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
668static int i740fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
669{
670 switch (var->bits_per_pixel) {
671 case 8:
672 var->red.offset = var->green.offset = var->blue.offset = 0;
673 var->red.length = var->green.length = var->blue.length = 8;
674 break;
675 case 16:
676 switch (var->green.length) {
677 default:
678 case 5:
679 var->red.offset = 10;
680 var->green.offset = 5;
681 var->blue.offset = 0;
682 var->red.length = 5;
683 var->green.length = 5;
684 var->blue.length = 5;
685 break;
686 case 6:
687 var->red.offset = 11;
688 var->green.offset = 5;
689 var->blue.offset = 0;
690 var->red.length = var->blue.length = 5;
691 break;
692 }
693 break;
694 case 24:
695 var->red.offset = 16;
696 var->green.offset = 8;
697 var->blue.offset = 0;
698 var->red.length = var->green.length = var->blue.length = 8;
699 break;
700 case 32:
701 var->transp.offset = 24;
702 var->red.offset = 16;
703 var->green.offset = 8;
704 var->blue.offset = 0;
705 var->transp.length = 8;
706 var->red.length = var->green.length = var->blue.length = 8;
707 break;
708 default:
709 return -EINVAL;
710 }
711
712 if (var->xres > var->xres_virtual)
713 var->xres_virtual = var->xres;
714
715 if (var->yres > var->yres_virtual)
716 var->yres_virtual = var->yres;
717
718 if (info->monspecs.hfmax && info->monspecs.vfmax &&
719 info->monspecs.dclkmax && fb_validate_mode(var, info) < 0)
720 return -EINVAL;
721
722 return 0;
723}
724
725static void vga_protect(struct i740fb_par *par)
726{
727 /* disable the display */
728 i740outreg_mask(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE, 0x20, 0x20);
729
730 i740inb(par, 0x3DA);
731 i740outb(par, VGA_ATT_W, 0x00); /* enable pallete access */
732}
733
734static void vga_unprotect(struct i740fb_par *par)
735{
736 /* reenable display */
737 i740outreg_mask(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE, 0, 0x20);
738
739 i740inb(par, 0x3DA);
740 i740outb(par, VGA_ATT_W, 0x20); /* disable pallete access */
741}
742
743static int i740fb_set_par(struct fb_info *info)
744{
745 struct i740fb_par *par = info->par;
746 u32 itemp;
747 int i;
748
749 i = i740fb_decode_var(&info->var, par, info);
750 if (i)
751 return i;
752
753 memset(info->screen_base, 0, info->screen_size);
754
755 vga_protect(par);
756
757 i740outreg(par, XRX, DRAM_EXT_CNTL, DRAM_REFRESH_DISABLE);
758
759 mdelay(1);
760
761 i740outreg(par, XRX, VCLK2_VCO_M, par->video_clk2_m);
762 i740outreg(par, XRX, VCLK2_VCO_N, par->video_clk2_n);
763 i740outreg(par, XRX, VCLK2_VCO_MN_MSBS, par->video_clk2_mn_msbs);
764 i740outreg(par, XRX, VCLK2_VCO_DIV_SEL, par->video_clk2_div_sel);
765
766 i740outreg_mask(par, XRX, PIXPIPE_CONFIG_0,
767 par->pixelpipe_cfg0 & DAC_8_BIT, 0x80);
768
769 i740inb(par, 0x3DA);
770 i740outb(par, 0x3C0, 0x00);
771
772 /* update misc output register */
773 i740outb(par, VGA_MIS_W, par->misc | 0x01);
774
775 /* synchronous reset on */
776 i740outreg(par, VGA_SEQ_I, VGA_SEQ_RESET, 0x01);
777 /* write sequencer registers */
778 i740outreg(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE,
779 par->seq[VGA_SEQ_CLOCK_MODE] | 0x20);
780 for (i = 2; i < VGA_SEQ_C; i++)
781 i740outreg(par, VGA_SEQ_I, i, par->seq[i]);
782
783 /* synchronous reset off */
784 i740outreg(par, VGA_SEQ_I, VGA_SEQ_RESET, 0x03);
785
786 /* deprotect CRT registers 0-7 */
787 i740outreg(par, VGA_CRT_IC, VGA_CRTC_V_SYNC_END,
788 par->crtc[VGA_CRTC_V_SYNC_END]);
789
790 /* write CRT registers */
791 for (i = 0; i < VGA_CRT_C; i++)
792 i740outreg(par, VGA_CRT_IC, i, par->crtc[i]);
793
794 /* write graphics controller registers */
795 for (i = 0; i < VGA_GFX_C; i++)
796 i740outreg(par, VGA_GFX_I, i, par->gdc[i]);
797
798 /* write attribute controller registers */
799 for (i = 0; i < VGA_ATT_C; i++) {
800 i740inb(par, VGA_IS1_RC); /* reset flip-flop */
801 i740outb(par, VGA_ATT_IW, i);
802 i740outb(par, VGA_ATT_IW, par->atc[i]);
803 }
804
805 i740inb(par, VGA_IS1_RC);
806 i740outb(par, VGA_ATT_IW, 0x20);
807
808 i740outreg(par, VGA_CRT_IC, EXT_VERT_TOTAL, par->ext_vert_total);
809 i740outreg(par, VGA_CRT_IC, EXT_VERT_DISPLAY, par->ext_vert_disp_end);
810 i740outreg(par, VGA_CRT_IC, EXT_VERT_SYNC_START,
811 par->ext_vert_sync_start);
812 i740outreg(par, VGA_CRT_IC, EXT_VERT_BLANK_START,
813 par->ext_vert_blank_start);
814 i740outreg(par, VGA_CRT_IC, EXT_HORIZ_TOTAL, par->ext_horiz_total);
815 i740outreg(par, VGA_CRT_IC, EXT_HORIZ_BLANK, par->ext_horiz_blank);
816 i740outreg(par, VGA_CRT_IC, EXT_OFFSET, par->ext_offset);
817 i740outreg(par, VGA_CRT_IC, EXT_START_ADDR_HI, par->ext_start_addr_hi);
818 i740outreg(par, VGA_CRT_IC, EXT_START_ADDR, par->ext_start_addr);
819
820 i740outreg_mask(par, VGA_CRT_IC, INTERLACE_CNTL,
821 par->interlace_cntl, INTERLACE_ENABLE);
822 i740outreg_mask(par, XRX, ADDRESS_MAPPING, par->address_mapping, 0x1F);
823 i740outreg_mask(par, XRX, BITBLT_CNTL, par->bitblt_cntl, COLEXP_MODE);
824 i740outreg_mask(par, XRX, DISPLAY_CNTL,
825 par->display_cntl, VGA_WRAP_MODE | GUI_MODE);
826 i740outreg_mask(par, XRX, PIXPIPE_CONFIG_0, par->pixelpipe_cfg0, 0x9B);
827 i740outreg_mask(par, XRX, PIXPIPE_CONFIG_2, par->pixelpipe_cfg2, 0x0C);
828
829 i740outreg(par, XRX, PLL_CNTL, par->pll_cntl);
830
831 i740outreg_mask(par, XRX, PIXPIPE_CONFIG_1,
832 par->pixelpipe_cfg1, DISPLAY_COLOR_MODE);
833
834 itemp = readl(par->regs + FWATER_BLC);
835 itemp &= ~(LMI_BURST_LENGTH | LMI_FIFO_WATERMARK);
836 itemp |= par->lmi_fifo_watermark;
837 writel(itemp, par->regs + FWATER_BLC);
838
839 i740outreg(par, XRX, DRAM_EXT_CNTL, DRAM_REFRESH_60HZ);
840
841 i740outreg_mask(par, MRX, COL_KEY_CNTL_1, 0, BLANK_DISP_OVERLAY);
842 i740outreg_mask(par, XRX, IO_CTNL,
843 par->io_cntl, EXTENDED_ATTR_CNTL | EXTENDED_CRTC_CNTL);
844
845 if (par->pixelpipe_cfg1 != DISPLAY_8BPP_MODE) {
846 i740outb(par, VGA_PEL_MSK, 0xFF);
847 i740outb(par, VGA_PEL_IW, 0x00);
848 for (i = 0; i < 256; i++) {
849 itemp = (par->pixelpipe_cfg0 & DAC_8_BIT) ? i : i >> 2;
850 i740outb(par, VGA_PEL_D, itemp);
851 i740outb(par, VGA_PEL_D, itemp);
852 i740outb(par, VGA_PEL_D, itemp);
853 }
854 }
855
856 /* Wait for screen to stabilize. */
857 mdelay(50);
858 vga_unprotect(par);
859
860 info->fix.line_length =
861 info->var.xres_virtual * info->var.bits_per_pixel / 8;
862 if (info->var.bits_per_pixel == 8)
863 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
864 else
865 info->fix.visual = FB_VISUAL_TRUECOLOR;
866
867 return 0;
868}
869
870static int i740fb_setcolreg(unsigned regno, unsigned red, unsigned green,
871 unsigned blue, unsigned transp,
872 struct fb_info *info)
873{
874 u32 r, g, b;
875
876 dev_dbg(info->device, "setcolreg: regno: %i, red=%d, green=%d, blue=%d, transp=%d, bpp=%d\n",
877 regno, red, green, blue, transp, info->var.bits_per_pixel);
878
879 switch (info->fix.visual) {
880 case FB_VISUAL_PSEUDOCOLOR:
881 if (regno >= 256)
882 return -EINVAL;
883 i740outb(info->par, VGA_PEL_IW, regno);
884 i740outb(info->par, VGA_PEL_D, red >> 8);
885 i740outb(info->par, VGA_PEL_D, green >> 8);
886 i740outb(info->par, VGA_PEL_D, blue >> 8);
887 break;
888 case FB_VISUAL_TRUECOLOR:
889 if (regno >= 16)
890 return -EINVAL;
891 r = (red >> (16 - info->var.red.length))
892 << info->var.red.offset;
893 b = (blue >> (16 - info->var.blue.length))
894 << info->var.blue.offset;
895 g = (green >> (16 - info->var.green.length))
896 << info->var.green.offset;
897 ((u32 *) info->pseudo_palette)[regno] = r | g | b;
898 break;
899 default:
900 return -EINVAL;
901 }
902
903 return 0;
904}
905
906static int i740fb_pan_display(struct fb_var_screeninfo *var,
907 struct fb_info *info)
908{
909 struct i740fb_par *par = info->par;
910 u32 base = (var->yoffset * info->var.xres_virtual
911 + (var->xoffset & ~7)) >> 2;
912
913 dev_dbg(info->device, "pan_display: xoffset: %i yoffset: %i base: %i\n",
914 var->xoffset, var->yoffset, base);
915
916 switch (info->var.bits_per_pixel) {
917 case 8:
918 break;
919 case 15:
920 case 16:
921 base *= 2;
922 break;
923 case 24:
924 /*
925 * The last bit does not seem to have any effect on the start
926 * address register in 24bpp mode, so...
927 */
928 base &= 0xFFFFFFFE; /* ...ignore the last bit. */
929 base *= 3;
930 break;
931 case 32:
932 base *= 4;
933 break;
934 }
935
936 par->crtc[VGA_CRTC_START_LO] = base & 0x000000FF;
937 par->crtc[VGA_CRTC_START_HI] = (base & 0x0000FF00) >> 8;
938 par->ext_start_addr_hi = (base & 0x3FC00000) >> 22;
939 par->ext_start_addr =
940 ((base & 0x003F0000) >> 16) | EXT_START_ADDR_ENABLE;
941
942 i740outreg(par, VGA_CRT_IC, VGA_CRTC_START_LO, base & 0x000000FF);
943 i740outreg(par, VGA_CRT_IC, VGA_CRTC_START_HI,
944 (base & 0x0000FF00) >> 8);
945 i740outreg(par, VGA_CRT_IC, EXT_START_ADDR_HI,
946 (base & 0x3FC00000) >> 22);
947 i740outreg(par, VGA_CRT_IC, EXT_START_ADDR,
948 ((base & 0x003F0000) >> 16) | EXT_START_ADDR_ENABLE);
949
950 return 0;
951}
952
953static int i740fb_blank(int blank_mode, struct fb_info *info)
954{
955 struct i740fb_par *par = info->par;
956
957 unsigned char SEQ01;
958 int DPMSSyncSelect;
959
960 switch (blank_mode) {
961 case FB_BLANK_UNBLANK:
962 case FB_BLANK_NORMAL:
963 SEQ01 = 0x00;
964 DPMSSyncSelect = HSYNC_ON | VSYNC_ON;
965 break;
966 case FB_BLANK_VSYNC_SUSPEND:
967 SEQ01 = 0x20;
968 DPMSSyncSelect = HSYNC_ON | VSYNC_OFF;
969 break;
970 case FB_BLANK_HSYNC_SUSPEND:
971 SEQ01 = 0x20;
972 DPMSSyncSelect = HSYNC_OFF | VSYNC_ON;
973 break;
974 case FB_BLANK_POWERDOWN:
975 SEQ01 = 0x20;
976 DPMSSyncSelect = HSYNC_OFF | VSYNC_OFF;
977 break;
978 default:
979 return -EINVAL;
980 }
981 /* Turn the screen on/off */
982 i740outb(par, SRX, 0x01);
983 SEQ01 |= i740inb(par, SRX + 1) & ~0x20;
984 i740outb(par, SRX, 0x01);
985 i740outb(par, SRX + 1, SEQ01);
986
987 /* Set the DPMS mode */
988 i740outreg(par, XRX, DPMS_SYNC_SELECT, DPMSSyncSelect);
989
990 /* Let fbcon do a soft blank for us */
991 return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
992}
993
994static struct fb_ops i740fb_ops = {
995 .owner = THIS_MODULE,
996 .fb_open = i740fb_open,
997 .fb_release = i740fb_release,
998 .fb_check_var = i740fb_check_var,
999 .fb_set_par = i740fb_set_par,
1000 .fb_setcolreg = i740fb_setcolreg,
1001 .fb_blank = i740fb_blank,
1002 .fb_pan_display = i740fb_pan_display,
1003 .fb_fillrect = cfb_fillrect,
1004 .fb_copyarea = cfb_copyarea,
1005 .fb_imageblit = cfb_imageblit,
1006};
1007
1008/* ------------------------------------------------------------------------- */
1009
1010static int __devinit i740fb_probe(struct pci_dev *dev,
1011 const struct pci_device_id *ent)
1012{
1013 struct fb_info *info;
1014 struct i740fb_par *par;
1015 int ret, tmp;
1016 bool found = false;
1017 u8 *edid;
1018
1019 info = framebuffer_alloc(sizeof(struct i740fb_par), &(dev->dev));
1020 if (!info) {
1021 dev_err(&(dev->dev), "cannot allocate framebuffer\n");
1022 return -ENOMEM;
1023 }
1024
1025 par = info->par;
1026 mutex_init(&par->open_lock);
1027
1028 info->var.activate = FB_ACTIVATE_NOW;
1029 info->var.bits_per_pixel = 8;
1030 info->fbops = &i740fb_ops;
1031 info->pseudo_palette = par->pseudo_palette;
1032
1033 ret = pci_enable_device(dev);
1034 if (ret) {
1035 dev_err(info->device, "cannot enable PCI device\n");
1036 goto err_enable_device;
1037 }
1038
1039 ret = pci_request_regions(dev, info->fix.id);
1040 if (ret) {
1041 dev_err(info->device, "error requesting regions\n");
1042 goto err_request_regions;
1043 }
1044
1045 info->screen_base = pci_ioremap_bar(dev, 0);
1046 if (!info->screen_base) {
1047 dev_err(info->device, "error remapping base\n");
1048 ret = -ENOMEM;
1049 goto err_ioremap_1;
1050 }
1051
1052 par->regs = pci_ioremap_bar(dev, 1);
1053 if (!par->regs) {
1054 dev_err(info->device, "error remapping MMIO\n");
1055 ret = -ENOMEM;
1056 goto err_ioremap_2;
1057 }
1058
1059 /* detect memory size */
1060 if ((i740inreg(par, XRX, DRAM_ROW_TYPE) & DRAM_ROW_1)
1061 == DRAM_ROW_1_SDRAM)
1062 i740outb(par, XRX, DRAM_ROW_BNDRY_1);
1063 else
1064 i740outb(par, XRX, DRAM_ROW_BNDRY_0);
1065 info->screen_size = i740inb(par, XRX + 1) * 1024 * 1024;
1066 /* detect memory type */
1067 tmp = i740inreg(par, XRX, DRAM_ROW_CNTL_LO);
1068 par->has_sgram = !((tmp & DRAM_RAS_TIMING) ||
1069 (tmp & DRAM_RAS_PRECHARGE));
1070
1071 printk(KERN_INFO "fb%d: Intel740 on %s, %ld KB %s\n", info->node,
1072 pci_name(dev), info->screen_size >> 10,
1073 par->has_sgram ? "SGRAM" : "SDRAM");
1074
1075 info->fix = i740fb_fix;
1076 info->fix.mmio_start = pci_resource_start(dev, 1);
1077 info->fix.mmio_len = pci_resource_len(dev, 1);
1078 info->fix.smem_start = pci_resource_start(dev, 0);
1079 info->fix.smem_len = info->screen_size;
1080 info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1081
1082 if (i740fb_setup_ddc_bus(info) == 0) {
1083 par->ddc_registered = true;
1084 edid = fb_ddc_read(&par->ddc_adapter);
1085 if (edid) {
1086 fb_edid_to_monspecs(edid, &info->monspecs);
1087 kfree(edid);
1088 if (!info->monspecs.modedb)
1089 dev_err(info->device,
1090 "error getting mode database\n");
1091 else {
1092 const struct fb_videomode *m;
1093
1094 fb_videomode_to_modelist(
1095 info->monspecs.modedb,
1096 info->monspecs.modedb_len,
1097 &info->modelist);
1098 m = fb_find_best_display(&info->monspecs,
1099 &info->modelist);
1100 if (m) {
1101 fb_videomode_to_var(&info->var, m);
1102 /* fill all other info->var's fields */
1103 if (!i740fb_check_var(&info->var, info))
1104 found = true;
1105 }
1106 }
1107 }
1108 }
1109
1110 if (!mode_option && !found)
1111 mode_option = "640x480-8@60";
1112
1113 if (mode_option) {
1114 ret = fb_find_mode(&info->var, info, mode_option,
1115 info->monspecs.modedb,
1116 info->monspecs.modedb_len,
1117 NULL, info->var.bits_per_pixel);
1118 if (!ret || ret == 4) {
1119 dev_err(info->device, "mode %s not found\n",
1120 mode_option);
1121 ret = -EINVAL;
1122 }
1123 }
1124
1125 fb_destroy_modedb(info->monspecs.modedb);
1126 info->monspecs.modedb = NULL;
1127
1128 /* maximize virtual vertical size for fast scrolling */
1129 info->var.yres_virtual = info->fix.smem_len * 8 /
1130 (info->var.bits_per_pixel * info->var.xres_virtual);
1131
1132 if (ret == -EINVAL)
1133 goto err_find_mode;
1134
1135 ret = fb_alloc_cmap(&info->cmap, 256, 0);
1136 if (ret) {
1137 dev_err(info->device, "cannot allocate colormap\n");
1138 goto err_alloc_cmap;
1139 }
1140
1141 ret = register_framebuffer(info);
1142 if (ret) {
1143 dev_err(info->device, "error registering framebuffer\n");
1144 goto err_reg_framebuffer;
1145 }
1146
1147 printk(KERN_INFO "fb%d: %s frame buffer device\n",
1148 info->node, info->fix.id);
1149 pci_set_drvdata(dev, info);
1150#ifdef CONFIG_MTRR
1151 if (mtrr) {
1152 par->mtrr_reg = -1;
1153 par->mtrr_reg = mtrr_add(info->fix.smem_start,
1154 info->fix.smem_len, MTRR_TYPE_WRCOMB, 1);
1155 }
1156#endif
1157 return 0;
1158
1159err_reg_framebuffer:
1160 fb_dealloc_cmap(&info->cmap);
1161err_alloc_cmap:
1162err_find_mode:
1163 if (par->ddc_registered)
1164 i2c_del_adapter(&par->ddc_adapter);
1165 pci_iounmap(dev, par->regs);
1166err_ioremap_2:
1167 pci_iounmap(dev, info->screen_base);
1168err_ioremap_1:
1169 pci_release_regions(dev);
1170err_request_regions:
1171/* pci_disable_device(dev); */
1172err_enable_device:
1173 framebuffer_release(info);
1174 return ret;
1175}
1176
1177static void __devexit i740fb_remove(struct pci_dev *dev)
1178{
1179 struct fb_info *info = pci_get_drvdata(dev);
1180
1181 if (info) {
1182#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
1204static int i740fb_suspend(struct pci_dev *dev, pm_message_t state)
1205{
1206 struct fb_info *info = pci_get_drvdata(dev);
1207 struct i740fb_par *par = info->par;
1208
1209 /* don't disable console during hibernation and wakeup from it */
1210 if (state.event == PM_EVENT_FREEZE || state.event == PM_EVENT_PRETHAW)
1211 return 0;
1212
1213 console_lock();
1214 mutex_lock(&(par->open_lock));
1215
1216 /* do nothing if framebuffer is not active */
1217 if (par->ref_count == 0) {
1218 mutex_unlock(&(par->open_lock));
1219 console_unlock();
1220 return 0;
1221 }
1222
1223 fb_set_suspend(info, 1);
1224
1225 pci_save_state(dev);
1226 pci_disable_device(dev);
1227 pci_set_power_state(dev, pci_choose_state(dev, state));
1228
1229 mutex_unlock(&(par->open_lock));
1230 console_unlock();
1231
1232 return 0;
1233}
1234
1235static int i740fb_resume(struct pci_dev *dev)
1236{
1237 struct fb_info *info = pci_get_drvdata(dev);
1238 struct i740fb_par *par = info->par;
1239
1240 console_lock();
1241 mutex_lock(&(par->open_lock));
1242
1243 if (par->ref_count == 0)
1244 goto fail;
1245
1246 pci_set_power_state(dev, PCI_D0);
1247 pci_restore_state(dev);
1248 if (pci_enable_device(dev))
1249 goto fail;
1250
1251 i740fb_set_par(info);
1252 fb_set_suspend(info, 0);
1253
1254fail:
1255 mutex_unlock(&(par->open_lock));
1256 console_unlock();
1257 return 0;
1258}
1259#else
1260#define i740fb_suspend NULL
1261#define i740fb_resume NULL
1262#endif /* CONFIG_PM */
1263
1264#define I740_ID_PCI 0x00d1
1265#define I740_ID_AGP 0x7800
1266
1267static DEFINE_PCI_DEVICE_TABLE(i740fb_id_table) = {
1268 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, I740_ID_PCI) },
1269 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, I740_ID_AGP) },
1270 { 0 }
1271};
1272MODULE_DEVICE_TABLE(pci, i740fb_id_table);
1273
1274static struct pci_driver i740fb_driver = {
1275 .name = "i740fb",
1276 .id_table = i740fb_id_table,
1277 .probe = i740fb_probe,
1278 .remove = __devexit_p(i740fb_remove),
1279 .suspend = i740fb_suspend,
1280 .resume = i740fb_resume,
1281};
1282
1283#ifndef MODULE
1284static int __init i740fb_setup(char *options)
1285{
1286 char *opt;
1287
1288 if (!options || !*options)
1289 return 0;
1290
1291 while ((opt = strsep(&options, ",")) != NULL) {
1292 if (!*opt)
1293 continue;
1294#ifdef CONFIG_MTRR
1295 else if (!strncmp(opt, "mtrr:", 5))
1296 mtrr = simple_strtoul(opt + 5, NULL, 0);
1297#endif
1298 else
1299 mode_option = opt;
1300 }
1301
1302 return 0;
1303}
1304#endif
1305
1306int __init i740fb_init(void)
1307{
1308#ifndef MODULE
1309 char *option = NULL;
1310
1311 if (fb_get_options("i740fb", &option))
1312 return -ENODEV;
1313 i740fb_setup(option);
1314#endif
1315
1316 return pci_register_driver(&i740fb_driver);
1317}
1318
1319static void __exit i740fb_exit(void)
1320{
1321 pci_unregister_driver(&i740fb_driver);
1322}
1323
1324module_init(i740fb_init);
1325module_exit(i740fb_exit);
1326
1327MODULE_AUTHOR("(c) 2011 Ondrej Zary <linux@rainbow-software.org>");
1328MODULE_LICENSE("GPL");
1329MODULE_DESCRIPTION("fbdev driver for Intel740");
1330
1331module_param(mode_option, charp, 0444);
1332MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)");
1333
1334#ifdef CONFIG_MTRR
1335module_param(mtrr, int, 0444);
1336MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");
1337#endif