drm/i915: Add LVDS support for IGDNG

Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
Signed-off-by: Eric Anholt <eric@anholt.net>
This commit is contained in:
Zhenyu Wang 2009-06-05 15:38:44 +08:00 committed by Eric Anholt
parent 30ad48b733
commit 541998a18b
2 changed files with 114 additions and 26 deletions

View file

@ -1542,6 +1542,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
int pch_fp_reg = (pipe == 0) ? PCH_FPA0 : PCH_FPB0; int pch_fp_reg = (pipe == 0) ? PCH_FPA0 : PCH_FPB0;
int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B; int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL; int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
int lvds_reg = LVDS;
u32 temp; u32 temp;
int sdvo_pixel_multiply; int sdvo_pixel_multiply;
@ -1772,8 +1773,12 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
* things on. * things on.
*/ */
if (is_lvds) { if (is_lvds) {
u32 lvds = I915_READ(LVDS); u32 lvds;
if (IS_IGDNG(dev))
lvds_reg = PCH_LVDS;
lvds = I915_READ(lvds_reg);
lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT; lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT;
/* Set the B0-B3 data pairs corresponding to whether we're going to /* Set the B0-B3 data pairs corresponding to whether we're going to
* set the DPLLs for dual-channel mode or not. * set the DPLLs for dual-channel mode or not.
@ -1788,8 +1793,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
* panels behave in the two modes. * panels behave in the two modes.
*/ */
I915_WRITE(LVDS, lvds); I915_WRITE(lvds_reg, lvds);
I915_READ(LVDS); I915_READ(lvds_reg);
} }
I915_WRITE(fp_reg, fp); I915_WRITE(fp_reg, fp);
@ -2428,7 +2433,7 @@ static void intel_setup_outputs(struct drm_device *dev)
intel_crt_init(dev); intel_crt_init(dev);
/* Set up integrated LVDS */ /* Set up integrated LVDS */
if (IS_MOBILE(dev) && !IS_I830(dev) && !IS_IGDNG(dev)) if (IS_MOBILE(dev) && !IS_I830(dev))
intel_lvds_init(dev); intel_lvds_init(dev);
if (IS_IGDNG(dev)) { if (IS_IGDNG(dev)) {

View file

@ -45,10 +45,15 @@
static void intel_lvds_set_backlight(struct drm_device *dev, int level) static void intel_lvds_set_backlight(struct drm_device *dev, int level)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 blc_pwm_ctl; u32 blc_pwm_ctl, reg;
blc_pwm_ctl = I915_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; if (IS_IGDNG(dev))
I915_WRITE(BLC_PWM_CTL, (blc_pwm_ctl | reg = BLC_PWM_CPU_CTL;
else
reg = BLC_PWM_CTL;
blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK;
I915_WRITE(reg, (blc_pwm_ctl |
(level << BACKLIGHT_DUTY_CYCLE_SHIFT))); (level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
} }
@ -58,8 +63,14 @@ static void intel_lvds_set_backlight(struct drm_device *dev, int level)
static u32 intel_lvds_get_max_backlight(struct drm_device *dev) static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 reg;
return ((I915_READ(BLC_PWM_CTL) & BACKLIGHT_MODULATION_FREQ_MASK) >> if (IS_IGDNG(dev))
reg = BLC_PWM_PCH_CTL2;
else
reg = BLC_PWM_CTL;
return ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >>
BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
} }
@ -69,23 +80,31 @@ static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
static void intel_lvds_set_power(struct drm_device *dev, bool on) static void intel_lvds_set_power(struct drm_device *dev, bool on)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp_status; u32 pp_status, ctl_reg, status_reg;
if (IS_IGDNG(dev)) {
ctl_reg = PCH_PP_CONTROL;
status_reg = PCH_PP_STATUS;
} else {
ctl_reg = PP_CONTROL;
status_reg = PP_STATUS;
}
if (on) { if (on) {
I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | I915_WRITE(ctl_reg, I915_READ(ctl_reg) |
POWER_TARGET_ON); POWER_TARGET_ON);
do { do {
pp_status = I915_READ(PP_STATUS); pp_status = I915_READ(status_reg);
} while ((pp_status & PP_ON) == 0); } while ((pp_status & PP_ON) == 0);
intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle); intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle);
} else { } else {
intel_lvds_set_backlight(dev, 0); intel_lvds_set_backlight(dev, 0);
I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & I915_WRITE(ctl_reg, I915_READ(ctl_reg) &
~POWER_TARGET_ON); ~POWER_TARGET_ON);
do { do {
pp_status = I915_READ(PP_STATUS); pp_status = I915_READ(status_reg);
} while (pp_status & PP_ON); } while (pp_status & PP_ON);
} }
} }
@ -106,12 +125,28 @@ static void intel_lvds_save(struct drm_connector *connector)
{ {
struct drm_device *dev = connector->dev; struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg;
u32 pwm_ctl_reg;
dev_priv->savePP_ON = I915_READ(PP_ON_DELAYS); if (IS_IGDNG(dev)) {
dev_priv->savePP_OFF = I915_READ(PP_OFF_DELAYS); pp_on_reg = PCH_PP_ON_DELAYS;
dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL); pp_off_reg = PCH_PP_OFF_DELAYS;
dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR); pp_ctl_reg = PCH_PP_CONTROL;
dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); pp_div_reg = PCH_PP_DIVISOR;
pwm_ctl_reg = BLC_PWM_CPU_CTL;
} else {
pp_on_reg = PP_ON_DELAYS;
pp_off_reg = PP_OFF_DELAYS;
pp_ctl_reg = PP_CONTROL;
pp_div_reg = PP_DIVISOR;
pwm_ctl_reg = BLC_PWM_CTL;
}
dev_priv->savePP_ON = I915_READ(pp_on_reg);
dev_priv->savePP_OFF = I915_READ(pp_off_reg);
dev_priv->savePP_CONTROL = I915_READ(pp_ctl_reg);
dev_priv->savePP_DIVISOR = I915_READ(pp_div_reg);
dev_priv->saveBLC_PWM_CTL = I915_READ(pwm_ctl_reg);
dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
BACKLIGHT_DUTY_CYCLE_MASK); BACKLIGHT_DUTY_CYCLE_MASK);
@ -127,12 +162,28 @@ static void intel_lvds_restore(struct drm_connector *connector)
{ {
struct drm_device *dev = connector->dev; struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg;
u32 pwm_ctl_reg;
I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL); if (IS_IGDNG(dev)) {
I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON); pp_on_reg = PCH_PP_ON_DELAYS;
I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF); pp_off_reg = PCH_PP_OFF_DELAYS;
I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR); pp_ctl_reg = PCH_PP_CONTROL;
I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL); pp_div_reg = PCH_PP_DIVISOR;
pwm_ctl_reg = BLC_PWM_CPU_CTL;
} else {
pp_on_reg = PP_ON_DELAYS;
pp_off_reg = PP_OFF_DELAYS;
pp_ctl_reg = PP_CONTROL;
pp_div_reg = PP_DIVISOR;
pwm_ctl_reg = BLC_PWM_CTL;
}
I915_WRITE(pwm_ctl_reg, dev_priv->saveBLC_PWM_CTL);
I915_WRITE(pp_on_reg, dev_priv->savePP_ON);
I915_WRITE(pp_off_reg, dev_priv->savePP_OFF);
I915_WRITE(pp_div_reg, dev_priv->savePP_DIVISOR);
I915_WRITE(pp_ctl_reg, dev_priv->savePP_CONTROL);
if (dev_priv->savePP_CONTROL & POWER_TARGET_ON) if (dev_priv->savePP_CONTROL & POWER_TARGET_ON)
intel_lvds_set_power(dev, true); intel_lvds_set_power(dev, true);
else else
@ -216,8 +267,14 @@ static void intel_lvds_prepare(struct drm_encoder *encoder)
{ {
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 reg;
dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); if (IS_IGDNG(dev))
reg = BLC_PWM_CPU_CTL;
else
reg = BLC_PWM_CTL;
dev_priv->saveBLC_PWM_CTL = I915_READ(reg);
dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
BACKLIGHT_DUTY_CYCLE_MASK); BACKLIGHT_DUTY_CYCLE_MASK);
@ -251,6 +308,10 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
* settings. * settings.
*/ */
/* No panel fitting yet, fixme */
if (IS_IGDNG(dev))
return;
/* /*
* Enable automatic panel scaling so that non-native modes fill the * Enable automatic panel scaling so that non-native modes fill the
* screen. Should be enabled before the pipe is enabled, according to * screen. Should be enabled before the pipe is enabled, according to
@ -446,12 +507,18 @@ void intel_lvds_init(struct drm_device *dev)
struct drm_display_mode *scan; /* *modes, *bios_mode; */ struct drm_display_mode *scan; /* *modes, *bios_mode; */
struct drm_crtc *crtc; struct drm_crtc *crtc;
u32 lvds; u32 lvds;
int pipe; int pipe, gpio = GPIOC;
/* Skip init on machines we know falsely report LVDS */ /* Skip init on machines we know falsely report LVDS */
if (dmi_check_system(intel_no_lvds)) if (dmi_check_system(intel_no_lvds))
return; return;
if (IS_IGDNG(dev)) {
if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
return;
gpio = PCH_GPIOC;
}
intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL); intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
if (!intel_output) { if (!intel_output) {
return; return;
@ -486,7 +553,7 @@ void intel_lvds_init(struct drm_device *dev)
*/ */
/* Set up the DDC bus. */ /* Set up the DDC bus. */
intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C"); intel_output->ddc_bus = intel_i2c_create(dev, gpio, "LVDSDDC_C");
if (!intel_output->ddc_bus) { if (!intel_output->ddc_bus) {
dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
"failed.\n"); "failed.\n");
@ -528,6 +595,11 @@ void intel_lvds_init(struct drm_device *dev)
* on. If so, assume that whatever is currently programmed is the * on. If so, assume that whatever is currently programmed is the
* correct mode. * correct mode.
*/ */
/* IGDNG: FIXME if still fail, not try pipe mode now */
if (IS_IGDNG(dev))
goto failed;
lvds = I915_READ(LVDS); lvds = I915_READ(LVDS);
pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
crtc = intel_get_crtc_from_pipe(dev, pipe); crtc = intel_get_crtc_from_pipe(dev, pipe);
@ -546,6 +618,17 @@ void intel_lvds_init(struct drm_device *dev)
goto failed; goto failed;
out: out:
if (IS_IGDNG(dev)) {
u32 pwm;
/* make sure PWM is enabled */
pwm = I915_READ(BLC_PWM_CPU_CTL2);
pwm |= (PWM_ENABLE | PWM_PIPE_B);
I915_WRITE(BLC_PWM_CPU_CTL2, pwm);
pwm = I915_READ(BLC_PWM_PCH_CTL1);
pwm |= PWM_PCH_ENABLE;
I915_WRITE(BLC_PWM_PCH_CTL1, pwm);
}
drm_sysfs_connector_add(connector); drm_sysfs_connector_add(connector);
return; return;