All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Fix resume from suspend to RAM on IBM X30
@ 2015-05-22 19:04 Thomas Richter
  2015-05-26  7:27 ` Daniel Vetter
       [not found] ` <12029_1432625085_55641FBD_12029_12802_1_20150526072710.GE12971@phenom.ffwll.local>
  0 siblings, 2 replies; 5+ messages in thread
From: Thomas Richter @ 2015-05-22 19:04 UTC (permalink / raw)
  To: Intel Graphics Development

[-- Attachment #1: Type: text/plain, Size: 412 bytes --]

Hi folks,

this is re-submitting the intel DVO patch that closes bug #49838, namely
that resuming from suspend-to-RAM on the IBM x30 leaves the laptop with
a blank screen. See the attached patch for details.

Please let me know what else is missing to make this patch go into the
kernel. It has been tested by Stefan Monnier, see 
https://bugs.freedesktop.org/show_bug.cgi?id=49838
for details.

Thanks,
	Thomas

[-- Attachment #2: 0001-Fixes-for-IBM-x30-suspend-to-ram.patch --]
[-- Type: text/x-patch, Size: 8873 bytes --]

>From 8ea307cc203d217cb6513ace045678d06c23ad61 Mon Sep 17 00:00:00 2001
From: Thomas Richter <thor@math.tu-berlin.de>
Date: Fri, 22 May 2015 20:55:54 +0200
Subject: [PATCH 1/1] Fixes for IBM x30 suspend to ram.

This patch fixes the resume from suspend on the X30
thinkpad. The bug is due to the X30 bios failing to
restore the IVCH (DVO) registers, specifically the PLL
registers.

This patch makes a backup of the internal DVO registers upon
initialization - assuming that the BIOS sets up everything
correctly. The values are then restored whenever the mode
has to be restored.

Signed-off-by: Thomas Richter <thor@math.tu-berlin.de>
---
 drivers/gpu/drm/i915/dvo_ivch.c |  119 +++++++++++++++++++++++++++++++--------
 1 file changed, 95 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c
index baaf65b..d60edf8 100644
--- a/drivers/gpu/drm/i915/dvo_ivch.c
+++ b/drivers/gpu/drm/i915/dvo_ivch.c
@@ -22,6 +22,7 @@
  *
  * Authors:
  *    Eric Anholt <eric@anholt.net>
+ *    Thomas Richter <thor@math.tu-berlin.de>
  *
  */
 
@@ -59,6 +60,8 @@
 # define VR01_DVO_BYPASS_ENABLE		(1 << 1)
 /** Enables the DVO clock */
 # define VR01_DVO_ENABLE		(1 << 0)
+/** Enables dithering */
+# define VR01_DITHER_ENABLE             (1 << 4)
 
 /*
  * LCD Interface Format
@@ -83,7 +86,7 @@
 /*
  * LCD Vertical Display Size
  */
-#define VR21	0x20
+#define VR21	0x21
 
 /*
  * Panel power down status
@@ -148,16 +151,41 @@
 # define VR8F_POWER_MASK		(0x3c)
 # define VR8F_POWER_POS			(2)
 
+/* Some Bios implementations do not restore the DVO state upon
+ * resume from standby. Thus, this driver has to handle it
+ * instead. The following list contains all registers that
+ * require saving.
+ */
+static const uint16_t backup_addresses[] = {
+	0x11, 0x12,
+	0x18, 0x19, 0x1a, 0x1f,
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+	0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+	0x8e, 0x8f,
+	0x10		/* this must come last */
+};
+
 
 struct ivch_priv {
 	bool quiet;
 
 	uint16_t width, height;
+
+	/* Register backup */
+
+	uint16_t reg_backup[ARRAY_SIZE(backup_addresses)];
 };
 
 
 static void ivch_dump_regs(struct intel_dvo_device *dvo);
 
+static inline struct intel_gmbus *
+to_intel_gmbus(struct i2c_adapter *i2c)
+{
+	return container_of(i2c, struct intel_gmbus, adapter);
+}
+
+
 /**
  * Reads a register on the ivch.
  *
@@ -167,6 +195,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
 {
 	struct ivch_priv *priv = dvo->dev_priv;
 	struct i2c_adapter *adapter = dvo->i2c_bus;
+	struct intel_gmbus *bus = to_intel_gmbus(adapter);
 	u8 out_buf[1];
 	u8 in_buf[2];
 
@@ -191,17 +220,19 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
 	};
 
 	out_buf[0] = addr;
-
+	bus->force_bit++; /* the IVCH requires bit-banging */
 	if (i2c_transfer(adapter, msgs, 3) == 3) {
 		*data = (in_buf[1] << 8) | in_buf[0];
+		bus->force_bit--;
 		return true;
-	};
+	}
 
 	if (!priv->quiet) {
 		DRM_DEBUG_KMS("Unable to read register 0x%02x from "
 				"%s:%02x.\n",
 			  addr, adapter->name, dvo->slave_addr);
 	}
+	bus->force_bit--;
 	return false;
 }
 
