166,6 → 166,19 |
POSTING_READ(VIDEO_DIP_CTL); |
} |
|
static bool g4x_infoframe_enabled(struct drm_encoder *encoder) |
{ |
struct drm_device *dev = encoder->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); |
u32 val = I915_READ(VIDEO_DIP_CTL); |
|
if (VIDEO_DIP_PORT(intel_dig_port->port) == (val & VIDEO_DIP_PORT_MASK)) |
return val & VIDEO_DIP_ENABLE; |
|
return false; |
} |
|
static void ibx_write_infoframe(struct drm_encoder *encoder, |
enum hdmi_infoframe_type type, |
const void *frame, ssize_t len) |
204,6 → 217,17 |
POSTING_READ(reg); |
} |
|
static bool ibx_infoframe_enabled(struct drm_encoder *encoder) |
{ |
struct drm_device *dev = encoder->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); |
int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); |
u32 val = I915_READ(reg); |
|
return val & VIDEO_DIP_ENABLE; |
} |
|
static void cpt_write_infoframe(struct drm_encoder *encoder, |
enum hdmi_infoframe_type type, |
const void *frame, ssize_t len) |
245,6 → 269,17 |
POSTING_READ(reg); |
} |
|
static bool cpt_infoframe_enabled(struct drm_encoder *encoder) |
{ |
struct drm_device *dev = encoder->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); |
int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); |
u32 val = I915_READ(reg); |
|
return val & VIDEO_DIP_ENABLE; |
} |
|
static void vlv_write_infoframe(struct drm_encoder *encoder, |
enum hdmi_infoframe_type type, |
const void *frame, ssize_t len) |
283,6 → 318,17 |
POSTING_READ(reg); |
} |
|
static bool vlv_infoframe_enabled(struct drm_encoder *encoder) |
{ |
struct drm_device *dev = encoder->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); |
int reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); |
u32 val = I915_READ(reg); |
|
return val & VIDEO_DIP_ENABLE; |
} |
|
static void hsw_write_infoframe(struct drm_encoder *encoder, |
enum hdmi_infoframe_type type, |
const void *frame, ssize_t len) |
320,6 → 366,18 |
POSTING_READ(ctl_reg); |
} |
|
static bool hsw_infoframe_enabled(struct drm_encoder *encoder) |
{ |
struct drm_device *dev = encoder->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); |
u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder); |
u32 val = I915_READ(ctl_reg); |
|
return val & (VIDEO_DIP_ENABLE_AVI_HSW | VIDEO_DIP_ENABLE_SPD_HSW | |
VIDEO_DIP_ENABLE_VS_HSW); |
} |
|
/* |
* The data we write to the DIP data buffer registers is 1 byte bigger than the |
* HDMI infoframe size because of an ECC/reserved byte at position 3 (starting |
661,14 → 719,6 |
if (crtc->config.has_hdmi_sink) |
hdmi_val |= HDMI_MODE_SELECT_HDMI; |
|
if (crtc->config.has_audio) { |
WARN_ON(!crtc->config.has_hdmi_sink); |
DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", |
pipe_name(crtc->pipe)); |
hdmi_val |= SDVO_AUDIO_ENABLE; |
intel_write_eld(&encoder->base, adjusted_mode); |
} |
|
if (HAS_PCH_CPT(dev)) |
hdmi_val |= SDVO_PIPE_SEL_CPT(crtc->pipe); |
else if (IS_CHERRYVIEW(dev)) |
690,7 → 740,7 |
u32 tmp; |
|
power_domain = intel_display_port_power_domain(encoder); |
if (!intel_display_power_enabled(dev_priv, power_domain)) |
if (!intel_display_power_is_enabled(dev_priv, power_domain)) |
return false; |
|
tmp = I915_READ(intel_hdmi->hdmi_reg); |
732,7 → 782,10 |
if (tmp & HDMI_MODE_SELECT_HDMI) |
pipe_config->has_hdmi_sink = true; |
|
if (tmp & HDMI_MODE_SELECT_HDMI) |
if (intel_hdmi->infoframe_enabled(&encoder->base)) |
pipe_config->has_infoframe = true; |
|
if (tmp & SDVO_AUDIO_ENABLE) |
pipe_config->has_audio = true; |
|
if (!HAS_PCH_SPLIT(dev) && |
791,7 → 844,14 |
I915_WRITE(intel_hdmi->hdmi_reg, temp); |
POSTING_READ(intel_hdmi->hdmi_reg); |
} |
|
if (intel_crtc->config.has_audio) { |
WARN_ON(!intel_crtc->config.has_hdmi_sink); |
DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", |
pipe_name(intel_crtc->pipe)); |
intel_audio_codec_enable(encoder); |
} |
} |
|
static void vlv_enable_hdmi(struct intel_encoder *encoder) |
{ |
802,9 → 862,13 |
struct drm_device *dev = encoder->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); |
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); |
u32 temp; |
u32 enable_bits = SDVO_ENABLE | SDVO_AUDIO_ENABLE; |
|
if (crtc->config.has_audio) |
intel_audio_codec_disable(encoder); |
|
temp = I915_READ(intel_hdmi->hdmi_reg); |
|
/* HW workaround for IBX, we need to move the port to transcoder A |
869,10 → 933,15 |
intel_hdmi_mode_valid(struct drm_connector *connector, |
struct drm_display_mode *mode) |
{ |
if (mode->clock > hdmi_portclock_limit(intel_attached_hdmi(connector), |
int clock = mode->clock; |
|
if (mode->flags & DRM_MODE_FLAG_DBLCLK) |
clock *= 2; |
|
if (clock > hdmi_portclock_limit(intel_attached_hdmi(connector), |
true)) |
return MODE_CLOCK_HIGH; |
if (mode->clock < 20000) |
if (clock < 20000) |
return MODE_CLOCK_LOW; |
|
if (mode->flags & DRM_MODE_FLAG_DBLSCAN) |
890,7 → 959,7 |
if (HAS_GMCH_DISPLAY(dev)) |
return false; |
|
list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { |
for_each_intel_encoder(dev, encoder) { |
if (encoder->new_crtc != crtc) |
continue; |
|
917,6 → 986,9 |
|
pipe_config->has_hdmi_sink = intel_hdmi->has_hdmi_sink; |
|
if (pipe_config->has_hdmi_sink) |
pipe_config->has_infoframe = true; |
|
if (intel_hdmi->color_range_auto) { |
/* See CEA-861-E - 5.1 Default Encoding Parameters */ |
if (pipe_config->has_hdmi_sink && |
926,6 → 998,10 |
intel_hdmi->color_range = 0; |
} |
|
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) { |
pipe_config->pixel_multiplier = 2; |
} |
|
if (intel_hdmi->color_range) |
pipe_config->limited_color_range = true; |
|
967,105 → 1043,118 |
return true; |
} |
|
static enum drm_connector_status |
intel_hdmi_detect(struct drm_connector *connector, bool force) |
static void |
intel_hdmi_unset_edid(struct drm_connector *connector) |
{ |
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 = dev->dev_private; |
|
intel_hdmi->has_hdmi_sink = false; |
intel_hdmi->has_audio = false; |
intel_hdmi->rgb_quant_range_selectable = false; |
|
kfree(to_intel_connector(connector)->detect_edid); |
to_intel_connector(connector)->detect_edid = NULL; |
} |
|
static bool |
intel_hdmi_set_edid(struct drm_connector *connector) |
{ |
struct drm_i915_private *dev_priv = to_i915(connector->dev); |
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); |
struct intel_encoder *intel_encoder = |
&hdmi_to_dig_port(intel_hdmi)->base; |
enum intel_display_power_domain power_domain; |
struct edid *edid; |
enum intel_display_power_domain power_domain; |
enum drm_connector_status status = connector_status_disconnected; |
bool connected = false; |
|
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", |
connector->base.id, connector->name); |
|
power_domain = intel_display_port_power_domain(intel_encoder); |
intel_display_power_get(dev_priv, power_domain); |
|
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)); |
|
if (edid) { |
if (edid->input & DRM_EDID_INPUT_DIGITAL) { |
status = connector_status_connected; |
if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI) |
intel_hdmi->has_hdmi_sink = |
drm_detect_hdmi_monitor(edid); |
intel_hdmi->has_audio = drm_detect_monitor_audio(edid); |
intel_display_power_put(dev_priv, power_domain); |
|
to_intel_connector(connector)->detect_edid = edid; |
if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { |
intel_hdmi->rgb_quant_range_selectable = |
drm_rgb_quant_range_selectable(edid); |
} |
kfree(edid); |
} |
|
if (status == connector_status_connected) { |
intel_hdmi->has_audio = drm_detect_monitor_audio(edid); |
if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO) |
intel_hdmi->has_audio = |
(intel_hdmi->force_audio == HDMI_AUDIO_ON); |
intel_encoder->type = INTEL_OUTPUT_HDMI; |
intel_hdmi->force_audio == HDMI_AUDIO_ON; |
|
if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI) |
intel_hdmi->has_hdmi_sink = |
drm_detect_hdmi_monitor(edid); |
|
connected = true; |
} |
|
intel_display_power_put(dev_priv, power_domain); |
return connected; |
} |
|
static enum drm_connector_status |
intel_hdmi_detect(struct drm_connector *connector, bool force) |
{ |
enum drm_connector_status status; |
|
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", |
connector->base.id, connector->name); |
|
intel_hdmi_unset_edid(connector); |
|
if (intel_hdmi_set_edid(connector)) { |
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); |
|
hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI; |
status = connector_status_connected; |
} else |
status = connector_status_disconnected; |
|
return status; |
} |
|
static int intel_hdmi_get_modes(struct drm_connector *connector) |
static void |
intel_hdmi_force(struct drm_connector *connector) |
{ |
struct intel_encoder *intel_encoder = intel_attached_encoder(connector); |
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base); |
struct drm_i915_private *dev_priv = connector->dev->dev_private; |
enum intel_display_power_domain power_domain; |
int ret; |
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); |
|
/* We should parse the EDID data and find out if it's an HDMI sink so |
* we can send audio to it. |
*/ |
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", |
connector->base.id, connector->name); |
|
power_domain = intel_display_port_power_domain(intel_encoder); |
intel_display_power_get(dev_priv, power_domain); |
intel_hdmi_unset_edid(connector); |
|
ret = intel_ddc_get_modes(connector, |
intel_gmbus_get_adapter(dev_priv, |
intel_hdmi->ddc_bus)); |
if (connector->status != connector_status_connected) |
return; |
|
intel_display_power_put(dev_priv, power_domain); |
intel_hdmi_set_edid(connector); |
hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI; |
} |
|
return ret; |
static int intel_hdmi_get_modes(struct drm_connector *connector) |
{ |
struct edid *edid; |
|
edid = to_intel_connector(connector)->detect_edid; |
if (edid == NULL) |
return 0; |
|
return intel_connector_update_modes(connector, edid); |
} |
|
static bool |
intel_hdmi_detect_audio(struct drm_connector *connector) |
{ |
struct intel_encoder *intel_encoder = intel_attached_encoder(connector); |
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base); |
struct drm_i915_private *dev_priv = connector->dev->dev_private; |
enum intel_display_power_domain power_domain; |
bool has_audio = false; |
struct edid *edid; |
bool has_audio = false; |
|
power_domain = intel_display_port_power_domain(intel_encoder); |
intel_display_power_get(dev_priv, power_domain); |
|
edid = drm_get_edid(connector, |
intel_gmbus_get_adapter(dev_priv, |
intel_hdmi->ddc_bus)); |
if (edid) { |
if (edid->input & DRM_EDID_INPUT_DIGITAL) |
edid = to_intel_connector(connector)->detect_edid; |
if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) |
has_audio = drm_detect_monitor_audio(edid); |
kfree(edid); |
} |
|
intel_display_power_put(dev_priv, power_domain); |
|
return has_audio; |
} |
|
1265,6 → 1354,8 |
enum pipe pipe = intel_crtc->pipe; |
u32 val; |
|
intel_hdmi_prepare(encoder); |
|
mutex_lock(&dev_priv->dpio_lock); |
|
/* program left/right clock distribution */ |
1370,10 → 1461,13 |
static void chv_hdmi_pre_enable(struct intel_encoder *encoder) |
{ |
struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); |
struct intel_hdmi *intel_hdmi = &dport->hdmi; |
struct drm_device *dev = encoder->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = |
to_intel_crtc(encoder->base.crtc); |
struct drm_display_mode *adjusted_mode = |
&intel_crtc->config.adjusted_mode; |
enum dpio_channel ch = vlv_dport_to_channel(dport); |
int pipe = intel_crtc->pipe; |
int data, i; |
1381,6 → 1475,15 |
|
mutex_lock(&dev_priv->dpio_lock); |
|
/* allow hardware to manage TX FIFO reset source */ |
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW11(ch)); |
val &= ~DPIO_LANEDESKEW_STRAP_OVRD; |
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val); |
|
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch)); |
val &= ~DPIO_LANEDESKEW_STRAP_OVRD; |
vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val); |
|
/* Deassert soft data lane reset*/ |
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch)); |
val |= CHV_PCS_REQ_SOFTRESET_EN; |
1417,12 → 1520,26 |
/* Clear calc init */ |
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW10(ch)); |
val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3); |
val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK); |
val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5; |
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val); |
|
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch)); |
val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3); |
val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK); |
val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5; |
vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val); |
|
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW9(ch)); |
val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK); |
val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000; |
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW9(ch), val); |
|
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW9(ch)); |
val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK); |
val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000; |
vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW9(ch), val); |
|
/* FIXME: Program the support xxx V-dB */ |
/* Use 800mV-0dB */ |
for (i = 0; i < 4; i++) { |
1434,8 → 1551,8 |
|
for (i = 0; i < 4; i++) { |
val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i)); |
val &= ~DPIO_SWING_MARGIN_MASK; |
val |= 102 << DPIO_SWING_MARGIN_SHIFT; |
val &= ~DPIO_SWING_MARGIN000_MASK; |
val |= 102 << DPIO_SWING_MARGIN000_SHIFT; |
vlv_dpio_write(dev_priv, pipe, CHV_TX_DW2(ch, i), val); |
} |
|
1475,6 → 1592,10 |
|
mutex_unlock(&dev_priv->dpio_lock); |
|
intel_hdmi->set_infoframes(&encoder->base, |
intel_crtc->config.has_hdmi_sink, |
adjusted_mode); |
|
intel_enable_hdmi(encoder); |
|
vlv_wait_port_ready(dev_priv, dport); |
1482,6 → 1603,7 |
|
static void intel_hdmi_destroy(struct drm_connector *connector) |
{ |
kfree(to_intel_connector(connector)->detect_edid); |
drm_connector_cleanup(connector); |
kfree(connector); |
} |
1489,6 → 1611,7 |
static const struct drm_connector_funcs intel_hdmi_connector_funcs = { |
.dpms = intel_connector_dpms, |
.detect = intel_hdmi_detect, |
.force = intel_hdmi_force, |
.fill_modes = drm_helper_probe_single_connector_modes, |
.set_property = intel_hdmi_set_property, |
.destroy = intel_hdmi_destroy, |
1567,18 → 1690,23 |
if (IS_VALLEYVIEW(dev)) { |
intel_hdmi->write_infoframe = vlv_write_infoframe; |
intel_hdmi->set_infoframes = vlv_set_infoframes; |
intel_hdmi->infoframe_enabled = vlv_infoframe_enabled; |
} else if (IS_G4X(dev)) { |
intel_hdmi->write_infoframe = g4x_write_infoframe; |
intel_hdmi->set_infoframes = g4x_set_infoframes; |
intel_hdmi->infoframe_enabled = g4x_infoframe_enabled; |
} else if (HAS_DDI(dev)) { |
intel_hdmi->write_infoframe = hsw_write_infoframe; |
intel_hdmi->set_infoframes = hsw_set_infoframes; |
intel_hdmi->infoframe_enabled = hsw_infoframe_enabled; |
} else if (HAS_PCH_IBX(dev)) { |
intel_hdmi->write_infoframe = ibx_write_infoframe; |
intel_hdmi->set_infoframes = ibx_set_infoframes; |
intel_hdmi->infoframe_enabled = ibx_infoframe_enabled; |
} else { |
intel_hdmi->write_infoframe = cpt_write_infoframe; |
intel_hdmi->set_infoframes = cpt_set_infoframes; |
intel_hdmi->infoframe_enabled = cpt_infoframe_enabled; |
} |
|
if (HAS_DDI(dev)) |