Merge branch 'intelfb-patches' of master.kernel.org:/pub/scm/linux/kernel/git/airlied/intelfb-2.6

* 'intelfb-patches' of master.kernel.org:/pub/scm/linux/kernel/git/airlied/intelfb-2.6:
  intelfbhw.c: intelfbhw_get_p1p2 defined but not used
  intelfb: fix mtrr_reg signedness
  intelfb: update doc and Kconfig (supported devices)
  intelfb: add preliminary i2c support
  intelfb: add preliminary i2c support
  intelfb: add preliminary i2c support
  intelfb: add preliminary i2c support
  intelfb: add preliminary i2c support
  intelfb: add preliminary i2c support
  intelfb: add preliminary i2c support
  intelfb: add preliminary i2c support
  intelfb: add vsync interrupt support
  intelfb: add vsync interrupt support
  intelfb: add vsync interrupt support
  intelfb: add vsync interrupt support
  intelfb: add vsync interrupt support
diff --git a/Documentation/fb/intelfb.txt b/Documentation/fb/intelfb.txt
index c12d39a..aa0d322 100644
--- a/Documentation/fb/intelfb.txt
+++ b/Documentation/fb/intelfb.txt
@@ -1,16 +1,19 @@
-Intel 830M/845G/852GM/855GM/865G/915G Framebuffer driver
+Intel 830M/845G/852GM/855GM/865G/915G/945G Framebuffer driver
 ================================================================
 
 A. Introduction
-	This is a framebuffer driver for various Intel 810/815 compatible
+	This is a framebuffer driver for various Intel 8xx/9xx compatible
 graphics devices.  These would include:
 
 	Intel 830M
-	Intel 810E845G
+	Intel 845G
 	Intel 852GM
 	Intel 855GM
 	Intel 865G
 	Intel 915G
+	Intel 915GM
+	Intel 945G
+	Intel 945GM
 
 B.  List of available options
 
@@ -78,7 +81,7 @@
 Separate each option/option-pair by commas (,) and the option from its value
 with an equals sign (=) as in the following:
 
-video=i810fb:option1,option2=value2
+video=intelfb:option1,option2=value2
 
 Sample Usage
 ------------
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 702eb93..e0ef332 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -825,30 +825,48 @@
 	help
 
 config FB_INTEL
-	tristate "Intel 830M/845G/852GM/855GM/865G support (EXPERIMENTAL)"
+	tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G support (EXPERIMENTAL)"
 	depends on FB && EXPERIMENTAL && PCI && X86
 	select AGP
 	select AGP_INTEL
+	select I2C_ALGOBIT if FB_INTEL_I2C
+	select I2C if FB_INTEL_I2C
 	select FB_MODE_HELPERS
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
 	help
 	  This driver supports the on-board graphics built in to the Intel
-          830M/845G/852GM/855GM/865G chipsets.
+          830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM chipsets.
           Say Y if you have and plan to use such a board.
 
-          To compile this driver as a module, choose M here: the
+	  If you say Y here and want DDC/I2C support you must first say Y to
+	  "I2C support" and "I2C bit-banging support" in the character devices
+	  section.
+
+	  If you say M here then "I2C support" and "I2C bit-banging support"
+	  can be build either as modules or built-in.
+
+	  To compile this driver as a module, choose M here: the
 	  module will be called intelfb.
 
+	  For more information, please read <file:Documentation/fb/intelfb.txt>
+
 config FB_INTEL_DEBUG
-        bool "Intel driver Debug Messages"
+	bool "Intel driver Debug Messages"
 	depends on FB_INTEL
 	---help---
 	  Say Y here if you want the Intel driver to output all sorts
 	  of debugging informations to provide to the maintainer when
 	  something goes wrong.
 
+config FB_INTEL_I2C
+	bool "DDC/I2C for Intel framebuffer support"
+	depends on FB_INTEL
+	default y
+	help
+	  Say Y here if you want DDC/I2C support for your on-board Intel graphics.
+
 config FB_MATROX
 	tristate "Matrox acceleration"
 	depends on FB && PCI
