blob: 9089604011f9217b5627187435f951945a5fc0f0 [file] [log] [blame]
Jesse Barnes79e53942008-11-07 14:24:08 -08001/*
2 * Copyright © 2006-2007 Intel Corporation
3 * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Eric Anholt <eric@anholt.net>
26 * Dave Airlie <airlied@linux.ie>
27 * Jesse Barnes <jesse.barnes@intel.com>
28 */
29
Jesse Barnesc1c7af62009-09-10 15:28:03 -070030#include <acpi/button.h>
Paul Collins565dcd42009-02-04 23:05:41 +130031#include <linux/dmi.h>
Jesse Barnes79e53942008-11-07 14:24:08 -080032#include <linux/i2c.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Jesse Barnes79e53942008-11-07 14:24:08 -080034#include "drmP.h"
35#include "drm.h"
36#include "drm_crtc.h"
37#include "drm_edid.h"
38#include "intel_drv.h"
39#include "i915_drm.h"
40#include "i915_drv.h"
Zhao Yakuie99da352009-06-26 09:46:18 +080041#include <linux/acpi.h>
Jesse Barnes79e53942008-11-07 14:24:08 -080042
Zhao Yakui3fbe18d2009-06-22 15:31:25 +080043/* Private structure for the integrated LVDS support */
Chris Wilsonea5b2132010-08-04 13:50:23 +010044struct intel_lvds {
45 struct intel_encoder base;
Zhao Yakui3fbe18d2009-06-22 15:31:25 +080046 int fitting_mode;
47 u32 pfit_control;
48 u32 pfit_pgm_ratios;
49};
50
Chris Wilsonea5b2132010-08-04 13:50:23 +010051static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder)
52{
Chris Wilson4ef69c72010-09-09 15:14:28 +010053 return container_of(encoder, struct intel_lvds, base.base);
Chris Wilsonea5b2132010-08-04 13:50:23 +010054}
55
Matthew Garrett309b1e32010-05-18 13:53:16 -040056static void intel_lvds_lock_panel(struct drm_device *dev, bool lock)
57{
58 struct drm_i915_private *dev_priv = dev->dev_private;
59
60 if (lock)
61 I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & 0x3);
62 else
63 I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
64}
65
Jesse Barnes79e53942008-11-07 14:24:08 -080066/**
Jesse Barnes79e53942008-11-07 14:24:08 -080067 * Sets the power state for the panel.
68 */
69static void intel_lvds_set_power(struct drm_device *dev, bool on)
70{
71 struct drm_i915_private *dev_priv = dev->dev_private;
Chris Wilson913d8d12010-08-07 11:01:35 +010072 u32 ctl_reg, status_reg, lvds_reg;
Zhenyu Wang541998a2009-06-05 15:38:44 +080073
Eric Anholtc619eed2010-01-28 16:45:52 -080074 if (HAS_PCH_SPLIT(dev)) {
Zhenyu Wang541998a2009-06-05 15:38:44 +080075 ctl_reg = PCH_PP_CONTROL;
76 status_reg = PCH_PP_STATUS;
Jesse Barnes469d1292010-02-11 12:41:05 -080077 lvds_reg = PCH_LVDS;
Zhenyu Wang541998a2009-06-05 15:38:44 +080078 } else {
79 ctl_reg = PP_CONTROL;
80 status_reg = PP_STATUS;
Jesse Barnes469d1292010-02-11 12:41:05 -080081 lvds_reg = LVDS;
Zhenyu Wang541998a2009-06-05 15:38:44 +080082 }
Jesse Barnes79e53942008-11-07 14:24:08 -080083
84 if (on) {
Jesse Barnes469d1292010-02-11 12:41:05 -080085 I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN);
Chris Wilson77d07fd2010-09-12 12:42:35 +010086 I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON);
Chris Wilsona9573552010-08-22 13:18:16 +010087 intel_panel_set_backlight(dev, dev_priv->backlight_level);
Jesse Barnes79e53942008-11-07 14:24:08 -080088 } else {
Chris Wilsona9573552010-08-22 13:18:16 +010089 intel_panel_set_backlight(dev, 0);
Chris Wilson77d07fd2010-09-12 12:42:35 +010090 I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON);
Jesse Barnes469d1292010-02-11 12:41:05 -080091 I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN);
Jesse Barnes79e53942008-11-07 14:24:08 -080092 }
Chris Wilsonc9f9ccc2010-09-12 13:07:25 +010093 POSTING_READ(lvds_reg);
Jesse Barnes79e53942008-11-07 14:24:08 -080094}
95
96static void intel_lvds_dpms(struct drm_encoder *encoder, int mode)
97{
98 struct drm_device *dev = encoder->dev;
99
100 if (mode == DRM_MODE_DPMS_ON)
101 intel_lvds_set_power(dev, true);
102 else
103 intel_lvds_set_power(dev, false);
104
105 /* XXX: We never power down the LVDS pairs. */
106}
107
Jesse Barnes79e53942008-11-07 14:24:08 -0800108static int intel_lvds_mode_valid(struct drm_connector *connector,
109 struct drm_display_mode *mode)
110{
111 struct drm_device *dev = connector->dev;
112 struct drm_i915_private *dev_priv = dev->dev_private;
113 struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode;
114
115 if (fixed_mode) {
116 if (mode->hdisplay > fixed_mode->hdisplay)
117 return MODE_PANEL;
118 if (mode->vdisplay > fixed_mode->vdisplay)
119 return MODE_PANEL;
120 }
121
122 return MODE_OK;
123}
124
Chris Wilson49be6632010-07-18 12:05:54 +0100125static void
126centre_horizontally(struct drm_display_mode *mode,
127 int width)
128{
129 u32 border, sync_pos, blank_width, sync_width;
130
131 /* keep the hsync and hblank widths constant */
132 sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start;
133 blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start;
134 sync_pos = (blank_width - sync_width + 1) / 2;
135
136 border = (mode->hdisplay - width + 1) / 2;
137 border += border & 1; /* make the border even */
138
139 mode->crtc_hdisplay = width;
140 mode->crtc_hblank_start = width + border;
141 mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width;
142
143 mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos;
144 mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width;
145}
146
147static void
148centre_vertically(struct drm_display_mode *mode,
149 int height)
150{
151 u32 border, sync_pos, blank_width, sync_width;
152
153 /* keep the vsync and vblank widths constant */
154 sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start;
155 blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start;
156 sync_pos = (blank_width - sync_width + 1) / 2;
157
158 border = (mode->vdisplay - height + 1) / 2;
159
160 mode->crtc_vdisplay = height;
161 mode->crtc_vblank_start = height + border;
162 mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width;
163
164 mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos;
165 mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width;
166}
167
168static inline u32 panel_fitter_scaling(u32 source, u32 target)
169{
170 /*
171 * Floating point operation is not supported. So the FACTOR
172 * is defined, which can avoid the floating point computation
173 * when calculating the panel ratio.
174 */
175#define ACCURACY 12
176#define FACTOR (1 << ACCURACY)
177 u32 ratio = source * FACTOR / target;
178 return (FACTOR * ratio + FACTOR/2) / FACTOR;
179}
180
Jesse Barnes79e53942008-11-07 14:24:08 -0800181static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
182 struct drm_display_mode *mode,
183 struct drm_display_mode *adjusted_mode)
184{
185 struct drm_device *dev = encoder->dev;
186 struct drm_i915_private *dev_priv = dev->dev_private;
187 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
Chris Wilsonea5b2132010-08-04 13:50:23 +0100188 struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
Jesse Barnes79e53942008-11-07 14:24:08 -0800189 struct drm_encoder *tmp_encoder;
Chris Wilson49be6632010-07-18 12:05:54 +0100190 u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
Jesse Barnes79e53942008-11-07 14:24:08 -0800191
192 /* Should never happen!! */
193 if (!IS_I965G(dev) && intel_crtc->pipe == 0) {
Keith Packard1ae8c0a2009-06-28 15:42:17 -0700194 DRM_ERROR("Can't support LVDS on pipe A\n");
Jesse Barnes79e53942008-11-07 14:24:08 -0800195 return false;
196 }
197
198 /* Should never happen!! */
199 list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list, head) {
200 if (tmp_encoder != encoder && tmp_encoder->crtc == encoder->crtc) {
Keith Packard1ae8c0a2009-06-28 15:42:17 -0700201 DRM_ERROR("Can't enable LVDS and another "
Jesse Barnes79e53942008-11-07 14:24:08 -0800202 "encoder on the same pipe\n");
203 return false;
204 }
205 }
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800206 /* If we don't have a panel mode, there is nothing we can do */
207 if (dev_priv->panel_fixed_mode == NULL)
208 return true;
Chris Wilson1d8e1c72010-08-07 11:01:28 +0100209
Jesse Barnes79e53942008-11-07 14:24:08 -0800210 /*
Chris Wilson71677042010-07-17 13:38:43 +0100211 * We have timings from the BIOS for the panel, put them in
Jesse Barnes79e53942008-11-07 14:24:08 -0800212 * to the adjusted mode. The CRTC will be set up for this mode,
213 * with the panel scaling set up to source from the H/VDisplay
214 * of the original mode.
215 */
Chris Wilson1d8e1c72010-08-07 11:01:28 +0100216 intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode);
217
218 if (HAS_PCH_SPLIT(dev)) {
219 intel_pch_panel_fitting(dev, intel_lvds->fitting_mode,
220 mode, adjusted_mode);
221 return true;
222 }
Jesse Barnes79e53942008-11-07 14:24:08 -0800223
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800224 /* Make sure pre-965s set dither correctly */
225 if (!IS_I965G(dev)) {
226 if (dev_priv->panel_wants_dither || dev_priv->lvds_dither)
227 pfit_control |= PANEL_8TO6_DITHER_ENABLE;
228 }
229
230 /* Native modes don't need fitting */
231 if (adjusted_mode->hdisplay == mode->hdisplay &&
Chris Wilson49be6632010-07-18 12:05:54 +0100232 adjusted_mode->vdisplay == mode->vdisplay)
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800233 goto out;
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800234
235 /* 965+ wants fuzzy fitting */
236 if (IS_I965G(dev))
Chris Wilson49be6632010-07-18 12:05:54 +0100237 pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
238 PFIT_FILTER_FUZZY);
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800239
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800240 /*
241 * Enable automatic panel scaling for non-native modes so that they fill
242 * the screen. Should be enabled before the pipe is enabled, according
243 * to register description and PRM.
244 * Change the value here to see the borders for debugging
245 */
Chris Wilson1d8e1c72010-08-07 11:01:28 +0100246 I915_WRITE(BCLRPAT_A, 0);
247 I915_WRITE(BCLRPAT_B, 0);
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800248
Chris Wilsonea5b2132010-08-04 13:50:23 +0100249 switch (intel_lvds->fitting_mode) {
Jesse Barnes53bd8382009-07-01 10:04:40 -0700250 case DRM_MODE_SCALE_CENTER:
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800251 /*
252 * For centered modes, we have to calculate border widths &
253 * heights and modify the values programmed into the CRTC.
254 */
Chris Wilson49be6632010-07-18 12:05:54 +0100255 centre_horizontally(adjusted_mode, mode->hdisplay);
256 centre_vertically(adjusted_mode, mode->vdisplay);
257 border = LVDS_BORDER_ENABLE;
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800258 break;
Chris Wilson49be6632010-07-18 12:05:54 +0100259
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800260 case DRM_MODE_SCALE_ASPECT:
Chris Wilson49be6632010-07-18 12:05:54 +0100261 /* Scale but preserve the aspect ratio */
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800262 if (IS_I965G(dev)) {
Chris Wilson49be6632010-07-18 12:05:54 +0100263 u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
264 u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
265
266 pfit_control |= PFIT_ENABLE;
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800267 /* 965+ is easy, it does everything in hw */
Chris Wilson49be6632010-07-18 12:05:54 +0100268 if (scaled_width > scaled_height)
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800269 pfit_control |= PFIT_SCALING_PILLAR;
Chris Wilson49be6632010-07-18 12:05:54 +0100270 else if (scaled_width < scaled_height)
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800271 pfit_control |= PFIT_SCALING_LETTER;
272 else
273 pfit_control |= PFIT_SCALING_AUTO;
274 } else {
Chris Wilson49be6632010-07-18 12:05:54 +0100275 u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
276 u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800277 /*
278 * For earlier chips we have to calculate the scaling
279 * ratio by hand and program it into the
280 * PFIT_PGM_RATIO register
281 */
Chris Wilson49be6632010-07-18 12:05:54 +0100282 if (scaled_width > scaled_height) { /* pillar */
283 centre_horizontally(adjusted_mode, scaled_height / mode->vdisplay);
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800284
Chris Wilson49be6632010-07-18 12:05:54 +0100285 border = LVDS_BORDER_ENABLE;
286 if (mode->vdisplay != adjusted_mode->vdisplay) {
287 u32 bits = panel_fitter_scaling(mode->vdisplay, adjusted_mode->vdisplay);
288 pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
289 bits << PFIT_VERT_SCALE_SHIFT);
290 pfit_control |= (PFIT_ENABLE |
291 VERT_INTERP_BILINEAR |
292 HORIZ_INTERP_BILINEAR);
293 }
294 } else if (scaled_width < scaled_height) { /* letter */
295 centre_vertically(adjusted_mode, scaled_width / mode->hdisplay);
296
297 border = LVDS_BORDER_ENABLE;
298 if (mode->hdisplay != adjusted_mode->hdisplay) {
299 u32 bits = panel_fitter_scaling(mode->hdisplay, adjusted_mode->hdisplay);
300 pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
301 bits << PFIT_VERT_SCALE_SHIFT);
302 pfit_control |= (PFIT_ENABLE |
303 VERT_INTERP_BILINEAR |
304 HORIZ_INTERP_BILINEAR);
305 }
306 } else
307 /* Aspects match, Let hw scale both directions */
308 pfit_control |= (PFIT_ENABLE |
309 VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800310 VERT_INTERP_BILINEAR |
311 HORIZ_INTERP_BILINEAR);
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800312 }
313 break;
314
315 case DRM_MODE_SCALE_FULLSCREEN:
316 /*
317 * Full scaling, even if it changes the aspect ratio.
318 * Fortunately this is all done for us in hw.
319 */
320 pfit_control |= PFIT_ENABLE;
321 if (IS_I965G(dev))
322 pfit_control |= PFIT_SCALING_AUTO;
323 else
324 pfit_control |= (VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
325 VERT_INTERP_BILINEAR |
326 HORIZ_INTERP_BILINEAR);
327 break;
Chris Wilson49be6632010-07-18 12:05:54 +0100328
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800329 default:
330 break;
331 }
332
333out:
Chris Wilsonea5b2132010-08-04 13:50:23 +0100334 intel_lvds->pfit_control = pfit_control;
335 intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios;
Chris Wilson49be6632010-07-18 12:05:54 +0100336 dev_priv->lvds_border_bits = border;
337
Zhao Yakuia3e17eb2009-10-10 10:42:37 +0800338 /*
Jesse Barnes79e53942008-11-07 14:24:08 -0800339 * XXX: It would be nice to support lower refresh rates on the
340 * panels to reduce power consumption, and perhaps match the
341 * user's requested refresh rate.
342 */
343
344 return true;
345}
346
347static void intel_lvds_prepare(struct drm_encoder *encoder)
348{
349 struct drm_device *dev = encoder->dev;
350 struct drm_i915_private *dev_priv = dev->dev_private;
Matthew Garrett309b1e32010-05-18 13:53:16 -0400351 struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
Jesse Barnes79e53942008-11-07 14:24:08 -0800352
Chris Wilsona9573552010-08-22 13:18:16 +0100353 dev_priv->backlight_level = intel_panel_get_backlight(dev);
Jesse Barnes79e53942008-11-07 14:24:08 -0800354
Matthew Garrett309b1e32010-05-18 13:53:16 -0400355 if (intel_lvds->pfit_control == I915_READ(PFIT_CONTROL))
356 intel_lvds_lock_panel(dev, false);
357 else
358 intel_lvds_set_power(dev, false);
Jesse Barnes79e53942008-11-07 14:24:08 -0800359}
360
361static void intel_lvds_commit( struct drm_encoder *encoder)
362{
363 struct drm_device *dev = encoder->dev;
364 struct drm_i915_private *dev_priv = dev->dev_private;
365
Chris Wilsona9573552010-08-22 13:18:16 +0100366 if (dev_priv->backlight_level == 0)
367 dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
Jesse Barnes79e53942008-11-07 14:24:08 -0800368
Matthew Garrett309b1e32010-05-18 13:53:16 -0400369 if ((I915_READ(PP_CONTROL) & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
370 intel_lvds_lock_panel(dev, true);
371 else
372 intel_lvds_set_power(dev, true);
Jesse Barnes79e53942008-11-07 14:24:08 -0800373}
374
375static void intel_lvds_mode_set(struct drm_encoder *encoder,
376 struct drm_display_mode *mode,
377 struct drm_display_mode *adjusted_mode)
378{
379 struct drm_device *dev = encoder->dev;
380 struct drm_i915_private *dev_priv = dev->dev_private;
Chris Wilsonea5b2132010-08-04 13:50:23 +0100381 struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
Jesse Barnes79e53942008-11-07 14:24:08 -0800382
383 /*
384 * The LVDS pin pair will already have been turned on in the
385 * intel_crtc_mode_set since it has a large impact on the DPLL
386 * settings.
387 */
388
Eric Anholtc619eed2010-01-28 16:45:52 -0800389 if (HAS_PCH_SPLIT(dev))
Zhenyu Wang541998a2009-06-05 15:38:44 +0800390 return;
391
Jesse Barnes79e53942008-11-07 14:24:08 -0800392 /*
393 * Enable automatic panel scaling so that non-native modes fill the
394 * screen. Should be enabled before the pipe is enabled, according to
395 * register description and PRM.
396 */
Chris Wilsonea5b2132010-08-04 13:50:23 +0100397 I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
398 I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
Jesse Barnes79e53942008-11-07 14:24:08 -0800399}
400
401/**
402 * Detect the LVDS connection.
403 *
Jesse Barnesb42d4c52009-09-10 15:28:04 -0700404 * Since LVDS doesn't have hotlug, we use the lid as a proxy. Open means
405 * connected and closed means disconnected. We also send hotplug events as
406 * needed, using lid status notification from the input layer.
Jesse Barnes79e53942008-11-07 14:24:08 -0800407 */
408static enum drm_connector_status intel_lvds_detect(struct drm_connector *connector)
409{
Jesse Barnes7b9c5ab2010-02-12 09:30:00 -0800410 struct drm_device *dev = connector->dev;
Jesse Barnesb42d4c52009-09-10 15:28:04 -0700411 enum drm_connector_status status = connector_status_connected;
412
Jesse Barnes7b9c5ab2010-02-12 09:30:00 -0800413 /* ACPI lid methods were generally unreliable in this generation, so
414 * don't even bother.
415 */
Eric Anholt6e6c8222010-03-17 13:48:06 -0700416 if (IS_GEN2(dev) || IS_GEN3(dev))
Jesse Barnes7b9c5ab2010-02-12 09:30:00 -0800417 return connector_status_connected;
418
Jesse Barnesb42d4c52009-09-10 15:28:04 -0700419 return status;
Jesse Barnes79e53942008-11-07 14:24:08 -0800420}
421
422/**
423 * Return the list of DDC modes if available, or the BIOS fixed mode otherwise.
424 */
425static int intel_lvds_get_modes(struct drm_connector *connector)
426{
427 struct drm_device *dev = connector->dev;
Jesse Barnes79e53942008-11-07 14:24:08 -0800428 struct drm_i915_private *dev_priv = dev->dev_private;
Jesse Barnes79e53942008-11-07 14:24:08 -0800429
Zhao Yakuibfac4d62010-04-07 17:11:22 +0800430 if (dev_priv->lvds_edid_good) {
Chris Wilsondf0e9242010-09-09 16:20:55 +0100431 struct intel_encoder *encoder = intel_attached_encoder(connector);
432 int ret = intel_ddc_get_modes(connector, encoder->ddc_bus);
Zhao Yakuibfac4d62010-04-07 17:11:22 +0800433 if (ret)
434 return ret;
435 }
Jesse Barnes79e53942008-11-07 14:24:08 -0800436
437 /* Didn't get an EDID, so
438 * Set wide sync ranges so we get all modes
439 * handed to valid_mode for checking
440 */
441 connector->display_info.min_vfreq = 0;
442 connector->display_info.max_vfreq = 200;
443 connector->display_info.min_hfreq = 0;
444 connector->display_info.max_hfreq = 200;
445
446 if (dev_priv->panel_fixed_mode != NULL) {
447 struct drm_display_mode *mode;
448
Jesse Barnes79e53942008-11-07 14:24:08 -0800449 mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
450 drm_mode_probed_add(connector, mode);
Jesse Barnes79e53942008-11-07 14:24:08 -0800451
452 return 1;
453 }
454
455 return 0;
456}
457
Thomas Bächler0544edf2010-07-02 10:44:23 +0200458static int intel_no_modeset_on_lid_dmi_callback(const struct dmi_system_id *id)
459{
460 DRM_DEBUG_KMS("Skipping forced modeset for %s\n", id->ident);
461 return 1;
462}
463
464/* The GPU hangs up on these systems if modeset is performed on LID open */
465static const struct dmi_system_id intel_no_modeset_on_lid[] = {
466 {
467 .callback = intel_no_modeset_on_lid_dmi_callback,
468 .ident = "Toshiba Tecra A11",
469 .matches = {
470 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
471 DMI_MATCH(DMI_PRODUCT_NAME, "TECRA A11"),
472 },
473 },
474
475 { } /* terminating entry */
476};
477
Linus Torvaldsc9354c82009-11-02 09:29:55 -0800478/*
479 * Lid events. Note the use of 'modeset_on_lid':
480 * - we set it on lid close, and reset it on open
481 * - we use it as a "only once" bit (ie we ignore
482 * duplicate events where it was already properly
483 * set/reset)
484 * - the suspend/resume paths will also set it to
485 * zero, since they restore the mode ("lid open").
486 */
Jesse Barnesc1c7af62009-09-10 15:28:03 -0700487static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
488 void *unused)
489{
490 struct drm_i915_private *dev_priv =
491 container_of(nb, struct drm_i915_private, lid_notifier);
492 struct drm_device *dev = dev_priv->dev;
Zhao Yakuia2565372009-12-11 09:26:11 +0800493 struct drm_connector *connector = dev_priv->int_lvds_connector;
Jesse Barnesc1c7af62009-09-10 15:28:03 -0700494
Zhao Yakuia2565372009-12-11 09:26:11 +0800495 /*
496 * check and update the status of LVDS connector after receiving
497 * the LID nofication event.
498 */
499 if (connector)
500 connector->status = connector->funcs->detect(connector);
Thomas Bächler0544edf2010-07-02 10:44:23 +0200501 /* Don't force modeset on machines where it causes a GPU lockup */
502 if (dmi_check_system(intel_no_modeset_on_lid))
503 return NOTIFY_OK;
Linus Torvaldsc9354c82009-11-02 09:29:55 -0800504 if (!acpi_lid_open()) {
505 dev_priv->modeset_on_lid = 1;
506 return NOTIFY_OK;
Jesse Barnes06891e22009-09-14 10:58:48 -0700507 }
Jesse Barnesc1c7af62009-09-10 15:28:03 -0700508
Linus Torvaldsc9354c82009-11-02 09:29:55 -0800509 if (!dev_priv->modeset_on_lid)
510 return NOTIFY_OK;
511
512 dev_priv->modeset_on_lid = 0;
513
514 mutex_lock(&dev->mode_config.mutex);
515 drm_helper_resume_force_mode(dev);
516 mutex_unlock(&dev->mode_config.mutex);
Jesse Barnes06324192009-09-10 15:28:05 -0700517
Jesse Barnesc1c7af62009-09-10 15:28:03 -0700518 return NOTIFY_OK;
519}
520
Jesse Barnes79e53942008-11-07 14:24:08 -0800521/**
522 * intel_lvds_destroy - unregister and free LVDS structures
523 * @connector: connector to free
524 *
525 * Unregister the DDC bus for this connector then free the driver private
526 * structure.
527 */
528static void intel_lvds_destroy(struct drm_connector *connector)
529{
Jesse Barnesc1c7af62009-09-10 15:28:03 -0700530 struct drm_device *dev = connector->dev;
Jesse Barnesc1c7af62009-09-10 15:28:03 -0700531 struct drm_i915_private *dev_priv = dev->dev_private;
Jesse Barnes79e53942008-11-07 14:24:08 -0800532
Jesse Barnesc1c7af62009-09-10 15:28:03 -0700533 if (dev_priv->lid_notifier.notifier_call)
534 acpi_lid_notifier_unregister(&dev_priv->lid_notifier);
Jesse Barnes79e53942008-11-07 14:24:08 -0800535 drm_sysfs_connector_remove(connector);
536 drm_connector_cleanup(connector);
537 kfree(connector);
538}
539
Jesse Barnes335041e2009-01-22 22:22:06 +1000540static int intel_lvds_set_property(struct drm_connector *connector,
541 struct drm_property *property,
542 uint64_t value)
543{
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800544 struct drm_device *dev = connector->dev;
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800545
546 if (property == dev->mode_config.scaling_mode_property &&
547 connector->encoder) {
548 struct drm_crtc *crtc = connector->encoder->crtc;
Zhenyu Wangbb8a3562010-03-29 16:40:50 +0800549 struct drm_encoder *encoder = connector->encoder;
Chris Wilsonea5b2132010-08-04 13:50:23 +0100550 struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
Zhenyu Wangbb8a3562010-03-29 16:40:50 +0800551
Jesse Barnes53bd8382009-07-01 10:04:40 -0700552 if (value == DRM_MODE_SCALE_NONE) {
553 DRM_DEBUG_KMS("no scaling not supported\n");
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800554 return 0;
555 }
Chris Wilsonea5b2132010-08-04 13:50:23 +0100556 if (intel_lvds->fitting_mode == value) {
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800557 /* the LVDS scaling property is not changed */
558 return 0;
559 }
Chris Wilsonea5b2132010-08-04 13:50:23 +0100560 intel_lvds->fitting_mode = value;
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800561 if (crtc && crtc->enabled) {
562 /*
563 * If the CRTC is enabled, the display will be changed
564 * according to the new panel fitting mode.
565 */
566 drm_crtc_helper_set_mode(crtc, &crtc->mode,
567 crtc->x, crtc->y, crtc->fb);
568 }
569 }
570
Jesse Barnes335041e2009-01-22 22:22:06 +1000571 return 0;
572}
573
Jesse Barnes79e53942008-11-07 14:24:08 -0800574static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = {
575 .dpms = intel_lvds_dpms,
576 .mode_fixup = intel_lvds_mode_fixup,
577 .prepare = intel_lvds_prepare,
578 .mode_set = intel_lvds_mode_set,
579 .commit = intel_lvds_commit,
580};
581
582static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = {
583 .get_modes = intel_lvds_get_modes,
584 .mode_valid = intel_lvds_mode_valid,
Chris Wilsondf0e9242010-09-09 16:20:55 +0100585 .best_encoder = intel_best_encoder,
Jesse Barnes79e53942008-11-07 14:24:08 -0800586};
587
588static const struct drm_connector_funcs intel_lvds_connector_funcs = {
Keith Packardc9fb15f2009-05-30 20:42:28 -0700589 .dpms = drm_helper_connector_dpms,
Jesse Barnes79e53942008-11-07 14:24:08 -0800590 .detect = intel_lvds_detect,
591 .fill_modes = drm_helper_probe_single_connector_modes,
Jesse Barnes335041e2009-01-22 22:22:06 +1000592 .set_property = intel_lvds_set_property,
Jesse Barnes79e53942008-11-07 14:24:08 -0800593 .destroy = intel_lvds_destroy,
594};
595
Jesse Barnes79e53942008-11-07 14:24:08 -0800596static const struct drm_encoder_funcs intel_lvds_enc_funcs = {
Chris Wilsonea5b2132010-08-04 13:50:23 +0100597 .destroy = intel_encoder_destroy,
Jesse Barnes79e53942008-11-07 14:24:08 -0800598};
599
Jarod Wilson425d2442009-05-05 10:00:25 -0400600static int __init intel_no_lvds_dmi_callback(const struct dmi_system_id *id)
601{
Zhao Yakui8a4c47f2009-07-20 13:48:04 +0800602 DRM_DEBUG_KMS("Skipping LVDS initialization for %s\n", id->ident);
Jarod Wilson425d2442009-05-05 10:00:25 -0400603 return 1;
604}
Jesse Barnes79e53942008-11-07 14:24:08 -0800605
Jarod Wilson425d2442009-05-05 10:00:25 -0400606/* These systems claim to have LVDS, but really don't */
Jaswinder Singh Rajput93c05f22009-06-04 09:41:19 +1000607static const struct dmi_system_id intel_no_lvds[] = {
Jarod Wilson425d2442009-05-05 10:00:25 -0400608 {
609 .callback = intel_no_lvds_dmi_callback,
610 .ident = "Apple Mac Mini (Core series)",
611 .matches = {
Keith Packard98acd462009-06-14 12:31:58 -0700612 DMI_MATCH(DMI_SYS_VENDOR, "Apple"),
Jarod Wilson425d2442009-05-05 10:00:25 -0400613 DMI_MATCH(DMI_PRODUCT_NAME, "Macmini1,1"),
614 },
615 },
616 {
617 .callback = intel_no_lvds_dmi_callback,
618 .ident = "Apple Mac Mini (Core 2 series)",
619 .matches = {
Keith Packard98acd462009-06-14 12:31:58 -0700620 DMI_MATCH(DMI_SYS_VENDOR, "Apple"),
Jarod Wilson425d2442009-05-05 10:00:25 -0400621 DMI_MATCH(DMI_PRODUCT_NAME, "Macmini2,1"),
622 },
623 },
624 {
625 .callback = intel_no_lvds_dmi_callback,
626 .ident = "MSI IM-945GSE-A",
627 .matches = {
628 DMI_MATCH(DMI_SYS_VENDOR, "MSI"),
629 DMI_MATCH(DMI_PRODUCT_NAME, "A9830IMS"),
630 },
631 },
632 {
633 .callback = intel_no_lvds_dmi_callback,
634 .ident = "Dell Studio Hybrid",
635 .matches = {
636 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
637 DMI_MATCH(DMI_PRODUCT_NAME, "Studio Hybrid 140g"),
638 },
639 },
Jarod Wilson70aa96c2009-05-27 17:20:39 -0400640 {
641 .callback = intel_no_lvds_dmi_callback,
642 .ident = "AOpen Mini PC",
643 .matches = {
644 DMI_MATCH(DMI_SYS_VENDOR, "AOpen"),
645 DMI_MATCH(DMI_PRODUCT_NAME, "i965GMx-IF"),
646 },
647 },
Michael Cousinfa0864b2009-06-05 21:16:22 +0200648 {
649 .callback = intel_no_lvds_dmi_callback,
Tormod Voldened8c7542009-07-13 22:26:48 +0200650 .ident = "AOpen Mini PC MP915",
651 .matches = {
652 DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
653 DMI_MATCH(DMI_BOARD_NAME, "i915GMx-F"),
654 },
655 },
656 {
657 .callback = intel_no_lvds_dmi_callback,
Michael Cousinfa0864b2009-06-05 21:16:22 +0200658 .ident = "Aopen i945GTt-VFA",
659 .matches = {
660 DMI_MATCH(DMI_PRODUCT_VERSION, "AO00001JW"),
661 },
662 },
Stefan Bader98755572010-03-29 17:53:12 +0200663 {
664 .callback = intel_no_lvds_dmi_callback,
665 .ident = "Clientron U800",
666 .matches = {
667 DMI_MATCH(DMI_SYS_VENDOR, "Clientron"),
668 DMI_MATCH(DMI_PRODUCT_NAME, "U800"),
669 },
670 },
Jarod Wilson425d2442009-05-05 10:00:25 -0400671
672 { } /* terminating entry */
673};
Jesse Barnes79e53942008-11-07 14:24:08 -0800674
675/**
Zhao Yakui18f9ed12009-11-20 03:24:16 +0000676 * intel_find_lvds_downclock - find the reduced downclock for LVDS in EDID
677 * @dev: drm device
678 * @connector: LVDS connector
679 *
680 * Find the reduced downclock for LVDS in EDID.
681 */
682static void intel_find_lvds_downclock(struct drm_device *dev,
683 struct drm_connector *connector)
684{
685 struct drm_i915_private *dev_priv = dev->dev_private;
686 struct drm_display_mode *scan, *panel_fixed_mode;
687 int temp_downclock;
688
689 panel_fixed_mode = dev_priv->panel_fixed_mode;
690 temp_downclock = panel_fixed_mode->clock;
691
692 mutex_lock(&dev->mode_config.mutex);
693 list_for_each_entry(scan, &connector->probed_modes, head) {
694 /*
695 * If one mode has the same resolution with the fixed_panel
696 * mode while they have the different refresh rate, it means
697 * that the reduced downclock is found for the LVDS. In such
698 * case we can set the different FPx0/1 to dynamically select
699 * between low and high frequency.
700 */
701 if (scan->hdisplay == panel_fixed_mode->hdisplay &&
702 scan->hsync_start == panel_fixed_mode->hsync_start &&
703 scan->hsync_end == panel_fixed_mode->hsync_end &&
704 scan->htotal == panel_fixed_mode->htotal &&
705 scan->vdisplay == panel_fixed_mode->vdisplay &&
706 scan->vsync_start == panel_fixed_mode->vsync_start &&
707 scan->vsync_end == panel_fixed_mode->vsync_end &&
708 scan->vtotal == panel_fixed_mode->vtotal) {
709 if (scan->clock < temp_downclock) {
710 /*
711 * The downclock is already found. But we
712 * expect to find the lower downclock.
713 */
714 temp_downclock = scan->clock;
715 }
716 }
717 }
718 mutex_unlock(&dev->mode_config.mutex);
Jesse Barnes33814342010-01-14 20:48:02 +0000719 if (temp_downclock < panel_fixed_mode->clock &&
720 i915_lvds_downclock) {
Zhao Yakui18f9ed12009-11-20 03:24:16 +0000721 /* We found the downclock for LVDS. */
722 dev_priv->lvds_downclock_avail = 1;
723 dev_priv->lvds_downclock = temp_downclock;
724 DRM_DEBUG_KMS("LVDS downclock is found in EDID. "
725 "Normal clock %dKhz, downclock %dKhz\n",
726 panel_fixed_mode->clock, temp_downclock);
727 }
728 return;
729}
730
Zhao Yakui7cf4f692009-11-24 09:48:47 +0800731/*
732 * Enumerate the child dev array parsed from VBT to check whether
733 * the LVDS is present.
734 * If it is present, return 1.
735 * If it is not present, return false.
736 * If no child dev is parsed from VBT, it assumes that the LVDS is present.
Zhao Yakui7cf4f692009-11-24 09:48:47 +0800737 */
Chris Wilson425904d2010-08-22 18:21:42 +0100738static bool lvds_is_present_in_vbt(struct drm_device *dev)
Zhao Yakui7cf4f692009-11-24 09:48:47 +0800739{
740 struct drm_i915_private *dev_priv = dev->dev_private;
Chris Wilson425904d2010-08-22 18:21:42 +0100741 int i;
Zhao Yakui7cf4f692009-11-24 09:48:47 +0800742
743 if (!dev_priv->child_dev_num)
Chris Wilson425904d2010-08-22 18:21:42 +0100744 return true;
Zhao Yakui7cf4f692009-11-24 09:48:47 +0800745
Zhao Yakui7cf4f692009-11-24 09:48:47 +0800746 for (i = 0; i < dev_priv->child_dev_num; i++) {
Chris Wilson425904d2010-08-22 18:21:42 +0100747 struct child_device_config *child = dev_priv->child_dev + i;
748
749 /* If the device type is not LFP, continue.
750 * We have to check both the new identifiers as well as the
751 * old for compatibility with some BIOSes.
Zhao Yakui7cf4f692009-11-24 09:48:47 +0800752 */
Chris Wilson425904d2010-08-22 18:21:42 +0100753 if (child->device_type != DEVICE_TYPE_INT_LFP &&
754 child->device_type != DEVICE_TYPE_LFP)
Zhao Yakui7cf4f692009-11-24 09:48:47 +0800755 continue;
756
Chris Wilson425904d2010-08-22 18:21:42 +0100757 /* However, we cannot trust the BIOS writers to populate
758 * the VBT correctly. Since LVDS requires additional
759 * information from AIM blocks, a non-zero addin offset is
760 * a good indicator that the LVDS is actually present.
Zhao Yakui7cf4f692009-11-24 09:48:47 +0800761 */
Chris Wilson425904d2010-08-22 18:21:42 +0100762 if (child->addin_offset)
763 return true;
764
765 /* But even then some BIOS writers perform some black magic
766 * and instantiate the device without reference to any
767 * additional data. Trust that if the VBT was written into
768 * the OpRegion then they have validated the LVDS's existence.
769 */
770 if (dev_priv->opregion.vbt)
771 return true;
Zhao Yakui7cf4f692009-11-24 09:48:47 +0800772 }
Chris Wilson425904d2010-08-22 18:21:42 +0100773
774 return false;
Zhao Yakui7cf4f692009-11-24 09:48:47 +0800775}
776
Zhao Yakui18f9ed12009-11-20 03:24:16 +0000777/**
Jesse Barnes79e53942008-11-07 14:24:08 -0800778 * intel_lvds_init - setup LVDS connectors on this device
779 * @dev: drm device
780 *
781 * Create the connector, register the LVDS DDC bus, and try to figure out what
782 * modes we can display on the LVDS panel (if present).
783 */
784void intel_lvds_init(struct drm_device *dev)
785{
786 struct drm_i915_private *dev_priv = dev->dev_private;
Chris Wilsonea5b2132010-08-04 13:50:23 +0100787 struct intel_lvds *intel_lvds;
Eric Anholt21d40d32010-03-25 11:11:14 -0700788 struct intel_encoder *intel_encoder;
Zhenyu Wangbb8a3562010-03-29 16:40:50 +0800789 struct intel_connector *intel_connector;
Jesse Barnes79e53942008-11-07 14:24:08 -0800790 struct drm_connector *connector;
791 struct drm_encoder *encoder;
792 struct drm_display_mode *scan; /* *modes, *bios_mode; */
793 struct drm_crtc *crtc;
794 u32 lvds;
Zhenyu Wang541998a2009-06-05 15:38:44 +0800795 int pipe, gpio = GPIOC;
Jesse Barnes79e53942008-11-07 14:24:08 -0800796
Jarod Wilson425d2442009-05-05 10:00:25 -0400797 /* Skip init on machines we know falsely report LVDS */
798 if (dmi_check_system(intel_no_lvds))
Paul Collins565dcd42009-02-04 23:05:41 +1300799 return;
Paul Collins565dcd42009-02-04 23:05:41 +1300800
Matthew Garrett11ba1592009-12-15 13:55:24 -0500801 if (!lvds_is_present_in_vbt(dev)) {
802 DRM_DEBUG_KMS("LVDS is not present in VBT\n");
Zhao Yakuie99da352009-06-26 09:46:18 +0800803 return;
Zhao Yakui7cf4f692009-11-24 09:48:47 +0800804 }
Zhao Yakuie99da352009-06-26 09:46:18 +0800805
Eric Anholtc619eed2010-01-28 16:45:52 -0800806 if (HAS_PCH_SPLIT(dev)) {
Zhenyu Wang541998a2009-06-05 15:38:44 +0800807 if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
808 return;
Zhenyu Wang32f9d652009-07-24 01:00:32 +0800809 if (dev_priv->edp_support) {
Zhao Yakui28c97732009-10-09 11:39:41 +0800810 DRM_DEBUG_KMS("disable LVDS for eDP support\n");
Zhenyu Wang32f9d652009-07-24 01:00:32 +0800811 return;
812 }
Zhenyu Wang541998a2009-06-05 15:38:44 +0800813 gpio = PCH_GPIOC;
814 }
815
Chris Wilsonea5b2132010-08-04 13:50:23 +0100816 intel_lvds = kzalloc(sizeof(struct intel_lvds), GFP_KERNEL);
817 if (!intel_lvds) {
Jesse Barnes79e53942008-11-07 14:24:08 -0800818 return;
819 }
820
Zhenyu Wangbb8a3562010-03-29 16:40:50 +0800821 intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
822 if (!intel_connector) {
Chris Wilsonea5b2132010-08-04 13:50:23 +0100823 kfree(intel_lvds);
Zhenyu Wangbb8a3562010-03-29 16:40:50 +0800824 return;
825 }
826
Chris Wilsonea5b2132010-08-04 13:50:23 +0100827 intel_encoder = &intel_lvds->base;
Chris Wilson4ef69c72010-09-09 15:14:28 +0100828 encoder = &intel_encoder->base;
Chris Wilsonea5b2132010-08-04 13:50:23 +0100829 connector = &intel_connector->base;
Zhenyu Wangbb8a3562010-03-29 16:40:50 +0800830 drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs,
Jesse Barnes79e53942008-11-07 14:24:08 -0800831 DRM_MODE_CONNECTOR_LVDS);
832
Chris Wilson4ef69c72010-09-09 15:14:28 +0100833 drm_encoder_init(dev, &intel_encoder->base, &intel_lvds_enc_funcs,
Jesse Barnes79e53942008-11-07 14:24:08 -0800834 DRM_MODE_ENCODER_LVDS);
835
Chris Wilsondf0e9242010-09-09 16:20:55 +0100836 intel_connector_attach_encoder(intel_connector, intel_encoder);
Eric Anholt21d40d32010-03-25 11:11:14 -0700837 intel_encoder->type = INTEL_OUTPUT_LVDS;
Jesse Barnes79e53942008-11-07 14:24:08 -0800838
Eric Anholt21d40d32010-03-25 11:11:14 -0700839 intel_encoder->clone_mask = (1 << INTEL_LVDS_CLONE_BIT);
840 intel_encoder->crtc_mask = (1 << 1);
Jesse Barnes79e53942008-11-07 14:24:08 -0800841 drm_encoder_helper_add(encoder, &intel_lvds_helper_funcs);
842 drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs);
843 connector->display_info.subpixel_order = SubPixelHorizontalRGB;
844 connector->interlace_allowed = false;
845 connector->doublescan_allowed = false;
846
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800847 /* create the scaling mode property */
848 drm_mode_create_scaling_mode_property(dev);
849 /*
850 * the initial panel fitting mode will be FULL_SCREEN.
851 */
Jesse Barnes79e53942008-11-07 14:24:08 -0800852
Zhenyu Wangbb8a3562010-03-29 16:40:50 +0800853 drm_connector_attach_property(&intel_connector->base,
Zhao Yakui3fbe18d2009-06-22 15:31:25 +0800854 dev->mode_config.scaling_mode_property,
Jesse Barnesdd1ea372010-06-24 11:05:10 -0700855 DRM_MODE_SCALE_ASPECT);
Chris Wilsonea5b2132010-08-04 13:50:23 +0100856 intel_lvds->fitting_mode = DRM_MODE_SCALE_ASPECT;
Jesse Barnes79e53942008-11-07 14:24:08 -0800857 /*
858 * LVDS discovery:
859 * 1) check for EDID on DDC
860 * 2) check for VBT data
861 * 3) check to see if LVDS is already on
862 * if none of the above, no panel
863 * 4) make sure lid is open
864 * if closed, act like it's not there for now
865 */
866
867 /* Set up the DDC bus. */
Eric Anholt21d40d32010-03-25 11:11:14 -0700868 intel_encoder->ddc_bus = intel_i2c_create(dev, gpio, "LVDSDDC_C");
869 if (!intel_encoder->ddc_bus) {
Jesse Barnes79e53942008-11-07 14:24:08 -0800870 dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
871 "failed.\n");
872 goto failed;
873 }
874
875 /*
876 * Attempt to get the fixed panel mode from DDC. Assume that the
877 * preferred mode is the right one.
878 */
Zhao Yakuibfac4d62010-04-07 17:11:22 +0800879 dev_priv->lvds_edid_good = true;
880
Zhenyu Wang335af9a2010-03-30 14:39:31 +0800881 if (!intel_ddc_get_modes(connector, intel_encoder->ddc_bus))
Zhao Yakuibfac4d62010-04-07 17:11:22 +0800882 dev_priv->lvds_edid_good = false;
Jesse Barnes79e53942008-11-07 14:24:08 -0800883
884 list_for_each_entry(scan, &connector->probed_modes, head) {
885 mutex_lock(&dev->mode_config.mutex);
886 if (scan->type & DRM_MODE_TYPE_PREFERRED) {
887 dev_priv->panel_fixed_mode =
888 drm_mode_duplicate(dev, scan);
889 mutex_unlock(&dev->mode_config.mutex);
Zhao Yakui18f9ed12009-11-20 03:24:16 +0000890 intel_find_lvds_downclock(dev, connector);
Paul Collins565dcd42009-02-04 23:05:41 +1300891 goto out;
Jesse Barnes79e53942008-11-07 14:24:08 -0800892 }
893 mutex_unlock(&dev->mode_config.mutex);
894 }
895
896 /* Failed to get EDID, what about VBT? */
Ma Ling88631702009-05-13 11:19:55 +0800897 if (dev_priv->lfp_lvds_vbt_mode) {
Jesse Barnes79e53942008-11-07 14:24:08 -0800898 mutex_lock(&dev->mode_config.mutex);
899 dev_priv->panel_fixed_mode =
Ma Ling88631702009-05-13 11:19:55 +0800900 drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
Jesse Barnes79e53942008-11-07 14:24:08 -0800901 mutex_unlock(&dev->mode_config.mutex);
Jesse Barnese285f3c2009-01-14 10:53:36 -0800902 if (dev_priv->panel_fixed_mode) {
903 dev_priv->panel_fixed_mode->type |=
904 DRM_MODE_TYPE_PREFERRED;
Jesse Barnese285f3c2009-01-14 10:53:36 -0800905 goto out;
906 }
Jesse Barnes79e53942008-11-07 14:24:08 -0800907 }
908
909 /*
910 * If we didn't get EDID, try checking if the panel is already turned
911 * on. If so, assume that whatever is currently programmed is the
912 * correct mode.
913 */
Zhenyu Wang541998a2009-06-05 15:38:44 +0800914
Adam Jacksonf2b115e2009-12-03 17:14:42 -0500915 /* Ironlake: FIXME if still fail, not try pipe mode now */
Eric Anholtc619eed2010-01-28 16:45:52 -0800916 if (HAS_PCH_SPLIT(dev))
Zhenyu Wang541998a2009-06-05 15:38:44 +0800917 goto failed;
918
Jesse Barnes79e53942008-11-07 14:24:08 -0800919 lvds = I915_READ(LVDS);
920 pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
Chris Wilsonf875c152010-09-09 15:44:14 +0100921 crtc = intel_get_crtc_for_pipe(dev, pipe);
Jesse Barnes79e53942008-11-07 14:24:08 -0800922
923 if (crtc && (lvds & LVDS_PORT_EN)) {
924 dev_priv->panel_fixed_mode = intel_crtc_mode_get(dev, crtc);
925 if (dev_priv->panel_fixed_mode) {
926 dev_priv->panel_fixed_mode->type |=
927 DRM_MODE_TYPE_PREFERRED;
Paul Collins565dcd42009-02-04 23:05:41 +1300928 goto out;
Jesse Barnes79e53942008-11-07 14:24:08 -0800929 }
930 }
931
932 /* If we still don't have a mode after all that, give up. */
933 if (!dev_priv->panel_fixed_mode)
934 goto failed;
935
Jesse Barnes79e53942008-11-07 14:24:08 -0800936out:
Eric Anholtc619eed2010-01-28 16:45:52 -0800937 if (HAS_PCH_SPLIT(dev)) {
Zhenyu Wang541998a2009-06-05 15:38:44 +0800938 u32 pwm;
939 /* make sure PWM is enabled */
940 pwm = I915_READ(BLC_PWM_CPU_CTL2);
941 pwm |= (PWM_ENABLE | PWM_PIPE_B);
942 I915_WRITE(BLC_PWM_CPU_CTL2, pwm);
943
944 pwm = I915_READ(BLC_PWM_PCH_CTL1);
945 pwm |= PWM_PCH_ENABLE;
946 I915_WRITE(BLC_PWM_PCH_CTL1, pwm);
947 }
Jesse Barnesc1c7af62009-09-10 15:28:03 -0700948 dev_priv->lid_notifier.notifier_call = intel_lid_notify;
949 if (acpi_lid_notifier_register(&dev_priv->lid_notifier)) {
Zhao Yakui28c97732009-10-09 11:39:41 +0800950 DRM_DEBUG_KMS("lid notifier registration failed\n");
Jesse Barnesc1c7af62009-09-10 15:28:03 -0700951 dev_priv->lid_notifier.notifier_call = NULL;
952 }
Zhao Yakuia2565372009-12-11 09:26:11 +0800953 /* keep the LVDS connector */
954 dev_priv->int_lvds_connector = connector;
Jesse Barnes79e53942008-11-07 14:24:08 -0800955 drm_sysfs_connector_add(connector);
956 return;
957
958failed:
Zhao Yakui8a4c47f2009-07-20 13:48:04 +0800959 DRM_DEBUG_KMS("No LVDS modes found, disabling.\n");
Eric Anholt21d40d32010-03-25 11:11:14 -0700960 if (intel_encoder->ddc_bus)
961 intel_i2c_destroy(intel_encoder->ddc_bus);
Jesse Barnes79e53942008-11-07 14:24:08 -0800962 drm_connector_cleanup(connector);
Shaohua Li1991bdf2009-11-17 17:19:23 +0800963 drm_encoder_cleanup(encoder);
Chris Wilsonea5b2132010-08-04 13:50:23 +0100964 kfree(intel_lvds);
Zhenyu Wangbb8a3562010-03-29 16:40:50 +0800965 kfree(intel_connector);
Jesse Barnes79e53942008-11-07 14:24:08 -0800966}