113,7 → 113,8 |
} |
|
static u32 hsw_infoframe_data_reg(enum hdmi_infoframe_type type, |
enum transcoder cpu_transcoder) |
enum transcoder cpu_transcoder, |
struct drm_i915_private *dev_priv) |
{ |
switch (type) { |
case HDMI_INFOFRAME_TYPE_AVI: |
296,7 → 297,8 |
u32 val = I915_READ(ctl_reg); |
|
data_reg = hsw_infoframe_data_reg(type, |
intel_crtc->config.cpu_transcoder); |
intel_crtc->config.cpu_transcoder, |
dev_priv); |
if (data_reg == 0) |
return; |
|
365,6 → 367,9 |
union hdmi_infoframe frame; |
int ret; |
|
/* Set user selected PAR to incoming mode's member */ |
adjusted_mode->picture_aspect_ratio = intel_hdmi->aspect_ratio; |
|
ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, |
adjusted_mode); |
if (ret < 0) { |
416,6 → 421,7 |
} |
|
static void g4x_set_infoframes(struct drm_encoder *encoder, |
bool enable, |
struct drm_display_mode *adjusted_mode) |
{ |
struct drm_i915_private *dev_priv = encoder->dev->dev_private; |
423,7 → 429,7 |
struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; |
u32 reg = VIDEO_DIP_CTL; |
u32 val = I915_READ(reg); |
u32 port; |
u32 port = VIDEO_DIP_PORT(intel_dig_port->port); |
|
assert_hdmi_port_disabled(intel_hdmi); |
|
438,7 → 444,7 |
* either. */ |
val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; |
|
if (!intel_hdmi->has_hdmi_sink) { |
if (!enable) { |
if (!(val & VIDEO_DIP_ENABLE)) |
return; |
val &= ~VIDEO_DIP_ENABLE; |
447,18 → 453,6 |
return; |
} |
|
switch (intel_dig_port->port) { |
case PORT_B: |
port = VIDEO_DIP_PORT_B; |
break; |
case PORT_C: |
port = VIDEO_DIP_PORT_C; |
break; |
default: |
BUG(); |
return; |
} |
|
if (port != (val & VIDEO_DIP_PORT_MASK)) { |
if (val & VIDEO_DIP_ENABLE) { |
val &= ~VIDEO_DIP_ENABLE; |
481,6 → 475,7 |
} |
|
static void ibx_set_infoframes(struct drm_encoder *encoder, |
bool enable, |
struct drm_display_mode *adjusted_mode) |
{ |
struct drm_i915_private *dev_priv = encoder->dev->dev_private; |
489,7 → 484,7 |
struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; |
u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe); |
u32 val = I915_READ(reg); |
u32 port; |
u32 port = VIDEO_DIP_PORT(intel_dig_port->port); |
|
assert_hdmi_port_disabled(intel_hdmi); |
|
496,7 → 491,7 |
/* See the big comment in g4x_set_infoframes() */ |
val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; |
|
if (!intel_hdmi->has_hdmi_sink) { |
if (!enable) { |
if (!(val & VIDEO_DIP_ENABLE)) |
return; |
val &= ~VIDEO_DIP_ENABLE; |
505,21 → 500,6 |
return; |
} |
|
switch (intel_dig_port->port) { |
case PORT_B: |
port = VIDEO_DIP_PORT_B; |
break; |
case PORT_C: |
port = VIDEO_DIP_PORT_C; |
break; |
case PORT_D: |
port = VIDEO_DIP_PORT_D; |
break; |
default: |
BUG(); |
return; |
} |
|
if (port != (val & VIDEO_DIP_PORT_MASK)) { |
if (val & VIDEO_DIP_ENABLE) { |
val &= ~VIDEO_DIP_ENABLE; |
543,6 → 523,7 |
} |
|
static void cpt_set_infoframes(struct drm_encoder *encoder, |
bool enable, |
struct drm_display_mode *adjusted_mode) |
{ |
struct drm_i915_private *dev_priv = encoder->dev->dev_private; |
556,7 → 537,7 |
/* See the big comment in g4x_set_infoframes() */ |
val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; |
|
if (!intel_hdmi->has_hdmi_sink) { |
if (!enable) { |
if (!(val & VIDEO_DIP_ENABLE)) |
return; |
val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI); |
579,13 → 560,16 |
} |
|
static void vlv_set_infoframes(struct drm_encoder *encoder, |
bool enable, |
struct drm_display_mode *adjusted_mode) |
{ |
struct drm_i915_private *dev_priv = encoder->dev->dev_private; |
struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); |
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); |
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); |
u32 reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); |
u32 val = I915_READ(reg); |
u32 port = VIDEO_DIP_PORT(intel_dig_port->port); |
|
assert_hdmi_port_disabled(intel_hdmi); |
|
592,7 → 576,7 |
/* See the big comment in g4x_set_infoframes() */ |
val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; |
|
if (!intel_hdmi->has_hdmi_sink) { |
if (!enable) { |
if (!(val & VIDEO_DIP_ENABLE)) |
return; |
val &= ~VIDEO_DIP_ENABLE; |
601,9 → 585,19 |
return; |
} |
|
if (port != (val & VIDEO_DIP_PORT_MASK)) { |
if (val & VIDEO_DIP_ENABLE) { |
val &= ~VIDEO_DIP_ENABLE; |
I915_WRITE(reg, val); |
POSTING_READ(reg); |
} |
val &= ~VIDEO_DIP_PORT_MASK; |
val |= port; |
} |
|
val |= VIDEO_DIP_ENABLE; |
val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | |
VIDEO_DIP_ENABLE_GCP); |
val &= ~(VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_ENABLE_VENDOR | |
VIDEO_DIP_ENABLE_GAMUT | VIDEO_DIP_ENABLE_GCP); |
|
I915_WRITE(reg, val); |
POSTING_READ(reg); |
614,6 → 608,7 |
} |
|
static void hsw_set_infoframes(struct drm_encoder *encoder, |
bool enable, |
struct drm_display_mode *adjusted_mode) |
{ |
struct drm_i915_private *dev_priv = encoder->dev->dev_private; |
624,7 → 619,7 |
|
assert_hdmi_port_disabled(intel_hdmi); |
|
if (!intel_hdmi->has_hdmi_sink) { |
if (!enable) { |
I915_WRITE(reg, 0); |
POSTING_READ(reg); |
return; |
641,7 → 636,7 |
intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode); |
} |
|
static void intel_hdmi_mode_set(struct intel_encoder *encoder) |
static void intel_hdmi_prepare(struct intel_encoder *encoder) |
{ |
struct drm_device *dev = encoder->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
663,27 → 658,26 |
else |
hdmi_val |= SDVO_COLOR_FORMAT_8bpc; |
|
/* Required on CPT */ |
if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev)) |
if (crtc->config.has_hdmi_sink) |
hdmi_val |= HDMI_MODE_SELECT_HDMI; |
|
if (intel_hdmi->has_audio) { |
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; |
hdmi_val |= HDMI_MODE_SELECT_HDMI; |
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)) |
hdmi_val |= SDVO_PIPE_SEL_CHV(crtc->pipe); |
else |
hdmi_val |= SDVO_PIPE_SEL(crtc->pipe); |
|
I915_WRITE(intel_hdmi->hdmi_reg, hdmi_val); |
POSTING_READ(intel_hdmi->hdmi_reg); |
|
intel_hdmi->set_infoframes(&encoder->base, adjusted_mode); |
} |
|
static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder, |
692,8 → 686,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); |
enum intel_display_power_domain power_domain; |
u32 tmp; |
|
power_domain = intel_display_port_power_domain(encoder); |
if (!intel_display_power_enabled(dev_priv, power_domain)) |
return false; |
|
tmp = I915_READ(intel_hdmi->hdmi_reg); |
|
if (!(tmp & SDVO_ENABLE)) |
701,6 → 700,8 |
|
if (HAS_PCH_CPT(dev)) |
*pipe = PORT_TO_PIPE_CPT(tmp); |
else if (IS_CHERRYVIEW(dev)) |
*pipe = SDVO_PORT_TO_PIPE_CHV(tmp); |
else |
*pipe = PORT_TO_PIPE(tmp); |
|
727,6 → 728,12 |
else |
flags |= DRM_MODE_FLAG_NVSYNC; |
|
if (tmp & HDMI_MODE_SELECT_HDMI) |
pipe_config->has_hdmi_sink = true; |
|
if (tmp & HDMI_MODE_SELECT_HDMI) |
pipe_config->has_audio = true; |
|
pipe_config->adjusted_mode.flags |= flags; |
|
if ((tmp & SDVO_COLOR_FORMAT_MASK) == HDMI_COLOR_FORMAT_12bpc) |
749,7 → 756,7 |
u32 temp; |
u32 enable_bits = SDVO_ENABLE; |
|
if (intel_hdmi->has_audio) |
if (intel_crtc->config.has_audio) |
enable_bits |= SDVO_AUDIO_ENABLE; |
|
temp = I915_READ(intel_hdmi->hdmi_reg); |
841,11 → 848,11 |
} |
} |
|
static int hdmi_portclock_limit(struct intel_hdmi *hdmi) |
static int hdmi_portclock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit) |
{ |
struct drm_device *dev = intel_hdmi_to_dev(hdmi); |
|
if (IS_G4X(dev)) |
if ((respect_dvi_limit && !hdmi->has_hdmi_sink) || IS_G4X(dev)) |
return 165000; |
else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8) |
return 300000; |
857,7 → 864,8 |
intel_hdmi_mode_valid(struct drm_connector *connector, |
struct drm_display_mode *mode) |
{ |
if (mode->clock > hdmi_portclock_limit(intel_attached_hdmi(connector))) |
if (mode->clock > hdmi_portclock_limit(intel_attached_hdmi(connector), |
true)) |
return MODE_CLOCK_HIGH; |
if (mode->clock < 20000) |
return MODE_CLOCK_LOW; |
868,6 → 876,30 |
return MODE_OK; |
} |
|
static bool hdmi_12bpc_possible(struct intel_crtc *crtc) |
{ |
struct drm_device *dev = crtc->base.dev; |
struct intel_encoder *encoder; |
int count = 0, count_hdmi = 0; |
|
if (HAS_GMCH_DISPLAY(dev)) |
return false; |
|
list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { |
if (encoder->new_crtc != crtc) |
continue; |
|
count_hdmi += encoder->type == INTEL_OUTPUT_HDMI; |
count++; |
} |
|
/* |
* HDMI 12bpc affects the clocks, so it's only possible |
* when not cloning with other encoder types. |
*/ |
return count_hdmi > 0 && count_hdmi == count; |
} |
|
bool intel_hdmi_compute_config(struct intel_encoder *encoder, |
struct intel_crtc_config *pipe_config) |
{ |
875,12 → 907,14 |
struct drm_device *dev = encoder->base.dev; |
struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; |
int clock_12bpc = pipe_config->adjusted_mode.crtc_clock * 3 / 2; |
int portclock_limit = hdmi_portclock_limit(intel_hdmi); |
int portclock_limit = hdmi_portclock_limit(intel_hdmi, false); |
int desired_bpp; |
|
pipe_config->has_hdmi_sink = intel_hdmi->has_hdmi_sink; |
|
if (intel_hdmi->color_range_auto) { |
/* See CEA-861-E - 5.1 Default Encoding Parameters */ |
if (intel_hdmi->has_hdmi_sink && |
if (pipe_config->has_hdmi_sink && |
drm_match_cea_mode(adjusted_mode) > 1) |
intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235; |
else |
893,6 → 927,9 |
if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev)) |
pipe_config->has_pch_encoder = true; |
|
if (pipe_config->has_hdmi_sink && intel_hdmi->has_audio) |
pipe_config->has_audio = true; |
|
/* |
* HDMI is either 12 or 8, so if the display lets 10bpc sneak |
* through, clamp it down. Note that g4x/vlv don't support 12bpc hdmi |
899,8 → 936,9 |
* outputs. We also need to check that the higher clock still fits |
* within limits. |
*/ |
if (pipe_config->pipe_bpp > 8*3 && clock_12bpc <= portclock_limit |
&& HAS_PCH_SPLIT(dev)) { |
if (pipe_config->pipe_bpp > 8*3 && pipe_config->has_hdmi_sink && |
clock_12bpc <= portclock_limit && |
hdmi_12bpc_possible(encoder->new_crtc)) { |
DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n"); |
desired_bpp = 12*3; |
|
934,11 → 972,15 |
struct intel_encoder *intel_encoder = &intel_dig_port->base; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct edid *edid; |
enum intel_display_power_domain power_domain; |
enum drm_connector_status status = connector_status_disconnected; |
|
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", |
connector->base.id, drm_get_connector_name(connector)); |
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; |
966,31 → 1008,48 |
intel_encoder->type = INTEL_OUTPUT_HDMI; |
} |
|
intel_display_power_put(dev_priv, power_domain); |
|
return status; |
} |
|
static int intel_hdmi_get_modes(struct drm_connector *connector) |
{ |
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(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; |
|
/* We should parse the EDID data and find out if it's an HDMI sink so |
* we can send audio to it. |
*/ |
|
return intel_ddc_get_modes(connector, |
power_domain = intel_display_port_power_domain(intel_encoder); |
intel_display_power_get(dev_priv, power_domain); |
|
ret = intel_ddc_get_modes(connector, |
intel_gmbus_get_adapter(dev_priv, |
intel_hdmi->ddc_bus)); |
|
intel_display_power_put(dev_priv, power_domain); |
|
return ret; |
} |
|
static bool |
intel_hdmi_detect_audio(struct drm_connector *connector) |
{ |
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(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; |
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)); |
1000,6 → 1059,8 |
kfree(edid); |
} |
|
intel_display_power_put(dev_priv, power_domain); |
|
return has_audio; |
} |
|
1066,8 → 1127,25 |
goto done; |
} |
|
if (property == connector->dev->mode_config.aspect_ratio_property) { |
switch (val) { |
case DRM_MODE_PICTURE_ASPECT_NONE: |
intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_NONE; |
break; |
case DRM_MODE_PICTURE_ASPECT_4_3: |
intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_4_3; |
break; |
case DRM_MODE_PICTURE_ASPECT_16_9: |
intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_16_9; |
break; |
default: |
return -EINVAL; |
} |
goto done; |
} |
|
return -EINVAL; |
|
done: |
if (intel_dig_port->base.base.crtc) |
intel_crtc_restore_mode(intel_dig_port->base.base.crtc); |
1075,20 → 1153,34 |
return 0; |
} |
|
static void intel_hdmi_pre_enable(struct intel_encoder *encoder) |
{ |
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); |
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); |
struct drm_display_mode *adjusted_mode = |
&intel_crtc->config.adjusted_mode; |
|
intel_hdmi_prepare(encoder); |
|
intel_hdmi->set_infoframes(&encoder->base, |
intel_crtc->config.has_hdmi_sink, |
adjusted_mode); |
} |
|
static void vlv_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 port = vlv_dport_to_channel(dport); |
int pipe = intel_crtc->pipe; |
u32 val; |
|
if (!IS_VALLEYVIEW(dev)) |
return; |
|
/* Enable clock channels for this port */ |
mutex_lock(&dev_priv->dpio_lock); |
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(port)); |
1115,6 → 1207,10 |
vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW23(port), 0x00400888); |
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); |
1130,8 → 1226,7 |
enum dpio_channel port = vlv_dport_to_channel(dport); |
int pipe = intel_crtc->pipe; |
|
if (!IS_VALLEYVIEW(dev)) |
return; |
intel_hdmi_prepare(encoder); |
|
/* Program Tx lane resets to default */ |
mutex_lock(&dev_priv->dpio_lock); |
1154,6 → 1249,70 |
mutex_unlock(&dev_priv->dpio_lock); |
} |
|
static void chv_hdmi_pre_pll_enable(struct intel_encoder *encoder) |
{ |
struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); |
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); |
enum dpio_channel ch = vlv_dport_to_channel(dport); |
enum pipe pipe = intel_crtc->pipe; |
u32 val; |
|
mutex_lock(&dev_priv->dpio_lock); |
|
/* program left/right clock distribution */ |
if (pipe != PIPE_B) { |
val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW5_CH0); |
val &= ~(CHV_BUFLEFTENA1_MASK | CHV_BUFRIGHTENA1_MASK); |
if (ch == DPIO_CH0) |
val |= CHV_BUFLEFTENA1_FORCE; |
if (ch == DPIO_CH1) |
val |= CHV_BUFRIGHTENA1_FORCE; |
vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW5_CH0, val); |
} else { |
val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW1_CH1); |
val &= ~(CHV_BUFLEFTENA2_MASK | CHV_BUFRIGHTENA2_MASK); |
if (ch == DPIO_CH0) |
val |= CHV_BUFLEFTENA2_FORCE; |
if (ch == DPIO_CH1) |
val |= CHV_BUFRIGHTENA2_FORCE; |
vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW1_CH1, val); |
} |
|
/* program clock channel usage */ |
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(ch)); |
val |= CHV_PCS_USEDCLKCHANNEL_OVRRIDE; |
if (pipe != PIPE_B) |
val &= ~CHV_PCS_USEDCLKCHANNEL; |
else |
val |= CHV_PCS_USEDCLKCHANNEL; |
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW8(ch), val); |
|
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW8(ch)); |
val |= CHV_PCS_USEDCLKCHANNEL_OVRRIDE; |
if (pipe != PIPE_B) |
val &= ~CHV_PCS_USEDCLKCHANNEL; |
else |
val |= CHV_PCS_USEDCLKCHANNEL; |
vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW8(ch), val); |
|
/* |
* This a a bit weird since generally CL |
* matches the pipe, but here we need to |
* pick the CL based on the port. |
*/ |
val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW19(ch)); |
if (pipe != PIPE_B) |
val &= ~CHV_CMN_USEDCLKCHANNEL; |
else |
val |= CHV_CMN_USEDCLKCHANNEL; |
vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW19(ch), val); |
|
mutex_unlock(&dev_priv->dpio_lock); |
} |
|
static void vlv_hdmi_post_disable(struct intel_encoder *encoder) |
{ |
struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); |
1170,6 → 1329,152 |
mutex_unlock(&dev_priv->dpio_lock); |
} |
|
static void chv_hdmi_post_disable(struct intel_encoder *encoder) |
{ |
struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); |
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); |
enum dpio_channel ch = vlv_dport_to_channel(dport); |
enum pipe pipe = intel_crtc->pipe; |
u32 val; |
|
mutex_lock(&dev_priv->dpio_lock); |
|
/* Propagate soft reset to data lane reset */ |
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch)); |
val |= CHV_PCS_REQ_SOFTRESET_EN; |
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val); |
|
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch)); |
val |= CHV_PCS_REQ_SOFTRESET_EN; |
vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val); |
|
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch)); |
val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); |
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val); |
|
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch)); |
val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); |
vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val); |
|
mutex_unlock(&dev_priv->dpio_lock); |
} |
|
static void chv_hdmi_pre_enable(struct intel_encoder *encoder) |
{ |
struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); |
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); |
enum dpio_channel ch = vlv_dport_to_channel(dport); |
int pipe = intel_crtc->pipe; |
int data, i; |
u32 val; |
|
mutex_lock(&dev_priv->dpio_lock); |
|
/* Deassert soft data lane reset*/ |
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch)); |
val |= CHV_PCS_REQ_SOFTRESET_EN; |
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val); |
|
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch)); |
val |= CHV_PCS_REQ_SOFTRESET_EN; |
vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val); |
|
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch)); |
val |= (DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); |
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val); |
|
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch)); |
val |= (DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); |
vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val); |
|
/* Program Tx latency optimal setting */ |
for (i = 0; i < 4; i++) { |
/* Set the latency optimal bit */ |
data = (i == 1) ? 0x0 : 0x6; |
vlv_dpio_write(dev_priv, pipe, CHV_TX_DW11(ch, i), |
data << DPIO_FRC_LATENCY_SHFIT); |
|
/* Set the upar bit */ |
data = (i == 1) ? 0x0 : 0x1; |
vlv_dpio_write(dev_priv, pipe, CHV_TX_DW14(ch, i), |
data << DPIO_UPAR_SHIFT); |
} |
|
/* Data lane stagger programming */ |
/* FIXME: Fix up value only after power analysis */ |
|
/* 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); |
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); |
vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val); |
|
/* FIXME: Program the support xxx V-dB */ |
/* Use 800mV-0dB */ |
for (i = 0; i < 4; i++) { |
val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW4(ch, i)); |
val &= ~DPIO_SWING_DEEMPH9P5_MASK; |
val |= 128 << DPIO_SWING_DEEMPH9P5_SHIFT; |
vlv_dpio_write(dev_priv, pipe, CHV_TX_DW4(ch, i), val); |
} |
|
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; |
vlv_dpio_write(dev_priv, pipe, CHV_TX_DW2(ch, i), val); |
} |
|
/* Disable unique transition scale */ |
for (i = 0; i < 4; i++) { |
val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW3(ch, i)); |
val &= ~DPIO_TX_UNIQ_TRANS_SCALE_EN; |
vlv_dpio_write(dev_priv, pipe, CHV_TX_DW3(ch, i), val); |
} |
|
/* Additional steps for 1200mV-0dB */ |
#if 0 |
val = vlv_dpio_read(dev_priv, pipe, VLV_TX_DW3(ch)); |
if (ch) |
val |= DPIO_TX_UNIQ_TRANS_SCALE_CH1; |
else |
val |= DPIO_TX_UNIQ_TRANS_SCALE_CH0; |
vlv_dpio_write(dev_priv, pipe, VLV_TX_DW3(ch), val); |
|
vlv_dpio_write(dev_priv, pipe, VLV_TX_DW2(ch), |
vlv_dpio_read(dev_priv, pipe, VLV_TX_DW2(ch)) | |
(0x9a << DPIO_UNIQ_TRANS_SCALE_SHIFT)); |
#endif |
/* Start swing calculation */ |
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW10(ch)); |
val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3; |
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; |
vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val); |
|
/* LRC Bypass */ |
val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW30); |
val |= DPIO_LRC_BYPASS; |
vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW30, val); |
|
mutex_unlock(&dev_priv->dpio_lock); |
|
intel_enable_hdmi(encoder); |
|
vlv_wait_port_ready(dev_priv, dport); |
} |
|
static void intel_hdmi_destroy(struct drm_connector *connector) |
{ |
drm_connector_cleanup(connector); |
1195,11 → 1500,22 |
}; |
|
static void |
intel_attach_aspect_ratio_property(struct drm_connector *connector) |
{ |
if (!drm_mode_create_aspect_ratio_property(connector->dev)) |
drm_object_attach_property(&connector->base, |
connector->dev->mode_config.aspect_ratio_property, |
DRM_MODE_PICTURE_ASPECT_NONE); |
} |
|
static void |
intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector) |
{ |
intel_attach_force_audio_property(connector); |
intel_attach_broadcast_rgb_property(connector); |
intel_hdmi->color_range_auto = true; |
intel_attach_aspect_ratio_property(connector); |
intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_NONE; |
} |
|
void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, |
1230,6 → 1546,9 |
intel_encoder->hpd_pin = HPD_PORT_C; |
break; |
case PORT_D: |
if (IS_CHERRYVIEW(dev)) |
intel_hdmi->ddc_bus = GMBUS_PORT_DPD_CHV; |
else |
intel_hdmi->ddc_bus = GMBUS_PORT_DPD; |
intel_encoder->hpd_pin = HPD_PORT_D; |
break; |
1243,7 → 1562,7 |
if (IS_VALLEYVIEW(dev)) { |
intel_hdmi->write_infoframe = vlv_write_infoframe; |
intel_hdmi->set_infoframes = vlv_set_infoframes; |
} else if (!HAS_PCH_SPLIT(dev)) { |
} else if (IS_G4X(dev)) { |
intel_hdmi->write_infoframe = g4x_write_infoframe; |
intel_hdmi->set_infoframes = g4x_set_infoframes; |
} else if (HAS_DDI(dev)) { |
1261,11 → 1580,12 |
intel_connector->get_hw_state = intel_ddi_connector_get_hw_state; |
else |
intel_connector->get_hw_state = intel_connector_get_hw_state; |
intel_connector->unregister = intel_connector_unregister; |
|
intel_hdmi_add_properties(intel_hdmi, connector); |
|
intel_connector_attach_encoder(intel_connector, intel_encoder); |
drm_sysfs_connector_add(connector); |
drm_connector_register(connector); |
|
/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written |
* 0xd. Failure to do so will result in spurious interrupts being |
1299,22 → 1619,41 |
DRM_MODE_ENCODER_TMDS); |
|
intel_encoder->compute_config = intel_hdmi_compute_config; |
intel_encoder->mode_set = intel_hdmi_mode_set; |
intel_encoder->disable = intel_disable_hdmi; |
intel_encoder->get_hw_state = intel_hdmi_get_hw_state; |
intel_encoder->get_config = intel_hdmi_get_config; |
if (IS_VALLEYVIEW(dev)) { |
if (IS_CHERRYVIEW(dev)) { |
intel_encoder->pre_pll_enable = chv_hdmi_pre_pll_enable; |
intel_encoder->pre_enable = chv_hdmi_pre_enable; |
intel_encoder->enable = vlv_enable_hdmi; |
intel_encoder->post_disable = chv_hdmi_post_disable; |
} else if (IS_VALLEYVIEW(dev)) { |
intel_encoder->pre_pll_enable = vlv_hdmi_pre_pll_enable; |
intel_encoder->pre_enable = vlv_hdmi_pre_enable; |
intel_encoder->enable = vlv_enable_hdmi; |
intel_encoder->post_disable = vlv_hdmi_post_disable; |
} else { |
intel_encoder->pre_enable = intel_hdmi_pre_enable; |
intel_encoder->enable = intel_enable_hdmi; |
} |
|
intel_encoder->type = INTEL_OUTPUT_HDMI; |
if (IS_CHERRYVIEW(dev)) { |
if (port == PORT_D) |
intel_encoder->crtc_mask = 1 << 2; |
else |
intel_encoder->crtc_mask = (1 << 0) | (1 << 1); |
} else { |
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); |
intel_encoder->cloneable = false; |
} |
intel_encoder->cloneable = 1 << INTEL_OUTPUT_ANALOG; |
/* |
* BSpec is unclear about HDMI+HDMI cloning on g4x, but it seems |
* to work on real hardware. And since g4x can send infoframes to |
* only one port anyway, nothing is lost by allowing it. |
*/ |
if (IS_G4X(dev)) |
intel_encoder->cloneable |= 1 << INTEL_OUTPUT_HDMI; |
|
intel_dig_port->port = port; |
intel_dig_port->hdmi.hdmi_reg = hdmi_reg; |