diff options
Diffstat (limited to 'drivers/video/i810')
-rw-r--r-- | drivers/video/i810/Makefile | 5 | ||||
-rw-r--r-- | drivers/video/i810/i810-i2c.c | 257 | ||||
-rw-r--r-- | drivers/video/i810/i810.h | 13 | ||||
-rw-r--r-- | drivers/video/i810/i810_main.c | 177 | ||||
-rw-r--r-- | drivers/video/i810/i810_main.h | 16 |
5 files changed, 423 insertions, 45 deletions
diff --git a/drivers/video/i810/Makefile b/drivers/video/i810/Makefile index 794ae76c7c4b..96e08c8ded97 100644 --- a/drivers/video/i810/Makefile +++ b/drivers/video/i810/Makefile | |||
@@ -4,7 +4,6 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_FB_I810) += i810fb.o | 5 | obj-$(CONFIG_FB_I810) += i810fb.o |
6 | 6 | ||
7 | |||
8 | i810fb-objs := i810_main.o i810_accel.o | 7 | i810fb-objs := i810_main.o i810_accel.o |
9 | 8 | ||
10 | ifdef CONFIG_FB_I810_GTF | 9 | ifdef CONFIG_FB_I810_GTF |
@@ -12,3 +11,7 @@ i810fb-objs += i810_gtf.o | |||
12 | else | 11 | else |
13 | i810fb-objs += i810_dvt.o | 12 | i810fb-objs += i810_dvt.o |
14 | endif | 13 | endif |
14 | |||
15 | ifdef CONFIG_FB_I810_I2C | ||
16 | i810fb-objs += i810-i2c.o | ||
17 | endif | ||
diff --git a/drivers/video/i810/i810-i2c.c b/drivers/video/i810/i810-i2c.c new file mode 100644 index 000000000000..fda53aac1fc1 --- /dev/null +++ b/drivers/video/i810/i810-i2c.c | |||
@@ -0,0 +1,257 @@ | |||
1 | /*-*- linux-c -*- | ||
2 | * linux/drivers/video/i810-i2c.c -- Intel 810/815 I2C support | ||
3 | * | ||
4 | * Copyright (C) 2004 Antonino Daplas<adaplas@pol.net> | ||
5 | * All Rights Reserved | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General Public | ||
8 | * License. See the file COPYING in the main directory of this archive for | ||
9 | * more details. | ||
10 | */ | ||
11 | #include <linux/config.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/pci.h> | ||
17 | #include <linux/fb.h> | ||
18 | #include "i810.h" | ||
19 | #include "i810_regs.h" | ||
20 | #include "../edid.h" | ||
21 | |||
22 | #define I810_DDC 0x50 | ||
23 | /* bit locations in the registers */ | ||
24 | #define SCL_DIR_MASK 0x0001 | ||
25 | #define SCL_DIR 0x0002 | ||
26 | #define SCL_VAL_MASK 0x0004 | ||
27 | #define SCL_VAL_OUT 0x0008 | ||
28 | #define SCL_VAL_IN 0x0010 | ||
29 | #define SDA_DIR_MASK 0x0100 | ||
30 | #define SDA_DIR 0x0200 | ||
31 | #define SDA_VAL_MASK 0x0400 | ||
32 | #define SDA_VAL_OUT 0x0800 | ||
33 | #define SDA_VAL_IN 0x1000 | ||
34 | |||
35 | #define DEBUG /* define this for verbose EDID parsing output */ | ||
36 | |||
37 | #ifdef DEBUG | ||
38 | #define DPRINTK(fmt, args...) printk(fmt,## args) | ||
39 | #else | ||
40 | #define DPRINTK(fmt, args...) | ||
41 | #endif | ||
42 | |||
43 | static void i810i2c_setscl(void *data, int state) | ||
44 | { | ||
45 | struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; | ||
46 | struct i810fb_par *par = chan->par; | ||
47 | u8 *mmio = par->mmio_start_virtual; | ||
48 | |||
49 | i810_writel(mmio, GPIOB, (state ? SCL_VAL_OUT : 0) | SCL_DIR | | ||
50 | SCL_DIR_MASK | SCL_VAL_MASK); | ||
51 | i810_readl(mmio, GPIOB); /* flush posted write */ | ||
52 | } | ||
53 | |||
54 | static void i810i2c_setsda(void *data, int state) | ||
55 | { | ||
56 | struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; | ||
57 | struct i810fb_par *par = chan->par; | ||
58 | u8 *mmio = par->mmio_start_virtual; | ||
59 | |||
60 | i810_writel(mmio, GPIOB, (state ? SDA_VAL_OUT : 0) | SDA_DIR | | ||
61 | SDA_DIR_MASK | SDA_VAL_MASK); | ||
62 | i810_readl(mmio, GPIOB); /* flush posted write */ | ||
63 | } | ||
64 | |||
65 | static int i810i2c_getscl(void *data) | ||
66 | { | ||
67 | struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; | ||
68 | struct i810fb_par *par = chan->par; | ||
69 | u8 *mmio = par->mmio_start_virtual; | ||
70 | |||
71 | i810_writel(mmio, GPIOB, SCL_DIR_MASK); | ||
72 | i810_writel(mmio, GPIOB, 0); | ||
73 | return (0 != (i810_readl(mmio, GPIOB) & SCL_VAL_IN)); | ||
74 | } | ||
75 | |||
76 | static int i810i2c_getsda(void *data) | ||
77 | { | ||
78 | struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; | ||
79 | struct i810fb_par *par = chan->par; | ||
80 | u8 *mmio = par->mmio_start_virtual; | ||
81 | |||
82 | i810_writel(mmio, GPIOB, SDA_DIR_MASK); | ||
83 | i810_writel(mmio, GPIOB, 0); | ||
84 | return (0 != (i810_readl(mmio, GPIOB) & SDA_VAL_IN)); | ||
85 | } | ||
86 | |||
87 | static void i810ddc_setscl(void *data, int state) | ||
88 | { | ||
89 | struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; | ||
90 | struct i810fb_par *par = chan->par; | ||
91 | u8 *mmio = par->mmio_start_virtual; | ||
92 | |||
93 | i810_writel(mmio, GPIOA, (state ? SCL_VAL_OUT : 0) | SCL_DIR | | ||
94 | SCL_DIR_MASK | SCL_VAL_MASK); | ||
95 | i810_readl(mmio, GPIOA); /* flush posted write */ | ||
96 | } | ||
97 | |||
98 | static void i810ddc_setsda(void *data, int state) | ||
99 | { | ||
100 | struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; | ||
101 | struct i810fb_par *par = chan->par; | ||
102 | u8 *mmio = par->mmio_start_virtual; | ||
103 | |||
104 | i810_writel(mmio, GPIOA, (state ? SDA_VAL_OUT : 0) | SDA_DIR | | ||
105 | SDA_DIR_MASK | SDA_VAL_MASK); | ||
106 | i810_readl(mmio, GPIOA); /* flush posted write */ | ||
107 | } | ||
108 | |||
109 | static int i810ddc_getscl(void *data) | ||
110 | { | ||
111 | struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; | ||
112 | struct i810fb_par *par = chan->par; | ||
113 | u8 *mmio = par->mmio_start_virtual; | ||
114 | |||
115 | i810_writel(mmio, GPIOA, SCL_DIR_MASK); | ||
116 | i810_writel(mmio, GPIOA, 0); | ||
117 | return (0 != (i810_readl(mmio, GPIOA) & SCL_VAL_IN)); | ||
118 | } | ||
119 | |||
120 | static int i810ddc_getsda(void *data) | ||
121 | { | ||
122 | struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; | ||
123 | struct i810fb_par *par = chan->par; | ||
124 | u8 *mmio = par->mmio_start_virtual; | ||
125 | |||
126 | i810_writel(mmio, GPIOA, SDA_DIR_MASK); | ||
127 | i810_writel(mmio, GPIOA, 0); | ||
128 | return (0 != (i810_readl(mmio, GPIOA) & SDA_VAL_IN)); | ||
129 | } | ||
130 | |||
131 | #define I2C_ALGO_DDC_I810 0x0e0000 | ||
132 | #define I2C_ALGO_I2C_I810 0x0f0000 | ||
133 | static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name, | ||
134 | int conn) | ||
135 | { | ||
136 | int rc; | ||
137 | |||
138 | strcpy(chan->adapter.name, name); | ||
139 | chan->adapter.owner = THIS_MODULE; | ||
140 | chan->adapter.algo_data = &chan->algo; | ||
141 | chan->adapter.dev.parent = &chan->par->dev->dev; | ||
142 | switch (conn) { | ||
143 | case 1: | ||
144 | chan->adapter.id = I2C_ALGO_DDC_I810; | ||
145 | chan->algo.setsda = i810ddc_setsda; | ||
146 | chan->algo.setscl = i810ddc_setscl; | ||
147 | chan->algo.getsda = i810ddc_getsda; | ||
148 | chan->algo.getscl = i810ddc_getscl; | ||
149 | break; | ||
150 | case 2: | ||
151 | chan->adapter.id = I2C_ALGO_I2C_I810; | ||
152 | chan->algo.setsda = i810i2c_setsda; | ||
153 | chan->algo.setscl = i810i2c_setscl; | ||
154 | chan->algo.getsda = i810i2c_getsda; | ||
155 | chan->algo.getscl = i810i2c_getscl; | ||
156 | break; | ||
157 | } | ||
158 | chan->algo.udelay = 10; | ||
159 | chan->algo.mdelay = 10; | ||
160 | chan->algo.timeout = (HZ/2); | ||
161 | chan->algo.data = chan; | ||
162 | |||
163 | i2c_set_adapdata(&chan->adapter, chan); | ||
164 | |||
165 | /* Raise SCL and SDA */ | ||
166 | chan->algo.setsda(chan, 1); | ||
167 | chan->algo.setscl(chan, 1); | ||
168 | udelay(20); | ||
169 | |||
170 | rc = i2c_bit_add_bus(&chan->adapter); | ||
171 | if (rc == 0) | ||
172 | dev_dbg(&chan->par->dev->dev, "I2C bus %s registered.\n",name); | ||
173 | else | ||
174 | dev_warn(&chan->par->dev->dev, "Failed to register I2C bus " | ||
175 | "%s.\n", name); | ||
176 | return rc; | ||
177 | } | ||
178 | |||
179 | void i810_create_i2c_busses(struct i810fb_par *par) | ||
180 | { | ||
181 | par->chan[0].par = par; | ||
182 | par->chan[1].par = par; | ||
183 | i810_setup_i2c_bus(&par->chan[0], "I810-DDC", 1); | ||
184 | i810_setup_i2c_bus(&par->chan[1], "I810-I2C", 2); | ||
185 | } | ||
186 | |||
187 | void i810_delete_i2c_busses(struct i810fb_par *par) | ||
188 | { | ||
189 | if (par->chan[0].par) | ||
190 | i2c_bit_del_bus(&par->chan[0].adapter); | ||
191 | par->chan[0].par = NULL; | ||
192 | if (par->chan[1].par) | ||
193 | i2c_bit_del_bus(&par->chan[1].adapter); | ||
194 | par->chan[1].par = NULL; | ||
195 | } | ||
196 | |||
197 | static u8 *i810_do_probe_i2c_edid(struct i810fb_i2c_chan *chan) | ||
198 | { | ||
199 | u8 start = 0x0; | ||
200 | struct i2c_msg msgs[] = { | ||
201 | { | ||
202 | .addr = I810_DDC, | ||
203 | .len = 1, | ||
204 | .buf = &start, | ||
205 | }, { | ||
206 | .addr = I810_DDC, | ||
207 | .flags = I2C_M_RD, | ||
208 | .len = EDID_LENGTH, | ||
209 | }, | ||
210 | }; | ||
211 | u8 *buf; | ||
212 | |||
213 | buf = kmalloc(EDID_LENGTH, GFP_KERNEL); | ||
214 | if (!buf) { | ||
215 | DPRINTK("i810-i2c: Failed to allocate memory\n"); | ||
216 | return NULL; | ||
217 | } | ||
218 | msgs[1].buf = buf; | ||
219 | |||
220 | if (i2c_transfer(&chan->adapter, msgs, 2) == 2) { | ||
221 | DPRINTK("i810-i2c: I2C Transfer successful\n"); | ||
222 | return buf; | ||
223 | } | ||
224 | DPRINTK("i810-i2c: Unable to read EDID block.\n"); | ||
225 | kfree(buf); | ||
226 | return NULL; | ||
227 | } | ||
228 | |||
229 | int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, int conn) | ||
230 | { | ||
231 | struct i810fb_par *par = info->par; | ||
232 | u8 *edid = NULL; | ||
233 | int i; | ||
234 | |||
235 | DPRINTK("i810-i2c: Probe DDC%i Bus\n", conn); | ||
236 | if (conn < 3) { | ||
237 | for (i = 0; i < 3; i++) { | ||
238 | /* Do the real work */ | ||
239 | edid = i810_do_probe_i2c_edid(&par->chan[conn-1]); | ||
240 | if (edid) | ||
241 | break; | ||
242 | } | ||
243 | } else { | ||
244 | DPRINTK("i810-i2c: Getting EDID from BIOS\n"); | ||
245 | edid = kmalloc(EDID_LENGTH, GFP_KERNEL); | ||
246 | if (edid) | ||
247 | memcpy(edid, fb_firmware_edid(info->device), | ||
248 | EDID_LENGTH); | ||
249 | } | ||
250 | |||
251 | if (out_edid) | ||
252 | *out_edid = edid; | ||
253 | |||
254 | return (edid) ? 0 : 1; | ||
255 | } | ||
256 | |||
257 | |||
diff --git a/drivers/video/i810/i810.h b/drivers/video/i810/i810.h index f59af3335ccf..d48949ceaacc 100644 --- a/drivers/video/i810/i810.h +++ b/drivers/video/i810/i810.h | |||
@@ -16,6 +16,9 @@ | |||
16 | #include <linux/list.h> | 16 | #include <linux/list.h> |
17 | #include <linux/agp_backend.h> | 17 | #include <linux/agp_backend.h> |
18 | #include <linux/fb.h> | 18 | #include <linux/fb.h> |
19 | #include <linux/i2c.h> | ||
20 | #include <linux/i2c-id.h> | ||
21 | #include <linux/i2c-algo-bit.h> | ||
19 | #include <video/vga.h> | 22 | #include <video/vga.h> |
20 | 23 | ||
21 | /* Fence */ | 24 | /* Fence */ |
@@ -240,6 +243,14 @@ struct state_registers { | |||
240 | u8 cr39, cr41, cr70, sr01, msr; | 243 | u8 cr39, cr41, cr70, sr01, msr; |
241 | }; | 244 | }; |
242 | 245 | ||
246 | struct i810fb_par; | ||
247 | |||
248 | struct i810fb_i2c_chan { | ||
249 | struct i810fb_par *par; | ||
250 | struct i2c_adapter adapter; | ||
251 | struct i2c_algo_bit_data algo; | ||
252 | }; | ||
253 | |||
243 | struct i810fb_par { | 254 | struct i810fb_par { |
244 | struct mode_registers regs; | 255 | struct mode_registers regs; |
245 | struct state_registers hw_state; | 256 | struct state_registers hw_state; |
@@ -251,10 +262,12 @@ struct i810fb_par { | |||
251 | struct heap_data iring; | 262 | struct heap_data iring; |
252 | struct heap_data cursor_heap; | 263 | struct heap_data cursor_heap; |
253 | struct vgastate state; | 264 | struct vgastate state; |
265 | struct i810fb_i2c_chan chan[2]; | ||
254 | atomic_t use_count; | 266 | atomic_t use_count; |
255 | u32 pseudo_palette[17]; | 267 | u32 pseudo_palette[17]; |
256 | unsigned long mmio_start_phys; | 268 | unsigned long mmio_start_phys; |
257 | u8 __iomem *mmio_start_virtual; | 269 | u8 __iomem *mmio_start_virtual; |
270 | u8 *edid; | ||
258 | u32 pitch; | 271 | u32 pitch; |
259 | u32 pixconf; | 272 | u32 pixconf; |
260 | u32 watermark; | 273 | u32 watermark; |
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index d07b1f203fc4..082ddd2089a5 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c | |||
@@ -92,20 +92,21 @@ static struct pci_driver i810fb_driver = { | |||
92 | .resume = i810fb_resume, | 92 | .resume = i810fb_resume, |
93 | }; | 93 | }; |
94 | 94 | ||
95 | static int vram __initdata = 4; | 95 | static char *mode_option __devinitdata = NULL; |
96 | static int bpp __initdata = 8; | 96 | static int vram __devinitdata = 4; |
97 | static int mtrr __initdata = 0; | 97 | static int bpp __devinitdata = 8; |
98 | static int accel __initdata = 0; | 98 | static int mtrr __devinitdata = 0; |
99 | static int hsync1 __initdata = 0; | 99 | static int accel __devinitdata = 0; |
100 | static int hsync2 __initdata = 0; | 100 | static int hsync1 __devinitdata = 0; |
101 | static int vsync1 __initdata = 0; | 101 | static int hsync2 __devinitdata = 0; |
102 | static int vsync2 __initdata = 0; | 102 | static int vsync1 __devinitdata = 0; |
103 | static int xres __initdata = 640; | 103 | static int vsync2 __devinitdata = 0; |
104 | static int yres __initdata = 480; | 104 | static int xres __devinitdata = 640; |
105 | static int vyres __initdata = 0; | 105 | static int yres __devinitdata = 480; |
106 | static int sync __initdata = 0; | 106 | static int vyres __devinitdata = 0; |
107 | static int ext_vga __initdata = 0; | 107 | static int sync __devinitdata = 0; |
108 | static int dcolor __initdata = 0; | 108 | static int ext_vga __devinitdata = 0; |
109 | static int dcolor __devinitdata = 0; | ||
109 | 110 | ||
110 | /*------------------------------------------------------------*/ | 111 | /*------------------------------------------------------------*/ |
111 | 112 | ||
@@ -947,31 +948,24 @@ static int i810_check_params(struct fb_var_screeninfo *var, | |||
947 | struct fb_info *info) | 948 | struct fb_info *info) |
948 | { | 949 | { |
949 | struct i810fb_par *par = (struct i810fb_par *) info->par; | 950 | struct i810fb_par *par = (struct i810fb_par *) info->par; |
950 | int line_length, vidmem; | 951 | int line_length, vidmem, mode_valid = 0; |
951 | u32 xres, yres, vxres, vyres; | 952 | u32 vyres = var->yres_virtual, vxres = var->xres_virtual; |
952 | |||
953 | xres = var->xres; | ||
954 | yres = var->yres; | ||
955 | vxres = var->xres_virtual; | ||
956 | vyres = var->yres_virtual; | ||
957 | |||
958 | /* | 953 | /* |
959 | * Memory limit | 954 | * Memory limit |
960 | */ | 955 | */ |
961 | line_length = get_line_length(par, vxres, | 956 | line_length = get_line_length(par, vxres, var->bits_per_pixel); |
962 | var->bits_per_pixel); | ||
963 | |||
964 | vidmem = line_length*vyres; | 957 | vidmem = line_length*vyres; |
958 | |||
965 | if (vidmem > par->fb.size) { | 959 | if (vidmem > par->fb.size) { |
966 | vyres = par->fb.size/line_length; | 960 | vyres = par->fb.size/line_length; |
967 | if (vyres < yres) { | 961 | if (vyres < var->yres) { |
968 | vyres = yres; | 962 | vyres = yres; |
969 | vxres = par->fb.size/vyres; | 963 | vxres = par->fb.size/vyres; |
970 | vxres /= var->bits_per_pixel >> 3; | 964 | vxres /= var->bits_per_pixel >> 3; |
971 | line_length = get_line_length(par, vxres, | 965 | line_length = get_line_length(par, vxres, |
972 | var->bits_per_pixel); | 966 | var->bits_per_pixel); |
973 | vidmem = line_length * yres; | 967 | vidmem = line_length * yres; |
974 | if (vxres < xres) { | 968 | if (vxres < var->xres) { |
975 | printk("i810fb: required video memory, " | 969 | printk("i810fb: required video memory, " |
976 | "%d bytes, for %dx%d-%d (virtual) " | 970 | "%d bytes, for %dx%d-%d (virtual) " |
977 | "is out of range\n", | 971 | "is out of range\n", |
@@ -981,6 +975,10 @@ static int i810_check_params(struct fb_var_screeninfo *var, | |||
981 | } | 975 | } |
982 | } | 976 | } |
983 | } | 977 | } |
978 | |||
979 | var->xres_virtual = vxres; | ||
980 | var->yres_virtual = vyres; | ||
981 | |||
984 | /* | 982 | /* |
985 | * Monitor limit | 983 | * Monitor limit |
986 | */ | 984 | */ |
@@ -996,25 +994,39 @@ static int i810_check_params(struct fb_var_screeninfo *var, | |||
996 | info->monspecs.dclkmax = 204000000; | 994 | info->monspecs.dclkmax = 204000000; |
997 | break; | 995 | break; |
998 | } | 996 | } |
997 | |||
999 | info->monspecs.dclkmin = 15000000; | 998 | info->monspecs.dclkmin = 15000000; |
1000 | 999 | ||
1001 | if (fb_validate_mode(var, info)) { | 1000 | if (!fb_validate_mode(var, info)) |
1001 | mode_valid = 1; | ||
1002 | |||
1003 | #ifdef CONFIG_FB_I810_I2C | ||
1004 | if (!mode_valid && info->monspecs.gtf && | ||
1005 | !fb_get_mode(FB_MAXTIMINGS, 0, var, info)) | ||
1006 | mode_valid = 1; | ||
1007 | |||
1008 | if (!mode_valid && info->monspecs.modedb_len) { | ||
1009 | struct fb_videomode *mode; | ||
1010 | |||
1011 | mode = fb_find_best_mode(var, &info->modelist); | ||
1012 | if (mode) { | ||
1013 | fb_videomode_to_var(var, mode); | ||
1014 | mode_valid = 1; | ||
1015 | } | ||
1016 | } | ||
1017 | #endif | ||
1018 | if (!mode_valid && info->monspecs.modedb_len == 0) { | ||
1002 | if (fb_get_mode(FB_MAXTIMINGS, 0, var, info)) { | 1019 | if (fb_get_mode(FB_MAXTIMINGS, 0, var, info)) { |
1003 | int default_sync = (info->monspecs.hfmin-HFMIN) | 1020 | int default_sync = (info->monspecs.hfmin-HFMIN) |
1004 | |(info->monspecs.hfmax-HFMAX) | 1021 | |(info->monspecs.hfmax-HFMAX) |
1005 | |(info->monspecs.vfmin-VFMIN) | 1022 | |(info->monspecs.vfmin-VFMIN) |
1006 | |(info->monspecs.vfmax-VFMAX); | 1023 | |(info->monspecs.vfmax-VFMAX); |
1007 | printk("i810fb: invalid video mode%s\n", | 1024 | printk("i810fb: invalid video mode%s\n", |
1008 | default_sync ? "" : | 1025 | default_sync ? "" : ". Specifying " |
1009 | ". Specifying vsyncN/hsyncN parameters may help"); | 1026 | "vsyncN/hsyncN parameters may help"); |
1010 | return -EINVAL; | ||
1011 | } | 1027 | } |
1012 | } | 1028 | } |
1013 | 1029 | ||
1014 | var->xres = xres; | ||
1015 | var->yres = yres; | ||
1016 | var->xres_virtual = vxres; | ||
1017 | var->yres_virtual = vyres; | ||
1018 | return 0; | 1030 | return 0; |
1019 | } | 1031 | } |
1020 | 1032 | ||
@@ -1812,8 +1824,72 @@ i810_allocate_pci_resource(struct i810fb_par *par, | |||
1812 | return 0; | 1824 | return 0; |
1813 | } | 1825 | } |
1814 | 1826 | ||
1827 | static void __devinit i810fb_find_init_mode(struct fb_info *info) | ||
1828 | { | ||
1829 | struct fb_videomode mode; | ||
1830 | struct fb_var_screeninfo var; | ||
1831 | struct fb_monspecs *specs = NULL; | ||
1832 | int found = 0; | ||
1833 | #ifdef CONFIG_FB_I810_I2C | ||
1834 | int i; | ||
1835 | int err; | ||
1836 | struct i810fb_par *par = info->par; | ||
1837 | #endif | ||
1838 | |||
1839 | INIT_LIST_HEAD(&info->modelist); | ||
1840 | memset(&mode, 0, sizeof(struct fb_videomode)); | ||
1841 | var = info->var; | ||
1842 | #ifdef CONFIG_FB_I810_I2C | ||
1843 | i810_create_i2c_busses(par); | ||
1844 | |||
1845 | for (i = 0; i < 3; i++) { | ||
1846 | err = i810_probe_i2c_connector(info, &par->edid, i+1); | ||
1847 | if (!err) | ||
1848 | break; | ||
1849 | } | ||
1850 | |||
1851 | if (!err) | ||
1852 | printk("i810fb_init_pci: DDC probe successful\n"); | ||
1853 | |||
1854 | fb_edid_to_monspecs(par->edid, &info->monspecs); | ||
1855 | |||
1856 | if (info->monspecs.modedb == NULL) | ||
1857 | printk("i810fb_init_pci: Unable to get Mode Database\n"); | ||
1858 | |||
1859 | specs = &info->monspecs; | ||
1860 | fb_videomode_to_modelist(specs->modedb, specs->modedb_len, | ||
1861 | &info->modelist); | ||
1862 | if (specs->modedb != NULL) { | ||
1863 | if (specs->misc & FB_MISC_1ST_DETAIL) { | ||
1864 | for (i = 0; i < specs->modedb_len; i++) { | ||
1865 | if (specs->modedb[i].flag & FB_MODE_IS_FIRST) { | ||
1866 | mode = specs->modedb[i]; | ||
1867 | found = 1; | ||
1868 | break; | ||
1869 | } | ||
1870 | } | ||
1871 | } | ||
1872 | |||
1873 | if (!found) { | ||
1874 | mode = specs->modedb[0]; | ||
1875 | found = 1; | ||
1876 | } | ||
1877 | |||
1878 | fb_videomode_to_var(&var, &mode); | ||
1879 | } | ||
1880 | #endif | ||
1881 | if (mode_option) | ||
1882 | fb_find_mode(&var, info, mode_option, specs->modedb, | ||
1883 | specs->modedb_len, (found) ? &mode : NULL, | ||
1884 | info->var.bits_per_pixel); | ||
1885 | |||
1886 | info->var = var; | ||
1887 | fb_destroy_modedb(specs->modedb); | ||
1888 | specs->modedb = NULL; | ||
1889 | } | ||
1890 | |||
1815 | #ifndef MODULE | 1891 | #ifndef MODULE |
1816 | static int __init i810fb_setup(char *options) | 1892 | static int __devinit i810fb_setup(char *options) |
1817 | { | 1893 | { |
1818 | char *this_opt, *suffix = NULL; | 1894 | char *this_opt, *suffix = NULL; |
1819 | 1895 | ||
@@ -1855,6 +1931,8 @@ static int __init i810fb_setup(char *options) | |||
1855 | vsync2 = simple_strtoul(this_opt+7, NULL, 0); | 1931 | vsync2 = simple_strtoul(this_opt+7, NULL, 0); |
1856 | else if (!strncmp(this_opt, "dcolor", 6)) | 1932 | else if (!strncmp(this_opt, "dcolor", 6)) |
1857 | dcolor = 1; | 1933 | dcolor = 1; |
1934 | else | ||
1935 | mode_option = this_opt; | ||
1858 | } | 1936 | } |
1859 | return 0; | 1937 | return 0; |
1860 | } | 1938 | } |
@@ -1865,6 +1943,7 @@ static int __devinit i810fb_init_pci (struct pci_dev *dev, | |||
1865 | { | 1943 | { |
1866 | struct fb_info *info; | 1944 | struct fb_info *info; |
1867 | struct i810fb_par *par = NULL; | 1945 | struct i810fb_par *par = NULL; |
1946 | struct fb_videomode mode; | ||
1868 | int i, err = -1, vfreq, hfreq, pixclock; | 1947 | int i, err = -1, vfreq, hfreq, pixclock; |
1869 | 1948 | ||
1870 | i = 0; | 1949 | i = 0; |
@@ -1873,7 +1952,7 @@ static int __devinit i810fb_init_pci (struct pci_dev *dev, | |||
1873 | if (!info) | 1952 | if (!info) |
1874 | return -ENOMEM; | 1953 | return -ENOMEM; |
1875 | 1954 | ||
1876 | par = (struct i810fb_par *) info->par; | 1955 | par = info->par; |
1877 | par->dev = dev; | 1956 | par->dev = dev; |
1878 | 1957 | ||
1879 | if (!(info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL))) { | 1958 | if (!(info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL))) { |
@@ -1904,15 +1983,20 @@ static int __devinit i810fb_init_pci (struct pci_dev *dev, | |||
1904 | info->fbops = &par->i810fb_ops; | 1983 | info->fbops = &par->i810fb_ops; |
1905 | info->pseudo_palette = par->pseudo_palette; | 1984 | info->pseudo_palette = par->pseudo_palette; |
1906 | fb_alloc_cmap(&info->cmap, 256, 0); | 1985 | fb_alloc_cmap(&info->cmap, 256, 0); |
1986 | i810fb_find_init_mode(info); | ||
1907 | 1987 | ||
1908 | if ((err = info->fbops->fb_check_var(&info->var, info))) { | 1988 | if ((err = info->fbops->fb_check_var(&info->var, info))) { |
1909 | i810fb_release_resource(info, par); | 1989 | i810fb_release_resource(info, par); |
1910 | return err; | 1990 | return err; |
1911 | } | 1991 | } |
1992 | |||
1993 | fb_var_to_videomode(&mode, &info->var); | ||
1994 | fb_add_videomode(&mode, &info->modelist); | ||
1912 | encode_fix(&info->fix, info); | 1995 | encode_fix(&info->fix, info); |
1913 | 1996 | ||
1914 | i810fb_init_ringbuffer(info); | 1997 | i810fb_init_ringbuffer(info); |
1915 | err = register_framebuffer(info); | 1998 | err = register_framebuffer(info); |
1999 | |||
1916 | if (err < 0) { | 2000 | if (err < 0) { |
1917 | i810fb_release_resource(info, par); | 2001 | i810fb_release_resource(info, par); |
1918 | printk("i810fb_init: cannot register framebuffer device\n"); | 2002 | printk("i810fb_init: cannot register framebuffer device\n"); |
@@ -1951,6 +2035,8 @@ static void i810fb_release_resource(struct fb_info *info, | |||
1951 | struct gtt_data *gtt = &par->i810_gtt; | 2035 | struct gtt_data *gtt = &par->i810_gtt; |
1952 | unset_mtrr(par); | 2036 | unset_mtrr(par); |
1953 | 2037 | ||
2038 | i810_delete_i2c_busses(par); | ||
2039 | |||
1954 | if (par->i810_gtt.i810_cursor_memory) | 2040 | if (par->i810_gtt.i810_cursor_memory) |
1955 | agp_free_memory(gtt->i810_cursor_memory); | 2041 | agp_free_memory(gtt->i810_cursor_memory); |
1956 | if (par->i810_gtt.i810_fb_memory) | 2042 | if (par->i810_gtt.i810_fb_memory) |
@@ -1960,7 +2046,8 @@ static void i810fb_release_resource(struct fb_info *info, | |||
1960 | iounmap(par->mmio_start_virtual); | 2046 | iounmap(par->mmio_start_virtual); |
1961 | if (par->aperture.virtual) | 2047 | if (par->aperture.virtual) |
1962 | iounmap(par->aperture.virtual); | 2048 | iounmap(par->aperture.virtual); |
1963 | 2049 | if (par->edid) | |
2050 | kfree(par->edid); | ||
1964 | if (par->res_flags & FRAMEBUFFER_REQ) | 2051 | if (par->res_flags & FRAMEBUFFER_REQ) |
1965 | release_mem_region(par->aperture.physical, | 2052 | release_mem_region(par->aperture.physical, |
1966 | par->aperture.size); | 2053 | par->aperture.size); |
@@ -1986,7 +2073,7 @@ static void __exit i810fb_remove_pci(struct pci_dev *dev) | |||
1986 | } | 2073 | } |
1987 | 2074 | ||
1988 | #ifndef MODULE | 2075 | #ifndef MODULE |
1989 | static int __init i810fb_init(void) | 2076 | static int __devinit i810fb_init(void) |
1990 | { | 2077 | { |
1991 | char *option = NULL; | 2078 | char *option = NULL; |
1992 | 2079 | ||
@@ -2004,7 +2091,7 @@ static int __init i810fb_init(void) | |||
2004 | 2091 | ||
2005 | #ifdef MODULE | 2092 | #ifdef MODULE |
2006 | 2093 | ||
2007 | static int __init i810fb_init(void) | 2094 | static int __devinit i810fb_init(void) |
2008 | { | 2095 | { |
2009 | hsync1 *= 1000; | 2096 | hsync1 *= 1000; |
2010 | hsync2 *= 1000; | 2097 | hsync2 *= 1000; |
@@ -2052,6 +2139,8 @@ MODULE_PARM_DESC(sync, "wait for accel engine to finish drawing" | |||
2052 | module_param(dcolor, bool, 0); | 2139 | module_param(dcolor, bool, 0); |
2053 | MODULE_PARM_DESC(dcolor, "use DirectColor visuals" | 2140 | MODULE_PARM_DESC(dcolor, "use DirectColor visuals" |
2054 | " (default = 0 = TrueColor)"); | 2141 | " (default = 0 = TrueColor)"); |
2142 | module_param(mode_option, charp, 0); | ||
2143 | MODULE_PARM_DESC(mode_option, "Specify initial video mode"); | ||
2055 | 2144 | ||
2056 | MODULE_AUTHOR("Tony A. Daplas"); | 2145 | MODULE_AUTHOR("Tony A. Daplas"); |
2057 | MODULE_DESCRIPTION("Framebuffer device for the Intel 810/815 and" | 2146 | MODULE_DESCRIPTION("Framebuffer device for the Intel 810/815 and" |
diff --git a/drivers/video/i810/i810_main.h b/drivers/video/i810/i810_main.h index 43b4297b4d48..06072a6466f2 100644 --- a/drivers/video/i810/i810_main.h +++ b/drivers/video/i810/i810_main.h | |||
@@ -83,6 +83,22 @@ extern int i810fb_sync (struct fb_info *p); | |||
83 | extern void i810fb_init_ringbuffer(struct fb_info *info); | 83 | extern void i810fb_init_ringbuffer(struct fb_info *info); |
84 | extern void i810fb_load_front (u32 offset, struct fb_info *info); | 84 | extern void i810fb_load_front (u32 offset, struct fb_info *info); |
85 | 85 | ||
86 | #ifdef CONFIG_FB_I810_I2C | ||
87 | /* I2C */ | ||
88 | extern int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, | ||
89 | int conn); | ||
90 | extern void i810_create_i2c_busses(struct i810fb_par *par); | ||
91 | extern void i810_delete_i2c_busses(struct i810fb_par *par); | ||
92 | #else | ||
93 | static inline int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, | ||
94 | int conn) | ||
95 | { | ||
96 | return 1; | ||
97 | } | ||
98 | static inline void i810_create_i2c_busses(struct i810fb_par *par) { } | ||
99 | static inline void i810_delete_i2c_busses(struct i810fb_par *par) { } | ||
100 | #endif | ||
101 | |||
86 | /* Conditionals */ | 102 | /* Conditionals */ |
87 | #ifdef CONFIG_X86 | 103 | #ifdef CONFIG_X86 |
88 | inline void flush_cache(void) | 104 | inline void flush_cache(void) |