X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=drivers%2Fgpu%2Fdrm%2Fi915%2Fintel_hdmi.c;h=ed65c6ddf5a2b42d0a61e64ec3ab071bfeff83a9;hb=22b8bf17c6c1db887e3e9adb0778d6f03e621e66;hp=2ee9821b9d9312bb502df6502cc7b8c0cdc63f77;hpb=1bd12c91de35756129b8ffe28a4fe45177b86381;p=~andy%2Flinux diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 2ee9821b9d9..ed65c6ddf5a 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -48,7 +48,7 @@ assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi) struct drm_i915_private *dev_priv = dev->dev_private; uint32_t enabled_bits; - enabled_bits = IS_HASWELL(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE; + enabled_bits = HAS_DDI(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE; WARN(I915_READ(intel_hdmi->sdvox_reg) & enabled_bits, "HDMI port enabled, expecting disabled\n"); @@ -331,6 +331,7 @@ static void intel_set_infoframe(struct drm_encoder *encoder, static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); struct dip_infoframe avi_if = { .type = DIP_TYPE_AVI, .ver = DIP_VERSION_AVI, @@ -340,6 +341,13 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2; + if (intel_hdmi->rgb_quant_range_selectable) { + if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED; + else + avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL; + } + avi_if.body.avi.VIC = drm_mode_cea_vic(adjusted_mode); intel_set_infoframe(encoder, &avi_if); @@ -364,7 +372,8 @@ static void g4x_set_infoframes(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct drm_i915_private *dev_priv = encoder->dev->dev_private; - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); + struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; u32 reg = VIDEO_DIP_CTL; u32 val = I915_READ(reg); u32 port; @@ -391,11 +400,11 @@ static void g4x_set_infoframes(struct drm_encoder *encoder, return; } - switch (intel_hdmi->sdvox_reg) { - case SDVOB: + switch (intel_dig_port->port) { + case PORT_B: port = VIDEO_DIP_PORT_B; break; - case SDVOC: + case PORT_C: port = VIDEO_DIP_PORT_C; break; default: @@ -428,7 +437,8 @@ static void ibx_set_infoframes(struct drm_encoder *encoder, { struct drm_i915_private *dev_priv = encoder->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); + struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg); u32 port; @@ -447,14 +457,14 @@ static void ibx_set_infoframes(struct drm_encoder *encoder, return; } - switch (intel_hdmi->sdvox_reg) { - case HDMIB: + switch (intel_dig_port->port) { + case PORT_B: port = VIDEO_DIP_PORT_B; break; - case HDMIC: + case PORT_C: port = VIDEO_DIP_PORT_C; break; - case HDMID: + case PORT_D: port = VIDEO_DIP_PORT_D; break; default: @@ -766,6 +776,20 @@ bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + + if (intel_hdmi->color_range_auto) { + /* See CEA-861-E - 5.1 Default Encoding Parameters */ + if (intel_hdmi->has_hdmi_sink && + drm_mode_cea_vic(adjusted_mode) > 1) + intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235; + else + intel_hdmi->color_range = 0; + } + + if (intel_hdmi->color_range) + adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; + return true; } @@ -773,14 +797,15 @@ static bool g4x_hdmi_connected(struct intel_hdmi *intel_hdmi) { struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi); struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_digital_port *intel_dig_port = hdmi_to_dig_port(intel_hdmi); uint32_t bit; - switch (intel_hdmi->sdvox_reg) { - case SDVOB: - bit = HDMIB_HOTPLUG_LIVE_STATUS; + switch (intel_dig_port->port) { + case PORT_B: + bit = PORTB_HOTPLUG_LIVE_STATUS; break; - case SDVOC: - bit = HDMIC_HOTPLUG_LIVE_STATUS; + case PORT_C: + bit = PORTC_HOTPLUG_LIVE_STATUS; break; default: bit = 0; @@ -793,19 +818,25 @@ static bool g4x_hdmi_connected(struct intel_hdmi *intel_hdmi) static enum drm_connector_status intel_hdmi_detect(struct drm_connector *connector, bool force) { + struct drm_device *dev = connector->dev; struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); struct intel_digital_port *intel_dig_port = hdmi_to_dig_port(intel_hdmi); struct intel_encoder *intel_encoder = &intel_dig_port->base; - struct drm_i915_private *dev_priv = connector->dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; struct edid *edid; enum drm_connector_status status = connector_status_disconnected; - if (IS_G4X(connector->dev) && !g4x_hdmi_connected(intel_hdmi)) + + if (IS_G4X(dev) && !g4x_hdmi_connected(intel_hdmi)) return status; + else if (HAS_PCH_SPLIT(dev) && + !ibx_digital_port_connected(dev_priv, intel_dig_port)) + return status; intel_hdmi->has_hdmi_sink = false; intel_hdmi->has_audio = false; + intel_hdmi->rgb_quant_range_selectable = false; edid = drm_get_edid(connector, intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus)); @@ -817,6 +848,8 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid); intel_hdmi->has_audio = drm_detect_monitor_audio(edid); + intel_hdmi->rgb_quant_range_selectable = + drm_rgb_quant_range_selectable(edid); } kfree(edid); } @@ -902,21 +935,29 @@ intel_hdmi_set_property(struct drm_connector *connector, } if (property == dev_priv->broadcast_rgb_property) { - if (val == !!intel_hdmi->color_range) - return 0; - - intel_hdmi->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0; + switch (val) { + case INTEL_BROADCAST_RGB_AUTO: + intel_hdmi->color_range_auto = true; + break; + case INTEL_BROADCAST_RGB_FULL: + intel_hdmi->color_range_auto = false; + intel_hdmi->color_range = 0; + break; + case INTEL_BROADCAST_RGB_LIMITED: + intel_hdmi->color_range_auto = false; + intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235; + break; + default: + return -EINVAL; + } goto done; } return -EINVAL; done: - if (intel_dig_port->base.base.crtc) { - struct drm_crtc *crtc = intel_dig_port->base.base.crtc; - intel_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, crtc->fb); - } + if (intel_dig_port->base.base.crtc) + intel_crtc_restore_mode(intel_dig_port->base.base.crtc); return 0; } @@ -957,6 +998,7 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c { intel_attach_force_audio_property(connector); intel_attach_broadcast_rgb_property(connector); + intel_hdmi->color_range_auto = true; } void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, @@ -980,15 +1022,15 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, switch (port) { case PORT_B: intel_hdmi->ddc_bus = GMBUS_PORT_DPB; - dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTB_HOTPLUG_INT_STATUS; break; case PORT_C: intel_hdmi->ddc_bus = GMBUS_PORT_DPC; - dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTC_HOTPLUG_INT_STATUS; break; case PORT_D: intel_hdmi->ddc_bus = GMBUS_PORT_DPD; - dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTD_HOTPLUG_INT_STATUS; break; case PORT_A: /* Internal port only for eDP. */ @@ -1002,7 +1044,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, } else if (IS_VALLEYVIEW(dev)) { intel_hdmi->write_infoframe = vlv_write_infoframe; intel_hdmi->set_infoframes = vlv_set_infoframes; - } else if (IS_HASWELL(dev)) { + } else if (HAS_DDI(dev)) { intel_hdmi->write_infoframe = hsw_write_infoframe; intel_hdmi->set_infoframes = hsw_set_infoframes; } else if (HAS_PCH_IBX(dev)) { @@ -1013,7 +1055,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, intel_hdmi->set_infoframes = cpt_set_infoframes; } - if (IS_HASWELL(dev)) + if (HAS_DDI(dev)) intel_connector->get_hw_state = intel_ddi_connector_get_hw_state; else intel_connector->get_hw_state = intel_connector_get_hw_state;