diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-12 21:09:18 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-12 21:09:18 -0400 |
commit | 6b702462cbe5b6f372966a53f4465d745d86b65c (patch) | |
tree | 19a8d090b284bb804e8a2ffa38fa51b58118db6a /drivers/gpu/drm/i915/intel_lvds.c | |
parent | 947ec0b0c1e7e80eef4fe64f7763a06d0cf04d2e (diff) | |
parent | 3c24475c1e4e8d10e50df161d8c4f1d382997a7c (diff) |
Merge branch 'drm-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6
* 'drm-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: (50 commits)
drm: include kernel list header file in hashtab header
drm: Export hash table functionality.
drm: Split out the mm declarations in a separate header. Add atomic operations.
drm/radeon: add support for RV790.
drm/radeon: add rv740 drm support.
drm_calloc_large: check right size, check integer overflow, use GFP_ZERO
drm: Eliminate magic I2C frobbing when reading EDID
drm/i915: duplicate desired mode for use by fbcon.
drm/via: vfree() no need checking before calling it
drm: Replace DRM_DEBUG with DRM_DEBUG_DRIVER in i915 driver
drm: Replace DRM_DEBUG with DRM_DEBUG_MODE in drm_mode
drm/i915: Replace DRM_DEBUG with DRM_DEBUG_KMS in intel_sdvo
drm/i915: replace DRM_DEBUG with DRM_DEBUG_KMS in intel_lvds
drm: add separate drm debugging levels
radeon: remove _DRM_DRIVER from the preadded sarea map
drm: don't associate _DRM_DRIVER maps with a master
drm: simplify kcalloc() call to kzalloc().
intelfb: fix spelling of "CLOCK"
drm: fix LOCK_TEST_WITH_RETURN macro
drm/i915: Hook connector to encoder during load detection (fixes tv/vga detect)
...
Diffstat (limited to 'drivers/gpu/drm/i915/intel_lvds.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_lvds.c | 151 |
1 files changed, 125 insertions, 26 deletions
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 53cccfa58b95..f073ed8432e8 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c | |||
@@ -37,6 +37,8 @@ | |||
37 | #include "i915_drm.h" | 37 | #include "i915_drm.h" |
38 | #include "i915_drv.h" | 38 | #include "i915_drv.h" |
39 | 39 | ||
40 | #define I915_LVDS "i915_lvds" | ||
41 | |||
40 | /** | 42 | /** |
41 | * Sets the backlight level. | 43 | * Sets the backlight level. |
42 | * | 44 | * |
@@ -45,10 +47,15 @@ | |||
45 | static void intel_lvds_set_backlight(struct drm_device *dev, int level) | 47 | static void intel_lvds_set_backlight(struct drm_device *dev, int level) |
46 | { | 48 | { |
47 | struct drm_i915_private *dev_priv = dev->dev_private; | 49 | struct drm_i915_private *dev_priv = dev->dev_private; |
48 | u32 blc_pwm_ctl; | 50 | u32 blc_pwm_ctl, reg; |
51 | |||
52 | if (IS_IGDNG(dev)) | ||
53 | reg = BLC_PWM_CPU_CTL; | ||
54 | else | ||
55 | reg = BLC_PWM_CTL; | ||
49 | 56 | ||
50 | blc_pwm_ctl = I915_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; | 57 | blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK; |
51 | I915_WRITE(BLC_PWM_CTL, (blc_pwm_ctl | | 58 | I915_WRITE(reg, (blc_pwm_ctl | |
52 | (level << BACKLIGHT_DUTY_CYCLE_SHIFT))); | 59 | (level << BACKLIGHT_DUTY_CYCLE_SHIFT))); |
53 | } | 60 | } |
54 | 61 | ||
@@ -58,8 +65,14 @@ static void intel_lvds_set_backlight(struct drm_device *dev, int level) | |||
58 | static u32 intel_lvds_get_max_backlight(struct drm_device *dev) | 65 | static u32 intel_lvds_get_max_backlight(struct drm_device *dev) |
59 | { | 66 | { |
60 | struct drm_i915_private *dev_priv = dev->dev_private; | 67 | struct drm_i915_private *dev_priv = dev->dev_private; |
68 | u32 reg; | ||
69 | |||
70 | if (IS_IGDNG(dev)) | ||
71 | reg = BLC_PWM_PCH_CTL2; | ||
72 | else | ||
73 | reg = BLC_PWM_CTL; | ||
61 | 74 | ||
62 | return ((I915_READ(BLC_PWM_CTL) & BACKLIGHT_MODULATION_FREQ_MASK) >> | 75 | return ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >> |
63 | BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; | 76 | BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; |
64 | } | 77 | } |
65 | 78 | ||
@@ -69,23 +82,31 @@ static u32 intel_lvds_get_max_backlight(struct drm_device *dev) | |||
69 | static void intel_lvds_set_power(struct drm_device *dev, bool on) | 82 | static void intel_lvds_set_power(struct drm_device *dev, bool on) |
70 | { | 83 | { |
71 | struct drm_i915_private *dev_priv = dev->dev_private; | 84 | struct drm_i915_private *dev_priv = dev->dev_private; |
72 | u32 pp_status; | 85 | u32 pp_status, ctl_reg, status_reg; |
86 | |||
87 | if (IS_IGDNG(dev)) { | ||
88 | ctl_reg = PCH_PP_CONTROL; | ||
89 | status_reg = PCH_PP_STATUS; | ||
90 | } else { | ||
91 | ctl_reg = PP_CONTROL; | ||
92 | status_reg = PP_STATUS; | ||
93 | } | ||
73 | 94 | ||
74 | if (on) { | 95 | if (on) { |
75 | I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | | 96 | I915_WRITE(ctl_reg, I915_READ(ctl_reg) | |
76 | POWER_TARGET_ON); | 97 | POWER_TARGET_ON); |
77 | do { | 98 | do { |
78 | pp_status = I915_READ(PP_STATUS); | 99 | pp_status = I915_READ(status_reg); |
79 | } while ((pp_status & PP_ON) == 0); | 100 | } while ((pp_status & PP_ON) == 0); |
80 | 101 | ||
81 | intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle); | 102 | intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle); |
82 | } else { | 103 | } else { |
83 | intel_lvds_set_backlight(dev, 0); | 104 | intel_lvds_set_backlight(dev, 0); |
84 | 105 | ||
85 | I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & | 106 | I915_WRITE(ctl_reg, I915_READ(ctl_reg) & |
86 | ~POWER_TARGET_ON); | 107 | ~POWER_TARGET_ON); |
87 | do { | 108 | do { |
88 | pp_status = I915_READ(PP_STATUS); | 109 | pp_status = I915_READ(status_reg); |
89 | } while (pp_status & PP_ON); | 110 | } while (pp_status & PP_ON); |
90 | } | 111 | } |
91 | } | 112 | } |
@@ -106,12 +127,28 @@ static void intel_lvds_save(struct drm_connector *connector) | |||
106 | { | 127 | { |
107 | struct drm_device *dev = connector->dev; | 128 | struct drm_device *dev = connector->dev; |
108 | struct drm_i915_private *dev_priv = dev->dev_private; | 129 | struct drm_i915_private *dev_priv = dev->dev_private; |
130 | u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg; | ||
131 | u32 pwm_ctl_reg; | ||
132 | |||
133 | if (IS_IGDNG(dev)) { | ||
134 | pp_on_reg = PCH_PP_ON_DELAYS; | ||
135 | pp_off_reg = PCH_PP_OFF_DELAYS; | ||
136 | pp_ctl_reg = PCH_PP_CONTROL; | ||
137 | pp_div_reg = PCH_PP_DIVISOR; | ||
138 | pwm_ctl_reg = BLC_PWM_CPU_CTL; | ||
139 | } else { | ||
140 | pp_on_reg = PP_ON_DELAYS; | ||
141 | pp_off_reg = PP_OFF_DELAYS; | ||
142 | pp_ctl_reg = PP_CONTROL; | ||
143 | pp_div_reg = PP_DIVISOR; | ||
144 | pwm_ctl_reg = BLC_PWM_CTL; | ||
145 | } | ||
109 | 146 | ||
110 | dev_priv->savePP_ON = I915_READ(PP_ON_DELAYS); | 147 | dev_priv->savePP_ON = I915_READ(pp_on_reg); |
111 | dev_priv->savePP_OFF = I915_READ(PP_OFF_DELAYS); | 148 | dev_priv->savePP_OFF = I915_READ(pp_off_reg); |
112 | dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL); | 149 | dev_priv->savePP_CONTROL = I915_READ(pp_ctl_reg); |
113 | dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR); | 150 | dev_priv->savePP_DIVISOR = I915_READ(pp_div_reg); |
114 | dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); | 151 | dev_priv->saveBLC_PWM_CTL = I915_READ(pwm_ctl_reg); |
115 | dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & | 152 | dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & |
116 | BACKLIGHT_DUTY_CYCLE_MASK); | 153 | BACKLIGHT_DUTY_CYCLE_MASK); |
117 | 154 | ||
@@ -127,12 +164,28 @@ static void intel_lvds_restore(struct drm_connector *connector) | |||
127 | { | 164 | { |
128 | struct drm_device *dev = connector->dev; | 165 | struct drm_device *dev = connector->dev; |
129 | struct drm_i915_private *dev_priv = dev->dev_private; | 166 | struct drm_i915_private *dev_priv = dev->dev_private; |
167 | u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg; | ||
168 | u32 pwm_ctl_reg; | ||
169 | |||
170 | if (IS_IGDNG(dev)) { | ||
171 | pp_on_reg = PCH_PP_ON_DELAYS; | ||
172 | pp_off_reg = PCH_PP_OFF_DELAYS; | ||
173 | pp_ctl_reg = PCH_PP_CONTROL; | ||
174 | pp_div_reg = PCH_PP_DIVISOR; | ||
175 | pwm_ctl_reg = BLC_PWM_CPU_CTL; | ||
176 | } else { | ||
177 | pp_on_reg = PP_ON_DELAYS; | ||
178 | pp_off_reg = PP_OFF_DELAYS; | ||
179 | pp_ctl_reg = PP_CONTROL; | ||
180 | pp_div_reg = PP_DIVISOR; | ||
181 | pwm_ctl_reg = BLC_PWM_CTL; | ||
182 | } | ||
130 | 183 | ||
131 | I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL); | 184 | I915_WRITE(pwm_ctl_reg, dev_priv->saveBLC_PWM_CTL); |
132 | I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON); | 185 | I915_WRITE(pp_on_reg, dev_priv->savePP_ON); |
133 | I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF); | 186 | I915_WRITE(pp_off_reg, dev_priv->savePP_OFF); |
134 | I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR); | 187 | I915_WRITE(pp_div_reg, dev_priv->savePP_DIVISOR); |
135 | I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL); | 188 | I915_WRITE(pp_ctl_reg, dev_priv->savePP_CONTROL); |
136 | if (dev_priv->savePP_CONTROL & POWER_TARGET_ON) | 189 | if (dev_priv->savePP_CONTROL & POWER_TARGET_ON) |
137 | intel_lvds_set_power(dev, true); | 190 | intel_lvds_set_power(dev, true); |
138 | else | 191 | else |
@@ -216,8 +269,14 @@ static void intel_lvds_prepare(struct drm_encoder *encoder) | |||
216 | { | 269 | { |
217 | struct drm_device *dev = encoder->dev; | 270 | struct drm_device *dev = encoder->dev; |
218 | struct drm_i915_private *dev_priv = dev->dev_private; | 271 | struct drm_i915_private *dev_priv = dev->dev_private; |
272 | u32 reg; | ||
273 | |||
274 | if (IS_IGDNG(dev)) | ||
275 | reg = BLC_PWM_CPU_CTL; | ||
276 | else | ||
277 | reg = BLC_PWM_CTL; | ||
219 | 278 | ||
220 | dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); | 279 | dev_priv->saveBLC_PWM_CTL = I915_READ(reg); |
221 | dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & | 280 | dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & |
222 | BACKLIGHT_DUTY_CYCLE_MASK); | 281 | BACKLIGHT_DUTY_CYCLE_MASK); |
223 | 282 | ||
@@ -251,6 +310,10 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder, | |||
251 | * settings. | 310 | * settings. |
252 | */ | 311 | */ |
253 | 312 | ||
313 | /* No panel fitting yet, fixme */ | ||
314 | if (IS_IGDNG(dev)) | ||
315 | return; | ||
316 | |||
254 | /* | 317 | /* |
255 | * Enable automatic panel scaling so that non-native modes fill the | 318 | * Enable automatic panel scaling so that non-native modes fill the |
256 | * screen. Should be enabled before the pipe is enabled, according to | 319 | * screen. Should be enabled before the pipe is enabled, according to |
@@ -382,7 +445,8 @@ static const struct drm_encoder_funcs intel_lvds_enc_funcs = { | |||
382 | 445 | ||
383 | static int __init intel_no_lvds_dmi_callback(const struct dmi_system_id *id) | 446 | static int __init intel_no_lvds_dmi_callback(const struct dmi_system_id *id) |
384 | { | 447 | { |
385 | DRM_DEBUG("Skipping LVDS initialization for %s\n", id->ident); | 448 | DRM_DEBUG_KMS(I915_LVDS, |
449 | "Skipping LVDS initialization for %s\n", id->ident); | ||
386 | return 1; | 450 | return 1; |
387 | } | 451 | } |
388 | 452 | ||
@@ -420,8 +484,21 @@ static const struct dmi_system_id intel_no_lvds[] = { | |||
420 | DMI_MATCH(DMI_PRODUCT_NAME, "Studio Hybrid 140g"), | 484 | DMI_MATCH(DMI_PRODUCT_NAME, "Studio Hybrid 140g"), |
421 | }, | 485 | }, |
422 | }, | 486 | }, |
423 | 487 | { | |
424 | /* FIXME: add a check for the Aopen Mini PC */ | 488 | .callback = intel_no_lvds_dmi_callback, |
489 | .ident = "AOpen Mini PC", | ||
490 | .matches = { | ||
491 | DMI_MATCH(DMI_SYS_VENDOR, "AOpen"), | ||
492 | DMI_MATCH(DMI_PRODUCT_NAME, "i965GMx-IF"), | ||
493 | }, | ||
494 | }, | ||
495 | { | ||
496 | .callback = intel_no_lvds_dmi_callback, | ||
497 | .ident = "Aopen i945GTt-VFA", | ||
498 | .matches = { | ||
499 | DMI_MATCH(DMI_PRODUCT_VERSION, "AO00001JW"), | ||
500 | }, | ||
501 | }, | ||
425 | 502 | ||
426 | { } /* terminating entry */ | 503 | { } /* terminating entry */ |
427 | }; | 504 | }; |
@@ -442,12 +519,18 @@ void intel_lvds_init(struct drm_device *dev) | |||
442 | struct drm_display_mode *scan; /* *modes, *bios_mode; */ | 519 | struct drm_display_mode *scan; /* *modes, *bios_mode; */ |
443 | struct drm_crtc *crtc; | 520 | struct drm_crtc *crtc; |
444 | u32 lvds; | 521 | u32 lvds; |
445 | int pipe; | 522 | int pipe, gpio = GPIOC; |
446 | 523 | ||
447 | /* Skip init on machines we know falsely report LVDS */ | 524 | /* Skip init on machines we know falsely report LVDS */ |
448 | if (dmi_check_system(intel_no_lvds)) | 525 | if (dmi_check_system(intel_no_lvds)) |
449 | return; | 526 | return; |
450 | 527 | ||
528 | if (IS_IGDNG(dev)) { | ||
529 | if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0) | ||
530 | return; | ||
531 | gpio = PCH_GPIOC; | ||
532 | } | ||
533 | |||
451 | intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL); | 534 | intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL); |
452 | if (!intel_output) { | 535 | if (!intel_output) { |
453 | return; | 536 | return; |
@@ -482,7 +565,7 @@ void intel_lvds_init(struct drm_device *dev) | |||
482 | */ | 565 | */ |
483 | 566 | ||
484 | /* Set up the DDC bus. */ | 567 | /* Set up the DDC bus. */ |
485 | intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C"); | 568 | intel_output->ddc_bus = intel_i2c_create(dev, gpio, "LVDSDDC_C"); |
486 | if (!intel_output->ddc_bus) { | 569 | if (!intel_output->ddc_bus) { |
487 | dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " | 570 | dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " |
488 | "failed.\n"); | 571 | "failed.\n"); |
@@ -524,6 +607,11 @@ void intel_lvds_init(struct drm_device *dev) | |||
524 | * on. If so, assume that whatever is currently programmed is the | 607 | * on. If so, assume that whatever is currently programmed is the |
525 | * correct mode. | 608 | * correct mode. |
526 | */ | 609 | */ |
610 | |||
611 | /* IGDNG: FIXME if still fail, not try pipe mode now */ | ||
612 | if (IS_IGDNG(dev)) | ||
613 | goto failed; | ||
614 | |||
527 | lvds = I915_READ(LVDS); | 615 | lvds = I915_READ(LVDS); |
528 | pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; | 616 | pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; |
529 | crtc = intel_get_crtc_from_pipe(dev, pipe); | 617 | crtc = intel_get_crtc_from_pipe(dev, pipe); |
@@ -542,11 +630,22 @@ void intel_lvds_init(struct drm_device *dev) | |||
542 | goto failed; | 630 | goto failed; |
543 | 631 | ||
544 | out: | 632 | out: |
633 | if (IS_IGDNG(dev)) { | ||
634 | u32 pwm; | ||
635 | /* make sure PWM is enabled */ | ||
636 | pwm = I915_READ(BLC_PWM_CPU_CTL2); | ||
637 | pwm |= (PWM_ENABLE | PWM_PIPE_B); | ||
638 | I915_WRITE(BLC_PWM_CPU_CTL2, pwm); | ||
639 | |||
640 | pwm = I915_READ(BLC_PWM_PCH_CTL1); | ||
641 | pwm |= PWM_PCH_ENABLE; | ||
642 | I915_WRITE(BLC_PWM_PCH_CTL1, pwm); | ||
643 | } | ||
545 | drm_sysfs_connector_add(connector); | 644 | drm_sysfs_connector_add(connector); |
546 | return; | 645 | return; |
547 | 646 | ||
548 | failed: | 647 | failed: |
549 | DRM_DEBUG("No LVDS modes found, disabling.\n"); | 648 | DRM_DEBUG_KMS(I915_LVDS, "No LVDS modes found, disabling.\n"); |
550 | if (intel_output->ddc_bus) | 649 | if (intel_output->ddc_bus) |
551 | intel_i2c_destroy(intel_output->ddc_bus); | 650 | intel_i2c_destroy(intel_output->ddc_bus); |
552 | drm_connector_cleanup(connector); | 651 | drm_connector_cleanup(connector); |