diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_lvds.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_lvds.c | 133 |
1 files changed, 75 insertions, 58 deletions
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index f1a649990ea9..25bcedf386fd 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c | |||
@@ -68,7 +68,7 @@ static struct intel_lvds *intel_attached_lvds(struct drm_connector *connector) | |||
68 | /** | 68 | /** |
69 | * Sets the power state for the panel. | 69 | * Sets the power state for the panel. |
70 | */ | 70 | */ |
71 | static void intel_lvds_set_power(struct intel_lvds *intel_lvds, bool on) | 71 | static void intel_lvds_enable(struct intel_lvds *intel_lvds) |
72 | { | 72 | { |
73 | struct drm_device *dev = intel_lvds->base.base.dev; | 73 | struct drm_device *dev = intel_lvds->base.base.dev; |
74 | struct drm_i915_private *dev_priv = dev->dev_private; | 74 | struct drm_i915_private *dev_priv = dev->dev_private; |
@@ -82,26 +82,61 @@ static void intel_lvds_set_power(struct intel_lvds *intel_lvds, bool on) | |||
82 | lvds_reg = LVDS; | 82 | lvds_reg = LVDS; |
83 | } | 83 | } |
84 | 84 | ||
85 | if (on) { | 85 | I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN); |
86 | I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN); | ||
87 | I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); | ||
88 | intel_panel_set_backlight(dev, dev_priv->backlight_level); | ||
89 | } else { | ||
90 | dev_priv->backlight_level = intel_panel_get_backlight(dev); | ||
91 | |||
92 | intel_panel_set_backlight(dev, 0); | ||
93 | I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON); | ||
94 | 86 | ||
95 | if (intel_lvds->pfit_control) { | 87 | if (intel_lvds->pfit_dirty) { |
96 | if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) | 88 | /* |
97 | DRM_ERROR("timed out waiting for panel to power off\n"); | 89 | * Enable automatic panel scaling so that non-native modes |
98 | I915_WRITE(PFIT_CONTROL, 0); | 90 | * fill the screen. The panel fitter should only be |
99 | intel_lvds->pfit_control = 0; | 91 | * adjusted whilst the pipe is disabled, according to |
92 | * register description and PRM. | ||
93 | */ | ||
94 | DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", | ||
95 | intel_lvds->pfit_control, | ||
96 | intel_lvds->pfit_pgm_ratios); | ||
97 | if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) { | ||
98 | DRM_ERROR("timed out waiting for panel to power off\n"); | ||
99 | } else { | ||
100 | I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios); | ||
101 | I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control); | ||
100 | intel_lvds->pfit_dirty = false; | 102 | intel_lvds->pfit_dirty = false; |
101 | } | 103 | } |
104 | } | ||
105 | |||
106 | I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); | ||
107 | POSTING_READ(lvds_reg); | ||
108 | |||
109 | intel_panel_set_backlight(dev, dev_priv->backlight_level); | ||
110 | } | ||
111 | |||
112 | static void intel_lvds_disable(struct intel_lvds *intel_lvds) | ||
113 | { | ||
114 | struct drm_device *dev = intel_lvds->base.base.dev; | ||
115 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
116 | u32 ctl_reg, lvds_reg; | ||
117 | |||
118 | if (HAS_PCH_SPLIT(dev)) { | ||
119 | ctl_reg = PCH_PP_CONTROL; | ||
120 | lvds_reg = PCH_LVDS; | ||
121 | } else { | ||
122 | ctl_reg = PP_CONTROL; | ||
123 | lvds_reg = LVDS; | ||
124 | } | ||
125 | |||
126 | dev_priv->backlight_level = intel_panel_get_backlight(dev); | ||
127 | intel_panel_set_backlight(dev, 0); | ||
102 | 128 | ||
103 | I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); | 129 | I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON); |
130 | |||
131 | if (intel_lvds->pfit_control) { | ||
132 | if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) | ||
133 | DRM_ERROR("timed out waiting for panel to power off\n"); | ||
134 | |||
135 | I915_WRITE(PFIT_CONTROL, 0); | ||
136 | intel_lvds->pfit_dirty = true; | ||
104 | } | 137 | } |
138 | |||
139 | I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); | ||
105 | POSTING_READ(lvds_reg); | 140 | POSTING_READ(lvds_reg); |
106 | } | 141 | } |
107 | 142 | ||
@@ -110,9 +145,9 @@ static void intel_lvds_dpms(struct drm_encoder *encoder, int mode) | |||
110 | struct intel_lvds *intel_lvds = to_intel_lvds(encoder); | 145 | struct intel_lvds *intel_lvds = to_intel_lvds(encoder); |
111 | 146 | ||
112 | if (mode == DRM_MODE_DPMS_ON) | 147 | if (mode == DRM_MODE_DPMS_ON) |
113 | intel_lvds_set_power(intel_lvds, true); | 148 | intel_lvds_enable(intel_lvds); |
114 | else | 149 | else |
115 | intel_lvds_set_power(intel_lvds, false); | 150 | intel_lvds_disable(intel_lvds); |
116 | 151 | ||
117 | /* XXX: We never power down the LVDS pairs. */ | 152 | /* XXX: We never power down the LVDS pairs. */ |
118 | } | 153 | } |
@@ -411,43 +446,18 @@ static void intel_lvds_commit(struct drm_encoder *encoder) | |||
411 | /* Always do a full power on as we do not know what state | 446 | /* Always do a full power on as we do not know what state |
412 | * we were left in. | 447 | * we were left in. |
413 | */ | 448 | */ |
414 | intel_lvds_set_power(intel_lvds, true); | 449 | intel_lvds_enable(intel_lvds); |
415 | } | 450 | } |
416 | 451 | ||
417 | static void intel_lvds_mode_set(struct drm_encoder *encoder, | 452 | static void intel_lvds_mode_set(struct drm_encoder *encoder, |
418 | struct drm_display_mode *mode, | 453 | struct drm_display_mode *mode, |
419 | struct drm_display_mode *adjusted_mode) | 454 | struct drm_display_mode *adjusted_mode) |
420 | { | 455 | { |
421 | struct drm_device *dev = encoder->dev; | ||
422 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
423 | struct intel_lvds *intel_lvds = to_intel_lvds(encoder); | ||
424 | |||
425 | /* | 456 | /* |
426 | * The LVDS pin pair will already have been turned on in the | 457 | * The LVDS pin pair will already have been turned on in the |
427 | * intel_crtc_mode_set since it has a large impact on the DPLL | 458 | * intel_crtc_mode_set since it has a large impact on the DPLL |
428 | * settings. | 459 | * settings. |
429 | */ | 460 | */ |
430 | |||
431 | if (HAS_PCH_SPLIT(dev)) | ||
432 | return; | ||
433 | |||
434 | if (!intel_lvds->pfit_dirty) | ||
435 | return; | ||
436 | |||
437 | /* | ||
438 | * Enable automatic panel scaling so that non-native modes fill the | ||
439 | * screen. Should be enabled before the pipe is enabled, according to | ||
440 | * register description and PRM. | ||
441 | */ | ||
442 | DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", | ||
443 | intel_lvds->pfit_control, | ||
444 | intel_lvds->pfit_pgm_ratios); | ||
445 | if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) | ||
446 | DRM_ERROR("timed out waiting for panel to power off\n"); | ||
447 | |||
448 | I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios); | ||
449 | I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control); | ||
450 | intel_lvds->pfit_dirty = false; | ||
451 | } | 461 | } |
452 | 462 | ||
453 | /** | 463 | /** |
@@ -481,11 +491,8 @@ static int intel_lvds_get_modes(struct drm_connector *connector) | |||
481 | struct drm_device *dev = connector->dev; | 491 | struct drm_device *dev = connector->dev; |
482 | struct drm_display_mode *mode; | 492 | struct drm_display_mode *mode; |
483 | 493 | ||
484 | if (intel_lvds->edid) { | 494 | if (intel_lvds->edid) |
485 | drm_mode_connector_update_edid_property(connector, | ||
486 | intel_lvds->edid); | ||
487 | return drm_add_edid_modes(connector, intel_lvds->edid); | 495 | return drm_add_edid_modes(connector, intel_lvds->edid); |
488 | } | ||
489 | 496 | ||
490 | mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode); | 497 | mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode); |
491 | if (mode == 0) | 498 | if (mode == 0) |
@@ -840,7 +847,7 @@ static bool intel_lvds_ddc_probe(struct drm_device *dev, u8 pin) | |||
840 | * Create the connector, register the LVDS DDC bus, and try to figure out what | 847 | * Create the connector, register the LVDS DDC bus, and try to figure out what |
841 | * modes we can display on the LVDS panel (if present). | 848 | * modes we can display on the LVDS panel (if present). |
842 | */ | 849 | */ |
843 | void intel_lvds_init(struct drm_device *dev) | 850 | bool intel_lvds_init(struct drm_device *dev) |
844 | { | 851 | { |
845 | struct drm_i915_private *dev_priv = dev->dev_private; | 852 | struct drm_i915_private *dev_priv = dev->dev_private; |
846 | struct intel_lvds *intel_lvds; | 853 | struct intel_lvds *intel_lvds; |
@@ -856,37 +863,37 @@ void intel_lvds_init(struct drm_device *dev) | |||
856 | 863 | ||
857 | /* Skip init on machines we know falsely report LVDS */ | 864 | /* Skip init on machines we know falsely report LVDS */ |
858 | if (dmi_check_system(intel_no_lvds)) | 865 | if (dmi_check_system(intel_no_lvds)) |
859 | return; | 866 | return false; |
860 | 867 | ||
861 | pin = GMBUS_PORT_PANEL; | 868 | pin = GMBUS_PORT_PANEL; |
862 | if (!lvds_is_present_in_vbt(dev, &pin)) { | 869 | if (!lvds_is_present_in_vbt(dev, &pin)) { |
863 | DRM_DEBUG_KMS("LVDS is not present in VBT\n"); | 870 | DRM_DEBUG_KMS("LVDS is not present in VBT\n"); |
864 | return; | 871 | return false; |
865 | } | 872 | } |
866 | 873 | ||
867 | if (HAS_PCH_SPLIT(dev)) { | 874 | if (HAS_PCH_SPLIT(dev)) { |
868 | if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0) | 875 | if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0) |
869 | return; | 876 | return false; |
870 | if (dev_priv->edp.support) { | 877 | if (dev_priv->edp.support) { |
871 | DRM_DEBUG_KMS("disable LVDS for eDP support\n"); | 878 | DRM_DEBUG_KMS("disable LVDS for eDP support\n"); |
872 | return; | 879 | return false; |
873 | } | 880 | } |
874 | } | 881 | } |
875 | 882 | ||
876 | if (!intel_lvds_ddc_probe(dev, pin)) { | 883 | if (!intel_lvds_ddc_probe(dev, pin)) { |
877 | DRM_DEBUG_KMS("LVDS did not respond to DDC probe\n"); | 884 | DRM_DEBUG_KMS("LVDS did not respond to DDC probe\n"); |
878 | return; | 885 | return false; |
879 | } | 886 | } |
880 | 887 | ||
881 | intel_lvds = kzalloc(sizeof(struct intel_lvds), GFP_KERNEL); | 888 | intel_lvds = kzalloc(sizeof(struct intel_lvds), GFP_KERNEL); |
882 | if (!intel_lvds) { | 889 | if (!intel_lvds) { |
883 | return; | 890 | return false; |
884 | } | 891 | } |
885 | 892 | ||
886 | intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); | 893 | intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); |
887 | if (!intel_connector) { | 894 | if (!intel_connector) { |
888 | kfree(intel_lvds); | 895 | kfree(intel_lvds); |
889 | return; | 896 | return false; |
890 | } | 897 | } |
891 | 898 | ||
892 | if (!HAS_PCH_SPLIT(dev)) { | 899 | if (!HAS_PCH_SPLIT(dev)) { |
@@ -939,7 +946,16 @@ void intel_lvds_init(struct drm_device *dev) | |||
939 | */ | 946 | */ |
940 | intel_lvds->edid = drm_get_edid(connector, | 947 | intel_lvds->edid = drm_get_edid(connector, |
941 | &dev_priv->gmbus[pin].adapter); | 948 | &dev_priv->gmbus[pin].adapter); |
942 | 949 | if (intel_lvds->edid) { | |
950 | if (drm_add_edid_modes(connector, | ||
951 | intel_lvds->edid)) { | ||
952 | drm_mode_connector_update_edid_property(connector, | ||
953 | intel_lvds->edid); | ||
954 | } else { | ||
955 | kfree(intel_lvds->edid); | ||
956 | intel_lvds->edid = NULL; | ||
957 | } | ||
958 | } | ||
943 | if (!intel_lvds->edid) { | 959 | if (!intel_lvds->edid) { |
944 | /* Didn't get an EDID, so | 960 | /* Didn't get an EDID, so |
945 | * Set wide sync ranges so we get all modes | 961 | * Set wide sync ranges so we get all modes |
@@ -1020,7 +1036,7 @@ out: | |||
1020 | /* keep the LVDS connector */ | 1036 | /* keep the LVDS connector */ |
1021 | dev_priv->int_lvds_connector = connector; | 1037 | dev_priv->int_lvds_connector = connector; |
1022 | drm_sysfs_connector_add(connector); | 1038 | drm_sysfs_connector_add(connector); |
1023 | return; | 1039 | return true; |
1024 | 1040 | ||
1025 | failed: | 1041 | failed: |
1026 | DRM_DEBUG_KMS("No LVDS modes found, disabling.\n"); | 1042 | DRM_DEBUG_KMS("No LVDS modes found, disabling.\n"); |
@@ -1028,4 +1044,5 @@ failed: | |||
1028 | drm_encoder_cleanup(encoder); | 1044 | drm_encoder_cleanup(encoder); |
1029 | kfree(intel_lvds); | 1045 | kfree(intel_lvds); |
1030 | kfree(intel_connector); | 1046 | kfree(intel_connector); |
1047 | return false; | ||
1031 | } | 1048 | } |