1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright © 2006-2011 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/dmi.h>
12*4882a593Smuzhiyun #include <linux/i2c.h>
13*4882a593Smuzhiyun #include <linux/pm_runtime.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include <drm/drm_simple_kms_helper.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include "cdv_device.h"
18*4882a593Smuzhiyun #include "intel_bios.h"
19*4882a593Smuzhiyun #include "power.h"
20*4882a593Smuzhiyun #include "psb_drv.h"
21*4882a593Smuzhiyun #include "psb_intel_drv.h"
22*4882a593Smuzhiyun #include "psb_intel_reg.h"
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun /**
25*4882a593Smuzhiyun * LVDS I2C backlight control macros
26*4882a593Smuzhiyun */
27*4882a593Smuzhiyun #define BRIGHTNESS_MAX_LEVEL 100
28*4882a593Smuzhiyun #define BRIGHTNESS_MASK 0xFF
29*4882a593Smuzhiyun #define BLC_I2C_TYPE 0x01
30*4882a593Smuzhiyun #define BLC_PWM_TYPT 0x02
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #define BLC_POLARITY_NORMAL 0
33*4882a593Smuzhiyun #define BLC_POLARITY_INVERSE 1
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #define PSB_BLC_MAX_PWM_REG_FREQ (0xFFFE)
36*4882a593Smuzhiyun #define PSB_BLC_MIN_PWM_REG_FREQ (0x2)
37*4882a593Smuzhiyun #define PSB_BLC_PWM_PRECISION_FACTOR (10)
38*4882a593Smuzhiyun #define PSB_BACKLIGHT_PWM_CTL_SHIFT (16)
39*4882a593Smuzhiyun #define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE)
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun struct cdv_intel_lvds_priv {
42*4882a593Smuzhiyun /**
43*4882a593Smuzhiyun * Saved LVDO output states
44*4882a593Smuzhiyun */
45*4882a593Smuzhiyun uint32_t savePP_ON;
46*4882a593Smuzhiyun uint32_t savePP_OFF;
47*4882a593Smuzhiyun uint32_t saveLVDS;
48*4882a593Smuzhiyun uint32_t savePP_CONTROL;
49*4882a593Smuzhiyun uint32_t savePP_CYCLE;
50*4882a593Smuzhiyun uint32_t savePFIT_CONTROL;
51*4882a593Smuzhiyun uint32_t savePFIT_PGM_RATIOS;
52*4882a593Smuzhiyun uint32_t saveBLC_PWM_CTL;
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun /*
56*4882a593Smuzhiyun * Returns the maximum level of the backlight duty cycle field.
57*4882a593Smuzhiyun */
cdv_intel_lvds_get_max_backlight(struct drm_device * dev)58*4882a593Smuzhiyun static u32 cdv_intel_lvds_get_max_backlight(struct drm_device *dev)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
61*4882a593Smuzhiyun u32 retval;
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun if (gma_power_begin(dev, false)) {
64*4882a593Smuzhiyun retval = ((REG_READ(BLC_PWM_CTL) &
65*4882a593Smuzhiyun BACKLIGHT_MODULATION_FREQ_MASK) >>
66*4882a593Smuzhiyun BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun gma_power_end(dev);
69*4882a593Smuzhiyun } else
70*4882a593Smuzhiyun retval = ((dev_priv->regs.saveBLC_PWM_CTL &
71*4882a593Smuzhiyun BACKLIGHT_MODULATION_FREQ_MASK) >>
72*4882a593Smuzhiyun BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun return retval;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun /**
78*4882a593Smuzhiyun * Sets the backlight level.
79*4882a593Smuzhiyun *
80*4882a593Smuzhiyun * level backlight level, from 0 to cdv_intel_lvds_get_max_backlight().
81*4882a593Smuzhiyun */
cdv_intel_lvds_set_backlight(struct drm_device * dev,int level)82*4882a593Smuzhiyun static void cdv_intel_lvds_set_backlight(struct drm_device *dev, int level)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
85*4882a593Smuzhiyun u32 blc_pwm_ctl;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun if (gma_power_begin(dev, false)) {
88*4882a593Smuzhiyun blc_pwm_ctl =
89*4882a593Smuzhiyun REG_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
90*4882a593Smuzhiyun REG_WRITE(BLC_PWM_CTL,
91*4882a593Smuzhiyun (blc_pwm_ctl |
92*4882a593Smuzhiyun (level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
93*4882a593Smuzhiyun gma_power_end(dev);
94*4882a593Smuzhiyun } else {
95*4882a593Smuzhiyun blc_pwm_ctl = dev_priv->regs.saveBLC_PWM_CTL &
96*4882a593Smuzhiyun ~BACKLIGHT_DUTY_CYCLE_MASK;
97*4882a593Smuzhiyun dev_priv->regs.saveBLC_PWM_CTL = (blc_pwm_ctl |
98*4882a593Smuzhiyun (level << BACKLIGHT_DUTY_CYCLE_SHIFT));
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun /**
103*4882a593Smuzhiyun * Sets the power state for the panel.
104*4882a593Smuzhiyun */
cdv_intel_lvds_set_power(struct drm_device * dev,struct drm_encoder * encoder,bool on)105*4882a593Smuzhiyun static void cdv_intel_lvds_set_power(struct drm_device *dev,
106*4882a593Smuzhiyun struct drm_encoder *encoder, bool on)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
109*4882a593Smuzhiyun u32 pp_status;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun if (!gma_power_begin(dev, true))
112*4882a593Smuzhiyun return;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun if (on) {
115*4882a593Smuzhiyun REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) |
116*4882a593Smuzhiyun POWER_TARGET_ON);
117*4882a593Smuzhiyun do {
118*4882a593Smuzhiyun pp_status = REG_READ(PP_STATUS);
119*4882a593Smuzhiyun } while ((pp_status & PP_ON) == 0);
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun cdv_intel_lvds_set_backlight(dev,
122*4882a593Smuzhiyun dev_priv->mode_dev.backlight_duty_cycle);
123*4882a593Smuzhiyun } else {
124*4882a593Smuzhiyun cdv_intel_lvds_set_backlight(dev, 0);
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) &
127*4882a593Smuzhiyun ~POWER_TARGET_ON);
128*4882a593Smuzhiyun do {
129*4882a593Smuzhiyun pp_status = REG_READ(PP_STATUS);
130*4882a593Smuzhiyun } while (pp_status & PP_ON);
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun gma_power_end(dev);
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun
cdv_intel_lvds_encoder_dpms(struct drm_encoder * encoder,int mode)135*4882a593Smuzhiyun static void cdv_intel_lvds_encoder_dpms(struct drm_encoder *encoder, int mode)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun struct drm_device *dev = encoder->dev;
138*4882a593Smuzhiyun if (mode == DRM_MODE_DPMS_ON)
139*4882a593Smuzhiyun cdv_intel_lvds_set_power(dev, encoder, true);
140*4882a593Smuzhiyun else
141*4882a593Smuzhiyun cdv_intel_lvds_set_power(dev, encoder, false);
142*4882a593Smuzhiyun /* XXX: We never power down the LVDS pairs. */
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
cdv_intel_lvds_save(struct drm_connector * connector)145*4882a593Smuzhiyun static void cdv_intel_lvds_save(struct drm_connector *connector)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun
cdv_intel_lvds_restore(struct drm_connector * connector)149*4882a593Smuzhiyun static void cdv_intel_lvds_restore(struct drm_connector *connector)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
cdv_intel_lvds_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)153*4882a593Smuzhiyun static enum drm_mode_status cdv_intel_lvds_mode_valid(struct drm_connector *connector,
154*4882a593Smuzhiyun struct drm_display_mode *mode)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun struct drm_device *dev = connector->dev;
157*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
158*4882a593Smuzhiyun struct drm_display_mode *fixed_mode =
159*4882a593Smuzhiyun dev_priv->mode_dev.panel_fixed_mode;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun /* just in case */
162*4882a593Smuzhiyun if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
163*4882a593Smuzhiyun return MODE_NO_DBLESCAN;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun /* just in case */
166*4882a593Smuzhiyun if (mode->flags & DRM_MODE_FLAG_INTERLACE)
167*4882a593Smuzhiyun return MODE_NO_INTERLACE;
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun if (fixed_mode) {
170*4882a593Smuzhiyun if (mode->hdisplay > fixed_mode->hdisplay)
171*4882a593Smuzhiyun return MODE_PANEL;
172*4882a593Smuzhiyun if (mode->vdisplay > fixed_mode->vdisplay)
173*4882a593Smuzhiyun return MODE_PANEL;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun return MODE_OK;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun
cdv_intel_lvds_mode_fixup(struct drm_encoder * encoder,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)178*4882a593Smuzhiyun static bool cdv_intel_lvds_mode_fixup(struct drm_encoder *encoder,
179*4882a593Smuzhiyun const struct drm_display_mode *mode,
180*4882a593Smuzhiyun struct drm_display_mode *adjusted_mode)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun struct drm_device *dev = encoder->dev;
183*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
184*4882a593Smuzhiyun struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev;
185*4882a593Smuzhiyun struct drm_encoder *tmp_encoder;
186*4882a593Smuzhiyun struct drm_display_mode *panel_fixed_mode = mode_dev->panel_fixed_mode;
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun /* Should never happen!! */
189*4882a593Smuzhiyun list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list,
190*4882a593Smuzhiyun head) {
191*4882a593Smuzhiyun if (tmp_encoder != encoder
192*4882a593Smuzhiyun && tmp_encoder->crtc == encoder->crtc) {
193*4882a593Smuzhiyun pr_err("Can't enable LVDS and another encoder on the same pipe\n");
194*4882a593Smuzhiyun return false;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun /*
199*4882a593Smuzhiyun * If we have timings from the BIOS for the panel, put them in
200*4882a593Smuzhiyun * to the adjusted mode. The CRTC will be set up for this mode,
201*4882a593Smuzhiyun * with the panel scaling set up to source from the H/VDisplay
202*4882a593Smuzhiyun * of the original mode.
203*4882a593Smuzhiyun */
204*4882a593Smuzhiyun if (panel_fixed_mode != NULL) {
205*4882a593Smuzhiyun adjusted_mode->hdisplay = panel_fixed_mode->hdisplay;
206*4882a593Smuzhiyun adjusted_mode->hsync_start = panel_fixed_mode->hsync_start;
207*4882a593Smuzhiyun adjusted_mode->hsync_end = panel_fixed_mode->hsync_end;
208*4882a593Smuzhiyun adjusted_mode->htotal = panel_fixed_mode->htotal;
209*4882a593Smuzhiyun adjusted_mode->vdisplay = panel_fixed_mode->vdisplay;
210*4882a593Smuzhiyun adjusted_mode->vsync_start = panel_fixed_mode->vsync_start;
211*4882a593Smuzhiyun adjusted_mode->vsync_end = panel_fixed_mode->vsync_end;
212*4882a593Smuzhiyun adjusted_mode->vtotal = panel_fixed_mode->vtotal;
213*4882a593Smuzhiyun adjusted_mode->clock = panel_fixed_mode->clock;
214*4882a593Smuzhiyun drm_mode_set_crtcinfo(adjusted_mode,
215*4882a593Smuzhiyun CRTC_INTERLACE_HALVE_V);
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun /*
219*4882a593Smuzhiyun * XXX: It would be nice to support lower refresh rates on the
220*4882a593Smuzhiyun * panels to reduce power consumption, and perhaps match the
221*4882a593Smuzhiyun * user's requested refresh rate.
222*4882a593Smuzhiyun */
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun return true;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
cdv_intel_lvds_prepare(struct drm_encoder * encoder)227*4882a593Smuzhiyun static void cdv_intel_lvds_prepare(struct drm_encoder *encoder)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun struct drm_device *dev = encoder->dev;
230*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
231*4882a593Smuzhiyun struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun if (!gma_power_begin(dev, true))
234*4882a593Smuzhiyun return;
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun mode_dev->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL);
237*4882a593Smuzhiyun mode_dev->backlight_duty_cycle = (mode_dev->saveBLC_PWM_CTL &
238*4882a593Smuzhiyun BACKLIGHT_DUTY_CYCLE_MASK);
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun cdv_intel_lvds_set_power(dev, encoder, false);
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun gma_power_end(dev);
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun
cdv_intel_lvds_commit(struct drm_encoder * encoder)245*4882a593Smuzhiyun static void cdv_intel_lvds_commit(struct drm_encoder *encoder)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun struct drm_device *dev = encoder->dev;
248*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
249*4882a593Smuzhiyun struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun if (mode_dev->backlight_duty_cycle == 0)
252*4882a593Smuzhiyun mode_dev->backlight_duty_cycle =
253*4882a593Smuzhiyun cdv_intel_lvds_get_max_backlight(dev);
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun cdv_intel_lvds_set_power(dev, encoder, true);
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
cdv_intel_lvds_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)258*4882a593Smuzhiyun static void cdv_intel_lvds_mode_set(struct drm_encoder *encoder,
259*4882a593Smuzhiyun struct drm_display_mode *mode,
260*4882a593Smuzhiyun struct drm_display_mode *adjusted_mode)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun struct drm_device *dev = encoder->dev;
263*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
264*4882a593Smuzhiyun struct gma_crtc *gma_crtc = to_gma_crtc(encoder->crtc);
265*4882a593Smuzhiyun u32 pfit_control;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun /*
268*4882a593Smuzhiyun * The LVDS pin pair will already have been turned on in the
269*4882a593Smuzhiyun * cdv_intel_crtc_mode_set since it has a large impact on the DPLL
270*4882a593Smuzhiyun * settings.
271*4882a593Smuzhiyun */
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun /*
274*4882a593Smuzhiyun * Enable automatic panel scaling so that non-native modes fill the
275*4882a593Smuzhiyun * screen. Should be enabled before the pipe is enabled, according to
276*4882a593Smuzhiyun * register description and PRM.
277*4882a593Smuzhiyun */
278*4882a593Smuzhiyun if (mode->hdisplay != adjusted_mode->hdisplay ||
279*4882a593Smuzhiyun mode->vdisplay != adjusted_mode->vdisplay)
280*4882a593Smuzhiyun pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE |
281*4882a593Smuzhiyun HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR |
282*4882a593Smuzhiyun HORIZ_INTERP_BILINEAR);
283*4882a593Smuzhiyun else
284*4882a593Smuzhiyun pfit_control = 0;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun pfit_control |= gma_crtc->pipe << PFIT_PIPE_SHIFT;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun if (dev_priv->lvds_dither)
289*4882a593Smuzhiyun pfit_control |= PANEL_8TO6_DITHER_ENABLE;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun REG_WRITE(PFIT_CONTROL, pfit_control);
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun /**
295*4882a593Smuzhiyun * Return the list of DDC modes if available, or the BIOS fixed mode otherwise.
296*4882a593Smuzhiyun */
cdv_intel_lvds_get_modes(struct drm_connector * connector)297*4882a593Smuzhiyun static int cdv_intel_lvds_get_modes(struct drm_connector *connector)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun struct drm_device *dev = connector->dev;
300*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
301*4882a593Smuzhiyun struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
302*4882a593Smuzhiyun struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev;
303*4882a593Smuzhiyun int ret;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun ret = psb_intel_ddc_get_modes(connector, &gma_encoder->i2c_bus->adapter);
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun if (ret)
308*4882a593Smuzhiyun return ret;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun if (mode_dev->panel_fixed_mode != NULL) {
311*4882a593Smuzhiyun struct drm_display_mode *mode =
312*4882a593Smuzhiyun drm_mode_duplicate(dev, mode_dev->panel_fixed_mode);
313*4882a593Smuzhiyun drm_mode_probed_add(connector, mode);
314*4882a593Smuzhiyun return 1;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun return 0;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun /**
321*4882a593Smuzhiyun * cdv_intel_lvds_destroy - unregister and free LVDS structures
322*4882a593Smuzhiyun * @connector: connector to free
323*4882a593Smuzhiyun *
324*4882a593Smuzhiyun * Unregister the DDC bus for this connector then free the driver private
325*4882a593Smuzhiyun * structure.
326*4882a593Smuzhiyun */
cdv_intel_lvds_destroy(struct drm_connector * connector)327*4882a593Smuzhiyun static void cdv_intel_lvds_destroy(struct drm_connector *connector)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun struct gma_encoder *gma_encoder = gma_attached_encoder(connector);
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun psb_intel_i2c_destroy(gma_encoder->i2c_bus);
332*4882a593Smuzhiyun drm_connector_unregister(connector);
333*4882a593Smuzhiyun drm_connector_cleanup(connector);
334*4882a593Smuzhiyun kfree(connector);
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
cdv_intel_lvds_set_property(struct drm_connector * connector,struct drm_property * property,uint64_t value)337*4882a593Smuzhiyun static int cdv_intel_lvds_set_property(struct drm_connector *connector,
338*4882a593Smuzhiyun struct drm_property *property,
339*4882a593Smuzhiyun uint64_t value)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun struct drm_encoder *encoder = connector->encoder;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun if (!strcmp(property->name, "scaling mode") && encoder) {
344*4882a593Smuzhiyun struct gma_crtc *crtc = to_gma_crtc(encoder->crtc);
345*4882a593Smuzhiyun uint64_t curValue;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun if (!crtc)
348*4882a593Smuzhiyun return -1;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun switch (value) {
351*4882a593Smuzhiyun case DRM_MODE_SCALE_FULLSCREEN:
352*4882a593Smuzhiyun break;
353*4882a593Smuzhiyun case DRM_MODE_SCALE_NO_SCALE:
354*4882a593Smuzhiyun break;
355*4882a593Smuzhiyun case DRM_MODE_SCALE_ASPECT:
356*4882a593Smuzhiyun break;
357*4882a593Smuzhiyun default:
358*4882a593Smuzhiyun return -1;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun if (drm_object_property_get_value(&connector->base,
362*4882a593Smuzhiyun property,
363*4882a593Smuzhiyun &curValue))
364*4882a593Smuzhiyun return -1;
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun if (curValue == value)
367*4882a593Smuzhiyun return 0;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun if (drm_object_property_set_value(&connector->base,
370*4882a593Smuzhiyun property,
371*4882a593Smuzhiyun value))
372*4882a593Smuzhiyun return -1;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun if (crtc->saved_mode.hdisplay != 0 &&
375*4882a593Smuzhiyun crtc->saved_mode.vdisplay != 0) {
376*4882a593Smuzhiyun if (!drm_crtc_helper_set_mode(encoder->crtc,
377*4882a593Smuzhiyun &crtc->saved_mode,
378*4882a593Smuzhiyun encoder->crtc->x,
379*4882a593Smuzhiyun encoder->crtc->y,
380*4882a593Smuzhiyun encoder->crtc->primary->fb))
381*4882a593Smuzhiyun return -1;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun } else if (!strcmp(property->name, "backlight") && encoder) {
384*4882a593Smuzhiyun if (drm_object_property_set_value(&connector->base,
385*4882a593Smuzhiyun property,
386*4882a593Smuzhiyun value))
387*4882a593Smuzhiyun return -1;
388*4882a593Smuzhiyun else
389*4882a593Smuzhiyun gma_backlight_set(encoder->dev, value);
390*4882a593Smuzhiyun } else if (!strcmp(property->name, "DPMS") && encoder) {
391*4882a593Smuzhiyun const struct drm_encoder_helper_funcs *helpers =
392*4882a593Smuzhiyun encoder->helper_private;
393*4882a593Smuzhiyun helpers->dpms(encoder, value);
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun return 0;
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun static const struct drm_encoder_helper_funcs
399*4882a593Smuzhiyun cdv_intel_lvds_helper_funcs = {
400*4882a593Smuzhiyun .dpms = cdv_intel_lvds_encoder_dpms,
401*4882a593Smuzhiyun .mode_fixup = cdv_intel_lvds_mode_fixup,
402*4882a593Smuzhiyun .prepare = cdv_intel_lvds_prepare,
403*4882a593Smuzhiyun .mode_set = cdv_intel_lvds_mode_set,
404*4882a593Smuzhiyun .commit = cdv_intel_lvds_commit,
405*4882a593Smuzhiyun };
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun static const struct drm_connector_helper_funcs
408*4882a593Smuzhiyun cdv_intel_lvds_connector_helper_funcs = {
409*4882a593Smuzhiyun .get_modes = cdv_intel_lvds_get_modes,
410*4882a593Smuzhiyun .mode_valid = cdv_intel_lvds_mode_valid,
411*4882a593Smuzhiyun .best_encoder = gma_best_encoder,
412*4882a593Smuzhiyun };
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun static const struct drm_connector_funcs cdv_intel_lvds_connector_funcs = {
415*4882a593Smuzhiyun .dpms = drm_helper_connector_dpms,
416*4882a593Smuzhiyun .fill_modes = drm_helper_probe_single_connector_modes,
417*4882a593Smuzhiyun .set_property = cdv_intel_lvds_set_property,
418*4882a593Smuzhiyun .destroy = cdv_intel_lvds_destroy,
419*4882a593Smuzhiyun };
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun /*
422*4882a593Smuzhiyun * Enumerate the child dev array parsed from VBT to check whether
423*4882a593Smuzhiyun * the LVDS is present.
424*4882a593Smuzhiyun * If it is present, return 1.
425*4882a593Smuzhiyun * If it is not present, return false.
426*4882a593Smuzhiyun * If no child dev is parsed from VBT, it assumes that the LVDS is present.
427*4882a593Smuzhiyun */
lvds_is_present_in_vbt(struct drm_device * dev,u8 * i2c_pin)428*4882a593Smuzhiyun static bool lvds_is_present_in_vbt(struct drm_device *dev,
429*4882a593Smuzhiyun u8 *i2c_pin)
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
432*4882a593Smuzhiyun int i;
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun if (!dev_priv->child_dev_num)
435*4882a593Smuzhiyun return true;
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun for (i = 0; i < dev_priv->child_dev_num; i++) {
438*4882a593Smuzhiyun struct child_device_config *child = dev_priv->child_dev + i;
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun /* If the device type is not LFP, continue.
441*4882a593Smuzhiyun * We have to check both the new identifiers as well as the
442*4882a593Smuzhiyun * old for compatibility with some BIOSes.
443*4882a593Smuzhiyun */
444*4882a593Smuzhiyun if (child->device_type != DEVICE_TYPE_INT_LFP &&
445*4882a593Smuzhiyun child->device_type != DEVICE_TYPE_LFP)
446*4882a593Smuzhiyun continue;
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun if (child->i2c_pin)
449*4882a593Smuzhiyun *i2c_pin = child->i2c_pin;
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun /* However, we cannot trust the BIOS writers to populate
452*4882a593Smuzhiyun * the VBT correctly. Since LVDS requires additional
453*4882a593Smuzhiyun * information from AIM blocks, a non-zero addin offset is
454*4882a593Smuzhiyun * a good indicator that the LVDS is actually present.
455*4882a593Smuzhiyun */
456*4882a593Smuzhiyun if (child->addin_offset)
457*4882a593Smuzhiyun return true;
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun /* But even then some BIOS writers perform some black magic
460*4882a593Smuzhiyun * and instantiate the device without reference to any
461*4882a593Smuzhiyun * additional data. Trust that if the VBT was written into
462*4882a593Smuzhiyun * the OpRegion then they have validated the LVDS's existence.
463*4882a593Smuzhiyun */
464*4882a593Smuzhiyun if (dev_priv->opregion.vbt)
465*4882a593Smuzhiyun return true;
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun return false;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun /**
472*4882a593Smuzhiyun * cdv_intel_lvds_init - setup LVDS connectors on this device
473*4882a593Smuzhiyun * @dev: drm device
474*4882a593Smuzhiyun *
475*4882a593Smuzhiyun * Create the connector, register the LVDS DDC bus, and try to figure out what
476*4882a593Smuzhiyun * modes we can display on the LVDS panel (if present).
477*4882a593Smuzhiyun */
cdv_intel_lvds_init(struct drm_device * dev,struct psb_intel_mode_device * mode_dev)478*4882a593Smuzhiyun void cdv_intel_lvds_init(struct drm_device *dev,
479*4882a593Smuzhiyun struct psb_intel_mode_device *mode_dev)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun struct gma_encoder *gma_encoder;
482*4882a593Smuzhiyun struct gma_connector *gma_connector;
483*4882a593Smuzhiyun struct cdv_intel_lvds_priv *lvds_priv;
484*4882a593Smuzhiyun struct drm_connector *connector;
485*4882a593Smuzhiyun struct drm_encoder *encoder;
486*4882a593Smuzhiyun struct drm_display_mode *scan;
487*4882a593Smuzhiyun struct drm_crtc *crtc;
488*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
489*4882a593Smuzhiyun u32 lvds;
490*4882a593Smuzhiyun int pipe;
491*4882a593Smuzhiyun u8 pin;
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun if (!dev_priv->lvds_enabled_in_vbt)
494*4882a593Smuzhiyun return;
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun pin = GMBUS_PORT_PANEL;
497*4882a593Smuzhiyun if (!lvds_is_present_in_vbt(dev, &pin)) {
498*4882a593Smuzhiyun DRM_DEBUG_KMS("LVDS is not present in VBT\n");
499*4882a593Smuzhiyun return;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun gma_encoder = kzalloc(sizeof(struct gma_encoder),
503*4882a593Smuzhiyun GFP_KERNEL);
504*4882a593Smuzhiyun if (!gma_encoder)
505*4882a593Smuzhiyun return;
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun gma_connector = kzalloc(sizeof(struct gma_connector),
508*4882a593Smuzhiyun GFP_KERNEL);
509*4882a593Smuzhiyun if (!gma_connector)
510*4882a593Smuzhiyun goto failed_connector;
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun lvds_priv = kzalloc(sizeof(struct cdv_intel_lvds_priv), GFP_KERNEL);
513*4882a593Smuzhiyun if (!lvds_priv)
514*4882a593Smuzhiyun goto failed_lvds_priv;
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun gma_encoder->dev_priv = lvds_priv;
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun connector = &gma_connector->base;
519*4882a593Smuzhiyun gma_connector->save = cdv_intel_lvds_save;
520*4882a593Smuzhiyun gma_connector->restore = cdv_intel_lvds_restore;
521*4882a593Smuzhiyun encoder = &gma_encoder->base;
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun drm_connector_init(dev, connector,
525*4882a593Smuzhiyun &cdv_intel_lvds_connector_funcs,
526*4882a593Smuzhiyun DRM_MODE_CONNECTOR_LVDS);
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_LVDS);
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun gma_connector_attach_encoder(gma_connector, gma_encoder);
531*4882a593Smuzhiyun gma_encoder->type = INTEL_OUTPUT_LVDS;
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun drm_encoder_helper_add(encoder, &cdv_intel_lvds_helper_funcs);
534*4882a593Smuzhiyun drm_connector_helper_add(connector,
535*4882a593Smuzhiyun &cdv_intel_lvds_connector_helper_funcs);
536*4882a593Smuzhiyun connector->display_info.subpixel_order = SubPixelHorizontalRGB;
537*4882a593Smuzhiyun connector->interlace_allowed = false;
538*4882a593Smuzhiyun connector->doublescan_allowed = false;
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun /*Attach connector properties*/
541*4882a593Smuzhiyun drm_object_attach_property(&connector->base,
542*4882a593Smuzhiyun dev->mode_config.scaling_mode_property,
543*4882a593Smuzhiyun DRM_MODE_SCALE_FULLSCREEN);
544*4882a593Smuzhiyun drm_object_attach_property(&connector->base,
545*4882a593Smuzhiyun dev_priv->backlight_property,
546*4882a593Smuzhiyun BRIGHTNESS_MAX_LEVEL);
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun /**
549*4882a593Smuzhiyun * Set up I2C bus
550*4882a593Smuzhiyun * FIXME: distroy i2c_bus when exit
551*4882a593Smuzhiyun */
552*4882a593Smuzhiyun gma_encoder->i2c_bus = psb_intel_i2c_create(dev,
553*4882a593Smuzhiyun GPIOB,
554*4882a593Smuzhiyun "LVDSBLC_B");
555*4882a593Smuzhiyun if (!gma_encoder->i2c_bus) {
556*4882a593Smuzhiyun dev_printk(KERN_ERR,
557*4882a593Smuzhiyun &dev->pdev->dev, "I2C bus registration failed.\n");
558*4882a593Smuzhiyun goto failed_blc_i2c;
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun gma_encoder->i2c_bus->slave_addr = 0x2C;
561*4882a593Smuzhiyun dev_priv->lvds_i2c_bus = gma_encoder->i2c_bus;
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun /*
564*4882a593Smuzhiyun * LVDS discovery:
565*4882a593Smuzhiyun * 1) check for EDID on DDC
566*4882a593Smuzhiyun * 2) check for VBT data
567*4882a593Smuzhiyun * 3) check to see if LVDS is already on
568*4882a593Smuzhiyun * if none of the above, no panel
569*4882a593Smuzhiyun * 4) make sure lid is open
570*4882a593Smuzhiyun * if closed, act like it's not there for now
571*4882a593Smuzhiyun */
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun /* Set up the DDC bus. */
574*4882a593Smuzhiyun gma_encoder->ddc_bus = psb_intel_i2c_create(dev,
575*4882a593Smuzhiyun GPIOC,
576*4882a593Smuzhiyun "LVDSDDC_C");
577*4882a593Smuzhiyun if (!gma_encoder->ddc_bus) {
578*4882a593Smuzhiyun dev_printk(KERN_ERR, &dev->pdev->dev,
579*4882a593Smuzhiyun "DDC bus registration " "failed.\n");
580*4882a593Smuzhiyun goto failed_ddc;
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun /*
584*4882a593Smuzhiyun * Attempt to get the fixed panel mode from DDC. Assume that the
585*4882a593Smuzhiyun * preferred mode is the right one.
586*4882a593Smuzhiyun */
587*4882a593Smuzhiyun mutex_lock(&dev->mode_config.mutex);
588*4882a593Smuzhiyun psb_intel_ddc_get_modes(connector,
589*4882a593Smuzhiyun &gma_encoder->ddc_bus->adapter);
590*4882a593Smuzhiyun list_for_each_entry(scan, &connector->probed_modes, head) {
591*4882a593Smuzhiyun if (scan->type & DRM_MODE_TYPE_PREFERRED) {
592*4882a593Smuzhiyun mode_dev->panel_fixed_mode =
593*4882a593Smuzhiyun drm_mode_duplicate(dev, scan);
594*4882a593Smuzhiyun goto out; /* FIXME: check for quirks */
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun /* Failed to get EDID, what about VBT? do we need this?*/
599*4882a593Smuzhiyun if (dev_priv->lfp_lvds_vbt_mode) {
600*4882a593Smuzhiyun mode_dev->panel_fixed_mode =
601*4882a593Smuzhiyun drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
602*4882a593Smuzhiyun if (mode_dev->panel_fixed_mode) {
603*4882a593Smuzhiyun mode_dev->panel_fixed_mode->type |=
604*4882a593Smuzhiyun DRM_MODE_TYPE_PREFERRED;
605*4882a593Smuzhiyun goto out; /* FIXME: check for quirks */
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun /*
609*4882a593Smuzhiyun * If we didn't get EDID, try checking if the panel is already turned
610*4882a593Smuzhiyun * on. If so, assume that whatever is currently programmed is the
611*4882a593Smuzhiyun * correct mode.
612*4882a593Smuzhiyun */
613*4882a593Smuzhiyun lvds = REG_READ(LVDS);
614*4882a593Smuzhiyun pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
615*4882a593Smuzhiyun crtc = psb_intel_get_crtc_from_pipe(dev, pipe);
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun if (crtc && (lvds & LVDS_PORT_EN)) {
618*4882a593Smuzhiyun mode_dev->panel_fixed_mode =
619*4882a593Smuzhiyun cdv_intel_crtc_mode_get(dev, crtc);
620*4882a593Smuzhiyun if (mode_dev->panel_fixed_mode) {
621*4882a593Smuzhiyun mode_dev->panel_fixed_mode->type |=
622*4882a593Smuzhiyun DRM_MODE_TYPE_PREFERRED;
623*4882a593Smuzhiyun goto out; /* FIXME: check for quirks */
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun /* If we still don't have a mode after all that, give up. */
628*4882a593Smuzhiyun if (!mode_dev->panel_fixed_mode) {
629*4882a593Smuzhiyun DRM_DEBUG
630*4882a593Smuzhiyun ("Found no modes on the lvds, ignoring the LVDS\n");
631*4882a593Smuzhiyun goto failed_find;
632*4882a593Smuzhiyun }
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun /* setup PWM */
635*4882a593Smuzhiyun {
636*4882a593Smuzhiyun u32 pwm;
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun pwm = REG_READ(BLC_PWM_CTL2);
639*4882a593Smuzhiyun if (pipe == 1)
640*4882a593Smuzhiyun pwm |= PWM_PIPE_B;
641*4882a593Smuzhiyun else
642*4882a593Smuzhiyun pwm &= ~PWM_PIPE_B;
643*4882a593Smuzhiyun pwm |= PWM_ENABLE;
644*4882a593Smuzhiyun REG_WRITE(BLC_PWM_CTL2, pwm);
645*4882a593Smuzhiyun }
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun out:
648*4882a593Smuzhiyun mutex_unlock(&dev->mode_config.mutex);
649*4882a593Smuzhiyun drm_connector_register(connector);
650*4882a593Smuzhiyun return;
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun failed_find:
653*4882a593Smuzhiyun mutex_unlock(&dev->mode_config.mutex);
654*4882a593Smuzhiyun pr_err("Failed find\n");
655*4882a593Smuzhiyun psb_intel_i2c_destroy(gma_encoder->ddc_bus);
656*4882a593Smuzhiyun failed_ddc:
657*4882a593Smuzhiyun pr_err("Failed DDC\n");
658*4882a593Smuzhiyun psb_intel_i2c_destroy(gma_encoder->i2c_bus);
659*4882a593Smuzhiyun failed_blc_i2c:
660*4882a593Smuzhiyun pr_err("Failed BLC\n");
661*4882a593Smuzhiyun drm_encoder_cleanup(encoder);
662*4882a593Smuzhiyun drm_connector_cleanup(connector);
663*4882a593Smuzhiyun kfree(lvds_priv);
664*4882a593Smuzhiyun failed_lvds_priv:
665*4882a593Smuzhiyun kfree(gma_connector);
666*4882a593Smuzhiyun failed_connector:
667*4882a593Smuzhiyun kfree(gma_encoder);
668*4882a593Smuzhiyun }
669