189c78134cc54dff016c83367912eb055637fa50cAlan Cox/* 289c78134cc54dff016c83367912eb055637fa50cAlan Cox * Copyright © 2006-2007 Intel Corporation 389c78134cc54dff016c83367912eb055637fa50cAlan Cox * 489c78134cc54dff016c83367912eb055637fa50cAlan Cox * This program is free software; you can redistribute it and/or modify it 589c78134cc54dff016c83367912eb055637fa50cAlan Cox * under the terms and conditions of the GNU General Public License, 689c78134cc54dff016c83367912eb055637fa50cAlan Cox * version 2, as published by the Free Software Foundation. 789c78134cc54dff016c83367912eb055637fa50cAlan Cox * 889c78134cc54dff016c83367912eb055637fa50cAlan Cox * This program is distributed in the hope it will be useful, but WITHOUT 989c78134cc54dff016c83367912eb055637fa50cAlan Cox * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1089c78134cc54dff016c83367912eb055637fa50cAlan Cox * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 1189c78134cc54dff016c83367912eb055637fa50cAlan Cox * more details. 1289c78134cc54dff016c83367912eb055637fa50cAlan Cox * 1389c78134cc54dff016c83367912eb055637fa50cAlan Cox * You should have received a copy of the GNU General Public License along with 1489c78134cc54dff016c83367912eb055637fa50cAlan Cox * this program; if not, write to the Free Software Foundation, Inc., 1589c78134cc54dff016c83367912eb055637fa50cAlan Cox * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 1689c78134cc54dff016c83367912eb055637fa50cAlan Cox * 1789c78134cc54dff016c83367912eb055637fa50cAlan Cox * Authors: 1889c78134cc54dff016c83367912eb055637fa50cAlan Cox * Eric Anholt <eric@anholt.net> 1989c78134cc54dff016c83367912eb055637fa50cAlan Cox * Dave Airlie <airlied@linux.ie> 2089c78134cc54dff016c83367912eb055637fa50cAlan Cox * Jesse Barnes <jesse.barnes@intel.com> 2189c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 2289c78134cc54dff016c83367912eb055637fa50cAlan Cox 2389c78134cc54dff016c83367912eb055637fa50cAlan Cox#include <linux/i2c.h> 2489c78134cc54dff016c83367912eb055637fa50cAlan Cox#include <drm/drmP.h> 2589c78134cc54dff016c83367912eb055637fa50cAlan Cox 2689c78134cc54dff016c83367912eb055637fa50cAlan Cox#include "intel_bios.h" 2789c78134cc54dff016c83367912eb055637fa50cAlan Cox#include "psb_drv.h" 2889c78134cc54dff016c83367912eb055637fa50cAlan Cox#include "psb_intel_drv.h" 2989c78134cc54dff016c83367912eb055637fa50cAlan Cox#include "psb_intel_reg.h" 3089c78134cc54dff016c83367912eb055637fa50cAlan Cox#include "power.h" 3189c78134cc54dff016c83367912eb055637fa50cAlan Cox#include <linux/pm_runtime.h> 3289c78134cc54dff016c83367912eb055637fa50cAlan Cox 3389c78134cc54dff016c83367912eb055637fa50cAlan Cox/* 3489c78134cc54dff016c83367912eb055637fa50cAlan Cox * LVDS I2C backlight control macros 3589c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 3689c78134cc54dff016c83367912eb055637fa50cAlan Cox#define BRIGHTNESS_MAX_LEVEL 100 3789c78134cc54dff016c83367912eb055637fa50cAlan Cox#define BRIGHTNESS_MASK 0xFF 3889c78134cc54dff016c83367912eb055637fa50cAlan Cox#define BLC_I2C_TYPE 0x01 3989c78134cc54dff016c83367912eb055637fa50cAlan Cox#define BLC_PWM_TYPT 0x02 4089c78134cc54dff016c83367912eb055637fa50cAlan Cox 4189c78134cc54dff016c83367912eb055637fa50cAlan Cox#define BLC_POLARITY_NORMAL 0 4289c78134cc54dff016c83367912eb055637fa50cAlan Cox#define BLC_POLARITY_INVERSE 1 4389c78134cc54dff016c83367912eb055637fa50cAlan Cox 4489c78134cc54dff016c83367912eb055637fa50cAlan Cox#define PSB_BLC_MAX_PWM_REG_FREQ (0xFFFE) 4589c78134cc54dff016c83367912eb055637fa50cAlan Cox#define PSB_BLC_MIN_PWM_REG_FREQ (0x2) 4689c78134cc54dff016c83367912eb055637fa50cAlan Cox#define PSB_BLC_PWM_PRECISION_FACTOR (10) 4789c78134cc54dff016c83367912eb055637fa50cAlan Cox#define PSB_BACKLIGHT_PWM_CTL_SHIFT (16) 4889c78134cc54dff016c83367912eb055637fa50cAlan Cox#define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) 4989c78134cc54dff016c83367912eb055637fa50cAlan Cox 5089c78134cc54dff016c83367912eb055637fa50cAlan Coxstruct psb_intel_lvds_priv { 5189c78134cc54dff016c83367912eb055637fa50cAlan Cox /* 5289c78134cc54dff016c83367912eb055637fa50cAlan Cox * Saved LVDO output states 5389c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 5489c78134cc54dff016c83367912eb055637fa50cAlan Cox uint32_t savePP_ON; 5589c78134cc54dff016c83367912eb055637fa50cAlan Cox uint32_t savePP_OFF; 5689c78134cc54dff016c83367912eb055637fa50cAlan Cox uint32_t saveLVDS; 5789c78134cc54dff016c83367912eb055637fa50cAlan Cox uint32_t savePP_CONTROL; 5889c78134cc54dff016c83367912eb055637fa50cAlan Cox uint32_t savePP_CYCLE; 5989c78134cc54dff016c83367912eb055637fa50cAlan Cox uint32_t savePFIT_CONTROL; 6089c78134cc54dff016c83367912eb055637fa50cAlan Cox uint32_t savePFIT_PGM_RATIOS; 6189c78134cc54dff016c83367912eb055637fa50cAlan Cox uint32_t saveBLC_PWM_CTL; 629c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson 639c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct psb_intel_i2c_chan *i2c_bus; 649c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct psb_intel_i2c_chan *ddc_bus; 6589c78134cc54dff016c83367912eb055637fa50cAlan Cox}; 6689c78134cc54dff016c83367912eb055637fa50cAlan Cox 6789c78134cc54dff016c83367912eb055637fa50cAlan Cox 6889c78134cc54dff016c83367912eb055637fa50cAlan Cox/* 6989c78134cc54dff016c83367912eb055637fa50cAlan Cox * Returns the maximum level of the backlight duty cycle field. 7089c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 7189c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic u32 psb_intel_lvds_get_max_backlight(struct drm_device *dev) 7289c78134cc54dff016c83367912eb055637fa50cAlan Cox{ 7389c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_psb_private *dev_priv = dev->dev_private; 741f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox u32 ret; 7589c78134cc54dff016c83367912eb055637fa50cAlan Cox 7689c78134cc54dff016c83367912eb055637fa50cAlan Cox if (gma_power_begin(dev, false)) { 771f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox ret = REG_READ(BLC_PWM_CTL); 7889c78134cc54dff016c83367912eb055637fa50cAlan Cox gma_power_end(dev); 791f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox } else /* Powered off, use the saved value */ 80648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox ret = dev_priv->regs.saveBLC_PWM_CTL; 811f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox 821f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox /* Top 15bits hold the frequency mask */ 831f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox ret = (ret & BACKLIGHT_MODULATION_FREQ_MASK) >> 841f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox BACKLIGHT_MODULATION_FREQ_SHIFT; 851f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox 861f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox ret *= 2; /* Return a 16bit range as needed for setting */ 871f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox if (ret == 0) 881f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox dev_err(dev->dev, "BL bug: Reg %08x save %08X\n", 89648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox REG_READ(BLC_PWM_CTL), dev_priv->regs.saveBLC_PWM_CTL); 901f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox return ret; 9189c78134cc54dff016c83367912eb055637fa50cAlan Cox} 9289c78134cc54dff016c83367912eb055637fa50cAlan Cox 9389c78134cc54dff016c83367912eb055637fa50cAlan Cox/* 9489c78134cc54dff016c83367912eb055637fa50cAlan Cox * Set LVDS backlight level by I2C command 9589c78134cc54dff016c83367912eb055637fa50cAlan Cox * 9689c78134cc54dff016c83367912eb055637fa50cAlan Cox * FIXME: at some point we need to both track this for PM and also 9789c78134cc54dff016c83367912eb055637fa50cAlan Cox * disable runtime pm on MRST if the brightness is nil (ie blanked) 9889c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 9989c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic int psb_lvds_i2c_set_brightness(struct drm_device *dev, 10089c78134cc54dff016c83367912eb055637fa50cAlan Cox unsigned int level) 10189c78134cc54dff016c83367912eb055637fa50cAlan Cox{ 10289c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_psb_private *dev_priv = 10389c78134cc54dff016c83367912eb055637fa50cAlan Cox (struct drm_psb_private *)dev->dev_private; 10489c78134cc54dff016c83367912eb055637fa50cAlan Cox 10589c78134cc54dff016c83367912eb055637fa50cAlan Cox struct psb_intel_i2c_chan *lvds_i2c_bus = dev_priv->lvds_i2c_bus; 10689c78134cc54dff016c83367912eb055637fa50cAlan Cox u8 out_buf[2]; 10789c78134cc54dff016c83367912eb055637fa50cAlan Cox unsigned int blc_i2c_brightness; 10889c78134cc54dff016c83367912eb055637fa50cAlan Cox 10989c78134cc54dff016c83367912eb055637fa50cAlan Cox struct i2c_msg msgs[] = { 11089c78134cc54dff016c83367912eb055637fa50cAlan Cox { 11189c78134cc54dff016c83367912eb055637fa50cAlan Cox .addr = lvds_i2c_bus->slave_addr, 11289c78134cc54dff016c83367912eb055637fa50cAlan Cox .flags = 0, 11389c78134cc54dff016c83367912eb055637fa50cAlan Cox .len = 2, 11489c78134cc54dff016c83367912eb055637fa50cAlan Cox .buf = out_buf, 11589c78134cc54dff016c83367912eb055637fa50cAlan Cox } 11689c78134cc54dff016c83367912eb055637fa50cAlan Cox }; 11789c78134cc54dff016c83367912eb055637fa50cAlan Cox 11889c78134cc54dff016c83367912eb055637fa50cAlan Cox blc_i2c_brightness = BRIGHTNESS_MASK & ((unsigned int)level * 11989c78134cc54dff016c83367912eb055637fa50cAlan Cox BRIGHTNESS_MASK / 12089c78134cc54dff016c83367912eb055637fa50cAlan Cox BRIGHTNESS_MAX_LEVEL); 12189c78134cc54dff016c83367912eb055637fa50cAlan Cox 12289c78134cc54dff016c83367912eb055637fa50cAlan Cox if (dev_priv->lvds_bl->pol == BLC_POLARITY_INVERSE) 12389c78134cc54dff016c83367912eb055637fa50cAlan Cox blc_i2c_brightness = BRIGHTNESS_MASK - blc_i2c_brightness; 12489c78134cc54dff016c83367912eb055637fa50cAlan Cox 12589c78134cc54dff016c83367912eb055637fa50cAlan Cox out_buf[0] = dev_priv->lvds_bl->brightnesscmd; 12689c78134cc54dff016c83367912eb055637fa50cAlan Cox out_buf[1] = (u8)blc_i2c_brightness; 12789c78134cc54dff016c83367912eb055637fa50cAlan Cox 12889c78134cc54dff016c83367912eb055637fa50cAlan Cox if (i2c_transfer(&lvds_i2c_bus->adapter, msgs, 1) == 1) { 12989c78134cc54dff016c83367912eb055637fa50cAlan Cox dev_dbg(dev->dev, "I2C set brightness.(command, value) (%d, %d)\n", 13089c78134cc54dff016c83367912eb055637fa50cAlan Cox dev_priv->lvds_bl->brightnesscmd, 13189c78134cc54dff016c83367912eb055637fa50cAlan Cox blc_i2c_brightness); 13289c78134cc54dff016c83367912eb055637fa50cAlan Cox return 0; 13389c78134cc54dff016c83367912eb055637fa50cAlan Cox } 13489c78134cc54dff016c83367912eb055637fa50cAlan Cox 13589c78134cc54dff016c83367912eb055637fa50cAlan Cox dev_err(dev->dev, "I2C transfer error\n"); 13689c78134cc54dff016c83367912eb055637fa50cAlan Cox return -1; 13789c78134cc54dff016c83367912eb055637fa50cAlan Cox} 13889c78134cc54dff016c83367912eb055637fa50cAlan Cox 13989c78134cc54dff016c83367912eb055637fa50cAlan Cox 14089c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic int psb_lvds_pwm_set_brightness(struct drm_device *dev, int level) 14189c78134cc54dff016c83367912eb055637fa50cAlan Cox{ 14289c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_psb_private *dev_priv = 14389c78134cc54dff016c83367912eb055637fa50cAlan Cox (struct drm_psb_private *)dev->dev_private; 14489c78134cc54dff016c83367912eb055637fa50cAlan Cox 14589c78134cc54dff016c83367912eb055637fa50cAlan Cox u32 max_pwm_blc; 14689c78134cc54dff016c83367912eb055637fa50cAlan Cox u32 blc_pwm_duty_cycle; 14789c78134cc54dff016c83367912eb055637fa50cAlan Cox 14889c78134cc54dff016c83367912eb055637fa50cAlan Cox max_pwm_blc = psb_intel_lvds_get_max_backlight(dev); 14989c78134cc54dff016c83367912eb055637fa50cAlan Cox 15089c78134cc54dff016c83367912eb055637fa50cAlan Cox /*BLC_PWM_CTL Should be initiated while backlight device init*/ 1511f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox BUG_ON(max_pwm_blc == 0); 15289c78134cc54dff016c83367912eb055637fa50cAlan Cox 15389c78134cc54dff016c83367912eb055637fa50cAlan Cox blc_pwm_duty_cycle = level * max_pwm_blc / BRIGHTNESS_MAX_LEVEL; 15489c78134cc54dff016c83367912eb055637fa50cAlan Cox 15589c78134cc54dff016c83367912eb055637fa50cAlan Cox if (dev_priv->lvds_bl->pol == BLC_POLARITY_INVERSE) 15689c78134cc54dff016c83367912eb055637fa50cAlan Cox blc_pwm_duty_cycle = max_pwm_blc - blc_pwm_duty_cycle; 15789c78134cc54dff016c83367912eb055637fa50cAlan Cox 15889c78134cc54dff016c83367912eb055637fa50cAlan Cox blc_pwm_duty_cycle &= PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR; 15989c78134cc54dff016c83367912eb055637fa50cAlan Cox REG_WRITE(BLC_PWM_CTL, 16089c78134cc54dff016c83367912eb055637fa50cAlan Cox (max_pwm_blc << PSB_BACKLIGHT_PWM_CTL_SHIFT) | 16189c78134cc54dff016c83367912eb055637fa50cAlan Cox (blc_pwm_duty_cycle)); 16289c78134cc54dff016c83367912eb055637fa50cAlan Cox 1631f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox dev_info(dev->dev, "Backlight lvds set brightness %08x\n", 1641f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox (max_pwm_blc << PSB_BACKLIGHT_PWM_CTL_SHIFT) | 1651f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox (blc_pwm_duty_cycle)); 1661f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox 16789c78134cc54dff016c83367912eb055637fa50cAlan Cox return 0; 16889c78134cc54dff016c83367912eb055637fa50cAlan Cox} 16989c78134cc54dff016c83367912eb055637fa50cAlan Cox 17089c78134cc54dff016c83367912eb055637fa50cAlan Cox/* 17189c78134cc54dff016c83367912eb055637fa50cAlan Cox * Set LVDS backlight level either by I2C or PWM 17289c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 17389c78134cc54dff016c83367912eb055637fa50cAlan Coxvoid psb_intel_lvds_set_brightness(struct drm_device *dev, int level) 17489c78134cc54dff016c83367912eb055637fa50cAlan Cox{ 1751f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox struct drm_psb_private *dev_priv = dev->dev_private; 17689c78134cc54dff016c83367912eb055637fa50cAlan Cox 17789c78134cc54dff016c83367912eb055637fa50cAlan Cox dev_dbg(dev->dev, "backlight level is %d\n", level); 17889c78134cc54dff016c83367912eb055637fa50cAlan Cox 17989c78134cc54dff016c83367912eb055637fa50cAlan Cox if (!dev_priv->lvds_bl) { 1801f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox dev_err(dev->dev, "NO LVDS backlight info\n"); 18189c78134cc54dff016c83367912eb055637fa50cAlan Cox return; 18289c78134cc54dff016c83367912eb055637fa50cAlan Cox } 18389c78134cc54dff016c83367912eb055637fa50cAlan Cox 18489c78134cc54dff016c83367912eb055637fa50cAlan Cox if (dev_priv->lvds_bl->type == BLC_I2C_TYPE) 18589c78134cc54dff016c83367912eb055637fa50cAlan Cox psb_lvds_i2c_set_brightness(dev, level); 18689c78134cc54dff016c83367912eb055637fa50cAlan Cox else 18789c78134cc54dff016c83367912eb055637fa50cAlan Cox psb_lvds_pwm_set_brightness(dev, level); 18889c78134cc54dff016c83367912eb055637fa50cAlan Cox} 18989c78134cc54dff016c83367912eb055637fa50cAlan Cox 19089c78134cc54dff016c83367912eb055637fa50cAlan Cox/* 19189c78134cc54dff016c83367912eb055637fa50cAlan Cox * Sets the backlight level. 19289c78134cc54dff016c83367912eb055637fa50cAlan Cox * 19389c78134cc54dff016c83367912eb055637fa50cAlan Cox * level: backlight level, from 0 to psb_intel_lvds_get_max_backlight(). 19489c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 19589c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic void psb_intel_lvds_set_backlight(struct drm_device *dev, int level) 19689c78134cc54dff016c83367912eb055637fa50cAlan Cox{ 19789c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_psb_private *dev_priv = dev->dev_private; 19889c78134cc54dff016c83367912eb055637fa50cAlan Cox u32 blc_pwm_ctl; 19989c78134cc54dff016c83367912eb055637fa50cAlan Cox 20089c78134cc54dff016c83367912eb055637fa50cAlan Cox if (gma_power_begin(dev, false)) { 2011f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox blc_pwm_ctl = REG_READ(BLC_PWM_CTL); 2021f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK; 20389c78134cc54dff016c83367912eb055637fa50cAlan Cox REG_WRITE(BLC_PWM_CTL, 20489c78134cc54dff016c83367912eb055637fa50cAlan Cox (blc_pwm_ctl | 20589c78134cc54dff016c83367912eb055637fa50cAlan Cox (level << BACKLIGHT_DUTY_CYCLE_SHIFT))); 206648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox dev_priv->regs.saveBLC_PWM_CTL = (blc_pwm_ctl | 2071f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox (level << BACKLIGHT_DUTY_CYCLE_SHIFT)); 20889c78134cc54dff016c83367912eb055637fa50cAlan Cox gma_power_end(dev); 20989c78134cc54dff016c83367912eb055637fa50cAlan Cox } else { 210648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox blc_pwm_ctl = dev_priv->regs.saveBLC_PWM_CTL & 21189c78134cc54dff016c83367912eb055637fa50cAlan Cox ~BACKLIGHT_DUTY_CYCLE_MASK; 212648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox dev_priv->regs.saveBLC_PWM_CTL = (blc_pwm_ctl | 21389c78134cc54dff016c83367912eb055637fa50cAlan Cox (level << BACKLIGHT_DUTY_CYCLE_SHIFT)); 21489c78134cc54dff016c83367912eb055637fa50cAlan Cox } 21589c78134cc54dff016c83367912eb055637fa50cAlan Cox} 21689c78134cc54dff016c83367912eb055637fa50cAlan Cox 21789c78134cc54dff016c83367912eb055637fa50cAlan Cox/* 21889c78134cc54dff016c83367912eb055637fa50cAlan Cox * Sets the power state for the panel. 21989c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 2209c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobssonstatic void psb_intel_lvds_set_power(struct drm_device *dev, bool on) 22189c78134cc54dff016c83367912eb055637fa50cAlan Cox{ 2229c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct drm_psb_private *dev_priv = dev->dev_private; 2239c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; 22489c78134cc54dff016c83367912eb055637fa50cAlan Cox u32 pp_status; 22589c78134cc54dff016c83367912eb055637fa50cAlan Cox 2261f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox if (!gma_power_begin(dev, true)) { 2271f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox dev_err(dev->dev, "set power, chip off!\n"); 22889c78134cc54dff016c83367912eb055637fa50cAlan Cox return; 2291f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox } 2301f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox 23189c78134cc54dff016c83367912eb055637fa50cAlan Cox if (on) { 23289c78134cc54dff016c83367912eb055637fa50cAlan Cox REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) | 23389c78134cc54dff016c83367912eb055637fa50cAlan Cox POWER_TARGET_ON); 23489c78134cc54dff016c83367912eb055637fa50cAlan Cox do { 23589c78134cc54dff016c83367912eb055637fa50cAlan Cox pp_status = REG_READ(PP_STATUS); 23689c78134cc54dff016c83367912eb055637fa50cAlan Cox } while ((pp_status & PP_ON) == 0); 23789c78134cc54dff016c83367912eb055637fa50cAlan Cox 23889c78134cc54dff016c83367912eb055637fa50cAlan Cox psb_intel_lvds_set_backlight(dev, 2399c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson mode_dev->backlight_duty_cycle); 24089c78134cc54dff016c83367912eb055637fa50cAlan Cox } else { 24189c78134cc54dff016c83367912eb055637fa50cAlan Cox psb_intel_lvds_set_backlight(dev, 0); 24289c78134cc54dff016c83367912eb055637fa50cAlan Cox 24389c78134cc54dff016c83367912eb055637fa50cAlan Cox REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) & 24489c78134cc54dff016c83367912eb055637fa50cAlan Cox ~POWER_TARGET_ON); 24589c78134cc54dff016c83367912eb055637fa50cAlan Cox do { 24689c78134cc54dff016c83367912eb055637fa50cAlan Cox pp_status = REG_READ(PP_STATUS); 24789c78134cc54dff016c83367912eb055637fa50cAlan Cox } while (pp_status & PP_ON); 24889c78134cc54dff016c83367912eb055637fa50cAlan Cox } 24989c78134cc54dff016c83367912eb055637fa50cAlan Cox 25089c78134cc54dff016c83367912eb055637fa50cAlan Cox gma_power_end(dev); 25189c78134cc54dff016c83367912eb055637fa50cAlan Cox} 25289c78134cc54dff016c83367912eb055637fa50cAlan Cox 25389c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic void psb_intel_lvds_encoder_dpms(struct drm_encoder *encoder, int mode) 25489c78134cc54dff016c83367912eb055637fa50cAlan Cox{ 25589c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_device *dev = encoder->dev; 25689c78134cc54dff016c83367912eb055637fa50cAlan Cox 25789c78134cc54dff016c83367912eb055637fa50cAlan Cox if (mode == DRM_MODE_DPMS_ON) 2589c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson psb_intel_lvds_set_power(dev, true); 25989c78134cc54dff016c83367912eb055637fa50cAlan Cox else 2609c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson psb_intel_lvds_set_power(dev, false); 26189c78134cc54dff016c83367912eb055637fa50cAlan Cox 26289c78134cc54dff016c83367912eb055637fa50cAlan Cox /* XXX: We never power down the LVDS pairs. */ 26389c78134cc54dff016c83367912eb055637fa50cAlan Cox} 26489c78134cc54dff016c83367912eb055637fa50cAlan Cox 26589c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic void psb_intel_lvds_save(struct drm_connector *connector) 26689c78134cc54dff016c83367912eb055637fa50cAlan Cox{ 26789c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_device *dev = connector->dev; 26889c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_psb_private *dev_priv = 26989c78134cc54dff016c83367912eb055637fa50cAlan Cox (struct drm_psb_private *)dev->dev_private; 2709c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct psb_intel_encoder *psb_intel_encoder = 2719c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson psb_intel_attached_encoder(connector); 27289c78134cc54dff016c83367912eb055637fa50cAlan Cox struct psb_intel_lvds_priv *lvds_priv = 2739c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson (struct psb_intel_lvds_priv *)psb_intel_encoder->dev_priv; 27489c78134cc54dff016c83367912eb055637fa50cAlan Cox 27589c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv->savePP_ON = REG_READ(LVDSPP_ON); 27689c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv->savePP_OFF = REG_READ(LVDSPP_OFF); 27789c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv->saveLVDS = REG_READ(LVDS); 27889c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv->savePP_CONTROL = REG_READ(PP_CONTROL); 27989c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv->savePP_CYCLE = REG_READ(PP_CYCLE); 28089c78134cc54dff016c83367912eb055637fa50cAlan Cox /*lvds_priv->savePP_DIVISOR = REG_READ(PP_DIVISOR);*/ 28189c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL); 28289c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv->savePFIT_CONTROL = REG_READ(PFIT_CONTROL); 28389c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv->savePFIT_PGM_RATIOS = REG_READ(PFIT_PGM_RATIOS); 28489c78134cc54dff016c83367912eb055637fa50cAlan Cox 28589c78134cc54dff016c83367912eb055637fa50cAlan Cox /*TODO: move backlight_duty_cycle to psb_intel_lvds_priv*/ 286648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox dev_priv->backlight_duty_cycle = (dev_priv->regs.saveBLC_PWM_CTL & 28789c78134cc54dff016c83367912eb055637fa50cAlan Cox BACKLIGHT_DUTY_CYCLE_MASK); 28889c78134cc54dff016c83367912eb055637fa50cAlan Cox 28989c78134cc54dff016c83367912eb055637fa50cAlan Cox /* 29089c78134cc54dff016c83367912eb055637fa50cAlan Cox * If the light is off at server startup, 29189c78134cc54dff016c83367912eb055637fa50cAlan Cox * just make it full brightness 29289c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 29389c78134cc54dff016c83367912eb055637fa50cAlan Cox if (dev_priv->backlight_duty_cycle == 0) 29489c78134cc54dff016c83367912eb055637fa50cAlan Cox dev_priv->backlight_duty_cycle = 29589c78134cc54dff016c83367912eb055637fa50cAlan Cox psb_intel_lvds_get_max_backlight(dev); 29689c78134cc54dff016c83367912eb055637fa50cAlan Cox 29789c78134cc54dff016c83367912eb055637fa50cAlan Cox dev_dbg(dev->dev, "(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", 29889c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv->savePP_ON, 29989c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv->savePP_OFF, 30089c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv->saveLVDS, 30189c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv->savePP_CONTROL, 30289c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv->savePP_CYCLE, 30389c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv->saveBLC_PWM_CTL); 30489c78134cc54dff016c83367912eb055637fa50cAlan Cox} 30589c78134cc54dff016c83367912eb055637fa50cAlan Cox 30689c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic void psb_intel_lvds_restore(struct drm_connector *connector) 30789c78134cc54dff016c83367912eb055637fa50cAlan Cox{ 30889c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_device *dev = connector->dev; 30989c78134cc54dff016c83367912eb055637fa50cAlan Cox u32 pp_status; 3109c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct psb_intel_encoder *psb_intel_encoder = 3119c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson psb_intel_attached_encoder(connector); 31289c78134cc54dff016c83367912eb055637fa50cAlan Cox struct psb_intel_lvds_priv *lvds_priv = 3139c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson (struct psb_intel_lvds_priv *)psb_intel_encoder->dev_priv; 31489c78134cc54dff016c83367912eb055637fa50cAlan Cox 31589c78134cc54dff016c83367912eb055637fa50cAlan Cox dev_dbg(dev->dev, "(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", 31689c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv->savePP_ON, 31789c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv->savePP_OFF, 31889c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv->saveLVDS, 31989c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv->savePP_CONTROL, 32089c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv->savePP_CYCLE, 32189c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv->saveBLC_PWM_CTL); 32289c78134cc54dff016c83367912eb055637fa50cAlan Cox 32389c78134cc54dff016c83367912eb055637fa50cAlan Cox REG_WRITE(BLC_PWM_CTL, lvds_priv->saveBLC_PWM_CTL); 32489c78134cc54dff016c83367912eb055637fa50cAlan Cox REG_WRITE(PFIT_CONTROL, lvds_priv->savePFIT_CONTROL); 32589c78134cc54dff016c83367912eb055637fa50cAlan Cox REG_WRITE(PFIT_PGM_RATIOS, lvds_priv->savePFIT_PGM_RATIOS); 32689c78134cc54dff016c83367912eb055637fa50cAlan Cox REG_WRITE(LVDSPP_ON, lvds_priv->savePP_ON); 32789c78134cc54dff016c83367912eb055637fa50cAlan Cox REG_WRITE(LVDSPP_OFF, lvds_priv->savePP_OFF); 32889c78134cc54dff016c83367912eb055637fa50cAlan Cox /*REG_WRITE(PP_DIVISOR, lvds_priv->savePP_DIVISOR);*/ 32989c78134cc54dff016c83367912eb055637fa50cAlan Cox REG_WRITE(PP_CYCLE, lvds_priv->savePP_CYCLE); 33089c78134cc54dff016c83367912eb055637fa50cAlan Cox REG_WRITE(PP_CONTROL, lvds_priv->savePP_CONTROL); 33189c78134cc54dff016c83367912eb055637fa50cAlan Cox REG_WRITE(LVDS, lvds_priv->saveLVDS); 33289c78134cc54dff016c83367912eb055637fa50cAlan Cox 33389c78134cc54dff016c83367912eb055637fa50cAlan Cox if (lvds_priv->savePP_CONTROL & POWER_TARGET_ON) { 33489c78134cc54dff016c83367912eb055637fa50cAlan Cox REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) | 33589c78134cc54dff016c83367912eb055637fa50cAlan Cox POWER_TARGET_ON); 33689c78134cc54dff016c83367912eb055637fa50cAlan Cox do { 33789c78134cc54dff016c83367912eb055637fa50cAlan Cox pp_status = REG_READ(PP_STATUS); 33889c78134cc54dff016c83367912eb055637fa50cAlan Cox } while ((pp_status & PP_ON) == 0); 33989c78134cc54dff016c83367912eb055637fa50cAlan Cox } else { 34089c78134cc54dff016c83367912eb055637fa50cAlan Cox REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) & 34189c78134cc54dff016c83367912eb055637fa50cAlan Cox ~POWER_TARGET_ON); 34289c78134cc54dff016c83367912eb055637fa50cAlan Cox do { 34389c78134cc54dff016c83367912eb055637fa50cAlan Cox pp_status = REG_READ(PP_STATUS); 34489c78134cc54dff016c83367912eb055637fa50cAlan Cox } while (pp_status & PP_ON); 34589c78134cc54dff016c83367912eb055637fa50cAlan Cox } 34689c78134cc54dff016c83367912eb055637fa50cAlan Cox} 34789c78134cc54dff016c83367912eb055637fa50cAlan Cox 34889c78134cc54dff016c83367912eb055637fa50cAlan Coxint psb_intel_lvds_mode_valid(struct drm_connector *connector, 34989c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_display_mode *mode) 35089c78134cc54dff016c83367912eb055637fa50cAlan Cox{ 3519c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct drm_psb_private *dev_priv = connector->dev->dev_private; 3529c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct psb_intel_encoder *psb_intel_encoder = 3539c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson psb_intel_attached_encoder(connector); 35489c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_display_mode *fixed_mode = 3559c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson dev_priv->mode_dev.panel_fixed_mode; 35689c78134cc54dff016c83367912eb055637fa50cAlan Cox 3579c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson if (psb_intel_encoder->type == INTEL_OUTPUT_MIPI2) 3589c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson fixed_mode = dev_priv->mode_dev.panel_fixed_mode2; 35989c78134cc54dff016c83367912eb055637fa50cAlan Cox 36089c78134cc54dff016c83367912eb055637fa50cAlan Cox /* just in case */ 36189c78134cc54dff016c83367912eb055637fa50cAlan Cox if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 36289c78134cc54dff016c83367912eb055637fa50cAlan Cox return MODE_NO_DBLESCAN; 36389c78134cc54dff016c83367912eb055637fa50cAlan Cox 36489c78134cc54dff016c83367912eb055637fa50cAlan Cox /* just in case */ 36589c78134cc54dff016c83367912eb055637fa50cAlan Cox if (mode->flags & DRM_MODE_FLAG_INTERLACE) 36689c78134cc54dff016c83367912eb055637fa50cAlan Cox return MODE_NO_INTERLACE; 36789c78134cc54dff016c83367912eb055637fa50cAlan Cox 36889c78134cc54dff016c83367912eb055637fa50cAlan Cox if (fixed_mode) { 36989c78134cc54dff016c83367912eb055637fa50cAlan Cox if (mode->hdisplay > fixed_mode->hdisplay) 37089c78134cc54dff016c83367912eb055637fa50cAlan Cox return MODE_PANEL; 37189c78134cc54dff016c83367912eb055637fa50cAlan Cox if (mode->vdisplay > fixed_mode->vdisplay) 37289c78134cc54dff016c83367912eb055637fa50cAlan Cox return MODE_PANEL; 37389c78134cc54dff016c83367912eb055637fa50cAlan Cox } 37489c78134cc54dff016c83367912eb055637fa50cAlan Cox return MODE_OK; 37589c78134cc54dff016c83367912eb055637fa50cAlan Cox} 37689c78134cc54dff016c83367912eb055637fa50cAlan Cox 37789c78134cc54dff016c83367912eb055637fa50cAlan Coxbool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder, 37889c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_display_mode *mode, 37989c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_display_mode *adjusted_mode) 38089c78134cc54dff016c83367912eb055637fa50cAlan Cox{ 38189c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_device *dev = encoder->dev; 3829c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct drm_psb_private *dev_priv = dev->dev_private; 3839c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; 38489c78134cc54dff016c83367912eb055637fa50cAlan Cox struct psb_intel_crtc *psb_intel_crtc = 38589c78134cc54dff016c83367912eb055637fa50cAlan Cox to_psb_intel_crtc(encoder->crtc); 38689c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_encoder *tmp_encoder; 38789c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_display_mode *panel_fixed_mode = mode_dev->panel_fixed_mode; 3889c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct psb_intel_encoder *psb_intel_encoder = 3899c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson to_psb_intel_encoder(encoder); 39089c78134cc54dff016c83367912eb055637fa50cAlan Cox 3919c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson if (psb_intel_encoder->type == INTEL_OUTPUT_MIPI2) 39289c78134cc54dff016c83367912eb055637fa50cAlan Cox panel_fixed_mode = mode_dev->panel_fixed_mode2; 39389c78134cc54dff016c83367912eb055637fa50cAlan Cox 39489c78134cc54dff016c83367912eb055637fa50cAlan Cox /* PSB requires the LVDS is on pipe B, MRST has only one pipe anyway */ 39589c78134cc54dff016c83367912eb055637fa50cAlan Cox if (!IS_MRST(dev) && psb_intel_crtc->pipe == 0) { 39689c78134cc54dff016c83367912eb055637fa50cAlan Cox printk(KERN_ERR "Can't support LVDS on pipe A\n"); 39789c78134cc54dff016c83367912eb055637fa50cAlan Cox return false; 39889c78134cc54dff016c83367912eb055637fa50cAlan Cox } 39989c78134cc54dff016c83367912eb055637fa50cAlan Cox if (IS_MRST(dev) && psb_intel_crtc->pipe != 0) { 40089c78134cc54dff016c83367912eb055637fa50cAlan Cox printk(KERN_ERR "Must use PIPE A\n"); 40189c78134cc54dff016c83367912eb055637fa50cAlan Cox return false; 40289c78134cc54dff016c83367912eb055637fa50cAlan Cox } 40389c78134cc54dff016c83367912eb055637fa50cAlan Cox /* Should never happen!! */ 40489c78134cc54dff016c83367912eb055637fa50cAlan Cox list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list, 40589c78134cc54dff016c83367912eb055637fa50cAlan Cox head) { 40689c78134cc54dff016c83367912eb055637fa50cAlan Cox if (tmp_encoder != encoder 40789c78134cc54dff016c83367912eb055637fa50cAlan Cox && tmp_encoder->crtc == encoder->crtc) { 40889c78134cc54dff016c83367912eb055637fa50cAlan Cox printk(KERN_ERR "Can't enable LVDS and another " 40989c78134cc54dff016c83367912eb055637fa50cAlan Cox "encoder on the same pipe\n"); 41089c78134cc54dff016c83367912eb055637fa50cAlan Cox return false; 41189c78134cc54dff016c83367912eb055637fa50cAlan Cox } 41289c78134cc54dff016c83367912eb055637fa50cAlan Cox } 41389c78134cc54dff016c83367912eb055637fa50cAlan Cox 41489c78134cc54dff016c83367912eb055637fa50cAlan Cox /* 41589c78134cc54dff016c83367912eb055637fa50cAlan Cox * If we have timings from the BIOS for the panel, put them in 41689c78134cc54dff016c83367912eb055637fa50cAlan Cox * to the adjusted mode. The CRTC will be set up for this mode, 41789c78134cc54dff016c83367912eb055637fa50cAlan Cox * with the panel scaling set up to source from the H/VDisplay 41889c78134cc54dff016c83367912eb055637fa50cAlan Cox * of the original mode. 41989c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 42089c78134cc54dff016c83367912eb055637fa50cAlan Cox if (panel_fixed_mode != NULL) { 42189c78134cc54dff016c83367912eb055637fa50cAlan Cox adjusted_mode->hdisplay = panel_fixed_mode->hdisplay; 42289c78134cc54dff016c83367912eb055637fa50cAlan Cox adjusted_mode->hsync_start = panel_fixed_mode->hsync_start; 42389c78134cc54dff016c83367912eb055637fa50cAlan Cox adjusted_mode->hsync_end = panel_fixed_mode->hsync_end; 42489c78134cc54dff016c83367912eb055637fa50cAlan Cox adjusted_mode->htotal = panel_fixed_mode->htotal; 42589c78134cc54dff016c83367912eb055637fa50cAlan Cox adjusted_mode->vdisplay = panel_fixed_mode->vdisplay; 42689c78134cc54dff016c83367912eb055637fa50cAlan Cox adjusted_mode->vsync_start = panel_fixed_mode->vsync_start; 42789c78134cc54dff016c83367912eb055637fa50cAlan Cox adjusted_mode->vsync_end = panel_fixed_mode->vsync_end; 42889c78134cc54dff016c83367912eb055637fa50cAlan Cox adjusted_mode->vtotal = panel_fixed_mode->vtotal; 42989c78134cc54dff016c83367912eb055637fa50cAlan Cox adjusted_mode->clock = panel_fixed_mode->clock; 43089c78134cc54dff016c83367912eb055637fa50cAlan Cox drm_mode_set_crtcinfo(adjusted_mode, 43189c78134cc54dff016c83367912eb055637fa50cAlan Cox CRTC_INTERLACE_HALVE_V); 43289c78134cc54dff016c83367912eb055637fa50cAlan Cox } 43389c78134cc54dff016c83367912eb055637fa50cAlan Cox 43489c78134cc54dff016c83367912eb055637fa50cAlan Cox /* 43589c78134cc54dff016c83367912eb055637fa50cAlan Cox * XXX: It would be nice to support lower refresh rates on the 43689c78134cc54dff016c83367912eb055637fa50cAlan Cox * panels to reduce power consumption, and perhaps match the 43789c78134cc54dff016c83367912eb055637fa50cAlan Cox * user's requested refresh rate. 43889c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 43989c78134cc54dff016c83367912eb055637fa50cAlan Cox 44089c78134cc54dff016c83367912eb055637fa50cAlan Cox return true; 44189c78134cc54dff016c83367912eb055637fa50cAlan Cox} 44289c78134cc54dff016c83367912eb055637fa50cAlan Cox 44389c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic void psb_intel_lvds_prepare(struct drm_encoder *encoder) 44489c78134cc54dff016c83367912eb055637fa50cAlan Cox{ 44589c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_device *dev = encoder->dev; 4469c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct drm_psb_private *dev_priv = dev->dev_private; 4479c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; 44889c78134cc54dff016c83367912eb055637fa50cAlan Cox 44989c78134cc54dff016c83367912eb055637fa50cAlan Cox if (!gma_power_begin(dev, true)) 45089c78134cc54dff016c83367912eb055637fa50cAlan Cox return; 45189c78134cc54dff016c83367912eb055637fa50cAlan Cox 45289c78134cc54dff016c83367912eb055637fa50cAlan Cox mode_dev->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL); 45389c78134cc54dff016c83367912eb055637fa50cAlan Cox mode_dev->backlight_duty_cycle = (mode_dev->saveBLC_PWM_CTL & 45489c78134cc54dff016c83367912eb055637fa50cAlan Cox BACKLIGHT_DUTY_CYCLE_MASK); 45589c78134cc54dff016c83367912eb055637fa50cAlan Cox 4569c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson psb_intel_lvds_set_power(dev, false); 45789c78134cc54dff016c83367912eb055637fa50cAlan Cox 45889c78134cc54dff016c83367912eb055637fa50cAlan Cox gma_power_end(dev); 45989c78134cc54dff016c83367912eb055637fa50cAlan Cox} 46089c78134cc54dff016c83367912eb055637fa50cAlan Cox 46189c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic void psb_intel_lvds_commit(struct drm_encoder *encoder) 46289c78134cc54dff016c83367912eb055637fa50cAlan Cox{ 46389c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_device *dev = encoder->dev; 4649c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct drm_psb_private *dev_priv = dev->dev_private; 4659c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; 46689c78134cc54dff016c83367912eb055637fa50cAlan Cox 46789c78134cc54dff016c83367912eb055637fa50cAlan Cox if (mode_dev->backlight_duty_cycle == 0) 46889c78134cc54dff016c83367912eb055637fa50cAlan Cox mode_dev->backlight_duty_cycle = 46989c78134cc54dff016c83367912eb055637fa50cAlan Cox psb_intel_lvds_get_max_backlight(dev); 47089c78134cc54dff016c83367912eb055637fa50cAlan Cox 4719c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson psb_intel_lvds_set_power(dev, true); 47289c78134cc54dff016c83367912eb055637fa50cAlan Cox} 47389c78134cc54dff016c83367912eb055637fa50cAlan Cox 47489c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic void psb_intel_lvds_mode_set(struct drm_encoder *encoder, 47589c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_display_mode *mode, 47689c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_display_mode *adjusted_mode) 47789c78134cc54dff016c83367912eb055637fa50cAlan Cox{ 47889c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_device *dev = encoder->dev; 47989c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_psb_private *dev_priv = dev->dev_private; 48089c78134cc54dff016c83367912eb055637fa50cAlan Cox u32 pfit_control; 48189c78134cc54dff016c83367912eb055637fa50cAlan Cox 48289c78134cc54dff016c83367912eb055637fa50cAlan Cox /* 48389c78134cc54dff016c83367912eb055637fa50cAlan Cox * The LVDS pin pair will already have been turned on in the 48489c78134cc54dff016c83367912eb055637fa50cAlan Cox * psb_intel_crtc_mode_set since it has a large impact on the DPLL 48589c78134cc54dff016c83367912eb055637fa50cAlan Cox * settings. 48689c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 48789c78134cc54dff016c83367912eb055637fa50cAlan Cox 48889c78134cc54dff016c83367912eb055637fa50cAlan Cox /* 48989c78134cc54dff016c83367912eb055637fa50cAlan Cox * Enable automatic panel scaling so that non-native modes fill the 49089c78134cc54dff016c83367912eb055637fa50cAlan Cox * screen. Should be enabled before the pipe is enabled, according to 49189c78134cc54dff016c83367912eb055637fa50cAlan Cox * register description and PRM. 49289c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 49389c78134cc54dff016c83367912eb055637fa50cAlan Cox if (mode->hdisplay != adjusted_mode->hdisplay || 49489c78134cc54dff016c83367912eb055637fa50cAlan Cox mode->vdisplay != adjusted_mode->vdisplay) 49589c78134cc54dff016c83367912eb055637fa50cAlan Cox pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE | 49689c78134cc54dff016c83367912eb055637fa50cAlan Cox HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR | 49789c78134cc54dff016c83367912eb055637fa50cAlan Cox HORIZ_INTERP_BILINEAR); 49889c78134cc54dff016c83367912eb055637fa50cAlan Cox else 49989c78134cc54dff016c83367912eb055637fa50cAlan Cox pfit_control = 0; 50089c78134cc54dff016c83367912eb055637fa50cAlan Cox 50189c78134cc54dff016c83367912eb055637fa50cAlan Cox if (dev_priv->lvds_dither) 50289c78134cc54dff016c83367912eb055637fa50cAlan Cox pfit_control |= PANEL_8TO6_DITHER_ENABLE; 50389c78134cc54dff016c83367912eb055637fa50cAlan Cox 50489c78134cc54dff016c83367912eb055637fa50cAlan Cox REG_WRITE(PFIT_CONTROL, pfit_control); 50589c78134cc54dff016c83367912eb055637fa50cAlan Cox} 50689c78134cc54dff016c83367912eb055637fa50cAlan Cox 50789c78134cc54dff016c83367912eb055637fa50cAlan Cox/* 50889c78134cc54dff016c83367912eb055637fa50cAlan Cox * Detect the LVDS connection. 50989c78134cc54dff016c83367912eb055637fa50cAlan Cox * 51089c78134cc54dff016c83367912eb055637fa50cAlan Cox * This always returns CONNECTOR_STATUS_CONNECTED. 51189c78134cc54dff016c83367912eb055637fa50cAlan Cox * This connector should only have 51289c78134cc54dff016c83367912eb055637fa50cAlan Cox * been set up if the LVDS was actually connected anyway. 51389c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 51489c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic enum drm_connector_status psb_intel_lvds_detect(struct drm_connector 51589c78134cc54dff016c83367912eb055637fa50cAlan Cox *connector, bool force) 51689c78134cc54dff016c83367912eb055637fa50cAlan Cox{ 51789c78134cc54dff016c83367912eb055637fa50cAlan Cox return connector_status_connected; 51889c78134cc54dff016c83367912eb055637fa50cAlan Cox} 51989c78134cc54dff016c83367912eb055637fa50cAlan Cox 52089c78134cc54dff016c83367912eb055637fa50cAlan Cox/* 52189c78134cc54dff016c83367912eb055637fa50cAlan Cox * Return the list of DDC modes if available, or the BIOS fixed mode otherwise. 52289c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 52389c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic int psb_intel_lvds_get_modes(struct drm_connector *connector) 52489c78134cc54dff016c83367912eb055637fa50cAlan Cox{ 52589c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_device *dev = connector->dev; 5269c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct drm_psb_private *dev_priv = dev->dev_private; 5279c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; 5289c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct psb_intel_encoder *psb_intel_encoder = 5299c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson psb_intel_attached_encoder(connector); 5309c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct psb_intel_lvds_priv *lvds_priv = psb_intel_encoder->dev_priv; 53189c78134cc54dff016c83367912eb055637fa50cAlan Cox int ret = 0; 53289c78134cc54dff016c83367912eb055637fa50cAlan Cox 53389c78134cc54dff016c83367912eb055637fa50cAlan Cox if (!IS_MRST(dev)) 5349c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson ret = psb_intel_ddc_get_modes(connector, &lvds_priv->i2c_bus->adapter); 53589c78134cc54dff016c83367912eb055637fa50cAlan Cox 53689c78134cc54dff016c83367912eb055637fa50cAlan Cox if (ret) 53789c78134cc54dff016c83367912eb055637fa50cAlan Cox return ret; 53889c78134cc54dff016c83367912eb055637fa50cAlan Cox 53989c78134cc54dff016c83367912eb055637fa50cAlan Cox /* Didn't get an EDID, so 54089c78134cc54dff016c83367912eb055637fa50cAlan Cox * Set wide sync ranges so we get all modes 54189c78134cc54dff016c83367912eb055637fa50cAlan Cox * handed to valid_mode for checking 54289c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 54389c78134cc54dff016c83367912eb055637fa50cAlan Cox connector->display_info.min_vfreq = 0; 54489c78134cc54dff016c83367912eb055637fa50cAlan Cox connector->display_info.max_vfreq = 200; 54589c78134cc54dff016c83367912eb055637fa50cAlan Cox connector->display_info.min_hfreq = 0; 54689c78134cc54dff016c83367912eb055637fa50cAlan Cox connector->display_info.max_hfreq = 200; 54789c78134cc54dff016c83367912eb055637fa50cAlan Cox 54889c78134cc54dff016c83367912eb055637fa50cAlan Cox if (mode_dev->panel_fixed_mode != NULL) { 54989c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_display_mode *mode = 55089c78134cc54dff016c83367912eb055637fa50cAlan Cox drm_mode_duplicate(dev, mode_dev->panel_fixed_mode); 55189c78134cc54dff016c83367912eb055637fa50cAlan Cox drm_mode_probed_add(connector, mode); 55289c78134cc54dff016c83367912eb055637fa50cAlan Cox return 1; 55389c78134cc54dff016c83367912eb055637fa50cAlan Cox } 55489c78134cc54dff016c83367912eb055637fa50cAlan Cox 55589c78134cc54dff016c83367912eb055637fa50cAlan Cox return 0; 55689c78134cc54dff016c83367912eb055637fa50cAlan Cox} 55789c78134cc54dff016c83367912eb055637fa50cAlan Cox 55889c78134cc54dff016c83367912eb055637fa50cAlan Cox/** 55989c78134cc54dff016c83367912eb055637fa50cAlan Cox * psb_intel_lvds_destroy - unregister and free LVDS structures 56089c78134cc54dff016c83367912eb055637fa50cAlan Cox * @connector: connector to free 56189c78134cc54dff016c83367912eb055637fa50cAlan Cox * 56289c78134cc54dff016c83367912eb055637fa50cAlan Cox * Unregister the DDC bus for this connector then free the driver private 56389c78134cc54dff016c83367912eb055637fa50cAlan Cox * structure. 56489c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 56589c78134cc54dff016c83367912eb055637fa50cAlan Coxvoid psb_intel_lvds_destroy(struct drm_connector *connector) 56689c78134cc54dff016c83367912eb055637fa50cAlan Cox{ 5679c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct psb_intel_encoder *psb_intel_encoder = 5689c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson psb_intel_attached_encoder(connector); 5699c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct psb_intel_lvds_priv *lvds_priv = psb_intel_encoder->dev_priv; 57089c78134cc54dff016c83367912eb055637fa50cAlan Cox 5719c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson if (lvds_priv->ddc_bus) 5729c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson psb_intel_i2c_destroy(lvds_priv->ddc_bus); 57389c78134cc54dff016c83367912eb055637fa50cAlan Cox drm_sysfs_connector_remove(connector); 57489c78134cc54dff016c83367912eb055637fa50cAlan Cox drm_connector_cleanup(connector); 57589c78134cc54dff016c83367912eb055637fa50cAlan Cox kfree(connector); 57689c78134cc54dff016c83367912eb055637fa50cAlan Cox} 57789c78134cc54dff016c83367912eb055637fa50cAlan Cox 57889c78134cc54dff016c83367912eb055637fa50cAlan Coxint psb_intel_lvds_set_property(struct drm_connector *connector, 57989c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_property *property, 58089c78134cc54dff016c83367912eb055637fa50cAlan Cox uint64_t value) 58189c78134cc54dff016c83367912eb055637fa50cAlan Cox{ 58289c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_encoder *encoder = connector->encoder; 58389c78134cc54dff016c83367912eb055637fa50cAlan Cox 58489c78134cc54dff016c83367912eb055637fa50cAlan Cox if (!encoder) 58589c78134cc54dff016c83367912eb055637fa50cAlan Cox return -1; 58689c78134cc54dff016c83367912eb055637fa50cAlan Cox 58789c78134cc54dff016c83367912eb055637fa50cAlan Cox if (!strcmp(property->name, "scaling mode")) { 58889c78134cc54dff016c83367912eb055637fa50cAlan Cox struct psb_intel_crtc *crtc = 58989c78134cc54dff016c83367912eb055637fa50cAlan Cox to_psb_intel_crtc(encoder->crtc); 59089c78134cc54dff016c83367912eb055637fa50cAlan Cox uint64_t curval; 59189c78134cc54dff016c83367912eb055637fa50cAlan Cox 59289c78134cc54dff016c83367912eb055637fa50cAlan Cox if (!crtc) 59389c78134cc54dff016c83367912eb055637fa50cAlan Cox goto set_prop_error; 59489c78134cc54dff016c83367912eb055637fa50cAlan Cox 59589c78134cc54dff016c83367912eb055637fa50cAlan Cox switch (value) { 59689c78134cc54dff016c83367912eb055637fa50cAlan Cox case DRM_MODE_SCALE_FULLSCREEN: 59789c78134cc54dff016c83367912eb055637fa50cAlan Cox break; 59889c78134cc54dff016c83367912eb055637fa50cAlan Cox case DRM_MODE_SCALE_NO_SCALE: 59989c78134cc54dff016c83367912eb055637fa50cAlan Cox break; 60089c78134cc54dff016c83367912eb055637fa50cAlan Cox case DRM_MODE_SCALE_ASPECT: 60189c78134cc54dff016c83367912eb055637fa50cAlan Cox break; 60289c78134cc54dff016c83367912eb055637fa50cAlan Cox default: 60389c78134cc54dff016c83367912eb055637fa50cAlan Cox goto set_prop_error; 60489c78134cc54dff016c83367912eb055637fa50cAlan Cox } 60589c78134cc54dff016c83367912eb055637fa50cAlan Cox 60689c78134cc54dff016c83367912eb055637fa50cAlan Cox if (drm_connector_property_get_value(connector, 60789c78134cc54dff016c83367912eb055637fa50cAlan Cox property, 60889c78134cc54dff016c83367912eb055637fa50cAlan Cox &curval)) 60989c78134cc54dff016c83367912eb055637fa50cAlan Cox goto set_prop_error; 61089c78134cc54dff016c83367912eb055637fa50cAlan Cox 61189c78134cc54dff016c83367912eb055637fa50cAlan Cox if (curval == value) 61289c78134cc54dff016c83367912eb055637fa50cAlan Cox goto set_prop_done; 61389c78134cc54dff016c83367912eb055637fa50cAlan Cox 61489c78134cc54dff016c83367912eb055637fa50cAlan Cox if (drm_connector_property_set_value(connector, 61589c78134cc54dff016c83367912eb055637fa50cAlan Cox property, 61689c78134cc54dff016c83367912eb055637fa50cAlan Cox value)) 61789c78134cc54dff016c83367912eb055637fa50cAlan Cox goto set_prop_error; 61889c78134cc54dff016c83367912eb055637fa50cAlan Cox 61989c78134cc54dff016c83367912eb055637fa50cAlan Cox if (crtc->saved_mode.hdisplay != 0 && 62089c78134cc54dff016c83367912eb055637fa50cAlan Cox crtc->saved_mode.vdisplay != 0) { 62189c78134cc54dff016c83367912eb055637fa50cAlan Cox if (!drm_crtc_helper_set_mode(encoder->crtc, 62289c78134cc54dff016c83367912eb055637fa50cAlan Cox &crtc->saved_mode, 62389c78134cc54dff016c83367912eb055637fa50cAlan Cox encoder->crtc->x, 62489c78134cc54dff016c83367912eb055637fa50cAlan Cox encoder->crtc->y, 62589c78134cc54dff016c83367912eb055637fa50cAlan Cox encoder->crtc->fb)) 62689c78134cc54dff016c83367912eb055637fa50cAlan Cox goto set_prop_error; 62789c78134cc54dff016c83367912eb055637fa50cAlan Cox } 62889c78134cc54dff016c83367912eb055637fa50cAlan Cox } else if (!strcmp(property->name, "backlight")) { 62989c78134cc54dff016c83367912eb055637fa50cAlan Cox if (drm_connector_property_set_value(connector, 63089c78134cc54dff016c83367912eb055637fa50cAlan Cox property, 63189c78134cc54dff016c83367912eb055637fa50cAlan Cox value)) 63289c78134cc54dff016c83367912eb055637fa50cAlan Cox goto set_prop_error; 63389c78134cc54dff016c83367912eb055637fa50cAlan Cox else { 63489c78134cc54dff016c83367912eb055637fa50cAlan Cox#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE 6351f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox struct drm_psb_private *devp = 6361f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox encoder->dev->dev_private; 63789c78134cc54dff016c83367912eb055637fa50cAlan Cox struct backlight_device *bd = devp->backlight_device; 63889c78134cc54dff016c83367912eb055637fa50cAlan Cox if (bd) { 63989c78134cc54dff016c83367912eb055637fa50cAlan Cox bd->props.brightness = value; 64089c78134cc54dff016c83367912eb055637fa50cAlan Cox backlight_update_status(bd); 64189c78134cc54dff016c83367912eb055637fa50cAlan Cox } 64289c78134cc54dff016c83367912eb055637fa50cAlan Cox#endif 64389c78134cc54dff016c83367912eb055637fa50cAlan Cox } 64489c78134cc54dff016c83367912eb055637fa50cAlan Cox } else if (!strcmp(property->name, "DPMS")) { 64589c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_encoder_helper_funcs *hfuncs 64689c78134cc54dff016c83367912eb055637fa50cAlan Cox = encoder->helper_private; 64789c78134cc54dff016c83367912eb055637fa50cAlan Cox hfuncs->dpms(encoder, value); 64889c78134cc54dff016c83367912eb055637fa50cAlan Cox } 64989c78134cc54dff016c83367912eb055637fa50cAlan Cox 65089c78134cc54dff016c83367912eb055637fa50cAlan Coxset_prop_done: 65189c78134cc54dff016c83367912eb055637fa50cAlan Cox return 0; 65289c78134cc54dff016c83367912eb055637fa50cAlan Coxset_prop_error: 65389c78134cc54dff016c83367912eb055637fa50cAlan Cox return -1; 65489c78134cc54dff016c83367912eb055637fa50cAlan Cox} 65589c78134cc54dff016c83367912eb055637fa50cAlan Cox 65689c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic const struct drm_encoder_helper_funcs psb_intel_lvds_helper_funcs = { 65789c78134cc54dff016c83367912eb055637fa50cAlan Cox .dpms = psb_intel_lvds_encoder_dpms, 65889c78134cc54dff016c83367912eb055637fa50cAlan Cox .mode_fixup = psb_intel_lvds_mode_fixup, 65989c78134cc54dff016c83367912eb055637fa50cAlan Cox .prepare = psb_intel_lvds_prepare, 66089c78134cc54dff016c83367912eb055637fa50cAlan Cox .mode_set = psb_intel_lvds_mode_set, 66189c78134cc54dff016c83367912eb055637fa50cAlan Cox .commit = psb_intel_lvds_commit, 66289c78134cc54dff016c83367912eb055637fa50cAlan Cox}; 66389c78134cc54dff016c83367912eb055637fa50cAlan Cox 66489c78134cc54dff016c83367912eb055637fa50cAlan Coxconst struct drm_connector_helper_funcs 66589c78134cc54dff016c83367912eb055637fa50cAlan Cox psb_intel_lvds_connector_helper_funcs = { 66689c78134cc54dff016c83367912eb055637fa50cAlan Cox .get_modes = psb_intel_lvds_get_modes, 66789c78134cc54dff016c83367912eb055637fa50cAlan Cox .mode_valid = psb_intel_lvds_mode_valid, 66889c78134cc54dff016c83367912eb055637fa50cAlan Cox .best_encoder = psb_intel_best_encoder, 66989c78134cc54dff016c83367912eb055637fa50cAlan Cox}; 67089c78134cc54dff016c83367912eb055637fa50cAlan Cox 67189c78134cc54dff016c83367912eb055637fa50cAlan Coxconst struct drm_connector_funcs psb_intel_lvds_connector_funcs = { 67289c78134cc54dff016c83367912eb055637fa50cAlan Cox .dpms = drm_helper_connector_dpms, 67389c78134cc54dff016c83367912eb055637fa50cAlan Cox .save = psb_intel_lvds_save, 67489c78134cc54dff016c83367912eb055637fa50cAlan Cox .restore = psb_intel_lvds_restore, 67589c78134cc54dff016c83367912eb055637fa50cAlan Cox .detect = psb_intel_lvds_detect, 67689c78134cc54dff016c83367912eb055637fa50cAlan Cox .fill_modes = drm_helper_probe_single_connector_modes, 67789c78134cc54dff016c83367912eb055637fa50cAlan Cox .set_property = psb_intel_lvds_set_property, 67889c78134cc54dff016c83367912eb055637fa50cAlan Cox .destroy = psb_intel_lvds_destroy, 67989c78134cc54dff016c83367912eb055637fa50cAlan Cox}; 68089c78134cc54dff016c83367912eb055637fa50cAlan Cox 68189c78134cc54dff016c83367912eb055637fa50cAlan Cox 68289c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic void psb_intel_lvds_enc_destroy(struct drm_encoder *encoder) 68389c78134cc54dff016c83367912eb055637fa50cAlan Cox{ 68489c78134cc54dff016c83367912eb055637fa50cAlan Cox drm_encoder_cleanup(encoder); 68589c78134cc54dff016c83367912eb055637fa50cAlan Cox} 68689c78134cc54dff016c83367912eb055637fa50cAlan Cox 68789c78134cc54dff016c83367912eb055637fa50cAlan Coxconst struct drm_encoder_funcs psb_intel_lvds_enc_funcs = { 68889c78134cc54dff016c83367912eb055637fa50cAlan Cox .destroy = psb_intel_lvds_enc_destroy, 68989c78134cc54dff016c83367912eb055637fa50cAlan Cox}; 69089c78134cc54dff016c83367912eb055637fa50cAlan Cox 69189c78134cc54dff016c83367912eb055637fa50cAlan Cox 69289c78134cc54dff016c83367912eb055637fa50cAlan Cox 69389c78134cc54dff016c83367912eb055637fa50cAlan Cox/** 69489c78134cc54dff016c83367912eb055637fa50cAlan Cox * psb_intel_lvds_init - setup LVDS connectors on this device 69589c78134cc54dff016c83367912eb055637fa50cAlan Cox * @dev: drm device 69689c78134cc54dff016c83367912eb055637fa50cAlan Cox * 69789c78134cc54dff016c83367912eb055637fa50cAlan Cox * Create the connector, register the LVDS DDC bus, and try to figure out what 69889c78134cc54dff016c83367912eb055637fa50cAlan Cox * modes we can display on the LVDS panel (if present). 69989c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 70089c78134cc54dff016c83367912eb055637fa50cAlan Coxvoid psb_intel_lvds_init(struct drm_device *dev, 7019c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct psb_intel_mode_device *mode_dev) 70289c78134cc54dff016c83367912eb055637fa50cAlan Cox{ 7039c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct psb_intel_encoder *psb_intel_encoder; 7049c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson struct psb_intel_connector *psb_intel_connector; 70589c78134cc54dff016c83367912eb055637fa50cAlan Cox struct psb_intel_lvds_priv *lvds_priv; 70689c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_connector *connector; 70789c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_encoder *encoder; 70889c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_display_mode *scan; /* *modes, *bios_mode; */ 70989c78134cc54dff016c83367912eb055637fa50cAlan Cox struct drm_crtc *crtc; 7101f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox struct drm_psb_private *dev_priv = dev->dev_private; 71189c78134cc54dff016c83367912eb055637fa50cAlan Cox u32 lvds; 71289c78134cc54dff016c83367912eb055637fa50cAlan Cox int pipe; 71389c78134cc54dff016c83367912eb055637fa50cAlan Cox 7149c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson psb_intel_encoder = 7159c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson kzalloc(sizeof(struct psb_intel_encoder), GFP_KERNEL); 7169c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson if (!psb_intel_encoder) { 7179c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson dev_err(dev->dev, "psb_intel_encoder allocation error\n"); 71889c78134cc54dff016c83367912eb055637fa50cAlan Cox return; 7199c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson } 7209c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson 7219c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson psb_intel_connector = 7229c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson kzalloc(sizeof(struct psb_intel_connector), GFP_KERNEL); 7239c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson if (!psb_intel_connector) { 7249c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson dev_err(dev->dev, "psb_intel_connector allocation error\n"); 725aa7c62af10b6ba7f0496ee3a1a760ad216426720Jesper Juhl goto failed_encoder; 7269c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson } 72789c78134cc54dff016c83367912eb055637fa50cAlan Cox 72889c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds_priv = kzalloc(sizeof(struct psb_intel_lvds_priv), GFP_KERNEL); 72989c78134cc54dff016c83367912eb055637fa50cAlan Cox if (!lvds_priv) { 73089c78134cc54dff016c83367912eb055637fa50cAlan Cox dev_err(dev->dev, "LVDS private allocation error\n"); 7319c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson goto failed_connector; 73289c78134cc54dff016c83367912eb055637fa50cAlan Cox } 73389c78134cc54dff016c83367912eb055637fa50cAlan Cox 7349c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson psb_intel_encoder->dev_priv = lvds_priv; 7351f0d0b5183c8dd4d58678e8ba35553cabaf87390Alan Cox 7369c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson connector = &psb_intel_connector->base; 7379c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson encoder = &psb_intel_encoder->base; 7389c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson drm_connector_init(dev, connector, 73989c78134cc54dff016c83367912eb055637fa50cAlan Cox &psb_intel_lvds_connector_funcs, 74089c78134cc54dff016c83367912eb055637fa50cAlan Cox DRM_MODE_CONNECTOR_LVDS); 74189c78134cc54dff016c83367912eb055637fa50cAlan Cox 7429c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson drm_encoder_init(dev, encoder, 74389c78134cc54dff016c83367912eb055637fa50cAlan Cox &psb_intel_lvds_enc_funcs, 74489c78134cc54dff016c83367912eb055637fa50cAlan Cox DRM_MODE_ENCODER_LVDS); 74589c78134cc54dff016c83367912eb055637fa50cAlan Cox 7469c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson psb_intel_connector_attach_encoder(psb_intel_connector, 7479c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson psb_intel_encoder); 7489c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson psb_intel_encoder->type = INTEL_OUTPUT_LVDS; 74989c78134cc54dff016c83367912eb055637fa50cAlan Cox 75089c78134cc54dff016c83367912eb055637fa50cAlan Cox drm_encoder_helper_add(encoder, &psb_intel_lvds_helper_funcs); 75189c78134cc54dff016c83367912eb055637fa50cAlan Cox drm_connector_helper_add(connector, 75289c78134cc54dff016c83367912eb055637fa50cAlan Cox &psb_intel_lvds_connector_helper_funcs); 75389c78134cc54dff016c83367912eb055637fa50cAlan Cox connector->display_info.subpixel_order = SubPixelHorizontalRGB; 75489c78134cc54dff016c83367912eb055637fa50cAlan Cox connector->interlace_allowed = false; 75589c78134cc54dff016c83367912eb055637fa50cAlan Cox connector->doublescan_allowed = false; 75689c78134cc54dff016c83367912eb055637fa50cAlan Cox 75789c78134cc54dff016c83367912eb055637fa50cAlan Cox /*Attach connector properties*/ 75889c78134cc54dff016c83367912eb055637fa50cAlan Cox drm_connector_attach_property(connector, 75989c78134cc54dff016c83367912eb055637fa50cAlan Cox dev->mode_config.scaling_mode_property, 76089c78134cc54dff016c83367912eb055637fa50cAlan Cox DRM_MODE_SCALE_FULLSCREEN); 76189c78134cc54dff016c83367912eb055637fa50cAlan Cox drm_connector_attach_property(connector, 76289c78134cc54dff016c83367912eb055637fa50cAlan Cox dev_priv->backlight_property, 76389c78134cc54dff016c83367912eb055637fa50cAlan Cox BRIGHTNESS_MAX_LEVEL); 76489c78134cc54dff016c83367912eb055637fa50cAlan Cox 76589c78134cc54dff016c83367912eb055637fa50cAlan Cox /* 76689c78134cc54dff016c83367912eb055637fa50cAlan Cox * Set up I2C bus 76789c78134cc54dff016c83367912eb055637fa50cAlan Cox * FIXME: distroy i2c_bus when exit 76889c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 7699c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson lvds_priv->i2c_bus = psb_intel_i2c_create(dev, GPIOB, "LVDSBLC_B"); 7709c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson if (!lvds_priv->i2c_bus) { 77189c78134cc54dff016c83367912eb055637fa50cAlan Cox dev_printk(KERN_ERR, 77289c78134cc54dff016c83367912eb055637fa50cAlan Cox &dev->pdev->dev, "I2C bus registration failed.\n"); 77389c78134cc54dff016c83367912eb055637fa50cAlan Cox goto failed_blc_i2c; 77489c78134cc54dff016c83367912eb055637fa50cAlan Cox } 7759c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson lvds_priv->i2c_bus->slave_addr = 0x2C; 7769c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson dev_priv->lvds_i2c_bus = lvds_priv->i2c_bus; 77789c78134cc54dff016c83367912eb055637fa50cAlan Cox 77889c78134cc54dff016c83367912eb055637fa50cAlan Cox /* 77989c78134cc54dff016c83367912eb055637fa50cAlan Cox * LVDS discovery: 78089c78134cc54dff016c83367912eb055637fa50cAlan Cox * 1) check for EDID on DDC 78189c78134cc54dff016c83367912eb055637fa50cAlan Cox * 2) check for VBT data 78289c78134cc54dff016c83367912eb055637fa50cAlan Cox * 3) check to see if LVDS is already on 78389c78134cc54dff016c83367912eb055637fa50cAlan Cox * if none of the above, no panel 78489c78134cc54dff016c83367912eb055637fa50cAlan Cox * 4) make sure lid is open 78589c78134cc54dff016c83367912eb055637fa50cAlan Cox * if closed, act like it's not there for now 78689c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 78789c78134cc54dff016c83367912eb055637fa50cAlan Cox 78889c78134cc54dff016c83367912eb055637fa50cAlan Cox /* Set up the DDC bus. */ 7899c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson lvds_priv->ddc_bus = psb_intel_i2c_create(dev, GPIOC, "LVDSDDC_C"); 7909c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson if (!lvds_priv->ddc_bus) { 79189c78134cc54dff016c83367912eb055637fa50cAlan Cox dev_printk(KERN_ERR, &dev->pdev->dev, 79289c78134cc54dff016c83367912eb055637fa50cAlan Cox "DDC bus registration " "failed.\n"); 79389c78134cc54dff016c83367912eb055637fa50cAlan Cox goto failed_ddc; 79489c78134cc54dff016c83367912eb055637fa50cAlan Cox } 79589c78134cc54dff016c83367912eb055637fa50cAlan Cox 79689c78134cc54dff016c83367912eb055637fa50cAlan Cox /* 79789c78134cc54dff016c83367912eb055637fa50cAlan Cox * Attempt to get the fixed panel mode from DDC. Assume that the 79889c78134cc54dff016c83367912eb055637fa50cAlan Cox * preferred mode is the right one. 79989c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 8009c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson psb_intel_ddc_get_modes(connector, &lvds_priv->ddc_bus->adapter); 80189c78134cc54dff016c83367912eb055637fa50cAlan Cox list_for_each_entry(scan, &connector->probed_modes, head) { 80289c78134cc54dff016c83367912eb055637fa50cAlan Cox if (scan->type & DRM_MODE_TYPE_PREFERRED) { 80389c78134cc54dff016c83367912eb055637fa50cAlan Cox mode_dev->panel_fixed_mode = 80489c78134cc54dff016c83367912eb055637fa50cAlan Cox drm_mode_duplicate(dev, scan); 80589c78134cc54dff016c83367912eb055637fa50cAlan Cox goto out; /* FIXME: check for quirks */ 80689c78134cc54dff016c83367912eb055637fa50cAlan Cox } 80789c78134cc54dff016c83367912eb055637fa50cAlan Cox } 80889c78134cc54dff016c83367912eb055637fa50cAlan Cox 80989c78134cc54dff016c83367912eb055637fa50cAlan Cox /* Failed to get EDID, what about VBT? do we need this? */ 81089c78134cc54dff016c83367912eb055637fa50cAlan Cox if (mode_dev->vbt_mode) 81189c78134cc54dff016c83367912eb055637fa50cAlan Cox mode_dev->panel_fixed_mode = 81289c78134cc54dff016c83367912eb055637fa50cAlan Cox drm_mode_duplicate(dev, mode_dev->vbt_mode); 81389c78134cc54dff016c83367912eb055637fa50cAlan Cox 81489c78134cc54dff016c83367912eb055637fa50cAlan Cox if (!mode_dev->panel_fixed_mode) 81589c78134cc54dff016c83367912eb055637fa50cAlan Cox if (dev_priv->lfp_lvds_vbt_mode) 81689c78134cc54dff016c83367912eb055637fa50cAlan Cox mode_dev->panel_fixed_mode = 81789c78134cc54dff016c83367912eb055637fa50cAlan Cox drm_mode_duplicate(dev, 81889c78134cc54dff016c83367912eb055637fa50cAlan Cox dev_priv->lfp_lvds_vbt_mode); 81989c78134cc54dff016c83367912eb055637fa50cAlan Cox 82089c78134cc54dff016c83367912eb055637fa50cAlan Cox /* 82189c78134cc54dff016c83367912eb055637fa50cAlan Cox * If we didn't get EDID, try checking if the panel is already turned 82289c78134cc54dff016c83367912eb055637fa50cAlan Cox * on. If so, assume that whatever is currently programmed is the 82389c78134cc54dff016c83367912eb055637fa50cAlan Cox * correct mode. 82489c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 82589c78134cc54dff016c83367912eb055637fa50cAlan Cox lvds = REG_READ(LVDS); 82689c78134cc54dff016c83367912eb055637fa50cAlan Cox pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; 82789c78134cc54dff016c83367912eb055637fa50cAlan Cox crtc = psb_intel_get_crtc_from_pipe(dev, pipe); 82889c78134cc54dff016c83367912eb055637fa50cAlan Cox 82989c78134cc54dff016c83367912eb055637fa50cAlan Cox if (crtc && (lvds & LVDS_PORT_EN)) { 83089c78134cc54dff016c83367912eb055637fa50cAlan Cox mode_dev->panel_fixed_mode = 83189c78134cc54dff016c83367912eb055637fa50cAlan Cox psb_intel_crtc_mode_get(dev, crtc); 83289c78134cc54dff016c83367912eb055637fa50cAlan Cox if (mode_dev->panel_fixed_mode) { 83389c78134cc54dff016c83367912eb055637fa50cAlan Cox mode_dev->panel_fixed_mode->type |= 83489c78134cc54dff016c83367912eb055637fa50cAlan Cox DRM_MODE_TYPE_PREFERRED; 83589c78134cc54dff016c83367912eb055637fa50cAlan Cox goto out; /* FIXME: check for quirks */ 83689c78134cc54dff016c83367912eb055637fa50cAlan Cox } 83789c78134cc54dff016c83367912eb055637fa50cAlan Cox } 83889c78134cc54dff016c83367912eb055637fa50cAlan Cox 83989c78134cc54dff016c83367912eb055637fa50cAlan Cox /* If we still don't have a mode after all that, give up. */ 84089c78134cc54dff016c83367912eb055637fa50cAlan Cox if (!mode_dev->panel_fixed_mode) { 84189c78134cc54dff016c83367912eb055637fa50cAlan Cox dev_err(dev->dev, "Found no modes on the lvds, ignoring the LVDS\n"); 84289c78134cc54dff016c83367912eb055637fa50cAlan Cox goto failed_find; 84389c78134cc54dff016c83367912eb055637fa50cAlan Cox } 84489c78134cc54dff016c83367912eb055637fa50cAlan Cox 84589c78134cc54dff016c83367912eb055637fa50cAlan Cox /* 84689c78134cc54dff016c83367912eb055637fa50cAlan Cox * Blacklist machines with BIOSes that list an LVDS panel without 84789c78134cc54dff016c83367912eb055637fa50cAlan Cox * actually having one. 84889c78134cc54dff016c83367912eb055637fa50cAlan Cox */ 84989c78134cc54dff016c83367912eb055637fa50cAlan Coxout: 85089c78134cc54dff016c83367912eb055637fa50cAlan Cox drm_sysfs_connector_add(connector); 85189c78134cc54dff016c83367912eb055637fa50cAlan Cox return; 85289c78134cc54dff016c83367912eb055637fa50cAlan Cox 85389c78134cc54dff016c83367912eb055637fa50cAlan Coxfailed_find: 8549c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson if (lvds_priv->ddc_bus) 8559c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson psb_intel_i2c_destroy(lvds_priv->ddc_bus); 85689c78134cc54dff016c83367912eb055637fa50cAlan Coxfailed_ddc: 8579c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson if (lvds_priv->i2c_bus) 8589c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobsson psb_intel_i2c_destroy(lvds_priv->i2c_bus); 85989c78134cc54dff016c83367912eb055637fa50cAlan Coxfailed_blc_i2c: 86089c78134cc54dff016c83367912eb055637fa50cAlan Cox drm_encoder_cleanup(encoder); 86189c78134cc54dff016c83367912eb055637fa50cAlan Cox drm_connector_cleanup(connector); 8629c8cee471392258271bdf36361903d306a0c2dd6Patrik Jakobssonfailed_connector: 863aa7c62af10b6ba7f0496ee3a1a760ad216426720Jesper Juhl kfree(psb_intel_connector); 864aa7c62af10b6ba7f0496ee3a1a760ad216426720Jesper Juhlfailed_encoder: 865aa7c62af10b6ba7f0496ee3a1a760ad216426720Jesper Juhl kfree(psb_intel_encoder); 86689c78134cc54dff016c83367912eb055637fa50cAlan Cox} 86789c78134cc54dff016c83367912eb055637fa50cAlan Cox 868