xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/gma500/psb_intel_lvds.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright © 2006-2007 Intel Corporation
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Authors:
6*4882a593Smuzhiyun  *	Eric Anholt <eric@anholt.net>
7*4882a593Smuzhiyun  *	Dave Airlie <airlied@linux.ie>
8*4882a593Smuzhiyun  *	Jesse Barnes <jesse.barnes@intel.com>
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/i2c.h>
12*4882a593Smuzhiyun #include <linux/pm_runtime.h>
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include <drm/drm_simple_kms_helper.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include "intel_bios.h"
17*4882a593Smuzhiyun #include "power.h"
18*4882a593Smuzhiyun #include "psb_drv.h"
19*4882a593Smuzhiyun #include "psb_intel_drv.h"
20*4882a593Smuzhiyun #include "psb_intel_reg.h"
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun /*
23*4882a593Smuzhiyun  * LVDS I2C backlight control macros
24*4882a593Smuzhiyun  */
25*4882a593Smuzhiyun #define BRIGHTNESS_MAX_LEVEL 100
26*4882a593Smuzhiyun #define BRIGHTNESS_MASK 0xFF
27*4882a593Smuzhiyun #define BLC_I2C_TYPE	0x01
28*4882a593Smuzhiyun #define BLC_PWM_TYPT	0x02
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #define BLC_POLARITY_NORMAL 0
31*4882a593Smuzhiyun #define BLC_POLARITY_INVERSE 1
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #define PSB_BLC_MAX_PWM_REG_FREQ       (0xFFFE)
34*4882a593Smuzhiyun #define PSB_BLC_MIN_PWM_REG_FREQ	(0x2)
35*4882a593Smuzhiyun #define PSB_BLC_PWM_PRECISION_FACTOR	(10)
36*4882a593Smuzhiyun #define PSB_BACKLIGHT_PWM_CTL_SHIFT	(16)
37*4882a593Smuzhiyun #define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE)
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun struct psb_intel_lvds_priv {
40*4882a593Smuzhiyun 	/*
41*4882a593Smuzhiyun 	 * Saved LVDO output states
42*4882a593Smuzhiyun 	 */
43*4882a593Smuzhiyun 	uint32_t savePP_ON;
44*4882a593Smuzhiyun 	uint32_t savePP_OFF;
45*4882a593Smuzhiyun 	uint32_t saveLVDS;
46*4882a593Smuzhiyun 	uint32_t savePP_CONTROL;
47*4882a593Smuzhiyun 	uint32_t savePP_CYCLE;
48*4882a593Smuzhiyun 	uint32_t savePFIT_CONTROL;
49*4882a593Smuzhiyun 	uint32_t savePFIT_PGM_RATIOS;
50*4882a593Smuzhiyun 	uint32_t saveBLC_PWM_CTL;
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	struct psb_intel_i2c_chan *i2c_bus;
53*4882a593Smuzhiyun 	struct psb_intel_i2c_chan *ddc_bus;
54*4882a593Smuzhiyun };
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun /*
58*4882a593Smuzhiyun  * Returns the maximum level of the backlight duty cycle field.
59*4882a593Smuzhiyun  */
psb_intel_lvds_get_max_backlight(struct drm_device * dev)60*4882a593Smuzhiyun static u32 psb_intel_lvds_get_max_backlight(struct drm_device *dev)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun 	struct drm_psb_private *dev_priv = dev->dev_private;
63*4882a593Smuzhiyun 	u32 ret;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	if (gma_power_begin(dev, false)) {
66*4882a593Smuzhiyun 		ret = REG_READ(BLC_PWM_CTL);
67*4882a593Smuzhiyun 		gma_power_end(dev);
68*4882a593Smuzhiyun 	} else /* Powered off, use the saved value */
69*4882a593Smuzhiyun 		ret = dev_priv->regs.saveBLC_PWM_CTL;
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	/* Top 15bits hold the frequency mask */
72*4882a593Smuzhiyun 	ret = (ret &  BACKLIGHT_MODULATION_FREQ_MASK) >>
73*4882a593Smuzhiyun 					BACKLIGHT_MODULATION_FREQ_SHIFT;
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun         ret *= 2;	/* Return a 16bit range as needed for setting */
76*4882a593Smuzhiyun         if (ret == 0)
77*4882a593Smuzhiyun                 dev_err(dev->dev, "BL bug: Reg %08x save %08X\n",
78*4882a593Smuzhiyun                         REG_READ(BLC_PWM_CTL), dev_priv->regs.saveBLC_PWM_CTL);
79*4882a593Smuzhiyun 	return ret;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun /*
83*4882a593Smuzhiyun  * Set LVDS backlight level by I2C command
84*4882a593Smuzhiyun  *
85*4882a593Smuzhiyun  * FIXME: at some point we need to both track this for PM and also
86*4882a593Smuzhiyun  * disable runtime pm on MRST if the brightness is nil (ie blanked)
87*4882a593Smuzhiyun  */
psb_lvds_i2c_set_brightness(struct drm_device * dev,unsigned int level)88*4882a593Smuzhiyun static int psb_lvds_i2c_set_brightness(struct drm_device *dev,
89*4882a593Smuzhiyun 					unsigned int level)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	struct drm_psb_private *dev_priv =
92*4882a593Smuzhiyun 		(struct drm_psb_private *)dev->dev_private;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	struct psb_intel_i2c_chan *lvds_i2c_bus = dev_priv->lvds_i2c_bus;
95*4882a593Smuzhiyun 	u8 out_buf[2];
96*4882a593Smuzhiyun 	unsigned int blc_i2c_brightness;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	struct i2c_msg msgs[] = {
99*4882a593Smuzhiyun 		{
100*4882a593Smuzhiyun 			.addr = lvds_i2c_bus->slave_addr,
101*4882a593Smuzhiyun 			.flags = 0,
102*4882a593Smuzhiyun 			.len = 2,
103*4882a593Smuzhiyun 			.buf = out_buf,
104*4882a593Smuzhiyun 		}
105*4882a593Smuzhiyun 	};
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	blc_i2c_brightness = BRIGHTNESS_MASK & ((unsigned int)level *
108*4882a593Smuzhiyun 			     BRIGHTNESS_MASK /
109*4882a593Smuzhiyun 			     BRIGHTNESS_MAX_LEVEL);
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	if (dev_priv->lvds_bl->pol == BLC_POLARITY_INVERSE)
112*4882a593Smuzhiyun 		blc_i2c_brightness = BRIGHTNESS_MASK - blc_i2c_brightness;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	out_buf[0] = dev_priv->lvds_bl->brightnesscmd;
115*4882a593Smuzhiyun 	out_buf[1] = (u8)blc_i2c_brightness;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	if (i2c_transfer(&lvds_i2c_bus->adapter, msgs, 1) == 1) {
118*4882a593Smuzhiyun 		dev_dbg(dev->dev, "I2C set brightness.(command, value) (%d, %d)\n",
119*4882a593Smuzhiyun 			dev_priv->lvds_bl->brightnesscmd,
120*4882a593Smuzhiyun 			blc_i2c_brightness);
121*4882a593Smuzhiyun 		return 0;
122*4882a593Smuzhiyun 	}
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	dev_err(dev->dev, "I2C transfer error\n");
125*4882a593Smuzhiyun 	return -1;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 
psb_lvds_pwm_set_brightness(struct drm_device * dev,int level)129*4882a593Smuzhiyun static int psb_lvds_pwm_set_brightness(struct drm_device *dev, int level)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun 	struct drm_psb_private *dev_priv =
132*4882a593Smuzhiyun 			(struct drm_psb_private *)dev->dev_private;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	u32 max_pwm_blc;
135*4882a593Smuzhiyun 	u32 blc_pwm_duty_cycle;
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	max_pwm_blc = psb_intel_lvds_get_max_backlight(dev);
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	/*BLC_PWM_CTL Should be initiated while backlight device init*/
140*4882a593Smuzhiyun 	BUG_ON(max_pwm_blc == 0);
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	blc_pwm_duty_cycle = level * max_pwm_blc / BRIGHTNESS_MAX_LEVEL;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	if (dev_priv->lvds_bl->pol == BLC_POLARITY_INVERSE)
145*4882a593Smuzhiyun 		blc_pwm_duty_cycle = max_pwm_blc - blc_pwm_duty_cycle;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	blc_pwm_duty_cycle &= PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR;
148*4882a593Smuzhiyun 	REG_WRITE(BLC_PWM_CTL,
149*4882a593Smuzhiyun 		  (max_pwm_blc << PSB_BACKLIGHT_PWM_CTL_SHIFT) |
150*4882a593Smuzhiyun 		  (blc_pwm_duty_cycle));
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun         dev_info(dev->dev, "Backlight lvds set brightness %08x\n",
153*4882a593Smuzhiyun 		  (max_pwm_blc << PSB_BACKLIGHT_PWM_CTL_SHIFT) |
154*4882a593Smuzhiyun 		  (blc_pwm_duty_cycle));
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	return 0;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun /*
160*4882a593Smuzhiyun  * Set LVDS backlight level either by I2C or PWM
161*4882a593Smuzhiyun  */
psb_intel_lvds_set_brightness(struct drm_device * dev,int level)162*4882a593Smuzhiyun void psb_intel_lvds_set_brightness(struct drm_device *dev, int level)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun 	struct drm_psb_private *dev_priv = dev->dev_private;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	dev_dbg(dev->dev, "backlight level is %d\n", level);
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	if (!dev_priv->lvds_bl) {
169*4882a593Smuzhiyun 		dev_err(dev->dev, "NO LVDS backlight info\n");
170*4882a593Smuzhiyun 		return;
171*4882a593Smuzhiyun 	}
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	if (dev_priv->lvds_bl->type == BLC_I2C_TYPE)
174*4882a593Smuzhiyun 		psb_lvds_i2c_set_brightness(dev, level);
175*4882a593Smuzhiyun 	else
176*4882a593Smuzhiyun 		psb_lvds_pwm_set_brightness(dev, level);
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun /*
180*4882a593Smuzhiyun  * Sets the backlight level.
181*4882a593Smuzhiyun  *
182*4882a593Smuzhiyun  * level: backlight level, from 0 to psb_intel_lvds_get_max_backlight().
183*4882a593Smuzhiyun  */
psb_intel_lvds_set_backlight(struct drm_device * dev,int level)184*4882a593Smuzhiyun static void psb_intel_lvds_set_backlight(struct drm_device *dev, int level)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun 	struct drm_psb_private *dev_priv = dev->dev_private;
187*4882a593Smuzhiyun 	u32 blc_pwm_ctl;
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	if (gma_power_begin(dev, false)) {
190*4882a593Smuzhiyun 		blc_pwm_ctl = REG_READ(BLC_PWM_CTL);
191*4882a593Smuzhiyun 		blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK;
192*4882a593Smuzhiyun 		REG_WRITE(BLC_PWM_CTL,
193*4882a593Smuzhiyun 				(blc_pwm_ctl |
194*4882a593Smuzhiyun 				(level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
195*4882a593Smuzhiyun 		dev_priv->regs.saveBLC_PWM_CTL = (blc_pwm_ctl |
196*4882a593Smuzhiyun 					(level << BACKLIGHT_DUTY_CYCLE_SHIFT));
197*4882a593Smuzhiyun 		gma_power_end(dev);
198*4882a593Smuzhiyun 	} else {
199*4882a593Smuzhiyun 		blc_pwm_ctl = dev_priv->regs.saveBLC_PWM_CTL &
200*4882a593Smuzhiyun 				~BACKLIGHT_DUTY_CYCLE_MASK;
201*4882a593Smuzhiyun 		dev_priv->regs.saveBLC_PWM_CTL = (blc_pwm_ctl |
202*4882a593Smuzhiyun 					(level << BACKLIGHT_DUTY_CYCLE_SHIFT));
203*4882a593Smuzhiyun 	}
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun /*
207*4882a593Smuzhiyun  * Sets the power state for the panel.
208*4882a593Smuzhiyun  */
psb_intel_lvds_set_power(struct drm_device * dev,bool on)209*4882a593Smuzhiyun static void psb_intel_lvds_set_power(struct drm_device *dev, bool on)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun 	struct drm_psb_private *dev_priv = dev->dev_private;
212*4882a593Smuzhiyun 	struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev;
213*4882a593Smuzhiyun 	u32 pp_status;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	if (!gma_power_begin(dev, true)) {
216*4882a593Smuzhiyun 	        dev_err(dev->dev, "set power, chip off!\n");
217*4882a593Smuzhiyun 		return;
218*4882a593Smuzhiyun         }
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	if (on) {
221*4882a593Smuzhiyun 		REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) |
222*4882a593Smuzhiyun 			  POWER_TARGET_ON);
223*4882a593Smuzhiyun 		do {
224*4882a593Smuzhiyun 			pp_status = REG_READ(PP_STATUS);
225*4882a593Smuzhiyun 		} while ((pp_status & PP_ON) == 0);
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 		psb_intel_lvds_set_backlight(dev,
228*4882a593Smuzhiyun 					     mode_dev->backlight_duty_cycle);
229*4882a593Smuzhiyun 	} else {
230*4882a593Smuzhiyun 		psb_intel_lvds_set_backlight(dev, 0);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 		REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) &
233*4882a593Smuzhiyun 			  ~POWER_TARGET_ON);
234*4882a593Smuzhiyun 		do {
235*4882a593Smuzhiyun 			pp_status = REG_READ(PP_STATUS);
236*4882a593Smuzhiyun 		} while (pp_status & PP_ON);
237*4882a593Smuzhiyun 	}
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	gma_power_end(dev);
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun 
psb_intel_lvds_encoder_dpms(struct drm_encoder * encoder,int mode)242*4882a593Smuzhiyun static void psb_intel_lvds_encoder_dpms(struct drm_encoder *encoder, int mode)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun 	struct drm_device *dev = encoder->dev;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	if (mode == DRM_MODE_DPMS_ON)
247*4882a593Smuzhiyun 		psb_intel_lvds_set_power(dev, true);
248*4882a593Smuzhiyun 	else
249*4882a593Smuzhiyun 		psb_intel_lvds_set_power(dev, false);
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	/* XXX: We never power down the LVDS pairs. */
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun 
psb_intel_lvds_save(struct drm_connector * connector)254*4882a593Smuzhiyun static void psb_intel_lvds_save(struct drm_connector *connector)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun 	struct drm_device *dev = connector->dev;
257*4882a593Smuzhiyun 	struct drm_psb_private *dev_priv =
258*4882a593Smuzhiyun 		(struct drm_psb_private *)dev->dev_private;
259*4882a593Smuzhiyun 	struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
260*4882a593Smuzhiyun 	struct psb_intel_lvds_priv *lvds_priv =
261*4882a593Smuzhiyun 		(struct psb_intel_lvds_priv *)gma_encoder->dev_priv;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	lvds_priv->savePP_ON = REG_READ(LVDSPP_ON);
264*4882a593Smuzhiyun 	lvds_priv->savePP_OFF = REG_READ(LVDSPP_OFF);
265*4882a593Smuzhiyun 	lvds_priv->saveLVDS = REG_READ(LVDS);
266*4882a593Smuzhiyun 	lvds_priv->savePP_CONTROL = REG_READ(PP_CONTROL);
267*4882a593Smuzhiyun 	lvds_priv->savePP_CYCLE = REG_READ(PP_CYCLE);
268*4882a593Smuzhiyun 	/*lvds_priv->savePP_DIVISOR = REG_READ(PP_DIVISOR);*/
269*4882a593Smuzhiyun 	lvds_priv->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL);
270*4882a593Smuzhiyun 	lvds_priv->savePFIT_CONTROL = REG_READ(PFIT_CONTROL);
271*4882a593Smuzhiyun 	lvds_priv->savePFIT_PGM_RATIOS = REG_READ(PFIT_PGM_RATIOS);
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	/*TODO: move backlight_duty_cycle to psb_intel_lvds_priv*/
274*4882a593Smuzhiyun 	dev_priv->backlight_duty_cycle = (dev_priv->regs.saveBLC_PWM_CTL &
275*4882a593Smuzhiyun 						BACKLIGHT_DUTY_CYCLE_MASK);
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	/*
278*4882a593Smuzhiyun 	 * If the light is off at server startup,
279*4882a593Smuzhiyun 	 * just make it full brightness
280*4882a593Smuzhiyun 	 */
281*4882a593Smuzhiyun 	if (dev_priv->backlight_duty_cycle == 0)
282*4882a593Smuzhiyun 		dev_priv->backlight_duty_cycle =
283*4882a593Smuzhiyun 		psb_intel_lvds_get_max_backlight(dev);
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	dev_dbg(dev->dev, "(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
286*4882a593Smuzhiyun 			lvds_priv->savePP_ON,
287*4882a593Smuzhiyun 			lvds_priv->savePP_OFF,
288*4882a593Smuzhiyun 			lvds_priv->saveLVDS,
289*4882a593Smuzhiyun 			lvds_priv->savePP_CONTROL,
290*4882a593Smuzhiyun 			lvds_priv->savePP_CYCLE,
291*4882a593Smuzhiyun 			lvds_priv->saveBLC_PWM_CTL);
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun 
psb_intel_lvds_restore(struct drm_connector * connector)294*4882a593Smuzhiyun static void psb_intel_lvds_restore(struct drm_connector *connector)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun 	struct drm_device *dev = connector->dev;
297*4882a593Smuzhiyun 	u32 pp_status;
298*4882a593Smuzhiyun 	struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
299*4882a593Smuzhiyun 	struct psb_intel_lvds_priv *lvds_priv =
300*4882a593Smuzhiyun 		(struct psb_intel_lvds_priv *)gma_encoder->dev_priv;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	dev_dbg(dev->dev, "(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
303*4882a593Smuzhiyun 			lvds_priv->savePP_ON,
304*4882a593Smuzhiyun 			lvds_priv->savePP_OFF,
305*4882a593Smuzhiyun 			lvds_priv->saveLVDS,
306*4882a593Smuzhiyun 			lvds_priv->savePP_CONTROL,
307*4882a593Smuzhiyun 			lvds_priv->savePP_CYCLE,
308*4882a593Smuzhiyun 			lvds_priv->saveBLC_PWM_CTL);
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	REG_WRITE(BLC_PWM_CTL, lvds_priv->saveBLC_PWM_CTL);
311*4882a593Smuzhiyun 	REG_WRITE(PFIT_CONTROL, lvds_priv->savePFIT_CONTROL);
312*4882a593Smuzhiyun 	REG_WRITE(PFIT_PGM_RATIOS, lvds_priv->savePFIT_PGM_RATIOS);
313*4882a593Smuzhiyun 	REG_WRITE(LVDSPP_ON, lvds_priv->savePP_ON);
314*4882a593Smuzhiyun 	REG_WRITE(LVDSPP_OFF, lvds_priv->savePP_OFF);
315*4882a593Smuzhiyun 	/*REG_WRITE(PP_DIVISOR, lvds_priv->savePP_DIVISOR);*/
316*4882a593Smuzhiyun 	REG_WRITE(PP_CYCLE, lvds_priv->savePP_CYCLE);
317*4882a593Smuzhiyun 	REG_WRITE(PP_CONTROL, lvds_priv->savePP_CONTROL);
318*4882a593Smuzhiyun 	REG_WRITE(LVDS, lvds_priv->saveLVDS);
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	if (lvds_priv->savePP_CONTROL & POWER_TARGET_ON) {
321*4882a593Smuzhiyun 		REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) |
322*4882a593Smuzhiyun 			POWER_TARGET_ON);
323*4882a593Smuzhiyun 		do {
324*4882a593Smuzhiyun 			pp_status = REG_READ(PP_STATUS);
325*4882a593Smuzhiyun 		} while ((pp_status & PP_ON) == 0);
326*4882a593Smuzhiyun 	} else {
327*4882a593Smuzhiyun 		REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) &
328*4882a593Smuzhiyun 			~POWER_TARGET_ON);
329*4882a593Smuzhiyun 		do {
330*4882a593Smuzhiyun 			pp_status = REG_READ(PP_STATUS);
331*4882a593Smuzhiyun 		} while (pp_status & PP_ON);
332*4882a593Smuzhiyun 	}
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun 
psb_intel_lvds_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)335*4882a593Smuzhiyun enum drm_mode_status psb_intel_lvds_mode_valid(struct drm_connector *connector,
336*4882a593Smuzhiyun 				 struct drm_display_mode *mode)
337*4882a593Smuzhiyun {
338*4882a593Smuzhiyun 	struct drm_psb_private *dev_priv = connector->dev->dev_private;
339*4882a593Smuzhiyun 	struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
340*4882a593Smuzhiyun 	struct drm_display_mode *fixed_mode =
341*4882a593Smuzhiyun 					dev_priv->mode_dev.panel_fixed_mode;
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	if (gma_encoder->type == INTEL_OUTPUT_MIPI2)
344*4882a593Smuzhiyun 		fixed_mode = dev_priv->mode_dev.panel_fixed_mode2;
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	/* just in case */
347*4882a593Smuzhiyun 	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
348*4882a593Smuzhiyun 		return MODE_NO_DBLESCAN;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	/* just in case */
351*4882a593Smuzhiyun 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
352*4882a593Smuzhiyun 		return MODE_NO_INTERLACE;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	if (fixed_mode) {
355*4882a593Smuzhiyun 		if (mode->hdisplay > fixed_mode->hdisplay)
356*4882a593Smuzhiyun 			return MODE_PANEL;
357*4882a593Smuzhiyun 		if (mode->vdisplay > fixed_mode->vdisplay)
358*4882a593Smuzhiyun 			return MODE_PANEL;
359*4882a593Smuzhiyun 	}
360*4882a593Smuzhiyun 	return MODE_OK;
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun 
psb_intel_lvds_mode_fixup(struct drm_encoder * encoder,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)363*4882a593Smuzhiyun bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder,
364*4882a593Smuzhiyun 				  const struct drm_display_mode *mode,
365*4882a593Smuzhiyun 				  struct drm_display_mode *adjusted_mode)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun 	struct drm_device *dev = encoder->dev;
368*4882a593Smuzhiyun 	struct drm_psb_private *dev_priv = dev->dev_private;
369*4882a593Smuzhiyun 	struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev;
370*4882a593Smuzhiyun 	struct gma_crtc *gma_crtc = to_gma_crtc(encoder->crtc);
371*4882a593Smuzhiyun 	struct drm_encoder *tmp_encoder;
372*4882a593Smuzhiyun 	struct drm_display_mode *panel_fixed_mode = mode_dev->panel_fixed_mode;
373*4882a593Smuzhiyun 	struct gma_encoder *gma_encoder = to_gma_encoder(encoder);
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	if (gma_encoder->type == INTEL_OUTPUT_MIPI2)
376*4882a593Smuzhiyun 		panel_fixed_mode = mode_dev->panel_fixed_mode2;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	/* PSB requires the LVDS is on pipe B, MRST has only one pipe anyway */
379*4882a593Smuzhiyun 	if (!IS_MRST(dev) && gma_crtc->pipe == 0) {
380*4882a593Smuzhiyun 		pr_err("Can't support LVDS on pipe A\n");
381*4882a593Smuzhiyun 		return false;
382*4882a593Smuzhiyun 	}
383*4882a593Smuzhiyun 	if (IS_MRST(dev) && gma_crtc->pipe != 0) {
384*4882a593Smuzhiyun 		pr_err("Must use PIPE A\n");
385*4882a593Smuzhiyun 		return false;
386*4882a593Smuzhiyun 	}
387*4882a593Smuzhiyun 	/* Should never happen!! */
388*4882a593Smuzhiyun 	list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list,
389*4882a593Smuzhiyun 			    head) {
390*4882a593Smuzhiyun 		if (tmp_encoder != encoder
391*4882a593Smuzhiyun 		    && tmp_encoder->crtc == encoder->crtc) {
392*4882a593Smuzhiyun 			pr_err("Can't enable LVDS and another encoder on the same pipe\n");
393*4882a593Smuzhiyun 			return false;
394*4882a593Smuzhiyun 		}
395*4882a593Smuzhiyun 	}
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	/*
398*4882a593Smuzhiyun 	 * If we have timings from the BIOS for the panel, put them in
399*4882a593Smuzhiyun 	 * to the adjusted mode.  The CRTC will be set up for this mode,
400*4882a593Smuzhiyun 	 * with the panel scaling set up to source from the H/VDisplay
401*4882a593Smuzhiyun 	 * of the original mode.
402*4882a593Smuzhiyun 	 */
403*4882a593Smuzhiyun 	if (panel_fixed_mode != NULL) {
404*4882a593Smuzhiyun 		adjusted_mode->hdisplay = panel_fixed_mode->hdisplay;
405*4882a593Smuzhiyun 		adjusted_mode->hsync_start = panel_fixed_mode->hsync_start;
406*4882a593Smuzhiyun 		adjusted_mode->hsync_end = panel_fixed_mode->hsync_end;
407*4882a593Smuzhiyun 		adjusted_mode->htotal = panel_fixed_mode->htotal;
408*4882a593Smuzhiyun 		adjusted_mode->vdisplay = panel_fixed_mode->vdisplay;
409*4882a593Smuzhiyun 		adjusted_mode->vsync_start = panel_fixed_mode->vsync_start;
410*4882a593Smuzhiyun 		adjusted_mode->vsync_end = panel_fixed_mode->vsync_end;
411*4882a593Smuzhiyun 		adjusted_mode->vtotal = panel_fixed_mode->vtotal;
412*4882a593Smuzhiyun 		adjusted_mode->clock = panel_fixed_mode->clock;
413*4882a593Smuzhiyun 		drm_mode_set_crtcinfo(adjusted_mode,
414*4882a593Smuzhiyun 				      CRTC_INTERLACE_HALVE_V);
415*4882a593Smuzhiyun 	}
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	/*
418*4882a593Smuzhiyun 	 * XXX: It would be nice to support lower refresh rates on the
419*4882a593Smuzhiyun 	 * panels to reduce power consumption, and perhaps match the
420*4882a593Smuzhiyun 	 * user's requested refresh rate.
421*4882a593Smuzhiyun 	 */
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	return true;
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun 
psb_intel_lvds_prepare(struct drm_encoder * encoder)426*4882a593Smuzhiyun static void psb_intel_lvds_prepare(struct drm_encoder *encoder)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun 	struct drm_device *dev = encoder->dev;
429*4882a593Smuzhiyun 	struct drm_psb_private *dev_priv = dev->dev_private;
430*4882a593Smuzhiyun 	struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev;
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	if (!gma_power_begin(dev, true))
433*4882a593Smuzhiyun 		return;
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	mode_dev->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL);
436*4882a593Smuzhiyun 	mode_dev->backlight_duty_cycle = (mode_dev->saveBLC_PWM_CTL &
437*4882a593Smuzhiyun 					  BACKLIGHT_DUTY_CYCLE_MASK);
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	psb_intel_lvds_set_power(dev, false);
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	gma_power_end(dev);
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun 
psb_intel_lvds_commit(struct drm_encoder * encoder)444*4882a593Smuzhiyun static void psb_intel_lvds_commit(struct drm_encoder *encoder)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun 	struct drm_device *dev = encoder->dev;
447*4882a593Smuzhiyun 	struct drm_psb_private *dev_priv = dev->dev_private;
448*4882a593Smuzhiyun 	struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev;
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	if (mode_dev->backlight_duty_cycle == 0)
451*4882a593Smuzhiyun 		mode_dev->backlight_duty_cycle =
452*4882a593Smuzhiyun 		    psb_intel_lvds_get_max_backlight(dev);
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	psb_intel_lvds_set_power(dev, true);
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun 
psb_intel_lvds_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)457*4882a593Smuzhiyun static void psb_intel_lvds_mode_set(struct drm_encoder *encoder,
458*4882a593Smuzhiyun 				struct drm_display_mode *mode,
459*4882a593Smuzhiyun 				struct drm_display_mode *adjusted_mode)
460*4882a593Smuzhiyun {
461*4882a593Smuzhiyun 	struct drm_device *dev = encoder->dev;
462*4882a593Smuzhiyun 	struct drm_psb_private *dev_priv = dev->dev_private;
463*4882a593Smuzhiyun 	u32 pfit_control;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	/*
466*4882a593Smuzhiyun 	 * The LVDS pin pair will already have been turned on in the
467*4882a593Smuzhiyun 	 * psb_intel_crtc_mode_set since it has a large impact on the DPLL
468*4882a593Smuzhiyun 	 * settings.
469*4882a593Smuzhiyun 	 */
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	/*
472*4882a593Smuzhiyun 	 * Enable automatic panel scaling so that non-native modes fill the
473*4882a593Smuzhiyun 	 * screen.  Should be enabled before the pipe is enabled, according to
474*4882a593Smuzhiyun 	 * register description and PRM.
475*4882a593Smuzhiyun 	 */
476*4882a593Smuzhiyun 	if (mode->hdisplay != adjusted_mode->hdisplay ||
477*4882a593Smuzhiyun 	    mode->vdisplay != adjusted_mode->vdisplay)
478*4882a593Smuzhiyun 		pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE |
479*4882a593Smuzhiyun 				HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR |
480*4882a593Smuzhiyun 				HORIZ_INTERP_BILINEAR);
481*4882a593Smuzhiyun 	else
482*4882a593Smuzhiyun 		pfit_control = 0;
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	if (dev_priv->lvds_dither)
485*4882a593Smuzhiyun 		pfit_control |= PANEL_8TO6_DITHER_ENABLE;
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	REG_WRITE(PFIT_CONTROL, pfit_control);
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun /*
491*4882a593Smuzhiyun  * Return the list of DDC modes if available, or the BIOS fixed mode otherwise.
492*4882a593Smuzhiyun  */
psb_intel_lvds_get_modes(struct drm_connector * connector)493*4882a593Smuzhiyun static int psb_intel_lvds_get_modes(struct drm_connector *connector)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun 	struct drm_device *dev = connector->dev;
496*4882a593Smuzhiyun 	struct drm_psb_private *dev_priv = dev->dev_private;
497*4882a593Smuzhiyun 	struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev;
498*4882a593Smuzhiyun 	struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
499*4882a593Smuzhiyun 	struct psb_intel_lvds_priv *lvds_priv = gma_encoder->dev_priv;
500*4882a593Smuzhiyun 	int ret = 0;
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	if (!IS_MRST(dev))
503*4882a593Smuzhiyun 		ret = psb_intel_ddc_get_modes(connector, &lvds_priv->i2c_bus->adapter);
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	if (ret)
506*4882a593Smuzhiyun 		return ret;
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun 	if (mode_dev->panel_fixed_mode != NULL) {
509*4882a593Smuzhiyun 		struct drm_display_mode *mode =
510*4882a593Smuzhiyun 		    drm_mode_duplicate(dev, mode_dev->panel_fixed_mode);
511*4882a593Smuzhiyun 		drm_mode_probed_add(connector, mode);
512*4882a593Smuzhiyun 		return 1;
513*4882a593Smuzhiyun 	}
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	return 0;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun /**
519*4882a593Smuzhiyun  * psb_intel_lvds_destroy - unregister and free LVDS structures
520*4882a593Smuzhiyun  * @connector: connector to free
521*4882a593Smuzhiyun  *
522*4882a593Smuzhiyun  * Unregister the DDC bus for this connector then free the driver private
523*4882a593Smuzhiyun  * structure.
524*4882a593Smuzhiyun  */
psb_intel_lvds_destroy(struct drm_connector * connector)525*4882a593Smuzhiyun void psb_intel_lvds_destroy(struct drm_connector *connector)
526*4882a593Smuzhiyun {
527*4882a593Smuzhiyun 	struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
528*4882a593Smuzhiyun 	struct psb_intel_lvds_priv *lvds_priv = gma_encoder->dev_priv;
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	psb_intel_i2c_destroy(lvds_priv->ddc_bus);
531*4882a593Smuzhiyun 	drm_connector_unregister(connector);
532*4882a593Smuzhiyun 	drm_connector_cleanup(connector);
533*4882a593Smuzhiyun 	kfree(connector);
534*4882a593Smuzhiyun }
535*4882a593Smuzhiyun 
psb_intel_lvds_set_property(struct drm_connector * connector,struct drm_property * property,uint64_t value)536*4882a593Smuzhiyun int psb_intel_lvds_set_property(struct drm_connector *connector,
537*4882a593Smuzhiyun 				       struct drm_property *property,
538*4882a593Smuzhiyun 				       uint64_t value)
539*4882a593Smuzhiyun {
540*4882a593Smuzhiyun 	struct drm_encoder *encoder = connector->encoder;
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	if (!encoder)
543*4882a593Smuzhiyun 		return -1;
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	if (!strcmp(property->name, "scaling mode")) {
546*4882a593Smuzhiyun 		struct gma_crtc *crtc = to_gma_crtc(encoder->crtc);
547*4882a593Smuzhiyun 		uint64_t curval;
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 		if (!crtc)
550*4882a593Smuzhiyun 			goto set_prop_error;
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 		switch (value) {
553*4882a593Smuzhiyun 		case DRM_MODE_SCALE_FULLSCREEN:
554*4882a593Smuzhiyun 			break;
555*4882a593Smuzhiyun 		case DRM_MODE_SCALE_NO_SCALE:
556*4882a593Smuzhiyun 			break;
557*4882a593Smuzhiyun 		case DRM_MODE_SCALE_ASPECT:
558*4882a593Smuzhiyun 			break;
559*4882a593Smuzhiyun 		default:
560*4882a593Smuzhiyun 			goto set_prop_error;
561*4882a593Smuzhiyun 		}
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 		if (drm_object_property_get_value(&connector->base,
564*4882a593Smuzhiyun 						     property,
565*4882a593Smuzhiyun 						     &curval))
566*4882a593Smuzhiyun 			goto set_prop_error;
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 		if (curval == value)
569*4882a593Smuzhiyun 			goto set_prop_done;
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 		if (drm_object_property_set_value(&connector->base,
572*4882a593Smuzhiyun 							property,
573*4882a593Smuzhiyun 							value))
574*4882a593Smuzhiyun 			goto set_prop_error;
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 		if (crtc->saved_mode.hdisplay != 0 &&
577*4882a593Smuzhiyun 		    crtc->saved_mode.vdisplay != 0) {
578*4882a593Smuzhiyun 			if (!drm_crtc_helper_set_mode(encoder->crtc,
579*4882a593Smuzhiyun 						      &crtc->saved_mode,
580*4882a593Smuzhiyun 						      encoder->crtc->x,
581*4882a593Smuzhiyun 						      encoder->crtc->y,
582*4882a593Smuzhiyun 						      encoder->crtc->primary->fb))
583*4882a593Smuzhiyun 				goto set_prop_error;
584*4882a593Smuzhiyun 		}
585*4882a593Smuzhiyun 	} else if (!strcmp(property->name, "backlight")) {
586*4882a593Smuzhiyun 		if (drm_object_property_set_value(&connector->base,
587*4882a593Smuzhiyun 							property,
588*4882a593Smuzhiyun 							value))
589*4882a593Smuzhiyun 			goto set_prop_error;
590*4882a593Smuzhiyun 		else
591*4882a593Smuzhiyun                         gma_backlight_set(encoder->dev, value);
592*4882a593Smuzhiyun 	} else if (!strcmp(property->name, "DPMS")) {
593*4882a593Smuzhiyun 		const struct drm_encoder_helper_funcs *hfuncs
594*4882a593Smuzhiyun 						= encoder->helper_private;
595*4882a593Smuzhiyun 		hfuncs->dpms(encoder, value);
596*4882a593Smuzhiyun 	}
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun set_prop_done:
599*4882a593Smuzhiyun 	return 0;
600*4882a593Smuzhiyun set_prop_error:
601*4882a593Smuzhiyun 	return -1;
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun static const struct drm_encoder_helper_funcs psb_intel_lvds_helper_funcs = {
605*4882a593Smuzhiyun 	.dpms = psb_intel_lvds_encoder_dpms,
606*4882a593Smuzhiyun 	.mode_fixup = psb_intel_lvds_mode_fixup,
607*4882a593Smuzhiyun 	.prepare = psb_intel_lvds_prepare,
608*4882a593Smuzhiyun 	.mode_set = psb_intel_lvds_mode_set,
609*4882a593Smuzhiyun 	.commit = psb_intel_lvds_commit,
610*4882a593Smuzhiyun };
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun const struct drm_connector_helper_funcs
613*4882a593Smuzhiyun 				psb_intel_lvds_connector_helper_funcs = {
614*4882a593Smuzhiyun 	.get_modes = psb_intel_lvds_get_modes,
615*4882a593Smuzhiyun 	.mode_valid = psb_intel_lvds_mode_valid,
616*4882a593Smuzhiyun 	.best_encoder = gma_best_encoder,
617*4882a593Smuzhiyun };
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun const struct drm_connector_funcs psb_intel_lvds_connector_funcs = {
620*4882a593Smuzhiyun 	.dpms = drm_helper_connector_dpms,
621*4882a593Smuzhiyun 	.fill_modes = drm_helper_probe_single_connector_modes,
622*4882a593Smuzhiyun 	.set_property = psb_intel_lvds_set_property,
623*4882a593Smuzhiyun 	.destroy = psb_intel_lvds_destroy,
624*4882a593Smuzhiyun };
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun /**
627*4882a593Smuzhiyun  * psb_intel_lvds_init - setup LVDS connectors on this device
628*4882a593Smuzhiyun  * @dev: drm device
629*4882a593Smuzhiyun  *
630*4882a593Smuzhiyun  * Create the connector, register the LVDS DDC bus, and try to figure out what
631*4882a593Smuzhiyun  * modes we can display on the LVDS panel (if present).
632*4882a593Smuzhiyun  */
psb_intel_lvds_init(struct drm_device * dev,struct psb_intel_mode_device * mode_dev)633*4882a593Smuzhiyun void psb_intel_lvds_init(struct drm_device *dev,
634*4882a593Smuzhiyun 			 struct psb_intel_mode_device *mode_dev)
635*4882a593Smuzhiyun {
636*4882a593Smuzhiyun 	struct gma_encoder *gma_encoder;
637*4882a593Smuzhiyun 	struct gma_connector *gma_connector;
638*4882a593Smuzhiyun 	struct psb_intel_lvds_priv *lvds_priv;
639*4882a593Smuzhiyun 	struct drm_connector *connector;
640*4882a593Smuzhiyun 	struct drm_encoder *encoder;
641*4882a593Smuzhiyun 	struct drm_display_mode *scan;	/* *modes, *bios_mode; */
642*4882a593Smuzhiyun 	struct drm_crtc *crtc;
643*4882a593Smuzhiyun 	struct drm_psb_private *dev_priv = dev->dev_private;
644*4882a593Smuzhiyun 	u32 lvds;
645*4882a593Smuzhiyun 	int pipe;
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL);
648*4882a593Smuzhiyun 	if (!gma_encoder) {
649*4882a593Smuzhiyun 		dev_err(dev->dev, "gma_encoder allocation error\n");
650*4882a593Smuzhiyun 		return;
651*4882a593Smuzhiyun 	}
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	gma_connector = kzalloc(sizeof(struct gma_connector), GFP_KERNEL);
654*4882a593Smuzhiyun 	if (!gma_connector) {
655*4882a593Smuzhiyun 		dev_err(dev->dev, "gma_connector allocation error\n");
656*4882a593Smuzhiyun 		goto failed_encoder;
657*4882a593Smuzhiyun 	}
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	lvds_priv = kzalloc(sizeof(struct psb_intel_lvds_priv), GFP_KERNEL);
660*4882a593Smuzhiyun 	if (!lvds_priv) {
661*4882a593Smuzhiyun 		dev_err(dev->dev, "LVDS private allocation error\n");
662*4882a593Smuzhiyun 		goto failed_connector;
663*4882a593Smuzhiyun 	}
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun 	gma_encoder->dev_priv = lvds_priv;
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 	connector = &gma_connector->base;
668*4882a593Smuzhiyun 	gma_connector->save = psb_intel_lvds_save;
669*4882a593Smuzhiyun 	gma_connector->restore = psb_intel_lvds_restore;
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	encoder = &gma_encoder->base;
672*4882a593Smuzhiyun 	drm_connector_init(dev, connector,
673*4882a593Smuzhiyun 			   &psb_intel_lvds_connector_funcs,
674*4882a593Smuzhiyun 			   DRM_MODE_CONNECTOR_LVDS);
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_LVDS);
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	gma_connector_attach_encoder(gma_connector, gma_encoder);
679*4882a593Smuzhiyun 	gma_encoder->type = INTEL_OUTPUT_LVDS;
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun 	drm_encoder_helper_add(encoder, &psb_intel_lvds_helper_funcs);
682*4882a593Smuzhiyun 	drm_connector_helper_add(connector,
683*4882a593Smuzhiyun 				 &psb_intel_lvds_connector_helper_funcs);
684*4882a593Smuzhiyun 	connector->display_info.subpixel_order = SubPixelHorizontalRGB;
685*4882a593Smuzhiyun 	connector->interlace_allowed = false;
686*4882a593Smuzhiyun 	connector->doublescan_allowed = false;
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	/*Attach connector properties*/
689*4882a593Smuzhiyun 	drm_object_attach_property(&connector->base,
690*4882a593Smuzhiyun 				      dev->mode_config.scaling_mode_property,
691*4882a593Smuzhiyun 				      DRM_MODE_SCALE_FULLSCREEN);
692*4882a593Smuzhiyun 	drm_object_attach_property(&connector->base,
693*4882a593Smuzhiyun 				      dev_priv->backlight_property,
694*4882a593Smuzhiyun 				      BRIGHTNESS_MAX_LEVEL);
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	/*
697*4882a593Smuzhiyun 	 * Set up I2C bus
698*4882a593Smuzhiyun 	 * FIXME: distroy i2c_bus when exit
699*4882a593Smuzhiyun 	 */
700*4882a593Smuzhiyun 	lvds_priv->i2c_bus = psb_intel_i2c_create(dev, GPIOB, "LVDSBLC_B");
701*4882a593Smuzhiyun 	if (!lvds_priv->i2c_bus) {
702*4882a593Smuzhiyun 		dev_printk(KERN_ERR,
703*4882a593Smuzhiyun 			&dev->pdev->dev, "I2C bus registration failed.\n");
704*4882a593Smuzhiyun 		goto failed_blc_i2c;
705*4882a593Smuzhiyun 	}
706*4882a593Smuzhiyun 	lvds_priv->i2c_bus->slave_addr = 0x2C;
707*4882a593Smuzhiyun 	dev_priv->lvds_i2c_bus =  lvds_priv->i2c_bus;
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun 	/*
710*4882a593Smuzhiyun 	 * LVDS discovery:
711*4882a593Smuzhiyun 	 * 1) check for EDID on DDC
712*4882a593Smuzhiyun 	 * 2) check for VBT data
713*4882a593Smuzhiyun 	 * 3) check to see if LVDS is already on
714*4882a593Smuzhiyun 	 *    if none of the above, no panel
715*4882a593Smuzhiyun 	 * 4) make sure lid is open
716*4882a593Smuzhiyun 	 *    if closed, act like it's not there for now
717*4882a593Smuzhiyun 	 */
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun 	/* Set up the DDC bus. */
720*4882a593Smuzhiyun 	lvds_priv->ddc_bus = psb_intel_i2c_create(dev, GPIOC, "LVDSDDC_C");
721*4882a593Smuzhiyun 	if (!lvds_priv->ddc_bus) {
722*4882a593Smuzhiyun 		dev_printk(KERN_ERR, &dev->pdev->dev,
723*4882a593Smuzhiyun 			   "DDC bus registration " "failed.\n");
724*4882a593Smuzhiyun 		goto failed_ddc;
725*4882a593Smuzhiyun 	}
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	/*
728*4882a593Smuzhiyun 	 * Attempt to get the fixed panel mode from DDC.  Assume that the
729*4882a593Smuzhiyun 	 * preferred mode is the right one.
730*4882a593Smuzhiyun 	 */
731*4882a593Smuzhiyun 	mutex_lock(&dev->mode_config.mutex);
732*4882a593Smuzhiyun 	psb_intel_ddc_get_modes(connector, &lvds_priv->ddc_bus->adapter);
733*4882a593Smuzhiyun 	list_for_each_entry(scan, &connector->probed_modes, head) {
734*4882a593Smuzhiyun 		if (scan->type & DRM_MODE_TYPE_PREFERRED) {
735*4882a593Smuzhiyun 			mode_dev->panel_fixed_mode =
736*4882a593Smuzhiyun 			    drm_mode_duplicate(dev, scan);
737*4882a593Smuzhiyun 			DRM_DEBUG_KMS("Using mode from DDC\n");
738*4882a593Smuzhiyun 			goto out;	/* FIXME: check for quirks */
739*4882a593Smuzhiyun 		}
740*4882a593Smuzhiyun 	}
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 	/* Failed to get EDID, what about VBT? do we need this? */
743*4882a593Smuzhiyun 	if (dev_priv->lfp_lvds_vbt_mode) {
744*4882a593Smuzhiyun 		mode_dev->panel_fixed_mode =
745*4882a593Smuzhiyun 			drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 		if (mode_dev->panel_fixed_mode) {
748*4882a593Smuzhiyun 			mode_dev->panel_fixed_mode->type |=
749*4882a593Smuzhiyun 				DRM_MODE_TYPE_PREFERRED;
750*4882a593Smuzhiyun 			DRM_DEBUG_KMS("Using mode from VBT\n");
751*4882a593Smuzhiyun 			goto out;
752*4882a593Smuzhiyun 		}
753*4882a593Smuzhiyun 	}
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 	/*
756*4882a593Smuzhiyun 	 * If we didn't get EDID, try checking if the panel is already turned
757*4882a593Smuzhiyun 	 * on.	If so, assume that whatever is currently programmed is the
758*4882a593Smuzhiyun 	 * correct mode.
759*4882a593Smuzhiyun 	 */
760*4882a593Smuzhiyun 	lvds = REG_READ(LVDS);
761*4882a593Smuzhiyun 	pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
762*4882a593Smuzhiyun 	crtc = psb_intel_get_crtc_from_pipe(dev, pipe);
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 	if (crtc && (lvds & LVDS_PORT_EN)) {
765*4882a593Smuzhiyun 		mode_dev->panel_fixed_mode =
766*4882a593Smuzhiyun 		    psb_intel_crtc_mode_get(dev, crtc);
767*4882a593Smuzhiyun 		if (mode_dev->panel_fixed_mode) {
768*4882a593Smuzhiyun 			mode_dev->panel_fixed_mode->type |=
769*4882a593Smuzhiyun 			    DRM_MODE_TYPE_PREFERRED;
770*4882a593Smuzhiyun 			DRM_DEBUG_KMS("Using pre-programmed mode\n");
771*4882a593Smuzhiyun 			goto out;	/* FIXME: check for quirks */
772*4882a593Smuzhiyun 		}
773*4882a593Smuzhiyun 	}
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	/* If we still don't have a mode after all that, give up. */
776*4882a593Smuzhiyun 	if (!mode_dev->panel_fixed_mode) {
777*4882a593Smuzhiyun 		dev_err(dev->dev, "Found no modes on the lvds, ignoring the LVDS\n");
778*4882a593Smuzhiyun 		goto failed_find;
779*4882a593Smuzhiyun 	}
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun 	/*
782*4882a593Smuzhiyun 	 * Blacklist machines with BIOSes that list an LVDS panel without
783*4882a593Smuzhiyun 	 * actually having one.
784*4882a593Smuzhiyun 	 */
785*4882a593Smuzhiyun out:
786*4882a593Smuzhiyun 	mutex_unlock(&dev->mode_config.mutex);
787*4882a593Smuzhiyun 	drm_connector_register(connector);
788*4882a593Smuzhiyun 	return;
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun failed_find:
791*4882a593Smuzhiyun 	mutex_unlock(&dev->mode_config.mutex);
792*4882a593Smuzhiyun 	psb_intel_i2c_destroy(lvds_priv->ddc_bus);
793*4882a593Smuzhiyun failed_ddc:
794*4882a593Smuzhiyun 	psb_intel_i2c_destroy(lvds_priv->i2c_bus);
795*4882a593Smuzhiyun failed_blc_i2c:
796*4882a593Smuzhiyun 	drm_encoder_cleanup(encoder);
797*4882a593Smuzhiyun 	drm_connector_cleanup(connector);
798*4882a593Smuzhiyun failed_connector:
799*4882a593Smuzhiyun 	kfree(gma_connector);
800*4882a593Smuzhiyun failed_encoder:
801*4882a593Smuzhiyun 	kfree(gma_encoder);
802*4882a593Smuzhiyun }
803*4882a593Smuzhiyun 
804