--- /dev/null
+From stefan.bader@canonical.com Thu Dec 17 06:03:08 2009
+From: Li Peng <peng.li@linux.intel.com>
+Date: Wed, 16 Dec 2009 16:33:26 +0100
+Subject: drm/i915: Fix sync to vblank when VGA output is turned off
+To: stable@kernel.org
+Cc: Eric Anholt <eric@anholt.net>, Li Peng <peng.li@intel.com>, Jesse Barnes <jbarnes@virtuousgeek.org>
+Message-ID: <1260977606-13664-3-git-send-email-stefan.bader@canonical.com>
+
+
+From: Li Peng <peng.li@linux.intel.com>
+
+commit 778c902640530371a169ad1c03566e7c51b09874 upstream
+
+In current vblank-wait implementation, if we turn off VGA output,
+drm_wait_vblank will still wait on the disabled pipe until timeout,
+because vblank on the pipe is assumed be enabled. This would cause
+slow system response on some system such as moblin.
+
+This patch resolve the issue by adding a drm helper function
+drm_vblank_off which explicitly clear vblank_enabled[crtc], wake up
+any waiting queue and save last vblank counter before turning off
+crtc. It also slightly change drm_vblank_get to ensure that we will
+will return immediately if trying to wait on a disabled pipe.
+
+Signed-off-by: Li Peng <peng.li@intel.com>
+Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
+[anholt: hand-applied for conflicts with overlay changes]
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Cc: Stefan Bader <stefan.bader@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/gpu/drm/drm_irq.c | 34 ++++++++++++++++++++++++++--------
+ drivers/gpu/drm/i915/intel_display.c | 1 +
+ include/drm/drmP.h | 1 +
+ 3 files changed, 28 insertions(+), 8 deletions(-)
+
+--- a/drivers/gpu/drm/drm_irq.c
++++ b/drivers/gpu/drm/drm_irq.c
+@@ -402,15 +402,21 @@ int drm_vblank_get(struct drm_device *de
+
+ spin_lock_irqsave(&dev->vbl_lock, irqflags);
+ /* Going from 0->1 means we have to enable interrupts again */
+- if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1 &&
+- !dev->vblank_enabled[crtc]) {
+- ret = dev->driver->enable_vblank(dev, crtc);
+- DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret);
+- if (ret)
++ if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) {
++ if (!dev->vblank_enabled[crtc]) {
++ ret = dev->driver->enable_vblank(dev, crtc);
++ DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret);
++ if (ret)
++ atomic_dec(&dev->vblank_refcount[crtc]);
++ else {
++ dev->vblank_enabled[crtc] = 1;
++ drm_update_vblank_count(dev, crtc);
++ }
++ }
++ } else {
++ if (!dev->vblank_enabled[crtc]) {
+ atomic_dec(&dev->vblank_refcount[crtc]);
+- else {
+- dev->vblank_enabled[crtc] = 1;
+- drm_update_vblank_count(dev, crtc);
++ ret = -EINVAL;
+ }
+ }
+ spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+@@ -437,6 +443,18 @@ void drm_vblank_put(struct drm_device *d
+ }
+ EXPORT_SYMBOL(drm_vblank_put);
+
++void drm_vblank_off(struct drm_device *dev, int crtc)
++{
++ unsigned long irqflags;
++
++ spin_lock_irqsave(&dev->vbl_lock, irqflags);
++ DRM_WAKEUP(&dev->vbl_queue[crtc]);
++ dev->vblank_enabled[crtc] = 0;
++ dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc);
++ spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
++}
++EXPORT_SYMBOL(drm_vblank_off);
++
+ /**
+ * drm_vblank_pre_modeset - account for vblanks across mode sets
+ * @dev: DRM device
+--- a/drivers/gpu/drm/i915/intel_display.c
++++ b/drivers/gpu/drm/i915/intel_display.c
+@@ -1562,6 +1562,7 @@ static void i9xx_crtc_dpms(struct drm_cr
+ intel_update_watermarks(dev);
+ /* Give the overlay scaler a chance to disable if it's on this pipe */
+ //intel_crtc_dpms_video(crtc, FALSE); TODO
++ drm_vblank_off(dev, pipe);
+
+ /* Disable the VGA plane that we never use */
+ i915_disable_vga(dev);
+--- a/include/drm/drmP.h
++++ b/include/drm/drmP.h
+@@ -1268,6 +1268,7 @@ extern u32 drm_vblank_count(struct drm_d
+ extern void drm_handle_vblank(struct drm_device *dev, int crtc);
+ extern int drm_vblank_get(struct drm_device *dev, int crtc);
+ extern void drm_vblank_put(struct drm_device *dev, int crtc);
++extern void drm_vblank_off(struct drm_device *dev, int crtc);
+ extern void drm_vblank_cleanup(struct drm_device *dev);
+ /* Modesetting support */
+ extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc);
--- /dev/null
+From 1496e89ae2a0962748e55165a590fa3209c6f158 Mon Sep 17 00:00:00 2001
+From: Darrick J. Wong <djwong@us.ibm.com>
+Date: Thu, 3 Dec 2009 16:19:59 +0000
+Subject: powerpc/therm_adt746x: Record pwm invert bit at module load time]
+
+From: Darrick J. Wong <djwong@us.ibm.com>
+
+commit 1496e89ae2a0962748e55165a590fa3209c6f158 upstream.
+
+In commit 0512a9a8e277a9de2820211eef964473b714ae65, we unilaterally zero the
+"pwm invert" bit in the fan behavior configuration register. On my PowerBook
+G4, this results in the fans going to full speed at low temperature and
+shutting off at high temperature because the pwm invert bit is supposed to be
+set.
+
+Therefore, record the pwm invert bit at driver load time, and write the bit
+into the fan behavior control register. This restores correct behavior on my
+PBG4 and should work around the bit being set to the wrong value after
+suspend/resume (which is what the original patch was trying to fix). It also
+fixes a minor omission where the pwm invert bit correction is NOT performed
+when switching into automatic mode.
+
+Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
+Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/macintosh/therm_adt746x.c | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+--- a/drivers/macintosh/therm_adt746x.c
++++ b/drivers/macintosh/therm_adt746x.c
+@@ -79,6 +79,7 @@ struct thermostat {
+ u8 limits[3];
+ int last_speed[2];
+ int last_var[2];
++ int pwm_inv[2];
+ };
+
+ static enum {ADT7460, ADT7467} therm_type;
+@@ -229,19 +230,23 @@ static void write_fan_speed(struct therm
+
+ if (speed >= 0) {
+ manual = read_reg(th, MANUAL_MODE[fan]);
++ manual &= ~INVERT_MASK;
+ write_reg(th, MANUAL_MODE[fan],
+- (manual|MANUAL_MASK) & (~INVERT_MASK));
++ manual | MANUAL_MASK | th->pwm_inv[fan]);
+ write_reg(th, FAN_SPD_SET[fan], speed);
+ } else {
+ /* back to automatic */
+ if(therm_type == ADT7460) {
+ manual = read_reg(th,
+ MANUAL_MODE[fan]) & (~MANUAL_MASK);
+-
++ manual &= ~INVERT_MASK;
++ manual |= th->pwm_inv[fan];
+ write_reg(th,
+ MANUAL_MODE[fan], manual|REM_CONTROL[fan]);
+ } else {
+ manual = read_reg(th, MANUAL_MODE[fan]);
++ manual &= ~INVERT_MASK;
++ manual |= th->pwm_inv[fan];
+ write_reg(th, MANUAL_MODE[fan], manual&(~AUTO_MASK));
+ }
+ }
+@@ -418,6 +423,10 @@ static int probe_thermostat(struct i2c_c
+
+ thermostat = th;
+
++ /* record invert bit status because fw can corrupt it after suspend */
++ th->pwm_inv[0] = read_reg(th, MANUAL_MODE[0]) & INVERT_MASK;
++ th->pwm_inv[1] = read_reg(th, MANUAL_MODE[1]) & INVERT_MASK;
++
+ /* be sure to really write fan speed the first time */
+ th->last_speed[0] = -2;
+ th->last_speed[1] = -2;