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