diff --git a/drivers/video/intelfb/Makefile b/drivers/video/intelfb/Makefile
index 722d21d..6c782d3 100644
--- a/drivers/video/intelfb/Makefile
+++ b/drivers/video/intelfb/Makefile
@@ -1,6 +1,8 @@
 obj-$(CONFIG_FB_INTEL) += intelfb.o
 
-intelfb-objs := intelfbdrv.o intelfbhw.o
+intelfb-y := intelfbdrv.o intelfbhw.o
+intelfb-$(CONFIG_FB_INTEL_I2C) += intelfb_i2c.o
+intelfb-objs := $(intelfb-y)
 
 ifdef CONFIG_FB_INTEL_DEBUG
 #EXTRA_CFLAGS += -DDEBUG -DVERBOSE -DREGDUMP
diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
index e290d74..80b94c1 100644
--- a/drivers/video/intelfb/intelfb.h
+++ b/drivers/video/intelfb/intelfb.h
@@ -6,6 +6,10 @@
 #include <linux/agp_backend.h>
 #include <linux/fb.h>
 
+#ifdef CONFIG_FB_INTEL_I2C
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#endif
 
 /*** Version/name ***/
 #define INTELFB_VERSION			"0.9.4"
@@ -115,6 +119,29 @@
 /* Intel agpgart driver */
 #define AGP_PHYSICAL_MEMORY     2
 
+/* store information about an Ixxx DVO */
+/* The i830->i865 use multiple DVOs with multiple i2cs */
+/* the i915, i945 have a single sDVO i2c bus - which is different */
+#define MAX_OUTPUTS 6
+
+/* these are outputs from the chip - integrated only
+   external chips are via DVO or SDVO output */
+#define INTELFB_OUTPUT_UNUSED 0
+#define INTELFB_OUTPUT_ANALOG 1
+#define INTELFB_OUTPUT_DVO 2
+#define INTELFB_OUTPUT_SDVO 3
+#define INTELFB_OUTPUT_LVDS 4
+#define INTELFB_OUTPUT_TVOUT 5
+
+#define INTELFB_DVO_CHIP_NONE 0
+#define INTELFB_DVO_CHIP_LVDS 1
+#define INTELFB_DVO_CHIP_TMDS 2
+#define INTELFB_DVO_CHIP_TVOUT 4
+
+#define INTELFB_OUTPUT_PIPE_NC  0
+#define INTELFB_OUTPUT_PIPE_A   1
+#define INTELFB_OUTPUT_PIPE_B   2
+
 /*** Data Types ***/
 
 /* supported chipsets */
@@ -195,6 +222,10 @@
 	u32 mem_mode;
 	u32 fw_blc_0;
 	u32 fw_blc_1;
+	u16 hwstam;
+	u16 ier;
+	u16 iir;
+	u16 imr;
 };
 
 struct intelfb_heap_data {
@@ -204,6 +235,33 @@
 	u32 size;    // in bytes
 };
 
+#ifdef CONFIG_FB_INTEL_I2C
+struct intelfb_i2c_chan {
+    struct intelfb_info *dinfo;
+    u32 reg;
+    struct i2c_adapter adapter;
+    struct i2c_algo_bit_data algo;
+};
+#endif
+
+struct intelfb_output_rec {
+    int type;
+    int pipe;
+    int flags;
+
+#ifdef CONFIG_FB_INTEL_I2C
+    struct intelfb_i2c_chan i2c_bus;
+    struct intelfb_i2c_chan ddc_bus;
+#endif
+};
+
+struct intelfb_vsync {
+	wait_queue_head_t wait;
+	unsigned int count;
+	int pan_display;
+	u32 pan_offset;
+};
+
 struct intelfb_info {
 	struct fb_info *info;
 	struct fb_ops  *fbops;
@@ -220,7 +278,7 @@
 	u8 fbmem_gart;
 
 	/* mtrr support */
-	u32 mtrr_reg;
+	int mtrr_reg;
 	u32 has_mtrr;
 
 	/* heap data */
@@ -267,6 +325,12 @@
 	int fixed_mode;
 	int ring_active;
 	int flag;
+	unsigned long irq_flags;
+	int open;
+
+	/* vsync */
+	struct intelfb_vsync vsync;
+	spinlock_t int_lock;
 
 	/* hw cursor */
 	int cursor_on;
@@ -285,12 +349,25 @@
 	
 	/* index into plls */
 	int pll_index;
+
+	/* outputs */
+	int num_outputs;
+	struct intelfb_output_rec output[MAX_OUTPUTS];
 };
 
 #define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G)||(dinfo->chipset == INTEL_915GM)||((dinfo)->chipset == INTEL_945G)||(dinfo->chipset==INTEL_945GM))
 
