From mboxrd@z Thu Jan 1 00:00:00 1970 From: Thomas Richter Subject: [PATCH] Fix resume from suspend to RAM on IBM X30 (take two) Date: Mon, 01 Jun 2015 10:25:10 +0200 Message-ID: <556C16E6.2040309@math.tu-berlin.de> References: <555F7DAC.1060608@math.tu-berlin.de> <12029_1432625085_55641FBD_12029_12802_1_20150526072710.GE12971@phenom.ffwll.local> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------010206000108080402050603" Return-path: Received: from mx3.rus.uni-stuttgart.de (mx3.rus.uni-stuttgart.de [129.69.192.3]) by gabe.freedesktop.org (Postfix) with ESMTP id ADE266E00A for ; Mon, 1 Jun 2015 01:33:41 -0700 (PDT) In-Reply-To: <12029_1432625085_55641FBD_12029_12802_1_20150526072710.GE12971@phenom.ffwll.local> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" To: Daniel Vetter Cc: Intel Graphics Development List-Id: intel-gfx@lists.freedesktop.org This is a multi-part message in MIME format. --------------010206000108080402050603 Content-Type: text/plain; charset=windows-1252 Content-Transfer-Encoding: 7bit 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 --------------010206000108080402050603 Content-Type: text/x-patch; name="0001-Fix-resume-from-suspend-on-IBM-X30.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="0001-Fix-resume-from-suspend-on-IBM-X30.patch" >>From 457d52863d4dfb9d68091fca5716560dd4eb4441 Mon Sep 17 00:00:00 2001 From: Thomas Richter 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 --- 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 + * Thomas Richter * * Minor modifications (Dithering enable): * Thomas Richter @@ -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 --------------010206000108080402050603 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Content-Disposition: inline X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KSW50ZWwtZ2Z4 IG1haWxpbmcgbGlzdApJbnRlbC1nZnhAbGlzdHMuZnJlZWRlc2t0b3Aub3JnCmh0dHA6Ly9saXN0 cy5mcmVlZGVza3RvcC5vcmcvbWFpbG1hbi9saXN0aW5mby9pbnRlbC1nZngK --------------010206000108080402050603--