diff options
| author | Antonino A. Daplas <adaplas@gmail.com> | 2005-09-09 16:10:04 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-09 17:03:41 -0400 |
| commit | 74f6ae84b2315c2fa8a4110b09a1c0f3dca92674 (patch) | |
| tree | 47b3bae44b4c57a699d2c130510ff0fbe110fa97 /drivers | |
| parent | 829e79b680210c4f4de435af6e1f90451922fc7d (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')
| -rw-r--r-- | drivers/video/Kconfig | 6 | ||||
| -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 |
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 | ||
| 754 | config FB_I810_I2C | ||
| 755 | bool "Enable DDC Support" | ||
| 756 | depends on FB_I810 && I2C && FB_I810_GTF | ||
| 757 | select I2C_ALGOBIT | ||
| 758 | help | ||
| 759 | |||
| 754 | config FB_INTEL | 760 | config 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 | ||
| 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) |