+#ifndef FBIO_WAITFORVSYNC
+#define FBIO_WAITFORVSYNC	_IOW('F', 0x20, __u32)
+#endif
+
 /*** function prototypes ***/
 
 extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var);
 
+#ifdef CONFIG_FB_INTEL_I2C
+extern void intelfb_create_i2c_busses(struct intelfb_info *dinfo);
+extern void intelfb_delete_i2c_busses(struct intelfb_info *dinfo);
+#endif
+
 #endif /* _INTELFB_H */
diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c
new file mode 100644
index 0000000..c1113d6
--- /dev/null
+++ b/drivers/video/intelfb/intelfb_i2c.c
@@ -0,0 +1,200 @@
+/**************************************************************************
+
+ Copyright 2006 Dave Airlie <airlied@linux.ie>
+
+All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, and/or sell copies of the Software, and to permit persons to whom
+the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/fb.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+
+#include <asm/io.h>
+
+#include "intelfb.h"
+#include "intelfbhw.h"
+
+/* bit locations in the registers */
+#define SCL_DIR_MASK		0x0001
+#define SCL_DIR			0x0002
+#define SCL_VAL_MASK		0x0004
+#define SCL_VAL_OUT		0x0008
+#define SCL_VAL_IN		0x0010
+#define SDA_DIR_MASK		0x0100
+#define SDA_DIR			0x0200
+#define SDA_VAL_MASK		0x0400
+#define SDA_VAL_OUT		0x0800
+#define SDA_VAL_IN		0x1000
+
+static void intelfb_gpio_setscl(void *data, int state)
+{
+	struct intelfb_i2c_chan *chan = data;
+	struct intelfb_info *dinfo = chan->dinfo;
+	u32 val;
+
+	OUTREG(chan->reg, (state ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK);
+	val = INREG(chan->reg);
+}
+
+static void intelfb_gpio_setsda(void *data, int state)
+{
+	struct intelfb_i2c_chan *chan = data;
+	struct intelfb_info *dinfo = chan->dinfo;
+	u32 val;
+
+	OUTREG(chan->reg, (state ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK);
+	val = INREG(chan->reg);
+}
+
+static int intelfb_gpio_getscl(void *data)
+{
+	struct intelfb_i2c_chan *chan = data;
+	struct intelfb_info *dinfo = chan->dinfo;
+	u32 val;
+
+	OUTREG(chan->reg, SCL_DIR_MASK);
+	OUTREG(chan->reg, 0);
+	val = INREG(chan->reg);
+	return ((val & SCL_VAL_IN) != 0);
+}
+
+static int intelfb_gpio_getsda(void *data)
+{
+	struct intelfb_i2c_chan *chan = data;
+	struct intelfb_info *dinfo = chan->dinfo;
+	u32 val;
+
+	OUTREG(chan->reg, SDA_DIR_MASK);
+	OUTREG(chan->reg, 0);
+	val = INREG(chan->reg);
+	return ((val & SDA_VAL_IN) != 0);
+}
+
+static int intelfb_setup_i2c_bus(struct intelfb_info *dinfo,
+								 struct intelfb_i2c_chan *chan,
+								 const u32 reg, const char *name)
+{
+	int rc;
+
+	chan->dinfo					= dinfo;
+	chan->reg					= reg;
+	snprintf(chan->adapter.name, I2C_NAME_SIZE, "intelfb %s", name);
+	chan->adapter.owner			= THIS_MODULE;
+	chan->adapter.id			= I2C_HW_B_INTELFB;
+	chan->adapter.algo_data		= &chan->algo;
+	chan->adapter.dev.parent	= &chan->dinfo->pdev->dev;
+	chan->algo.setsda			= intelfb_gpio_setsda;
+	chan->algo.setscl			= intelfb_gpio_setscl;
+	chan->algo.getsda			= intelfb_gpio_getsda;
+	chan->algo.getscl			= intelfb_gpio_getscl;
+	chan->algo.udelay			= 40;
+	chan->algo.timeout			= 20;
+	chan->algo.data				= chan;
+
+	i2c_set_adapdata(&chan->adapter, chan);
+
+	/* Raise SCL and SDA */
+	intelfb_gpio_setsda(chan, 1);
+	intelfb_gpio_setscl(chan, 1);
+	udelay(20);
+
+	rc = i2c_bit_add_bus(&chan->adapter);
+	if (rc == 0)
+		DBG_MSG("I2C bus %s registered.\n", name);
+	else
+		WRN_MSG("Failed to register I2C bus %s.\n", name);
+	return rc;
+}
+
+void intelfb_create_i2c_busses(struct intelfb_info *dinfo)
+{
+	int i = 0;
+
+	/* everyone has at least a single analog output */
+	dinfo->num_outputs = 1;
+	dinfo->output[i].type = INTELFB_OUTPUT_ANALOG;
+
+	/* setup the DDC bus for analog output */
+	intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOA, "CRTDDC_A");
+	i++;
+
+    /* need to add the output busses for each device
+       - this function is very incomplete
+       - i915GM has LVDS and TVOUT for example
+    */
+    switch(dinfo->chipset) {
+	case INTEL_830M:
+	case INTEL_845G:
+	case INTEL_855GM:
+	case INTEL_865G:
+		dinfo->output[i].type = INTELFB_OUTPUT_DVO;
+		intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOD, "DVODDC_D");
+		intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, GPIOE, "DVOI2C_E");
+		i++;
+		break;
+	case INTEL_915G:
+	case INTEL_915GM:
+		/* has  some LVDS + tv-out */
+	case INTEL_945G:
+	case INTEL_945GM:
+		/* SDVO ports have a single control bus - 2 devices */
+		dinfo->output[i].type = INTELFB_OUTPUT_SDVO;
+		intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, GPIOE, "SDVOCTRL_E");
+		/* TODO: initialize the SDVO */
+//		I830SDVOInit(pScrn, i, DVOB);
+		i++;
+
+		/* set up SDVOC */
+		dinfo->output[i].type = INTELFB_OUTPUT_SDVO;
+		dinfo->output[i].i2c_bus = dinfo->output[i - 1].i2c_bus;
+		/* TODO: initialize the SDVO */
+//		I830SDVOInit(pScrn, i, DVOC);
+		i++;
+		break;
+	}
+	dinfo->num_outputs = i;
+}
+
+void intelfb_delete_i2c_busses(struct intelfb_info *dinfo)
+{
+	int i;
+
+	for (i = 0; i < MAX_OUTPUTS; i++) {
+		if (dinfo->output[i].i2c_bus.dinfo) {
+			i2c_bit_del_bus(&dinfo->output[i].i2c_bus.adapter);
+			dinfo->output[i].i2c_bus.dinfo = NULL;
+		}
+		if (dinfo->output[i].ddc_bus.dinfo) {
+			i2c_bit_del_bus(&dinfo->output[i].ddc_bus.adapter);
+			dinfo->output[i].ddc_bus.dinfo = NULL;
+		}
+	}
+}
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 06af89d..6f9de04 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -136,6 +136,8 @@
 static void __devinit get_initial_mode(struct intelfb_info *dinfo);
 static void update_dinfo(struct intelfb_info *dinfo,
 			 struct fb_var_screeninfo *var);
