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