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