X-Git-Url: http://nv-tegra.nvidia.com/gitweb/?p=linux-2.6.git;a=blobdiff_plain;f=drivers%2Fgpu%2Fdrm%2Fi915%2Fintel_tv.c;h=50d7ed70b338a2c867eccb7caa1562e1ce6cbf53;hp=0e606855c8586e09ba5b26410a37803554901edf;hb=6b702462cbe5b6f372966a53f4465d745d86b65c;hpb=ba01079c71559304771f9d741c9bbe8b2eac22a2 diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 0e60685..50d7ed7 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1082,7 +1082,7 @@ intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mo const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output); /* Ensure TV refresh is close to desired refresh */ - if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode)) < 1) + if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode)) < 10) return MODE_OK; return MODE_CLOCK_RANGE; } @@ -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; @@ -1495,7 +1506,8 @@ intel_tv_get_modes(struct drm_connector *connector) struct drm_display_mode *mode_ptr; struct intel_output *intel_output = to_intel_output(connector); const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output); - int j; + int j, count = 0; + u64 tmp; for (j = 0; j < sizeof(input_res_table) / sizeof(input_res_table[0]); j++) { @@ -1510,8 +1522,9 @@ intel_tv_get_modes(struct drm_connector *connector) && !tv_mode->component_only)) continue; - mode_ptr = drm_calloc(1, sizeof(struct drm_display_mode), - DRM_MEM_DRIVER); + mode_ptr = drm_mode_create(connector->dev); + if (!mode_ptr) + continue; strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN); mode_ptr->hdisplay = hactive_s; @@ -1528,15 +1541,17 @@ intel_tv_get_modes(struct drm_connector *connector) mode_ptr->vsync_end = mode_ptr->vsync_start + 1; mode_ptr->vtotal = vactive_s + 33; - mode_ptr->clock = (int) (tv_mode->refresh * - mode_ptr->vtotal * - mode_ptr->htotal / 1000) / 1000; + tmp = (u64) tv_mode->refresh * mode_ptr->vtotal; + tmp *= mode_ptr->htotal; + tmp = div_u64(tmp, 1000000); + mode_ptr->clock = (int) tmp; mode_ptr->type = DRM_MODE_TYPE_DRIVER; drm_mode_probed_add(connector, mode_ptr); + count++; } - return 0; + return count; } static void @@ -1558,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; } @@ -1598,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,