+static int intelfb_open(struct fb_info *info, int user);
+static int intelfb_release(struct fb_info *info, int user);
 static int intelfb_check_var(struct fb_var_screeninfo *var,
 			     struct fb_info *info);
 static int intelfb_set_par(struct fb_info *info);
@@ -194,6 +196,8 @@
 /* fb ops */
 static struct fb_ops intel_fb_ops = {
 	.owner =		THIS_MODULE,
+	.fb_open =              intelfb_open,
+	.fb_release =           intelfb_release,
 	.fb_check_var =         intelfb_check_var,
 	.fb_set_par =           intelfb_set_par,
 	.fb_setcolreg =		intelfb_setcolreg,
@@ -446,6 +450,8 @@
 	if (!dinfo)
 		return;
 
+	intelfbhw_disable_irq(dinfo);
+
 	fb_dealloc_cmap(&dinfo->info->cmap);
 	kfree(dinfo->info->pixmap.addr);
 
@@ -467,6 +473,11 @@
 		agp_free_memory(dinfo->gtt_ring_mem);
 	}
 
+#ifdef CONFIG_FB_INTEL_I2C
+	/* un-register I2C bus */
+	intelfb_delete_i2c_busses(dinfo);
+#endif
+
 	if (dinfo->mmio_base)
 		iounmap((void __iomem *)dinfo->mmio_base);
 	if (dinfo->aperture.virtual)
