Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 5059 → Rev 5060

/drivers/video/drm/i915/intel_hdmi.c
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;