aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorJani Nikula <jani.nikula@intel.com>2014-06-24 11:27:40 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2014-07-23 01:07:18 -0400
commit6dda730e55f412a6dfb181cae6784822ba463847 (patch)
tree8af4bf0685d6f1e23bcb26ecb59daa658b70a763 /drivers/gpu/drm
parent1de6068eb755cf8f87b985277fc396903d6bccd2 (diff)
drm/i915: respect the VBT minimum backlight brightness
Historically we've exposed the full backlight PWM duty cycle range to the userspace, in the name of "mechanism, not policy". However, it turns out there are both panels and board designs where there is a minimum duty cycle that is required for proper operation. The minimum duty cycle is available in the VBT. The backlight class sysfs interface does not make any promises to the userspace about the physical meaning of the range 0..max_brightness. Specifically there is no guarantee that 0 means off; indeed for acpi_backlight 0 usually is not off, but the minimum acceptable value. Respect the minimum backlight, and expose the range acceptable to the hardware as 0..max_brightness to the userspace via the backlight class device; 0 means the minimum acceptable enabled value. To switch off the backlight, the user must disable the encoder. As a side effect, make the backlight class device max brightness and physical PWM modulation frequency (i.e. max duty cycle) independent. This allows a follow-up patch to virtualize the max value exposed to the userspace. Signed-off-by: Jani Nikula <jani.nikula@intel.com> Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> [danvet: s/BUG_ON/WARN_ON/] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h5
-rw-r--r--drivers/gpu/drm/i915/intel_opregion.c2
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c160
3 files changed, 147 insertions, 20 deletions
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 8fc68c783228..bb9042bde7dd 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -165,6 +165,7 @@ struct intel_panel {
165 struct { 165 struct {
166 bool present; 166 bool present;
167 u32 level; 167 u32 level;
168 u32 min;
168 u32 max; 169 u32 max;
169 bool enabled; 170 bool enabled;
170 bool combination_mode; /* gen 2/4 only */ 171 bool combination_mode; /* gen 2/4 only */
@@ -969,8 +970,8 @@ void intel_pch_panel_fitting(struct intel_crtc *crtc,
969void intel_gmch_panel_fitting(struct intel_crtc *crtc, 970void intel_gmch_panel_fitting(struct intel_crtc *crtc,
970 struct intel_crtc_config *pipe_config, 971 struct intel_crtc_config *pipe_config,
971 int fitting_mode); 972 int fitting_mode);
972void intel_panel_set_backlight(struct intel_connector *connector, u32 level, 973void intel_panel_set_backlight_acpi(struct intel_connector *connector,
973 u32 max); 974 u32 level, u32 max);
974int intel_panel_setup_backlight(struct drm_connector *connector); 975int intel_panel_setup_backlight(struct drm_connector *connector);
975void intel_panel_enable_backlight(struct intel_connector *connector); 976void intel_panel_enable_backlight(struct intel_connector *connector);
976void intel_panel_disable_backlight(struct intel_connector *connector); 977void intel_panel_disable_backlight(struct intel_connector *connector);
diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c
index 2e2c71fcc9ed..5a979b70e3cf 100644
--- a/drivers/gpu/drm/i915/intel_opregion.c
+++ b/drivers/gpu/drm/i915/intel_opregion.c
@@ -418,7 +418,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
418 */ 418 */
419 DRM_DEBUG_KMS("updating opregion backlight %d/255\n", bclp); 419 DRM_DEBUG_KMS("updating opregion backlight %d/255\n", bclp);
420 list_for_each_entry(intel_connector, &dev->mode_config.connector_list, base.head) 420 list_for_each_entry(intel_connector, &dev->mode_config.connector_list, base.head)
421 intel_panel_set_backlight(intel_connector, bclp, 255); 421 intel_panel_set_backlight_acpi(intel_connector, bclp, 255);
422 iowrite32(DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID, &asle->cblv); 422 iowrite32(DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID, &asle->cblv);
423 423
424 drm_modeset_unlock(&dev->mode_config.connection_mutex); 424 drm_modeset_unlock(&dev->mode_config.connection_mutex);
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 38a98570d10c..f2d5f2ebcdde 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -398,6 +398,69 @@ intel_panel_detect(struct drm_device *dev)
398 } 398 }
399} 399}
400 400
401/**
402 * scale - scale values from one range to another
403 *
404 * @source_val: value in range [@source_min..@source_max]
405 *
406 * Return @source_val in range [@source_min..@source_max] scaled to range
407 * [@target_min..@target_max].
408 */
409static uint32_t scale(uint32_t source_val,
410 uint32_t source_min, uint32_t source_max,
411 uint32_t target_min, uint32_t target_max)
412{
413 uint64_t target_val;
414
415 WARN_ON(source_min > source_max);
416 WARN_ON(target_min > target_max);
417
418 /* defensive */
419 source_val = clamp(source_val, source_min, source_max);
420
421 /* avoid overflows */
422 target_val = (uint64_t)(source_val - source_min) *
423 (target_max - target_min);
424 do_div(target_val, source_max - source_min);
425 target_val += target_min;
426
427 return target_val;
428}
429
430/* Scale user_level in range [0..user_max] to [hw_min..hw_max]. */
431static inline u32 scale_user_to_hw(struct intel_connector *connector,
432 u32 user_level, u32 user_max)
433{
434 struct intel_panel *panel = &connector->panel;
435
436 return scale(user_level, 0, user_max,
437 panel->backlight.min, panel->backlight.max);
438}
439
440/* Scale user_level in range [0..user_max] to [0..hw_max], clamping the result
441 * to [hw_min..hw_max]. */
442static inline u32 clamp_user_to_hw(struct intel_connector *connector,
443 u32 user_level, u32 user_max)
444{
445 struct intel_panel *panel = &connector->panel;
446 u32 hw_level;
447
448 hw_level = scale(user_level, 0, user_max, 0, panel->backlight.max);
449 hw_level = clamp(hw_level, panel->backlight.min, panel->backlight.max);
450
451 return hw_level;
452}
453
454/* Scale hw_level in range [hw_min..hw_max] to [0..user_max]. */
455static inline u32 scale_hw_to_user(struct intel_connector *connector,
456 u32 hw_level, u32 user_max)
457{
458 struct intel_panel *panel = &connector->panel;
459
460 return scale(hw_level, panel->backlight.min, panel->backlight.max,
461 0, user_max);
462}
463
401static u32 intel_panel_compute_brightness(struct intel_connector *connector, 464static u32 intel_panel_compute_brightness(struct intel_connector *connector,
402 u32 val) 465 u32 val)
403{ 466{
@@ -557,17 +620,16 @@ intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level)
557 dev_priv->display.set_backlight(connector, level); 620 dev_priv->display.set_backlight(connector, level);
558} 621}
559 622
560/* set backlight brightness to level in range [0..max] */ 623/* set backlight brightness to level in range [0..max], scaling wrt hw min */
561void intel_panel_set_backlight(struct intel_connector *connector, u32 level, 624static void intel_panel_set_backlight(struct intel_connector *connector,
562 u32 max) 625 u32 user_level, u32 user_max)
563{ 626{
564 struct drm_device *dev = connector->base.dev; 627 struct drm_device *dev = connector->base.dev;
565 struct drm_i915_private *dev_priv = dev->dev_private; 628 struct drm_i915_private *dev_priv = dev->dev_private;
566 struct intel_panel *panel = &connector->panel; 629 struct intel_panel *panel = &connector->panel;
567 enum pipe pipe = intel_get_pipe_from_connector(connector); 630 enum pipe pipe = intel_get_pipe_from_connector(connector);
568 u32 freq; 631 u32 hw_level;
569 unsigned long flags; 632 unsigned long flags;
570 u64 n;
571 633
572 if (!panel->backlight.present || pipe == INVALID_PIPE) 634 if (!panel->backlight.present || pipe == INVALID_PIPE)
573 return; 635 return;
@@ -576,18 +638,46 @@ void intel_panel_set_backlight(struct intel_connector *connector, u32 level,
576 638
577 WARN_ON(panel->backlight.max == 0); 639 WARN_ON(panel->backlight.max == 0);
578 640
579 /* scale to hardware max, but be careful to not overflow */ 641 hw_level = scale_user_to_hw(connector, user_level, user_max);
580 freq = panel->backlight.max; 642 panel->backlight.level = hw_level;
581 n = (u64)level * freq; 643
582 do_div(n, max); 644 if (panel->backlight.enabled)
583 level = n; 645 intel_panel_actually_set_backlight(connector, hw_level);
646
647 spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);
648}
649
650/* set backlight brightness to level in range [0..max], assuming hw min is
651 * respected.
652 */
653void intel_panel_set_backlight_acpi(struct intel_connector *connector,
654 u32 user_level, u32 user_max)
655{
656 struct drm_device *dev = connector->base.dev;
657 struct drm_i915_private *dev_priv = dev->dev_private;
658 struct intel_panel *panel = &connector->panel;
659 enum pipe pipe = intel_get_pipe_from_connector(connector);
660 u32 hw_level;
661 unsigned long flags;
662
663 if (!panel->backlight.present || pipe == INVALID_PIPE)
664 return;
665
666 spin_lock_irqsave(&dev_priv->backlight_lock, flags);
667
668 WARN_ON(panel->backlight.max == 0);
669
670 hw_level = clamp_user_to_hw(connector, user_level, user_max);
671 panel->backlight.level = hw_level;
584 672
585 panel->backlight.level = level;
586 if (panel->backlight.device) 673 if (panel->backlight.device)
587 panel->backlight.device->props.brightness = level; 674 panel->backlight.device->props.brightness =
675 scale_hw_to_user(connector,
676 panel->backlight.level,
677 panel->backlight.device->props.max_brightness);
588 678
589 if (panel->backlight.enabled) 679 if (panel->backlight.enabled)
590 intel_panel_actually_set_backlight(connector, level); 680 intel_panel_actually_set_backlight(connector, hw_level);
591 681
592 spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); 682 spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);
593} 683}
@@ -860,7 +950,9 @@ void intel_panel_enable_backlight(struct intel_connector *connector)
860 panel->backlight.level = panel->backlight.max; 950 panel->backlight.level = panel->backlight.max;
861 if (panel->backlight.device) 951 if (panel->backlight.device)
862 panel->backlight.device->props.brightness = 952 panel->backlight.device->props.brightness =
863 panel->backlight.level; 953 scale_hw_to_user(connector,
954 panel->backlight.level,
955 panel->backlight.device->props.max_brightness);
864 } 956 }
865 957
866 dev_priv->display.enable_backlight(connector); 958 dev_priv->display.enable_backlight(connector);
@@ -889,11 +981,15 @@ static int intel_backlight_device_get_brightness(struct backlight_device *bd)
889 struct intel_connector *connector = bl_get_data(bd); 981 struct intel_connector *connector = bl_get_data(bd);
890 struct drm_device *dev = connector->base.dev; 982 struct drm_device *dev = connector->base.dev;
891 struct drm_i915_private *dev_priv = dev->dev_private; 983 struct drm_i915_private *dev_priv = dev->dev_private;
984 u32 hw_level;
892 int ret; 985 int ret;
893 986
894 intel_runtime_pm_get(dev_priv); 987 intel_runtime_pm_get(dev_priv);
895 drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 988 drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
896 ret = intel_panel_get_backlight(connector); 989
990 hw_level = intel_panel_get_backlight(connector);
991 ret = scale_hw_to_user(connector, hw_level, bd->props.max_brightness);
992
897 drm_modeset_unlock(&dev->mode_config.connection_mutex); 993 drm_modeset_unlock(&dev->mode_config.connection_mutex);
898 intel_runtime_pm_put(dev_priv); 994 intel_runtime_pm_put(dev_priv);
899 995
@@ -913,12 +1009,19 @@ static int intel_backlight_device_register(struct intel_connector *connector)
913 if (WARN_ON(panel->backlight.device)) 1009 if (WARN_ON(panel->backlight.device))
914 return -ENODEV; 1010 return -ENODEV;
915 1011
916 BUG_ON(panel->backlight.max == 0); 1012 WARN_ON(panel->backlight.max == 0);
917 1013
918 memset(&props, 0, sizeof(props)); 1014 memset(&props, 0, sizeof(props));
919 props.type = BACKLIGHT_RAW; 1015 props.type = BACKLIGHT_RAW;
920 props.brightness = panel->backlight.level; 1016
1017 /*
1018 * Note: Everything should work even if the backlight device max
1019 * presented to the userspace is arbitrarily chosen.
1020 */
921 props.max_brightness = panel->backlight.max; 1021 props.max_brightness = panel->backlight.max;
1022 props.brightness = scale_hw_to_user(connector,
1023 panel->backlight.level,
1024 props.max_brightness);
922 1025
923 /* 1026 /*
924 * Note: using the same name independent of the connector prevents 1027 * Note: using the same name independent of the connector prevents
@@ -964,6 +1067,19 @@ static void intel_backlight_device_unregister(struct intel_connector *connector)
964 * XXX: Query mode clock or hardware clock and program PWM modulation frequency 1067 * XXX: Query mode clock or hardware clock and program PWM modulation frequency
965 * appropriately when it's 0. Use VBT and/or sane defaults. 1068 * appropriately when it's 0. Use VBT and/or sane defaults.
966 */ 1069 */
1070static u32 get_backlight_min_vbt(struct intel_connector *connector)
1071{
1072 struct drm_device *dev = connector->base.dev;
1073 struct drm_i915_private *dev_priv = dev->dev_private;
1074 struct intel_panel *panel = &connector->panel;
1075
1076 WARN_ON(panel->backlight.max == 0);
1077
1078 /* vbt value is a coefficient in range [0..255] */
1079 return scale(dev_priv->vbt.backlight.min_brightness, 0, 255,
1080 0, panel->backlight.max);
1081}
1082
967static int bdw_setup_backlight(struct intel_connector *connector) 1083static int bdw_setup_backlight(struct intel_connector *connector)
968{ 1084{
969 struct drm_device *dev = connector->base.dev; 1085 struct drm_device *dev = connector->base.dev;
@@ -979,6 +1095,8 @@ static int bdw_setup_backlight(struct intel_connector *connector)
979 if (!panel->backlight.max) 1095 if (!panel->backlight.max)
980 return -ENODEV; 1096 return -ENODEV;
981 1097
1098 panel->backlight.min = get_backlight_min_vbt(connector);
1099
982 val = bdw_get_backlight(connector); 1100 val = bdw_get_backlight(connector);
983 panel->backlight.level = intel_panel_compute_brightness(connector, val); 1101 panel->backlight.level = intel_panel_compute_brightness(connector, val);
984 1102
@@ -1003,6 +1121,8 @@ static int pch_setup_backlight(struct intel_connector *connector)
1003 if (!panel->backlight.max) 1121 if (!panel->backlight.max)
1004 return -ENODEV; 1122 return -ENODEV;
1005 1123
1124 panel->backlight.min = get_backlight_min_vbt(connector);
1125
1006 val = pch_get_backlight(connector); 1126 val = pch_get_backlight(connector);
1007 panel->backlight.level = intel_panel_compute_brightness(connector, val); 1127 panel->backlight.level = intel_panel_compute_brightness(connector, val);
1008 1128
@@ -1035,6 +1155,8 @@ static int i9xx_setup_backlight(struct intel_connector *connector)
1035 if (!panel->backlight.max) 1155 if (!panel->backlight.max)
1036 return -ENODEV; 1156 return -ENODEV;
1037 1157
1158 panel->backlight.min = get_backlight_min_vbt(connector);
1159
1038 val = i9xx_get_backlight(connector); 1160 val = i9xx_get_backlight(connector);
1039 panel->backlight.level = intel_panel_compute_brightness(connector, val); 1161 panel->backlight.level = intel_panel_compute_brightness(connector, val);
1040 1162
@@ -1062,6 +1184,8 @@ static int i965_setup_backlight(struct intel_connector *connector)
1062 if (!panel->backlight.max) 1184 if (!panel->backlight.max)
1063 return -ENODEV; 1185 return -ENODEV;
1064 1186
1187 panel->backlight.min = get_backlight_min_vbt(connector);
1188
1065 val = i9xx_get_backlight(connector); 1189 val = i9xx_get_backlight(connector);
1066 panel->backlight.level = intel_panel_compute_brightness(connector, val); 1190 panel->backlight.level = intel_panel_compute_brightness(connector, val);
1067 1191
@@ -1099,6 +1223,8 @@ static int vlv_setup_backlight(struct intel_connector *connector)
1099 if (!panel->backlight.max) 1223 if (!panel->backlight.max)
1100 return -ENODEV; 1224 return -ENODEV;
1101 1225
1226 panel->backlight.min = get_backlight_min_vbt(connector);
1227
1102 val = _vlv_get_backlight(dev, PIPE_A); 1228 val = _vlv_get_backlight(dev, PIPE_A);
1103 panel->backlight.level = intel_panel_compute_brightness(connector, val); 1229 panel->backlight.level = intel_panel_compute_brightness(connector, val);
1104 1230