xref: /openbmc/linux/drivers/gpu/drm/gma500/psb_intel_lvds.c (revision 7e24a55b2122746c2eef192296fc84624354f895)
1a61127c2SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
289c78134SAlan Cox /*
389c78134SAlan Cox  * Copyright © 2006-2007 Intel Corporation
489c78134SAlan Cox  *
589c78134SAlan Cox  * Authors:
689c78134SAlan Cox  *	Eric Anholt <eric@anholt.net>
789c78134SAlan Cox  *	Dave Airlie <airlied@linux.ie>
889c78134SAlan Cox  *	Jesse Barnes <jesse.barnes@intel.com>
989c78134SAlan Cox  */
1089c78134SAlan Cox 
1189c78134SAlan Cox #include <linux/i2c.h>
120c7b178aSSam Ravnborg #include <linux/pm_runtime.h>
1389c78134SAlan Cox 
143599dfa1SThomas Zimmermann #include <drm/drm_crtc_helper.h>
153599dfa1SThomas Zimmermann #include <drm/drm_modeset_helper_vtables.h>
16d088b69fSThomas Zimmermann #include <drm/drm_simple_kms_helper.h>
17d088b69fSThomas Zimmermann 
1889c78134SAlan Cox #include "intel_bios.h"
190c7b178aSSam Ravnborg #include "power.h"
2089c78134SAlan Cox #include "psb_drv.h"
2189c78134SAlan Cox #include "psb_intel_drv.h"
2289c78134SAlan Cox #include "psb_intel_reg.h"
2389c78134SAlan Cox 
2489c78134SAlan Cox /*
2589c78134SAlan Cox  * LVDS I2C backlight control macros
2689c78134SAlan Cox  */
2789c78134SAlan Cox #define BRIGHTNESS_MAX_LEVEL 100
2889c78134SAlan Cox #define BRIGHTNESS_MASK 0xFF
2989c78134SAlan Cox #define BLC_I2C_TYPE	0x01
3089c78134SAlan Cox #define BLC_PWM_TYPT	0x02
3189c78134SAlan Cox 
3289c78134SAlan Cox #define BLC_POLARITY_NORMAL 0
3389c78134SAlan Cox #define BLC_POLARITY_INVERSE 1
3489c78134SAlan Cox 
3589c78134SAlan Cox #define PSB_BLC_MAX_PWM_REG_FREQ       (0xFFFE)
3689c78134SAlan Cox #define PSB_BLC_MIN_PWM_REG_FREQ	(0x2)
3789c78134SAlan Cox #define PSB_BLC_PWM_PRECISION_FACTOR	(10)
3889c78134SAlan Cox #define PSB_BACKLIGHT_PWM_CTL_SHIFT	(16)
3989c78134SAlan Cox #define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE)
4089c78134SAlan Cox 
4189c78134SAlan Cox struct psb_intel_lvds_priv {
4289c78134SAlan Cox 	/*
4389c78134SAlan Cox 	 * Saved LVDO output states
4489c78134SAlan Cox 	 */
4589c78134SAlan Cox 	uint32_t savePP_ON;
4689c78134SAlan Cox 	uint32_t savePP_OFF;
4789c78134SAlan Cox 	uint32_t saveLVDS;
4889c78134SAlan Cox 	uint32_t savePP_CONTROL;
4989c78134SAlan Cox 	uint32_t savePP_CYCLE;
5089c78134SAlan Cox 	uint32_t savePFIT_CONTROL;
5189c78134SAlan Cox 	uint32_t savePFIT_PGM_RATIOS;
5289c78134SAlan Cox 	uint32_t saveBLC_PWM_CTL;
539c8cee47SPatrik Jakobsson 
5404477e5eSPatrik Jakobsson 	struct gma_i2c_chan *i2c_bus;
5589c78134SAlan Cox };
5689c78134SAlan Cox 
5789c78134SAlan Cox 
5889c78134SAlan Cox /*
5989c78134SAlan Cox  * Returns the maximum level of the backlight duty cycle field.
6089c78134SAlan Cox  */
psb_intel_lvds_get_max_backlight(struct drm_device * dev)6189c78134SAlan Cox static u32 psb_intel_lvds_get_max_backlight(struct drm_device *dev)
6289c78134SAlan Cox {
63f71635e8SThomas Zimmermann 	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
641f0d0b51SAlan Cox 	u32 ret;
6589c78134SAlan Cox 
6689c78134SAlan Cox 	if (gma_power_begin(dev, false)) {
671f0d0b51SAlan Cox 		ret = REG_READ(BLC_PWM_CTL);
6889c78134SAlan Cox 		gma_power_end(dev);
691f0d0b51SAlan Cox 	} else /* Powered off, use the saved value */
70648a8e34SAlan Cox 		ret = dev_priv->regs.saveBLC_PWM_CTL;
7189c78134SAlan Cox 
721f0d0b51SAlan Cox 	/* Top 15bits hold the frequency mask */
731f0d0b51SAlan Cox 	ret = (ret &  BACKLIGHT_MODULATION_FREQ_MASK) >>
741f0d0b51SAlan Cox 					BACKLIGHT_MODULATION_FREQ_SHIFT;
751f0d0b51SAlan Cox 
761f0d0b51SAlan Cox         ret *= 2;	/* Return a 16bit range as needed for setting */
771f0d0b51SAlan Cox         if (ret == 0)
781f0d0b51SAlan Cox                 dev_err(dev->dev, "BL bug: Reg %08x save %08X\n",
79648a8e34SAlan Cox                         REG_READ(BLC_PWM_CTL), dev_priv->regs.saveBLC_PWM_CTL);
801f0d0b51SAlan Cox 	return ret;
8189c78134SAlan Cox }
8289c78134SAlan Cox 
8389c78134SAlan Cox /*
8489c78134SAlan Cox  * Set LVDS backlight level by I2C command
8589c78134SAlan Cox  *
8689c78134SAlan Cox  * FIXME: at some point we need to both track this for PM and also
8789c78134SAlan Cox  * disable runtime pm on MRST if the brightness is nil (ie blanked)
8889c78134SAlan Cox  */
psb_lvds_i2c_set_brightness(struct drm_device * dev,unsigned int level)8989c78134SAlan Cox static int psb_lvds_i2c_set_brightness(struct drm_device *dev,
9089c78134SAlan Cox 					unsigned int level)
9189c78134SAlan Cox {
92f71635e8SThomas Zimmermann 	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
9389c78134SAlan Cox 
9404477e5eSPatrik Jakobsson 	struct gma_i2c_chan *lvds_i2c_bus = dev_priv->lvds_i2c_bus;
9589c78134SAlan Cox 	u8 out_buf[2];
9689c78134SAlan Cox 	unsigned int blc_i2c_brightness;
9789c78134SAlan Cox 
9889c78134SAlan Cox 	struct i2c_msg msgs[] = {
9989c78134SAlan Cox 		{
10089c78134SAlan Cox 			.addr = lvds_i2c_bus->slave_addr,
10189c78134SAlan Cox 			.flags = 0,
10289c78134SAlan Cox 			.len = 2,
10389c78134SAlan Cox 			.buf = out_buf,
10489c78134SAlan Cox 		}
10589c78134SAlan Cox 	};
10689c78134SAlan Cox 
10789c78134SAlan Cox 	blc_i2c_brightness = BRIGHTNESS_MASK & ((unsigned int)level *
10889c78134SAlan Cox 			     BRIGHTNESS_MASK /
10989c78134SAlan Cox 			     BRIGHTNESS_MAX_LEVEL);
11089c78134SAlan Cox 
11189c78134SAlan Cox 	if (dev_priv->lvds_bl->pol == BLC_POLARITY_INVERSE)
11289c78134SAlan Cox 		blc_i2c_brightness = BRIGHTNESS_MASK - blc_i2c_brightness;
11389c78134SAlan Cox 
11489c78134SAlan Cox 	out_buf[0] = dev_priv->lvds_bl->brightnesscmd;
11589c78134SAlan Cox 	out_buf[1] = (u8)blc_i2c_brightness;
11689c78134SAlan Cox 
117ba1677f7SPatrik Jakobsson 	if (i2c_transfer(&lvds_i2c_bus->base, msgs, 1) == 1) {
11889c78134SAlan Cox 		dev_dbg(dev->dev, "I2C set brightness.(command, value) (%d, %d)\n",
11989c78134SAlan Cox 			dev_priv->lvds_bl->brightnesscmd,
12089c78134SAlan Cox 			blc_i2c_brightness);
12189c78134SAlan Cox 		return 0;
12289c78134SAlan Cox 	}
12389c78134SAlan Cox 
12489c78134SAlan Cox 	dev_err(dev->dev, "I2C transfer error\n");
12589c78134SAlan Cox 	return -1;
12689c78134SAlan Cox }
12789c78134SAlan Cox 
12889c78134SAlan Cox 
psb_lvds_pwm_set_brightness(struct drm_device * dev,int level)12989c78134SAlan Cox static int psb_lvds_pwm_set_brightness(struct drm_device *dev, int level)
13089c78134SAlan Cox {
131f71635e8SThomas Zimmermann 	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
13289c78134SAlan Cox 
13389c78134SAlan Cox 	u32 max_pwm_blc;
13489c78134SAlan Cox 	u32 blc_pwm_duty_cycle;
13589c78134SAlan Cox 
13689c78134SAlan Cox 	max_pwm_blc = psb_intel_lvds_get_max_backlight(dev);
13789c78134SAlan Cox 
13889c78134SAlan Cox 	/*BLC_PWM_CTL Should be initiated while backlight device init*/
1391f0d0b51SAlan Cox 	BUG_ON(max_pwm_blc == 0);
14089c78134SAlan Cox 
14189c78134SAlan Cox 	blc_pwm_duty_cycle = level * max_pwm_blc / BRIGHTNESS_MAX_LEVEL;
14289c78134SAlan Cox 
14389c78134SAlan Cox 	if (dev_priv->lvds_bl->pol == BLC_POLARITY_INVERSE)
14489c78134SAlan Cox 		blc_pwm_duty_cycle = max_pwm_blc - blc_pwm_duty_cycle;
14589c78134SAlan Cox 
14689c78134SAlan Cox 	blc_pwm_duty_cycle &= PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR;
14789c78134SAlan Cox 	REG_WRITE(BLC_PWM_CTL,
14889c78134SAlan Cox 		  (max_pwm_blc << PSB_BACKLIGHT_PWM_CTL_SHIFT) |
14989c78134SAlan Cox 		  (blc_pwm_duty_cycle));
15089c78134SAlan Cox 
1511f0d0b51SAlan Cox         dev_info(dev->dev, "Backlight lvds set brightness %08x\n",
1521f0d0b51SAlan Cox 		  (max_pwm_blc << PSB_BACKLIGHT_PWM_CTL_SHIFT) |
1531f0d0b51SAlan Cox 		  (blc_pwm_duty_cycle));
1541f0d0b51SAlan Cox 
15589c78134SAlan Cox 	return 0;
15689c78134SAlan Cox }
15789c78134SAlan Cox 
15889c78134SAlan Cox /*
15989c78134SAlan Cox  * Set LVDS backlight level either by I2C or PWM
16089c78134SAlan Cox  */
psb_intel_lvds_set_brightness(struct drm_device * dev,int level)16189c78134SAlan Cox void psb_intel_lvds_set_brightness(struct drm_device *dev, int level)
16289c78134SAlan Cox {
163f71635e8SThomas Zimmermann 	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
16489c78134SAlan Cox 
16589c78134SAlan Cox 	dev_dbg(dev->dev, "backlight level is %d\n", level);
16689c78134SAlan Cox 
16789c78134SAlan Cox 	if (!dev_priv->lvds_bl) {
1681f0d0b51SAlan Cox 		dev_err(dev->dev, "NO LVDS backlight info\n");
16989c78134SAlan Cox 		return;
17089c78134SAlan Cox 	}
17189c78134SAlan Cox 
17289c78134SAlan Cox 	if (dev_priv->lvds_bl->type == BLC_I2C_TYPE)
17389c78134SAlan Cox 		psb_lvds_i2c_set_brightness(dev, level);
17489c78134SAlan Cox 	else
17589c78134SAlan Cox 		psb_lvds_pwm_set_brightness(dev, level);
17689c78134SAlan Cox }
17789c78134SAlan Cox 
17889c78134SAlan Cox /*
17989c78134SAlan Cox  * Sets the backlight level.
18089c78134SAlan Cox  *
18189c78134SAlan Cox  * level: backlight level, from 0 to psb_intel_lvds_get_max_backlight().
18289c78134SAlan Cox  */
psb_intel_lvds_set_backlight(struct drm_device * dev,int level)18389c78134SAlan Cox static void psb_intel_lvds_set_backlight(struct drm_device *dev, int level)
18489c78134SAlan Cox {
185f71635e8SThomas Zimmermann 	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
18689c78134SAlan Cox 	u32 blc_pwm_ctl;
18789c78134SAlan Cox 
18889c78134SAlan Cox 	if (gma_power_begin(dev, false)) {
1891f0d0b51SAlan Cox 		blc_pwm_ctl = REG_READ(BLC_PWM_CTL);
1901f0d0b51SAlan Cox 		blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK;
19189c78134SAlan Cox 		REG_WRITE(BLC_PWM_CTL,
19289c78134SAlan Cox 				(blc_pwm_ctl |
19389c78134SAlan Cox 				(level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
194648a8e34SAlan Cox 		dev_priv->regs.saveBLC_PWM_CTL = (blc_pwm_ctl |
1951f0d0b51SAlan Cox 					(level << BACKLIGHT_DUTY_CYCLE_SHIFT));
19689c78134SAlan Cox 		gma_power_end(dev);
19789c78134SAlan Cox 	} else {
198648a8e34SAlan Cox 		blc_pwm_ctl = dev_priv->regs.saveBLC_PWM_CTL &
19989c78134SAlan Cox 				~BACKLIGHT_DUTY_CYCLE_MASK;
200648a8e34SAlan Cox 		dev_priv->regs.saveBLC_PWM_CTL = (blc_pwm_ctl |
20189c78134SAlan Cox 					(level << BACKLIGHT_DUTY_CYCLE_SHIFT));
20289c78134SAlan Cox 	}
20389c78134SAlan Cox }
20489c78134SAlan Cox 
20589c78134SAlan Cox /*
20689c78134SAlan Cox  * Sets the power state for the panel.
20789c78134SAlan Cox  */
psb_intel_lvds_set_power(struct drm_device * dev,bool on)2089c8cee47SPatrik Jakobsson static void psb_intel_lvds_set_power(struct drm_device *dev, bool on)
20989c78134SAlan Cox {
210f71635e8SThomas Zimmermann 	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
2119c8cee47SPatrik Jakobsson 	struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev;
21289c78134SAlan Cox 	u32 pp_status;
21389c78134SAlan Cox 
2141f0d0b51SAlan Cox 	if (!gma_power_begin(dev, true)) {
2151f0d0b51SAlan Cox 	        dev_err(dev->dev, "set power, chip off!\n");
21689c78134SAlan Cox 		return;
2171f0d0b51SAlan Cox         }
21889c78134SAlan Cox 
21989c78134SAlan Cox 	if (on) {
22089c78134SAlan Cox 		REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) |
22189c78134SAlan Cox 			  POWER_TARGET_ON);
22289c78134SAlan Cox 		do {
22389c78134SAlan Cox 			pp_status = REG_READ(PP_STATUS);
22489c78134SAlan Cox 		} while ((pp_status & PP_ON) == 0);
22589c78134SAlan Cox 
22689c78134SAlan Cox 		psb_intel_lvds_set_backlight(dev,
22789c78134SAlan Cox 					     mode_dev->backlight_duty_cycle);
22889c78134SAlan Cox 	} else {
22989c78134SAlan Cox 		psb_intel_lvds_set_backlight(dev, 0);
23089c78134SAlan Cox 
23189c78134SAlan Cox 		REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) &
23289c78134SAlan Cox 			  ~POWER_TARGET_ON);
23389c78134SAlan Cox 		do {
23489c78134SAlan Cox 			pp_status = REG_READ(PP_STATUS);
23589c78134SAlan Cox 		} while (pp_status & PP_ON);
23689c78134SAlan Cox 	}
23789c78134SAlan Cox 
23889c78134SAlan Cox 	gma_power_end(dev);
23989c78134SAlan Cox }
24089c78134SAlan Cox 
psb_intel_lvds_encoder_dpms(struct drm_encoder * encoder,int mode)24189c78134SAlan Cox static void psb_intel_lvds_encoder_dpms(struct drm_encoder *encoder, int mode)
24289c78134SAlan Cox {
24389c78134SAlan Cox 	struct drm_device *dev = encoder->dev;
24489c78134SAlan Cox 
24589c78134SAlan Cox 	if (mode == DRM_MODE_DPMS_ON)
2469c8cee47SPatrik Jakobsson 		psb_intel_lvds_set_power(dev, true);
24789c78134SAlan Cox 	else
2489c8cee47SPatrik Jakobsson 		psb_intel_lvds_set_power(dev, false);
24989c78134SAlan Cox 
25089c78134SAlan Cox 	/* XXX: We never power down the LVDS pairs. */
25189c78134SAlan Cox }
25289c78134SAlan Cox 
psb_intel_lvds_save(struct drm_connector * connector)25389c78134SAlan Cox static void psb_intel_lvds_save(struct drm_connector *connector)
25489c78134SAlan Cox {
25589c78134SAlan Cox 	struct drm_device *dev = connector->dev;
256f71635e8SThomas Zimmermann 	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
257367e4408SPatrik Jakobsson 	struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
25889c78134SAlan Cox 	struct psb_intel_lvds_priv *lvds_priv =
259367e4408SPatrik Jakobsson 		(struct psb_intel_lvds_priv *)gma_encoder->dev_priv;
26089c78134SAlan Cox 
26189c78134SAlan Cox 	lvds_priv->savePP_ON = REG_READ(LVDSPP_ON);
26289c78134SAlan Cox 	lvds_priv->savePP_OFF = REG_READ(LVDSPP_OFF);
26389c78134SAlan Cox 	lvds_priv->saveLVDS = REG_READ(LVDS);
26489c78134SAlan Cox 	lvds_priv->savePP_CONTROL = REG_READ(PP_CONTROL);
26589c78134SAlan Cox 	lvds_priv->savePP_CYCLE = REG_READ(PP_CYCLE);
26689c78134SAlan Cox 	/*lvds_priv->savePP_DIVISOR = REG_READ(PP_DIVISOR);*/
26789c78134SAlan Cox 	lvds_priv->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL);
26889c78134SAlan Cox 	lvds_priv->savePFIT_CONTROL = REG_READ(PFIT_CONTROL);
26989c78134SAlan Cox 	lvds_priv->savePFIT_PGM_RATIOS = REG_READ(PFIT_PGM_RATIOS);
27089c78134SAlan Cox 
27189c78134SAlan Cox 	/*TODO: move backlight_duty_cycle to psb_intel_lvds_priv*/
272648a8e34SAlan Cox 	dev_priv->backlight_duty_cycle = (dev_priv->regs.saveBLC_PWM_CTL &
27389c78134SAlan Cox 						BACKLIGHT_DUTY_CYCLE_MASK);
27489c78134SAlan Cox 
27589c78134SAlan Cox 	/*
27689c78134SAlan Cox 	 * If the light is off at server startup,
27789c78134SAlan Cox 	 * just make it full brightness
27889c78134SAlan Cox 	 */
27989c78134SAlan Cox 	if (dev_priv->backlight_duty_cycle == 0)
28089c78134SAlan Cox 		dev_priv->backlight_duty_cycle =
28189c78134SAlan Cox 		psb_intel_lvds_get_max_backlight(dev);
28289c78134SAlan Cox 
28389c78134SAlan Cox 	dev_dbg(dev->dev, "(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
28489c78134SAlan Cox 			lvds_priv->savePP_ON,
28589c78134SAlan Cox 			lvds_priv->savePP_OFF,
28689c78134SAlan Cox 			lvds_priv->saveLVDS,
28789c78134SAlan Cox 			lvds_priv->savePP_CONTROL,
28889c78134SAlan Cox 			lvds_priv->savePP_CYCLE,
28989c78134SAlan Cox 			lvds_priv->saveBLC_PWM_CTL);
29089c78134SAlan Cox }
29189c78134SAlan Cox 
psb_intel_lvds_restore(struct drm_connector * connector)29289c78134SAlan Cox static void psb_intel_lvds_restore(struct drm_connector *connector)
29389c78134SAlan Cox {
29489c78134SAlan Cox 	struct drm_device *dev = connector->dev;
29589c78134SAlan Cox 	u32 pp_status;
296367e4408SPatrik Jakobsson 	struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
29789c78134SAlan Cox 	struct psb_intel_lvds_priv *lvds_priv =
298367e4408SPatrik Jakobsson 		(struct psb_intel_lvds_priv *)gma_encoder->dev_priv;
29989c78134SAlan Cox 
30089c78134SAlan Cox 	dev_dbg(dev->dev, "(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
30189c78134SAlan Cox 			lvds_priv->savePP_ON,
30289c78134SAlan Cox 			lvds_priv->savePP_OFF,
30389c78134SAlan Cox 			lvds_priv->saveLVDS,
30489c78134SAlan Cox 			lvds_priv->savePP_CONTROL,
30589c78134SAlan Cox 			lvds_priv->savePP_CYCLE,
30689c78134SAlan Cox 			lvds_priv->saveBLC_PWM_CTL);
30789c78134SAlan Cox 
30889c78134SAlan Cox 	REG_WRITE(BLC_PWM_CTL, lvds_priv->saveBLC_PWM_CTL);
30989c78134SAlan Cox 	REG_WRITE(PFIT_CONTROL, lvds_priv->savePFIT_CONTROL);
31089c78134SAlan Cox 	REG_WRITE(PFIT_PGM_RATIOS, lvds_priv->savePFIT_PGM_RATIOS);
31189c78134SAlan Cox 	REG_WRITE(LVDSPP_ON, lvds_priv->savePP_ON);
31289c78134SAlan Cox 	REG_WRITE(LVDSPP_OFF, lvds_priv->savePP_OFF);
31389c78134SAlan Cox 	/*REG_WRITE(PP_DIVISOR, lvds_priv->savePP_DIVISOR);*/
31489c78134SAlan Cox 	REG_WRITE(PP_CYCLE, lvds_priv->savePP_CYCLE);
31589c78134SAlan Cox 	REG_WRITE(PP_CONTROL, lvds_priv->savePP_CONTROL);
31689c78134SAlan Cox 	REG_WRITE(LVDS, lvds_priv->saveLVDS);
31789c78134SAlan Cox 
31889c78134SAlan Cox 	if (lvds_priv->savePP_CONTROL & POWER_TARGET_ON) {
31989c78134SAlan Cox 		REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) |
32089c78134SAlan Cox 			POWER_TARGET_ON);
32189c78134SAlan Cox 		do {
32289c78134SAlan Cox 			pp_status = REG_READ(PP_STATUS);
32389c78134SAlan Cox 		} while ((pp_status & PP_ON) == 0);
32489c78134SAlan Cox 	} else {
32589c78134SAlan Cox 		REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) &
32689c78134SAlan Cox 			~POWER_TARGET_ON);
32789c78134SAlan Cox 		do {
32889c78134SAlan Cox 			pp_status = REG_READ(PP_STATUS);
32989c78134SAlan Cox 		} while (pp_status & PP_ON);
33089c78134SAlan Cox 	}
33189c78134SAlan Cox }
33289c78134SAlan Cox 
psb_intel_lvds_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)3332ea00909SLuc Van Oostenryck enum drm_mode_status psb_intel_lvds_mode_valid(struct drm_connector *connector,
33489c78134SAlan Cox 				 struct drm_display_mode *mode)
33589c78134SAlan Cox {
336f71635e8SThomas Zimmermann 	struct drm_psb_private *dev_priv = to_drm_psb_private(connector->dev);
337367e4408SPatrik Jakobsson 	struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
33889c78134SAlan Cox 	struct drm_display_mode *fixed_mode =
3399c8cee47SPatrik Jakobsson 					dev_priv->mode_dev.panel_fixed_mode;
34089c78134SAlan Cox 
341367e4408SPatrik Jakobsson 	if (gma_encoder->type == INTEL_OUTPUT_MIPI2)
3429c8cee47SPatrik Jakobsson 		fixed_mode = dev_priv->mode_dev.panel_fixed_mode2;
34389c78134SAlan Cox 
34489c78134SAlan Cox 	/* just in case */
34589c78134SAlan Cox 	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
34689c78134SAlan Cox 		return MODE_NO_DBLESCAN;
34789c78134SAlan Cox 
34889c78134SAlan Cox 	/* just in case */
34989c78134SAlan Cox 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
35089c78134SAlan Cox 		return MODE_NO_INTERLACE;
35189c78134SAlan Cox 
35289c78134SAlan Cox 	if (fixed_mode) {
35389c78134SAlan Cox 		if (mode->hdisplay > fixed_mode->hdisplay)
35489c78134SAlan Cox 			return MODE_PANEL;
35589c78134SAlan Cox 		if (mode->vdisplay > fixed_mode->vdisplay)
35689c78134SAlan Cox 			return MODE_PANEL;
35789c78134SAlan Cox 	}
35889c78134SAlan Cox 	return MODE_OK;
35989c78134SAlan Cox }
36089c78134SAlan Cox 
psb_intel_lvds_mode_fixup(struct drm_encoder * encoder,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)36189c78134SAlan Cox bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder,
362e811f5aeSLaurent Pinchart 				  const struct drm_display_mode *mode,
36389c78134SAlan Cox 				  struct drm_display_mode *adjusted_mode)
36489c78134SAlan Cox {
36589c78134SAlan Cox 	struct drm_device *dev = encoder->dev;
366f71635e8SThomas Zimmermann 	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
3679c8cee47SPatrik Jakobsson 	struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev;
3686306865dSPatrik Jakobsson 	struct gma_crtc *gma_crtc = to_gma_crtc(encoder->crtc);
36989c78134SAlan Cox 	struct drm_encoder *tmp_encoder;
37089c78134SAlan Cox 	struct drm_display_mode *panel_fixed_mode = mode_dev->panel_fixed_mode;
371367e4408SPatrik Jakobsson 	struct gma_encoder *gma_encoder = to_gma_encoder(encoder);
37289c78134SAlan Cox 
373367e4408SPatrik Jakobsson 	if (gma_encoder->type == INTEL_OUTPUT_MIPI2)
37489c78134SAlan Cox 		panel_fixed_mode = mode_dev->panel_fixed_mode2;
37589c78134SAlan Cox 
37689c78134SAlan Cox 	/* PSB requires the LVDS is on pipe B, MRST has only one pipe anyway */
3776306865dSPatrik Jakobsson 	if (!IS_MRST(dev) && gma_crtc->pipe == 0) {
3788dfe162aSJoe Perches 		pr_err("Can't support LVDS on pipe A\n");
37989c78134SAlan Cox 		return false;
38089c78134SAlan Cox 	}
3816306865dSPatrik Jakobsson 	if (IS_MRST(dev) && gma_crtc->pipe != 0) {
3828dfe162aSJoe Perches 		pr_err("Must use PIPE A\n");
38389c78134SAlan Cox 		return false;
38489c78134SAlan Cox 	}
38589c78134SAlan Cox 	/* Should never happen!! */
38689c78134SAlan Cox 	list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list,
38789c78134SAlan Cox 			    head) {
38889c78134SAlan Cox 		if (tmp_encoder != encoder
38989c78134SAlan Cox 		    && tmp_encoder->crtc == encoder->crtc) {
3908dfe162aSJoe Perches 			pr_err("Can't enable LVDS and another encoder on the same pipe\n");
39189c78134SAlan Cox 			return false;
39289c78134SAlan Cox 		}
39389c78134SAlan Cox 	}
39489c78134SAlan Cox 
39589c78134SAlan Cox 	/*
39689c78134SAlan Cox 	 * If we have timings from the BIOS for the panel, put them in
39789c78134SAlan Cox 	 * to the adjusted mode.  The CRTC will be set up for this mode,
39889c78134SAlan Cox 	 * with the panel scaling set up to source from the H/VDisplay
39989c78134SAlan Cox 	 * of the original mode.
40089c78134SAlan Cox 	 */
40189c78134SAlan Cox 	if (panel_fixed_mode != NULL) {
40289c78134SAlan Cox 		adjusted_mode->hdisplay = panel_fixed_mode->hdisplay;
40389c78134SAlan Cox 		adjusted_mode->hsync_start = panel_fixed_mode->hsync_start;
40489c78134SAlan Cox 		adjusted_mode->hsync_end = panel_fixed_mode->hsync_end;
40589c78134SAlan Cox 		adjusted_mode->htotal = panel_fixed_mode->htotal;
40689c78134SAlan Cox 		adjusted_mode->vdisplay = panel_fixed_mode->vdisplay;
40789c78134SAlan Cox 		adjusted_mode->vsync_start = panel_fixed_mode->vsync_start;
40889c78134SAlan Cox 		adjusted_mode->vsync_end = panel_fixed_mode->vsync_end;
40989c78134SAlan Cox 		adjusted_mode->vtotal = panel_fixed_mode->vtotal;
41089c78134SAlan Cox 		adjusted_mode->clock = panel_fixed_mode->clock;
41189c78134SAlan Cox 		drm_mode_set_crtcinfo(adjusted_mode,
41289c78134SAlan Cox 				      CRTC_INTERLACE_HALVE_V);
41389c78134SAlan Cox 	}
41489c78134SAlan Cox 
41589c78134SAlan Cox 	/*
41689c78134SAlan Cox 	 * XXX: It would be nice to support lower refresh rates on the
41789c78134SAlan Cox 	 * panels to reduce power consumption, and perhaps match the
41889c78134SAlan Cox 	 * user's requested refresh rate.
41989c78134SAlan Cox 	 */
42089c78134SAlan Cox 
42189c78134SAlan Cox 	return true;
42289c78134SAlan Cox }
42389c78134SAlan Cox 
psb_intel_lvds_prepare(struct drm_encoder * encoder)42489c78134SAlan Cox static void psb_intel_lvds_prepare(struct drm_encoder *encoder)
42589c78134SAlan Cox {
42689c78134SAlan Cox 	struct drm_device *dev = encoder->dev;
427f71635e8SThomas Zimmermann 	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
4289c8cee47SPatrik Jakobsson 	struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev;
42989c78134SAlan Cox 
43089c78134SAlan Cox 	if (!gma_power_begin(dev, true))
43189c78134SAlan Cox 		return;
43289c78134SAlan Cox 
43389c78134SAlan Cox 	mode_dev->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL);
43489c78134SAlan Cox 	mode_dev->backlight_duty_cycle = (mode_dev->saveBLC_PWM_CTL &
43589c78134SAlan Cox 					  BACKLIGHT_DUTY_CYCLE_MASK);
43689c78134SAlan Cox 
4379c8cee47SPatrik Jakobsson 	psb_intel_lvds_set_power(dev, false);
43889c78134SAlan Cox 
43989c78134SAlan Cox 	gma_power_end(dev);
44089c78134SAlan Cox }
44189c78134SAlan Cox 
psb_intel_lvds_commit(struct drm_encoder * encoder)44289c78134SAlan Cox static void psb_intel_lvds_commit(struct drm_encoder *encoder)
44389c78134SAlan Cox {
44489c78134SAlan Cox 	struct drm_device *dev = encoder->dev;
445f71635e8SThomas Zimmermann 	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
4469c8cee47SPatrik Jakobsson 	struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev;
44789c78134SAlan Cox 
44889c78134SAlan Cox 	if (mode_dev->backlight_duty_cycle == 0)
44989c78134SAlan Cox 		mode_dev->backlight_duty_cycle =
45089c78134SAlan Cox 		    psb_intel_lvds_get_max_backlight(dev);
45189c78134SAlan Cox 
4529c8cee47SPatrik Jakobsson 	psb_intel_lvds_set_power(dev, true);
45389c78134SAlan Cox }
45489c78134SAlan Cox 
psb_intel_lvds_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)45589c78134SAlan Cox static void psb_intel_lvds_mode_set(struct drm_encoder *encoder,
45689c78134SAlan Cox 				struct drm_display_mode *mode,
45789c78134SAlan Cox 				struct drm_display_mode *adjusted_mode)
45889c78134SAlan Cox {
45989c78134SAlan Cox 	struct drm_device *dev = encoder->dev;
460f71635e8SThomas Zimmermann 	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
46189c78134SAlan Cox 	u32 pfit_control;
46289c78134SAlan Cox 
46389c78134SAlan Cox 	/*
46489c78134SAlan Cox 	 * The LVDS pin pair will already have been turned on in the
46589c78134SAlan Cox 	 * psb_intel_crtc_mode_set since it has a large impact on the DPLL
46689c78134SAlan Cox 	 * settings.
46789c78134SAlan Cox 	 */
46889c78134SAlan Cox 
46989c78134SAlan Cox 	/*
47089c78134SAlan Cox 	 * Enable automatic panel scaling so that non-native modes fill the
47189c78134SAlan Cox 	 * screen.  Should be enabled before the pipe is enabled, according to
47289c78134SAlan Cox 	 * register description and PRM.
47389c78134SAlan Cox 	 */
47489c78134SAlan Cox 	if (mode->hdisplay != adjusted_mode->hdisplay ||
47589c78134SAlan Cox 	    mode->vdisplay != adjusted_mode->vdisplay)
47689c78134SAlan Cox 		pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE |
47789c78134SAlan Cox 				HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR |
47889c78134SAlan Cox 				HORIZ_INTERP_BILINEAR);
47989c78134SAlan Cox 	else
48089c78134SAlan Cox 		pfit_control = 0;
48189c78134SAlan Cox 
48289c78134SAlan Cox 	if (dev_priv->lvds_dither)
48389c78134SAlan Cox 		pfit_control |= PANEL_8TO6_DITHER_ENABLE;
48489c78134SAlan Cox 
48589c78134SAlan Cox 	REG_WRITE(PFIT_CONTROL, pfit_control);
48689c78134SAlan Cox }
48789c78134SAlan Cox 
48889c78134SAlan Cox /*
48989c78134SAlan Cox  * Return the list of DDC modes if available, or the BIOS fixed mode otherwise.
49089c78134SAlan Cox  */
psb_intel_lvds_get_modes(struct drm_connector * connector)49189c78134SAlan Cox static int psb_intel_lvds_get_modes(struct drm_connector *connector)
49289c78134SAlan Cox {
49389c78134SAlan Cox 	struct drm_device *dev = connector->dev;
494f71635e8SThomas Zimmermann 	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
4959c8cee47SPatrik Jakobsson 	struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev;
49689c78134SAlan Cox 	int ret = 0;
49789c78134SAlan Cox 
49889c78134SAlan Cox 	if (!IS_MRST(dev))
499e9ca4e9eSPatrik Jakobsson 		ret = psb_intel_ddc_get_modes(connector, connector->ddc);
50089c78134SAlan Cox 
50189c78134SAlan Cox 	if (ret)
50289c78134SAlan Cox 		return ret;
50389c78134SAlan Cox 
50489c78134SAlan Cox 	if (mode_dev->panel_fixed_mode != NULL) {
50589c78134SAlan Cox 		struct drm_display_mode *mode =
50689c78134SAlan Cox 		    drm_mode_duplicate(dev, mode_dev->panel_fixed_mode);
507*46d2ef27SMa Ke 		if (!mode)
508*46d2ef27SMa Ke 			return 0;
509*46d2ef27SMa Ke 
51089c78134SAlan Cox 		drm_mode_probed_add(connector, mode);
51189c78134SAlan Cox 		return 1;
51289c78134SAlan Cox 	}
51389c78134SAlan Cox 
51489c78134SAlan Cox 	return 0;
51589c78134SAlan Cox }
51689c78134SAlan Cox 
psb_intel_lvds_destroy(struct drm_connector * connector)51789c78134SAlan Cox void psb_intel_lvds_destroy(struct drm_connector *connector)
51889c78134SAlan Cox {
51912e67ccaSPatrik Jakobsson 	struct gma_connector *gma_connector = to_gma_connector(connector);
520147a0907SPatrik Jakobsson 	struct gma_i2c_chan *ddc_bus = to_gma_i2c_chan(connector->ddc);
52189c78134SAlan Cox 
522147a0907SPatrik Jakobsson 	gma_i2c_destroy(ddc_bus);
52389c78134SAlan Cox 	drm_connector_cleanup(connector);
52412e67ccaSPatrik Jakobsson 	kfree(gma_connector);
52589c78134SAlan Cox }
52689c78134SAlan Cox 
psb_intel_lvds_set_property(struct drm_connector * connector,struct drm_property * property,uint64_t value)52789c78134SAlan Cox int psb_intel_lvds_set_property(struct drm_connector *connector,
52889c78134SAlan Cox 				       struct drm_property *property,
52989c78134SAlan Cox 				       uint64_t value)
53089c78134SAlan Cox {
53189c78134SAlan Cox 	struct drm_encoder *encoder = connector->encoder;
53289c78134SAlan Cox 
53389c78134SAlan Cox 	if (!encoder)
53489c78134SAlan Cox 		return -1;
53589c78134SAlan Cox 
53689c78134SAlan Cox 	if (!strcmp(property->name, "scaling mode")) {
5376306865dSPatrik Jakobsson 		struct gma_crtc *crtc = to_gma_crtc(encoder->crtc);
53889c78134SAlan Cox 		uint64_t curval;
53989c78134SAlan Cox 
54089c78134SAlan Cox 		if (!crtc)
54189c78134SAlan Cox 			goto set_prop_error;
54289c78134SAlan Cox 
54389c78134SAlan Cox 		switch (value) {
54489c78134SAlan Cox 		case DRM_MODE_SCALE_FULLSCREEN:
54589c78134SAlan Cox 			break;
54689c78134SAlan Cox 		case DRM_MODE_SCALE_NO_SCALE:
54789c78134SAlan Cox 			break;
54889c78134SAlan Cox 		case DRM_MODE_SCALE_ASPECT:
54989c78134SAlan Cox 			break;
55089c78134SAlan Cox 		default:
55189c78134SAlan Cox 			goto set_prop_error;
55289c78134SAlan Cox 		}
55389c78134SAlan Cox 
554a69ac9eaSRob Clark 		if (drm_object_property_get_value(&connector->base,
55589c78134SAlan Cox 						     property,
55689c78134SAlan Cox 						     &curval))
55789c78134SAlan Cox 			goto set_prop_error;
55889c78134SAlan Cox 
55989c78134SAlan Cox 		if (curval == value)
56089c78134SAlan Cox 			goto set_prop_done;
56189c78134SAlan Cox 
562a69ac9eaSRob Clark 		if (drm_object_property_set_value(&connector->base,
56389c78134SAlan Cox 							property,
56489c78134SAlan Cox 							value))
56589c78134SAlan Cox 			goto set_prop_error;
56689c78134SAlan Cox 
56789c78134SAlan Cox 		if (crtc->saved_mode.hdisplay != 0 &&
56889c78134SAlan Cox 		    crtc->saved_mode.vdisplay != 0) {
56989c78134SAlan Cox 			if (!drm_crtc_helper_set_mode(encoder->crtc,
57089c78134SAlan Cox 						      &crtc->saved_mode,
57189c78134SAlan Cox 						      encoder->crtc->x,
57289c78134SAlan Cox 						      encoder->crtc->y,
573f4510a27SMatt Roper 						      encoder->crtc->primary->fb))
57489c78134SAlan Cox 				goto set_prop_error;
57589c78134SAlan Cox 		}
57689c78134SAlan Cox 	} else if (!strcmp(property->name, "backlight")) {
577a69ac9eaSRob Clark 		if (drm_object_property_set_value(&connector->base,
57889c78134SAlan Cox 							property,
57989c78134SAlan Cox 							value))
58089c78134SAlan Cox 			goto set_prop_error;
581d112a816SZhao Yakui 		else
582d112a816SZhao Yakui                         gma_backlight_set(encoder->dev, value);
58389c78134SAlan Cox 	} else if (!strcmp(property->name, "DPMS")) {
58445fe734cSJani Nikula 		const struct drm_encoder_helper_funcs *hfuncs
58589c78134SAlan Cox 						= encoder->helper_private;
58689c78134SAlan Cox 		hfuncs->dpms(encoder, value);
58789c78134SAlan Cox 	}
58889c78134SAlan Cox 
58989c78134SAlan Cox set_prop_done:
59089c78134SAlan Cox 	return 0;
59189c78134SAlan Cox set_prop_error:
59289c78134SAlan Cox 	return -1;
59389c78134SAlan Cox }
59489c78134SAlan Cox 
59589c78134SAlan Cox static const struct drm_encoder_helper_funcs psb_intel_lvds_helper_funcs = {
59689c78134SAlan Cox 	.dpms = psb_intel_lvds_encoder_dpms,
59789c78134SAlan Cox 	.mode_fixup = psb_intel_lvds_mode_fixup,
59889c78134SAlan Cox 	.prepare = psb_intel_lvds_prepare,
59989c78134SAlan Cox 	.mode_set = psb_intel_lvds_mode_set,
60089c78134SAlan Cox 	.commit = psb_intel_lvds_commit,
60189c78134SAlan Cox };
60289c78134SAlan Cox 
60389c78134SAlan Cox const struct drm_connector_helper_funcs
60489c78134SAlan Cox 				psb_intel_lvds_connector_helper_funcs = {
60589c78134SAlan Cox 	.get_modes = psb_intel_lvds_get_modes,
60689c78134SAlan Cox 	.mode_valid = psb_intel_lvds_mode_valid,
607c9d49590SPatrik Jakobsson 	.best_encoder = gma_best_encoder,
60889c78134SAlan Cox };
60989c78134SAlan Cox 
61089c78134SAlan Cox const struct drm_connector_funcs psb_intel_lvds_connector_funcs = {
61189c78134SAlan Cox 	.dpms = drm_helper_connector_dpms,
61289c78134SAlan Cox 	.fill_modes = drm_helper_probe_single_connector_modes,
61389c78134SAlan Cox 	.set_property = psb_intel_lvds_set_property,
61489c78134SAlan Cox 	.destroy = psb_intel_lvds_destroy,
61589c78134SAlan Cox };
61689c78134SAlan Cox 
61789c78134SAlan Cox /**
61889c78134SAlan Cox  * psb_intel_lvds_init - setup LVDS connectors on this device
61989c78134SAlan Cox  * @dev: drm device
62073512178SLee Jones  * @mode_dev: mode device
62189c78134SAlan Cox  *
62289c78134SAlan Cox  * Create the connector, register the LVDS DDC bus, and try to figure out what
62389c78134SAlan Cox  * modes we can display on the LVDS panel (if present).
62489c78134SAlan Cox  */
psb_intel_lvds_init(struct drm_device * dev,struct psb_intel_mode_device * mode_dev)62589c78134SAlan Cox void psb_intel_lvds_init(struct drm_device *dev,
62689c78134SAlan Cox 			 struct psb_intel_mode_device *mode_dev)
62789c78134SAlan Cox {
628367e4408SPatrik Jakobsson 	struct gma_encoder *gma_encoder;
629a3d5d75fSPatrik Jakobsson 	struct gma_connector *gma_connector;
63089c78134SAlan Cox 	struct psb_intel_lvds_priv *lvds_priv;
63189c78134SAlan Cox 	struct drm_connector *connector;
63289c78134SAlan Cox 	struct drm_encoder *encoder;
63389c78134SAlan Cox 	struct drm_display_mode *scan;	/* *modes, *bios_mode; */
63489c78134SAlan Cox 	struct drm_crtc *crtc;
635f71635e8SThomas Zimmermann 	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
636147a0907SPatrik Jakobsson 	struct gma_i2c_chan *ddc_bus;
63789c78134SAlan Cox 	u32 lvds;
63889c78134SAlan Cox 	int pipe;
639147a0907SPatrik Jakobsson 	int ret;
64089c78134SAlan Cox 
641367e4408SPatrik Jakobsson 	gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL);
642367e4408SPatrik Jakobsson 	if (!gma_encoder) {
643367e4408SPatrik Jakobsson 		dev_err(dev->dev, "gma_encoder allocation error\n");
64489c78134SAlan Cox 		return;
64589c78134SAlan Cox 	}
646147a0907SPatrik Jakobsson 	encoder = &gma_encoder->base;
64789c78134SAlan Cox 
648a3d5d75fSPatrik Jakobsson 	gma_connector = kzalloc(sizeof(struct gma_connector), GFP_KERNEL);
649a3d5d75fSPatrik Jakobsson 	if (!gma_connector) {
650a3d5d75fSPatrik Jakobsson 		dev_err(dev->dev, "gma_connector allocation error\n");
651147a0907SPatrik Jakobsson 		goto err_free_encoder;
6529c8cee47SPatrik Jakobsson 	}
6539c8cee47SPatrik Jakobsson 
6549c8cee47SPatrik Jakobsson 	lvds_priv = kzalloc(sizeof(struct psb_intel_lvds_priv), GFP_KERNEL);
6559c8cee47SPatrik Jakobsson 	if (!lvds_priv) {
6569c8cee47SPatrik Jakobsson 		dev_err(dev->dev, "LVDS private allocation error\n");
657147a0907SPatrik Jakobsson 		goto err_free_connector;
6589c8cee47SPatrik Jakobsson 	}
6599c8cee47SPatrik Jakobsson 
660367e4408SPatrik Jakobsson 	gma_encoder->dev_priv = lvds_priv;
6619c8cee47SPatrik Jakobsson 
662a3d5d75fSPatrik Jakobsson 	connector = &gma_connector->base;
663d56f57acSDaniel Vetter 	gma_connector->save = psb_intel_lvds_save;
664d56f57acSDaniel Vetter 	gma_connector->restore = psb_intel_lvds_restore;
665d56f57acSDaniel Vetter 
666147a0907SPatrik Jakobsson 	/* Set up the DDC bus. */
667147a0907SPatrik Jakobsson 	ddc_bus = gma_i2c_create(dev, GPIOC, "LVDSDDC_C");
668147a0907SPatrik Jakobsson 	if (!ddc_bus) {
669147a0907SPatrik Jakobsson 		dev_printk(KERN_ERR, dev->dev,
670147a0907SPatrik Jakobsson 			   "DDC bus registration " "failed.\n");
671147a0907SPatrik Jakobsson 		goto err_free_lvds_priv;
672147a0907SPatrik Jakobsson 	}
67389c78134SAlan Cox 
674147a0907SPatrik Jakobsson 	ret = drm_connector_init_with_ddc(dev, connector,
675147a0907SPatrik Jakobsson 					  &psb_intel_lvds_connector_funcs,
676147a0907SPatrik Jakobsson 					  DRM_MODE_CONNECTOR_LVDS,
677147a0907SPatrik Jakobsson 					  &ddc_bus->base);
678147a0907SPatrik Jakobsson 	if (ret)
679147a0907SPatrik Jakobsson 		goto err_ddc_destroy;
680147a0907SPatrik Jakobsson 
681147a0907SPatrik Jakobsson 	ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_LVDS);
682147a0907SPatrik Jakobsson 	if (ret)
683147a0907SPatrik Jakobsson 		goto err_connector_cleanup;
68489c78134SAlan Cox 
685367e4408SPatrik Jakobsson 	gma_connector_attach_encoder(gma_connector, gma_encoder);
686367e4408SPatrik Jakobsson 	gma_encoder->type = INTEL_OUTPUT_LVDS;
68789c78134SAlan Cox 
68889c78134SAlan Cox 	drm_encoder_helper_add(encoder, &psb_intel_lvds_helper_funcs);
68989c78134SAlan Cox 	drm_connector_helper_add(connector,
69089c78134SAlan Cox 				 &psb_intel_lvds_connector_helper_funcs);
69189c78134SAlan Cox 	connector->display_info.subpixel_order = SubPixelHorizontalRGB;
69289c78134SAlan Cox 	connector->interlace_allowed = false;
69389c78134SAlan Cox 	connector->doublescan_allowed = false;
69489c78134SAlan Cox 
69589c78134SAlan Cox 	/*Attach connector properties*/
696a69ac9eaSRob Clark 	drm_object_attach_property(&connector->base,
69789c78134SAlan Cox 				      dev->mode_config.scaling_mode_property,
69889c78134SAlan Cox 				      DRM_MODE_SCALE_FULLSCREEN);
699a69ac9eaSRob Clark 	drm_object_attach_property(&connector->base,
70089c78134SAlan Cox 				      dev_priv->backlight_property,
70189c78134SAlan Cox 				      BRIGHTNESS_MAX_LEVEL);
70289c78134SAlan Cox 
70389c78134SAlan Cox 	/*
70489c78134SAlan Cox 	 * Set up I2C bus
70589c78134SAlan Cox 	 * FIXME: distroy i2c_bus when exit
70689c78134SAlan Cox 	 */
70704477e5eSPatrik Jakobsson 	lvds_priv->i2c_bus = gma_i2c_create(dev, GPIOB, "LVDSBLC_B");
7089c8cee47SPatrik Jakobsson 	if (!lvds_priv->i2c_bus) {
70989c78134SAlan Cox 		dev_printk(KERN_ERR,
710a2c68495SThomas Zimmermann 			dev->dev, "I2C bus registration failed.\n");
711147a0907SPatrik Jakobsson 		goto err_encoder_cleanup;
71289c78134SAlan Cox 	}
7139c8cee47SPatrik Jakobsson 	lvds_priv->i2c_bus->slave_addr = 0x2C;
7149c8cee47SPatrik Jakobsson 	dev_priv->lvds_i2c_bus =  lvds_priv->i2c_bus;
71589c78134SAlan Cox 
71689c78134SAlan Cox 	/*
71789c78134SAlan Cox 	 * LVDS discovery:
71889c78134SAlan Cox 	 * 1) check for EDID on DDC
71989c78134SAlan Cox 	 * 2) check for VBT data
72089c78134SAlan Cox 	 * 3) check to see if LVDS is already on
72189c78134SAlan Cox 	 *    if none of the above, no panel
72289c78134SAlan Cox 	 * 4) make sure lid is open
72389c78134SAlan Cox 	 *    if closed, act like it's not there for now
72489c78134SAlan Cox 	 */
72589c78134SAlan Cox 
72689c78134SAlan Cox 	/*
72789c78134SAlan Cox 	 * Attempt to get the fixed panel mode from DDC.  Assume that the
72889c78134SAlan Cox 	 * preferred mode is the right one.
72989c78134SAlan Cox 	 */
730c46145aeSDaniel Vetter 	mutex_lock(&dev->mode_config.mutex);
731147a0907SPatrik Jakobsson 	psb_intel_ddc_get_modes(connector, &ddc_bus->base);
732147a0907SPatrik Jakobsson 
73389c78134SAlan Cox 	list_for_each_entry(scan, &connector->probed_modes, head) {
73489c78134SAlan Cox 		if (scan->type & DRM_MODE_TYPE_PREFERRED) {
73589c78134SAlan Cox 			mode_dev->panel_fixed_mode =
73689c78134SAlan Cox 			    drm_mode_duplicate(dev, scan);
73782bc9a42SPatrik Jakobsson 			DRM_DEBUG_KMS("Using mode from DDC\n");
73889c78134SAlan Cox 			goto out;	/* FIXME: check for quirks */
73989c78134SAlan Cox 		}
74089c78134SAlan Cox 	}
74189c78134SAlan Cox 
74289c78134SAlan Cox 	/* Failed to get EDID, what about VBT? do we need this? */
74382bc9a42SPatrik Jakobsson 	if (dev_priv->lfp_lvds_vbt_mode) {
74489c78134SAlan Cox 		mode_dev->panel_fixed_mode =
74582bc9a42SPatrik Jakobsson 			drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
74689c78134SAlan Cox 
74782bc9a42SPatrik Jakobsson 		if (mode_dev->panel_fixed_mode) {
74882bc9a42SPatrik Jakobsson 			mode_dev->panel_fixed_mode->type |=
74982bc9a42SPatrik Jakobsson 				DRM_MODE_TYPE_PREFERRED;
75082bc9a42SPatrik Jakobsson 			DRM_DEBUG_KMS("Using mode from VBT\n");
75182bc9a42SPatrik Jakobsson 			goto out;
75282bc9a42SPatrik Jakobsson 		}
75382bc9a42SPatrik Jakobsson 	}
75489c78134SAlan Cox 
75589c78134SAlan Cox 	/*
75689c78134SAlan Cox 	 * If we didn't get EDID, try checking if the panel is already turned
75789c78134SAlan Cox 	 * on.	If so, assume that whatever is currently programmed is the
75889c78134SAlan Cox 	 * correct mode.
75989c78134SAlan Cox 	 */
76089c78134SAlan Cox 	lvds = REG_READ(LVDS);
76189c78134SAlan Cox 	pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
76289c78134SAlan Cox 	crtc = psb_intel_get_crtc_from_pipe(dev, pipe);
76389c78134SAlan Cox 
76489c78134SAlan Cox 	if (crtc && (lvds & LVDS_PORT_EN)) {
76589c78134SAlan Cox 		mode_dev->panel_fixed_mode =
76689c78134SAlan Cox 		    psb_intel_crtc_mode_get(dev, crtc);
76789c78134SAlan Cox 		if (mode_dev->panel_fixed_mode) {
76889c78134SAlan Cox 			mode_dev->panel_fixed_mode->type |=
76989c78134SAlan Cox 			    DRM_MODE_TYPE_PREFERRED;
77082bc9a42SPatrik Jakobsson 			DRM_DEBUG_KMS("Using pre-programmed mode\n");
77189c78134SAlan Cox 			goto out;	/* FIXME: check for quirks */
77289c78134SAlan Cox 		}
77389c78134SAlan Cox 	}
77489c78134SAlan Cox 
77589c78134SAlan Cox 	/* If we still don't have a mode after all that, give up. */
77689c78134SAlan Cox 	if (!mode_dev->panel_fixed_mode) {
77789c78134SAlan Cox 		dev_err(dev->dev, "Found no modes on the lvds, ignoring the LVDS\n");
778147a0907SPatrik Jakobsson 		goto err_unlock;
77989c78134SAlan Cox 	}
78089c78134SAlan Cox 
78189c78134SAlan Cox 	/*
78289c78134SAlan Cox 	 * Blacklist machines with BIOSes that list an LVDS panel without
78389c78134SAlan Cox 	 * actually having one.
78489c78134SAlan Cox 	 */
78589c78134SAlan Cox out:
786c46145aeSDaniel Vetter 	mutex_unlock(&dev->mode_config.mutex);
78789c78134SAlan Cox 	return;
78889c78134SAlan Cox 
789147a0907SPatrik Jakobsson err_unlock:
790c46145aeSDaniel Vetter 	mutex_unlock(&dev->mode_config.mutex);
79104477e5eSPatrik Jakobsson 	gma_i2c_destroy(lvds_priv->i2c_bus);
792147a0907SPatrik Jakobsson err_encoder_cleanup:
79389c78134SAlan Cox 	drm_encoder_cleanup(encoder);
794147a0907SPatrik Jakobsson err_connector_cleanup:
79589c78134SAlan Cox 	drm_connector_cleanup(connector);
796147a0907SPatrik Jakobsson err_ddc_destroy:
797147a0907SPatrik Jakobsson 	gma_i2c_destroy(ddc_bus);
798147a0907SPatrik Jakobsson err_free_lvds_priv:
799147a0907SPatrik Jakobsson 	kfree(lvds_priv);
800147a0907SPatrik Jakobsson err_free_connector:
801a3d5d75fSPatrik Jakobsson 	kfree(gma_connector);
802147a0907SPatrik Jakobsson err_free_encoder:
803367e4408SPatrik Jakobsson 	kfree(gma_encoder);
80489c78134SAlan Cox }
80589c78134SAlan Cox 
806