@@ -844,6 +855,11 @@
 	if (bailearly == 5)
 		bailout(dinfo);
 
+#ifdef CONFIG_FB_INTEL_I2C
+	/* register I2C bus */
+	intelfb_create_i2c_busses(dinfo);
+#endif
+
 	if (bailearly == 6)
 		bailout(dinfo);
 
@@ -888,6 +904,13 @@
 	}
 
 	dinfo->registered = 1;
+	dinfo->open = 0;
+
+	init_waitqueue_head(&dinfo->vsync.wait);
+	spin_lock_init(&dinfo->int_lock);
+	dinfo->irq_flags = 0;
+	dinfo->vsync.pan_display = 0;
+	dinfo->vsync.pan_offset = 0;
 
 	return 0;
 
@@ -1188,6 +1211,34 @@
  ***************************************************************/
 
 static int
+intelfb_open(struct fb_info *info, int user)
+{
+	struct intelfb_info *dinfo = GET_DINFO(info);
+
+	if (user) {
+		dinfo->open++;
+	}
+
+	return 0;
+}
+
+static int
+intelfb_release(struct fb_info *info, int user)
+{
+	struct intelfb_info *dinfo = GET_DINFO(info);
+
+	if (user) {
+		dinfo->open--;
+		msleep(1);
+		if (!dinfo->open) {
+			intelfbhw_disable_irq(dinfo);
+		}
+	}
+
+	return 0;
+}
+
+static int
 intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
 	int change_var = 0;
@@ -1433,6 +1484,19 @@
 intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
 	int retval = 0;
+	struct intelfb_info *dinfo = GET_DINFO(info);
+	u32 pipe = 0;
+
+	switch (cmd) {
+		case FBIO_WAITFORVSYNC:
+			if (get_user(pipe, (__u32 __user *)arg))
+				return -EFAULT;
+
+			retval = intelfbhw_wait_for_vsync(dinfo, pipe);
+			break;
+		default:
+			break;
+	}
 
 	return retval;
 }
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 2a9322f..f887f1e 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -32,6 +32,7 @@
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
 #include <linux/pagemap.h>
+#include <linux/interrupt.h>
 
 #include <asm/io.h>
 
@@ -368,7 +369,13 @@
 
 	offset += dinfo->fb.offset << 12;
 
-	OUTREG(DSPABASE, offset);
+	dinfo->vsync.pan_offset = offset;
+	if ((var->activate & FB_ACTIVATE_VBL) && !intelfbhw_enable_irq(dinfo, 0)) {
+		dinfo->vsync.pan_display = 1;
+	} else {
+		dinfo->vsync.pan_display = 0;
+		OUTREG(DSPABASE, offset);
+	}
 
 	return 0;
 }
@@ -585,6 +592,11 @@
 	hw->fw_blc_0 = INREG(FW_BLC_0);
 	hw->fw_blc_1 = INREG(FW_BLC_1);
 
+	hw->hwstam = INREG16(HWSTAM);
+	hw->ier = INREG16(IER);
+	hw->iir = INREG16(IIR);
+	hw->imr = INREG16(IMR);
+
 	return 0;
 }
 
