aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorAntonino A. Daplas <adaplas@gmail.com>2005-09-09 16:10:04 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-09 17:03:41 -0400
commit74f6ae84b2315c2fa8a4110b09a1c0f3dca92674 (patch)
tree47b3bae44b4c57a699d2c130510ff0fbe110fa97 /drivers/video
parent829e79b680210c4f4de435af6e1f90451922fc7d (diff)
[PATCH] i810fb: Add i2c/DDC support
Add ddc/i2c support for i810fb. This will allow the driver to get display information, especially for monitors with fickle timings. The i2c support depends on CONFIG_FB_I810_GTF. Changed __init* to __devinit* Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Alexander Nyberg <alexn@telia.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/Kconfig6
-rw-r--r--drivers/video/i810/Makefile5
-rw-r--r--drivers/video/i810/i810-i2c.c257
-rw-r--r--drivers/video/i810/i810.h13
-rw-r--r--drivers/video/i810/i810_main.c177
-rw-r--r--drivers/video/i810/i810_main.h16
6 files changed, 429 insertions, 45 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index e27aefd49ea3..f8c341d48caf 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -751,6 +751,12 @@ config FB_I810_GTF
751 751
752 If unsure, say N. 752 If unsure, say N.
753 753
754config FB_I810_I2C
755 bool "Enable DDC Support"
756 depends on FB_I810 && I2C && FB_I810_GTF
757 select I2C_ALGOBIT
758 help
759
754config FB_INTEL 760config FB_INTEL
755 tristate "Intel 830M/845G/852GM/855GM/865G support (EXPERIMENTAL)" 761 tristate "Intel 830M/845G/852GM/855GM/865G support (EXPERIMENTAL)"
756 depends on FB && EXPERIMENTAL && PCI && X86 && !X86_64 762 depends on FB && EXPERIMENTAL && PCI && X86 && !X86_64
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
5obj-$(CONFIG_FB_I810) += i810fb.o 5obj-$(CONFIG_FB_I810) += i810fb.o
6 6
7
8i810fb-objs := i810_main.o i810_accel.o 7i810fb-objs := i810_main.o i810_accel.o
9 8
10ifdef CONFIG_FB_I810_GTF 9ifdef CONFIG_FB_I810_GTF
@@ -12,3 +11,7 @@ i810fb-objs += i810_gtf.o
12else 11else
13i810fb-objs += i810_dvt.o 12i810fb-objs += i810_dvt.o
14endif 13endif
14
15ifdef CONFIG_FB_I810_I2C
16i810fb-objs += i810-i2c.o
17endif
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
43static 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
54static 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
65static 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
76static 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
87static 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
98static 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
109static 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
120static 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
133static 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
179void 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
187void 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
197static 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
229int 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
246struct i810fb_par;
247
248struct i810fb_i2c_chan {
249 struct i810fb_par *par;
250 struct i2c_adapter adapter;
251 struct i2c_algo_bit_data algo;
252};
253
243struct i810fb_par { 254struct 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
95static int vram __initdata = 4; 95static char *mode_option __devinitdata = NULL;
96static int bpp __initdata = 8; 96static int vram __devinitdata = 4;
97static int mtrr __initdata = 0; 97static int bpp __devinitdata = 8;
98static int accel __initdata = 0; 98static int mtrr __devinitdata = 0;
99static int hsync1 __initdata = 0; 99static int accel __devinitdata = 0;
100static int hsync2 __initdata = 0; 100static int hsync1 __devinitdata = 0;
101static int vsync1 __initdata = 0; 101static int hsync2 __devinitdata = 0;
102static int vsync2 __initdata = 0; 102static int vsync1 __devinitdata = 0;
103static int xres __initdata = 640; 103static int vsync2 __devinitdata = 0;
104static int yres __initdata = 480; 104static int xres __devinitdata = 640;
105static int vyres __initdata = 0; 105static int yres __devinitdata = 480;
106static int sync __initdata = 0; 106static int vyres __devinitdata = 0;
107static int ext_vga __initdata = 0; 107static int sync __devinitdata = 0;
108static int dcolor __initdata = 0; 108static int ext_vga __devinitdata = 0;
109static 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
1827static 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
1816static int __init i810fb_setup(char *options) 1892static 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
1989static int __init i810fb_init(void) 2076static 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
2007static int __init i810fb_init(void) 2094static 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"
2052module_param(dcolor, bool, 0); 2139module_param(dcolor, bool, 0);
2053MODULE_PARM_DESC(dcolor, "use DirectColor visuals" 2140MODULE_PARM_DESC(dcolor, "use DirectColor visuals"
2054 " (default = 0 = TrueColor)"); 2141 " (default = 0 = TrueColor)");
2142module_param(mode_option, charp, 0);
2143MODULE_PARM_DESC(mode_option, "Specify initial video mode");
2055 2144
2056MODULE_AUTHOR("Tony A. Daplas"); 2145MODULE_AUTHOR("Tony A. Daplas");
2057MODULE_DESCRIPTION("Framebuffer device for the Intel 810/815 and" 2146MODULE_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);
83extern void i810fb_init_ringbuffer(struct fb_info *info); 83extern void i810fb_init_ringbuffer(struct fb_info *info);
84extern void i810fb_load_front (u32 offset, struct fb_info *info); 84extern void i810fb_load_front (u32 offset, struct fb_info *info);
85 85
86#ifdef CONFIG_FB_I810_I2C
87/* I2C */
88extern int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid,
89 int conn);
90extern void i810_create_i2c_busses(struct i810fb_par *par);
91extern void i810_delete_i2c_busses(struct i810fb_par *par);
92#else
93static inline int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid,
94 int conn)
95{
96 return 1;
97}
98static inline void i810_create_i2c_busses(struct i810fb_par *par) { }
99static 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
88inline void flush_cache(void) 104inline void flush_cache(void)