16a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox/* 26a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * Copyright © 2006-2011 Intel Corporation 36a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * 46a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * This program is free software; you can redistribute it and/or modify it 56a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * under the terms and conditions of the GNU General Public License, 66a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * version 2, as published by the Free Software Foundation. 76a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * 86a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * This program is distributed in the hope it will be useful, but WITHOUT 96a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 106a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 116a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * more details. 126a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * 136a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * You should have received a copy of the GNU General Public License along with 146a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * this program; if not, write to the Free Software Foundation, Inc., 156a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 166a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * 176a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * Authors: 186a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * Eric Anholt <eric@anholt.net> 196a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * Dave Airlie <airlied@linux.ie> 206a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * Jesse Barnes <jesse.barnes@intel.com> 216a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 226a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 236a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#include <linux/i2c.h> 246a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#include <linux/dmi.h> 256a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#include <drm/drmP.h> 266a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 276a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#include "intel_bios.h" 286a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#include "psb_drv.h" 296a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#include "psb_intel_drv.h" 306a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#include "psb_intel_reg.h" 316a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#include "power.h" 326a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#include <linux/pm_runtime.h> 336a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#include "cdv_device.h" 346a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 356a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox/** 366a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * LVDS I2C backlight control macros 376a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 386a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define BRIGHTNESS_MAX_LEVEL 100 396a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define BRIGHTNESS_MASK 0xFF 406a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define BLC_I2C_TYPE 0x01 416a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define BLC_PWM_TYPT 0x02 426a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 436a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define BLC_POLARITY_NORMAL 0 446a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define BLC_POLARITY_INVERSE 1 456a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 466a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define PSB_BLC_MAX_PWM_REG_FREQ (0xFFFE) 476a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define PSB_BLC_MIN_PWM_REG_FREQ (0x2) 486a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define PSB_BLC_PWM_PRECISION_FACTOR (10) 496a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define PSB_BACKLIGHT_PWM_CTL_SHIFT (16) 506a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) 516a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 526a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstruct cdv_intel_lvds_priv { 536a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox /** 546a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * Saved LVDO output states 556a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 566a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox uint32_t savePP_ON; 576a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox uint32_t savePP_OFF; 586a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox uint32_t saveLVDS; 596a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox uint32_t savePP_CONTROL; 606a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox uint32_t savePP_CYCLE; 616a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox uint32_t savePFIT_CONTROL; 626a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox uint32_t savePFIT_PGM_RATIOS; 636a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox uint32_t saveBLC_PWM_CTL; 646a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox}; 656a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 666a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox/* 676a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * Returns the maximum level of the backlight duty cycle field. 686a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 696a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic u32 cdv_intel_lvds_get_max_backlight(struct drm_device *dev) 706a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{ 716a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_psb_private *dev_priv = dev->dev_private; 726a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox u32 retval; 736a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 746a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (gma_power_begin(dev, false)) { 756a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox retval = ((REG_READ(BLC_PWM_CTL) & 766a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox BACKLIGHT_MODULATION_FREQ_MASK) >> 776a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; 786a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 796a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox gma_power_end(dev); 806a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } else 81648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox retval = ((dev_priv->regs.saveBLC_PWM_CTL & 826a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox BACKLIGHT_MODULATION_FREQ_MASK) >> 836a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; 846a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 856a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return retval; 866a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox} 876a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 88062d054eb359bf143fdd61c8c8837b4d6fd8a10cKirill A. Shutemov#if 0 896a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox/* 906a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * Set LVDS backlight level by I2C command 916a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 926a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic int cdv_lvds_i2c_set_brightness(struct drm_device *dev, 936a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox unsigned int level) 946a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{ 956a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_psb_private *dev_priv = dev->dev_private; 966a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct psb_intel_i2c_chan *lvds_i2c_bus = dev_priv->lvds_i2c_bus; 976a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox u8 out_buf[2]; 986a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox unsigned int blc_i2c_brightness; 996a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1006a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct i2c_msg msgs[] = { 1016a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox { 1026a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox .addr = lvds_i2c_bus->slave_addr, 1036a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox .flags = 0, 1046a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox .len = 2, 1056a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox .buf = out_buf, 1066a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 1076a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox }; 1086a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1096a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox blc_i2c_brightness = BRIGHTNESS_MASK & ((unsigned int)level * 1106a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox BRIGHTNESS_MASK / 1116a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox BRIGHTNESS_MAX_LEVEL); 1126a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1136a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (dev_priv->lvds_bl->pol == BLC_POLARITY_INVERSE) 1146a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox blc_i2c_brightness = BRIGHTNESS_MASK - blc_i2c_brightness; 1156a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1166a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox out_buf[0] = dev_priv->lvds_bl->brightnesscmd; 1176a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox out_buf[1] = (u8)blc_i2c_brightness; 1186a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1196a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (i2c_transfer(&lvds_i2c_bus->adapter, msgs, 1) == 1) 1206a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return 0; 1216a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1226a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox DRM_ERROR("I2C transfer error\n"); 1236a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return -1; 1246a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox} 1256a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1266a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1276a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic int cdv_lvds_pwm_set_brightness(struct drm_device *dev, int level) 1286a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{ 1296a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_psb_private *dev_priv = dev->dev_private; 1306a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1316a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox u32 max_pwm_blc; 1326a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox u32 blc_pwm_duty_cycle; 1336a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1346a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox max_pwm_blc = cdv_intel_lvds_get_max_backlight(dev); 1356a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1366a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox /*BLC_PWM_CTL Should be initiated while backlight device init*/ 1376a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox BUG_ON((max_pwm_blc & PSB_BLC_MAX_PWM_REG_FREQ) == 0); 1386a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1396a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox blc_pwm_duty_cycle = level * max_pwm_blc / BRIGHTNESS_MAX_LEVEL; 1406a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1416a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (dev_priv->lvds_bl->pol == BLC_POLARITY_INVERSE) 1426a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox blc_pwm_duty_cycle = max_pwm_blc - blc_pwm_duty_cycle; 1436a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1446a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox blc_pwm_duty_cycle &= PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR; 1456a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox REG_WRITE(BLC_PWM_CTL, 1466a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox (max_pwm_blc << PSB_BACKLIGHT_PWM_CTL_SHIFT) | 1476a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox (blc_pwm_duty_cycle)); 1486a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1496a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return 0; 1506a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox} 1516a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1526a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox/* 1536a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * Set LVDS backlight level either by I2C or PWM 1546a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 1556a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxvoid cdv_intel_lvds_set_brightness(struct drm_device *dev, int level) 1566a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{ 1576a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_psb_private *dev_priv = dev->dev_private; 1586a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1596a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (!dev_priv->lvds_bl) { 1606a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox DRM_ERROR("NO LVDS Backlight Info\n"); 1616a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return; 1626a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 1636a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1646a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (dev_priv->lvds_bl->type == BLC_I2C_TYPE) 1656a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox cdv_lvds_i2c_set_brightness(dev, level); 1666a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox else 1676a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox cdv_lvds_pwm_set_brightness(dev, level); 1686a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox} 169062d054eb359bf143fdd61c8c8837b4d6fd8a10cKirill A. Shutemov#endif 1706a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1716a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox/** 1726a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * Sets the backlight level. 1736a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * 1746a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * level backlight level, from 0 to cdv_intel_lvds_get_max_backlight(). 1756a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 1766a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic void cdv_intel_lvds_set_backlight(struct drm_device *dev, int level) 1776a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{ 1786a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_psb_private *dev_priv = dev->dev_private; 1796a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox u32 blc_pwm_ctl; 1806a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1816a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (gma_power_begin(dev, false)) { 1826a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox blc_pwm_ctl = 1836a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox REG_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; 1846a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox REG_WRITE(BLC_PWM_CTL, 1856a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox (blc_pwm_ctl | 1866a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox (level << BACKLIGHT_DUTY_CYCLE_SHIFT))); 1876a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox gma_power_end(dev); 1886a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } else { 189648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox blc_pwm_ctl = dev_priv->regs.saveBLC_PWM_CTL & 1906a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox ~BACKLIGHT_DUTY_CYCLE_MASK; 191648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox dev_priv->regs.saveBLC_PWM_CTL = (blc_pwm_ctl | 1926a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox (level << BACKLIGHT_DUTY_CYCLE_SHIFT)); 1936a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 1946a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox} 1956a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 1966a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox/** 1976a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * Sets the power state for the panel. 1986a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 1996a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic void cdv_intel_lvds_set_power(struct drm_device *dev, 200a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson struct drm_encoder *encoder, bool on) 2016a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{ 202a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson struct drm_psb_private *dev_priv = dev->dev_private; 2036a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox u32 pp_status; 2046a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 2056a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (!gma_power_begin(dev, true)) 2066a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return; 2076a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 2086a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (on) { 2096a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) | 2106a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox POWER_TARGET_ON); 2116a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox do { 2126a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox pp_status = REG_READ(PP_STATUS); 2136a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } while ((pp_status & PP_ON) == 0); 2146a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 2156a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox cdv_intel_lvds_set_backlight(dev, 216a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson dev_priv->mode_dev.backlight_duty_cycle); 2176a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } else { 2186a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox cdv_intel_lvds_set_backlight(dev, 0); 2196a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 2206a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) & 2216a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox ~POWER_TARGET_ON); 2226a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox do { 2236a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox pp_status = REG_READ(PP_STATUS); 2246a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } while (pp_status & PP_ON); 2256a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 2266a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox gma_power_end(dev); 2276a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox} 2286a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 2296a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic void cdv_intel_lvds_encoder_dpms(struct drm_encoder *encoder, int mode) 2306a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{ 2316a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_device *dev = encoder->dev; 2326a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (mode == DRM_MODE_DPMS_ON) 233a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson cdv_intel_lvds_set_power(dev, encoder, true); 2346a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox else 235a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson cdv_intel_lvds_set_power(dev, encoder, false); 2366a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox /* XXX: We never power down the LVDS pairs. */ 2376a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox} 2386a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 2396a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic void cdv_intel_lvds_save(struct drm_connector *connector) 2406a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{ 2416a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox} 2426a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 2436a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic void cdv_intel_lvds_restore(struct drm_connector *connector) 2446a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{ 2456a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox} 2466a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 247bc11da70aca65283e62e8a4bdccc11c3324ccf97Kirill A. Shutemovstatic int cdv_intel_lvds_mode_valid(struct drm_connector *connector, 248a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson struct drm_display_mode *mode) 2496a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{ 250a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson struct drm_device *dev = connector->dev; 251a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson struct drm_psb_private *dev_priv = dev->dev_private; 2526a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_display_mode *fixed_mode = 253a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson dev_priv->mode_dev.panel_fixed_mode; 2546a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 2556a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox /* just in case */ 2566a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 2576a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return MODE_NO_DBLESCAN; 2586a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 2596a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox /* just in case */ 2606a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (mode->flags & DRM_MODE_FLAG_INTERLACE) 2616a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return MODE_NO_INTERLACE; 2626a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 2636a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (fixed_mode) { 2646a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (mode->hdisplay > fixed_mode->hdisplay) 2656a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return MODE_PANEL; 2666a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (mode->vdisplay > fixed_mode->vdisplay) 2676a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return MODE_PANEL; 2686a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 2696a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return MODE_OK; 2706a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox} 2716a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 272bc11da70aca65283e62e8a4bdccc11c3324ccf97Kirill A. Shutemovstatic bool cdv_intel_lvds_mode_fixup(struct drm_encoder *encoder, 2736a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_display_mode *mode, 2746a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_display_mode *adjusted_mode) 2756a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{ 2766a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_device *dev = encoder->dev; 277a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson struct drm_psb_private *dev_priv = dev->dev_private; 278a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; 2796a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_encoder *tmp_encoder; 2806a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_display_mode *panel_fixed_mode = mode_dev->panel_fixed_mode; 2816a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 2826a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox /* Should never happen!! */ 2836a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list, 2846a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox head) { 2856a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (tmp_encoder != encoder 2866a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox && tmp_encoder->crtc == encoder->crtc) { 2876a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox printk(KERN_ERR "Can't enable LVDS and another " 2886a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox "encoder on the same pipe\n"); 2896a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return false; 2906a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 2916a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 2926a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 2936a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox /* 2946a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * If we have timings from the BIOS for the panel, put them in 2956a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * to the adjusted mode. The CRTC will be set up for this mode, 2966a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * with the panel scaling set up to source from the H/VDisplay 2976a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * of the original mode. 2986a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 2996a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (panel_fixed_mode != NULL) { 3006a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox adjusted_mode->hdisplay = panel_fixed_mode->hdisplay; 3016a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox adjusted_mode->hsync_start = panel_fixed_mode->hsync_start; 3026a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox adjusted_mode->hsync_end = panel_fixed_mode->hsync_end; 3036a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox adjusted_mode->htotal = panel_fixed_mode->htotal; 3046a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox adjusted_mode->vdisplay = panel_fixed_mode->vdisplay; 3056a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox adjusted_mode->vsync_start = panel_fixed_mode->vsync_start; 3066a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox adjusted_mode->vsync_end = panel_fixed_mode->vsync_end; 3076a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox adjusted_mode->vtotal = panel_fixed_mode->vtotal; 3086a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox adjusted_mode->clock = panel_fixed_mode->clock; 3096a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox drm_mode_set_crtcinfo(adjusted_mode, 3106a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox CRTC_INTERLACE_HALVE_V); 3116a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 3126a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 3136a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox /* 3146a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * XXX: It would be nice to support lower refresh rates on the 3156a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * panels to reduce power consumption, and perhaps match the 3166a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * user's requested refresh rate. 3176a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 3186a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 3196a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return true; 3206a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox} 3216a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 3226a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic void cdv_intel_lvds_prepare(struct drm_encoder *encoder) 3236a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{ 3246a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_device *dev = encoder->dev; 325a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson struct drm_psb_private *dev_priv = dev->dev_private; 326a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; 3276a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 3286a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (!gma_power_begin(dev, true)) 3296a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return; 3306a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 3316a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox mode_dev->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL); 3326a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox mode_dev->backlight_duty_cycle = (mode_dev->saveBLC_PWM_CTL & 3336a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox BACKLIGHT_DUTY_CYCLE_MASK); 3346a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 335a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson cdv_intel_lvds_set_power(dev, encoder, false); 3366a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 3376a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox gma_power_end(dev); 3386a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox} 3396a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 3406a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic void cdv_intel_lvds_commit(struct drm_encoder *encoder) 3416a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{ 3426a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_device *dev = encoder->dev; 343a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson struct drm_psb_private *dev_priv = dev->dev_private; 344a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; 3456a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 3466a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (mode_dev->backlight_duty_cycle == 0) 3476a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox mode_dev->backlight_duty_cycle = 3486a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox cdv_intel_lvds_get_max_backlight(dev); 3496a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 350a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson cdv_intel_lvds_set_power(dev, encoder, true); 3516a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox} 3526a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 3536a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic void cdv_intel_lvds_mode_set(struct drm_encoder *encoder, 3546a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_display_mode *mode, 3556a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_display_mode *adjusted_mode) 3566a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{ 3576a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_device *dev = encoder->dev; 3586a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_psb_private *dev_priv = dev->dev_private; 3596a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox u32 pfit_control; 3606a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 3616a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox /* 3626a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * The LVDS pin pair will already have been turned on in the 3636a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * cdv_intel_crtc_mode_set since it has a large impact on the DPLL 3646a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * settings. 3656a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 3666a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 3676a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox /* 3686a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * Enable automatic panel scaling so that non-native modes fill the 3696a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * screen. Should be enabled before the pipe is enabled, according to 3706a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * register description and PRM. 3716a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 3726a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (mode->hdisplay != adjusted_mode->hdisplay || 3736a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox mode->vdisplay != adjusted_mode->vdisplay) 3746a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE | 3756a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR | 3766a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox HORIZ_INTERP_BILINEAR); 3776a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox else 3786a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox pfit_control = 0; 3796a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 3806a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (dev_priv->lvds_dither) 3816a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox pfit_control |= PANEL_8TO6_DITHER_ENABLE; 3826a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 3836a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox REG_WRITE(PFIT_CONTROL, pfit_control); 3846a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox} 3856a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 3866a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox/** 3876a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * Detect the LVDS connection. 3886a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * 3896a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * This always returns CONNECTOR_STATUS_CONNECTED. 3906a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * This connector should only have 3916a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * been set up if the LVDS was actually connected anyway. 3926a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 3936a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic enum drm_connector_status cdv_intel_lvds_detect( 3946a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_connector *connector, bool force) 3956a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{ 3966a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return connector_status_connected; 3976a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox} 3986a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 3996a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox/** 4006a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * Return the list of DDC modes if available, or the BIOS fixed mode otherwise. 4016a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 4026a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic int cdv_intel_lvds_get_modes(struct drm_connector *connector) 4036a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{ 4046a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_device *dev = connector->dev; 405a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson struct drm_psb_private *dev_priv = dev->dev_private; 406a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson struct psb_intel_encoder *psb_intel_encoder = 407a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson psb_intel_attached_encoder(connector); 408a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; 4096a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox int ret; 4106a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 411a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson ret = psb_intel_ddc_get_modes(connector, &psb_intel_encoder->i2c_bus->adapter); 4126a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 4136a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (ret) 4146a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return ret; 4156a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 4166a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox /* Didn't get an EDID, so 4176a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * Set wide sync ranges so we get all modes 4186a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * handed to valid_mode for checking 4196a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 4206a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox connector->display_info.min_vfreq = 0; 4216a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox connector->display_info.max_vfreq = 200; 4226a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox connector->display_info.min_hfreq = 0; 4236a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox connector->display_info.max_hfreq = 200; 4246a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (mode_dev->panel_fixed_mode != NULL) { 4256a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_display_mode *mode = 4266a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox drm_mode_duplicate(dev, mode_dev->panel_fixed_mode); 4276a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox drm_mode_probed_add(connector, mode); 4286a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return 1; 4296a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 4306a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 4316a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return 0; 4326a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox} 4336a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 4346a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox/** 4356a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * cdv_intel_lvds_destroy - unregister and free LVDS structures 4366a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * @connector: connector to free 4376a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * 4386a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * Unregister the DDC bus for this connector then free the driver private 4396a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * structure. 4406a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 441bc11da70aca65283e62e8a4bdccc11c3324ccf97Kirill A. Shutemovstatic void cdv_intel_lvds_destroy(struct drm_connector *connector) 4426a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{ 443a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson struct psb_intel_encoder *psb_intel_encoder = 444a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson psb_intel_attached_encoder(connector); 4456a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 446a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson if (psb_intel_encoder->i2c_bus) 447a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson psb_intel_i2c_destroy(psb_intel_encoder->i2c_bus); 4486a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox drm_sysfs_connector_remove(connector); 4496a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox drm_connector_cleanup(connector); 4506a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox kfree(connector); 4516a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox} 4526a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 453bc11da70aca65283e62e8a4bdccc11c3324ccf97Kirill A. Shutemovstatic int cdv_intel_lvds_set_property(struct drm_connector *connector, 4546a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_property *property, 4556a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox uint64_t value) 4566a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{ 4576a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_encoder *encoder = connector->encoder; 4586a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 4596a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (!strcmp(property->name, "scaling mode") && encoder) { 4606a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct psb_intel_crtc *crtc = 4616a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox to_psb_intel_crtc(encoder->crtc); 4626a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox uint64_t curValue; 4636a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 4646a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (!crtc) 4656a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return -1; 4666a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 4676a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox switch (value) { 4686a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox case DRM_MODE_SCALE_FULLSCREEN: 4696a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox break; 4706a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox case DRM_MODE_SCALE_NO_SCALE: 4716a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox break; 4726a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox case DRM_MODE_SCALE_ASPECT: 4736a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox break; 4746a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox default: 4756a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return -1; 4766a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 4776a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 4786a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (drm_connector_property_get_value(connector, 4796a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox property, 4806a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox &curValue)) 4816a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return -1; 4826a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 4836a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (curValue == value) 4846a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return 0; 4856a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 4866a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (drm_connector_property_set_value(connector, 4876a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox property, 4886a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox value)) 4896a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return -1; 4906a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 4916a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (crtc->saved_mode.hdisplay != 0 && 4926a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox crtc->saved_mode.vdisplay != 0) { 4936a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (!drm_crtc_helper_set_mode(encoder->crtc, 4946a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox &crtc->saved_mode, 4956a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox encoder->crtc->x, 4966a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox encoder->crtc->y, 4976a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox encoder->crtc->fb)) 4986a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return -1; 4996a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 5006a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } else if (!strcmp(property->name, "backlight") && encoder) { 5016a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (drm_connector_property_set_value(connector, 5026a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox property, 5036a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox value)) 5046a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return -1; 5056a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox else { 5066a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE 5076a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_psb_private *dev_priv = 5086a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox encoder->dev->dev_private; 5096a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct backlight_device *bd = 5106a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox dev_priv->backlight_device; 5116a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox bd->props.brightness = value; 5126a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox backlight_update_status(bd); 5136a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#endif 5146a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 5156a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } else if (!strcmp(property->name, "DPMS") && encoder) { 5166a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_encoder_helper_funcs *helpers = 5176a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox encoder->helper_private; 5186a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox helpers->dpms(encoder, value); 5196a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 5206a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return 0; 5216a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox} 5226a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 5236a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic const struct drm_encoder_helper_funcs 5246a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox cdv_intel_lvds_helper_funcs = { 5256a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox .dpms = cdv_intel_lvds_encoder_dpms, 5266a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox .mode_fixup = cdv_intel_lvds_mode_fixup, 5276a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox .prepare = cdv_intel_lvds_prepare, 5286a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox .mode_set = cdv_intel_lvds_mode_set, 5296a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox .commit = cdv_intel_lvds_commit, 5306a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox}; 5316a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 5326a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic const struct drm_connector_helper_funcs 5336a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox cdv_intel_lvds_connector_helper_funcs = { 5346a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox .get_modes = cdv_intel_lvds_get_modes, 5356a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox .mode_valid = cdv_intel_lvds_mode_valid, 5366a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox .best_encoder = psb_intel_best_encoder, 5376a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox}; 5386a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 5396a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic const struct drm_connector_funcs cdv_intel_lvds_connector_funcs = { 5406a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox .dpms = drm_helper_connector_dpms, 5416a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox .save = cdv_intel_lvds_save, 5426a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox .restore = cdv_intel_lvds_restore, 5436a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox .detect = cdv_intel_lvds_detect, 5446a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox .fill_modes = drm_helper_probe_single_connector_modes, 5456a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox .set_property = cdv_intel_lvds_set_property, 5466a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox .destroy = cdv_intel_lvds_destroy, 5476a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox}; 5486a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 5496a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 5506a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic void cdv_intel_lvds_enc_destroy(struct drm_encoder *encoder) 5516a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{ 5526a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox drm_encoder_cleanup(encoder); 5536a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox} 5546a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 5556a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxconst struct drm_encoder_funcs cdv_intel_lvds_enc_funcs = { 5566a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox .destroy = cdv_intel_lvds_enc_destroy, 5576a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox}; 5586a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 5596a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox/** 5606a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * cdv_intel_lvds_init - setup LVDS connectors on this device 5616a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * @dev: drm device 5626a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * 5636a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * Create the connector, register the LVDS DDC bus, and try to figure out what 5646a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * modes we can display on the LVDS panel (if present). 5656a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 5666a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxvoid cdv_intel_lvds_init(struct drm_device *dev, 5676a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct psb_intel_mode_device *mode_dev) 5686a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{ 569a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson struct psb_intel_encoder *psb_intel_encoder; 570a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson struct psb_intel_connector *psb_intel_connector; 5716a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct cdv_intel_lvds_priv *lvds_priv; 5726a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_connector *connector; 5736a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_encoder *encoder; 5746a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_display_mode *scan; 5756a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_crtc *crtc; 5766a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox struct drm_psb_private *dev_priv = dev->dev_private; 5776a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox u32 lvds; 5786a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox int pipe; 5796a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 580a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder), 581a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson GFP_KERNEL); 582a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson if (!psb_intel_encoder) 5836a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return; 5846a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 585a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson psb_intel_connector = kzalloc(sizeof(struct psb_intel_connector), 586a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson GFP_KERNEL); 587a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson if (!psb_intel_connector) 588a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson goto failed_connector; 5896a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 590a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson lvds_priv = kzalloc(sizeof(struct cdv_intel_lvds_priv), GFP_KERNEL); 591a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson if (!lvds_priv) 592a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson goto failed_lvds_priv; 5936a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 594a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson psb_intel_encoder->dev_priv = lvds_priv; 5956a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 596a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson connector = &psb_intel_connector->base; 597a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson encoder = &psb_intel_encoder->base; 5986a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 599a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson 600a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson drm_connector_init(dev, connector, 6016a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox &cdv_intel_lvds_connector_funcs, 6026a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox DRM_MODE_CONNECTOR_LVDS); 6036a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 604a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson drm_encoder_init(dev, encoder, 6056a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox &cdv_intel_lvds_enc_funcs, 6066a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox DRM_MODE_ENCODER_LVDS); 6076a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 6086a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 609a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson psb_intel_connector_attach_encoder(psb_intel_connector, 610a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson psb_intel_encoder); 611a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson psb_intel_encoder->type = INTEL_OUTPUT_LVDS; 6126a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 6136a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox drm_encoder_helper_add(encoder, &cdv_intel_lvds_helper_funcs); 6146a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox drm_connector_helper_add(connector, 6156a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox &cdv_intel_lvds_connector_helper_funcs); 6166a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox connector->display_info.subpixel_order = SubPixelHorizontalRGB; 6176a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox connector->interlace_allowed = false; 6186a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox connector->doublescan_allowed = false; 6196a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 6206a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox /*Attach connector properties*/ 6216a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox drm_connector_attach_property(connector, 6226a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox dev->mode_config.scaling_mode_property, 6236a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox DRM_MODE_SCALE_FULLSCREEN); 6246a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox drm_connector_attach_property(connector, 6256a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox dev_priv->backlight_property, 6266a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox BRIGHTNESS_MAX_LEVEL); 6276a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 6286a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox /** 6296a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * Set up I2C bus 6306a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * FIXME: distroy i2c_bus when exit 6316a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 632a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson psb_intel_encoder->i2c_bus = psb_intel_i2c_create(dev, 6336a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox GPIOB, 6346a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox "LVDSBLC_B"); 635a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson if (!psb_intel_encoder->i2c_bus) { 6366a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox dev_printk(KERN_ERR, 6376a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox &dev->pdev->dev, "I2C bus registration failed.\n"); 6386a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox goto failed_blc_i2c; 6396a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 640a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson psb_intel_encoder->i2c_bus->slave_addr = 0x2C; 641a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson dev_priv->lvds_i2c_bus = psb_intel_encoder->i2c_bus; 6426a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 6436a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox /* 6446a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * LVDS discovery: 6456a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * 1) check for EDID on DDC 6466a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * 2) check for VBT data 6476a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * 3) check to see if LVDS is already on 6486a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * if none of the above, no panel 6496a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * 4) make sure lid is open 6506a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * if closed, act like it's not there for now 6516a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 6526a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 6536a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox /* Set up the DDC bus. */ 654a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson psb_intel_encoder->ddc_bus = psb_intel_i2c_create(dev, 6556a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox GPIOC, 6566a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox "LVDSDDC_C"); 657a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson if (!psb_intel_encoder->ddc_bus) { 6586a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox dev_printk(KERN_ERR, &dev->pdev->dev, 6596a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox "DDC bus registration " "failed.\n"); 6606a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox goto failed_ddc; 6616a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 6626a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 6636a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox /* 6646a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * Attempt to get the fixed panel mode from DDC. Assume that the 6656a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * preferred mode is the right one. 6666a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 667a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson psb_intel_ddc_get_modes(connector, 668a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson &psb_intel_encoder->ddc_bus->adapter); 6696a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox list_for_each_entry(scan, &connector->probed_modes, head) { 6706a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (scan->type & DRM_MODE_TYPE_PREFERRED) { 6716a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox mode_dev->panel_fixed_mode = 6726a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox drm_mode_duplicate(dev, scan); 6736a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox goto out; /* FIXME: check for quirks */ 6746a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 6756a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 6766a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 6776a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox /* Failed to get EDID, what about VBT? do we need this?*/ 6786a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (dev_priv->lfp_lvds_vbt_mode) { 6796a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox mode_dev->panel_fixed_mode = 6806a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); 6816a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (mode_dev->panel_fixed_mode) { 6826a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox mode_dev->panel_fixed_mode->type |= 6836a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox DRM_MODE_TYPE_PREFERRED; 6846a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox goto out; /* FIXME: check for quirks */ 6856a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 6866a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 6876a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox /* 6886a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * If we didn't get EDID, try checking if the panel is already turned 6896a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * on. If so, assume that whatever is currently programmed is the 6906a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * correct mode. 6916a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */ 6926a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox lvds = REG_READ(LVDS); 6936a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; 6946a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox crtc = psb_intel_get_crtc_from_pipe(dev, pipe); 6956a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 6966a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (crtc && (lvds & LVDS_PORT_EN)) { 6976a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox mode_dev->panel_fixed_mode = 6986a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox cdv_intel_crtc_mode_get(dev, crtc); 6996a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (mode_dev->panel_fixed_mode) { 7006a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox mode_dev->panel_fixed_mode->type |= 7016a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox DRM_MODE_TYPE_PREFERRED; 7026a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox goto out; /* FIXME: check for quirks */ 7036a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 7046a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 7056a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 7066a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox /* If we still don't have a mode after all that, give up. */ 7076a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox if (!mode_dev->panel_fixed_mode) { 7086a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox DRM_DEBUG 7096a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox ("Found no modes on the lvds, ignoring the LVDS\n"); 7106a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox goto failed_find; 7116a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox } 7126a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 7136a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxout: 7146a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox drm_sysfs_connector_add(connector); 7156a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox return; 7166a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox 7176a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxfailed_find: 7186a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox printk(KERN_ERR "Failed find\n"); 719a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson if (psb_intel_encoder->ddc_bus) 720a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson psb_intel_i2c_destroy(psb_intel_encoder->ddc_bus); 7216a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxfailed_ddc: 7226a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox printk(KERN_ERR "Failed DDC\n"); 723a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson if (psb_intel_encoder->i2c_bus) 724a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson psb_intel_i2c_destroy(psb_intel_encoder->i2c_bus); 7256a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxfailed_blc_i2c: 7266a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox printk(KERN_ERR "Failed BLC\n"); 7276a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox drm_encoder_cleanup(encoder); 7286a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox drm_connector_cleanup(connector); 729a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson kfree(lvds_priv); 730a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobssonfailed_lvds_priv: 731a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson kfree(psb_intel_connector); 732a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobssonfailed_connector: 733a12d6a078e47e244a476b67c3f4b6ca03c138a99Patrik Jakobsson kfree(psb_intel_encoder); 7346a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox} 735