1e3adcf8fSFrançois Tigeot /* 2e3adcf8fSFrançois Tigeot * Copyright 2006 Dave Airlie <airlied@linux.ie> 3e3adcf8fSFrançois Tigeot * Copyright © 2006-2009 Intel Corporation 4e3adcf8fSFrançois Tigeot * 5e3adcf8fSFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a 6e3adcf8fSFrançois Tigeot * copy of this software and associated documentation files (the "Software"), 7e3adcf8fSFrançois Tigeot * to deal in the Software without restriction, including without limitation 8e3adcf8fSFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9e3adcf8fSFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the 10e3adcf8fSFrançois Tigeot * Software is furnished to do so, subject to the following conditions: 11e3adcf8fSFrançois Tigeot * 12e3adcf8fSFrançois Tigeot * The above copyright notice and this permission notice (including the next 13e3adcf8fSFrançois Tigeot * paragraph) shall be included in all copies or substantial portions of the 14e3adcf8fSFrançois Tigeot * Software. 15e3adcf8fSFrançois Tigeot * 16e3adcf8fSFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17e3adcf8fSFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18e3adcf8fSFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19e3adcf8fSFrançois Tigeot * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20e3adcf8fSFrançois Tigeot * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21e3adcf8fSFrançois Tigeot * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22e3adcf8fSFrançois Tigeot * DEALINGS IN THE SOFTWARE. 23e3adcf8fSFrançois Tigeot * 24e3adcf8fSFrançois Tigeot * Authors: 25e3adcf8fSFrançois Tigeot * Eric Anholt <eric@anholt.net> 26e3adcf8fSFrançois Tigeot * Jesse Barnes <jesse.barnes@intel.com> 27e3adcf8fSFrançois Tigeot */ 28e3adcf8fSFrançois Tigeot 29a2fdbec6SFrançois Tigeot #include <linux/i2c.h> 30a2fdbec6SFrançois Tigeot #include <linux/delay.h> 31*9edbd4a0SFrançois Tigeot #include <linux/hdmi.h> 3218e26a6dSFrançois Tigeot #include <drm/drmP.h> 3318e26a6dSFrançois Tigeot #include <drm/drm_crtc.h> 3418e26a6dSFrançois Tigeot #include <drm/drm_edid.h> 3518e26a6dSFrançois Tigeot #include "intel_drv.h" 365c6c6f23SFrançois Tigeot #include <drm/i915_drm.h> 37e3adcf8fSFrançois Tigeot #include "i915_drv.h" 38e3adcf8fSFrançois Tigeot 3919df918dSFrançois Tigeot static struct drm_device *intel_hdmi_to_dev(struct intel_hdmi *intel_hdmi) 40e3adcf8fSFrançois Tigeot { 4119df918dSFrançois Tigeot return hdmi_to_dig_port(intel_hdmi)->base.base.dev; 4219df918dSFrançois Tigeot } 4319df918dSFrançois Tigeot 4419df918dSFrançois Tigeot static void 4519df918dSFrançois Tigeot assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi) 4619df918dSFrançois Tigeot { 4719df918dSFrançois Tigeot struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi); 4819df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 4919df918dSFrançois Tigeot uint32_t enabled_bits; 5019df918dSFrançois Tigeot 51a2fdbec6SFrançois Tigeot enabled_bits = HAS_DDI(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE; 5219df918dSFrançois Tigeot 538e26cdf6SFrançois Tigeot WARN(I915_READ(intel_hdmi->hdmi_reg) & enabled_bits, 5419df918dSFrançois Tigeot "HDMI port enabled, expecting disabled\n"); 5519df918dSFrançois Tigeot } 5619df918dSFrançois Tigeot 5719df918dSFrançois Tigeot struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) 5819df918dSFrançois Tigeot { 5919df918dSFrançois Tigeot struct intel_digital_port *intel_dig_port = 6019df918dSFrançois Tigeot container_of(encoder, struct intel_digital_port, base.base); 6119df918dSFrançois Tigeot return &intel_dig_port->hdmi; 62e3adcf8fSFrançois Tigeot } 63e3adcf8fSFrançois Tigeot 64e3adcf8fSFrançois Tigeot static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector) 65e3adcf8fSFrançois Tigeot { 6619df918dSFrançois Tigeot return enc_to_intel_hdmi(&intel_attached_encoder(connector)->base); 67e3adcf8fSFrançois Tigeot } 68e3adcf8fSFrançois Tigeot 69*9edbd4a0SFrançois Tigeot static u32 g4x_infoframe_index(enum hdmi_infoframe_type type) 70e3adcf8fSFrançois Tigeot { 71*9edbd4a0SFrançois Tigeot switch (type) { 72*9edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_AVI: 7319df918dSFrançois Tigeot return VIDEO_DIP_SELECT_AVI; 74*9edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_SPD: 7519df918dSFrançois Tigeot return VIDEO_DIP_SELECT_SPD; 76*9edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_VENDOR: 77*9edbd4a0SFrançois Tigeot return VIDEO_DIP_SELECT_VENDOR; 78e3adcf8fSFrançois Tigeot default: 79*9edbd4a0SFrançois Tigeot DRM_DEBUG_DRIVER("unknown info frame type %d\n", type); 8019df918dSFrançois Tigeot return 0; 8119df918dSFrançois Tigeot } 82e3adcf8fSFrançois Tigeot } 83e3adcf8fSFrançois Tigeot 84*9edbd4a0SFrançois Tigeot static u32 g4x_infoframe_enable(enum hdmi_infoframe_type type) 85e3adcf8fSFrançois Tigeot { 86*9edbd4a0SFrançois Tigeot switch (type) { 87*9edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_AVI: 8819df918dSFrançois Tigeot return VIDEO_DIP_ENABLE_AVI; 89*9edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_SPD: 9019df918dSFrançois Tigeot return VIDEO_DIP_ENABLE_SPD; 91*9edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_VENDOR: 92*9edbd4a0SFrançois Tigeot return VIDEO_DIP_ENABLE_VENDOR; 93e3adcf8fSFrançois Tigeot default: 94*9edbd4a0SFrançois Tigeot DRM_DEBUG_DRIVER("unknown info frame type %d\n", type); 9519df918dSFrançois Tigeot return 0; 9619df918dSFrançois Tigeot } 97e3adcf8fSFrançois Tigeot } 98e3adcf8fSFrançois Tigeot 99*9edbd4a0SFrançois Tigeot static u32 hsw_infoframe_enable(enum hdmi_infoframe_type type) 10019df918dSFrançois Tigeot { 101*9edbd4a0SFrançois Tigeot switch (type) { 102*9edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_AVI: 10319df918dSFrançois Tigeot return VIDEO_DIP_ENABLE_AVI_HSW; 104*9edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_SPD: 10519df918dSFrançois Tigeot return VIDEO_DIP_ENABLE_SPD_HSW; 106*9edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_VENDOR: 107*9edbd4a0SFrançois Tigeot return VIDEO_DIP_ENABLE_VS_HSW; 10819df918dSFrançois Tigeot default: 109*9edbd4a0SFrançois Tigeot DRM_DEBUG_DRIVER("unknown info frame type %d\n", type); 11019df918dSFrançois Tigeot return 0; 11119df918dSFrançois Tigeot } 112e3adcf8fSFrançois Tigeot } 113e3adcf8fSFrançois Tigeot 114*9edbd4a0SFrançois Tigeot static u32 hsw_infoframe_data_reg(enum hdmi_infoframe_type type, 1158e26cdf6SFrançois Tigeot enum transcoder cpu_transcoder) 11619df918dSFrançois Tigeot { 117*9edbd4a0SFrançois Tigeot switch (type) { 118*9edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_AVI: 1198e26cdf6SFrançois Tigeot return HSW_TVIDEO_DIP_AVI_DATA(cpu_transcoder); 120*9edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_SPD: 1218e26cdf6SFrançois Tigeot return HSW_TVIDEO_DIP_SPD_DATA(cpu_transcoder); 122*9edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_VENDOR: 123*9edbd4a0SFrançois Tigeot return HSW_TVIDEO_DIP_VS_DATA(cpu_transcoder); 12419df918dSFrançois Tigeot default: 125*9edbd4a0SFrançois Tigeot DRM_DEBUG_DRIVER("unknown info frame type %d\n", type); 12619df918dSFrançois Tigeot return 0; 12719df918dSFrançois Tigeot } 12819df918dSFrançois Tigeot } 12919df918dSFrançois Tigeot 13019df918dSFrançois Tigeot static void g4x_write_infoframe(struct drm_encoder *encoder, 131*9edbd4a0SFrançois Tigeot enum hdmi_infoframe_type type, 132*9edbd4a0SFrançois Tigeot const void *frame, ssize_t len) 133e3adcf8fSFrançois Tigeot { 134*9edbd4a0SFrançois Tigeot const uint32_t *data = frame; 135e3adcf8fSFrançois Tigeot struct drm_device *dev = encoder->dev; 136e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 13719df918dSFrançois Tigeot u32 val = I915_READ(VIDEO_DIP_CTL); 138*9edbd4a0SFrançois Tigeot int i; 139e3adcf8fSFrançois Tigeot 14019df918dSFrançois Tigeot WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n"); 141e3adcf8fSFrançois Tigeot 14219df918dSFrançois Tigeot val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ 143*9edbd4a0SFrançois Tigeot val |= g4x_infoframe_index(type); 144e3adcf8fSFrançois Tigeot 145*9edbd4a0SFrançois Tigeot val &= ~g4x_infoframe_enable(type); 146e3adcf8fSFrançois Tigeot 14719df918dSFrançois Tigeot I915_WRITE(VIDEO_DIP_CTL, val); 148e3adcf8fSFrançois Tigeot 14919df918dSFrançois Tigeot mmiowb(); 150e3adcf8fSFrançois Tigeot for (i = 0; i < len; i += 4) { 151e3adcf8fSFrançois Tigeot I915_WRITE(VIDEO_DIP_DATA, *data); 152e3adcf8fSFrançois Tigeot data++; 153e3adcf8fSFrançois Tigeot } 15419df918dSFrançois Tigeot /* Write every possible data byte to force correct ECC calculation. */ 15519df918dSFrançois Tigeot for (; i < VIDEO_DIP_DATA_SIZE; i += 4) 15619df918dSFrançois Tigeot I915_WRITE(VIDEO_DIP_DATA, 0); 15719df918dSFrançois Tigeot mmiowb(); 158e3adcf8fSFrançois Tigeot 159*9edbd4a0SFrançois Tigeot val |= g4x_infoframe_enable(type); 16019df918dSFrançois Tigeot val &= ~VIDEO_DIP_FREQ_MASK; 16119df918dSFrançois Tigeot val |= VIDEO_DIP_FREQ_VSYNC; 162e3adcf8fSFrançois Tigeot 16319df918dSFrançois Tigeot I915_WRITE(VIDEO_DIP_CTL, val); 16419df918dSFrançois Tigeot POSTING_READ(VIDEO_DIP_CTL); 165e3adcf8fSFrançois Tigeot } 166e3adcf8fSFrançois Tigeot 16719df918dSFrançois Tigeot static void ibx_write_infoframe(struct drm_encoder *encoder, 168*9edbd4a0SFrançois Tigeot enum hdmi_infoframe_type type, 169*9edbd4a0SFrançois Tigeot const void *frame, ssize_t len) 170e3adcf8fSFrançois Tigeot { 171*9edbd4a0SFrançois Tigeot const uint32_t *data = frame; 172e3adcf8fSFrançois Tigeot struct drm_device *dev = encoder->dev; 173e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 17419df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 175*9edbd4a0SFrançois Tigeot int i, reg = TVIDEO_DIP_CTL(intel_crtc->pipe); 17619df918dSFrançois Tigeot u32 val = I915_READ(reg); 177e3adcf8fSFrançois Tigeot 17819df918dSFrançois Tigeot WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n"); 179e3adcf8fSFrançois Tigeot 180e3adcf8fSFrançois Tigeot val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ 181*9edbd4a0SFrançois Tigeot val |= g4x_infoframe_index(type); 182e3adcf8fSFrançois Tigeot 183*9edbd4a0SFrançois Tigeot val &= ~g4x_infoframe_enable(type); 184e3adcf8fSFrançois Tigeot 18519df918dSFrançois Tigeot I915_WRITE(reg, val); 18619df918dSFrançois Tigeot 18719df918dSFrançois Tigeot mmiowb(); 188e3adcf8fSFrançois Tigeot for (i = 0; i < len; i += 4) { 189e3adcf8fSFrançois Tigeot I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); 190e3adcf8fSFrançois Tigeot data++; 191e3adcf8fSFrançois Tigeot } 19219df918dSFrançois Tigeot /* Write every possible data byte to force correct ECC calculation. */ 19319df918dSFrançois Tigeot for (; i < VIDEO_DIP_DATA_SIZE; i += 4) 19419df918dSFrançois Tigeot I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0); 19519df918dSFrançois Tigeot mmiowb(); 196e3adcf8fSFrançois Tigeot 197*9edbd4a0SFrançois Tigeot val |= g4x_infoframe_enable(type); 19819df918dSFrançois Tigeot val &= ~VIDEO_DIP_FREQ_MASK; 19919df918dSFrançois Tigeot val |= VIDEO_DIP_FREQ_VSYNC; 200e3adcf8fSFrançois Tigeot 20119df918dSFrançois Tigeot I915_WRITE(reg, val); 20219df918dSFrançois Tigeot POSTING_READ(reg); 20319df918dSFrançois Tigeot } 20419df918dSFrançois Tigeot 20519df918dSFrançois Tigeot static void cpt_write_infoframe(struct drm_encoder *encoder, 206*9edbd4a0SFrançois Tigeot enum hdmi_infoframe_type type, 207*9edbd4a0SFrançois Tigeot const void *frame, ssize_t len) 20819df918dSFrançois Tigeot { 209*9edbd4a0SFrançois Tigeot const uint32_t *data = frame; 21019df918dSFrançois Tigeot struct drm_device *dev = encoder->dev; 21119df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 21219df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 213*9edbd4a0SFrançois Tigeot int i, reg = TVIDEO_DIP_CTL(intel_crtc->pipe); 21419df918dSFrançois Tigeot u32 val = I915_READ(reg); 21519df918dSFrançois Tigeot 21619df918dSFrançois Tigeot WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n"); 21719df918dSFrançois Tigeot 21819df918dSFrançois Tigeot val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ 219*9edbd4a0SFrançois Tigeot val |= g4x_infoframe_index(type); 22019df918dSFrançois Tigeot 22119df918dSFrançois Tigeot /* The DIP control register spec says that we need to update the AVI 22219df918dSFrançois Tigeot * infoframe without clearing its enable bit */ 223*9edbd4a0SFrançois Tigeot if (type != HDMI_INFOFRAME_TYPE_AVI) 224*9edbd4a0SFrançois Tigeot val &= ~g4x_infoframe_enable(type); 22519df918dSFrançois Tigeot 22619df918dSFrançois Tigeot I915_WRITE(reg, val); 22719df918dSFrançois Tigeot 22819df918dSFrançois Tigeot mmiowb(); 22919df918dSFrançois Tigeot for (i = 0; i < len; i += 4) { 23019df918dSFrançois Tigeot I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); 23119df918dSFrançois Tigeot data++; 23219df918dSFrançois Tigeot } 23319df918dSFrançois Tigeot /* Write every possible data byte to force correct ECC calculation. */ 23419df918dSFrançois Tigeot for (; i < VIDEO_DIP_DATA_SIZE; i += 4) 23519df918dSFrançois Tigeot I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0); 23619df918dSFrançois Tigeot mmiowb(); 23719df918dSFrançois Tigeot 238*9edbd4a0SFrançois Tigeot val |= g4x_infoframe_enable(type); 23919df918dSFrançois Tigeot val &= ~VIDEO_DIP_FREQ_MASK; 24019df918dSFrançois Tigeot val |= VIDEO_DIP_FREQ_VSYNC; 24119df918dSFrançois Tigeot 24219df918dSFrançois Tigeot I915_WRITE(reg, val); 24319df918dSFrançois Tigeot POSTING_READ(reg); 24419df918dSFrançois Tigeot } 24519df918dSFrançois Tigeot 24619df918dSFrançois Tigeot static void vlv_write_infoframe(struct drm_encoder *encoder, 247*9edbd4a0SFrançois Tigeot enum hdmi_infoframe_type type, 248*9edbd4a0SFrançois Tigeot const void *frame, ssize_t len) 24919df918dSFrançois Tigeot { 250*9edbd4a0SFrançois Tigeot const uint32_t *data = frame; 25119df918dSFrançois Tigeot struct drm_device *dev = encoder->dev; 25219df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 25319df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 254*9edbd4a0SFrançois Tigeot int i, reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); 25519df918dSFrançois Tigeot u32 val = I915_READ(reg); 25619df918dSFrançois Tigeot 25719df918dSFrançois Tigeot WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n"); 25819df918dSFrançois Tigeot 25919df918dSFrançois Tigeot val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ 260*9edbd4a0SFrançois Tigeot val |= g4x_infoframe_index(type); 26119df918dSFrançois Tigeot 262*9edbd4a0SFrançois Tigeot val &= ~g4x_infoframe_enable(type); 26319df918dSFrançois Tigeot 26419df918dSFrançois Tigeot I915_WRITE(reg, val); 26519df918dSFrançois Tigeot 26619df918dSFrançois Tigeot mmiowb(); 26719df918dSFrançois Tigeot for (i = 0; i < len; i += 4) { 26819df918dSFrançois Tigeot I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data); 26919df918dSFrançois Tigeot data++; 27019df918dSFrançois Tigeot } 27119df918dSFrançois Tigeot /* Write every possible data byte to force correct ECC calculation. */ 27219df918dSFrançois Tigeot for (; i < VIDEO_DIP_DATA_SIZE; i += 4) 27319df918dSFrançois Tigeot I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), 0); 27419df918dSFrançois Tigeot mmiowb(); 27519df918dSFrançois Tigeot 276*9edbd4a0SFrançois Tigeot val |= g4x_infoframe_enable(type); 27719df918dSFrançois Tigeot val &= ~VIDEO_DIP_FREQ_MASK; 27819df918dSFrançois Tigeot val |= VIDEO_DIP_FREQ_VSYNC; 27919df918dSFrançois Tigeot 28019df918dSFrançois Tigeot I915_WRITE(reg, val); 28119df918dSFrançois Tigeot POSTING_READ(reg); 28219df918dSFrançois Tigeot } 28319df918dSFrançois Tigeot 28419df918dSFrançois Tigeot static void hsw_write_infoframe(struct drm_encoder *encoder, 285*9edbd4a0SFrançois Tigeot enum hdmi_infoframe_type type, 286*9edbd4a0SFrançois Tigeot const void *frame, ssize_t len) 28719df918dSFrançois Tigeot { 288*9edbd4a0SFrançois Tigeot const uint32_t *data = frame; 28919df918dSFrançois Tigeot struct drm_device *dev = encoder->dev; 29019df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 29119df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 2928e26cdf6SFrançois Tigeot u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder); 293*9edbd4a0SFrançois Tigeot u32 data_reg; 294*9edbd4a0SFrançois Tigeot int i; 29519df918dSFrançois Tigeot u32 val = I915_READ(ctl_reg); 29619df918dSFrançois Tigeot 297*9edbd4a0SFrançois Tigeot data_reg = hsw_infoframe_data_reg(type, 298*9edbd4a0SFrançois Tigeot intel_crtc->config.cpu_transcoder); 29919df918dSFrançois Tigeot if (data_reg == 0) 30019df918dSFrançois Tigeot return; 30119df918dSFrançois Tigeot 302*9edbd4a0SFrançois Tigeot val &= ~hsw_infoframe_enable(type); 30319df918dSFrançois Tigeot I915_WRITE(ctl_reg, val); 30419df918dSFrançois Tigeot 30519df918dSFrançois Tigeot mmiowb(); 30619df918dSFrançois Tigeot for (i = 0; i < len; i += 4) { 30719df918dSFrançois Tigeot I915_WRITE(data_reg + i, *data); 30819df918dSFrançois Tigeot data++; 30919df918dSFrançois Tigeot } 31019df918dSFrançois Tigeot /* Write every possible data byte to force correct ECC calculation. */ 31119df918dSFrançois Tigeot for (; i < VIDEO_DIP_DATA_SIZE; i += 4) 31219df918dSFrançois Tigeot I915_WRITE(data_reg + i, 0); 31319df918dSFrançois Tigeot mmiowb(); 31419df918dSFrançois Tigeot 315*9edbd4a0SFrançois Tigeot val |= hsw_infoframe_enable(type); 31619df918dSFrançois Tigeot I915_WRITE(ctl_reg, val); 31719df918dSFrançois Tigeot POSTING_READ(ctl_reg); 318e3adcf8fSFrançois Tigeot } 319e3adcf8fSFrançois Tigeot 320*9edbd4a0SFrançois Tigeot /* 321*9edbd4a0SFrançois Tigeot * The data we write to the DIP data buffer registers is 1 byte bigger than the 322*9edbd4a0SFrançois Tigeot * HDMI infoframe size because of an ECC/reserved byte at position 3 (starting 323*9edbd4a0SFrançois Tigeot * at 0). It's also a byte used by DisplayPort so the same DIP registers can be 324*9edbd4a0SFrançois Tigeot * used for both technologies. 325*9edbd4a0SFrançois Tigeot * 326*9edbd4a0SFrançois Tigeot * DW0: Reserved/ECC/DP | HB2 | HB1 | HB0 327*9edbd4a0SFrançois Tigeot * DW1: DB3 | DB2 | DB1 | DB0 328*9edbd4a0SFrançois Tigeot * DW2: DB7 | DB6 | DB5 | DB4 329*9edbd4a0SFrançois Tigeot * DW3: ... 330*9edbd4a0SFrançois Tigeot * 331*9edbd4a0SFrançois Tigeot * (HB is Header Byte, DB is Data Byte) 332*9edbd4a0SFrançois Tigeot * 333*9edbd4a0SFrançois Tigeot * The hdmi pack() functions don't know about that hardware specific hole so we 334*9edbd4a0SFrançois Tigeot * trick them by giving an offset into the buffer and moving back the header 335*9edbd4a0SFrançois Tigeot * bytes by one. 336*9edbd4a0SFrançois Tigeot */ 337*9edbd4a0SFrançois Tigeot static void intel_write_infoframe(struct drm_encoder *encoder, 338*9edbd4a0SFrançois Tigeot union hdmi_infoframe *frame) 339e3adcf8fSFrançois Tigeot { 340e3adcf8fSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 341*9edbd4a0SFrançois Tigeot uint8_t buffer[VIDEO_DIP_DATA_SIZE]; 342*9edbd4a0SFrançois Tigeot ssize_t len; 343e3adcf8fSFrançois Tigeot 344*9edbd4a0SFrançois Tigeot /* see comment above for the reason for this offset */ 345*9edbd4a0SFrançois Tigeot len = hdmi_infoframe_pack(frame, buffer + 1, sizeof(buffer) - 1); 346*9edbd4a0SFrançois Tigeot if (len < 0) 347*9edbd4a0SFrançois Tigeot return; 348*9edbd4a0SFrançois Tigeot 349*9edbd4a0SFrançois Tigeot /* Insert the 'hole' (see big comment above) at position 3 */ 350*9edbd4a0SFrançois Tigeot buffer[0] = buffer[1]; 351*9edbd4a0SFrançois Tigeot buffer[1] = buffer[2]; 352*9edbd4a0SFrançois Tigeot buffer[2] = buffer[3]; 353*9edbd4a0SFrançois Tigeot buffer[3] = 0; 354*9edbd4a0SFrançois Tigeot len++; 355*9edbd4a0SFrançois Tigeot 356*9edbd4a0SFrançois Tigeot intel_hdmi->write_infoframe(encoder, frame->any.type, buffer, len); 357e3adcf8fSFrançois Tigeot } 358e3adcf8fSFrançois Tigeot 35919df918dSFrançois Tigeot static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, 36019df918dSFrançois Tigeot struct drm_display_mode *adjusted_mode) 361e3adcf8fSFrançois Tigeot { 362a2fdbec6SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 3638e26cdf6SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 364*9edbd4a0SFrançois Tigeot union hdmi_infoframe frame; 365*9edbd4a0SFrançois Tigeot int ret; 366e3adcf8fSFrançois Tigeot 367*9edbd4a0SFrançois Tigeot ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, 368*9edbd4a0SFrançois Tigeot adjusted_mode); 369*9edbd4a0SFrançois Tigeot if (ret < 0) { 370*9edbd4a0SFrançois Tigeot DRM_ERROR("couldn't fill AVI infoframe\n"); 371*9edbd4a0SFrançois Tigeot return; 372*9edbd4a0SFrançois Tigeot } 37319df918dSFrançois Tigeot 374a2fdbec6SFrançois Tigeot if (intel_hdmi->rgb_quant_range_selectable) { 3758e26cdf6SFrançois Tigeot if (intel_crtc->config.limited_color_range) 376*9edbd4a0SFrançois Tigeot frame.avi.quantization_range = 377*9edbd4a0SFrançois Tigeot HDMI_QUANTIZATION_RANGE_LIMITED; 378a2fdbec6SFrançois Tigeot else 379*9edbd4a0SFrançois Tigeot frame.avi.quantization_range = 380*9edbd4a0SFrançois Tigeot HDMI_QUANTIZATION_RANGE_FULL; 381a2fdbec6SFrançois Tigeot } 382a2fdbec6SFrançois Tigeot 383*9edbd4a0SFrançois Tigeot intel_write_infoframe(encoder, &frame); 384e3adcf8fSFrançois Tigeot } 385e3adcf8fSFrançois Tigeot 386e3adcf8fSFrançois Tigeot static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder) 387e3adcf8fSFrançois Tigeot { 388*9edbd4a0SFrançois Tigeot union hdmi_infoframe frame; 389*9edbd4a0SFrançois Tigeot int ret; 390e3adcf8fSFrançois Tigeot 391*9edbd4a0SFrançois Tigeot ret = hdmi_spd_infoframe_init(&frame.spd, "Intel", "Integrated gfx"); 392*9edbd4a0SFrançois Tigeot if (ret < 0) { 393*9edbd4a0SFrançois Tigeot DRM_ERROR("couldn't fill SPD infoframe\n"); 394*9edbd4a0SFrançois Tigeot return; 395*9edbd4a0SFrançois Tigeot } 396e3adcf8fSFrançois Tigeot 397*9edbd4a0SFrançois Tigeot frame.spd.sdi = HDMI_SPD_SDI_PC; 398*9edbd4a0SFrançois Tigeot 399*9edbd4a0SFrançois Tigeot intel_write_infoframe(encoder, &frame); 400*9edbd4a0SFrançois Tigeot } 401*9edbd4a0SFrançois Tigeot 402*9edbd4a0SFrançois Tigeot static void 403*9edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder, 404*9edbd4a0SFrançois Tigeot struct drm_display_mode *adjusted_mode) 405*9edbd4a0SFrançois Tigeot { 406*9edbd4a0SFrançois Tigeot union hdmi_infoframe frame; 407*9edbd4a0SFrançois Tigeot int ret; 408*9edbd4a0SFrançois Tigeot 409*9edbd4a0SFrançois Tigeot ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi, 410*9edbd4a0SFrançois Tigeot adjusted_mode); 411*9edbd4a0SFrançois Tigeot if (ret < 0) 412*9edbd4a0SFrançois Tigeot return; 413*9edbd4a0SFrançois Tigeot 414*9edbd4a0SFrançois Tigeot intel_write_infoframe(encoder, &frame); 415e3adcf8fSFrançois Tigeot } 416e3adcf8fSFrançois Tigeot 41719df918dSFrançois Tigeot static void g4x_set_infoframes(struct drm_encoder *encoder, 41819df918dSFrançois Tigeot struct drm_display_mode *adjusted_mode) 41919df918dSFrançois Tigeot { 42019df918dSFrançois Tigeot struct drm_i915_private *dev_priv = encoder->dev->dev_private; 421a2fdbec6SFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); 422a2fdbec6SFrançois Tigeot struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; 42319df918dSFrançois Tigeot u32 reg = VIDEO_DIP_CTL; 42419df918dSFrançois Tigeot u32 val = I915_READ(reg); 42519df918dSFrançois Tigeot u32 port; 42619df918dSFrançois Tigeot 42719df918dSFrançois Tigeot assert_hdmi_port_disabled(intel_hdmi); 42819df918dSFrançois Tigeot 42919df918dSFrançois Tigeot /* If the registers were not initialized yet, they might be zeroes, 43019df918dSFrançois Tigeot * which means we're selecting the AVI DIP and we're setting its 43119df918dSFrançois Tigeot * frequency to once. This seems to really confuse the HW and make 43219df918dSFrançois Tigeot * things stop working (the register spec says the AVI always needs to 43319df918dSFrançois Tigeot * be sent every VSync). So here we avoid writing to the register more 43419df918dSFrançois Tigeot * than we need and also explicitly select the AVI DIP and explicitly 43519df918dSFrançois Tigeot * set its frequency to every VSync. Avoiding to write it twice seems to 43619df918dSFrançois Tigeot * be enough to solve the problem, but being defensive shouldn't hurt us 43719df918dSFrançois Tigeot * either. */ 43819df918dSFrançois Tigeot val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; 43919df918dSFrançois Tigeot 44019df918dSFrançois Tigeot if (!intel_hdmi->has_hdmi_sink) { 44119df918dSFrançois Tigeot if (!(val & VIDEO_DIP_ENABLE)) 44219df918dSFrançois Tigeot return; 44319df918dSFrançois Tigeot val &= ~VIDEO_DIP_ENABLE; 44419df918dSFrançois Tigeot I915_WRITE(reg, val); 44519df918dSFrançois Tigeot POSTING_READ(reg); 44619df918dSFrançois Tigeot return; 44719df918dSFrançois Tigeot } 44819df918dSFrançois Tigeot 449a2fdbec6SFrançois Tigeot switch (intel_dig_port->port) { 450a2fdbec6SFrançois Tigeot case PORT_B: 45119df918dSFrançois Tigeot port = VIDEO_DIP_PORT_B; 45219df918dSFrançois Tigeot break; 453a2fdbec6SFrançois Tigeot case PORT_C: 45419df918dSFrançois Tigeot port = VIDEO_DIP_PORT_C; 45519df918dSFrançois Tigeot break; 45619df918dSFrançois Tigeot default: 45719df918dSFrançois Tigeot BUG(); 45819df918dSFrançois Tigeot return; 45919df918dSFrançois Tigeot } 46019df918dSFrançois Tigeot 46119df918dSFrançois Tigeot if (port != (val & VIDEO_DIP_PORT_MASK)) { 46219df918dSFrançois Tigeot if (val & VIDEO_DIP_ENABLE) { 46319df918dSFrançois Tigeot val &= ~VIDEO_DIP_ENABLE; 46419df918dSFrançois Tigeot I915_WRITE(reg, val); 46519df918dSFrançois Tigeot POSTING_READ(reg); 46619df918dSFrançois Tigeot } 46719df918dSFrançois Tigeot val &= ~VIDEO_DIP_PORT_MASK; 46819df918dSFrançois Tigeot val |= port; 46919df918dSFrançois Tigeot } 47019df918dSFrançois Tigeot 47119df918dSFrançois Tigeot val |= VIDEO_DIP_ENABLE; 47219df918dSFrançois Tigeot val &= ~VIDEO_DIP_ENABLE_VENDOR; 47319df918dSFrançois Tigeot 47419df918dSFrançois Tigeot I915_WRITE(reg, val); 47519df918dSFrançois Tigeot POSTING_READ(reg); 47619df918dSFrançois Tigeot 47719df918dSFrançois Tigeot intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); 47819df918dSFrançois Tigeot intel_hdmi_set_spd_infoframe(encoder); 479*9edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode); 48019df918dSFrançois Tigeot } 48119df918dSFrançois Tigeot 48219df918dSFrançois Tigeot static void ibx_set_infoframes(struct drm_encoder *encoder, 48319df918dSFrançois Tigeot struct drm_display_mode *adjusted_mode) 48419df918dSFrançois Tigeot { 48519df918dSFrançois Tigeot struct drm_i915_private *dev_priv = encoder->dev->dev_private; 48619df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 487a2fdbec6SFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); 488a2fdbec6SFrançois Tigeot struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; 48919df918dSFrançois Tigeot u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe); 49019df918dSFrançois Tigeot u32 val = I915_READ(reg); 49119df918dSFrançois Tigeot u32 port; 49219df918dSFrançois Tigeot 49319df918dSFrançois Tigeot assert_hdmi_port_disabled(intel_hdmi); 49419df918dSFrançois Tigeot 49519df918dSFrançois Tigeot /* See the big comment in g4x_set_infoframes() */ 49619df918dSFrançois Tigeot val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; 49719df918dSFrançois Tigeot 49819df918dSFrançois Tigeot if (!intel_hdmi->has_hdmi_sink) { 49919df918dSFrançois Tigeot if (!(val & VIDEO_DIP_ENABLE)) 50019df918dSFrançois Tigeot return; 50119df918dSFrançois Tigeot val &= ~VIDEO_DIP_ENABLE; 50219df918dSFrançois Tigeot I915_WRITE(reg, val); 50319df918dSFrançois Tigeot POSTING_READ(reg); 50419df918dSFrançois Tigeot return; 50519df918dSFrançois Tigeot } 50619df918dSFrançois Tigeot 507a2fdbec6SFrançois Tigeot switch (intel_dig_port->port) { 508a2fdbec6SFrançois Tigeot case PORT_B: 50919df918dSFrançois Tigeot port = VIDEO_DIP_PORT_B; 51019df918dSFrançois Tigeot break; 511a2fdbec6SFrançois Tigeot case PORT_C: 51219df918dSFrançois Tigeot port = VIDEO_DIP_PORT_C; 51319df918dSFrançois Tigeot break; 514a2fdbec6SFrançois Tigeot case PORT_D: 51519df918dSFrançois Tigeot port = VIDEO_DIP_PORT_D; 51619df918dSFrançois Tigeot break; 51719df918dSFrançois Tigeot default: 51819df918dSFrançois Tigeot BUG(); 51919df918dSFrançois Tigeot return; 52019df918dSFrançois Tigeot } 52119df918dSFrançois Tigeot 52219df918dSFrançois Tigeot if (port != (val & VIDEO_DIP_PORT_MASK)) { 52319df918dSFrançois Tigeot if (val & VIDEO_DIP_ENABLE) { 52419df918dSFrançois Tigeot val &= ~VIDEO_DIP_ENABLE; 52519df918dSFrançois Tigeot I915_WRITE(reg, val); 52619df918dSFrançois Tigeot POSTING_READ(reg); 52719df918dSFrançois Tigeot } 52819df918dSFrançois Tigeot val &= ~VIDEO_DIP_PORT_MASK; 52919df918dSFrançois Tigeot val |= port; 53019df918dSFrançois Tigeot } 53119df918dSFrançois Tigeot 53219df918dSFrançois Tigeot val |= VIDEO_DIP_ENABLE; 53319df918dSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | 53419df918dSFrançois Tigeot VIDEO_DIP_ENABLE_GCP); 53519df918dSFrançois Tigeot 53619df918dSFrançois Tigeot I915_WRITE(reg, val); 53719df918dSFrançois Tigeot POSTING_READ(reg); 53819df918dSFrançois Tigeot 53919df918dSFrançois Tigeot intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); 54019df918dSFrançois Tigeot intel_hdmi_set_spd_infoframe(encoder); 541*9edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode); 54219df918dSFrançois Tigeot } 54319df918dSFrançois Tigeot 54419df918dSFrançois Tigeot static void cpt_set_infoframes(struct drm_encoder *encoder, 54519df918dSFrançois Tigeot struct drm_display_mode *adjusted_mode) 54619df918dSFrançois Tigeot { 54719df918dSFrançois Tigeot struct drm_i915_private *dev_priv = encoder->dev->dev_private; 54819df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 54919df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 55019df918dSFrançois Tigeot u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe); 55119df918dSFrançois Tigeot u32 val = I915_READ(reg); 55219df918dSFrançois Tigeot 55319df918dSFrançois Tigeot assert_hdmi_port_disabled(intel_hdmi); 55419df918dSFrançois Tigeot 55519df918dSFrançois Tigeot /* See the big comment in g4x_set_infoframes() */ 55619df918dSFrançois Tigeot val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; 55719df918dSFrançois Tigeot 55819df918dSFrançois Tigeot if (!intel_hdmi->has_hdmi_sink) { 55919df918dSFrançois Tigeot if (!(val & VIDEO_DIP_ENABLE)) 56019df918dSFrançois Tigeot return; 56119df918dSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI); 56219df918dSFrançois Tigeot I915_WRITE(reg, val); 56319df918dSFrançois Tigeot POSTING_READ(reg); 56419df918dSFrançois Tigeot return; 56519df918dSFrançois Tigeot } 56619df918dSFrançois Tigeot 56719df918dSFrançois Tigeot /* Set both together, unset both together: see the spec. */ 56819df918dSFrançois Tigeot val |= VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI; 56919df918dSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | 57019df918dSFrançois Tigeot VIDEO_DIP_ENABLE_GCP); 57119df918dSFrançois Tigeot 57219df918dSFrançois Tigeot I915_WRITE(reg, val); 57319df918dSFrançois Tigeot POSTING_READ(reg); 57419df918dSFrançois Tigeot 57519df918dSFrançois Tigeot intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); 57619df918dSFrançois Tigeot intel_hdmi_set_spd_infoframe(encoder); 577*9edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode); 57819df918dSFrançois Tigeot } 57919df918dSFrançois Tigeot 58019df918dSFrançois Tigeot static void vlv_set_infoframes(struct drm_encoder *encoder, 58119df918dSFrançois Tigeot struct drm_display_mode *adjusted_mode) 58219df918dSFrançois Tigeot { 58319df918dSFrançois Tigeot struct drm_i915_private *dev_priv = encoder->dev->dev_private; 58419df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 58519df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 58619df918dSFrançois Tigeot u32 reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); 58719df918dSFrançois Tigeot u32 val = I915_READ(reg); 58819df918dSFrançois Tigeot 58919df918dSFrançois Tigeot assert_hdmi_port_disabled(intel_hdmi); 59019df918dSFrançois Tigeot 59119df918dSFrançois Tigeot /* See the big comment in g4x_set_infoframes() */ 59219df918dSFrançois Tigeot val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; 59319df918dSFrançois Tigeot 59419df918dSFrançois Tigeot if (!intel_hdmi->has_hdmi_sink) { 59519df918dSFrançois Tigeot if (!(val & VIDEO_DIP_ENABLE)) 59619df918dSFrançois Tigeot return; 59719df918dSFrançois Tigeot val &= ~VIDEO_DIP_ENABLE; 59819df918dSFrançois Tigeot I915_WRITE(reg, val); 59919df918dSFrançois Tigeot POSTING_READ(reg); 60019df918dSFrançois Tigeot return; 60119df918dSFrançois Tigeot } 60219df918dSFrançois Tigeot 60319df918dSFrançois Tigeot val |= VIDEO_DIP_ENABLE; 60419df918dSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | 60519df918dSFrançois Tigeot VIDEO_DIP_ENABLE_GCP); 60619df918dSFrançois Tigeot 60719df918dSFrançois Tigeot I915_WRITE(reg, val); 60819df918dSFrançois Tigeot POSTING_READ(reg); 60919df918dSFrançois Tigeot 61019df918dSFrançois Tigeot intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); 61119df918dSFrançois Tigeot intel_hdmi_set_spd_infoframe(encoder); 612*9edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode); 61319df918dSFrançois Tigeot } 61419df918dSFrançois Tigeot 61519df918dSFrançois Tigeot static void hsw_set_infoframes(struct drm_encoder *encoder, 61619df918dSFrançois Tigeot struct drm_display_mode *adjusted_mode) 61719df918dSFrançois Tigeot { 61819df918dSFrançois Tigeot struct drm_i915_private *dev_priv = encoder->dev->dev_private; 61919df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 62019df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 6218e26cdf6SFrançois Tigeot u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder); 62219df918dSFrançois Tigeot u32 val = I915_READ(reg); 62319df918dSFrançois Tigeot 62419df918dSFrançois Tigeot assert_hdmi_port_disabled(intel_hdmi); 62519df918dSFrançois Tigeot 62619df918dSFrançois Tigeot if (!intel_hdmi->has_hdmi_sink) { 62719df918dSFrançois Tigeot I915_WRITE(reg, 0); 62819df918dSFrançois Tigeot POSTING_READ(reg); 62919df918dSFrançois Tigeot return; 63019df918dSFrançois Tigeot } 63119df918dSFrançois Tigeot 63219df918dSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_GCP_HSW | 63319df918dSFrançois Tigeot VIDEO_DIP_ENABLE_VS_HSW | VIDEO_DIP_ENABLE_GMP_HSW); 63419df918dSFrançois Tigeot 63519df918dSFrançois Tigeot I915_WRITE(reg, val); 63619df918dSFrançois Tigeot POSTING_READ(reg); 63719df918dSFrançois Tigeot 63819df918dSFrançois Tigeot intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); 63919df918dSFrançois Tigeot intel_hdmi_set_spd_infoframe(encoder); 640*9edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode); 64119df918dSFrançois Tigeot } 64219df918dSFrançois Tigeot 643*9edbd4a0SFrançois Tigeot static void intel_hdmi_mode_set(struct intel_encoder *encoder) 644e3adcf8fSFrançois Tigeot { 645*9edbd4a0SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 646e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 647*9edbd4a0SFrançois Tigeot struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); 648*9edbd4a0SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 649*9edbd4a0SFrançois Tigeot struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode; 6508e26cdf6SFrançois Tigeot u32 hdmi_val; 651e3adcf8fSFrançois Tigeot 6528e26cdf6SFrançois Tigeot hdmi_val = SDVO_ENCODING_HDMI; 6535d0b1887SFrançois Tigeot if (!HAS_PCH_SPLIT(dev)) 6548e26cdf6SFrançois Tigeot hdmi_val |= intel_hdmi->color_range; 655e3adcf8fSFrançois Tigeot if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) 6568e26cdf6SFrançois Tigeot hdmi_val |= SDVO_VSYNC_ACTIVE_HIGH; 657e3adcf8fSFrançois Tigeot if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) 6588e26cdf6SFrançois Tigeot hdmi_val |= SDVO_HSYNC_ACTIVE_HIGH; 659e3adcf8fSFrançois Tigeot 660*9edbd4a0SFrançois Tigeot if (crtc->config.pipe_bpp > 24) 6618e26cdf6SFrançois Tigeot hdmi_val |= HDMI_COLOR_FORMAT_12bpc; 662e3adcf8fSFrançois Tigeot else 6638e26cdf6SFrançois Tigeot hdmi_val |= SDVO_COLOR_FORMAT_8bpc; 664e3adcf8fSFrançois Tigeot 665e3adcf8fSFrançois Tigeot /* Required on CPT */ 666e3adcf8fSFrançois Tigeot if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev)) 6678e26cdf6SFrançois Tigeot hdmi_val |= HDMI_MODE_SELECT_HDMI; 668e3adcf8fSFrançois Tigeot 669e3adcf8fSFrançois Tigeot if (intel_hdmi->has_audio) { 67019df918dSFrançois Tigeot DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", 671*9edbd4a0SFrançois Tigeot pipe_name(crtc->pipe)); 6728e26cdf6SFrançois Tigeot hdmi_val |= SDVO_AUDIO_ENABLE; 6738e26cdf6SFrançois Tigeot hdmi_val |= HDMI_MODE_SELECT_HDMI; 674*9edbd4a0SFrançois Tigeot intel_write_eld(&encoder->base, adjusted_mode); 675e3adcf8fSFrançois Tigeot } 676e3adcf8fSFrançois Tigeot 677e3adcf8fSFrançois Tigeot if (HAS_PCH_CPT(dev)) 678*9edbd4a0SFrançois Tigeot hdmi_val |= SDVO_PIPE_SEL_CPT(crtc->pipe); 6798e26cdf6SFrançois Tigeot else 680*9edbd4a0SFrançois Tigeot hdmi_val |= SDVO_PIPE_SEL(crtc->pipe); 681e3adcf8fSFrançois Tigeot 6828e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, hdmi_val); 6838e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 684e3adcf8fSFrançois Tigeot 685*9edbd4a0SFrançois Tigeot intel_hdmi->set_infoframes(&encoder->base, adjusted_mode); 686e3adcf8fSFrançois Tigeot } 687e3adcf8fSFrançois Tigeot 68819df918dSFrançois Tigeot static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder, 68919df918dSFrançois Tigeot enum i915_pipe *pipe) 690e3adcf8fSFrançois Tigeot { 69119df918dSFrançois Tigeot struct drm_device *dev = encoder->base.dev; 692e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 69319df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 69419df918dSFrançois Tigeot u32 tmp; 69519df918dSFrançois Tigeot 6968e26cdf6SFrançois Tigeot tmp = I915_READ(intel_hdmi->hdmi_reg); 69719df918dSFrançois Tigeot 69819df918dSFrançois Tigeot if (!(tmp & SDVO_ENABLE)) 69919df918dSFrançois Tigeot return false; 70019df918dSFrançois Tigeot 70119df918dSFrançois Tigeot if (HAS_PCH_CPT(dev)) 70219df918dSFrançois Tigeot *pipe = PORT_TO_PIPE_CPT(tmp); 70319df918dSFrançois Tigeot else 70419df918dSFrançois Tigeot *pipe = PORT_TO_PIPE(tmp); 70519df918dSFrançois Tigeot 70619df918dSFrançois Tigeot return true; 70719df918dSFrançois Tigeot } 70819df918dSFrançois Tigeot 7095d0b1887SFrançois Tigeot static void intel_hdmi_get_config(struct intel_encoder *encoder, 7105d0b1887SFrançois Tigeot struct intel_crtc_config *pipe_config) 7115d0b1887SFrançois Tigeot { 7125d0b1887SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 7135d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; 7145d0b1887SFrançois Tigeot u32 tmp, flags = 0; 715*9edbd4a0SFrançois Tigeot int dotclock; 7165d0b1887SFrançois Tigeot 7175d0b1887SFrançois Tigeot tmp = I915_READ(intel_hdmi->hdmi_reg); 7185d0b1887SFrançois Tigeot 7195d0b1887SFrançois Tigeot if (tmp & SDVO_HSYNC_ACTIVE_HIGH) 7205d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_PHSYNC; 7215d0b1887SFrançois Tigeot else 7225d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_NHSYNC; 7235d0b1887SFrançois Tigeot 7245d0b1887SFrançois Tigeot if (tmp & SDVO_VSYNC_ACTIVE_HIGH) 7255d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_PVSYNC; 7265d0b1887SFrançois Tigeot else 7275d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_NVSYNC; 7285d0b1887SFrançois Tigeot 7295d0b1887SFrançois Tigeot pipe_config->adjusted_mode.flags |= flags; 730*9edbd4a0SFrançois Tigeot 731*9edbd4a0SFrançois Tigeot if ((tmp & SDVO_COLOR_FORMAT_MASK) == HDMI_COLOR_FORMAT_12bpc) 732*9edbd4a0SFrançois Tigeot dotclock = pipe_config->port_clock * 2 / 3; 733*9edbd4a0SFrançois Tigeot else 734*9edbd4a0SFrançois Tigeot dotclock = pipe_config->port_clock; 735*9edbd4a0SFrançois Tigeot 736*9edbd4a0SFrançois Tigeot if (HAS_PCH_SPLIT(dev_priv->dev)) 737*9edbd4a0SFrançois Tigeot ironlake_check_encoder_dotclock(pipe_config, dotclock); 738*9edbd4a0SFrançois Tigeot 739*9edbd4a0SFrançois Tigeot pipe_config->adjusted_mode.crtc_clock = dotclock; 7405d0b1887SFrançois Tigeot } 7415d0b1887SFrançois Tigeot 74219df918dSFrançois Tigeot static void intel_enable_hdmi(struct intel_encoder *encoder) 74319df918dSFrançois Tigeot { 74419df918dSFrançois Tigeot struct drm_device *dev = encoder->base.dev; 74519df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 7468e26cdf6SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); 74719df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 748e3adcf8fSFrançois Tigeot u32 temp; 749e3adcf8fSFrançois Tigeot u32 enable_bits = SDVO_ENABLE; 750e3adcf8fSFrançois Tigeot 751e3adcf8fSFrançois Tigeot if (intel_hdmi->has_audio) 752e3adcf8fSFrançois Tigeot enable_bits |= SDVO_AUDIO_ENABLE; 753e3adcf8fSFrançois Tigeot 7548e26cdf6SFrançois Tigeot temp = I915_READ(intel_hdmi->hdmi_reg); 755e3adcf8fSFrançois Tigeot 75619df918dSFrançois Tigeot /* HW workaround for IBX, we need to move the port to transcoder A 7578e26cdf6SFrançois Tigeot * before disabling it, so restore the transcoder select bit here. */ 7588e26cdf6SFrançois Tigeot if (HAS_PCH_IBX(dev)) 7598e26cdf6SFrançois Tigeot enable_bits |= SDVO_PIPE_SEL(intel_crtc->pipe); 76019df918dSFrançois Tigeot 761e3adcf8fSFrançois Tigeot /* HW workaround, need to toggle enable bit off and on for 12bpc, but 762e3adcf8fSFrançois Tigeot * we do this anyway which shows more stable in testing. 763e3adcf8fSFrançois Tigeot */ 764e3adcf8fSFrançois Tigeot if (HAS_PCH_SPLIT(dev)) { 7658e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE); 7668e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 767e3adcf8fSFrançois Tigeot } 768e3adcf8fSFrançois Tigeot 769e3adcf8fSFrançois Tigeot temp |= enable_bits; 77019df918dSFrançois Tigeot 7718e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 7728e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 77319df918dSFrançois Tigeot 77419df918dSFrançois Tigeot /* HW workaround, need to write this twice for issue that may result 77519df918dSFrançois Tigeot * in first write getting masked. 77619df918dSFrançois Tigeot */ 77719df918dSFrançois Tigeot if (HAS_PCH_SPLIT(dev)) { 7788e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 7798e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 780e3adcf8fSFrançois Tigeot } 7815d0b1887SFrançois Tigeot } 782*9edbd4a0SFrançois Tigeot 783*9edbd4a0SFrançois Tigeot static void vlv_enable_hdmi(struct intel_encoder *encoder) 784*9edbd4a0SFrançois Tigeot { 78519df918dSFrançois Tigeot } 78619df918dSFrançois Tigeot 78719df918dSFrançois Tigeot static void intel_disable_hdmi(struct intel_encoder *encoder) 78819df918dSFrançois Tigeot { 78919df918dSFrançois Tigeot struct drm_device *dev = encoder->base.dev; 79019df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 79119df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 79219df918dSFrançois Tigeot u32 temp; 79319df918dSFrançois Tigeot u32 enable_bits = SDVO_ENABLE | SDVO_AUDIO_ENABLE; 79419df918dSFrançois Tigeot 7958e26cdf6SFrançois Tigeot temp = I915_READ(intel_hdmi->hdmi_reg); 79619df918dSFrançois Tigeot 79719df918dSFrançois Tigeot /* HW workaround for IBX, we need to move the port to transcoder A 79819df918dSFrançois Tigeot * before disabling it. */ 79919df918dSFrançois Tigeot if (HAS_PCH_IBX(dev)) { 80019df918dSFrançois Tigeot struct drm_crtc *crtc = encoder->base.crtc; 80119df918dSFrançois Tigeot int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1; 80219df918dSFrançois Tigeot 80319df918dSFrançois Tigeot if (temp & SDVO_PIPE_B_SELECT) { 80419df918dSFrançois Tigeot temp &= ~SDVO_PIPE_B_SELECT; 8058e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 8068e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 80719df918dSFrançois Tigeot 80819df918dSFrançois Tigeot /* Again we need to write this twice. */ 8098e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 8108e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 81119df918dSFrançois Tigeot 81219df918dSFrançois Tigeot /* Transcoder selection bits only update 81319df918dSFrançois Tigeot * effectively on vblank. */ 81419df918dSFrançois Tigeot if (crtc) 81519df918dSFrançois Tigeot intel_wait_for_vblank(dev, pipe); 81619df918dSFrançois Tigeot else 81719df918dSFrançois Tigeot msleep(50); 81819df918dSFrançois Tigeot } 81919df918dSFrançois Tigeot } 82019df918dSFrançois Tigeot 82119df918dSFrançois Tigeot /* HW workaround, need to toggle enable bit off and on for 12bpc, but 82219df918dSFrançois Tigeot * we do this anyway which shows more stable in testing. 82319df918dSFrançois Tigeot */ 82419df918dSFrançois Tigeot if (HAS_PCH_SPLIT(dev)) { 8258e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE); 8268e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 82719df918dSFrançois Tigeot } 82819df918dSFrançois Tigeot 82919df918dSFrançois Tigeot temp &= ~enable_bits; 830e3adcf8fSFrançois Tigeot 8318e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 8328e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 833e3adcf8fSFrançois Tigeot 834e3adcf8fSFrançois Tigeot /* HW workaround, need to write this twice for issue that may result 835e3adcf8fSFrançois Tigeot * in first write getting masked. 836e3adcf8fSFrançois Tigeot */ 837e3adcf8fSFrançois Tigeot if (HAS_PCH_SPLIT(dev)) { 8388e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 8398e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 840e3adcf8fSFrançois Tigeot } 841e3adcf8fSFrançois Tigeot } 842e3adcf8fSFrançois Tigeot 8435d0b1887SFrançois Tigeot static int hdmi_portclock_limit(struct intel_hdmi *hdmi) 8445d0b1887SFrançois Tigeot { 8455d0b1887SFrançois Tigeot struct drm_device *dev = intel_hdmi_to_dev(hdmi); 8465d0b1887SFrançois Tigeot 847*9edbd4a0SFrançois Tigeot if (!hdmi->has_hdmi_sink || IS_G4X(dev)) 8485d0b1887SFrançois Tigeot return 165000; 849*9edbd4a0SFrançois Tigeot else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8) 8505d0b1887SFrançois Tigeot return 300000; 8515d0b1887SFrançois Tigeot else 8525d0b1887SFrançois Tigeot return 225000; 8535d0b1887SFrançois Tigeot } 8545d0b1887SFrançois Tigeot 855*9edbd4a0SFrançois Tigeot static enum drm_mode_status 856*9edbd4a0SFrançois Tigeot intel_hdmi_mode_valid(struct drm_connector *connector, 857e3adcf8fSFrançois Tigeot struct drm_display_mode *mode) 858e3adcf8fSFrançois Tigeot { 8595d0b1887SFrançois Tigeot if (mode->clock > hdmi_portclock_limit(intel_attached_hdmi(connector))) 860e3adcf8fSFrançois Tigeot return MODE_CLOCK_HIGH; 861e3adcf8fSFrançois Tigeot if (mode->clock < 20000) 862e3adcf8fSFrançois Tigeot return MODE_CLOCK_LOW; 863e3adcf8fSFrançois Tigeot 864e3adcf8fSFrançois Tigeot if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 865e3adcf8fSFrançois Tigeot return MODE_NO_DBLESCAN; 866e3adcf8fSFrançois Tigeot 867e3adcf8fSFrançois Tigeot return MODE_OK; 868e3adcf8fSFrançois Tigeot } 869e3adcf8fSFrançois Tigeot 8708e26cdf6SFrançois Tigeot bool intel_hdmi_compute_config(struct intel_encoder *encoder, 8718e26cdf6SFrançois Tigeot struct intel_crtc_config *pipe_config) 872e3adcf8fSFrançois Tigeot { 8738e26cdf6SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 8748e26cdf6SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 8758e26cdf6SFrançois Tigeot struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; 876*9edbd4a0SFrançois Tigeot int clock_12bpc = pipe_config->adjusted_mode.crtc_clock * 3 / 2; 8775d0b1887SFrançois Tigeot int portclock_limit = hdmi_portclock_limit(intel_hdmi); 8785d0b1887SFrançois Tigeot int desired_bpp; 879a2fdbec6SFrançois Tigeot 880a2fdbec6SFrançois Tigeot if (intel_hdmi->color_range_auto) { 881a2fdbec6SFrançois Tigeot /* See CEA-861-E - 5.1 Default Encoding Parameters */ 882a2fdbec6SFrançois Tigeot if (intel_hdmi->has_hdmi_sink && 883a2fdbec6SFrançois Tigeot drm_match_cea_mode(adjusted_mode) > 1) 8848e26cdf6SFrançois Tigeot intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235; 885a2fdbec6SFrançois Tigeot else 886a2fdbec6SFrançois Tigeot intel_hdmi->color_range = 0; 887a2fdbec6SFrançois Tigeot } 888a2fdbec6SFrançois Tigeot 889a2fdbec6SFrançois Tigeot if (intel_hdmi->color_range) 8908e26cdf6SFrançois Tigeot pipe_config->limited_color_range = true; 8918e26cdf6SFrançois Tigeot 8928e26cdf6SFrançois Tigeot if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev)) 8938e26cdf6SFrançois Tigeot pipe_config->has_pch_encoder = true; 8948e26cdf6SFrançois Tigeot 8958e26cdf6SFrançois Tigeot /* 8968e26cdf6SFrançois Tigeot * HDMI is either 12 or 8, so if the display lets 10bpc sneak 8978e26cdf6SFrançois Tigeot * through, clamp it down. Note that g4x/vlv don't support 12bpc hdmi 8985d0b1887SFrançois Tigeot * outputs. We also need to check that the higher clock still fits 8995d0b1887SFrançois Tigeot * within limits. 9008e26cdf6SFrançois Tigeot */ 901*9edbd4a0SFrançois Tigeot if (pipe_config->pipe_bpp > 8*3 && intel_hdmi->has_hdmi_sink && 902*9edbd4a0SFrançois Tigeot clock_12bpc <= portclock_limit && HAS_PCH_SPLIT(dev)) { 9035d0b1887SFrançois Tigeot DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n"); 9045d0b1887SFrançois Tigeot desired_bpp = 12*3; 9055d0b1887SFrançois Tigeot 9065d0b1887SFrançois Tigeot /* Need to adjust the port link by 1.5x for 12bpc. */ 9075d0b1887SFrançois Tigeot pipe_config->port_clock = clock_12bpc; 9088e26cdf6SFrançois Tigeot } else { 9095d0b1887SFrançois Tigeot DRM_DEBUG_KMS("picking bpc to 8 for HDMI output\n"); 9105d0b1887SFrançois Tigeot desired_bpp = 8*3; 9115d0b1887SFrançois Tigeot } 9125d0b1887SFrançois Tigeot 9135d0b1887SFrançois Tigeot if (!pipe_config->bw_constrained) { 9145d0b1887SFrançois Tigeot DRM_DEBUG_KMS("forcing pipe bpc to %i for HDMI\n", desired_bpp); 9155d0b1887SFrançois Tigeot pipe_config->pipe_bpp = desired_bpp; 9165d0b1887SFrançois Tigeot } 9175d0b1887SFrançois Tigeot 918*9edbd4a0SFrançois Tigeot if (adjusted_mode->crtc_clock > portclock_limit) { 9195d0b1887SFrançois Tigeot DRM_DEBUG_KMS("too high HDMI clock, rejecting mode\n"); 9205d0b1887SFrançois Tigeot return false; 9218e26cdf6SFrançois Tigeot } 922a2fdbec6SFrançois Tigeot 923e3adcf8fSFrançois Tigeot return true; 924e3adcf8fSFrançois Tigeot } 925e3adcf8fSFrançois Tigeot 926e3adcf8fSFrançois Tigeot static enum drm_connector_status 927e3adcf8fSFrançois Tigeot intel_hdmi_detect(struct drm_connector *connector, bool force) 928e3adcf8fSFrançois Tigeot { 929a2fdbec6SFrançois Tigeot struct drm_device *dev = connector->dev; 930e3adcf8fSFrançois Tigeot struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 93119df918dSFrançois Tigeot struct intel_digital_port *intel_dig_port = 93219df918dSFrançois Tigeot hdmi_to_dig_port(intel_hdmi); 93319df918dSFrançois Tigeot struct intel_encoder *intel_encoder = &intel_dig_port->base; 934a2fdbec6SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 935e3adcf8fSFrançois Tigeot struct edid *edid; 936e3adcf8fSFrançois Tigeot enum drm_connector_status status = connector_status_disconnected; 937e3adcf8fSFrançois Tigeot 938*9edbd4a0SFrançois Tigeot DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 939*9edbd4a0SFrançois Tigeot connector->base.id, drm_get_connector_name(connector)); 940*9edbd4a0SFrançois Tigeot 941e3adcf8fSFrançois Tigeot intel_hdmi->has_hdmi_sink = false; 942e3adcf8fSFrançois Tigeot intel_hdmi->has_audio = false; 943a2fdbec6SFrançois Tigeot intel_hdmi->rgb_quant_range_selectable = false; 94419df918dSFrançois Tigeot edid = drm_get_edid(connector, 94519df918dSFrançois Tigeot intel_gmbus_get_adapter(dev_priv, 94619df918dSFrançois Tigeot intel_hdmi->ddc_bus)); 947e3adcf8fSFrançois Tigeot 948e3adcf8fSFrançois Tigeot if (edid) { 949e3adcf8fSFrançois Tigeot if (edid->input & DRM_EDID_INPUT_DIGITAL) { 950e3adcf8fSFrançois Tigeot status = connector_status_connected; 951e3adcf8fSFrançois Tigeot if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI) 952e3adcf8fSFrançois Tigeot intel_hdmi->has_hdmi_sink = 953e3adcf8fSFrançois Tigeot drm_detect_hdmi_monitor(edid); 954e3adcf8fSFrançois Tigeot intel_hdmi->has_audio = drm_detect_monitor_audio(edid); 955a2fdbec6SFrançois Tigeot intel_hdmi->rgb_quant_range_selectable = 956a2fdbec6SFrançois Tigeot drm_rgb_quant_range_selectable(edid); 957e3adcf8fSFrançois Tigeot } 9588e26cdf6SFrançois Tigeot kfree(edid); 959e3adcf8fSFrançois Tigeot } 960e3adcf8fSFrançois Tigeot 961e3adcf8fSFrançois Tigeot if (status == connector_status_connected) { 962e3adcf8fSFrançois Tigeot if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO) 963e3adcf8fSFrançois Tigeot intel_hdmi->has_audio = 964e3adcf8fSFrançois Tigeot (intel_hdmi->force_audio == HDMI_AUDIO_ON); 96519df918dSFrançois Tigeot intel_encoder->type = INTEL_OUTPUT_HDMI; 966e3adcf8fSFrançois Tigeot } 967e3adcf8fSFrançois Tigeot 968e3adcf8fSFrançois Tigeot return status; 969e3adcf8fSFrançois Tigeot } 970e3adcf8fSFrançois Tigeot 971e3adcf8fSFrançois Tigeot static int intel_hdmi_get_modes(struct drm_connector *connector) 972e3adcf8fSFrançois Tigeot { 973e3adcf8fSFrançois Tigeot struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 974e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = connector->dev->dev_private; 975e3adcf8fSFrançois Tigeot 976e3adcf8fSFrançois Tigeot /* We should parse the EDID data and find out if it's an HDMI sink so 977e3adcf8fSFrançois Tigeot * we can send audio to it. 978e3adcf8fSFrançois Tigeot */ 979e3adcf8fSFrançois Tigeot 980e3adcf8fSFrançois Tigeot return intel_ddc_get_modes(connector, 98119df918dSFrançois Tigeot intel_gmbus_get_adapter(dev_priv, 98219df918dSFrançois Tigeot intel_hdmi->ddc_bus)); 983e3adcf8fSFrançois Tigeot } 984e3adcf8fSFrançois Tigeot 985e3adcf8fSFrançois Tigeot static bool 986e3adcf8fSFrançois Tigeot intel_hdmi_detect_audio(struct drm_connector *connector) 987e3adcf8fSFrançois Tigeot { 988e3adcf8fSFrançois Tigeot struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 989e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = connector->dev->dev_private; 990e3adcf8fSFrançois Tigeot struct edid *edid; 991e3adcf8fSFrançois Tigeot bool has_audio = false; 992e3adcf8fSFrançois Tigeot 99319df918dSFrançois Tigeot edid = drm_get_edid(connector, 99419df918dSFrançois Tigeot intel_gmbus_get_adapter(dev_priv, 99519df918dSFrançois Tigeot intel_hdmi->ddc_bus)); 996e3adcf8fSFrançois Tigeot if (edid) { 997e3adcf8fSFrançois Tigeot if (edid->input & DRM_EDID_INPUT_DIGITAL) 998e3adcf8fSFrançois Tigeot has_audio = drm_detect_monitor_audio(edid); 9998e26cdf6SFrançois Tigeot kfree(edid); 1000e3adcf8fSFrançois Tigeot } 1001e3adcf8fSFrançois Tigeot 1002e3adcf8fSFrançois Tigeot return has_audio; 1003e3adcf8fSFrançois Tigeot } 1004e3adcf8fSFrançois Tigeot 1005e3adcf8fSFrançois Tigeot static int 1006e3adcf8fSFrançois Tigeot intel_hdmi_set_property(struct drm_connector *connector, 1007e3adcf8fSFrançois Tigeot struct drm_property *property, 1008e3adcf8fSFrançois Tigeot uint64_t val) 1009e3adcf8fSFrançois Tigeot { 1010e3adcf8fSFrançois Tigeot struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 101119df918dSFrançois Tigeot struct intel_digital_port *intel_dig_port = 101219df918dSFrançois Tigeot hdmi_to_dig_port(intel_hdmi); 1013e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = connector->dev->dev_private; 1014e3adcf8fSFrançois Tigeot int ret; 1015e3adcf8fSFrançois Tigeot 1016b5162e19SFrançois Tigeot ret = drm_object_property_set_value(&connector->base, property, val); 1017e3adcf8fSFrançois Tigeot if (ret) 1018e3adcf8fSFrançois Tigeot return ret; 1019e3adcf8fSFrançois Tigeot 1020e3adcf8fSFrançois Tigeot if (property == dev_priv->force_audio_property) { 1021e3adcf8fSFrançois Tigeot enum hdmi_force_audio i = val; 1022e3adcf8fSFrançois Tigeot bool has_audio; 1023e3adcf8fSFrançois Tigeot 1024e3adcf8fSFrançois Tigeot if (i == intel_hdmi->force_audio) 1025e3adcf8fSFrançois Tigeot return 0; 1026e3adcf8fSFrançois Tigeot 1027e3adcf8fSFrançois Tigeot intel_hdmi->force_audio = i; 1028e3adcf8fSFrançois Tigeot 1029e3adcf8fSFrançois Tigeot if (i == HDMI_AUDIO_AUTO) 1030e3adcf8fSFrançois Tigeot has_audio = intel_hdmi_detect_audio(connector); 1031e3adcf8fSFrançois Tigeot else 1032e3adcf8fSFrançois Tigeot has_audio = (i == HDMI_AUDIO_ON); 1033e3adcf8fSFrançois Tigeot 1034e3adcf8fSFrançois Tigeot if (i == HDMI_AUDIO_OFF_DVI) 1035e3adcf8fSFrançois Tigeot intel_hdmi->has_hdmi_sink = 0; 1036e3adcf8fSFrançois Tigeot 1037e3adcf8fSFrançois Tigeot intel_hdmi->has_audio = has_audio; 1038e3adcf8fSFrançois Tigeot goto done; 1039e3adcf8fSFrançois Tigeot } 1040e3adcf8fSFrançois Tigeot 1041e3adcf8fSFrançois Tigeot if (property == dev_priv->broadcast_rgb_property) { 10428e26cdf6SFrançois Tigeot bool old_auto = intel_hdmi->color_range_auto; 10438e26cdf6SFrançois Tigeot uint32_t old_range = intel_hdmi->color_range; 10448e26cdf6SFrançois Tigeot 1045a2fdbec6SFrançois Tigeot switch (val) { 1046a2fdbec6SFrançois Tigeot case INTEL_BROADCAST_RGB_AUTO: 1047a2fdbec6SFrançois Tigeot intel_hdmi->color_range_auto = true; 1048a2fdbec6SFrançois Tigeot break; 1049a2fdbec6SFrançois Tigeot case INTEL_BROADCAST_RGB_FULL: 1050a2fdbec6SFrançois Tigeot intel_hdmi->color_range_auto = false; 1051a2fdbec6SFrançois Tigeot intel_hdmi->color_range = 0; 1052a2fdbec6SFrançois Tigeot break; 1053a2fdbec6SFrançois Tigeot case INTEL_BROADCAST_RGB_LIMITED: 1054a2fdbec6SFrançois Tigeot intel_hdmi->color_range_auto = false; 10558e26cdf6SFrançois Tigeot intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235; 1056a2fdbec6SFrançois Tigeot break; 1057a2fdbec6SFrançois Tigeot default: 1058a2fdbec6SFrançois Tigeot return -EINVAL; 1059a2fdbec6SFrançois Tigeot } 10608e26cdf6SFrançois Tigeot 10618e26cdf6SFrançois Tigeot if (old_auto == intel_hdmi->color_range_auto && 10628e26cdf6SFrançois Tigeot old_range == intel_hdmi->color_range) 10638e26cdf6SFrançois Tigeot return 0; 10648e26cdf6SFrançois Tigeot 1065e3adcf8fSFrançois Tigeot goto done; 1066e3adcf8fSFrançois Tigeot } 1067e3adcf8fSFrançois Tigeot 1068e3adcf8fSFrançois Tigeot return -EINVAL; 1069e3adcf8fSFrançois Tigeot 1070e3adcf8fSFrançois Tigeot done: 1071a2fdbec6SFrançois Tigeot if (intel_dig_port->base.base.crtc) 1072a2fdbec6SFrançois Tigeot intel_crtc_restore_mode(intel_dig_port->base.base.crtc); 1073e3adcf8fSFrançois Tigeot 1074e3adcf8fSFrançois Tigeot return 0; 1075e3adcf8fSFrançois Tigeot } 1076e3adcf8fSFrançois Tigeot 1077*9edbd4a0SFrançois Tigeot static void vlv_hdmi_pre_enable(struct intel_encoder *encoder) 10785d0b1887SFrançois Tigeot { 10795d0b1887SFrançois Tigeot struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); 10805d0b1887SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 10815d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 10825d0b1887SFrançois Tigeot struct intel_crtc *intel_crtc = 10835d0b1887SFrançois Tigeot to_intel_crtc(encoder->base.crtc); 1084*9edbd4a0SFrançois Tigeot enum dpio_channel port = vlv_dport_to_channel(dport); 10855d0b1887SFrançois Tigeot int pipe = intel_crtc->pipe; 10865d0b1887SFrançois Tigeot u32 val; 10875d0b1887SFrançois Tigeot 10885d0b1887SFrançois Tigeot if (!IS_VALLEYVIEW(dev)) 10895d0b1887SFrançois Tigeot return; 10905d0b1887SFrançois Tigeot 10915d0b1887SFrançois Tigeot /* Enable clock channels for this port */ 1092*9edbd4a0SFrançois Tigeot mutex_lock(&dev_priv->dpio_lock); 1093*9edbd4a0SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(port)); 10945d0b1887SFrançois Tigeot val = 0; 10955d0b1887SFrançois Tigeot if (pipe) 10965d0b1887SFrançois Tigeot val |= (1<<21); 10975d0b1887SFrançois Tigeot else 10985d0b1887SFrançois Tigeot val &= ~(1<<21); 10995d0b1887SFrançois Tigeot val |= 0x001000c4; 1100*9edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW8(port), val); 11015d0b1887SFrançois Tigeot 11025d0b1887SFrançois Tigeot /* HDMI 1.0V-2dB */ 1103*9edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), 0); 1104*9edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW4(port), 0x2b245f5f); 1105*9edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW2(port), 0x5578b83a); 1106*9edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW3(port), 0x0c782040); 1107*9edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX3_DW4(port), 0x2b247878); 1108*9edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW11(port), 0x00030000); 1109*9edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW9(port), 0x00002000); 1110*9edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), DPIO_TX_OCALINIT_EN); 11115d0b1887SFrançois Tigeot 11125d0b1887SFrançois Tigeot /* Program lane clock */ 1113*9edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW14(port), 0x00760018); 1114*9edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW23(port), 0x00400888); 1115*9edbd4a0SFrançois Tigeot mutex_unlock(&dev_priv->dpio_lock); 1116*9edbd4a0SFrançois Tigeot 1117*9edbd4a0SFrançois Tigeot intel_enable_hdmi(encoder); 1118*9edbd4a0SFrançois Tigeot 1119*9edbd4a0SFrançois Tigeot vlv_wait_port_ready(dev_priv, dport); 11205d0b1887SFrançois Tigeot } 11215d0b1887SFrançois Tigeot 1122*9edbd4a0SFrançois Tigeot static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder) 11235d0b1887SFrançois Tigeot { 11245d0b1887SFrançois Tigeot struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); 11255d0b1887SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 11265d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1127*9edbd4a0SFrançois Tigeot struct intel_crtc *intel_crtc = 1128*9edbd4a0SFrançois Tigeot to_intel_crtc(encoder->base.crtc); 1129*9edbd4a0SFrançois Tigeot enum dpio_channel port = vlv_dport_to_channel(dport); 1130*9edbd4a0SFrançois Tigeot int pipe = intel_crtc->pipe; 11315d0b1887SFrançois Tigeot 11325d0b1887SFrançois Tigeot if (!IS_VALLEYVIEW(dev)) 11335d0b1887SFrançois Tigeot return; 11345d0b1887SFrançois Tigeot 11355d0b1887SFrançois Tigeot /* Program Tx lane resets to default */ 1136*9edbd4a0SFrançois Tigeot mutex_lock(&dev_priv->dpio_lock); 1137*9edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), 11385d0b1887SFrançois Tigeot DPIO_PCS_TX_LANE2_RESET | 11395d0b1887SFrançois Tigeot DPIO_PCS_TX_LANE1_RESET); 1140*9edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), 11415d0b1887SFrançois Tigeot DPIO_PCS_CLK_CRI_RXEB_EIOS_EN | 11425d0b1887SFrançois Tigeot DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN | 11435d0b1887SFrançois Tigeot (1<<DPIO_PCS_CLK_DATAWIDTH_SHIFT) | 11445d0b1887SFrançois Tigeot DPIO_PCS_CLK_SOFT_RESET); 11455d0b1887SFrançois Tigeot 11465d0b1887SFrançois Tigeot /* Fix up inter-pair skew failure */ 1147*9edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW12(port), 0x00750f00); 1148*9edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW11(port), 0x00001500); 1149*9edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW14(port), 0x40400000); 11505d0b1887SFrançois Tigeot 1151*9edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW9(port), 0x00002000); 1152*9edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), DPIO_TX_OCALINIT_EN); 1153*9edbd4a0SFrançois Tigeot mutex_unlock(&dev_priv->dpio_lock); 11545d0b1887SFrançois Tigeot } 11555d0b1887SFrançois Tigeot 1156*9edbd4a0SFrançois Tigeot static void vlv_hdmi_post_disable(struct intel_encoder *encoder) 11575d0b1887SFrançois Tigeot { 11585d0b1887SFrançois Tigeot struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); 11595d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; 1160*9edbd4a0SFrançois Tigeot struct intel_crtc *intel_crtc = 1161*9edbd4a0SFrançois Tigeot to_intel_crtc(encoder->base.crtc); 1162*9edbd4a0SFrançois Tigeot enum dpio_channel port = vlv_dport_to_channel(dport); 1163*9edbd4a0SFrançois Tigeot int pipe = intel_crtc->pipe; 11645d0b1887SFrançois Tigeot 11655d0b1887SFrançois Tigeot /* Reset lanes to avoid HDMI flicker (VLV w/a) */ 11665d0b1887SFrançois Tigeot mutex_lock(&dev_priv->dpio_lock); 1167*9edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), 0x00000000); 1168*9edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), 0x00e00060); 11695d0b1887SFrançois Tigeot mutex_unlock(&dev_priv->dpio_lock); 11705d0b1887SFrançois Tigeot } 11715d0b1887SFrançois Tigeot 1172e3adcf8fSFrançois Tigeot static void intel_hdmi_destroy(struct drm_connector *connector) 1173e3adcf8fSFrançois Tigeot { 1174e3adcf8fSFrançois Tigeot drm_connector_cleanup(connector); 11758e26cdf6SFrançois Tigeot kfree(connector); 1176e3adcf8fSFrançois Tigeot } 1177e3adcf8fSFrançois Tigeot 1178e3adcf8fSFrançois Tigeot static const struct drm_connector_funcs intel_hdmi_connector_funcs = { 117919df918dSFrançois Tigeot .dpms = intel_connector_dpms, 1180e3adcf8fSFrançois Tigeot .detect = intel_hdmi_detect, 1181e3adcf8fSFrançois Tigeot .fill_modes = drm_helper_probe_single_connector_modes, 1182e3adcf8fSFrançois Tigeot .set_property = intel_hdmi_set_property, 1183e3adcf8fSFrançois Tigeot .destroy = intel_hdmi_destroy, 1184e3adcf8fSFrançois Tigeot }; 1185e3adcf8fSFrançois Tigeot 1186e3adcf8fSFrançois Tigeot static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = { 1187e3adcf8fSFrançois Tigeot .get_modes = intel_hdmi_get_modes, 1188e3adcf8fSFrançois Tigeot .mode_valid = intel_hdmi_mode_valid, 1189e3adcf8fSFrançois Tigeot .best_encoder = intel_best_encoder, 1190e3adcf8fSFrançois Tigeot }; 1191e3adcf8fSFrançois Tigeot 1192e3adcf8fSFrançois Tigeot static const struct drm_encoder_funcs intel_hdmi_enc_funcs = { 1193e3adcf8fSFrançois Tigeot .destroy = intel_encoder_destroy, 1194e3adcf8fSFrançois Tigeot }; 1195e3adcf8fSFrançois Tigeot 1196e3adcf8fSFrançois Tigeot static void 1197e3adcf8fSFrançois Tigeot intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector) 1198e3adcf8fSFrançois Tigeot { 1199e3adcf8fSFrançois Tigeot intel_attach_force_audio_property(connector); 1200e3adcf8fSFrançois Tigeot intel_attach_broadcast_rgb_property(connector); 1201a2fdbec6SFrançois Tigeot intel_hdmi->color_range_auto = true; 1202e3adcf8fSFrançois Tigeot } 1203e3adcf8fSFrançois Tigeot 120419df918dSFrançois Tigeot void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, 120519df918dSFrançois Tigeot struct intel_connector *intel_connector) 1206e3adcf8fSFrançois Tigeot { 120719df918dSFrançois Tigeot struct drm_connector *connector = &intel_connector->base; 120819df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; 120919df918dSFrançois Tigeot struct intel_encoder *intel_encoder = &intel_dig_port->base; 121019df918dSFrançois Tigeot struct drm_device *dev = intel_encoder->base.dev; 1211e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 121219df918dSFrançois Tigeot enum port port = intel_dig_port->port; 1213e3adcf8fSFrançois Tigeot 1214e3adcf8fSFrançois Tigeot drm_connector_init(dev, connector, &intel_hdmi_connector_funcs, 1215e3adcf8fSFrançois Tigeot DRM_MODE_CONNECTOR_HDMIA); 1216e3adcf8fSFrançois Tigeot drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs); 1217e3adcf8fSFrançois Tigeot 1218e3adcf8fSFrançois Tigeot connector->interlace_allowed = 1; 1219e3adcf8fSFrançois Tigeot connector->doublescan_allowed = 0; 1220*9edbd4a0SFrançois Tigeot connector->stereo_allowed = 1; 1221e3adcf8fSFrançois Tigeot 122219df918dSFrançois Tigeot switch (port) { 122319df918dSFrançois Tigeot case PORT_B: 1224e3adcf8fSFrançois Tigeot intel_hdmi->ddc_bus = GMBUS_PORT_DPB; 12258e26cdf6SFrançois Tigeot intel_encoder->hpd_pin = HPD_PORT_B; 122619df918dSFrançois Tigeot break; 122719df918dSFrançois Tigeot case PORT_C: 1228e3adcf8fSFrançois Tigeot intel_hdmi->ddc_bus = GMBUS_PORT_DPC; 12298e26cdf6SFrançois Tigeot intel_encoder->hpd_pin = HPD_PORT_C; 123019df918dSFrançois Tigeot break; 123119df918dSFrançois Tigeot case PORT_D: 1232e3adcf8fSFrançois Tigeot intel_hdmi->ddc_bus = GMBUS_PORT_DPD; 12338e26cdf6SFrançois Tigeot intel_encoder->hpd_pin = HPD_PORT_D; 123419df918dSFrançois Tigeot break; 123519df918dSFrançois Tigeot case PORT_A: 12368e26cdf6SFrançois Tigeot intel_encoder->hpd_pin = HPD_PORT_A; 123719df918dSFrançois Tigeot /* Internal port only for eDP. */ 123819df918dSFrançois Tigeot default: 123919df918dSFrançois Tigeot BUG(); 1240e3adcf8fSFrançois Tigeot } 1241e3adcf8fSFrançois Tigeot 12428e26cdf6SFrançois Tigeot if (IS_VALLEYVIEW(dev)) { 124319df918dSFrançois Tigeot intel_hdmi->write_infoframe = vlv_write_infoframe; 124419df918dSFrançois Tigeot intel_hdmi->set_infoframes = vlv_set_infoframes; 12458e26cdf6SFrançois Tigeot } else if (!HAS_PCH_SPLIT(dev)) { 12468e26cdf6SFrançois Tigeot intel_hdmi->write_infoframe = g4x_write_infoframe; 12478e26cdf6SFrançois Tigeot intel_hdmi->set_infoframes = g4x_set_infoframes; 12488e26cdf6SFrançois Tigeot } else if (HAS_DDI(dev)) { 124919df918dSFrançois Tigeot intel_hdmi->write_infoframe = hsw_write_infoframe; 125019df918dSFrançois Tigeot intel_hdmi->set_infoframes = hsw_set_infoframes; 125119df918dSFrançois Tigeot } else if (HAS_PCH_IBX(dev)) { 125219df918dSFrançois Tigeot intel_hdmi->write_infoframe = ibx_write_infoframe; 125319df918dSFrançois Tigeot intel_hdmi->set_infoframes = ibx_set_infoframes; 1254e3adcf8fSFrançois Tigeot } else { 125519df918dSFrançois Tigeot intel_hdmi->write_infoframe = cpt_write_infoframe; 125619df918dSFrançois Tigeot intel_hdmi->set_infoframes = cpt_set_infoframes; 1257e3adcf8fSFrançois Tigeot } 1258e3adcf8fSFrançois Tigeot 1259a2fdbec6SFrançois Tigeot if (HAS_DDI(dev)) 126019df918dSFrançois Tigeot intel_connector->get_hw_state = intel_ddi_connector_get_hw_state; 126119df918dSFrançois Tigeot else 126219df918dSFrançois Tigeot intel_connector->get_hw_state = intel_connector_get_hw_state; 1263e3adcf8fSFrançois Tigeot 1264e3adcf8fSFrançois Tigeot intel_hdmi_add_properties(intel_hdmi, connector); 1265e3adcf8fSFrançois Tigeot 1266e3adcf8fSFrançois Tigeot intel_connector_attach_encoder(intel_connector, intel_encoder); 1267e3adcf8fSFrançois Tigeot drm_sysfs_connector_add(connector); 1268e3adcf8fSFrançois Tigeot 1269e3adcf8fSFrançois Tigeot /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written 1270e3adcf8fSFrançois Tigeot * 0xd. Failure to do so will result in spurious interrupts being 1271e3adcf8fSFrançois Tigeot * generated on the port when a cable is not attached. 1272e3adcf8fSFrançois Tigeot */ 1273e3adcf8fSFrançois Tigeot if (IS_G4X(dev) && !IS_GM45(dev)) { 1274e3adcf8fSFrançois Tigeot u32 temp = I915_READ(PEG_BAND_GAP_DATA); 1275e3adcf8fSFrançois Tigeot I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); 1276e3adcf8fSFrançois Tigeot } 1277e3adcf8fSFrançois Tigeot } 127819df918dSFrançois Tigeot 12798e26cdf6SFrançois Tigeot void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) 128019df918dSFrançois Tigeot { 128119df918dSFrançois Tigeot struct intel_digital_port *intel_dig_port; 128219df918dSFrançois Tigeot struct intel_encoder *intel_encoder; 128319df918dSFrançois Tigeot struct intel_connector *intel_connector; 128419df918dSFrançois Tigeot 1285*9edbd4a0SFrançois Tigeot intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL); 128619df918dSFrançois Tigeot if (!intel_dig_port) 128719df918dSFrançois Tigeot return; 128819df918dSFrançois Tigeot 1289*9edbd4a0SFrançois Tigeot intel_connector = kzalloc(sizeof(*intel_connector), GFP_KERNEL); 129019df918dSFrançois Tigeot if (!intel_connector) { 1291158486a6SFrançois Tigeot kfree(intel_dig_port); 129219df918dSFrançois Tigeot return; 129319df918dSFrançois Tigeot } 129419df918dSFrançois Tigeot 129519df918dSFrançois Tigeot intel_encoder = &intel_dig_port->base; 129619df918dSFrançois Tigeot 129719df918dSFrançois Tigeot drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs, 129819df918dSFrançois Tigeot DRM_MODE_ENCODER_TMDS); 129919df918dSFrançois Tigeot 13008e26cdf6SFrançois Tigeot intel_encoder->compute_config = intel_hdmi_compute_config; 1301*9edbd4a0SFrançois Tigeot intel_encoder->mode_set = intel_hdmi_mode_set; 130219df918dSFrançois Tigeot intel_encoder->disable = intel_disable_hdmi; 130319df918dSFrançois Tigeot intel_encoder->get_hw_state = intel_hdmi_get_hw_state; 13045d0b1887SFrançois Tigeot intel_encoder->get_config = intel_hdmi_get_config; 13055d0b1887SFrançois Tigeot if (IS_VALLEYVIEW(dev)) { 1306*9edbd4a0SFrançois Tigeot intel_encoder->pre_pll_enable = vlv_hdmi_pre_pll_enable; 1307*9edbd4a0SFrançois Tigeot intel_encoder->pre_enable = vlv_hdmi_pre_enable; 1308*9edbd4a0SFrançois Tigeot intel_encoder->enable = vlv_enable_hdmi; 1309*9edbd4a0SFrançois Tigeot intel_encoder->post_disable = vlv_hdmi_post_disable; 1310*9edbd4a0SFrançois Tigeot } else { 1311*9edbd4a0SFrançois Tigeot intel_encoder->enable = intel_enable_hdmi; 13125d0b1887SFrançois Tigeot } 131319df918dSFrançois Tigeot 131419df918dSFrançois Tigeot intel_encoder->type = INTEL_OUTPUT_HDMI; 131519df918dSFrançois Tigeot intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); 131619df918dSFrançois Tigeot intel_encoder->cloneable = false; 131719df918dSFrançois Tigeot 131819df918dSFrançois Tigeot intel_dig_port->port = port; 13198e26cdf6SFrançois Tigeot intel_dig_port->hdmi.hdmi_reg = hdmi_reg; 132019df918dSFrançois Tigeot intel_dig_port->dp.output_reg = 0; 132119df918dSFrançois Tigeot 132219df918dSFrançois Tigeot intel_hdmi_init_connector(intel_dig_port, intel_connector); 132319df918dSFrançois Tigeot } 1324