@@ -210,6 +241,7 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
 {
 	struct ivch_priv *priv = dvo->dev_priv;
 	struct i2c_adapter *adapter = dvo->i2c_bus;
+	struct intel_gmbus *bus = to_intel_gmbus(adapter);
 	u8 out_buf[3];
 	struct i2c_msg msg = {
 		.addr = dvo->slave_addr,
@@ -221,15 +253,19 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
 	out_buf[0] = addr;
 	out_buf[1] = data & 0xff;
 	out_buf[2] = data >> 8;
+	bus->force_bit++; /* bit-banging required for the IVCH */
 
-	if (i2c_transfer(adapter, &msg, 1) == 1)
+	if (i2c_transfer(adapter, &msg, 1) == 1) {
+		bus->force_bit--;
 		return true;
+	}
 
 	if (!priv->quiet) {
 		DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
 			  addr, adapter->name, dvo->slave_addr);
 	}
 
+	bus->force_bit--;
 	return false;
 }
 
@@ -239,6 +275,7 @@ static bool ivch_init(struct intel_dvo_device *dvo,
 {
 	struct ivch_priv *priv;
 	uint16_t temp;
+	int i;
 
 	priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL);
 	if (priv == NULL)
@@ -266,6 +303,14 @@ static bool ivch_init(struct intel_dvo_device *dvo,
 	ivch_read(dvo, VR20, &priv->width);
 	ivch_read(dvo, VR21, &priv->height);
 
+	/* Make a backup of the registers to be able to restore them
+	 * upon suspend.
+	 */
+	for (i = 0; i < ARRAY_SIZE(backup_addresses); i++)
+		ivch_read(dvo, backup_addresses[i], priv->reg_backup + i);
+
+	ivch_dump_regs(dvo);
+
 	return true;
 
 out:
@@ -287,12 +332,31 @@ static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo,
 	return MODE_OK;
 }
 
+/* Restore the DVO registers after a resume
+ * from RAM. Registers have been saved during
+ * the initialization.
+ */
+static void ivch_reset(struct intel_dvo_device *dvo)
+{
+	struct ivch_priv *priv = dvo->dev_priv;
+	int i;
+
+	DRM_DEBUG_KMS("Resetting the IVCH registers\n");
+
+	ivch_write(dvo, VR10, 0x0000);
+
+	for (i = 0; i < ARRAY_SIZE(backup_addresses); i++)
+		ivch_write(dvo, backup_addresses[i], priv->reg_backup[i]);
+}
+
 /** Sets the power state of the panel connected to the ivch */
 static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
 {
 	int i;
 	uint16_t vr01, vr30, backlight;
 
+	ivch_reset(dvo);
+
 	/* Set the new power state of the panel. */
 	if (!ivch_read(dvo, VR01, &vr01))
 		return;
@@ -301,6 +365,7 @@ static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
 		backlight = 1;
 	else
 		backlight = 0;
+
 	ivch_write(dvo, VR80, backlight);
 
 	if (enable)
@@ -327,6 +392,8 @@ static bool ivch_get_hw_state(struct intel_dvo_device *dvo)
 {
 	uint16_t vr01;
 
+	ivch_reset(dvo);
+
 	/* Set the new power state of the panel. */
 	if (!ivch_read(dvo, VR01, &vr01))
 		return false;
@@ -344,16 +411,18 @@ static void ivch_mode_set(struct intel_dvo_device *dvo,
 	uint16_t vr40 = 0;
 	uint16_t vr01;
 
-	vr01 = 0;
-	vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE |
-		VR40_HORIZONTAL_INTERP_ENABLE);
+	ivch_reset(dvo);
+
+	vr01 = VR01_DITHER_ENABLE;
+	vr40 = VR40_STALL_ENABLE;
 
 	if (mode->hdisplay != adjusted_mode->hdisplay ||
 	    mode->vdisplay != adjusted_mode->vdisplay) {
 		uint16_t x_ratio, y_ratio;
 
 		vr01 |= VR01_PANEL_FIT_ENABLE;
-		vr40 |= VR40_CLOCK_GATING_ENABLE;
+		vr40 |= VR40_CLOCK_GATING_ENABLE | VR40_VERTICAL_INTERP_ENABLE |
+		  VR40_HORIZONTAL_INTERP_ENABLE;
 		x_ratio = (((mode->hdisplay - 1) << 16) /
 			   (adjusted_mode->hdisplay - 1)) >> 2;
 		y_ratio = (((mode->vdisplay - 1) << 16) /
@@ -369,7 +438,7 @@ static void ivch_mode_set(struct intel_dvo_device *dvo,
 	ivch_write(dvo, VR01, vr01);
 	ivch_write(dvo, VR40, vr40);
 
-	ivch_dump_regs(dvo);
+	/* ivch_dump_regs(dvo); */
 }
 
 static void ivch_dump_regs(struct intel_dvo_device *dvo)
@@ -377,41 +446,43 @@ static void ivch_dump_regs(struct intel_dvo_device *dvo)
 	uint16_t val;
 
 	ivch_read(dvo, VR00, &val);
-	DRM_LOG_KMS("VR00: 0x%04x\n", val);
+	DRM_DEBUG_KMS("VR00: 0x%04x\n", val);
 	ivch_read(dvo, VR01, &val);
-	DRM_LOG_KMS("VR01: 0x%04x\n", val);
+	DRM_DEBUG_KMS("VR01: 0x%04x\n", val);
+	ivch_read(dvo, VR10, &val);
+	DRM_DEBUG_KMS("VR10: 0x%04x\n", val);
 	ivch_read(dvo, VR30, &val);
-	DRM_LOG_KMS("VR30: 0x%04x\n", val);
+	DRM_DEBUG_KMS("VR30: 0x%04x\n", val);
 	ivch_read(dvo, VR40, &val);
-	DRM_LOG_KMS("VR40: 0x%04x\n", val);
+	DRM_DEBUG_KMS("VR40: 0x%04x\n", val);
 
 	/* GPIO registers */
 	ivch_read(dvo, VR80, &val);
-	DRM_LOG_KMS("VR80: 0x%04x\n", val);
+	DRM_DEBUG_KMS("VR80: 0x%04x\n", val);
 	ivch_read(dvo, VR81, &val);
-	DRM_LOG_KMS("VR81: 0x%04x\n", val);
+	DRM_DEBUG_KMS("VR81: 0x%04x\n", val);
 	ivch_read(dvo, VR82, &val);
-	DRM_LOG_KMS("VR82: 0x%04x\n", val);
+	DRM_DEBUG_KMS("VR82: 0x%04x\n", val);
 	ivch_read(dvo, VR83, &val);
-	DRM_LOG_KMS("VR83: 0x%04x\n", val);
+	DRM_DEBUG_KMS("VR83: 0x%04x\n", val);
 	ivch_read(dvo, VR84, &val);
-	DRM_LOG_KMS("VR84: 0x%04x\n", val);
+	DRM_DEBUG_KMS("VR84: 0x%04x\n", val);
 	ivch_read(dvo, VR85, &val);
-	DRM_LOG_KMS("VR85: 0x%04x\n", val);
+	DRM_DEBUG_KMS("VR85: 0x%04x\n", val);
 	ivch_read(dvo, VR86, &val);
-	DRM_LOG_KMS("VR86: 0x%04x\n", val);
+	DRM_DEBUG_KMS("VR86: 0x%04x\n", val);
 	ivch_read(dvo, VR87, &val);
-	DRM_LOG_KMS("VR87: 0x%04x\n", val);
+	DRM_DEBUG_KMS("VR87: 0x%04x\n", val);
 	ivch_read(dvo, VR88, &val);
-	DRM_LOG_KMS("VR88: 0x%04x\n", val);
+	DRM_DEBUG_KMS("VR88: 0x%04x\n", val);
 
 	/* Scratch register 0 - AIM Panel type */
 	ivch_read(dvo, VR8E, &val);
-	DRM_LOG_KMS("VR8E: 0x%04x\n", val);
+	DRM_DEBUG_KMS("VR8E: 0x%04x\n", val);
 
 	/* Scratch register 1 - Status register */
 	ivch_read(dvo, VR8F, &val);
-	DRM_LOG_KMS("VR8F: 0x%04x\n", val);
+	DRM_DEBUG_KMS("VR8F: 0x%04x\n", val);
 }
 
 static void ivch_destroy(struct intel_dvo_device *dvo)
-- 
1.7.10.4


[-- Attachment #3: Type: text/plain, Size: 159 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH] Fix resume from suspend to RAM on IBM X30
  2015-05-22 19:04 [PATCH] Fix resume from suspend to RAM on IBM X30 Thomas Richter
@ 2015-05-26  7:27 ` Daniel Vetter
       [not found] ` <12029_1432625085_55641FBD_12029_12802_1_20150526072710.GE12971@phenom.ffwll.local>
  1 sibling, 0 replies; 5+ messages in thread
From: Daniel Vetter @ 2015-05-26  7:27 UTC (permalink / raw)
  To: Thomas Richter; +Cc: Intel Graphics Development

On Fri, May 22, 2015 at 09:04:12PM +0200, Thomas Richter wrote:
> Hi folks,
> 
> this is re-submitting the intel DVO patch that closes bug #49838, namely
> that resuming from suspend-to-RAM on the IBM x30 leaves the laptop with
> a blank screen. See the attached patch for details.
> 
> Please let me know what else is missing to make this patch go into the
> kernel. It has been tested by Stefan Monnier, see
> https://bugs.freedesktop.org/show_bug.cgi?id=49838
> for details.
> 
> Thanks,
> 	Thomas

> From 8ea307cc203d217cb6513ace045678d06c23ad61 Mon Sep 17 00:00:00 2001
> From: Thomas Richter <thor@math.tu-berlin.de>
> Date: Fri, 22 May 2015 20:55:54 +0200
> Subject: [PATCH 1/1] Fixes for IBM x30 suspend to ram.
> 
> This patch fixes the resume from suspend on the X30
> thinkpad. The bug is due to the X30 bios failing to
> restore the IVCH (DVO) registers, specifically the PLL
> registers.
> 
> This patch makes a backup of the internal DVO registers upon
> initialization - assuming that the BIOS sets up everything
> correctly. The values are then restored whenever the mode
> has to be restored.
> 
> Signed-off-by: Thomas Richter <thor@math.tu-berlin.de>

Ok patch format looks good now, but unfortunately they have pretty heavy
conflicts with drm-intel-nightly. Can you please rebase onto latest
upstream and resubmit? Applies to both patches.

One more comment below.

> ---
>  drivers/gpu/drm/i915/dvo_ivch.c |  119 +++++++++++++++++++++++++++++++--------
>  1 file changed, 95 insertions(+), 24 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c
> index baaf65b..d60edf8 100644
> --- a/drivers/gpu/drm/i915/dvo_ivch.c
> +++ b/drivers/gpu/drm/i915/dvo_ivch.c
> @@ -22,6 +22,7 @@
>   *
>   * Authors:
>   *    Eric Anholt <eric@anholt.net>
> + *    Thomas Richter <thor@math.tu-berlin.de>
>   *
>   */
>  
> @@ -59,6 +60,8 @@
>  # define VR01_DVO_BYPASS_ENABLE		(1 << 1)
>  /** Enables the DVO clock */
>  # define VR01_DVO_ENABLE		(1 << 0)
> +/** Enables dithering */
> +# define VR01_DITHER_ENABLE             (1 << 4)
>  
>  /*
>   * LCD Interface Format
> @@ -83,7 +86,7 @@
>  /*
>   * LCD Vertical Display Size
>   */
> -#define VR21	0x20
> +#define VR21	0x21
>  
>  /*
>   * Panel power down status
> @@ -148,16 +151,41 @@
>  # define VR8F_POWER_MASK		(0x3c)
>  # define VR8F_POWER_POS			(2)
>  
> +/* Some Bios implementations do not restore the DVO state upon
> + * resume from standby. Thus, this driver has to handle it
> + * instead. The following list contains all registers that
> + * require saving.
> + */
> +static const uint16_t backup_addresses[] = {
> +	0x11, 0x12,
> +	0x18, 0x19, 0x1a, 0x1f,
> +	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
> +	0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
> +	0x8e, 0x8f,
> +	0x10		/* this must come last */
> +};
> +
>  
>  struct ivch_priv {
>  	bool quiet;
>  
>  	uint16_t width, height;
> +
> +	/* Register backup */
> +
> +	uint16_t reg_backup[ARRAY_SIZE(backup_addresses)];
>  };
>  
>  
>  static void ivch_dump_regs(struct intel_dvo_device *dvo);
>  
> +static inline struct intel_gmbus *
> +to_intel_gmbus(struct i2c_adapter *i2c)
> +{
> +	return container_of(i2c, struct intel_gmbus, adapter);
> +}
> +
> +
>  /**
>   * Reads a register on the ivch.
>   *
> @@ -167,6 +195,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
>  {
>  	struct ivch_priv *priv = dvo->dev_priv;
>  	struct i2c_adapter *adapter = dvo->i2c_bus;
> +	struct intel_gmbus *bus = to_intel_gmbus(adapter);
>  	u8 out_buf[1];
>  	u8 in_buf[2];
>  
> @@ -191,17 +220,19 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
>  	};
>  
>  	out_buf[0] = addr;
> -
> +	bus->force_bit++; /* the IVCH requires bit-banging */
>  	if (i2c_transfer(adapter, msgs, 3) == 3) {
>  		*data = (in_buf[1] << 8) | in_buf[0];
> +		bus->force_bit--;
>  		return true;
> -	};
> +	}
>  
>  	if (!priv->quiet) {
>  		DRM_DEBUG_KMS("Unable to read register 0x%02x from "
>  				"%s:%02x.\n",
>  			  addr, adapter->name, dvo->slave_addr);
>  	}
> +	bus->force_bit--;

There's no gmbus on i830M, this should be a no-op. Are you sure this is
required? Also the correct way to do this is by calling
intel_gmbus_force_bit.
-Daniel

>  	return false;
>  }
>  
> @@ -210,6 +241,7 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
>  {
>  	struct ivch_priv *priv = dvo->dev_priv;
>  	struct i2c_adapter *adapter = dvo->i2c_bus;
> +	struct intel_gmbus *bus = to_intel_gmbus(adapter);
>  	u8 out_buf[3];
>  	struct i2c_msg msg = {
>  		.addr = dvo->slave_addr,
> @@ -221,15 +253,19 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
>  	out_buf[0] = addr;
>  	out_buf[1] = data & 0xff;
>  	out_buf[2] = data >> 8;
> +	bus->force_bit++; /* bit-banging required for the IVCH */
>  
> -	if (i2c_transfer(adapter, &msg, 1) == 1)
> +	if (i2c_transfer(adapter, &msg, 1) == 1) {
> +		bus->force_bit--;
>  		return true;
> +	}
>  
>  	if (!priv->quiet) {
>  		DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
>  			  addr, adapter->name, dvo->slave_addr);
>  	}
>  
> +	bus->force_bit--;
>  	return false;
>  }
>  
> @@ -239,6 +275,7 @@ static bool ivch_init(struct intel_dvo_device *dvo,
>  {
>  	struct ivch_priv *priv;
>  	uint16_t temp;
> +	int i;
>  
>  	priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL);
>  	if (priv == NULL)
> @@ -266,6 +303,14 @@ static bool ivch_init(struct intel_dvo_device *dvo,
>  	ivch_read(dvo, VR20, &priv->width);
>  	ivch_read(dvo, VR21, &priv->height);
>  
> +	/* Make a backup of the registers to be able to restore them
> +	 * upon suspend.
> +	 */
> +	for (i = 0; i < ARRAY_SIZE(backup_addresses); i++)
> +		ivch_read(dvo, backup_addresses[i], priv->reg_backup + i);
> +
> +	ivch_dump_regs(dvo);
> +
>  	return true;
>  
>  out:
> @@ -287,12 +332,31 @@ static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo,
>  	return MODE_OK;
>  }
>  
> +/* Restore the DVO registers after a resume
> + * from RAM. Registers have been saved during
> + * the initialization.
> + */
> +static void ivch_reset(struct intel_dvo_device *dvo)
> +{
> +	struct ivch_priv *priv = dvo->dev_priv;
> +	int i;
> +
> +	DRM_DEBUG_KMS("Resetting the IVCH registers\n");
> +
> +	ivch_write(dvo, VR10, 0x0000);
> +
> +	for (i = 0; i < ARRAY_SIZE(backup_addresses); i++)
> +		ivch_write(dvo, backup_addresses[i], priv->reg_backup[i]);
> +}
> +
>  /** Sets the power state of the panel connected to the ivch */
>  static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
>  {
>  	int i;
>  	uint16_t vr01, vr30, backlight;
>  
> +	ivch_reset(dvo);
> +
>  	/* Set the new power state of the panel. */
>  	if (!ivch_read(dvo, VR01, &vr01))
>  		return;
> @@ -301,6 +365,7 @@ static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
>  		backlight = 1;
>  	else
>  		backlight = 0;
> +
>  	ivch_write(dvo, VR80, backlight);
>  
>  	if (enable)
> @@ -327,6 +392,8 @@ static bool ivch_get_hw_state(struct intel_dvo_device *dvo)
>  {
>  	uint16_t vr01;
>  
> +	ivch_reset(dvo);
> +
>  	/* Set the new power state of the panel. */
>  	if (!ivch_read(dvo, VR01, &vr01))
>  		return false;
> @@ -344,16 +411,18 @@ static void ivch_mode_set(struct intel_dvo_device *dvo,
>  	uint16_t vr40 = 0;
>  	uint16_t vr01;
>  
> -	vr01 = 0;
> -	vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE |
> -		VR40_HORIZONTAL_INTERP_ENABLE);
> +	ivch_reset(dvo);
> +
> +	vr01 = VR01_DITHER_ENABLE;
> +	vr40 = VR40_STALL_ENABLE;
>  
>  	if (mode->hdisplay != adjusted_mode->hdisplay ||
>  	    mode->vdisplay != adjusted_mode->vdisplay) {
>  		uint16_t x_ratio, y_ratio;
>  
>  		vr01 |= VR01_PANEL_FIT_ENABLE;
> -		vr40 |= VR40_CLOCK_GATING_ENABLE;
> +		vr40 |= VR40_CLOCK_GATING_ENABLE | VR40_VERTICAL_INTERP_ENABLE |
> +		  VR40_HORIZONTAL_INTERP_ENABLE;
>  		x_ratio = (((mode->hdisplay - 1) << 16) /
>  			   (adjusted_mode->hdisplay - 1)) >> 2;
>  		y_ratio = (((mode->vdisplay - 1) << 16) /
> @@ -369,7 +438,7 @@ static void ivch_mode_set(struct intel_dvo_device *dvo,
>  	ivch_write(dvo, VR01, vr01);
>  	ivch_write(dvo, VR40, vr40);
>  
> -	ivch_dump_regs(dvo);
> +	/* ivch_dump_regs(dvo); */
>  }
>  
>  static void ivch_dump_regs(struct intel_dvo_device *dvo)
> @@ -377,41 +446,43 @@ static void ivch_dump_regs(struct intel_dvo_device *dvo)
>  	uint16_t val;
>  
>  	ivch_read(dvo, VR00, &val);
> -	DRM_LOG_KMS("VR00: 0x%04x\n", val);
> +	DRM_DEBUG_KMS("VR00: 0x%04x\n", val);
>  	ivch_read(dvo, VR01, &val);
> -	DRM_LOG_KMS("VR01: 0x%04x\n", val);
> +	DRM_DEBUG_KMS("VR01: 0x%04x\n", val);
> +	ivch_read(dvo, VR10, &val);
> +	DRM_DEBUG_KMS("VR10: 0x%04x\n", val);
>  	ivch_read(dvo, VR30, &val);
> -	DRM_LOG_KMS("VR30: 0x%04x\n", val);
> +	DRM_DEBUG_KMS("VR30: 0x%04x\n", val);
>  	ivch_read(dvo, VR40, &val);
> -	DRM_LOG_KMS("VR40: 0x%04x\n", val);
> +	DRM_DEBUG_KMS("VR40: 0x%04x\n", val);
>  
>  	/* GPIO registers */
>  	ivch_read(dvo, VR80, &val);
> -	DRM_LOG_KMS("VR80: 0x%04x\n", val);
> +	DRM_DEBUG_KMS("VR80: 0x%04x\n", val);
>  	ivch_read(dvo, VR81, &val);
> -	DRM_LOG_KMS("VR81: 0x%04x\n", val);
> +	DRM_DEBUG_KMS("VR81: 0x%04x\n", val);
>  	ivch_read(dvo, VR82, &val);
> -	DRM_LOG_KMS("VR82: 0x%04x\n", val);
> +	DRM_DEBUG_KMS("VR82: 0x%04x\n", val);
>  	ivch_read(dvo, VR83, &val);
> -	DRM_LOG_KMS("VR83: 0x%04x\n", val);
> +	DRM_DEBUG_KMS("VR83: 0x%04x\n", val);
>  	ivch_read(dvo, VR84, &val);
> -	DRM_LOG_KMS("VR84: 0x%04x\n", val);
> +	DRM_DEBUG_KMS("VR84: 0x%04x\n", val);
>  	ivch_read(dvo, VR85, &val);
> -	DRM_LOG_KMS("VR85: 0x%04x\n", val);
> +	DRM_DEBUG_KMS("VR85: 0x%04x\n", val);
>  	ivch_read(dvo, VR86, &val);
> -	DRM_LOG_KMS("VR86: 0x%04x\n", val);
> +	DRM_DEBUG_KMS("VR86: 0x%04x\n", val);
>  	ivch_read(dvo, VR87, &val);
> -	DRM_LOG_KMS("VR87: 0x%04x\n", val);
> +	DRM_DEBUG_KMS("VR87: 0x%04x\n", val);
>  	ivch_read(dvo, VR88, &val);
> -	DRM_LOG_KMS("VR88: 0x%04x\n", val);
> +	DRM_DEBUG_KMS("VR88: 0x%04x\n", val);
>  
>  	/* Scratch register 0 - AIM Panel type */
>  	ivch_read(dvo, VR8E, &val);
> -	DRM_LOG_KMS("VR8E: 0x%04x\n", val);
> +	DRM_DEBUG_KMS("VR8E: 0x%04x\n", val);
>  
>  	/* Scratch register 1 - Status register */
>  	ivch_read(dvo, VR8F, &val);
> -	DRM_LOG_KMS("VR8F: 0x%04x\n", val);
> +	DRM_DEBUG_KMS("VR8F: 0x%04x\n", val);
>  }
>  
>  static void ivch_destroy(struct intel_dvo_device *dvo)
> -- 
> 1.7.10.4
> 


-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH] Fix resume from suspend to RAM on IBM X30 (take two)
       [not found] ` <12029_1432625085_55641FBD_12029_12802_1_20150526072710.GE12971@phenom.ffwll.local>
@ 2015-06-01  8:25   ` Thomas Richter
  2015-06-15 10:21     ` Daniel Vetter
  0 siblings, 1 reply; 5+ messages in thread
From: Thomas Richter @ 2015-06-01  8:25 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development

[-- Attachment #1: Type: text/plain, Size: 951 bytes --]

Hi Daniel, hi Ville,

as suggested, I again checked against the latest drm-intel-nightly
branch and indeed, the patch as originally submitted does not apply
there. So I recompiled the patch again (see attachment) which works now
correctly with the latest branch.

As suggested, I made a couple of additional changes:

* No longer forces bit-banging on. As Daniel observed, this is not
really required, and I checked that, indeed, it is not.

* Ville made a comment a while ago that we should not enable the
extended panel-scaling of the IVCH, so I removed it. In fact, as the X30
bios does not restore registers during resume, it also fails to restore
the (undocumented) values of the advanced interpolation polynomials and
as such degrades the image quality when resuming from suspend.

Other than that, this patch has been successfully tested both on an IBM
X30 and on an IBM R31 ThinkPad, both making use of the IVCH DVO chip.

Greetings,
	Thomas


[-- Attachment #2: 0001-Fix-resume-from-suspend-on-IBM-X30.patch --]
[-- Type: text/x-patch, Size: 5029 bytes --]

>From 457d52863d4dfb9d68091fca5716560dd4eb4441 Mon Sep 17 00:00:00 2001
From: Thomas Richter <thor@math.tu-berlin.de>
Date: Sat, 30 May 2015 20:25:53 +0200
Subject: [PATCH 1/1] Fix resume from suspend on IBM X30

This patch fixes the resume from suspend-to-ram on the IBM X30
laptop. The problem is caused by the Bios missing to re-initialize
the iVCH registers, especially the PLL registers.

This patch records the iVCH registers during initialization, and
re-installs this register set when resuming.

Signed-off-by: Thomas Richter <thor@math.tu-berlin.de>
---
 drivers/gpu/drm/i915/dvo_ivch.c |   63 +++++++++++++++++++++++++++++++++++----
 1 file changed, 57 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c
index 89b08a8..732ce87 100644
--- a/drivers/gpu/drm/i915/dvo_ivch.c
+++ b/drivers/gpu/drm/i915/dvo_ivch.c
@@ -22,6 +22,7 @@
  *
  * Authors:
  *    Eric Anholt <eric@anholt.net>
+ *    Thomas Richter <thor@math.tu-berlin.de>
  *
  * Minor modifications (Dithering enable):
  *    Thomas Richter <thor@math.tu-berlin.de>
@@ -90,7 +91,7 @@
 /*
  * LCD Vertical Display Size
  */
-#define VR21	0x20
+#define VR21	0x21
 
 /*
  * Panel power down status
@@ -155,16 +156,33 @@
 # define VR8F_POWER_MASK		(0x3c)
 # define VR8F_POWER_POS			(2)
 
+/* Some Bios implementations do not restore the DVO state upon
+ * resume from standby. Thus, this driver has to handle it
+ * instead. The following list contains all registers that
+ * require saving.
+ */
+static const uint16_t backup_addresses[] = {
+	0x11, 0x12,
+	0x18, 0x19, 0x1a, 0x1f,
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+	0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+	0x8e, 0x8f,
+	0x10		/* this must come last */
+};
+
 
 struct ivch_priv {
 	bool quiet;
 
 	uint16_t width, height;
+
+	/* Register backup */
+
+	uint16_t reg_backup[ARRAY_SIZE(backup_addresses)];
 };
 
 
 static void ivch_dump_regs(struct intel_dvo_device *dvo);
-
 /**
  * Reads a register on the ivch.
  *
@@ -246,6 +264,7 @@ static bool ivch_init(struct intel_dvo_device *dvo,
 {
 	struct ivch_priv *priv;
 	uint16_t temp;
+	int i;
 
 	priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL);
 	if (priv == NULL)
@@ -273,6 +292,14 @@ static bool ivch_init(struct intel_dvo_device *dvo,
 	ivch_read(dvo, VR20, &priv->width);
 	ivch_read(dvo, VR21, &priv->height);
 
+	/* Make a backup of the registers to be able to restore them
+	 * upon suspend.
+	 */
+	for (i = 0; i < ARRAY_SIZE(backup_addresses); i++)
+		ivch_read(dvo, backup_addresses[i], priv->reg_backup + i);
+
+	ivch_dump_regs(dvo);
+
 	return true;
 
 out:
@@ -294,12 +321,31 @@ static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo,
 	return MODE_OK;
 }
 
+/* Restore the DVO registers after a resume
+ * from RAM. Registers have been saved during
+ * the initialization.
+ */
+static void ivch_reset(struct intel_dvo_device *dvo)
+{
+	struct ivch_priv *priv = dvo->dev_priv;
+	int i;
+
+	DRM_DEBUG_KMS("Resetting the IVCH registers\n");
+
+	ivch_write(dvo, VR10, 0x0000);
+
+	for (i = 0; i < ARRAY_SIZE(backup_addresses); i++)
+		ivch_write(dvo, backup_addresses[i], priv->reg_backup[i]);
+}
+
 /** Sets the power state of the panel connected to the ivch */
 static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
 {
 	int i;
 	uint16_t vr01, vr30, backlight;
 
+	ivch_reset(dvo);
+
 	/* Set the new power state of the panel. */
 	if (!ivch_read(dvo, VR01, &vr01))
 		return;
@@ -308,6 +354,7 @@ static void ivch_dpms(struct intel_dvo_device *dvo, bool enable)
 		backlight = 1;
 	else
 		backlight = 0;
+
 	ivch_write(dvo, VR80, backlight);
 
 	if (enable)
@@ -334,6 +381,8 @@ static bool ivch_get_hw_state(struct intel_dvo_device *dvo)
 {
 	uint16_t vr01;
 
+	ivch_reset(dvo);
+
 	/* Set the new power state of the panel. */
 	if (!ivch_read(dvo, VR01, &vr01))
 		return false;
@@ -348,11 +397,15 @@ static void ivch_mode_set(struct intel_dvo_device *dvo,
 			  struct drm_display_mode *mode,
 			  struct drm_display_mode *adjusted_mode)
 {
+	struct ivch_priv *priv = dvo->dev_priv;
 	uint16_t vr40 = 0;
 	uint16_t vr01 = 0;
 	uint16_t vr10;
 
-	ivch_read(dvo, VR10, &vr10);
+	ivch_reset(dvo);
+
+	vr10 = priv->reg_backup[ARRAY_SIZE(backup_addresses) - 1];
+
 	/* Enable dithering for 18 bpp pipelines */
 	vr10 &= VR10_INTERFACE_DEPTH_MASK;
 	if (vr10 == VR10_INTERFACE_2X18 || vr10 == VR10_INTERFACE_1X18)
@@ -366,7 +419,7 @@ static void ivch_mode_set(struct intel_dvo_device *dvo,
 		uint16_t x_ratio, y_ratio;
 
 		vr01 |= VR01_PANEL_FIT_ENABLE;
-		vr40 |= VR40_CLOCK_GATING_ENABLE | VR40_ENHANCED_PANEL_FITTING;
+		vr40 |= VR40_CLOCK_GATING_ENABLE;
 		x_ratio = (((mode->hdisplay - 1) << 16) /
 			   (adjusted_mode->hdisplay - 1)) >> 2;
 		y_ratio = (((mode->vdisplay - 1) << 16) /
@@ -381,8 +434,6 @@ static void ivch_mode_set(struct intel_dvo_device *dvo,
 
 	ivch_write(dvo, VR01, vr01);
 	ivch_write(dvo, VR40, vr40);
-
-	ivch_dump_regs(dvo);
 }
 
 static void ivch_dump_regs(struct intel_dvo_device *dvo)
-- 
1.7.10.4


[-- Attachment #3: Type: text/plain, Size: 159 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH] Fix resume from suspend to RAM on IBM X30 (take two)
  2015-06-01  8:25   ` [PATCH] Fix resume from suspend to RAM on IBM X30 (take two) Thomas Richter
@ 2015-06-15 10:21     ` Daniel Vetter
  2015-06-15 13:46       ` Stefan Monnier
  0 siblings, 1 reply; 5+ messages in thread
From: Daniel Vetter @ 2015-06-15 10:21 UTC (permalink / raw)
  To: Thomas Richter; +Cc: Intel Graphics Development

On Mon, Jun 01, 2015 at 10:25:10AM +0200, Thomas Richter wrote:
> Hi Daniel, hi Ville,
> 
> as suggested, I again checked against the latest drm-intel-nightly
> branch and indeed, the patch as originally submitted does not apply
> there. So I recompiled the patch again (see attachment) which works now
> correctly with the latest branch.
> 
> As suggested, I made a couple of additional changes:
> 
> * No longer forces bit-banging on. As Daniel observed, this is not
> really required, and I checked that, indeed, it is not.
> 
> * Ville made a comment a while ago that we should not enable the
> extended panel-scaling of the IVCH, so I removed it. In fact, as the X30
> bios does not restore registers during resume, it also fails to restore
> the (undocumented) values of the advanced interpolation polynomials and
> as such degrades the image quality when resuming from suspend.
> 
> Other than that, this patch has been successfully tested both on an IBM
> X30 and on an IBM R31 ThinkPad, both making use of the IVCH DVO chip.

Yup this one applies cleanly now. Queued for -next, thanks for the patch.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Fix resume from suspend to RAM on IBM X30 (take two)
  2015-06-15 10:21     ` Daniel Vetter
@ 2015-06-15 13:46       ` Stefan Monnier
  0 siblings, 0 replies; 5+ messages in thread
From: Stefan Monnier @ 2015-06-15 13:46 UTC (permalink / raw)
  To: intel-gfx

> Yup this one applies cleanly now. Queued for -next, thanks for the patch.

Yay!  Thanks!


        Stefan

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2015-06-15 13:47 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-22 19:04 [PATCH] Fix resume from suspend to RAM on IBM X30 Thomas Richter
2015-05-26  7:27 ` Daniel Vetter
     [not found] ` <12029_1432625085_55641FBD_12029_12802_1_20150526072710.GE12971@phenom.ffwll.local>
2015-06-01  8:25   ` [PATCH] Fix resume from suspend to RAM on IBM X30 (take two) Thomas Richter
2015-06-15 10:21     ` Daniel Vetter
2015-06-15 13:46       ` Stefan Monnier

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.