@@ -613,6 +625,7 @@
 	return vco / p;
 }
 
+#if REGDUMP
 static void
 intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2)
 {
@@ -638,6 +651,7 @@
 	*o_p1 = p1;
 	*o_p2 = p2;
 }
+#endif
 
 
 void
@@ -794,6 +808,10 @@
 	printk("	FW_BLC_0		0x%08x\n", hw->fw_blc_0);
 	printk("	FW_BLC_1		0x%08x\n", hw->fw_blc_1);
 
+	printk("	HWSTAM			0x%04x\n", hw->hwstam);
+	printk("	IER			0x%04x\n", hw->ier);
+	printk("	IIR			0x%04x\n", hw->iir);
+	printk("	IMR			0x%04x\n", hw->imr);
 	printk("hw state dump end\n");
 #endif
 }
@@ -1932,3 +1950,119 @@
 		addr += 16;
 	}
 }
+
+static irqreturn_t
+intelfbhw_irq(int irq, void *dev_id, struct pt_regs *fp) {
+	int handled = 0;
+	u16 tmp;
+	struct intelfb_info *dinfo = (struct intelfb_info *)dev_id;
+
+	spin_lock(&dinfo->int_lock);
+
+	tmp = INREG16(IIR);
+	tmp &= VSYNC_PIPE_A_INTERRUPT;
+
+	if (tmp == 0) {
+		spin_unlock(&dinfo->int_lock);
+		return IRQ_RETVAL(handled);
+	}
+
+	OUTREG16(IIR, tmp);
+
+	if (tmp & VSYNC_PIPE_A_INTERRUPT) {
+		dinfo->vsync.count++;
+		if (dinfo->vsync.pan_display) {
+			dinfo->vsync.pan_display = 0;
+			OUTREG(DSPABASE, dinfo->vsync.pan_offset);
+		}
+		wake_up_interruptible(&dinfo->vsync.wait);
+		handled = 1;
+	}
+
+	spin_unlock(&dinfo->int_lock);
+
+	return IRQ_RETVAL(handled);
+}
+
+int
+intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable) {
+
+	if (!test_and_set_bit(0, &dinfo->irq_flags)) {
+		if (request_irq(dinfo->pdev->irq, intelfbhw_irq, SA_SHIRQ, "intelfb", dinfo)) {
+			clear_bit(0, &dinfo->irq_flags);
+			return -EINVAL;
+		}
+
+		spin_lock_irq(&dinfo->int_lock);
+		OUTREG16(HWSTAM, 0xfffe);
+		OUTREG16(IMR, 0x0);
+		OUTREG16(IER, VSYNC_PIPE_A_INTERRUPT);
+		spin_unlock_irq(&dinfo->int_lock);
+	} else if (reenable) {
+		u16 ier;
+
+		spin_lock_irq(&dinfo->int_lock);
+		ier = INREG16(IER);
+		if ((ier & VSYNC_PIPE_A_INTERRUPT)) {
+			DBG_MSG("someone disabled the IRQ [%08X]\n", ier);
+			OUTREG(IER, VSYNC_PIPE_A_INTERRUPT);
+		}
+		spin_unlock_irq(&dinfo->int_lock);
+	}
+	return 0;
+}
+
+void
+intelfbhw_disable_irq(struct intelfb_info *dinfo) {
+	u16 tmp;
+
+	if (test_and_clear_bit(0, &dinfo->irq_flags)) {
+		if (dinfo->vsync.pan_display) {
+			dinfo->vsync.pan_display = 0;
+			OUTREG(DSPABASE, dinfo->vsync.pan_offset);
+		}
+		spin_lock_irq(&dinfo->int_lock);
+		OUTREG16(HWSTAM, 0xffff);
+		OUTREG16(IMR, 0xffff);
+		OUTREG16(IER, 0x0);
+
+		tmp = INREG16(IIR);
+		OUTREG16(IIR, tmp);
+		spin_unlock_irq(&dinfo->int_lock);
+
+		free_irq(dinfo->pdev->irq, dinfo);
+	}
+}
+
+int
+intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) {
+	struct intelfb_vsync *vsync;
+	unsigned int count;
+	int ret;
+
+	switch (pipe) {
+		case 0:
+			vsync = &dinfo->vsync;
+			break;
+		default:
+			return -ENODEV;
+	}
+
+	ret = intelfbhw_enable_irq(dinfo, 0);
+	if (ret) {
+		return ret;
+	}
+
+	count = vsync->count;
+	ret = wait_event_interruptible_timeout(vsync->wait, count != vsync->count, HZ/10);
+	if (ret < 0) {
+		return ret;
+	}
+	if (ret == 0) {
+		intelfbhw_enable_irq(dinfo, 1);
+		DBG_MSG("wait_for_vsync timed out!\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h
index 10acda0..8c54ba8 100644
--- a/drivers/video/intelfb/intelfbhw.h
+++ b/drivers/video/intelfb/intelfbhw.h
@@ -88,6 +88,19 @@
 #define INSTDONE		0x2090
 #define PRI_RING_EMPTY			1
 
+#define HWSTAM			0x2098
+#define IER			0x20A0
+#define IIR			0x20A4
+#define IMR			0x20A8
+#define VSYNC_PIPE_A_INTERRUPT		(1 << 7)
+#define PIPE_A_EVENT_INTERRUPT		(1 << 4)
+#define VSYNC_PIPE_B_INTERRUPT		(1 << 5)
+#define PIPE_B_EVENT_INTERRUPT		(1 << 4)
+#define HOST_PORT_EVENT_INTERRUPT	(1 << 3)
+#define CAPTURE_EVENT_INTERRUPT		(1 << 2)
+#define USER_DEFINED_INTERRUPT		(1 << 1)
+#define BREAKPOINT_INTERRUPT		1
+
 #define INSTPM			0x20c0
 #define SYNC_FLUSH_ENABLE		(1 << 5)
 
@@ -113,6 +126,12 @@
 #define FW_DISPC_BL_SHIFT		8
 #define FW_DISPC_BL_MASK		0x7
 
+#define GPIOA             0x5010
+#define GPIOB             0x5014
+#define GPIOC             0x5018 // this may be external DDC on i830
+#define GPIOD             0x501C // this is DVO DDC
+#define GPIOE             0x5020 // this is DVO i2C
+#define GPIOF             0x5024
 
 /* PLL registers */
 #define VGA0_DIVISOR		0x06000
@@ -468,9 +487,12 @@
 
 /* I/O macros */
 #define INREG8(addr)	      readb((u8 __iomem *)(dinfo->mmio_base + (addr)))
+#define INREG16(addr)	      readw((u16 __iomem *)(dinfo->mmio_base + (addr)))
 #define INREG(addr)	      readl((u32 __iomem *)(dinfo->mmio_base + (addr)))
 #define OUTREG8(addr, val)    writeb((val),(u8 __iomem *)(dinfo->mmio_base + \
 							   (addr)))
+#define OUTREG16(addr, val)    writew((val),(u16 __iomem *)(dinfo->mmio_base + \
+							   (addr)))
 #define OUTREG(addr, val)     writel((val),(u32 __iomem *)(dinfo->mmio_base + \
                                      (addr)))
 
@@ -545,5 +567,8 @@
 extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width,
 				  int height, u8 *data);
 extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo);
+extern int intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable);
+extern void intelfbhw_disable_irq(struct intelfb_info *dinfo);
+extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe);
 
 #endif /* _INTELFBHW_H */
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index 9418519..0a8f750 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -193,6 +193,7 @@
 #define I2C_HW_B_RADEON		0x01001e /* radeon framebuffer driver */
 #define I2C_HW_B_EM28XX		0x01001f /* em28xx video capture cards */
 #define I2C_HW_B_CX2341X	0x010020 /* Conexant CX2341X MPEG encoder cards */
+#define I2C_HW_B_INTELFB	0x010021 /* intel framebuffer driver */
 
 /* --- PCF 8584 based algorithms					*/
 #define I2C_HW_P_LP		0x020000 /* Parallel port interface */