From: Takashi Iwai <tiwai@suse.de>
To: Chris Wilson <chris@chris-wilson.co.uk>
Cc: hcb@chaoticmind.net, intel-gfx@lists.freedesktop.org
Subject: Re: Thinkpad T420 and single/dual channel lvds
Date: Thu, 15 Mar 2012 14:30:35 +0100 [thread overview]
Message-ID: <s5hpqcevvno.wl%tiwai@suse.de> (raw)
In-Reply-To: <d08817$3homf2@azsmga001.ch.intel.com>
At Thu, 15 Mar 2012 13:25:08 +0000,
Chris Wilson wrote:
>
> On Thu, 15 Mar 2012 14:15:54 +0100, Takashi Iwai <tiwai@suse.de> wrote:
> > +static bool is_dual_link_lvds(struct drm_i915_private *dev_priv)
> > +{
> > + /* BIOS should set the proper LVDS register value at boot, but
> > + * in reality, it doesn't set the value when the lid is closed;
> > + * thus when a machine is booted with the lid closed, the LVDS
> > + * reg value can't be trusted. So we need to check "the value
> > + * to be set" in VBT at first.
> > + */
> > + if ((dev_priv->bios_lvds_val & LVDS_CLKB_POWER_MASK) ==
> > + LVDS_CLKB_POWER_UP)
> > + return true;
> > + if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) ==
>
> This is either PCH_LVDS or LVDS depending on the generation.
Oh, right. The revised patch is below.
thanks,
Takashi
---
From: Takashi Iwai <tiwai@suse.de>
Subject: [PATCH v2] drm/i915: Check VBIOS value for determining LVDS dual channel mode, too
Currently i915 driver checks [PCH_]LVDS register bits to decide
whether to set up the dual-link or the single-link mode. This relies
implicitly on that BIOS initializes the register properly at boot.
However, BIOS doesn't initialize it always. When the machine is
booted with the closed lid, BIOS skips the LVDS reg initialization.
This ends up in blank output on a machine with a dual-link LVDS when
you open the lid after the boot.
This patch adds a workaround for that problem by checking the initial
LVDS register value in VBT.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
v1->v2: Fix the register for gen<=4
drivers/gpu/drm/i915/i915_drv.h | 1 +
drivers/gpu/drm/i915/intel_bios.c | 22 ++++++++++++++++++++++
drivers/gpu/drm/i915/intel_display.c | 26 ++++++++++++++++++++------
3 files changed, 43 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 9689ca3..8c8e488 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -376,6 +376,7 @@ typedef struct drm_i915_private {
unsigned int lvds_use_ssc:1;
unsigned int display_clock_mode:1;
int lvds_ssc_freq;
+ unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */
struct {
int rate;
int lanes;
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 63880e2..e04f06d 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -173,6 +173,25 @@ get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data,
return (struct lvds_dvo_timing *)(entry + dvo_timing_offset);
}
+/* read the initial LVDS register value for the given panel mode */
+static unsigned int get_lvds_reg_val(const struct bdb_header *bdb,
+ const struct bdb_lvds_lfp_data_ptrs *ptrs,
+ int index)
+{
+ unsigned int ofs;
+ const struct lvds_fp_timing *timing;
+
+ if (index >= ARRAY_SIZE(ptrs->ptr))
+ return 0;
+ ofs = ptrs->ptr[index].fp_timing_offset;
+ if (ofs + sizeof(*timing) > bdb->bdb_size)
+ return 0;
+ timing = (const struct lvds_fp_timing *)((const u8 *)bdb + ofs);
+ if (timing->lvds_reg_val == -1)
+ return 0; /* just to be sure */
+ return timing->lvds_reg_val;
+}
+
/* Try to find integrated panel data */
static void
parse_lfp_panel_data(struct drm_i915_private *dev_priv,
@@ -243,6 +262,9 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
"Normal Clock %dKHz, downclock %dKHz\n",
panel_fixed_mode->clock, 10*downclock);
}
+
+ dev_priv->bios_lvds_val = get_lvds_reg_val(bdb, lvds_lfp_data_ptrs,
+ lvds_options->panel_type);
}
/* Try to find sdvo panel data */
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index f851db7..314af26 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -356,6 +356,23 @@ static const intel_limit_t intel_limits_ironlake_display_port = {
.find_pll = intel_find_pll_ironlake_dp,
};
+static bool is_dual_link_lvds(struct drm_i915_private *dev_priv,
+ unsigned int reg)
+{
+ /* BIOS should set the proper LVDS register value at boot, but
+ * in reality, it doesn't set the value when the lid is closed;
+ * thus when a machine is booted with the lid closed, the LVDS
+ * reg value can't be trusted. So we need to check "the value
+ * to be set" in VBT at first.
+ */
+ if ((dev_priv->bios_lvds_val & LVDS_CLKB_POWER_MASK) ==
+ LVDS_CLKB_POWER_UP)
+ return true;
+ if ((I915_READ(reg) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP)
+ return true;
+ return false;
+}
+
static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc,
int refclk)
{
@@ -364,8 +381,7 @@ static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc,
const intel_limit_t *limit;
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
- if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) ==
- LVDS_CLKB_POWER_UP) {
+ if (is_dual_link_lvds(dev_priv, PCH_LVDS)) {
/* LVDS dual channel */
if (refclk == 100000)
limit = &intel_limits_ironlake_dual_lvds_100m;
@@ -393,8 +409,7 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc)
const intel_limit_t *limit;
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
- if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
- LVDS_CLKB_POWER_UP)
+ if (is_dual_link_lvds(dev_priv, LVDS))
/* LVDS with dual channel */
limit = &intel_limits_g4x_dual_channel_lvds;
else
@@ -531,8 +546,7 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
* reliably set up different single/dual channel state, if we
* even can.
*/
- if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
- LVDS_CLKB_POWER_UP)
+ if (is_dual_link_lvds(dev_priv, LVDS))
clock.p2 = limit->p2.p2_fast;
else
clock.p2 = limit->p2.p2_slow;
--
1.7.9.2
next prev parent reply other threads:[~2012-03-15 13:30 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-03-14 12:37 Thinkpad T420 and single/dual channel lvds Helge Bahmann
2012-03-14 14:45 ` Adam Jackson
2012-03-14 16:44 ` Takashi Iwai
2012-03-14 18:09 ` Adam Jackson
2012-03-15 13:15 ` Takashi Iwai
2012-03-15 13:25 ` Chris Wilson
2012-03-15 13:30 ` Takashi Iwai [this message]
2012-03-15 14:42 ` Takashi Iwai
2012-03-16 15:33 ` Rodrigo Vivi
2012-03-16 19:55 ` Adam Jackson
2012-03-16 20:29 ` Takashi Iwai
2012-03-18 17:50 ` Daniel Vetter
2012-03-18 18:01 ` Andreas Heider
2012-03-18 20:26 ` Takashi Iwai
2012-03-18 20:24 ` Takashi Iwai
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=s5hpqcevvno.wl%tiwai@suse.de \
--to=tiwai@suse.de \
--cc=chris@chris-wilson.co.uk \
--cc=hcb@chaoticmind.net \
--cc=intel-gfx@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox