Merge branch 'drm-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[linux-2.6.git] / drivers / gpu / drm / i915 / intel_tv.c
index 08c4034..50d7ed7 100644 (file)
@@ -1135,7 +1135,8 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
        if (!tv_mode)
                return; /* can't happen (mode_prepare prevents this) */
 
-       tv_ctl = 0;
+       tv_ctl = I915_READ(TV_CTL);
+       tv_ctl &= TV_CTL_SAVE;
 
        switch (tv_priv->type) {
        default:
@@ -1215,7 +1216,6 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
        /* dda1 implies valid video levels */
        if (tv_mode->dda1_inc) {
                scctl1 |= TV_SC_DDA1_EN;
-               scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
        }
 
        if (tv_mode->dda2_inc)
@@ -1225,6 +1225,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                scctl1 |= TV_SC_DDA3_EN;
 
        scctl1 |= tv_mode->sc_reset;
+       scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
        scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
 
        scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
@@ -1266,7 +1267,11 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                           color_conversion->av);
        }
 
-       I915_WRITE(TV_CLR_KNOBS, 0x00606000);
+       if (IS_I965G(dev))
+               I915_WRITE(TV_CLR_KNOBS, 0x00404000);
+       else
+               I915_WRITE(TV_CLR_KNOBS, 0x00606000);
+
        if (video_levels)
                I915_WRITE(TV_CLR_LEVEL,
                           ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
@@ -1387,6 +1392,9 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output)
                tv_ctl &= ~TV_TEST_MODE_MASK;
                tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
                tv_dac &= ~TVDAC_SENSE_MASK;
+               tv_dac &= ~DAC_A_MASK;
+               tv_dac &= ~DAC_B_MASK;
+               tv_dac &= ~DAC_C_MASK;
                tv_dac |= (TVDAC_STATE_CHG_EN |
                           TVDAC_A_SENSE_CTL |
                           TVDAC_B_SENSE_CTL |
@@ -1401,6 +1409,7 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output)
                tv_dac = I915_READ(TV_DAC);
                I915_WRITE(TV_DAC, save_tv_dac);
                I915_WRITE(TV_CTL, save_tv_ctl);
+               intel_wait_for_vblank(dev);
        }
        /*
         *  A B C
@@ -1451,7 +1460,7 @@ intel_tv_detect(struct drm_connector *connector)
        mode = reported_modes[0];
        drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
 
-       if (encoder->crtc) {
+       if (encoder->crtc && encoder->crtc->enabled) {
                type = intel_tv_detect_type(encoder->crtc, intel_output);
        } else {
                crtc = intel_get_load_detect_pipe(intel_output, &mode, &dpms_mode);
@@ -1462,6 +1471,8 @@ intel_tv_detect(struct drm_connector *connector)
                        type = -1;
        }
 
+       tv_priv->type = type;
+
        if (type < 0)
                return connector_status_disconnected;
 
@@ -1562,33 +1573,49 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop
        struct drm_device *dev = connector->dev;
        struct intel_output *intel_output = to_intel_output(connector);
        struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+       struct drm_encoder *encoder = &intel_output->enc;
+       struct drm_crtc *crtc = encoder->crtc;
        int ret = 0;
+       bool changed = false;
 
        ret = drm_connector_property_set_value(connector, property, val);
        if (ret < 0)
                goto out;
 
-       if (property == dev->mode_config.tv_left_margin_property)
+       if (property == dev->mode_config.tv_left_margin_property &&
+               tv_priv->margin[TV_MARGIN_LEFT] != val) {
                tv_priv->margin[TV_MARGIN_LEFT] = val;
-       else if (property == dev->mode_config.tv_right_margin_property)
+               changed = true;
+       } else if (property == dev->mode_config.tv_right_margin_property &&
+               tv_priv->margin[TV_MARGIN_RIGHT] != val) {
                tv_priv->margin[TV_MARGIN_RIGHT] = val;
-       else if (property == dev->mode_config.tv_top_margin_property)
+               changed = true;
+       } else if (property == dev->mode_config.tv_top_margin_property &&
+               tv_priv->margin[TV_MARGIN_TOP] != val) {
                tv_priv->margin[TV_MARGIN_TOP] = val;
-       else if (property == dev->mode_config.tv_bottom_margin_property)
+               changed = true;
+       } else if (property == dev->mode_config.tv_bottom_margin_property &&
+               tv_priv->margin[TV_MARGIN_BOTTOM] != val) {
                tv_priv->margin[TV_MARGIN_BOTTOM] = val;
-       else if (property == dev->mode_config.tv_mode_property) {
+               changed = true;
+       } else if (property == dev->mode_config.tv_mode_property) {
                if (val >= NUM_TV_MODES) {
                        ret = -EINVAL;
                        goto out;
                }
+               if (!strcmp(tv_priv->tv_format, tv_modes[val].name))
+                       goto out;
+
                tv_priv->tv_format = tv_modes[val].name;
-               intel_tv_mode_set(&intel_output->enc, NULL, NULL);
+               changed = true;
        } else {
                ret = -EINVAL;
                goto out;
        }
 
-       intel_tv_mode_set(&intel_output->enc, NULL, NULL);
+       if (changed && crtc)
+               drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
+                               crtc->y, crtc->fb);
 out:
        return ret;
 }
@@ -1602,6 +1629,7 @@ static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = {
 };
 
 static const struct drm_connector_funcs intel_tv_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
        .save = intel_tv_save,
        .restore = intel_tv_restore,
        .detect = intel_tv_detect,