/[linux-patches]/genpatches-2.6/tags/3.4-10/2700_dual-channel-mode-vbios-check.patch
Gentoo

Contents of /genpatches-2.6/tags/3.4-10/2700_dual-channel-mode-vbios-check.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2192 - (show annotations) (download)
Fri Aug 17 23:46:53 2012 UTC (5 years, 11 months ago) by mpagano
File size: 6182 byte(s)
3.4-10 release
1 From: Takashi Iwai <tiwai@suse.de>
2 Date: Tue, 20 Mar 2012 12:07:05 +0000 (+0100)
3 Subject: drm/i915: Check VBIOS value for determining LVDS dual channel mode, too
4 X-Git-Tag: v3.5-rc1~83^2~140^2~83
5 X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git;a=commitdiff_plain;h=b03543857fd75876b96e10d4320b775e95041bb7
6
7 drm/i915: Check VBIOS value for determining LVDS dual channel mode, too
8
9 Currently i915 driver checks [PCH_]LVDS register bits to decide
10 whether to set up the dual-link or the single-link mode. This relies
11 implicitly on that BIOS initializes the register properly at boot.
12 However, BIOS doesn't initialize it always. When the machine is
13 booted with the closed lid, BIOS skips the LVDS reg initialization.
14 This ends up in blank output on a machine with a dual-link LVDS when
15 you open the lid after the boot.
16
17 This patch adds a workaround for that problem by checking the initial
18 LVDS register value in VBT.
19
20 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=37742
21 Tested-By: Paulo Zanoni <paulo.r.zanoni@intel.com>
22 Reviewed-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
23 Reviewed-by: Adam Jackson <ajax@redhat.com>
24 Signed-off-by: Takashi Iwai <tiwai@suse.de>
25 Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
26 ---
27
28 diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
29 index b6098b0..4cbed7f 100644
30 --- a/drivers/gpu/drm/i915/i915_drv.h
31 +++ b/drivers/gpu/drm/i915/i915_drv.h
32 @@ -406,6 +406,8 @@ typedef struct drm_i915_private {
33 unsigned int lvds_use_ssc:1;
34 unsigned int display_clock_mode:1;
35 int lvds_ssc_freq;
36 + unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */
37 + unsigned int lvds_val; /* used for checking LVDS channel mode */
38 struct {
39 int rate;
40 int lanes;
41 diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
42 index 0ae76d6..e4317da 100644
43 --- a/drivers/gpu/drm/i915/intel_bios.c
44 +++ b/drivers/gpu/drm/i915/intel_bios.c
45 @@ -173,6 +173,28 @@ get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data,
46 return (struct lvds_dvo_timing *)(entry + dvo_timing_offset);
47 }
48
49 +/* get lvds_fp_timing entry
50 + * this function may return NULL if the corresponding entry is invalid
51 + */
52 +static const struct lvds_fp_timing *
53 +get_lvds_fp_timing(const struct bdb_header *bdb,
54 + const struct bdb_lvds_lfp_data *data,
55 + const struct bdb_lvds_lfp_data_ptrs *ptrs,
56 + int index)
57 +{
58 + size_t data_ofs = (const u8 *)data - (const u8 *)bdb;
59 + u16 data_size = ((const u16 *)data)[-1]; /* stored in header */
60 + size_t ofs;
61 +
62 + if (index >= ARRAY_SIZE(ptrs->ptr))
63 + return NULL;
64 + ofs = ptrs->ptr[index].fp_timing_offset;
65 + if (ofs < data_ofs ||
66 + ofs + sizeof(struct lvds_fp_timing) > data_ofs + data_size)
67 + return NULL;
68 + return (const struct lvds_fp_timing *)((const u8 *)bdb + ofs);
69 +}
70 +
71 /* Try to find integrated panel data */
72 static void
73 parse_lfp_panel_data(struct drm_i915_private *dev_priv,
74 @@ -182,6 +204,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
75 const struct bdb_lvds_lfp_data *lvds_lfp_data;
76 const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs;
77 const struct lvds_dvo_timing *panel_dvo_timing;
78 + const struct lvds_fp_timing *fp_timing;
79 struct drm_display_mode *panel_fixed_mode;
80 int i, downclock;
81
82 @@ -243,6 +266,19 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
83 "Normal Clock %dKHz, downclock %dKHz\n",
84 panel_fixed_mode->clock, 10*downclock);
85 }
86 +
87 + fp_timing = get_lvds_fp_timing(bdb, lvds_lfp_data,
88 + lvds_lfp_data_ptrs,
89 + lvds_options->panel_type);
90 + if (fp_timing) {
91 + /* check the resolution, just to be sure */
92 + if (fp_timing->x_res == panel_fixed_mode->hdisplay &&
93 + fp_timing->y_res == panel_fixed_mode->vdisplay) {
94 + dev_priv->bios_lvds_val = fp_timing->lvds_reg_val;
95 + DRM_DEBUG_KMS("VBT initial LVDS value %x\n",
96 + dev_priv->bios_lvds_val);
97 + }
98 + }
99 }
100
101 /* Try to find sdvo panel data */
102 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
103 index 683002fb..a76ac2e 100644
104 --- a/drivers/gpu/drm/i915/intel_display.c
105 +++ b/drivers/gpu/drm/i915/intel_display.c
106 @@ -360,6 +360,27 @@ static const intel_limit_t intel_limits_ironlake_display_port = {
107 .find_pll = intel_find_pll_ironlake_dp,
108 };
109
110 +static bool is_dual_link_lvds(struct drm_i915_private *dev_priv,
111 + unsigned int reg)
112 +{
113 + unsigned int val;
114 +
115 + if (dev_priv->lvds_val)
116 + val = dev_priv->lvds_val;
117 + else {
118 + /* BIOS should set the proper LVDS register value at boot, but
119 + * in reality, it doesn't set the value when the lid is closed;
120 + * we need to check "the value to be set" in VBT when LVDS
121 + * register is uninitialized.
122 + */
123 + val = I915_READ(reg);
124 + if (!(val & ~LVDS_DETECTED))
125 + val = dev_priv->bios_lvds_val;
126 + dev_priv->lvds_val = val;
127 + }
128 + return (val & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP;
129 +}
130 +
131 static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc,
132 int refclk)
133 {
134 @@ -368,8 +389,7 @@ static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc,
135 const intel_limit_t *limit;
136
137 if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
138 - if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) ==
139 - LVDS_CLKB_POWER_UP) {
140 + if (is_dual_link_lvds(dev_priv, PCH_LVDS)) {
141 /* LVDS dual channel */
142 if (refclk == 100000)
143 limit = &intel_limits_ironlake_dual_lvds_100m;
144 @@ -397,8 +417,7 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc)
145 const intel_limit_t *limit;
146
147 if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
148 - if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
149 - LVDS_CLKB_POWER_UP)
150 + if (is_dual_link_lvds(dev_priv, LVDS))
151 /* LVDS with dual channel */
152 limit = &intel_limits_g4x_dual_channel_lvds;
153 else
154 @@ -536,8 +555,7 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
155 * reliably set up different single/dual channel state, if we
156 * even can.
157 */
158 - if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
159 - LVDS_CLKB_POWER_UP)
160 + if (is_dual_link_lvds(dev_priv, LVDS))
161 clock.p2 = limit->p2.p2_fast;
162 else
163 clock.p2 = limit->p2.p2_slow;

  ViewVC Help
Powered by ViewVC 1.1.20