diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_lvds.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_lvds.c | 140 |
1 files changed, 118 insertions, 22 deletions
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index eb365021bb5a..3118ce274e67 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c | |||
@@ -56,7 +56,7 @@ static void intel_lvds_set_backlight(struct drm_device *dev, int level) | |||
56 | struct drm_i915_private *dev_priv = dev->dev_private; | 56 | struct drm_i915_private *dev_priv = dev->dev_private; |
57 | u32 blc_pwm_ctl, reg; | 57 | u32 blc_pwm_ctl, reg; |
58 | 58 | ||
59 | if (IS_IGDNG(dev)) | 59 | if (IS_IRONLAKE(dev)) |
60 | reg = BLC_PWM_CPU_CTL; | 60 | reg = BLC_PWM_CPU_CTL; |
61 | else | 61 | else |
62 | reg = BLC_PWM_CTL; | 62 | reg = BLC_PWM_CTL; |
@@ -74,7 +74,7 @@ static u32 intel_lvds_get_max_backlight(struct drm_device *dev) | |||
74 | struct drm_i915_private *dev_priv = dev->dev_private; | 74 | struct drm_i915_private *dev_priv = dev->dev_private; |
75 | u32 reg; | 75 | u32 reg; |
76 | 76 | ||
77 | if (IS_IGDNG(dev)) | 77 | if (IS_IRONLAKE(dev)) |
78 | reg = BLC_PWM_PCH_CTL2; | 78 | reg = BLC_PWM_PCH_CTL2; |
79 | else | 79 | else |
80 | reg = BLC_PWM_CTL; | 80 | reg = BLC_PWM_CTL; |
@@ -91,7 +91,7 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) | |||
91 | struct drm_i915_private *dev_priv = dev->dev_private; | 91 | struct drm_i915_private *dev_priv = dev->dev_private; |
92 | u32 pp_status, ctl_reg, status_reg; | 92 | u32 pp_status, ctl_reg, status_reg; |
93 | 93 | ||
94 | if (IS_IGDNG(dev)) { | 94 | if (IS_IRONLAKE(dev)) { |
95 | ctl_reg = PCH_PP_CONTROL; | 95 | ctl_reg = PCH_PP_CONTROL; |
96 | status_reg = PCH_PP_STATUS; | 96 | status_reg = PCH_PP_STATUS; |
97 | } else { | 97 | } else { |
@@ -137,7 +137,7 @@ static void intel_lvds_save(struct drm_connector *connector) | |||
137 | u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg; | 137 | u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg; |
138 | u32 pwm_ctl_reg; | 138 | u32 pwm_ctl_reg; |
139 | 139 | ||
140 | if (IS_IGDNG(dev)) { | 140 | if (IS_IRONLAKE(dev)) { |
141 | pp_on_reg = PCH_PP_ON_DELAYS; | 141 | pp_on_reg = PCH_PP_ON_DELAYS; |
142 | pp_off_reg = PCH_PP_OFF_DELAYS; | 142 | pp_off_reg = PCH_PP_OFF_DELAYS; |
143 | pp_ctl_reg = PCH_PP_CONTROL; | 143 | pp_ctl_reg = PCH_PP_CONTROL; |
@@ -174,7 +174,7 @@ static void intel_lvds_restore(struct drm_connector *connector) | |||
174 | u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg; | 174 | u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg; |
175 | u32 pwm_ctl_reg; | 175 | u32 pwm_ctl_reg; |
176 | 176 | ||
177 | if (IS_IGDNG(dev)) { | 177 | if (IS_IRONLAKE(dev)) { |
178 | pp_on_reg = PCH_PP_ON_DELAYS; | 178 | pp_on_reg = PCH_PP_ON_DELAYS; |
179 | pp_off_reg = PCH_PP_OFF_DELAYS; | 179 | pp_off_reg = PCH_PP_OFF_DELAYS; |
180 | pp_ctl_reg = PCH_PP_CONTROL; | 180 | pp_ctl_reg = PCH_PP_CONTROL; |
@@ -297,7 +297,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, | |||
297 | } | 297 | } |
298 | 298 | ||
299 | /* full screen scale for now */ | 299 | /* full screen scale for now */ |
300 | if (IS_IGDNG(dev)) | 300 | if (IS_IRONLAKE(dev)) |
301 | goto out; | 301 | goto out; |
302 | 302 | ||
303 | /* 965+ wants fuzzy fitting */ | 303 | /* 965+ wants fuzzy fitting */ |
@@ -327,7 +327,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, | |||
327 | * to register description and PRM. | 327 | * to register description and PRM. |
328 | * Change the value here to see the borders for debugging | 328 | * Change the value here to see the borders for debugging |
329 | */ | 329 | */ |
330 | if (!IS_IGDNG(dev)) { | 330 | if (!IS_IRONLAKE(dev)) { |
331 | I915_WRITE(BCLRPAT_A, 0); | 331 | I915_WRITE(BCLRPAT_A, 0); |
332 | I915_WRITE(BCLRPAT_B, 0); | 332 | I915_WRITE(BCLRPAT_B, 0); |
333 | } | 333 | } |
@@ -548,7 +548,7 @@ static void intel_lvds_prepare(struct drm_encoder *encoder) | |||
548 | struct drm_i915_private *dev_priv = dev->dev_private; | 548 | struct drm_i915_private *dev_priv = dev->dev_private; |
549 | u32 reg; | 549 | u32 reg; |
550 | 550 | ||
551 | if (IS_IGDNG(dev)) | 551 | if (IS_IRONLAKE(dev)) |
552 | reg = BLC_PWM_CPU_CTL; | 552 | reg = BLC_PWM_CPU_CTL; |
553 | else | 553 | else |
554 | reg = BLC_PWM_CTL; | 554 | reg = BLC_PWM_CTL; |
@@ -587,7 +587,7 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder, | |||
587 | * settings. | 587 | * settings. |
588 | */ | 588 | */ |
589 | 589 | ||
590 | if (IS_IGDNG(dev)) | 590 | if (IS_IRONLAKE(dev)) |
591 | return; | 591 | return; |
592 | 592 | ||
593 | /* | 593 | /* |
@@ -914,6 +914,101 @@ static int intel_lid_present(void) | |||
914 | #endif | 914 | #endif |
915 | 915 | ||
916 | /** | 916 | /** |
917 | * intel_find_lvds_downclock - find the reduced downclock for LVDS in EDID | ||
918 | * @dev: drm device | ||
919 | * @connector: LVDS connector | ||
920 | * | ||
921 | * Find the reduced downclock for LVDS in EDID. | ||
922 | */ | ||
923 | static void intel_find_lvds_downclock(struct drm_device *dev, | ||
924 | struct drm_connector *connector) | ||
925 | { | ||
926 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
927 | struct drm_display_mode *scan, *panel_fixed_mode; | ||
928 | int temp_downclock; | ||
929 | |||
930 | panel_fixed_mode = dev_priv->panel_fixed_mode; | ||
931 | temp_downclock = panel_fixed_mode->clock; | ||
932 | |||
933 | mutex_lock(&dev->mode_config.mutex); | ||
934 | list_for_each_entry(scan, &connector->probed_modes, head) { | ||
935 | /* | ||
936 | * If one mode has the same resolution with the fixed_panel | ||
937 | * mode while they have the different refresh rate, it means | ||
938 | * that the reduced downclock is found for the LVDS. In such | ||
939 | * case we can set the different FPx0/1 to dynamically select | ||
940 | * between low and high frequency. | ||
941 | */ | ||
942 | if (scan->hdisplay == panel_fixed_mode->hdisplay && | ||
943 | scan->hsync_start == panel_fixed_mode->hsync_start && | ||
944 | scan->hsync_end == panel_fixed_mode->hsync_end && | ||
945 | scan->htotal == panel_fixed_mode->htotal && | ||
946 | scan->vdisplay == panel_fixed_mode->vdisplay && | ||
947 | scan->vsync_start == panel_fixed_mode->vsync_start && | ||
948 | scan->vsync_end == panel_fixed_mode->vsync_end && | ||
949 | scan->vtotal == panel_fixed_mode->vtotal) { | ||
950 | if (scan->clock < temp_downclock) { | ||
951 | /* | ||
952 | * The downclock is already found. But we | ||
953 | * expect to find the lower downclock. | ||
954 | */ | ||
955 | temp_downclock = scan->clock; | ||
956 | } | ||
957 | } | ||
958 | } | ||
959 | mutex_unlock(&dev->mode_config.mutex); | ||
960 | if (temp_downclock < panel_fixed_mode->clock) { | ||
961 | /* We found the downclock for LVDS. */ | ||
962 | dev_priv->lvds_downclock_avail = 1; | ||
963 | dev_priv->lvds_downclock = temp_downclock; | ||
964 | DRM_DEBUG_KMS("LVDS downclock is found in EDID. " | ||
965 | "Normal clock %dKhz, downclock %dKhz\n", | ||
966 | panel_fixed_mode->clock, temp_downclock); | ||
967 | } | ||
968 | return; | ||
969 | } | ||
970 | |||
971 | /* | ||
972 | * Enumerate the child dev array parsed from VBT to check whether | ||
973 | * the LVDS is present. | ||
974 | * If it is present, return 1. | ||
975 | * If it is not present, return false. | ||
976 | * If no child dev is parsed from VBT, it assumes that the LVDS is present. | ||
977 | * Note: The addin_offset should also be checked for LVDS panel. | ||
978 | * Only when it is non-zero, it is assumed that it is present. | ||
979 | */ | ||
980 | static int lvds_is_present_in_vbt(struct drm_device *dev) | ||
981 | { | ||
982 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
983 | struct child_device_config *p_child; | ||
984 | int i, ret; | ||
985 | |||
986 | if (!dev_priv->child_dev_num) | ||
987 | return 1; | ||
988 | |||
989 | ret = 0; | ||
990 | for (i = 0; i < dev_priv->child_dev_num; i++) { | ||
991 | p_child = dev_priv->child_dev + i; | ||
992 | /* | ||
993 | * If the device type is not LFP, continue. | ||
994 | * If the device type is 0x22, it is also regarded as LFP. | ||
995 | */ | ||
996 | if (p_child->device_type != DEVICE_TYPE_INT_LFP && | ||
997 | p_child->device_type != DEVICE_TYPE_LFP) | ||
998 | continue; | ||
999 | |||
1000 | /* The addin_offset should be checked. Only when it is | ||
1001 | * non-zero, it is regarded as present. | ||
1002 | */ | ||
1003 | if (p_child->addin_offset) { | ||
1004 | ret = 1; | ||
1005 | break; | ||
1006 | } | ||
1007 | } | ||
1008 | return ret; | ||
1009 | } | ||
1010 | |||
1011 | /** | ||
917 | * intel_lvds_init - setup LVDS connectors on this device | 1012 | * intel_lvds_init - setup LVDS connectors on this device |
918 | * @dev: drm device | 1013 | * @dev: drm device |
919 | * | 1014 | * |
@@ -936,21 +1031,20 @@ void intel_lvds_init(struct drm_device *dev) | |||
936 | if (dmi_check_system(intel_no_lvds)) | 1031 | if (dmi_check_system(intel_no_lvds)) |
937 | return; | 1032 | return; |
938 | 1033 | ||
939 | /* Assume that any device without an ACPI LID device also doesn't | 1034 | /* |
940 | * have an integrated LVDS. We would be better off parsing the BIOS | 1035 | * Assume LVDS is present if there's an ACPI lid device or if the |
941 | * to get a reliable indicator, but that code isn't written yet. | 1036 | * device is present in the VBT. |
942 | * | ||
943 | * In the case of all-in-one desktops using LVDS that we've seen, | ||
944 | * they're using SDVO LVDS. | ||
945 | */ | 1037 | */ |
946 | if (!intel_lid_present()) | 1038 | if (!lvds_is_present_in_vbt(dev) && !intel_lid_present()) { |
1039 | DRM_DEBUG_KMS("LVDS is not present in VBT and no lid detected\n"); | ||
947 | return; | 1040 | return; |
1041 | } | ||
948 | 1042 | ||
949 | if (IS_IGDNG(dev)) { | 1043 | if (IS_IRONLAKE(dev)) { |
950 | if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0) | 1044 | if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0) |
951 | return; | 1045 | return; |
952 | if (dev_priv->edp_support) { | 1046 | if (dev_priv->edp_support) { |
953 | DRM_DEBUG("disable LVDS for eDP support\n"); | 1047 | DRM_DEBUG_KMS("disable LVDS for eDP support\n"); |
954 | return; | 1048 | return; |
955 | } | 1049 | } |
956 | gpio = PCH_GPIOC; | 1050 | gpio = PCH_GPIOC; |
@@ -1023,6 +1117,7 @@ void intel_lvds_init(struct drm_device *dev) | |||
1023 | dev_priv->panel_fixed_mode = | 1117 | dev_priv->panel_fixed_mode = |
1024 | drm_mode_duplicate(dev, scan); | 1118 | drm_mode_duplicate(dev, scan); |
1025 | mutex_unlock(&dev->mode_config.mutex); | 1119 | mutex_unlock(&dev->mode_config.mutex); |
1120 | intel_find_lvds_downclock(dev, connector); | ||
1026 | goto out; | 1121 | goto out; |
1027 | } | 1122 | } |
1028 | mutex_unlock(&dev->mode_config.mutex); | 1123 | mutex_unlock(&dev->mode_config.mutex); |
@@ -1047,8 +1142,8 @@ void intel_lvds_init(struct drm_device *dev) | |||
1047 | * correct mode. | 1142 | * correct mode. |
1048 | */ | 1143 | */ |
1049 | 1144 | ||
1050 | /* IGDNG: FIXME if still fail, not try pipe mode now */ | 1145 | /* Ironlake: FIXME if still fail, not try pipe mode now */ |
1051 | if (IS_IGDNG(dev)) | 1146 | if (IS_IRONLAKE(dev)) |
1052 | goto failed; | 1147 | goto failed; |
1053 | 1148 | ||
1054 | lvds = I915_READ(LVDS); | 1149 | lvds = I915_READ(LVDS); |
@@ -1069,7 +1164,7 @@ void intel_lvds_init(struct drm_device *dev) | |||
1069 | goto failed; | 1164 | goto failed; |
1070 | 1165 | ||
1071 | out: | 1166 | out: |
1072 | if (IS_IGDNG(dev)) { | 1167 | if (IS_IRONLAKE(dev)) { |
1073 | u32 pwm; | 1168 | u32 pwm; |
1074 | /* make sure PWM is enabled */ | 1169 | /* make sure PWM is enabled */ |
1075 | pwm = I915_READ(BLC_PWM_CPU_CTL2); | 1170 | pwm = I915_READ(BLC_PWM_CPU_CTL2); |
@@ -1082,7 +1177,7 @@ out: | |||
1082 | } | 1177 | } |
1083 | dev_priv->lid_notifier.notifier_call = intel_lid_notify; | 1178 | dev_priv->lid_notifier.notifier_call = intel_lid_notify; |
1084 | if (acpi_lid_notifier_register(&dev_priv->lid_notifier)) { | 1179 | if (acpi_lid_notifier_register(&dev_priv->lid_notifier)) { |
1085 | DRM_DEBUG("lid notifier registration failed\n"); | 1180 | DRM_DEBUG_KMS("lid notifier registration failed\n"); |
1086 | dev_priv->lid_notifier.notifier_call = NULL; | 1181 | dev_priv->lid_notifier.notifier_call = NULL; |
1087 | } | 1182 | } |
1088 | drm_sysfs_connector_add(connector); | 1183 | drm_sysfs_connector_add(connector); |
@@ -1093,5 +1188,6 @@ failed: | |||
1093 | if (intel_output->ddc_bus) | 1188 | if (intel_output->ddc_bus) |
1094 | intel_i2c_destroy(intel_output->ddc_bus); | 1189 | intel_i2c_destroy(intel_output->ddc_bus); |
1095 | drm_connector_cleanup(connector); | 1190 | drm_connector_cleanup(connector); |
1191 | drm_encoder_cleanup(encoder); | ||
1096 | kfree(intel_output); | 1192 | kfree(intel_output); |
1097 | } | 1193 | } |