11d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson/* 21d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * Copyright © 2006-2010 Intel Corporation 31d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * Copyright (c) 2006 Dave Airlie <airlied@linux.ie> 41d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * 51d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * Permission is hereby granted, free of charge, to any person obtaining a 61d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * copy of this software and associated documentation files (the "Software"), 71d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * to deal in the Software without restriction, including without limitation 81d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * the rights to use, copy, modify, merge, publish, distribute, sublicense, 91d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * and/or sell copies of the Software, and to permit persons to whom the 101d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * Software is furnished to do so, subject to the following conditions: 111d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * 121d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * The above copyright notice and this permission notice (including the next 131d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * paragraph) shall be included in all copies or substantial portions of the 141d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * Software. 151d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * 161d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 171d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 181d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 191d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 201d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 211d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 221d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * DEALINGS IN THE SOFTWARE. 231d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * 241d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * Authors: 251d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * Eric Anholt <eric@anholt.net> 261d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * Dave Airlie <airlied@linux.ie> 271d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * Jesse Barnes <jesse.barnes@intel.com> 281d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson * Chris Wilson <chris@chris-wilson.co.uk> 291d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson */ 301d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson 311d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson#include "intel_drv.h" 321d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson 33ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */ 34ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai 351d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilsonvoid 361d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilsonintel_fixed_panel_mode(struct drm_display_mode *fixed_mode, 371d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson struct drm_display_mode *adjusted_mode) 381d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson{ 391d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson adjusted_mode->hdisplay = fixed_mode->hdisplay; 401d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson adjusted_mode->hsync_start = fixed_mode->hsync_start; 411d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson adjusted_mode->hsync_end = fixed_mode->hsync_end; 421d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson adjusted_mode->htotal = fixed_mode->htotal; 431d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson 441d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson adjusted_mode->vdisplay = fixed_mode->vdisplay; 451d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson adjusted_mode->vsync_start = fixed_mode->vsync_start; 461d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson adjusted_mode->vsync_end = fixed_mode->vsync_end; 471d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson adjusted_mode->vtotal = fixed_mode->vtotal; 481d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson 491d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson adjusted_mode->clock = fixed_mode->clock; 501d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson} 511d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson 521d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson/* adjusted_mode has been preset to be the panel's fixed mode */ 531d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilsonvoid 541d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilsonintel_pch_panel_fitting(struct drm_device *dev, 551d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson int fitting_mode, 561d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson struct drm_display_mode *mode, 571d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson struct drm_display_mode *adjusted_mode) 581d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson{ 591d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson struct drm_i915_private *dev_priv = dev->dev_private; 601d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson int x, y, width, height; 611d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson 621d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson x = y = width = height = 0; 631d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson 641d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson /* Native modes don't need fitting */ 651d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson if (adjusted_mode->hdisplay == mode->hdisplay && 661d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson adjusted_mode->vdisplay == mode->vdisplay) 671d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson goto done; 681d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson 691d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson switch (fitting_mode) { 701d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson case DRM_MODE_SCALE_CENTER: 711d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson width = mode->hdisplay; 721d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson height = mode->vdisplay; 731d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson x = (adjusted_mode->hdisplay - width + 1)/2; 741d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson y = (adjusted_mode->vdisplay - height + 1)/2; 751d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson break; 761d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson 771d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson case DRM_MODE_SCALE_ASPECT: 781d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson /* Scale but preserve the aspect ratio */ 791d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson { 801d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay; 811d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; 821d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson if (scaled_width > scaled_height) { /* pillar */ 831d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson width = scaled_height / mode->vdisplay; 84302983e9059e9ef5de3ca7671918eeb237c5971eAdam Jackson if (width & 1) 850206e353a0416ad63ce07f53c807c2c725633b87Akshay Joshi width++; 861d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson x = (adjusted_mode->hdisplay - width + 1) / 2; 871d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson y = 0; 881d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson height = adjusted_mode->vdisplay; 891d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson } else if (scaled_width < scaled_height) { /* letter */ 901d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson height = scaled_width / mode->hdisplay; 91302983e9059e9ef5de3ca7671918eeb237c5971eAdam Jackson if (height & 1) 92302983e9059e9ef5de3ca7671918eeb237c5971eAdam Jackson height++; 931d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson y = (adjusted_mode->vdisplay - height + 1) / 2; 941d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson x = 0; 951d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson width = adjusted_mode->hdisplay; 961d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson } else { 971d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson x = y = 0; 981d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson width = adjusted_mode->hdisplay; 991d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson height = adjusted_mode->vdisplay; 1001d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson } 1011d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson } 1021d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson break; 1031d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson 1041d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson default: 1051d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson case DRM_MODE_SCALE_FULLSCREEN: 1061d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson x = y = 0; 1071d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson width = adjusted_mode->hdisplay; 1081d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson height = adjusted_mode->vdisplay; 1091d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson break; 1101d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson } 1111d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson 1121d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilsondone: 1131d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson dev_priv->pch_pf_pos = (x << 16) | y; 1141d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson dev_priv->pch_pf_size = (width << 16) | height; 1151d8e1c75ffa84400758aef9cc59298920b8801f9Chris Wilson} 116a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson 117ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwaistatic int is_backlight_combination_mode(struct drm_device *dev) 118ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai{ 119ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai struct drm_i915_private *dev_priv = dev->dev_private; 120ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai 121ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai if (INTEL_INFO(dev)->gen >= 4) 122ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE; 123ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai 124ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai if (IS_GEN2(dev)) 125ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE; 126ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai 127ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai return 0; 128ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai} 129ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai 1300b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilsonstatic u32 i915_read_blc_pwm_ctl(struct drm_i915_private *dev_priv) 1310b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson{ 1320b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson u32 val; 1330b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson 1340b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson /* Restore the CTL value if it lost, e.g. GPU reset */ 1350b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson 1360b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson if (HAS_PCH_SPLIT(dev_priv->dev)) { 1370b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson val = I915_READ(BLC_PWM_PCH_CTL2); 1380b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson if (dev_priv->saveBLC_PWM_CTL2 == 0) { 1390b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson dev_priv->saveBLC_PWM_CTL2 = val; 1400b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson } else if (val == 0) { 1410b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson I915_WRITE(BLC_PWM_PCH_CTL2, 1422aded1b6bb83cabe3ee5763e5c3834e36bf4a61fSimon Que dev_priv->saveBLC_PWM_CTL2); 1432aded1b6bb83cabe3ee5763e5c3834e36bf4a61fSimon Que val = dev_priv->saveBLC_PWM_CTL2; 1440b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson } 1450b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson } else { 1460b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson val = I915_READ(BLC_PWM_CTL); 1470b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson if (dev_priv->saveBLC_PWM_CTL == 0) { 1480b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson dev_priv->saveBLC_PWM_CTL = val; 1490b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2); 1500b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson } else if (val == 0) { 1510b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson I915_WRITE(BLC_PWM_CTL, 1520b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson dev_priv->saveBLC_PWM_CTL); 1530b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson I915_WRITE(BLC_PWM_CTL2, 1540b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson dev_priv->saveBLC_PWM_CTL2); 1550b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson val = dev_priv->saveBLC_PWM_CTL; 1560b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson } 1570b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson } 1580b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson 1590b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson return val; 1600b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson} 1610b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson 162a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilsonu32 intel_panel_get_max_backlight(struct drm_device *dev) 163a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson{ 164a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson struct drm_i915_private *dev_priv = dev->dev_private; 165a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson u32 max; 166a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson 1670b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson max = i915_read_blc_pwm_ctl(dev_priv); 1680b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson if (max == 0) { 1690b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson /* XXX add code here to query mode clock or hardware clock 1700b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson * and program max PWM appropriately. 1710b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson */ 1720b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson printk_once(KERN_WARNING "fixme: max PWM is zero.\n"); 1730b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson return 1; 1740b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson } 1750b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson 176a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson if (HAS_PCH_SPLIT(dev)) { 1770b0b053a3949f5c467c3b3ba135d4c161f9fbd00Chris Wilson max >>= 16; 178a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson } else { 179ca88479c1c3b7b1a9f94320745f5331e1de77f80Keith Packard if (INTEL_INFO(dev)->gen < 4) 180a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson max >>= 17; 181ca88479c1c3b7b1a9f94320745f5331e1de77f80Keith Packard else 182a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson max >>= 16; 183ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai 184ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai if (is_backlight_combination_mode(dev)) 185ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai max *= 0xff; 186a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson } 187a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson 188a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max); 189a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson return max; 190a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson} 191a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson 192a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilsonu32 intel_panel_get_backlight(struct drm_device *dev) 193a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson{ 194a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson struct drm_i915_private *dev_priv = dev->dev_private; 195a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson u32 val; 196a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson 197a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson if (HAS_PCH_SPLIT(dev)) { 198a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; 199a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson } else { 200a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; 201ca88479c1c3b7b1a9f94320745f5331e1de77f80Keith Packard if (INTEL_INFO(dev)->gen < 4) 202a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson val >>= 1; 203ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai 2040206e353a0416ad63ce07f53c807c2c725633b87Akshay Joshi if (is_backlight_combination_mode(dev)) { 205ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai u8 lbpc; 206ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai 207ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc); 208ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai val *= lbpc; 209ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai } 210a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson } 211a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson 212a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); 213a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson return val; 214a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson} 215a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson 216a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilsonstatic void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level) 217a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson{ 218a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson struct drm_i915_private *dev_priv = dev->dev_private; 219a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; 220a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson I915_WRITE(BLC_PWM_CPU_CTL, val | level); 221a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson} 222a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson 223f52c619a590fa75276c07dfcaf380dee53e4ea4cTakashi Iwaistatic void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level) 224a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson{ 225a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson struct drm_i915_private *dev_priv = dev->dev_private; 226a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson u32 tmp; 227a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson 228a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); 229a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson 230a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson if (HAS_PCH_SPLIT(dev)) 231a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson return intel_pch_panel_set_backlight(dev, level); 232ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai 2330206e353a0416ad63ce07f53c807c2c725633b87Akshay Joshi if (is_backlight_combination_mode(dev)) { 234ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai u32 max = intel_panel_get_max_backlight(dev); 235ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai u8 lbpc; 236ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai 237ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai lbpc = level * 0xfe / max + 1; 238ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai level /= lbpc; 239ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc); 240ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai } 241ba3820ade317ee36e496b9b40d2ec3987dd4aef0Takashi Iwai 242a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson tmp = I915_READ(BLC_PWM_CTL); 243ca88479c1c3b7b1a9f94320745f5331e1de77f80Keith Packard if (INTEL_INFO(dev)->gen < 4) 244a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson level <<= 1; 245ca88479c1c3b7b1a9f94320745f5331e1de77f80Keith Packard tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK; 246a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson I915_WRITE(BLC_PWM_CTL, tmp | level); 247a95735569312f2ab0c80425e2cd1e5cb0b4e1870Chris Wilson} 24847356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson 249f52c619a590fa75276c07dfcaf380dee53e4ea4cTakashi Iwaivoid intel_panel_set_backlight(struct drm_device *dev, u32 level) 25047356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson{ 25147356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson struct drm_i915_private *dev_priv = dev->dev_private; 25247356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson 253f52c619a590fa75276c07dfcaf380dee53e4ea4cTakashi Iwai dev_priv->backlight_level = level; 254f52c619a590fa75276c07dfcaf380dee53e4ea4cTakashi Iwai if (dev_priv->backlight_enabled) 255f52c619a590fa75276c07dfcaf380dee53e4ea4cTakashi Iwai intel_panel_actually_set_backlight(dev, level); 256f52c619a590fa75276c07dfcaf380dee53e4ea4cTakashi Iwai} 257f52c619a590fa75276c07dfcaf380dee53e4ea4cTakashi Iwai 258f52c619a590fa75276c07dfcaf380dee53e4ea4cTakashi Iwaivoid intel_panel_disable_backlight(struct drm_device *dev) 259f52c619a590fa75276c07dfcaf380dee53e4ea4cTakashi Iwai{ 260f52c619a590fa75276c07dfcaf380dee53e4ea4cTakashi Iwai struct drm_i915_private *dev_priv = dev->dev_private; 26147356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson 262f52c619a590fa75276c07dfcaf380dee53e4ea4cTakashi Iwai dev_priv->backlight_enabled = false; 263f52c619a590fa75276c07dfcaf380dee53e4ea4cTakashi Iwai intel_panel_actually_set_backlight(dev, 0); 26447356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson} 26547356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson 26647356eb67285014527a5ab87543ba1fae3d1e10aChris Wilsonvoid intel_panel_enable_backlight(struct drm_device *dev) 26747356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson{ 26847356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson struct drm_i915_private *dev_priv = dev->dev_private; 26947356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson 27047356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson if (dev_priv->backlight_level == 0) 27147356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson dev_priv->backlight_level = intel_panel_get_max_backlight(dev); 27247356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson 27347356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson dev_priv->backlight_enabled = true; 274f52c619a590fa75276c07dfcaf380dee53e4ea4cTakashi Iwai intel_panel_actually_set_backlight(dev, dev_priv->backlight_level); 27547356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson} 27647356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson 277aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrettstatic void intel_panel_init_backlight(struct drm_device *dev) 27847356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson{ 27947356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson struct drm_i915_private *dev_priv = dev->dev_private; 28047356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson 281c8303e7f3f3093c16ef0fa5f73280637c89d4368Indan Zupancic dev_priv->backlight_level = intel_panel_get_backlight(dev); 28247356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson dev_priv->backlight_enabled = dev_priv->backlight_level != 0; 28347356eb67285014527a5ab87543ba1fae3d1e10aChris Wilson} 284fe16d949b45036d9f80e20e07bde1ddacc930b10Chris Wilson 285fe16d949b45036d9f80e20e07bde1ddacc930b10Chris Wilsonenum drm_connector_status 286fe16d949b45036d9f80e20e07bde1ddacc930b10Chris Wilsonintel_panel_detect(struct drm_device *dev) 287fe16d949b45036d9f80e20e07bde1ddacc930b10Chris Wilson{ 288bcd5023c961a44c7149936553b6929b2b233dd27Dave Airlie#if 0 289fe16d949b45036d9f80e20e07bde1ddacc930b10Chris Wilson struct drm_i915_private *dev_priv = dev->dev_private; 290bcd5023c961a44c7149936553b6929b2b233dd27Dave Airlie#endif 291fe16d949b45036d9f80e20e07bde1ddacc930b10Chris Wilson 292fca874092597ef946b8f07031d8c31c58b212144Chris Wilson if (i915_panel_ignore_lid) 293fca874092597ef946b8f07031d8c31c58b212144Chris Wilson return i915_panel_ignore_lid > 0 ? 294fca874092597ef946b8f07031d8c31c58b212144Chris Wilson connector_status_connected : 295fca874092597ef946b8f07031d8c31c58b212144Chris Wilson connector_status_disconnected; 296fca874092597ef946b8f07031d8c31c58b212144Chris Wilson 297bcd5023c961a44c7149936553b6929b2b233dd27Dave Airlie /* opregion lid state on HP 2540p is wrong at boot up, 298bcd5023c961a44c7149936553b6929b2b233dd27Dave Airlie * appears to be either the BIOS or Linux ACPI fault */ 299bcd5023c961a44c7149936553b6929b2b233dd27Dave Airlie#if 0 300fe16d949b45036d9f80e20e07bde1ddacc930b10Chris Wilson /* Assume that the BIOS does not lie through the OpRegion... */ 301fe16d949b45036d9f80e20e07bde1ddacc930b10Chris Wilson if (dev_priv->opregion.lid_state) 302fe16d949b45036d9f80e20e07bde1ddacc930b10Chris Wilson return ioread32(dev_priv->opregion.lid_state) & 0x1 ? 303fe16d949b45036d9f80e20e07bde1ddacc930b10Chris Wilson connector_status_connected : 304fe16d949b45036d9f80e20e07bde1ddacc930b10Chris Wilson connector_status_disconnected; 305bcd5023c961a44c7149936553b6929b2b233dd27Dave Airlie#endif 306fe16d949b45036d9f80e20e07bde1ddacc930b10Chris Wilson 307fe16d949b45036d9f80e20e07bde1ddacc930b10Chris Wilson return connector_status_unknown; 308fe16d949b45036d9f80e20e07bde1ddacc930b10Chris Wilson} 309aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett 310aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE 311aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrettstatic int intel_panel_update_status(struct backlight_device *bd) 312aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett{ 313aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett struct drm_device *dev = bl_get_data(bd); 314aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett intel_panel_set_backlight(dev, bd->props.brightness); 315aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett return 0; 316aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett} 317aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett 318aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrettstatic int intel_panel_get_brightness(struct backlight_device *bd) 319aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett{ 320aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett struct drm_device *dev = bl_get_data(bd); 32104b38670cf46c096705f24e92a8747d1ab89e53cTakashi Iwai struct drm_i915_private *dev_priv = dev->dev_private; 32204b38670cf46c096705f24e92a8747d1ab89e53cTakashi Iwai return dev_priv->backlight_level; 323aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett} 324aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett 325aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrettstatic const struct backlight_ops intel_panel_bl_ops = { 326aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett .update_status = intel_panel_update_status, 327aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett .get_brightness = intel_panel_get_brightness, 328aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett}; 329aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett 330aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrettint intel_panel_setup_backlight(struct drm_device *dev) 331aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett{ 332aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett struct drm_i915_private *dev_priv = dev->dev_private; 333aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett struct backlight_properties props; 334aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett struct drm_connector *connector; 335aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett 336aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett intel_panel_init_backlight(dev); 337aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett 338aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett if (dev_priv->int_lvds_connector) 339aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett connector = dev_priv->int_lvds_connector; 340aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett else if (dev_priv->int_edp_connector) 341aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett connector = dev_priv->int_edp_connector; 342aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett else 343aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett return -ENODEV; 344aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett 345aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett props.type = BACKLIGHT_RAW; 346aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett props.max_brightness = intel_panel_get_max_backlight(dev); 347aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett dev_priv->backlight = 348aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett backlight_device_register("intel_backlight", 349aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett &connector->kdev, dev, 350aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett &intel_panel_bl_ops, &props); 351aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett 352aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett if (IS_ERR(dev_priv->backlight)) { 353aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett DRM_ERROR("Failed to register backlight: %ld\n", 354aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett PTR_ERR(dev_priv->backlight)); 355aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett dev_priv->backlight = NULL; 356aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett return -ENODEV; 357aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett } 358aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett dev_priv->backlight->props.brightness = intel_panel_get_backlight(dev); 359aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett return 0; 360aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett} 361aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett 362aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrettvoid intel_panel_destroy_backlight(struct drm_device *dev) 363aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett{ 364aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett struct drm_i915_private *dev_priv = dev->dev_private; 365aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett if (dev_priv->backlight) 366aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett backlight_device_unregister(dev_priv->backlight); 367aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett} 368aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett#else 369aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrettint intel_panel_setup_backlight(struct drm_device *dev) 370aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett{ 371aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett intel_panel_init_backlight(dev); 372aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett return 0; 373aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett} 374aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett 375aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrettvoid intel_panel_destroy_backlight(struct drm_device *dev) 376aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett{ 377aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett return; 378aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett} 379aaa6fd2a004147bf32fce05720938236de3361d9Matthew Garrett#endif 380