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> 319edbd4a0SFrançois Tigeot #include <linux/hdmi.h> 3218e26a6dSFrançois Tigeot #include <drm/drmP.h> 332c9916cdSFrançois Tigeot #include <drm/drm_atomic_helper.h> 3418e26a6dSFrançois Tigeot #include <drm/drm_crtc.h> 3518e26a6dSFrançois Tigeot #include <drm/drm_edid.h> 3618e26a6dSFrançois Tigeot #include "intel_drv.h" 375c6c6f23SFrançois Tigeot #include <drm/i915_drm.h> 38e3adcf8fSFrançois Tigeot #include "i915_drv.h" 39e3adcf8fSFrançois Tigeot 4019df918dSFrançois Tigeot static struct drm_device *intel_hdmi_to_dev(struct intel_hdmi *intel_hdmi) 41e3adcf8fSFrançois Tigeot { 4219df918dSFrançois Tigeot return hdmi_to_dig_port(intel_hdmi)->base.base.dev; 4319df918dSFrançois Tigeot } 4419df918dSFrançois Tigeot 4519df918dSFrançois Tigeot static void 4619df918dSFrançois Tigeot assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi) 4719df918dSFrançois Tigeot { 4819df918dSFrançois Tigeot struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi); 4919df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 5019df918dSFrançois Tigeot uint32_t enabled_bits; 5119df918dSFrançois Tigeot 52a2fdbec6SFrançois Tigeot enabled_bits = HAS_DDI(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE; 5319df918dSFrançois Tigeot 548e26cdf6SFrançois Tigeot WARN(I915_READ(intel_hdmi->hdmi_reg) & enabled_bits, 5519df918dSFrançois Tigeot "HDMI port enabled, expecting disabled\n"); 5619df918dSFrançois Tigeot } 5719df918dSFrançois Tigeot 5819df918dSFrançois Tigeot struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) 5919df918dSFrançois Tigeot { 6019df918dSFrançois Tigeot struct intel_digital_port *intel_dig_port = 6119df918dSFrançois Tigeot container_of(encoder, struct intel_digital_port, base.base); 6219df918dSFrançois Tigeot return &intel_dig_port->hdmi; 63e3adcf8fSFrançois Tigeot } 64e3adcf8fSFrançois Tigeot 65e3adcf8fSFrançois Tigeot static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector) 66e3adcf8fSFrançois Tigeot { 6719df918dSFrançois Tigeot return enc_to_intel_hdmi(&intel_attached_encoder(connector)->base); 68e3adcf8fSFrançois Tigeot } 69e3adcf8fSFrançois Tigeot 709edbd4a0SFrançois Tigeot static u32 g4x_infoframe_index(enum hdmi_infoframe_type type) 71e3adcf8fSFrançois Tigeot { 729edbd4a0SFrançois Tigeot switch (type) { 739edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_AVI: 7419df918dSFrançois Tigeot return VIDEO_DIP_SELECT_AVI; 759edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_SPD: 7619df918dSFrançois Tigeot return VIDEO_DIP_SELECT_SPD; 779edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_VENDOR: 789edbd4a0SFrançois Tigeot return VIDEO_DIP_SELECT_VENDOR; 79e3adcf8fSFrançois Tigeot default: 809edbd4a0SFrançois Tigeot DRM_DEBUG_DRIVER("unknown info frame type %d\n", type); 8119df918dSFrançois Tigeot return 0; 8219df918dSFrançois Tigeot } 83e3adcf8fSFrançois Tigeot } 84e3adcf8fSFrançois Tigeot 859edbd4a0SFrançois Tigeot static u32 g4x_infoframe_enable(enum hdmi_infoframe_type type) 86e3adcf8fSFrançois Tigeot { 879edbd4a0SFrançois Tigeot switch (type) { 889edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_AVI: 8919df918dSFrançois Tigeot return VIDEO_DIP_ENABLE_AVI; 909edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_SPD: 9119df918dSFrançois Tigeot return VIDEO_DIP_ENABLE_SPD; 929edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_VENDOR: 939edbd4a0SFrançois Tigeot return VIDEO_DIP_ENABLE_VENDOR; 94e3adcf8fSFrançois Tigeot default: 959edbd4a0SFrançois Tigeot DRM_DEBUG_DRIVER("unknown info frame type %d\n", type); 9619df918dSFrançois Tigeot return 0; 9719df918dSFrançois Tigeot } 98e3adcf8fSFrançois Tigeot } 99e3adcf8fSFrançois Tigeot 1009edbd4a0SFrançois Tigeot static u32 hsw_infoframe_enable(enum hdmi_infoframe_type type) 10119df918dSFrançois Tigeot { 1029edbd4a0SFrançois Tigeot switch (type) { 1039edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_AVI: 10419df918dSFrançois Tigeot return VIDEO_DIP_ENABLE_AVI_HSW; 1059edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_SPD: 10619df918dSFrançois Tigeot return VIDEO_DIP_ENABLE_SPD_HSW; 1079edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_VENDOR: 1089edbd4a0SFrançois Tigeot return VIDEO_DIP_ENABLE_VS_HSW; 10919df918dSFrançois Tigeot default: 1109edbd4a0SFrançois Tigeot DRM_DEBUG_DRIVER("unknown info frame type %d\n", type); 11119df918dSFrançois Tigeot return 0; 11219df918dSFrançois Tigeot } 113e3adcf8fSFrançois Tigeot } 114e3adcf8fSFrançois Tigeot 1159edbd4a0SFrançois Tigeot static u32 hsw_infoframe_data_reg(enum hdmi_infoframe_type type, 116ba55f2f5SFrançois Tigeot enum transcoder cpu_transcoder, 117ba55f2f5SFrançois Tigeot struct drm_i915_private *dev_priv) 11819df918dSFrançois Tigeot { 1199edbd4a0SFrançois Tigeot switch (type) { 1209edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_AVI: 1218e26cdf6SFrançois Tigeot return HSW_TVIDEO_DIP_AVI_DATA(cpu_transcoder); 1229edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_SPD: 1238e26cdf6SFrançois Tigeot return HSW_TVIDEO_DIP_SPD_DATA(cpu_transcoder); 1249edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_VENDOR: 1259edbd4a0SFrançois Tigeot return HSW_TVIDEO_DIP_VS_DATA(cpu_transcoder); 12619df918dSFrançois Tigeot default: 1279edbd4a0SFrançois Tigeot DRM_DEBUG_DRIVER("unknown info frame type %d\n", type); 12819df918dSFrançois Tigeot return 0; 12919df918dSFrançois Tigeot } 13019df918dSFrançois Tigeot } 13119df918dSFrançois Tigeot 13219df918dSFrançois Tigeot static void g4x_write_infoframe(struct drm_encoder *encoder, 1339edbd4a0SFrançois Tigeot enum hdmi_infoframe_type type, 1349edbd4a0SFrançois Tigeot const void *frame, ssize_t len) 135e3adcf8fSFrançois Tigeot { 1369edbd4a0SFrançois Tigeot const uint32_t *data = frame; 137e3adcf8fSFrançois Tigeot struct drm_device *dev = encoder->dev; 138e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 13919df918dSFrançois Tigeot u32 val = I915_READ(VIDEO_DIP_CTL); 1409edbd4a0SFrançois Tigeot int i; 141e3adcf8fSFrançois Tigeot 14219df918dSFrançois Tigeot WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n"); 143e3adcf8fSFrançois Tigeot 14419df918dSFrançois Tigeot val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ 1459edbd4a0SFrançois Tigeot val |= g4x_infoframe_index(type); 146e3adcf8fSFrançois Tigeot 1479edbd4a0SFrançois Tigeot val &= ~g4x_infoframe_enable(type); 148e3adcf8fSFrançois Tigeot 14919df918dSFrançois Tigeot I915_WRITE(VIDEO_DIP_CTL, val); 150e3adcf8fSFrançois Tigeot 15119df918dSFrançois Tigeot mmiowb(); 152e3adcf8fSFrançois Tigeot for (i = 0; i < len; i += 4) { 153e3adcf8fSFrançois Tigeot I915_WRITE(VIDEO_DIP_DATA, *data); 154e3adcf8fSFrançois Tigeot data++; 155e3adcf8fSFrançois Tigeot } 15619df918dSFrançois Tigeot /* Write every possible data byte to force correct ECC calculation. */ 15719df918dSFrançois Tigeot for (; i < VIDEO_DIP_DATA_SIZE; i += 4) 15819df918dSFrançois Tigeot I915_WRITE(VIDEO_DIP_DATA, 0); 15919df918dSFrançois Tigeot mmiowb(); 160e3adcf8fSFrançois Tigeot 1619edbd4a0SFrançois Tigeot val |= g4x_infoframe_enable(type); 16219df918dSFrançois Tigeot val &= ~VIDEO_DIP_FREQ_MASK; 16319df918dSFrançois Tigeot val |= VIDEO_DIP_FREQ_VSYNC; 164e3adcf8fSFrançois Tigeot 16519df918dSFrançois Tigeot I915_WRITE(VIDEO_DIP_CTL, val); 16619df918dSFrançois Tigeot POSTING_READ(VIDEO_DIP_CTL); 167e3adcf8fSFrançois Tigeot } 168e3adcf8fSFrançois Tigeot 1692c9916cdSFrançois Tigeot static bool g4x_infoframe_enabled(struct drm_encoder *encoder) 1702c9916cdSFrançois Tigeot { 1712c9916cdSFrançois Tigeot struct drm_device *dev = encoder->dev; 1722c9916cdSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1732c9916cdSFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); 1742c9916cdSFrançois Tigeot u32 val = I915_READ(VIDEO_DIP_CTL); 1752c9916cdSFrançois Tigeot 176*a05eeebfSFrançois Tigeot if ((val & VIDEO_DIP_ENABLE) == 0) 1772c9916cdSFrançois Tigeot return false; 178*a05eeebfSFrançois Tigeot 179*a05eeebfSFrançois Tigeot if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->port)) 180*a05eeebfSFrançois Tigeot return false; 181*a05eeebfSFrançois Tigeot 182*a05eeebfSFrançois Tigeot return val & (VIDEO_DIP_ENABLE_AVI | 183*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD); 1842c9916cdSFrançois Tigeot } 1852c9916cdSFrançois Tigeot 18619df918dSFrançois Tigeot static void ibx_write_infoframe(struct drm_encoder *encoder, 1879edbd4a0SFrançois Tigeot enum hdmi_infoframe_type type, 1889edbd4a0SFrançois Tigeot const void *frame, ssize_t len) 189e3adcf8fSFrançois Tigeot { 1909edbd4a0SFrançois Tigeot const uint32_t *data = frame; 191e3adcf8fSFrançois Tigeot struct drm_device *dev = encoder->dev; 192e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 19319df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 1949edbd4a0SFrançois Tigeot int i, reg = TVIDEO_DIP_CTL(intel_crtc->pipe); 19519df918dSFrançois Tigeot u32 val = I915_READ(reg); 196e3adcf8fSFrançois Tigeot 19719df918dSFrançois Tigeot WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n"); 198e3adcf8fSFrançois Tigeot 199e3adcf8fSFrançois Tigeot val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ 2009edbd4a0SFrançois Tigeot val |= g4x_infoframe_index(type); 201e3adcf8fSFrançois Tigeot 2029edbd4a0SFrançois Tigeot val &= ~g4x_infoframe_enable(type); 203e3adcf8fSFrançois Tigeot 20419df918dSFrançois Tigeot I915_WRITE(reg, val); 20519df918dSFrançois Tigeot 20619df918dSFrançois Tigeot mmiowb(); 207e3adcf8fSFrançois Tigeot for (i = 0; i < len; i += 4) { 208e3adcf8fSFrançois Tigeot I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); 209e3adcf8fSFrançois Tigeot data++; 210e3adcf8fSFrançois Tigeot } 21119df918dSFrançois Tigeot /* Write every possible data byte to force correct ECC calculation. */ 21219df918dSFrançois Tigeot for (; i < VIDEO_DIP_DATA_SIZE; i += 4) 21319df918dSFrançois Tigeot I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0); 21419df918dSFrançois Tigeot mmiowb(); 215e3adcf8fSFrançois Tigeot 2169edbd4a0SFrançois Tigeot val |= g4x_infoframe_enable(type); 21719df918dSFrançois Tigeot val &= ~VIDEO_DIP_FREQ_MASK; 21819df918dSFrançois Tigeot val |= VIDEO_DIP_FREQ_VSYNC; 219e3adcf8fSFrançois Tigeot 22019df918dSFrançois Tigeot I915_WRITE(reg, val); 22119df918dSFrançois Tigeot POSTING_READ(reg); 22219df918dSFrançois Tigeot } 22319df918dSFrançois Tigeot 2242c9916cdSFrançois Tigeot static bool ibx_infoframe_enabled(struct drm_encoder *encoder) 2252c9916cdSFrançois Tigeot { 2262c9916cdSFrançois Tigeot struct drm_device *dev = encoder->dev; 2272c9916cdSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 2282c9916cdSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 22919c468b4SFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); 2302c9916cdSFrançois Tigeot int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); 2312c9916cdSFrançois Tigeot u32 val = I915_READ(reg); 2322c9916cdSFrançois Tigeot 233*a05eeebfSFrançois Tigeot if ((val & VIDEO_DIP_ENABLE) == 0) 23419c468b4SFrançois Tigeot return false; 235*a05eeebfSFrançois Tigeot 236*a05eeebfSFrançois Tigeot if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->port)) 237*a05eeebfSFrançois Tigeot return false; 238*a05eeebfSFrançois Tigeot 239*a05eeebfSFrançois Tigeot return val & (VIDEO_DIP_ENABLE_AVI | 240*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | 241*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); 2422c9916cdSFrançois Tigeot } 2432c9916cdSFrançois Tigeot 24419df918dSFrançois Tigeot static void cpt_write_infoframe(struct drm_encoder *encoder, 2459edbd4a0SFrançois Tigeot enum hdmi_infoframe_type type, 2469edbd4a0SFrançois Tigeot const void *frame, ssize_t len) 24719df918dSFrançois Tigeot { 2489edbd4a0SFrançois Tigeot const uint32_t *data = frame; 24919df918dSFrançois Tigeot struct drm_device *dev = encoder->dev; 25019df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 25119df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 2529edbd4a0SFrançois Tigeot int i, reg = TVIDEO_DIP_CTL(intel_crtc->pipe); 25319df918dSFrançois Tigeot u32 val = I915_READ(reg); 25419df918dSFrançois Tigeot 25519df918dSFrançois Tigeot WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n"); 25619df918dSFrançois Tigeot 25719df918dSFrançois Tigeot val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ 2589edbd4a0SFrançois Tigeot val |= g4x_infoframe_index(type); 25919df918dSFrançois Tigeot 26019df918dSFrançois Tigeot /* The DIP control register spec says that we need to update the AVI 26119df918dSFrançois Tigeot * infoframe without clearing its enable bit */ 2629edbd4a0SFrançois Tigeot if (type != HDMI_INFOFRAME_TYPE_AVI) 2639edbd4a0SFrançois Tigeot val &= ~g4x_infoframe_enable(type); 26419df918dSFrançois Tigeot 26519df918dSFrançois Tigeot I915_WRITE(reg, val); 26619df918dSFrançois Tigeot 26719df918dSFrançois Tigeot mmiowb(); 26819df918dSFrançois Tigeot for (i = 0; i < len; i += 4) { 26919df918dSFrançois Tigeot I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); 27019df918dSFrançois Tigeot data++; 27119df918dSFrançois Tigeot } 27219df918dSFrançois Tigeot /* Write every possible data byte to force correct ECC calculation. */ 27319df918dSFrançois Tigeot for (; i < VIDEO_DIP_DATA_SIZE; i += 4) 27419df918dSFrançois Tigeot I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0); 27519df918dSFrançois Tigeot mmiowb(); 27619df918dSFrançois Tigeot 2779edbd4a0SFrançois Tigeot val |= g4x_infoframe_enable(type); 27819df918dSFrançois Tigeot val &= ~VIDEO_DIP_FREQ_MASK; 27919df918dSFrançois Tigeot val |= VIDEO_DIP_FREQ_VSYNC; 28019df918dSFrançois Tigeot 28119df918dSFrançois Tigeot I915_WRITE(reg, val); 28219df918dSFrançois Tigeot POSTING_READ(reg); 28319df918dSFrançois Tigeot } 28419df918dSFrançois Tigeot 2852c9916cdSFrançois Tigeot static bool cpt_infoframe_enabled(struct drm_encoder *encoder) 2862c9916cdSFrançois Tigeot { 2872c9916cdSFrançois Tigeot struct drm_device *dev = encoder->dev; 2882c9916cdSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 2892c9916cdSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 2902c9916cdSFrançois Tigeot int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); 2912c9916cdSFrançois Tigeot u32 val = I915_READ(reg); 2922c9916cdSFrançois Tigeot 293*a05eeebfSFrançois Tigeot if ((val & VIDEO_DIP_ENABLE) == 0) 294*a05eeebfSFrançois Tigeot return false; 295*a05eeebfSFrançois Tigeot 296*a05eeebfSFrançois Tigeot return val & (VIDEO_DIP_ENABLE_AVI | 297*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | 298*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); 2992c9916cdSFrançois Tigeot } 3002c9916cdSFrançois Tigeot 30119df918dSFrançois Tigeot static void vlv_write_infoframe(struct drm_encoder *encoder, 3029edbd4a0SFrançois Tigeot enum hdmi_infoframe_type type, 3039edbd4a0SFrançois Tigeot const void *frame, ssize_t len) 30419df918dSFrançois Tigeot { 3059edbd4a0SFrançois Tigeot const uint32_t *data = frame; 30619df918dSFrançois Tigeot struct drm_device *dev = encoder->dev; 30719df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 30819df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 3099edbd4a0SFrançois Tigeot int i, reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); 31019df918dSFrançois Tigeot u32 val = I915_READ(reg); 31119df918dSFrançois Tigeot 31219df918dSFrançois Tigeot WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n"); 31319df918dSFrançois Tigeot 31419df918dSFrançois Tigeot val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ 3159edbd4a0SFrançois Tigeot val |= g4x_infoframe_index(type); 31619df918dSFrançois Tigeot 3179edbd4a0SFrançois Tigeot val &= ~g4x_infoframe_enable(type); 31819df918dSFrançois Tigeot 31919df918dSFrançois Tigeot I915_WRITE(reg, val); 32019df918dSFrançois Tigeot 32119df918dSFrançois Tigeot mmiowb(); 32219df918dSFrançois Tigeot for (i = 0; i < len; i += 4) { 32319df918dSFrançois Tigeot I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data); 32419df918dSFrançois Tigeot data++; 32519df918dSFrançois Tigeot } 32619df918dSFrançois Tigeot /* Write every possible data byte to force correct ECC calculation. */ 32719df918dSFrançois Tigeot for (; i < VIDEO_DIP_DATA_SIZE; i += 4) 32819df918dSFrançois Tigeot I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), 0); 32919df918dSFrançois Tigeot mmiowb(); 33019df918dSFrançois Tigeot 3319edbd4a0SFrançois Tigeot val |= g4x_infoframe_enable(type); 33219df918dSFrançois Tigeot val &= ~VIDEO_DIP_FREQ_MASK; 33319df918dSFrançois Tigeot val |= VIDEO_DIP_FREQ_VSYNC; 33419df918dSFrançois Tigeot 33519df918dSFrançois Tigeot I915_WRITE(reg, val); 33619df918dSFrançois Tigeot POSTING_READ(reg); 33719df918dSFrançois Tigeot } 33819df918dSFrançois Tigeot 3392c9916cdSFrançois Tigeot static bool vlv_infoframe_enabled(struct drm_encoder *encoder) 3402c9916cdSFrançois Tigeot { 3412c9916cdSFrançois Tigeot struct drm_device *dev = encoder->dev; 3422c9916cdSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 3432c9916cdSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 34419c468b4SFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); 3452c9916cdSFrançois Tigeot int reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); 3462c9916cdSFrançois Tigeot u32 val = I915_READ(reg); 3472c9916cdSFrançois Tigeot 348*a05eeebfSFrançois Tigeot if ((val & VIDEO_DIP_ENABLE) == 0) 34919c468b4SFrançois Tigeot return false; 350*a05eeebfSFrançois Tigeot 351*a05eeebfSFrançois Tigeot if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->port)) 352*a05eeebfSFrançois Tigeot return false; 353*a05eeebfSFrançois Tigeot 354*a05eeebfSFrançois Tigeot return val & (VIDEO_DIP_ENABLE_AVI | 355*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | 356*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); 3572c9916cdSFrançois Tigeot } 3582c9916cdSFrançois Tigeot 35919df918dSFrançois Tigeot static void hsw_write_infoframe(struct drm_encoder *encoder, 3609edbd4a0SFrançois Tigeot enum hdmi_infoframe_type type, 3619edbd4a0SFrançois Tigeot const void *frame, ssize_t len) 36219df918dSFrançois Tigeot { 3639edbd4a0SFrançois Tigeot const uint32_t *data = frame; 36419df918dSFrançois Tigeot struct drm_device *dev = encoder->dev; 36519df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 36619df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 3672c9916cdSFrançois Tigeot u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder); 3689edbd4a0SFrançois Tigeot u32 data_reg; 3699edbd4a0SFrançois Tigeot int i; 37019df918dSFrançois Tigeot u32 val = I915_READ(ctl_reg); 37119df918dSFrançois Tigeot 3729edbd4a0SFrançois Tigeot data_reg = hsw_infoframe_data_reg(type, 3732c9916cdSFrançois Tigeot intel_crtc->config->cpu_transcoder, 374ba55f2f5SFrançois Tigeot dev_priv); 37519df918dSFrançois Tigeot if (data_reg == 0) 37619df918dSFrançois Tigeot return; 37719df918dSFrançois Tigeot 3789edbd4a0SFrançois Tigeot val &= ~hsw_infoframe_enable(type); 37919df918dSFrançois Tigeot I915_WRITE(ctl_reg, val); 38019df918dSFrançois Tigeot 38119df918dSFrançois Tigeot mmiowb(); 38219df918dSFrançois Tigeot for (i = 0; i < len; i += 4) { 38319df918dSFrançois Tigeot I915_WRITE(data_reg + i, *data); 38419df918dSFrançois Tigeot data++; 38519df918dSFrançois Tigeot } 38619df918dSFrançois Tigeot /* Write every possible data byte to force correct ECC calculation. */ 38719df918dSFrançois Tigeot for (; i < VIDEO_DIP_DATA_SIZE; i += 4) 38819df918dSFrançois Tigeot I915_WRITE(data_reg + i, 0); 38919df918dSFrançois Tigeot mmiowb(); 39019df918dSFrançois Tigeot 3919edbd4a0SFrançois Tigeot val |= hsw_infoframe_enable(type); 39219df918dSFrançois Tigeot I915_WRITE(ctl_reg, val); 39319df918dSFrançois Tigeot POSTING_READ(ctl_reg); 394e3adcf8fSFrançois Tigeot } 395e3adcf8fSFrançois Tigeot 3962c9916cdSFrançois Tigeot static bool hsw_infoframe_enabled(struct drm_encoder *encoder) 3972c9916cdSFrançois Tigeot { 3982c9916cdSFrançois Tigeot struct drm_device *dev = encoder->dev; 3992c9916cdSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 4002c9916cdSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 4012c9916cdSFrançois Tigeot u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder); 4022c9916cdSFrançois Tigeot u32 val = I915_READ(ctl_reg); 4032c9916cdSFrançois Tigeot 404*a05eeebfSFrançois Tigeot return val & (VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW | 405*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW | 406*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW); 4072c9916cdSFrançois Tigeot } 4082c9916cdSFrançois Tigeot 4099edbd4a0SFrançois Tigeot /* 4109edbd4a0SFrançois Tigeot * The data we write to the DIP data buffer registers is 1 byte bigger than the 4119edbd4a0SFrançois Tigeot * HDMI infoframe size because of an ECC/reserved byte at position 3 (starting 4129edbd4a0SFrançois Tigeot * at 0). It's also a byte used by DisplayPort so the same DIP registers can be 4139edbd4a0SFrançois Tigeot * used for both technologies. 4149edbd4a0SFrançois Tigeot * 4159edbd4a0SFrançois Tigeot * DW0: Reserved/ECC/DP | HB2 | HB1 | HB0 4169edbd4a0SFrançois Tigeot * DW1: DB3 | DB2 | DB1 | DB0 4179edbd4a0SFrançois Tigeot * DW2: DB7 | DB6 | DB5 | DB4 4189edbd4a0SFrançois Tigeot * DW3: ... 4199edbd4a0SFrançois Tigeot * 4209edbd4a0SFrançois Tigeot * (HB is Header Byte, DB is Data Byte) 4219edbd4a0SFrançois Tigeot * 4229edbd4a0SFrançois Tigeot * The hdmi pack() functions don't know about that hardware specific hole so we 4239edbd4a0SFrançois Tigeot * trick them by giving an offset into the buffer and moving back the header 4249edbd4a0SFrançois Tigeot * bytes by one. 4259edbd4a0SFrançois Tigeot */ 4269edbd4a0SFrançois Tigeot static void intel_write_infoframe(struct drm_encoder *encoder, 4279edbd4a0SFrançois Tigeot union hdmi_infoframe *frame) 428e3adcf8fSFrançois Tigeot { 429e3adcf8fSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 4309edbd4a0SFrançois Tigeot uint8_t buffer[VIDEO_DIP_DATA_SIZE]; 4319edbd4a0SFrançois Tigeot ssize_t len; 432e3adcf8fSFrançois Tigeot 4339edbd4a0SFrançois Tigeot /* see comment above for the reason for this offset */ 4349edbd4a0SFrançois Tigeot len = hdmi_infoframe_pack(frame, buffer + 1, sizeof(buffer) - 1); 4359edbd4a0SFrançois Tigeot if (len < 0) 4369edbd4a0SFrançois Tigeot return; 4379edbd4a0SFrançois Tigeot 4389edbd4a0SFrançois Tigeot /* Insert the 'hole' (see big comment above) at position 3 */ 4399edbd4a0SFrançois Tigeot buffer[0] = buffer[1]; 4409edbd4a0SFrançois Tigeot buffer[1] = buffer[2]; 4419edbd4a0SFrançois Tigeot buffer[2] = buffer[3]; 4429edbd4a0SFrançois Tigeot buffer[3] = 0; 4439edbd4a0SFrançois Tigeot len++; 4449edbd4a0SFrançois Tigeot 4459edbd4a0SFrançois Tigeot intel_hdmi->write_infoframe(encoder, frame->any.type, buffer, len); 446e3adcf8fSFrançois Tigeot } 447e3adcf8fSFrançois Tigeot 44819df918dSFrançois Tigeot static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, 44919df918dSFrançois Tigeot struct drm_display_mode *adjusted_mode) 450e3adcf8fSFrançois Tigeot { 451a2fdbec6SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 4528e26cdf6SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 4539edbd4a0SFrançois Tigeot union hdmi_infoframe frame; 4549edbd4a0SFrançois Tigeot int ret; 455e3adcf8fSFrançois Tigeot 45624edb884SFrançois Tigeot /* Set user selected PAR to incoming mode's member */ 45724edb884SFrançois Tigeot adjusted_mode->picture_aspect_ratio = intel_hdmi->aspect_ratio; 45824edb884SFrançois Tigeot 4599edbd4a0SFrançois Tigeot ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, 4609edbd4a0SFrançois Tigeot adjusted_mode); 4619edbd4a0SFrançois Tigeot if (ret < 0) { 4629edbd4a0SFrançois Tigeot DRM_ERROR("couldn't fill AVI infoframe\n"); 4639edbd4a0SFrançois Tigeot return; 4649edbd4a0SFrançois Tigeot } 46519df918dSFrançois Tigeot 466a2fdbec6SFrançois Tigeot if (intel_hdmi->rgb_quant_range_selectable) { 4672c9916cdSFrançois Tigeot if (intel_crtc->config->limited_color_range) 4689edbd4a0SFrançois Tigeot frame.avi.quantization_range = 4699edbd4a0SFrançois Tigeot HDMI_QUANTIZATION_RANGE_LIMITED; 470a2fdbec6SFrançois Tigeot else 4719edbd4a0SFrançois Tigeot frame.avi.quantization_range = 4729edbd4a0SFrançois Tigeot HDMI_QUANTIZATION_RANGE_FULL; 473a2fdbec6SFrançois Tigeot } 474a2fdbec6SFrançois Tigeot 4759edbd4a0SFrançois Tigeot intel_write_infoframe(encoder, &frame); 476e3adcf8fSFrançois Tigeot } 477e3adcf8fSFrançois Tigeot 478e3adcf8fSFrançois Tigeot static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder) 479e3adcf8fSFrançois Tigeot { 4809edbd4a0SFrançois Tigeot union hdmi_infoframe frame; 4819edbd4a0SFrançois Tigeot int ret; 482e3adcf8fSFrançois Tigeot 4839edbd4a0SFrançois Tigeot ret = hdmi_spd_infoframe_init(&frame.spd, "Intel", "Integrated gfx"); 4849edbd4a0SFrançois Tigeot if (ret < 0) { 4859edbd4a0SFrançois Tigeot DRM_ERROR("couldn't fill SPD infoframe\n"); 4869edbd4a0SFrançois Tigeot return; 4879edbd4a0SFrançois Tigeot } 488e3adcf8fSFrançois Tigeot 4899edbd4a0SFrançois Tigeot frame.spd.sdi = HDMI_SPD_SDI_PC; 4909edbd4a0SFrançois Tigeot 4919edbd4a0SFrançois Tigeot intel_write_infoframe(encoder, &frame); 4929edbd4a0SFrançois Tigeot } 4939edbd4a0SFrançois Tigeot 4949edbd4a0SFrançois Tigeot static void 4959edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder, 4969edbd4a0SFrançois Tigeot struct drm_display_mode *adjusted_mode) 4979edbd4a0SFrançois Tigeot { 4989edbd4a0SFrançois Tigeot union hdmi_infoframe frame; 4999edbd4a0SFrançois Tigeot int ret; 5009edbd4a0SFrançois Tigeot 5019edbd4a0SFrançois Tigeot ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi, 5029edbd4a0SFrançois Tigeot adjusted_mode); 5039edbd4a0SFrançois Tigeot if (ret < 0) 5049edbd4a0SFrançois Tigeot return; 5059edbd4a0SFrançois Tigeot 5069edbd4a0SFrançois Tigeot intel_write_infoframe(encoder, &frame); 507e3adcf8fSFrançois Tigeot } 508e3adcf8fSFrançois Tigeot 50919df918dSFrançois Tigeot static void g4x_set_infoframes(struct drm_encoder *encoder, 510ba55f2f5SFrançois Tigeot bool enable, 51119df918dSFrançois Tigeot struct drm_display_mode *adjusted_mode) 51219df918dSFrançois Tigeot { 51319df918dSFrançois Tigeot struct drm_i915_private *dev_priv = encoder->dev->dev_private; 514a2fdbec6SFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); 515a2fdbec6SFrançois Tigeot struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; 51619df918dSFrançois Tigeot u32 reg = VIDEO_DIP_CTL; 51719df918dSFrançois Tigeot u32 val = I915_READ(reg); 518ba55f2f5SFrançois Tigeot u32 port = VIDEO_DIP_PORT(intel_dig_port->port); 51919df918dSFrançois Tigeot 52019df918dSFrançois Tigeot assert_hdmi_port_disabled(intel_hdmi); 52119df918dSFrançois Tigeot 52219df918dSFrançois Tigeot /* If the registers were not initialized yet, they might be zeroes, 52319df918dSFrançois Tigeot * which means we're selecting the AVI DIP and we're setting its 52419df918dSFrançois Tigeot * frequency to once. This seems to really confuse the HW and make 52519df918dSFrançois Tigeot * things stop working (the register spec says the AVI always needs to 52619df918dSFrançois Tigeot * be sent every VSync). So here we avoid writing to the register more 52719df918dSFrançois Tigeot * than we need and also explicitly select the AVI DIP and explicitly 52819df918dSFrançois Tigeot * set its frequency to every VSync. Avoiding to write it twice seems to 52919df918dSFrançois Tigeot * be enough to solve the problem, but being defensive shouldn't hurt us 53019df918dSFrançois Tigeot * either. */ 53119df918dSFrançois Tigeot val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; 53219df918dSFrançois Tigeot 533ba55f2f5SFrançois Tigeot if (!enable) { 53419df918dSFrançois Tigeot if (!(val & VIDEO_DIP_ENABLE)) 53519df918dSFrançois Tigeot return; 536*a05eeebfSFrançois Tigeot if (port != (val & VIDEO_DIP_PORT_MASK)) { 537*a05eeebfSFrançois Tigeot DRM_DEBUG_KMS("video DIP still enabled on port %c\n", 538*a05eeebfSFrançois Tigeot (val & VIDEO_DIP_PORT_MASK) >> 29); 539*a05eeebfSFrançois Tigeot return; 540*a05eeebfSFrançois Tigeot } 541*a05eeebfSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI | 542*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD); 54319df918dSFrançois Tigeot I915_WRITE(reg, val); 54419df918dSFrançois Tigeot POSTING_READ(reg); 54519df918dSFrançois Tigeot return; 54619df918dSFrançois Tigeot } 54719df918dSFrançois Tigeot 54819df918dSFrançois Tigeot if (port != (val & VIDEO_DIP_PORT_MASK)) { 54919df918dSFrançois Tigeot if (val & VIDEO_DIP_ENABLE) { 550*a05eeebfSFrançois Tigeot DRM_DEBUG_KMS("video DIP already enabled on port %c\n", 551*a05eeebfSFrançois Tigeot (val & VIDEO_DIP_PORT_MASK) >> 29); 552*a05eeebfSFrançois Tigeot return; 55319df918dSFrançois Tigeot } 55419df918dSFrançois Tigeot val &= ~VIDEO_DIP_PORT_MASK; 55519df918dSFrançois Tigeot val |= port; 55619df918dSFrançois Tigeot } 55719df918dSFrançois Tigeot 55819df918dSFrançois Tigeot val |= VIDEO_DIP_ENABLE; 559*a05eeebfSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE_AVI | 560*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD); 56119df918dSFrançois Tigeot 56219df918dSFrançois Tigeot I915_WRITE(reg, val); 56319df918dSFrançois Tigeot POSTING_READ(reg); 56419df918dSFrançois Tigeot 56519df918dSFrançois Tigeot intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); 56619df918dSFrançois Tigeot intel_hdmi_set_spd_infoframe(encoder); 5679edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode); 56819df918dSFrançois Tigeot } 56919df918dSFrançois Tigeot 570*a05eeebfSFrançois Tigeot static bool hdmi_sink_is_deep_color(struct drm_encoder *encoder) 571*a05eeebfSFrançois Tigeot { 572*a05eeebfSFrançois Tigeot struct drm_device *dev = encoder->dev; 573*a05eeebfSFrançois Tigeot struct drm_connector *connector; 574*a05eeebfSFrançois Tigeot 575*a05eeebfSFrançois Tigeot WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); 576*a05eeebfSFrançois Tigeot 577*a05eeebfSFrançois Tigeot /* 578*a05eeebfSFrançois Tigeot * HDMI cloning is only supported on g4x which doesn't 579*a05eeebfSFrançois Tigeot * support deep color or GCP infoframes anyway so no 580*a05eeebfSFrançois Tigeot * need to worry about multiple HDMI sinks here. 581*a05eeebfSFrançois Tigeot */ 582*a05eeebfSFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) 583*a05eeebfSFrançois Tigeot if (connector->encoder == encoder) 584*a05eeebfSFrançois Tigeot return connector->display_info.bpc > 8; 585*a05eeebfSFrançois Tigeot 586*a05eeebfSFrançois Tigeot return false; 587*a05eeebfSFrançois Tigeot } 588*a05eeebfSFrançois Tigeot 589*a05eeebfSFrançois Tigeot /* 590*a05eeebfSFrançois Tigeot * Determine if default_phase=1 can be indicated in the GCP infoframe. 591*a05eeebfSFrançois Tigeot * 592*a05eeebfSFrançois Tigeot * From HDMI specification 1.4a: 593*a05eeebfSFrançois Tigeot * - The first pixel of each Video Data Period shall always have a pixel packing phase of 0 594*a05eeebfSFrançois Tigeot * - The first pixel following each Video Data Period shall have a pixel packing phase of 0 595*a05eeebfSFrançois Tigeot * - The PP bits shall be constant for all GCPs and will be equal to the last packing phase 596*a05eeebfSFrançois Tigeot * - The first pixel following every transition of HSYNC or VSYNC shall have a pixel packing 597*a05eeebfSFrançois Tigeot * phase of 0 598*a05eeebfSFrançois Tigeot */ 599*a05eeebfSFrançois Tigeot static bool gcp_default_phase_possible(int pipe_bpp, 600*a05eeebfSFrançois Tigeot const struct drm_display_mode *mode) 601*a05eeebfSFrançois Tigeot { 602*a05eeebfSFrançois Tigeot unsigned int pixels_per_group; 603*a05eeebfSFrançois Tigeot 604*a05eeebfSFrançois Tigeot switch (pipe_bpp) { 605*a05eeebfSFrançois Tigeot case 30: 606*a05eeebfSFrançois Tigeot /* 4 pixels in 5 clocks */ 607*a05eeebfSFrançois Tigeot pixels_per_group = 4; 608*a05eeebfSFrançois Tigeot break; 609*a05eeebfSFrançois Tigeot case 36: 610*a05eeebfSFrançois Tigeot /* 2 pixels in 3 clocks */ 611*a05eeebfSFrançois Tigeot pixels_per_group = 2; 612*a05eeebfSFrançois Tigeot break; 613*a05eeebfSFrançois Tigeot case 48: 614*a05eeebfSFrançois Tigeot /* 1 pixel in 2 clocks */ 615*a05eeebfSFrançois Tigeot pixels_per_group = 1; 616*a05eeebfSFrançois Tigeot break; 617*a05eeebfSFrançois Tigeot default: 618*a05eeebfSFrançois Tigeot /* phase information not relevant for 8bpc */ 619*a05eeebfSFrançois Tigeot return false; 620*a05eeebfSFrançois Tigeot } 621*a05eeebfSFrançois Tigeot 622*a05eeebfSFrançois Tigeot return mode->crtc_hdisplay % pixels_per_group == 0 && 623*a05eeebfSFrançois Tigeot mode->crtc_htotal % pixels_per_group == 0 && 624*a05eeebfSFrançois Tigeot mode->crtc_hblank_start % pixels_per_group == 0 && 625*a05eeebfSFrançois Tigeot mode->crtc_hblank_end % pixels_per_group == 0 && 626*a05eeebfSFrançois Tigeot mode->crtc_hsync_start % pixels_per_group == 0 && 627*a05eeebfSFrançois Tigeot mode->crtc_hsync_end % pixels_per_group == 0 && 628*a05eeebfSFrançois Tigeot ((mode->flags & DRM_MODE_FLAG_INTERLACE) == 0 || 629*a05eeebfSFrançois Tigeot mode->crtc_htotal/2 % pixels_per_group == 0); 630*a05eeebfSFrançois Tigeot } 631*a05eeebfSFrançois Tigeot 632*a05eeebfSFrançois Tigeot static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder) 633*a05eeebfSFrançois Tigeot { 634*a05eeebfSFrançois Tigeot struct drm_i915_private *dev_priv = encoder->dev->dev_private; 635*a05eeebfSFrançois Tigeot struct intel_crtc *crtc = to_intel_crtc(encoder->crtc); 636*a05eeebfSFrançois Tigeot u32 reg, val = 0; 637*a05eeebfSFrançois Tigeot 638*a05eeebfSFrançois Tigeot if (HAS_DDI(dev_priv)) 639*a05eeebfSFrançois Tigeot reg = HSW_TVIDEO_DIP_GCP(crtc->config->cpu_transcoder); 640*a05eeebfSFrançois Tigeot else if (IS_VALLEYVIEW(dev_priv)) 641*a05eeebfSFrançois Tigeot reg = VLV_TVIDEO_DIP_GCP(crtc->pipe); 642*a05eeebfSFrançois Tigeot else if (HAS_PCH_SPLIT(dev_priv->dev)) 643*a05eeebfSFrançois Tigeot reg = TVIDEO_DIP_GCP(crtc->pipe); 644*a05eeebfSFrançois Tigeot else 645*a05eeebfSFrançois Tigeot return false; 646*a05eeebfSFrançois Tigeot 647*a05eeebfSFrançois Tigeot /* Indicate color depth whenever the sink supports deep color */ 648*a05eeebfSFrançois Tigeot if (hdmi_sink_is_deep_color(encoder)) 649*a05eeebfSFrançois Tigeot val |= GCP_COLOR_INDICATION; 650*a05eeebfSFrançois Tigeot 651*a05eeebfSFrançois Tigeot /* Enable default_phase whenever the display mode is suitably aligned */ 652*a05eeebfSFrançois Tigeot if (gcp_default_phase_possible(crtc->config->pipe_bpp, 653*a05eeebfSFrançois Tigeot &crtc->config->base.adjusted_mode)) 654*a05eeebfSFrançois Tigeot val |= GCP_DEFAULT_PHASE_ENABLE; 655*a05eeebfSFrançois Tigeot 656*a05eeebfSFrançois Tigeot I915_WRITE(reg, val); 657*a05eeebfSFrançois Tigeot 658*a05eeebfSFrançois Tigeot return val != 0; 659*a05eeebfSFrançois Tigeot } 660*a05eeebfSFrançois Tigeot 66119df918dSFrançois Tigeot static void ibx_set_infoframes(struct drm_encoder *encoder, 662ba55f2f5SFrançois Tigeot bool enable, 66319df918dSFrançois Tigeot struct drm_display_mode *adjusted_mode) 66419df918dSFrançois Tigeot { 66519df918dSFrançois Tigeot struct drm_i915_private *dev_priv = encoder->dev->dev_private; 66619df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 667a2fdbec6SFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); 668a2fdbec6SFrançois Tigeot struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; 66919df918dSFrançois Tigeot u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe); 67019df918dSFrançois Tigeot u32 val = I915_READ(reg); 671ba55f2f5SFrançois Tigeot u32 port = VIDEO_DIP_PORT(intel_dig_port->port); 67219df918dSFrançois Tigeot 67319df918dSFrançois Tigeot assert_hdmi_port_disabled(intel_hdmi); 67419df918dSFrançois Tigeot 67519df918dSFrançois Tigeot /* See the big comment in g4x_set_infoframes() */ 67619df918dSFrançois Tigeot val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; 67719df918dSFrançois Tigeot 678ba55f2f5SFrançois Tigeot if (!enable) { 67919df918dSFrançois Tigeot if (!(val & VIDEO_DIP_ENABLE)) 68019df918dSFrançois Tigeot return; 681*a05eeebfSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI | 682*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | 683*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); 68419df918dSFrançois Tigeot I915_WRITE(reg, val); 68519df918dSFrançois Tigeot POSTING_READ(reg); 68619df918dSFrançois Tigeot return; 68719df918dSFrançois Tigeot } 68819df918dSFrançois Tigeot 68919df918dSFrançois Tigeot if (port != (val & VIDEO_DIP_PORT_MASK)) { 690*a05eeebfSFrançois Tigeot WARN(val & VIDEO_DIP_ENABLE, 691*a05eeebfSFrançois Tigeot "DIP already enabled on port %c\n", 692*a05eeebfSFrançois Tigeot (val & VIDEO_DIP_PORT_MASK) >> 29); 69319df918dSFrançois Tigeot val &= ~VIDEO_DIP_PORT_MASK; 69419df918dSFrançois Tigeot val |= port; 69519df918dSFrançois Tigeot } 69619df918dSFrançois Tigeot 69719df918dSFrançois Tigeot val |= VIDEO_DIP_ENABLE; 698*a05eeebfSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE_AVI | 699*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | 700*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); 701*a05eeebfSFrançois Tigeot 702*a05eeebfSFrançois Tigeot if (intel_hdmi_set_gcp_infoframe(encoder)) 703*a05eeebfSFrançois Tigeot val |= VIDEO_DIP_ENABLE_GCP; 70419df918dSFrançois Tigeot 70519df918dSFrançois Tigeot I915_WRITE(reg, val); 70619df918dSFrançois Tigeot POSTING_READ(reg); 70719df918dSFrançois Tigeot 70819df918dSFrançois Tigeot intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); 70919df918dSFrançois Tigeot intel_hdmi_set_spd_infoframe(encoder); 7109edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode); 71119df918dSFrançois Tigeot } 71219df918dSFrançois Tigeot 71319df918dSFrançois Tigeot static void cpt_set_infoframes(struct drm_encoder *encoder, 714ba55f2f5SFrançois Tigeot bool enable, 71519df918dSFrançois Tigeot struct drm_display_mode *adjusted_mode) 71619df918dSFrançois Tigeot { 71719df918dSFrançois Tigeot struct drm_i915_private *dev_priv = encoder->dev->dev_private; 71819df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 71919df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 72019df918dSFrançois Tigeot u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe); 72119df918dSFrançois Tigeot u32 val = I915_READ(reg); 72219df918dSFrançois Tigeot 72319df918dSFrançois Tigeot assert_hdmi_port_disabled(intel_hdmi); 72419df918dSFrançois Tigeot 72519df918dSFrançois Tigeot /* See the big comment in g4x_set_infoframes() */ 72619df918dSFrançois Tigeot val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; 72719df918dSFrançois Tigeot 728ba55f2f5SFrançois Tigeot if (!enable) { 72919df918dSFrançois Tigeot if (!(val & VIDEO_DIP_ENABLE)) 73019df918dSFrançois Tigeot return; 731*a05eeebfSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI | 732*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | 733*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); 73419df918dSFrançois Tigeot I915_WRITE(reg, val); 73519df918dSFrançois Tigeot POSTING_READ(reg); 73619df918dSFrançois Tigeot return; 73719df918dSFrançois Tigeot } 73819df918dSFrançois Tigeot 73919df918dSFrançois Tigeot /* Set both together, unset both together: see the spec. */ 74019df918dSFrançois Tigeot val |= VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI; 74119df918dSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | 742*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); 743*a05eeebfSFrançois Tigeot 744*a05eeebfSFrançois Tigeot if (intel_hdmi_set_gcp_infoframe(encoder)) 745*a05eeebfSFrançois Tigeot val |= VIDEO_DIP_ENABLE_GCP; 74619df918dSFrançois Tigeot 74719df918dSFrançois Tigeot I915_WRITE(reg, val); 74819df918dSFrançois Tigeot POSTING_READ(reg); 74919df918dSFrançois Tigeot 75019df918dSFrançois Tigeot intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); 75119df918dSFrançois Tigeot intel_hdmi_set_spd_infoframe(encoder); 7529edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode); 75319df918dSFrançois Tigeot } 75419df918dSFrançois Tigeot 75519df918dSFrançois Tigeot static void vlv_set_infoframes(struct drm_encoder *encoder, 756ba55f2f5SFrançois Tigeot bool enable, 75719df918dSFrançois Tigeot struct drm_display_mode *adjusted_mode) 75819df918dSFrançois Tigeot { 75919df918dSFrançois Tigeot struct drm_i915_private *dev_priv = encoder->dev->dev_private; 760ba55f2f5SFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); 76119df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 76219df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 76319df918dSFrançois Tigeot u32 reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); 76419df918dSFrançois Tigeot u32 val = I915_READ(reg); 765ba55f2f5SFrançois Tigeot u32 port = VIDEO_DIP_PORT(intel_dig_port->port); 76619df918dSFrançois Tigeot 76719df918dSFrançois Tigeot assert_hdmi_port_disabled(intel_hdmi); 76819df918dSFrançois Tigeot 76919df918dSFrançois Tigeot /* See the big comment in g4x_set_infoframes() */ 77019df918dSFrançois Tigeot val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; 77119df918dSFrançois Tigeot 772ba55f2f5SFrançois Tigeot if (!enable) { 77319df918dSFrançois Tigeot if (!(val & VIDEO_DIP_ENABLE)) 77419df918dSFrançois Tigeot return; 775*a05eeebfSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI | 776*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | 777*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); 77819df918dSFrançois Tigeot I915_WRITE(reg, val); 77919df918dSFrançois Tigeot POSTING_READ(reg); 78019df918dSFrançois Tigeot return; 78119df918dSFrançois Tigeot } 78219df918dSFrançois Tigeot 783ba55f2f5SFrançois Tigeot if (port != (val & VIDEO_DIP_PORT_MASK)) { 784*a05eeebfSFrançois Tigeot WARN(val & VIDEO_DIP_ENABLE, 785*a05eeebfSFrançois Tigeot "DIP already enabled on port %c\n", 786*a05eeebfSFrançois Tigeot (val & VIDEO_DIP_PORT_MASK) >> 29); 787ba55f2f5SFrançois Tigeot val &= ~VIDEO_DIP_PORT_MASK; 788ba55f2f5SFrançois Tigeot val |= port; 789ba55f2f5SFrançois Tigeot } 790ba55f2f5SFrançois Tigeot 79119df918dSFrançois Tigeot val |= VIDEO_DIP_ENABLE; 792*a05eeebfSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE_AVI | 793*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | 794*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); 795*a05eeebfSFrançois Tigeot 796*a05eeebfSFrançois Tigeot if (intel_hdmi_set_gcp_infoframe(encoder)) 797*a05eeebfSFrançois Tigeot val |= VIDEO_DIP_ENABLE_GCP; 79819df918dSFrançois Tigeot 79919df918dSFrançois Tigeot I915_WRITE(reg, val); 80019df918dSFrançois Tigeot POSTING_READ(reg); 80119df918dSFrançois Tigeot 80219df918dSFrançois Tigeot intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); 80319df918dSFrançois Tigeot intel_hdmi_set_spd_infoframe(encoder); 8049edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode); 80519df918dSFrançois Tigeot } 80619df918dSFrançois Tigeot 80719df918dSFrançois Tigeot static void hsw_set_infoframes(struct drm_encoder *encoder, 808ba55f2f5SFrançois Tigeot bool enable, 80919df918dSFrançois Tigeot struct drm_display_mode *adjusted_mode) 81019df918dSFrançois Tigeot { 81119df918dSFrançois Tigeot struct drm_i915_private *dev_priv = encoder->dev->dev_private; 81219df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 81319df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 8142c9916cdSFrançois Tigeot u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder); 81519df918dSFrançois Tigeot u32 val = I915_READ(reg); 81619df918dSFrançois Tigeot 81719df918dSFrançois Tigeot assert_hdmi_port_disabled(intel_hdmi); 81819df918dSFrançois Tigeot 819*a05eeebfSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW | 820*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW | 821*a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW); 822*a05eeebfSFrançois Tigeot 823ba55f2f5SFrançois Tigeot if (!enable) { 824*a05eeebfSFrançois Tigeot I915_WRITE(reg, val); 82519df918dSFrançois Tigeot POSTING_READ(reg); 82619df918dSFrançois Tigeot return; 82719df918dSFrançois Tigeot } 82819df918dSFrançois Tigeot 829*a05eeebfSFrançois Tigeot if (intel_hdmi_set_gcp_infoframe(encoder)) 830*a05eeebfSFrançois Tigeot val |= VIDEO_DIP_ENABLE_GCP_HSW; 83119df918dSFrançois Tigeot 83219df918dSFrançois Tigeot I915_WRITE(reg, val); 83319df918dSFrançois Tigeot POSTING_READ(reg); 83419df918dSFrançois Tigeot 83519df918dSFrançois Tigeot intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); 83619df918dSFrançois Tigeot intel_hdmi_set_spd_infoframe(encoder); 8379edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode); 83819df918dSFrançois Tigeot } 83919df918dSFrançois Tigeot 840ba55f2f5SFrançois Tigeot static void intel_hdmi_prepare(struct intel_encoder *encoder) 841e3adcf8fSFrançois Tigeot { 8429edbd4a0SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 843e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 8449edbd4a0SFrançois Tigeot struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); 8459edbd4a0SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 8462c9916cdSFrançois Tigeot struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; 8478e26cdf6SFrançois Tigeot u32 hdmi_val; 848e3adcf8fSFrançois Tigeot 8498e26cdf6SFrançois Tigeot hdmi_val = SDVO_ENCODING_HDMI; 8505d0b1887SFrançois Tigeot if (!HAS_PCH_SPLIT(dev)) 8518e26cdf6SFrançois Tigeot hdmi_val |= intel_hdmi->color_range; 852e3adcf8fSFrançois Tigeot if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) 8538e26cdf6SFrançois Tigeot hdmi_val |= SDVO_VSYNC_ACTIVE_HIGH; 854e3adcf8fSFrançois Tigeot if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) 8558e26cdf6SFrançois Tigeot hdmi_val |= SDVO_HSYNC_ACTIVE_HIGH; 856e3adcf8fSFrançois Tigeot 8572c9916cdSFrançois Tigeot if (crtc->config->pipe_bpp > 24) 8588e26cdf6SFrançois Tigeot hdmi_val |= HDMI_COLOR_FORMAT_12bpc; 859e3adcf8fSFrançois Tigeot else 8608e26cdf6SFrançois Tigeot hdmi_val |= SDVO_COLOR_FORMAT_8bpc; 861e3adcf8fSFrançois Tigeot 8622c9916cdSFrançois Tigeot if (crtc->config->has_hdmi_sink) 8638e26cdf6SFrançois Tigeot hdmi_val |= HDMI_MODE_SELECT_HDMI; 864e3adcf8fSFrançois Tigeot 865e3adcf8fSFrançois Tigeot if (HAS_PCH_CPT(dev)) 8669edbd4a0SFrançois Tigeot hdmi_val |= SDVO_PIPE_SEL_CPT(crtc->pipe); 867ba55f2f5SFrançois Tigeot else if (IS_CHERRYVIEW(dev)) 868ba55f2f5SFrançois Tigeot hdmi_val |= SDVO_PIPE_SEL_CHV(crtc->pipe); 8698e26cdf6SFrançois Tigeot else 8709edbd4a0SFrançois Tigeot hdmi_val |= SDVO_PIPE_SEL(crtc->pipe); 871e3adcf8fSFrançois Tigeot 8728e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, hdmi_val); 8738e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 874e3adcf8fSFrançois Tigeot } 875e3adcf8fSFrançois Tigeot 87619df918dSFrançois Tigeot static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder, 87719df918dSFrançois Tigeot enum i915_pipe *pipe) 878e3adcf8fSFrançois Tigeot { 87919df918dSFrançois Tigeot struct drm_device *dev = encoder->base.dev; 880e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 88119df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 882ba55f2f5SFrançois Tigeot enum intel_display_power_domain power_domain; 88319df918dSFrançois Tigeot u32 tmp; 88419df918dSFrançois Tigeot 885ba55f2f5SFrançois Tigeot power_domain = intel_display_port_power_domain(encoder); 8862c9916cdSFrançois Tigeot if (!intel_display_power_is_enabled(dev_priv, power_domain)) 887ba55f2f5SFrançois Tigeot return false; 888ba55f2f5SFrançois Tigeot 8898e26cdf6SFrançois Tigeot tmp = I915_READ(intel_hdmi->hdmi_reg); 89019df918dSFrançois Tigeot 89119df918dSFrançois Tigeot if (!(tmp & SDVO_ENABLE)) 89219df918dSFrançois Tigeot return false; 89319df918dSFrançois Tigeot 89419df918dSFrançois Tigeot if (HAS_PCH_CPT(dev)) 89519df918dSFrançois Tigeot *pipe = PORT_TO_PIPE_CPT(tmp); 896ba55f2f5SFrançois Tigeot else if (IS_CHERRYVIEW(dev)) 897ba55f2f5SFrançois Tigeot *pipe = SDVO_PORT_TO_PIPE_CHV(tmp); 89819df918dSFrançois Tigeot else 89919df918dSFrançois Tigeot *pipe = PORT_TO_PIPE(tmp); 90019df918dSFrançois Tigeot 90119df918dSFrançois Tigeot return true; 90219df918dSFrançois Tigeot } 90319df918dSFrançois Tigeot 9045d0b1887SFrançois Tigeot static void intel_hdmi_get_config(struct intel_encoder *encoder, 9052c9916cdSFrançois Tigeot struct intel_crtc_state *pipe_config) 9065d0b1887SFrançois Tigeot { 9075d0b1887SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 90824edb884SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 90924edb884SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 9105d0b1887SFrançois Tigeot u32 tmp, flags = 0; 9119edbd4a0SFrançois Tigeot int dotclock; 9125d0b1887SFrançois Tigeot 9135d0b1887SFrançois Tigeot tmp = I915_READ(intel_hdmi->hdmi_reg); 9145d0b1887SFrançois Tigeot 9155d0b1887SFrançois Tigeot if (tmp & SDVO_HSYNC_ACTIVE_HIGH) 9165d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_PHSYNC; 9175d0b1887SFrançois Tigeot else 9185d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_NHSYNC; 9195d0b1887SFrançois Tigeot 9205d0b1887SFrançois Tigeot if (tmp & SDVO_VSYNC_ACTIVE_HIGH) 9215d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_PVSYNC; 9225d0b1887SFrançois Tigeot else 9235d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_NVSYNC; 9245d0b1887SFrançois Tigeot 925ba55f2f5SFrançois Tigeot if (tmp & HDMI_MODE_SELECT_HDMI) 926ba55f2f5SFrançois Tigeot pipe_config->has_hdmi_sink = true; 927ba55f2f5SFrançois Tigeot 9282c9916cdSFrançois Tigeot if (intel_hdmi->infoframe_enabled(&encoder->base)) 9292c9916cdSFrançois Tigeot pipe_config->has_infoframe = true; 9302c9916cdSFrançois Tigeot 93124edb884SFrançois Tigeot if (tmp & SDVO_AUDIO_ENABLE) 932ba55f2f5SFrançois Tigeot pipe_config->has_audio = true; 933ba55f2f5SFrançois Tigeot 93424edb884SFrançois Tigeot if (!HAS_PCH_SPLIT(dev) && 93524edb884SFrançois Tigeot tmp & HDMI_COLOR_RANGE_16_235) 93624edb884SFrançois Tigeot pipe_config->limited_color_range = true; 93724edb884SFrançois Tigeot 9382c9916cdSFrançois Tigeot pipe_config->base.adjusted_mode.flags |= flags; 9399edbd4a0SFrançois Tigeot 9409edbd4a0SFrançois Tigeot if ((tmp & SDVO_COLOR_FORMAT_MASK) == HDMI_COLOR_FORMAT_12bpc) 9419edbd4a0SFrançois Tigeot dotclock = pipe_config->port_clock * 2 / 3; 9429edbd4a0SFrançois Tigeot else 9439edbd4a0SFrançois Tigeot dotclock = pipe_config->port_clock; 9449edbd4a0SFrançois Tigeot 945*a05eeebfSFrançois Tigeot if (pipe_config->pixel_multiplier) 946*a05eeebfSFrançois Tigeot dotclock /= pipe_config->pixel_multiplier; 947*a05eeebfSFrançois Tigeot 9489edbd4a0SFrançois Tigeot if (HAS_PCH_SPLIT(dev_priv->dev)) 9499edbd4a0SFrançois Tigeot ironlake_check_encoder_dotclock(pipe_config, dotclock); 9509edbd4a0SFrançois Tigeot 9512c9916cdSFrançois Tigeot pipe_config->base.adjusted_mode.crtc_clock = dotclock; 9525d0b1887SFrançois Tigeot } 9535d0b1887SFrançois Tigeot 954*a05eeebfSFrançois Tigeot static void intel_enable_hdmi_audio(struct intel_encoder *encoder) 955*a05eeebfSFrançois Tigeot { 956*a05eeebfSFrançois Tigeot struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); 957*a05eeebfSFrançois Tigeot 958*a05eeebfSFrançois Tigeot WARN_ON(!crtc->config->has_hdmi_sink); 959*a05eeebfSFrançois Tigeot DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", 960*a05eeebfSFrançois Tigeot pipe_name(crtc->pipe)); 961*a05eeebfSFrançois Tigeot intel_audio_codec_enable(encoder); 962*a05eeebfSFrançois Tigeot } 963*a05eeebfSFrançois Tigeot 964*a05eeebfSFrançois Tigeot static void g4x_enable_hdmi(struct intel_encoder *encoder) 96519df918dSFrançois Tigeot { 96619df918dSFrançois Tigeot struct drm_device *dev = encoder->base.dev; 96719df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 968*a05eeebfSFrançois Tigeot struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); 96919df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 970e3adcf8fSFrançois Tigeot u32 temp; 971e3adcf8fSFrançois Tigeot 9728e26cdf6SFrançois Tigeot temp = I915_READ(intel_hdmi->hdmi_reg); 973e3adcf8fSFrançois Tigeot 974*a05eeebfSFrançois Tigeot temp |= SDVO_ENABLE; 975*a05eeebfSFrançois Tigeot if (crtc->config->has_audio) 976*a05eeebfSFrançois Tigeot temp |= SDVO_AUDIO_ENABLE; 97719df918dSFrançois Tigeot 978*a05eeebfSFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 979*a05eeebfSFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 980*a05eeebfSFrançois Tigeot 981*a05eeebfSFrançois Tigeot if (crtc->config->has_audio) 982*a05eeebfSFrançois Tigeot intel_enable_hdmi_audio(encoder); 983*a05eeebfSFrançois Tigeot } 984*a05eeebfSFrançois Tigeot 985*a05eeebfSFrançois Tigeot static void ibx_enable_hdmi(struct intel_encoder *encoder) 986*a05eeebfSFrançois Tigeot { 987*a05eeebfSFrançois Tigeot struct drm_device *dev = encoder->base.dev; 988*a05eeebfSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 989*a05eeebfSFrançois Tigeot struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); 990*a05eeebfSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 991*a05eeebfSFrançois Tigeot u32 temp; 992*a05eeebfSFrançois Tigeot 993*a05eeebfSFrançois Tigeot temp = I915_READ(intel_hdmi->hdmi_reg); 994*a05eeebfSFrançois Tigeot 995*a05eeebfSFrançois Tigeot temp |= SDVO_ENABLE; 996*a05eeebfSFrançois Tigeot if (crtc->config->has_audio) 997*a05eeebfSFrançois Tigeot temp |= SDVO_AUDIO_ENABLE; 998*a05eeebfSFrançois Tigeot 999*a05eeebfSFrançois Tigeot /* 1000*a05eeebfSFrançois Tigeot * HW workaround, need to write this twice for issue 1001*a05eeebfSFrançois Tigeot * that may result in first write getting masked. 1002e3adcf8fSFrançois Tigeot */ 1003*a05eeebfSFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 1004*a05eeebfSFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 1005*a05eeebfSFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 1006*a05eeebfSFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 1007*a05eeebfSFrançois Tigeot 1008*a05eeebfSFrançois Tigeot /* 1009*a05eeebfSFrançois Tigeot * HW workaround, need to toggle enable bit off and on 1010*a05eeebfSFrançois Tigeot * for 12bpc with pixel repeat. 1011*a05eeebfSFrançois Tigeot * 1012*a05eeebfSFrançois Tigeot * FIXME: BSpec says this should be done at the end of 1013*a05eeebfSFrançois Tigeot * of the modeset sequence, so not sure if this isn't too soon. 1014*a05eeebfSFrançois Tigeot */ 1015*a05eeebfSFrançois Tigeot if (crtc->config->pipe_bpp > 24 && 1016*a05eeebfSFrançois Tigeot crtc->config->pixel_multiplier > 1) { 10178e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE); 10188e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 1019e3adcf8fSFrançois Tigeot 1020*a05eeebfSFrançois Tigeot /* 1021*a05eeebfSFrançois Tigeot * HW workaround, need to write this twice for issue 1022*a05eeebfSFrançois Tigeot * that may result in first write getting masked. 102319df918dSFrançois Tigeot */ 1024*a05eeebfSFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 1025*a05eeebfSFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 10268e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 10278e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 1028e3adcf8fSFrançois Tigeot } 10292c9916cdSFrançois Tigeot 1030*a05eeebfSFrançois Tigeot if (crtc->config->has_audio) 1031*a05eeebfSFrançois Tigeot intel_enable_hdmi_audio(encoder); 10322c9916cdSFrançois Tigeot } 1033*a05eeebfSFrançois Tigeot 1034*a05eeebfSFrançois Tigeot static void cpt_enable_hdmi(struct intel_encoder *encoder) 1035*a05eeebfSFrançois Tigeot { 1036*a05eeebfSFrançois Tigeot struct drm_device *dev = encoder->base.dev; 1037*a05eeebfSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1038*a05eeebfSFrançois Tigeot struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); 1039*a05eeebfSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 1040*a05eeebfSFrançois Tigeot enum i915_pipe pipe = crtc->pipe; 1041*a05eeebfSFrançois Tigeot u32 temp; 1042*a05eeebfSFrançois Tigeot 1043*a05eeebfSFrançois Tigeot temp = I915_READ(intel_hdmi->hdmi_reg); 1044*a05eeebfSFrançois Tigeot 1045*a05eeebfSFrançois Tigeot temp |= SDVO_ENABLE; 1046*a05eeebfSFrançois Tigeot if (crtc->config->has_audio) 1047*a05eeebfSFrançois Tigeot temp |= SDVO_AUDIO_ENABLE; 1048*a05eeebfSFrançois Tigeot 1049*a05eeebfSFrançois Tigeot /* 1050*a05eeebfSFrançois Tigeot * WaEnableHDMI8bpcBefore12bpc:snb,ivb 1051*a05eeebfSFrançois Tigeot * 1052*a05eeebfSFrançois Tigeot * The procedure for 12bpc is as follows: 1053*a05eeebfSFrançois Tigeot * 1. disable HDMI clock gating 1054*a05eeebfSFrançois Tigeot * 2. enable HDMI with 8bpc 1055*a05eeebfSFrançois Tigeot * 3. enable HDMI with 12bpc 1056*a05eeebfSFrançois Tigeot * 4. enable HDMI clock gating 1057*a05eeebfSFrançois Tigeot */ 1058*a05eeebfSFrançois Tigeot 1059*a05eeebfSFrançois Tigeot if (crtc->config->pipe_bpp > 24) { 1060*a05eeebfSFrançois Tigeot I915_WRITE(TRANS_CHICKEN1(pipe), 1061*a05eeebfSFrançois Tigeot I915_READ(TRANS_CHICKEN1(pipe)) | 1062*a05eeebfSFrançois Tigeot TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE); 1063*a05eeebfSFrançois Tigeot 1064*a05eeebfSFrançois Tigeot temp &= ~SDVO_COLOR_FORMAT_MASK; 1065*a05eeebfSFrançois Tigeot temp |= SDVO_COLOR_FORMAT_8bpc; 1066*a05eeebfSFrançois Tigeot } 1067*a05eeebfSFrançois Tigeot 1068*a05eeebfSFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 1069*a05eeebfSFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 1070*a05eeebfSFrançois Tigeot 1071*a05eeebfSFrançois Tigeot if (crtc->config->pipe_bpp > 24) { 1072*a05eeebfSFrançois Tigeot temp &= ~SDVO_COLOR_FORMAT_MASK; 1073*a05eeebfSFrançois Tigeot temp |= HDMI_COLOR_FORMAT_12bpc; 1074*a05eeebfSFrançois Tigeot 1075*a05eeebfSFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 1076*a05eeebfSFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 1077*a05eeebfSFrançois Tigeot 1078*a05eeebfSFrançois Tigeot I915_WRITE(TRANS_CHICKEN1(pipe), 1079*a05eeebfSFrançois Tigeot I915_READ(TRANS_CHICKEN1(pipe)) & 1080*a05eeebfSFrançois Tigeot ~TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE); 1081*a05eeebfSFrançois Tigeot } 1082*a05eeebfSFrançois Tigeot 1083*a05eeebfSFrançois Tigeot if (crtc->config->has_audio) 1084*a05eeebfSFrançois Tigeot intel_enable_hdmi_audio(encoder); 10855d0b1887SFrançois Tigeot } 10869edbd4a0SFrançois Tigeot 10879edbd4a0SFrançois Tigeot static void vlv_enable_hdmi(struct intel_encoder *encoder) 10889edbd4a0SFrançois Tigeot { 108919df918dSFrançois Tigeot } 109019df918dSFrançois Tigeot 109119df918dSFrançois Tigeot static void intel_disable_hdmi(struct intel_encoder *encoder) 109219df918dSFrançois Tigeot { 109319df918dSFrançois Tigeot struct drm_device *dev = encoder->base.dev; 109419df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 109519df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 10962c9916cdSFrançois Tigeot struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); 109719df918dSFrançois Tigeot u32 temp; 109819c468b4SFrançois Tigeot 109919c468b4SFrançois Tigeot temp = I915_READ(intel_hdmi->hdmi_reg); 110019c468b4SFrançois Tigeot 110119c468b4SFrançois Tigeot temp &= ~(SDVO_ENABLE | SDVO_AUDIO_ENABLE); 110219c468b4SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 110319c468b4SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 110419c468b4SFrançois Tigeot 110519c468b4SFrançois Tigeot /* 110619c468b4SFrançois Tigeot * HW workaround for IBX, we need to move the port 110719c468b4SFrançois Tigeot * to transcoder A after disabling it to allow the 110819c468b4SFrançois Tigeot * matching DP port to be enabled on transcoder A. 110919c468b4SFrançois Tigeot */ 111019c468b4SFrançois Tigeot if (HAS_PCH_IBX(dev) && crtc->pipe == PIPE_B) { 111119c468b4SFrançois Tigeot temp &= ~SDVO_PIPE_B_SELECT; 111219c468b4SFrançois Tigeot temp |= SDVO_ENABLE; 111319c468b4SFrançois Tigeot /* 111419c468b4SFrançois Tigeot * HW workaround, need to write this twice for issue 111519c468b4SFrançois Tigeot * that may result in first write getting masked. 111619c468b4SFrançois Tigeot */ 111719c468b4SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 111819c468b4SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 111919c468b4SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 112019c468b4SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 112119c468b4SFrançois Tigeot 112219c468b4SFrançois Tigeot temp &= ~SDVO_ENABLE; 112319c468b4SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 112419c468b4SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 112519c468b4SFrançois Tigeot } 1126*a05eeebfSFrançois Tigeot 1127*a05eeebfSFrançois Tigeot intel_hdmi->set_infoframes(&encoder->base, false, NULL); 112819c468b4SFrançois Tigeot } 112919c468b4SFrançois Tigeot 113019c468b4SFrançois Tigeot static void g4x_disable_hdmi(struct intel_encoder *encoder) 113119c468b4SFrançois Tigeot { 113219c468b4SFrançois Tigeot struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); 113319df918dSFrançois Tigeot 11342c9916cdSFrançois Tigeot if (crtc->config->has_audio) 11352c9916cdSFrançois Tigeot intel_audio_codec_disable(encoder); 11362c9916cdSFrançois Tigeot 113719c468b4SFrançois Tigeot intel_disable_hdmi(encoder); 113819df918dSFrançois Tigeot } 113919df918dSFrançois Tigeot 114019c468b4SFrançois Tigeot static void pch_disable_hdmi(struct intel_encoder *encoder) 114119c468b4SFrançois Tigeot { 114219c468b4SFrançois Tigeot struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); 114319c468b4SFrançois Tigeot 114419c468b4SFrançois Tigeot if (crtc->config->has_audio) 114519c468b4SFrançois Tigeot intel_audio_codec_disable(encoder); 114619df918dSFrançois Tigeot } 114719df918dSFrançois Tigeot 114819c468b4SFrançois Tigeot static void pch_post_disable_hdmi(struct intel_encoder *encoder) 114919c468b4SFrançois Tigeot { 115019c468b4SFrançois Tigeot intel_disable_hdmi(encoder); 1151e3adcf8fSFrançois Tigeot } 1152e3adcf8fSFrançois Tigeot 1153*a05eeebfSFrançois Tigeot static int hdmi_port_clock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit) 11545d0b1887SFrançois Tigeot { 11555d0b1887SFrançois Tigeot struct drm_device *dev = intel_hdmi_to_dev(hdmi); 11565d0b1887SFrançois Tigeot 1157ba55f2f5SFrançois Tigeot if ((respect_dvi_limit && !hdmi->has_hdmi_sink) || IS_G4X(dev)) 11585d0b1887SFrançois Tigeot return 165000; 11599edbd4a0SFrançois Tigeot else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8) 11605d0b1887SFrançois Tigeot return 300000; 11615d0b1887SFrançois Tigeot else 11625d0b1887SFrançois Tigeot return 225000; 11635d0b1887SFrançois Tigeot } 11645d0b1887SFrançois Tigeot 11659edbd4a0SFrançois Tigeot static enum drm_mode_status 1166*a05eeebfSFrançois Tigeot hdmi_port_clock_valid(struct intel_hdmi *hdmi, 1167*a05eeebfSFrançois Tigeot int clock, bool respect_dvi_limit) 1168*a05eeebfSFrançois Tigeot { 1169*a05eeebfSFrançois Tigeot struct drm_device *dev = intel_hdmi_to_dev(hdmi); 1170*a05eeebfSFrançois Tigeot 1171*a05eeebfSFrançois Tigeot if (clock < 25000) 1172*a05eeebfSFrançois Tigeot return MODE_CLOCK_LOW; 1173*a05eeebfSFrançois Tigeot if (clock > hdmi_port_clock_limit(hdmi, respect_dvi_limit)) 1174*a05eeebfSFrançois Tigeot return MODE_CLOCK_HIGH; 1175*a05eeebfSFrançois Tigeot 1176*a05eeebfSFrançois Tigeot /* BXT DPLL can't generate 223-240 MHz */ 1177*a05eeebfSFrançois Tigeot if (IS_BROXTON(dev) && clock > 223333 && clock < 240000) 1178*a05eeebfSFrançois Tigeot return MODE_CLOCK_RANGE; 1179*a05eeebfSFrançois Tigeot 1180*a05eeebfSFrançois Tigeot /* CHV DPLL can't generate 216-240 MHz */ 1181*a05eeebfSFrançois Tigeot if (IS_CHERRYVIEW(dev) && clock > 216000 && clock < 240000) 1182*a05eeebfSFrançois Tigeot return MODE_CLOCK_RANGE; 1183*a05eeebfSFrançois Tigeot 1184*a05eeebfSFrançois Tigeot return MODE_OK; 1185*a05eeebfSFrançois Tigeot } 1186*a05eeebfSFrançois Tigeot 1187*a05eeebfSFrançois Tigeot static enum drm_mode_status 11889edbd4a0SFrançois Tigeot intel_hdmi_mode_valid(struct drm_connector *connector, 1189e3adcf8fSFrançois Tigeot struct drm_display_mode *mode) 1190e3adcf8fSFrançois Tigeot { 1191*a05eeebfSFrançois Tigeot struct intel_hdmi *hdmi = intel_attached_hdmi(connector); 1192*a05eeebfSFrançois Tigeot struct drm_device *dev = intel_hdmi_to_dev(hdmi); 1193*a05eeebfSFrançois Tigeot enum drm_mode_status status; 1194*a05eeebfSFrançois Tigeot int clock; 1195e3adcf8fSFrançois Tigeot 1196e3adcf8fSFrançois Tigeot if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 1197e3adcf8fSFrançois Tigeot return MODE_NO_DBLESCAN; 1198e3adcf8fSFrançois Tigeot 1199*a05eeebfSFrançois Tigeot clock = mode->clock; 1200*a05eeebfSFrançois Tigeot if (mode->flags & DRM_MODE_FLAG_DBLCLK) 1201*a05eeebfSFrançois Tigeot clock *= 2; 1202*a05eeebfSFrançois Tigeot 1203*a05eeebfSFrançois Tigeot /* check if we can do 8bpc */ 1204*a05eeebfSFrançois Tigeot status = hdmi_port_clock_valid(hdmi, clock, true); 1205*a05eeebfSFrançois Tigeot 1206*a05eeebfSFrançois Tigeot /* if we can't do 8bpc we may still be able to do 12bpc */ 1207*a05eeebfSFrançois Tigeot if (!HAS_GMCH_DISPLAY(dev) && status != MODE_OK) 1208*a05eeebfSFrançois Tigeot status = hdmi_port_clock_valid(hdmi, clock * 3 / 2, true); 1209*a05eeebfSFrançois Tigeot 1210*a05eeebfSFrançois Tigeot return status; 1211e3adcf8fSFrançois Tigeot } 1212e3adcf8fSFrançois Tigeot 1213477eb7f9SFrançois Tigeot static bool hdmi_12bpc_possible(struct intel_crtc_state *crtc_state) 1214ba55f2f5SFrançois Tigeot { 1215477eb7f9SFrançois Tigeot struct drm_device *dev = crtc_state->base.crtc->dev; 1216477eb7f9SFrançois Tigeot struct drm_atomic_state *state; 1217ba55f2f5SFrançois Tigeot struct intel_encoder *encoder; 121819c468b4SFrançois Tigeot struct drm_connector *connector; 1219477eb7f9SFrançois Tigeot struct drm_connector_state *connector_state; 1220ba55f2f5SFrançois Tigeot int count = 0, count_hdmi = 0; 1221477eb7f9SFrançois Tigeot int i; 1222ba55f2f5SFrançois Tigeot 122324edb884SFrançois Tigeot if (HAS_GMCH_DISPLAY(dev)) 1224ba55f2f5SFrançois Tigeot return false; 1225ba55f2f5SFrançois Tigeot 1226477eb7f9SFrançois Tigeot state = crtc_state->base.state; 1227477eb7f9SFrançois Tigeot 122819c468b4SFrançois Tigeot for_each_connector_in_state(state, connector, connector_state, i) { 1229477eb7f9SFrançois Tigeot if (connector_state->crtc != crtc_state->base.crtc) 1230477eb7f9SFrançois Tigeot continue; 1231477eb7f9SFrançois Tigeot 1232477eb7f9SFrançois Tigeot encoder = to_intel_encoder(connector_state->best_encoder); 1233477eb7f9SFrançois Tigeot 1234ba55f2f5SFrançois Tigeot count_hdmi += encoder->type == INTEL_OUTPUT_HDMI; 1235ba55f2f5SFrançois Tigeot count++; 1236ba55f2f5SFrançois Tigeot } 1237ba55f2f5SFrançois Tigeot 1238ba55f2f5SFrançois Tigeot /* 1239ba55f2f5SFrançois Tigeot * HDMI 12bpc affects the clocks, so it's only possible 1240ba55f2f5SFrançois Tigeot * when not cloning with other encoder types. 1241ba55f2f5SFrançois Tigeot */ 1242ba55f2f5SFrançois Tigeot return count_hdmi > 0 && count_hdmi == count; 1243ba55f2f5SFrançois Tigeot } 1244ba55f2f5SFrançois Tigeot 12458e26cdf6SFrançois Tigeot bool intel_hdmi_compute_config(struct intel_encoder *encoder, 12462c9916cdSFrançois Tigeot struct intel_crtc_state *pipe_config) 1247e3adcf8fSFrançois Tigeot { 12488e26cdf6SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 12498e26cdf6SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 12502c9916cdSFrançois Tigeot struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; 1251*a05eeebfSFrançois Tigeot int clock_8bpc = pipe_config->base.adjusted_mode.crtc_clock; 1252*a05eeebfSFrançois Tigeot int clock_12bpc = clock_8bpc * 3 / 2; 12535d0b1887SFrançois Tigeot int desired_bpp; 1254a2fdbec6SFrançois Tigeot 1255ba55f2f5SFrançois Tigeot pipe_config->has_hdmi_sink = intel_hdmi->has_hdmi_sink; 1256ba55f2f5SFrançois Tigeot 12572c9916cdSFrançois Tigeot if (pipe_config->has_hdmi_sink) 12582c9916cdSFrançois Tigeot pipe_config->has_infoframe = true; 12592c9916cdSFrançois Tigeot 1260a2fdbec6SFrançois Tigeot if (intel_hdmi->color_range_auto) { 1261a2fdbec6SFrançois Tigeot /* See CEA-861-E - 5.1 Default Encoding Parameters */ 1262ba55f2f5SFrançois Tigeot if (pipe_config->has_hdmi_sink && 1263a2fdbec6SFrançois Tigeot drm_match_cea_mode(adjusted_mode) > 1) 12648e26cdf6SFrançois Tigeot intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235; 1265a2fdbec6SFrançois Tigeot else 1266a2fdbec6SFrançois Tigeot intel_hdmi->color_range = 0; 1267a2fdbec6SFrançois Tigeot } 1268a2fdbec6SFrançois Tigeot 12691b13d190SFrançois Tigeot if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) { 12701b13d190SFrançois Tigeot pipe_config->pixel_multiplier = 2; 1271*a05eeebfSFrançois Tigeot clock_8bpc *= 2; 1272*a05eeebfSFrançois Tigeot clock_12bpc *= 2; 12731b13d190SFrançois Tigeot } 12741b13d190SFrançois Tigeot 1275a2fdbec6SFrançois Tigeot if (intel_hdmi->color_range) 12768e26cdf6SFrançois Tigeot pipe_config->limited_color_range = true; 12778e26cdf6SFrançois Tigeot 12788e26cdf6SFrançois Tigeot if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev)) 12798e26cdf6SFrançois Tigeot pipe_config->has_pch_encoder = true; 12808e26cdf6SFrançois Tigeot 1281ba55f2f5SFrançois Tigeot if (pipe_config->has_hdmi_sink && intel_hdmi->has_audio) 1282ba55f2f5SFrançois Tigeot pipe_config->has_audio = true; 1283ba55f2f5SFrançois Tigeot 12848e26cdf6SFrançois Tigeot /* 12858e26cdf6SFrançois Tigeot * HDMI is either 12 or 8, so if the display lets 10bpc sneak 12868e26cdf6SFrançois Tigeot * through, clamp it down. Note that g4x/vlv don't support 12bpc hdmi 12875d0b1887SFrançois Tigeot * outputs. We also need to check that the higher clock still fits 12885d0b1887SFrançois Tigeot * within limits. 12898e26cdf6SFrançois Tigeot */ 1290ba55f2f5SFrançois Tigeot if (pipe_config->pipe_bpp > 8*3 && pipe_config->has_hdmi_sink && 1291*a05eeebfSFrançois Tigeot hdmi_port_clock_valid(intel_hdmi, clock_12bpc, false) == MODE_OK && 1292*a05eeebfSFrançois Tigeot hdmi_12bpc_possible(pipe_config)) { 12935d0b1887SFrançois Tigeot DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n"); 12945d0b1887SFrançois Tigeot desired_bpp = 12*3; 12955d0b1887SFrançois Tigeot 12965d0b1887SFrançois Tigeot /* Need to adjust the port link by 1.5x for 12bpc. */ 12975d0b1887SFrançois Tigeot pipe_config->port_clock = clock_12bpc; 12988e26cdf6SFrançois Tigeot } else { 12995d0b1887SFrançois Tigeot DRM_DEBUG_KMS("picking bpc to 8 for HDMI output\n"); 13005d0b1887SFrançois Tigeot desired_bpp = 8*3; 1301*a05eeebfSFrançois Tigeot 1302*a05eeebfSFrançois Tigeot pipe_config->port_clock = clock_8bpc; 13035d0b1887SFrançois Tigeot } 13045d0b1887SFrançois Tigeot 13055d0b1887SFrançois Tigeot if (!pipe_config->bw_constrained) { 13065d0b1887SFrançois Tigeot DRM_DEBUG_KMS("forcing pipe bpc to %i for HDMI\n", desired_bpp); 13075d0b1887SFrançois Tigeot pipe_config->pipe_bpp = desired_bpp; 13085d0b1887SFrançois Tigeot } 13095d0b1887SFrançois Tigeot 1310*a05eeebfSFrançois Tigeot if (hdmi_port_clock_valid(intel_hdmi, pipe_config->port_clock, 1311*a05eeebfSFrançois Tigeot false) != MODE_OK) { 1312*a05eeebfSFrançois Tigeot DRM_DEBUG_KMS("unsupported HDMI clock, rejecting mode\n"); 13135d0b1887SFrançois Tigeot return false; 13148e26cdf6SFrançois Tigeot } 1315a2fdbec6SFrançois Tigeot 1316e3adcf8fSFrançois Tigeot return true; 1317e3adcf8fSFrançois Tigeot } 1318e3adcf8fSFrançois Tigeot 13191b13d190SFrançois Tigeot static void 13201b13d190SFrançois Tigeot intel_hdmi_unset_edid(struct drm_connector *connector) 1321e3adcf8fSFrançois Tigeot { 1322e3adcf8fSFrançois Tigeot struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 13239edbd4a0SFrançois Tigeot 1324e3adcf8fSFrançois Tigeot intel_hdmi->has_hdmi_sink = false; 1325e3adcf8fSFrançois Tigeot intel_hdmi->has_audio = false; 1326a2fdbec6SFrançois Tigeot intel_hdmi->rgb_quant_range_selectable = false; 1327e3adcf8fSFrançois Tigeot 13281b13d190SFrançois Tigeot kfree(to_intel_connector(connector)->detect_edid); 13291b13d190SFrançois Tigeot to_intel_connector(connector)->detect_edid = NULL; 1330e3adcf8fSFrançois Tigeot } 1331e3adcf8fSFrançois Tigeot 13321b13d190SFrançois Tigeot static bool 13331b13d190SFrançois Tigeot intel_hdmi_set_edid(struct drm_connector *connector) 1334e3adcf8fSFrançois Tigeot { 13351b13d190SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(connector->dev); 13361b13d190SFrançois Tigeot struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 13371b13d190SFrançois Tigeot struct intel_encoder *intel_encoder = 13381b13d190SFrançois Tigeot &hdmi_to_dig_port(intel_hdmi)->base; 1339ba55f2f5SFrançois Tigeot enum intel_display_power_domain power_domain; 13401b13d190SFrançois Tigeot struct edid *edid; 13411b13d190SFrançois Tigeot bool connected = false; 1342e3adcf8fSFrançois Tigeot 1343ba55f2f5SFrançois Tigeot power_domain = intel_display_port_power_domain(intel_encoder); 1344ba55f2f5SFrançois Tigeot intel_display_power_get(dev_priv, power_domain); 1345ba55f2f5SFrançois Tigeot 13461b13d190SFrançois Tigeot edid = drm_get_edid(connector, 134719df918dSFrançois Tigeot intel_gmbus_get_adapter(dev_priv, 134819df918dSFrançois Tigeot intel_hdmi->ddc_bus)); 1349ba55f2f5SFrançois Tigeot 1350ba55f2f5SFrançois Tigeot intel_display_power_put(dev_priv, power_domain); 1351ba55f2f5SFrançois Tigeot 13521b13d190SFrançois Tigeot to_intel_connector(connector)->detect_edid = edid; 13531b13d190SFrançois Tigeot if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { 13541b13d190SFrançois Tigeot intel_hdmi->rgb_quant_range_selectable = 13551b13d190SFrançois Tigeot drm_rgb_quant_range_selectable(edid); 13561b13d190SFrançois Tigeot 13571b13d190SFrançois Tigeot intel_hdmi->has_audio = drm_detect_monitor_audio(edid); 13581b13d190SFrançois Tigeot if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO) 13591b13d190SFrançois Tigeot intel_hdmi->has_audio = 13601b13d190SFrançois Tigeot intel_hdmi->force_audio == HDMI_AUDIO_ON; 13611b13d190SFrançois Tigeot 13621b13d190SFrançois Tigeot if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI) 13631b13d190SFrançois Tigeot intel_hdmi->has_hdmi_sink = 13641b13d190SFrançois Tigeot drm_detect_hdmi_monitor(edid); 13651b13d190SFrançois Tigeot 13661b13d190SFrançois Tigeot connected = true; 13671b13d190SFrançois Tigeot } 13681b13d190SFrançois Tigeot 13691b13d190SFrançois Tigeot return connected; 13701b13d190SFrançois Tigeot } 13711b13d190SFrançois Tigeot 13721b13d190SFrançois Tigeot static enum drm_connector_status 13731b13d190SFrançois Tigeot intel_hdmi_detect(struct drm_connector *connector, bool force) 13741b13d190SFrançois Tigeot { 13751b13d190SFrançois Tigeot enum drm_connector_status status; 13761b13d190SFrançois Tigeot 13771b13d190SFrançois Tigeot DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 13781b13d190SFrançois Tigeot connector->base.id, connector->name); 13791b13d190SFrançois Tigeot 13801b13d190SFrançois Tigeot intel_hdmi_unset_edid(connector); 13811b13d190SFrançois Tigeot 13821b13d190SFrançois Tigeot if (intel_hdmi_set_edid(connector)) { 13831b13d190SFrançois Tigeot struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 13841b13d190SFrançois Tigeot 13851b13d190SFrançois Tigeot hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI; 13861b13d190SFrançois Tigeot status = connector_status_connected; 13871b13d190SFrançois Tigeot } else 13881b13d190SFrançois Tigeot status = connector_status_disconnected; 13891b13d190SFrançois Tigeot 13901b13d190SFrançois Tigeot return status; 13911b13d190SFrançois Tigeot } 13921b13d190SFrançois Tigeot 13931b13d190SFrançois Tigeot static void 13941b13d190SFrançois Tigeot intel_hdmi_force(struct drm_connector *connector) 13951b13d190SFrançois Tigeot { 13961b13d190SFrançois Tigeot struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 13971b13d190SFrançois Tigeot 13981b13d190SFrançois Tigeot DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 13991b13d190SFrançois Tigeot connector->base.id, connector->name); 14001b13d190SFrançois Tigeot 14011b13d190SFrançois Tigeot intel_hdmi_unset_edid(connector); 14021b13d190SFrançois Tigeot 14031b13d190SFrançois Tigeot if (connector->status != connector_status_connected) 14041b13d190SFrançois Tigeot return; 14051b13d190SFrançois Tigeot 14061b13d190SFrançois Tigeot intel_hdmi_set_edid(connector); 14071b13d190SFrançois Tigeot hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI; 14081b13d190SFrançois Tigeot } 14091b13d190SFrançois Tigeot 14101b13d190SFrançois Tigeot static int intel_hdmi_get_modes(struct drm_connector *connector) 14111b13d190SFrançois Tigeot { 14121b13d190SFrançois Tigeot struct edid *edid; 14131b13d190SFrançois Tigeot 14141b13d190SFrançois Tigeot edid = to_intel_connector(connector)->detect_edid; 14151b13d190SFrançois Tigeot if (edid == NULL) 14161b13d190SFrançois Tigeot return 0; 14171b13d190SFrançois Tigeot 14181b13d190SFrançois Tigeot return intel_connector_update_modes(connector, edid); 1419e3adcf8fSFrançois Tigeot } 1420e3adcf8fSFrançois Tigeot 1421e3adcf8fSFrançois Tigeot static bool 1422e3adcf8fSFrançois Tigeot intel_hdmi_detect_audio(struct drm_connector *connector) 1423e3adcf8fSFrançois Tigeot { 1424e3adcf8fSFrançois Tigeot bool has_audio = false; 14251b13d190SFrançois Tigeot struct edid *edid; 1426e3adcf8fSFrançois Tigeot 14271b13d190SFrançois Tigeot edid = to_intel_connector(connector)->detect_edid; 14281b13d190SFrançois Tigeot if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) 1429e3adcf8fSFrançois Tigeot has_audio = drm_detect_monitor_audio(edid); 1430ba55f2f5SFrançois Tigeot 1431e3adcf8fSFrançois Tigeot return has_audio; 1432e3adcf8fSFrançois Tigeot } 1433e3adcf8fSFrançois Tigeot 1434e3adcf8fSFrançois Tigeot static int 1435e3adcf8fSFrançois Tigeot intel_hdmi_set_property(struct drm_connector *connector, 1436e3adcf8fSFrançois Tigeot struct drm_property *property, 1437e3adcf8fSFrançois Tigeot uint64_t val) 1438e3adcf8fSFrançois Tigeot { 1439e3adcf8fSFrançois Tigeot struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 144019df918dSFrançois Tigeot struct intel_digital_port *intel_dig_port = 144119df918dSFrançois Tigeot hdmi_to_dig_port(intel_hdmi); 1442e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = connector->dev->dev_private; 1443e3adcf8fSFrançois Tigeot int ret; 1444e3adcf8fSFrançois Tigeot 1445b5162e19SFrançois Tigeot ret = drm_object_property_set_value(&connector->base, property, val); 1446e3adcf8fSFrançois Tigeot if (ret) 1447e3adcf8fSFrançois Tigeot return ret; 1448e3adcf8fSFrançois Tigeot 1449e3adcf8fSFrançois Tigeot if (property == dev_priv->force_audio_property) { 1450e3adcf8fSFrançois Tigeot enum hdmi_force_audio i = val; 1451e3adcf8fSFrançois Tigeot bool has_audio; 1452e3adcf8fSFrançois Tigeot 1453e3adcf8fSFrançois Tigeot if (i == intel_hdmi->force_audio) 1454e3adcf8fSFrançois Tigeot return 0; 1455e3adcf8fSFrançois Tigeot 1456e3adcf8fSFrançois Tigeot intel_hdmi->force_audio = i; 1457e3adcf8fSFrançois Tigeot 1458e3adcf8fSFrançois Tigeot if (i == HDMI_AUDIO_AUTO) 1459e3adcf8fSFrançois Tigeot has_audio = intel_hdmi_detect_audio(connector); 1460e3adcf8fSFrançois Tigeot else 1461e3adcf8fSFrançois Tigeot has_audio = (i == HDMI_AUDIO_ON); 1462e3adcf8fSFrançois Tigeot 1463e3adcf8fSFrançois Tigeot if (i == HDMI_AUDIO_OFF_DVI) 1464e3adcf8fSFrançois Tigeot intel_hdmi->has_hdmi_sink = 0; 1465e3adcf8fSFrançois Tigeot 1466e3adcf8fSFrançois Tigeot intel_hdmi->has_audio = has_audio; 1467e3adcf8fSFrançois Tigeot goto done; 1468e3adcf8fSFrançois Tigeot } 1469e3adcf8fSFrançois Tigeot 1470e3adcf8fSFrançois Tigeot if (property == dev_priv->broadcast_rgb_property) { 14718e26cdf6SFrançois Tigeot bool old_auto = intel_hdmi->color_range_auto; 14728e26cdf6SFrançois Tigeot uint32_t old_range = intel_hdmi->color_range; 14738e26cdf6SFrançois Tigeot 1474a2fdbec6SFrançois Tigeot switch (val) { 1475a2fdbec6SFrançois Tigeot case INTEL_BROADCAST_RGB_AUTO: 1476a2fdbec6SFrançois Tigeot intel_hdmi->color_range_auto = true; 1477a2fdbec6SFrançois Tigeot break; 1478a2fdbec6SFrançois Tigeot case INTEL_BROADCAST_RGB_FULL: 1479a2fdbec6SFrançois Tigeot intel_hdmi->color_range_auto = false; 1480a2fdbec6SFrançois Tigeot intel_hdmi->color_range = 0; 1481a2fdbec6SFrançois Tigeot break; 1482a2fdbec6SFrançois Tigeot case INTEL_BROADCAST_RGB_LIMITED: 1483a2fdbec6SFrançois Tigeot intel_hdmi->color_range_auto = false; 14848e26cdf6SFrançois Tigeot intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235; 1485a2fdbec6SFrançois Tigeot break; 1486a2fdbec6SFrançois Tigeot default: 1487a2fdbec6SFrançois Tigeot return -EINVAL; 1488a2fdbec6SFrançois Tigeot } 14898e26cdf6SFrançois Tigeot 14908e26cdf6SFrançois Tigeot if (old_auto == intel_hdmi->color_range_auto && 14918e26cdf6SFrançois Tigeot old_range == intel_hdmi->color_range) 14928e26cdf6SFrançois Tigeot return 0; 14938e26cdf6SFrançois Tigeot 1494e3adcf8fSFrançois Tigeot goto done; 1495e3adcf8fSFrançois Tigeot } 1496e3adcf8fSFrançois Tigeot 149724edb884SFrançois Tigeot if (property == connector->dev->mode_config.aspect_ratio_property) { 149824edb884SFrançois Tigeot switch (val) { 149924edb884SFrançois Tigeot case DRM_MODE_PICTURE_ASPECT_NONE: 150024edb884SFrançois Tigeot intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_NONE; 150124edb884SFrançois Tigeot break; 150224edb884SFrançois Tigeot case DRM_MODE_PICTURE_ASPECT_4_3: 150324edb884SFrançois Tigeot intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_4_3; 150424edb884SFrançois Tigeot break; 150524edb884SFrançois Tigeot case DRM_MODE_PICTURE_ASPECT_16_9: 150624edb884SFrançois Tigeot intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_16_9; 150724edb884SFrançois Tigeot break; 150824edb884SFrançois Tigeot default: 150924edb884SFrançois Tigeot return -EINVAL; 151024edb884SFrançois Tigeot } 151124edb884SFrançois Tigeot goto done; 151224edb884SFrançois Tigeot } 151324edb884SFrançois Tigeot 1514e3adcf8fSFrançois Tigeot return -EINVAL; 1515e3adcf8fSFrançois Tigeot 1516e3adcf8fSFrançois Tigeot done: 1517a2fdbec6SFrançois Tigeot if (intel_dig_port->base.base.crtc) 1518a2fdbec6SFrançois Tigeot intel_crtc_restore_mode(intel_dig_port->base.base.crtc); 1519e3adcf8fSFrançois Tigeot 1520e3adcf8fSFrançois Tigeot return 0; 1521e3adcf8fSFrançois Tigeot } 1522e3adcf8fSFrançois Tigeot 1523ba55f2f5SFrançois Tigeot static void intel_hdmi_pre_enable(struct intel_encoder *encoder) 1524ba55f2f5SFrançois Tigeot { 1525ba55f2f5SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 1526ba55f2f5SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); 1527ba55f2f5SFrançois Tigeot struct drm_display_mode *adjusted_mode = 15282c9916cdSFrançois Tigeot &intel_crtc->config->base.adjusted_mode; 1529ba55f2f5SFrançois Tigeot 1530ba55f2f5SFrançois Tigeot intel_hdmi_prepare(encoder); 1531ba55f2f5SFrançois Tigeot 1532ba55f2f5SFrançois Tigeot intel_hdmi->set_infoframes(&encoder->base, 15332c9916cdSFrançois Tigeot intel_crtc->config->has_hdmi_sink, 1534ba55f2f5SFrançois Tigeot adjusted_mode); 1535ba55f2f5SFrançois Tigeot } 1536ba55f2f5SFrançois Tigeot 15379edbd4a0SFrançois Tigeot static void vlv_hdmi_pre_enable(struct intel_encoder *encoder) 15385d0b1887SFrançois Tigeot { 15395d0b1887SFrançois Tigeot struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); 1540ba55f2f5SFrançois Tigeot struct intel_hdmi *intel_hdmi = &dport->hdmi; 15415d0b1887SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 15425d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 15435d0b1887SFrançois Tigeot struct intel_crtc *intel_crtc = 15445d0b1887SFrançois Tigeot to_intel_crtc(encoder->base.crtc); 1545ba55f2f5SFrançois Tigeot struct drm_display_mode *adjusted_mode = 15462c9916cdSFrançois Tigeot &intel_crtc->config->base.adjusted_mode; 15479edbd4a0SFrançois Tigeot enum dpio_channel port = vlv_dport_to_channel(dport); 15485d0b1887SFrançois Tigeot int pipe = intel_crtc->pipe; 15495d0b1887SFrançois Tigeot u32 val; 15505d0b1887SFrançois Tigeot 15515d0b1887SFrançois Tigeot /* Enable clock channels for this port */ 155219c468b4SFrançois Tigeot mutex_lock(&dev_priv->sb_lock); 15539edbd4a0SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(port)); 15545d0b1887SFrançois Tigeot val = 0; 15555d0b1887SFrançois Tigeot if (pipe) 15565d0b1887SFrançois Tigeot val |= (1<<21); 15575d0b1887SFrançois Tigeot else 15585d0b1887SFrançois Tigeot val &= ~(1<<21); 15595d0b1887SFrançois Tigeot val |= 0x001000c4; 15609edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW8(port), val); 15615d0b1887SFrançois Tigeot 15625d0b1887SFrançois Tigeot /* HDMI 1.0V-2dB */ 15639edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), 0); 15649edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW4(port), 0x2b245f5f); 15659edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW2(port), 0x5578b83a); 15669edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW3(port), 0x0c782040); 15679edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX3_DW4(port), 0x2b247878); 15689edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW11(port), 0x00030000); 15699edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW9(port), 0x00002000); 15709edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), DPIO_TX_OCALINIT_EN); 15715d0b1887SFrançois Tigeot 15725d0b1887SFrançois Tigeot /* Program lane clock */ 15739edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW14(port), 0x00760018); 15749edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW23(port), 0x00400888); 157519c468b4SFrançois Tigeot mutex_unlock(&dev_priv->sb_lock); 15769edbd4a0SFrançois Tigeot 1577ba55f2f5SFrançois Tigeot intel_hdmi->set_infoframes(&encoder->base, 15782c9916cdSFrançois Tigeot intel_crtc->config->has_hdmi_sink, 1579ba55f2f5SFrançois Tigeot adjusted_mode); 1580ba55f2f5SFrançois Tigeot 1581*a05eeebfSFrançois Tigeot g4x_enable_hdmi(encoder); 15829edbd4a0SFrançois Tigeot 158319c468b4SFrançois Tigeot vlv_wait_port_ready(dev_priv, dport, 0x0); 15845d0b1887SFrançois Tigeot } 15855d0b1887SFrançois Tigeot 15869edbd4a0SFrançois Tigeot static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder) 15875d0b1887SFrançois Tigeot { 15885d0b1887SFrançois Tigeot struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); 15895d0b1887SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 15905d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 15919edbd4a0SFrançois Tigeot struct intel_crtc *intel_crtc = 15929edbd4a0SFrançois Tigeot to_intel_crtc(encoder->base.crtc); 15939edbd4a0SFrançois Tigeot enum dpio_channel port = vlv_dport_to_channel(dport); 15949edbd4a0SFrançois Tigeot int pipe = intel_crtc->pipe; 15955d0b1887SFrançois Tigeot 1596ba55f2f5SFrançois Tigeot intel_hdmi_prepare(encoder); 15975d0b1887SFrançois Tigeot 15985d0b1887SFrançois Tigeot /* Program Tx lane resets to default */ 159919c468b4SFrançois Tigeot mutex_lock(&dev_priv->sb_lock); 16009edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), 16015d0b1887SFrançois Tigeot DPIO_PCS_TX_LANE2_RESET | 16025d0b1887SFrançois Tigeot DPIO_PCS_TX_LANE1_RESET); 16039edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), 16045d0b1887SFrançois Tigeot DPIO_PCS_CLK_CRI_RXEB_EIOS_EN | 16055d0b1887SFrançois Tigeot DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN | 16065d0b1887SFrançois Tigeot (1<<DPIO_PCS_CLK_DATAWIDTH_SHIFT) | 16075d0b1887SFrançois Tigeot DPIO_PCS_CLK_SOFT_RESET); 16085d0b1887SFrançois Tigeot 16095d0b1887SFrançois Tigeot /* Fix up inter-pair skew failure */ 16109edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW12(port), 0x00750f00); 16119edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW11(port), 0x00001500); 16129edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW14(port), 0x40400000); 16135d0b1887SFrançois Tigeot 16149edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW9(port), 0x00002000); 16159edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), DPIO_TX_OCALINIT_EN); 161619c468b4SFrançois Tigeot mutex_unlock(&dev_priv->sb_lock); 16175d0b1887SFrançois Tigeot } 16185d0b1887SFrançois Tigeot 161924edb884SFrançois Tigeot static void chv_hdmi_pre_pll_enable(struct intel_encoder *encoder) 162024edb884SFrançois Tigeot { 162124edb884SFrançois Tigeot struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); 162224edb884SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 162324edb884SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 162424edb884SFrançois Tigeot struct intel_crtc *intel_crtc = 162524edb884SFrançois Tigeot to_intel_crtc(encoder->base.crtc); 162624edb884SFrançois Tigeot enum dpio_channel ch = vlv_dport_to_channel(dport); 162724edb884SFrançois Tigeot enum i915_pipe pipe = intel_crtc->pipe; 162824edb884SFrançois Tigeot u32 val; 162924edb884SFrançois Tigeot 16301b13d190SFrançois Tigeot intel_hdmi_prepare(encoder); 16311b13d190SFrançois Tigeot 163219c468b4SFrançois Tigeot mutex_lock(&dev_priv->sb_lock); 163324edb884SFrançois Tigeot 163424edb884SFrançois Tigeot /* program left/right clock distribution */ 163524edb884SFrançois Tigeot if (pipe != PIPE_B) { 163624edb884SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW5_CH0); 163724edb884SFrançois Tigeot val &= ~(CHV_BUFLEFTENA1_MASK | CHV_BUFRIGHTENA1_MASK); 163824edb884SFrançois Tigeot if (ch == DPIO_CH0) 163924edb884SFrançois Tigeot val |= CHV_BUFLEFTENA1_FORCE; 164024edb884SFrançois Tigeot if (ch == DPIO_CH1) 164124edb884SFrançois Tigeot val |= CHV_BUFRIGHTENA1_FORCE; 164224edb884SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW5_CH0, val); 164324edb884SFrançois Tigeot } else { 164424edb884SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW1_CH1); 164524edb884SFrançois Tigeot val &= ~(CHV_BUFLEFTENA2_MASK | CHV_BUFRIGHTENA2_MASK); 164624edb884SFrançois Tigeot if (ch == DPIO_CH0) 164724edb884SFrançois Tigeot val |= CHV_BUFLEFTENA2_FORCE; 164824edb884SFrançois Tigeot if (ch == DPIO_CH1) 164924edb884SFrançois Tigeot val |= CHV_BUFRIGHTENA2_FORCE; 165024edb884SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW1_CH1, val); 165124edb884SFrançois Tigeot } 165224edb884SFrançois Tigeot 165324edb884SFrançois Tigeot /* program clock channel usage */ 165424edb884SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(ch)); 165524edb884SFrançois Tigeot val |= CHV_PCS_USEDCLKCHANNEL_OVRRIDE; 165624edb884SFrançois Tigeot if (pipe != PIPE_B) 165724edb884SFrançois Tigeot val &= ~CHV_PCS_USEDCLKCHANNEL; 165824edb884SFrançois Tigeot else 165924edb884SFrançois Tigeot val |= CHV_PCS_USEDCLKCHANNEL; 166024edb884SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW8(ch), val); 166124edb884SFrançois Tigeot 166224edb884SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW8(ch)); 166324edb884SFrançois Tigeot val |= CHV_PCS_USEDCLKCHANNEL_OVRRIDE; 166424edb884SFrançois Tigeot if (pipe != PIPE_B) 166524edb884SFrançois Tigeot val &= ~CHV_PCS_USEDCLKCHANNEL; 166624edb884SFrançois Tigeot else 166724edb884SFrançois Tigeot val |= CHV_PCS_USEDCLKCHANNEL; 166824edb884SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW8(ch), val); 166924edb884SFrançois Tigeot 167024edb884SFrançois Tigeot /* 167124edb884SFrançois Tigeot * This a a bit weird since generally CL 167224edb884SFrançois Tigeot * matches the pipe, but here we need to 167324edb884SFrançois Tigeot * pick the CL based on the port. 167424edb884SFrançois Tigeot */ 167524edb884SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW19(ch)); 167624edb884SFrançois Tigeot if (pipe != PIPE_B) 167724edb884SFrançois Tigeot val &= ~CHV_CMN_USEDCLKCHANNEL; 167824edb884SFrançois Tigeot else 167924edb884SFrançois Tigeot val |= CHV_CMN_USEDCLKCHANNEL; 168024edb884SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW19(ch), val); 168124edb884SFrançois Tigeot 168219c468b4SFrançois Tigeot mutex_unlock(&dev_priv->sb_lock); 168324edb884SFrançois Tigeot } 168424edb884SFrançois Tigeot 16859edbd4a0SFrançois Tigeot static void vlv_hdmi_post_disable(struct intel_encoder *encoder) 16865d0b1887SFrançois Tigeot { 16875d0b1887SFrançois Tigeot struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); 16885d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; 16899edbd4a0SFrançois Tigeot struct intel_crtc *intel_crtc = 16909edbd4a0SFrançois Tigeot to_intel_crtc(encoder->base.crtc); 16919edbd4a0SFrançois Tigeot enum dpio_channel port = vlv_dport_to_channel(dport); 16929edbd4a0SFrançois Tigeot int pipe = intel_crtc->pipe; 16935d0b1887SFrançois Tigeot 16945d0b1887SFrançois Tigeot /* Reset lanes to avoid HDMI flicker (VLV w/a) */ 169519c468b4SFrançois Tigeot mutex_lock(&dev_priv->sb_lock); 16969edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), 0x00000000); 16979edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), 0x00e00060); 169819c468b4SFrançois Tigeot mutex_unlock(&dev_priv->sb_lock); 16995d0b1887SFrançois Tigeot } 17005d0b1887SFrançois Tigeot 1701ba55f2f5SFrançois Tigeot static void chv_hdmi_post_disable(struct intel_encoder *encoder) 1702ba55f2f5SFrançois Tigeot { 1703ba55f2f5SFrançois Tigeot struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); 1704ba55f2f5SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 1705ba55f2f5SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1706ba55f2f5SFrançois Tigeot struct intel_crtc *intel_crtc = 1707ba55f2f5SFrançois Tigeot to_intel_crtc(encoder->base.crtc); 1708ba55f2f5SFrançois Tigeot enum dpio_channel ch = vlv_dport_to_channel(dport); 1709ba55f2f5SFrançois Tigeot enum i915_pipe pipe = intel_crtc->pipe; 1710ba55f2f5SFrançois Tigeot u32 val; 1711ba55f2f5SFrançois Tigeot 171219c468b4SFrançois Tigeot mutex_lock(&dev_priv->sb_lock); 1713ba55f2f5SFrançois Tigeot 1714ba55f2f5SFrançois Tigeot /* Propagate soft reset to data lane reset */ 1715ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch)); 1716ba55f2f5SFrançois Tigeot val |= CHV_PCS_REQ_SOFTRESET_EN; 1717ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val); 1718ba55f2f5SFrançois Tigeot 1719ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch)); 1720ba55f2f5SFrançois Tigeot val |= CHV_PCS_REQ_SOFTRESET_EN; 1721ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val); 1722ba55f2f5SFrançois Tigeot 1723ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch)); 1724ba55f2f5SFrançois Tigeot val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); 1725ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val); 1726ba55f2f5SFrançois Tigeot 1727ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch)); 1728ba55f2f5SFrançois Tigeot val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); 1729ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val); 1730ba55f2f5SFrançois Tigeot 173119c468b4SFrançois Tigeot mutex_unlock(&dev_priv->sb_lock); 1732ba55f2f5SFrançois Tigeot } 1733ba55f2f5SFrançois Tigeot 1734ba55f2f5SFrançois Tigeot static void chv_hdmi_pre_enable(struct intel_encoder *encoder) 1735ba55f2f5SFrançois Tigeot { 1736ba55f2f5SFrançois Tigeot struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); 17372c9916cdSFrançois Tigeot struct intel_hdmi *intel_hdmi = &dport->hdmi; 1738ba55f2f5SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 1739ba55f2f5SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1740ba55f2f5SFrançois Tigeot struct intel_crtc *intel_crtc = 1741ba55f2f5SFrançois Tigeot to_intel_crtc(encoder->base.crtc); 17422c9916cdSFrançois Tigeot struct drm_display_mode *adjusted_mode = 17432c9916cdSFrançois Tigeot &intel_crtc->config->base.adjusted_mode; 1744ba55f2f5SFrançois Tigeot enum dpio_channel ch = vlv_dport_to_channel(dport); 1745ba55f2f5SFrançois Tigeot int pipe = intel_crtc->pipe; 174619c468b4SFrançois Tigeot int data, i, stagger; 1747ba55f2f5SFrançois Tigeot u32 val; 1748ba55f2f5SFrançois Tigeot 174919c468b4SFrançois Tigeot mutex_lock(&dev_priv->sb_lock); 1750ba55f2f5SFrançois Tigeot 17512c9916cdSFrançois Tigeot /* allow hardware to manage TX FIFO reset source */ 17522c9916cdSFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW11(ch)); 17532c9916cdSFrançois Tigeot val &= ~DPIO_LANEDESKEW_STRAP_OVRD; 17542c9916cdSFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val); 17552c9916cdSFrançois Tigeot 17562c9916cdSFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch)); 17572c9916cdSFrançois Tigeot val &= ~DPIO_LANEDESKEW_STRAP_OVRD; 17582c9916cdSFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val); 17592c9916cdSFrançois Tigeot 1760ba55f2f5SFrançois Tigeot /* Deassert soft data lane reset*/ 1761ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch)); 1762ba55f2f5SFrançois Tigeot val |= CHV_PCS_REQ_SOFTRESET_EN; 1763ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val); 1764ba55f2f5SFrançois Tigeot 1765ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch)); 1766ba55f2f5SFrançois Tigeot val |= CHV_PCS_REQ_SOFTRESET_EN; 1767ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val); 1768ba55f2f5SFrançois Tigeot 1769ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch)); 1770ba55f2f5SFrançois Tigeot val |= (DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); 1771ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val); 1772ba55f2f5SFrançois Tigeot 1773ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch)); 1774ba55f2f5SFrançois Tigeot val |= (DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); 1775ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val); 1776ba55f2f5SFrançois Tigeot 1777ba55f2f5SFrançois Tigeot /* Program Tx latency optimal setting */ 1778ba55f2f5SFrançois Tigeot for (i = 0; i < 4; i++) { 1779ba55f2f5SFrançois Tigeot /* Set the upar bit */ 1780ba55f2f5SFrançois Tigeot data = (i == 1) ? 0x0 : 0x1; 1781ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, CHV_TX_DW14(ch, i), 1782ba55f2f5SFrançois Tigeot data << DPIO_UPAR_SHIFT); 1783ba55f2f5SFrançois Tigeot } 1784ba55f2f5SFrançois Tigeot 1785ba55f2f5SFrançois Tigeot /* Data lane stagger programming */ 178619c468b4SFrançois Tigeot if (intel_crtc->config->port_clock > 270000) 178719c468b4SFrançois Tigeot stagger = 0x18; 178819c468b4SFrançois Tigeot else if (intel_crtc->config->port_clock > 135000) 178919c468b4SFrançois Tigeot stagger = 0xd; 179019c468b4SFrançois Tigeot else if (intel_crtc->config->port_clock > 67500) 179119c468b4SFrançois Tigeot stagger = 0x7; 179219c468b4SFrançois Tigeot else if (intel_crtc->config->port_clock > 33750) 179319c468b4SFrançois Tigeot stagger = 0x4; 179419c468b4SFrançois Tigeot else 179519c468b4SFrançois Tigeot stagger = 0x2; 179619c468b4SFrançois Tigeot 179719c468b4SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW11(ch)); 179819c468b4SFrançois Tigeot val |= DPIO_TX2_STAGGER_MASK(0x1f); 179919c468b4SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val); 180019c468b4SFrançois Tigeot 180119c468b4SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch)); 180219c468b4SFrançois Tigeot val |= DPIO_TX2_STAGGER_MASK(0x1f); 180319c468b4SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val); 180419c468b4SFrançois Tigeot 180519c468b4SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW12(ch), 180619c468b4SFrançois Tigeot DPIO_LANESTAGGER_STRAP(stagger) | 180719c468b4SFrançois Tigeot DPIO_LANESTAGGER_STRAP_OVRD | 180819c468b4SFrançois Tigeot DPIO_TX1_STAGGER_MASK(0x1f) | 180919c468b4SFrançois Tigeot DPIO_TX1_STAGGER_MULT(6) | 181019c468b4SFrançois Tigeot DPIO_TX2_STAGGER_MULT(0)); 181119c468b4SFrançois Tigeot 181219c468b4SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW12(ch), 181319c468b4SFrançois Tigeot DPIO_LANESTAGGER_STRAP(stagger) | 181419c468b4SFrançois Tigeot DPIO_LANESTAGGER_STRAP_OVRD | 181519c468b4SFrançois Tigeot DPIO_TX1_STAGGER_MASK(0x1f) | 181619c468b4SFrançois Tigeot DPIO_TX1_STAGGER_MULT(7) | 181719c468b4SFrançois Tigeot DPIO_TX2_STAGGER_MULT(5)); 1818ba55f2f5SFrançois Tigeot 1819ba55f2f5SFrançois Tigeot /* Clear calc init */ 1820ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW10(ch)); 1821ba55f2f5SFrançois Tigeot val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3); 18222c9916cdSFrançois Tigeot val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK); 18232c9916cdSFrançois Tigeot val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5; 1824ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val); 1825ba55f2f5SFrançois Tigeot 1826ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch)); 1827ba55f2f5SFrançois Tigeot val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3); 18282c9916cdSFrançois Tigeot val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK); 18292c9916cdSFrançois Tigeot val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5; 1830ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val); 1831ba55f2f5SFrançois Tigeot 18322c9916cdSFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW9(ch)); 18332c9916cdSFrançois Tigeot val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK); 18342c9916cdSFrançois Tigeot val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000; 18352c9916cdSFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW9(ch), val); 18362c9916cdSFrançois Tigeot 18372c9916cdSFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW9(ch)); 18382c9916cdSFrançois Tigeot val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK); 18392c9916cdSFrançois Tigeot val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000; 18402c9916cdSFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW9(ch), val); 18412c9916cdSFrançois Tigeot 1842ba55f2f5SFrançois Tigeot /* FIXME: Program the support xxx V-dB */ 1843ba55f2f5SFrançois Tigeot /* Use 800mV-0dB */ 1844ba55f2f5SFrançois Tigeot for (i = 0; i < 4; i++) { 1845ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW4(ch, i)); 1846ba55f2f5SFrançois Tigeot val &= ~DPIO_SWING_DEEMPH9P5_MASK; 1847ba55f2f5SFrançois Tigeot val |= 128 << DPIO_SWING_DEEMPH9P5_SHIFT; 1848ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, CHV_TX_DW4(ch, i), val); 1849ba55f2f5SFrançois Tigeot } 1850ba55f2f5SFrançois Tigeot 1851ba55f2f5SFrançois Tigeot for (i = 0; i < 4; i++) { 1852ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i)); 18531b13d190SFrançois Tigeot val &= ~DPIO_SWING_MARGIN000_MASK; 18541b13d190SFrançois Tigeot val |= 102 << DPIO_SWING_MARGIN000_SHIFT; 1855ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, CHV_TX_DW2(ch, i), val); 1856ba55f2f5SFrançois Tigeot } 1857ba55f2f5SFrançois Tigeot 1858ba55f2f5SFrançois Tigeot /* Disable unique transition scale */ 1859ba55f2f5SFrançois Tigeot for (i = 0; i < 4; i++) { 1860ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW3(ch, i)); 1861ba55f2f5SFrançois Tigeot val &= ~DPIO_TX_UNIQ_TRANS_SCALE_EN; 1862ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, CHV_TX_DW3(ch, i), val); 1863ba55f2f5SFrançois Tigeot } 1864ba55f2f5SFrançois Tigeot 1865ba55f2f5SFrançois Tigeot /* Additional steps for 1200mV-0dB */ 1866ba55f2f5SFrançois Tigeot #if 0 1867ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_TX_DW3(ch)); 1868ba55f2f5SFrançois Tigeot if (ch) 1869ba55f2f5SFrançois Tigeot val |= DPIO_TX_UNIQ_TRANS_SCALE_CH1; 1870ba55f2f5SFrançois Tigeot else 1871ba55f2f5SFrançois Tigeot val |= DPIO_TX_UNIQ_TRANS_SCALE_CH0; 1872ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW3(ch), val); 1873ba55f2f5SFrançois Tigeot 1874ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW2(ch), 1875ba55f2f5SFrançois Tigeot vlv_dpio_read(dev_priv, pipe, VLV_TX_DW2(ch)) | 1876ba55f2f5SFrançois Tigeot (0x9a << DPIO_UNIQ_TRANS_SCALE_SHIFT)); 1877ba55f2f5SFrançois Tigeot #endif 1878ba55f2f5SFrançois Tigeot /* Start swing calculation */ 1879ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW10(ch)); 1880ba55f2f5SFrançois Tigeot val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3; 1881ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val); 1882ba55f2f5SFrançois Tigeot 1883ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch)); 1884ba55f2f5SFrançois Tigeot val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3; 1885ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val); 1886ba55f2f5SFrançois Tigeot 1887ba55f2f5SFrançois Tigeot /* LRC Bypass */ 1888ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW30); 1889ba55f2f5SFrançois Tigeot val |= DPIO_LRC_BYPASS; 1890ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW30, val); 1891ba55f2f5SFrançois Tigeot 189219c468b4SFrançois Tigeot mutex_unlock(&dev_priv->sb_lock); 1893ba55f2f5SFrançois Tigeot 18942c9916cdSFrançois Tigeot intel_hdmi->set_infoframes(&encoder->base, 18952c9916cdSFrançois Tigeot intel_crtc->config->has_hdmi_sink, 18962c9916cdSFrançois Tigeot adjusted_mode); 18972c9916cdSFrançois Tigeot 1898*a05eeebfSFrançois Tigeot g4x_enable_hdmi(encoder); 1899ba55f2f5SFrançois Tigeot 190019c468b4SFrançois Tigeot vlv_wait_port_ready(dev_priv, dport, 0x0); 1901ba55f2f5SFrançois Tigeot } 1902ba55f2f5SFrançois Tigeot 1903e3adcf8fSFrançois Tigeot static void intel_hdmi_destroy(struct drm_connector *connector) 1904e3adcf8fSFrançois Tigeot { 19051b13d190SFrançois Tigeot kfree(to_intel_connector(connector)->detect_edid); 1906e3adcf8fSFrançois Tigeot drm_connector_cleanup(connector); 19078e26cdf6SFrançois Tigeot kfree(connector); 1908e3adcf8fSFrançois Tigeot } 1909e3adcf8fSFrançois Tigeot 1910e3adcf8fSFrançois Tigeot static const struct drm_connector_funcs intel_hdmi_connector_funcs = { 1911*a05eeebfSFrançois Tigeot .dpms = drm_atomic_helper_connector_dpms, 1912e3adcf8fSFrançois Tigeot .detect = intel_hdmi_detect, 19131b13d190SFrançois Tigeot .force = intel_hdmi_force, 1914e3adcf8fSFrançois Tigeot .fill_modes = drm_helper_probe_single_connector_modes, 1915e3adcf8fSFrançois Tigeot .set_property = intel_hdmi_set_property, 19162c9916cdSFrançois Tigeot .atomic_get_property = intel_connector_atomic_get_property, 1917e3adcf8fSFrançois Tigeot .destroy = intel_hdmi_destroy, 19182c9916cdSFrançois Tigeot .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 1919477eb7f9SFrançois Tigeot .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 1920e3adcf8fSFrançois Tigeot }; 1921e3adcf8fSFrançois Tigeot 1922e3adcf8fSFrançois Tigeot static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = { 1923e3adcf8fSFrançois Tigeot .get_modes = intel_hdmi_get_modes, 1924e3adcf8fSFrançois Tigeot .mode_valid = intel_hdmi_mode_valid, 1925e3adcf8fSFrançois Tigeot .best_encoder = intel_best_encoder, 1926e3adcf8fSFrançois Tigeot }; 1927e3adcf8fSFrançois Tigeot 1928e3adcf8fSFrançois Tigeot static const struct drm_encoder_funcs intel_hdmi_enc_funcs = { 1929e3adcf8fSFrançois Tigeot .destroy = intel_encoder_destroy, 1930e3adcf8fSFrançois Tigeot }; 1931e3adcf8fSFrançois Tigeot 1932e3adcf8fSFrançois Tigeot static void 193324edb884SFrançois Tigeot intel_attach_aspect_ratio_property(struct drm_connector *connector) 193424edb884SFrançois Tigeot { 193524edb884SFrançois Tigeot if (!drm_mode_create_aspect_ratio_property(connector->dev)) 193624edb884SFrançois Tigeot drm_object_attach_property(&connector->base, 193724edb884SFrançois Tigeot connector->dev->mode_config.aspect_ratio_property, 193824edb884SFrançois Tigeot DRM_MODE_PICTURE_ASPECT_NONE); 193924edb884SFrançois Tigeot } 194024edb884SFrançois Tigeot 194124edb884SFrançois Tigeot static void 1942e3adcf8fSFrançois Tigeot intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector) 1943e3adcf8fSFrançois Tigeot { 1944e3adcf8fSFrançois Tigeot intel_attach_force_audio_property(connector); 1945e3adcf8fSFrançois Tigeot intel_attach_broadcast_rgb_property(connector); 1946a2fdbec6SFrançois Tigeot intel_hdmi->color_range_auto = true; 194724edb884SFrançois Tigeot intel_attach_aspect_ratio_property(connector); 194824edb884SFrançois Tigeot intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_NONE; 1949e3adcf8fSFrançois Tigeot } 1950e3adcf8fSFrançois Tigeot 195119df918dSFrançois Tigeot void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, 195219df918dSFrançois Tigeot struct intel_connector *intel_connector) 1953e3adcf8fSFrançois Tigeot { 195419df918dSFrançois Tigeot struct drm_connector *connector = &intel_connector->base; 195519df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; 195619df918dSFrançois Tigeot struct intel_encoder *intel_encoder = &intel_dig_port->base; 195719df918dSFrançois Tigeot struct drm_device *dev = intel_encoder->base.dev; 1958e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 195919df918dSFrançois Tigeot enum port port = intel_dig_port->port; 1960*a05eeebfSFrançois Tigeot uint8_t alternate_ddc_pin; 1961e3adcf8fSFrançois Tigeot 1962e3adcf8fSFrançois Tigeot drm_connector_init(dev, connector, &intel_hdmi_connector_funcs, 1963e3adcf8fSFrançois Tigeot DRM_MODE_CONNECTOR_HDMIA); 1964e3adcf8fSFrançois Tigeot drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs); 1965e3adcf8fSFrançois Tigeot 1966e3adcf8fSFrançois Tigeot connector->interlace_allowed = 1; 1967e3adcf8fSFrançois Tigeot connector->doublescan_allowed = 0; 19689edbd4a0SFrançois Tigeot connector->stereo_allowed = 1; 1969e3adcf8fSFrançois Tigeot 197019df918dSFrançois Tigeot switch (port) { 197119df918dSFrançois Tigeot case PORT_B: 197219c468b4SFrançois Tigeot if (IS_BROXTON(dev_priv)) 197319c468b4SFrançois Tigeot intel_hdmi->ddc_bus = GMBUS_PIN_1_BXT; 197419c468b4SFrançois Tigeot else 197519c468b4SFrançois Tigeot intel_hdmi->ddc_bus = GMBUS_PIN_DPB; 19768e26cdf6SFrançois Tigeot intel_encoder->hpd_pin = HPD_PORT_B; 197719df918dSFrançois Tigeot break; 197819df918dSFrançois Tigeot case PORT_C: 197919c468b4SFrançois Tigeot if (IS_BROXTON(dev_priv)) 198019c468b4SFrançois Tigeot intel_hdmi->ddc_bus = GMBUS_PIN_2_BXT; 198119c468b4SFrançois Tigeot else 198219c468b4SFrançois Tigeot intel_hdmi->ddc_bus = GMBUS_PIN_DPC; 19838e26cdf6SFrançois Tigeot intel_encoder->hpd_pin = HPD_PORT_C; 198419df918dSFrançois Tigeot break; 198519df918dSFrançois Tigeot case PORT_D: 198619c468b4SFrançois Tigeot if (WARN_ON(IS_BROXTON(dev_priv))) 198719c468b4SFrançois Tigeot intel_hdmi->ddc_bus = GMBUS_PIN_DISABLED; 198819c468b4SFrançois Tigeot else if (IS_CHERRYVIEW(dev_priv)) 198919c468b4SFrançois Tigeot intel_hdmi->ddc_bus = GMBUS_PIN_DPD_CHV; 1990ba55f2f5SFrançois Tigeot else 199119c468b4SFrançois Tigeot intel_hdmi->ddc_bus = GMBUS_PIN_DPD; 19928e26cdf6SFrançois Tigeot intel_encoder->hpd_pin = HPD_PORT_D; 199319df918dSFrançois Tigeot break; 1994*a05eeebfSFrançois Tigeot case PORT_E: 1995*a05eeebfSFrançois Tigeot /* On SKL PORT E doesn't have seperate GMBUS pin 1996*a05eeebfSFrançois Tigeot * We rely on VBT to set a proper alternate GMBUS pin. */ 1997*a05eeebfSFrançois Tigeot alternate_ddc_pin = 1998*a05eeebfSFrançois Tigeot dev_priv->vbt.ddi_port_info[PORT_E].alternate_ddc_pin; 1999*a05eeebfSFrançois Tigeot switch (alternate_ddc_pin) { 2000*a05eeebfSFrançois Tigeot case DDC_PIN_B: 2001*a05eeebfSFrançois Tigeot intel_hdmi->ddc_bus = GMBUS_PIN_DPB; 2002*a05eeebfSFrançois Tigeot break; 2003*a05eeebfSFrançois Tigeot case DDC_PIN_C: 2004*a05eeebfSFrançois Tigeot intel_hdmi->ddc_bus = GMBUS_PIN_DPC; 2005*a05eeebfSFrançois Tigeot break; 2006*a05eeebfSFrançois Tigeot case DDC_PIN_D: 2007*a05eeebfSFrançois Tigeot intel_hdmi->ddc_bus = GMBUS_PIN_DPD; 2008*a05eeebfSFrançois Tigeot break; 2009*a05eeebfSFrançois Tigeot default: 2010*a05eeebfSFrançois Tigeot MISSING_CASE(alternate_ddc_pin); 2011*a05eeebfSFrançois Tigeot } 2012*a05eeebfSFrançois Tigeot intel_encoder->hpd_pin = HPD_PORT_E; 2013*a05eeebfSFrançois Tigeot break; 201419df918dSFrançois Tigeot case PORT_A: 20158e26cdf6SFrançois Tigeot intel_encoder->hpd_pin = HPD_PORT_A; 201619df918dSFrançois Tigeot /* Internal port only for eDP. */ 201719df918dSFrançois Tigeot default: 201819df918dSFrançois Tigeot BUG(); 2019e3adcf8fSFrançois Tigeot } 2020e3adcf8fSFrançois Tigeot 20218e26cdf6SFrançois Tigeot if (IS_VALLEYVIEW(dev)) { 202219df918dSFrançois Tigeot intel_hdmi->write_infoframe = vlv_write_infoframe; 202319df918dSFrançois Tigeot intel_hdmi->set_infoframes = vlv_set_infoframes; 20242c9916cdSFrançois Tigeot intel_hdmi->infoframe_enabled = vlv_infoframe_enabled; 202524edb884SFrançois Tigeot } else if (IS_G4X(dev)) { 20268e26cdf6SFrançois Tigeot intel_hdmi->write_infoframe = g4x_write_infoframe; 20278e26cdf6SFrançois Tigeot intel_hdmi->set_infoframes = g4x_set_infoframes; 20282c9916cdSFrançois Tigeot intel_hdmi->infoframe_enabled = g4x_infoframe_enabled; 20298e26cdf6SFrançois Tigeot } else if (HAS_DDI(dev)) { 203019df918dSFrançois Tigeot intel_hdmi->write_infoframe = hsw_write_infoframe; 203119df918dSFrançois Tigeot intel_hdmi->set_infoframes = hsw_set_infoframes; 20322c9916cdSFrançois Tigeot intel_hdmi->infoframe_enabled = hsw_infoframe_enabled; 203319df918dSFrançois Tigeot } else if (HAS_PCH_IBX(dev)) { 203419df918dSFrançois Tigeot intel_hdmi->write_infoframe = ibx_write_infoframe; 203519df918dSFrançois Tigeot intel_hdmi->set_infoframes = ibx_set_infoframes; 20362c9916cdSFrançois Tigeot intel_hdmi->infoframe_enabled = ibx_infoframe_enabled; 2037e3adcf8fSFrançois Tigeot } else { 203819df918dSFrançois Tigeot intel_hdmi->write_infoframe = cpt_write_infoframe; 203919df918dSFrançois Tigeot intel_hdmi->set_infoframes = cpt_set_infoframes; 20402c9916cdSFrançois Tigeot intel_hdmi->infoframe_enabled = cpt_infoframe_enabled; 2041e3adcf8fSFrançois Tigeot } 2042e3adcf8fSFrançois Tigeot 2043a2fdbec6SFrançois Tigeot if (HAS_DDI(dev)) 204419df918dSFrançois Tigeot intel_connector->get_hw_state = intel_ddi_connector_get_hw_state; 204519df918dSFrançois Tigeot else 204619df918dSFrançois Tigeot intel_connector->get_hw_state = intel_connector_get_hw_state; 2047ba55f2f5SFrançois Tigeot intel_connector->unregister = intel_connector_unregister; 2048e3adcf8fSFrançois Tigeot 2049e3adcf8fSFrançois Tigeot intel_hdmi_add_properties(intel_hdmi, connector); 2050e3adcf8fSFrançois Tigeot 2051e3adcf8fSFrançois Tigeot intel_connector_attach_encoder(intel_connector, intel_encoder); 2052c6f73aabSFrançois Tigeot drm_connector_register(connector); 2053e3adcf8fSFrançois Tigeot 2054e3adcf8fSFrançois Tigeot /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written 2055e3adcf8fSFrançois Tigeot * 0xd. Failure to do so will result in spurious interrupts being 2056e3adcf8fSFrançois Tigeot * generated on the port when a cable is not attached. 2057e3adcf8fSFrançois Tigeot */ 2058e3adcf8fSFrançois Tigeot if (IS_G4X(dev) && !IS_GM45(dev)) { 2059e3adcf8fSFrançois Tigeot u32 temp = I915_READ(PEG_BAND_GAP_DATA); 2060e3adcf8fSFrançois Tigeot I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); 2061e3adcf8fSFrançois Tigeot } 2062e3adcf8fSFrançois Tigeot } 206319df918dSFrançois Tigeot 20648e26cdf6SFrançois Tigeot void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) 206519df918dSFrançois Tigeot { 206619df918dSFrançois Tigeot struct intel_digital_port *intel_dig_port; 206719df918dSFrançois Tigeot struct intel_encoder *intel_encoder; 206819df918dSFrançois Tigeot struct intel_connector *intel_connector; 206919df918dSFrançois Tigeot 20709edbd4a0SFrançois Tigeot intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL); 207119df918dSFrançois Tigeot if (!intel_dig_port) 207219df918dSFrançois Tigeot return; 207319df918dSFrançois Tigeot 2074477eb7f9SFrançois Tigeot intel_connector = intel_connector_alloc(); 207519df918dSFrançois Tigeot if (!intel_connector) { 2076158486a6SFrançois Tigeot kfree(intel_dig_port); 207719df918dSFrançois Tigeot return; 207819df918dSFrançois Tigeot } 207919df918dSFrançois Tigeot 208019df918dSFrançois Tigeot intel_encoder = &intel_dig_port->base; 208119df918dSFrançois Tigeot 208219df918dSFrançois Tigeot drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs, 208319df918dSFrançois Tigeot DRM_MODE_ENCODER_TMDS); 208419df918dSFrançois Tigeot 20858e26cdf6SFrançois Tigeot intel_encoder->compute_config = intel_hdmi_compute_config; 208619c468b4SFrançois Tigeot if (HAS_PCH_SPLIT(dev)) { 208719c468b4SFrançois Tigeot intel_encoder->disable = pch_disable_hdmi; 208819c468b4SFrançois Tigeot intel_encoder->post_disable = pch_post_disable_hdmi; 208919c468b4SFrançois Tigeot } else { 209019c468b4SFrançois Tigeot intel_encoder->disable = g4x_disable_hdmi; 209119c468b4SFrançois Tigeot } 209219df918dSFrançois Tigeot intel_encoder->get_hw_state = intel_hdmi_get_hw_state; 20935d0b1887SFrançois Tigeot intel_encoder->get_config = intel_hdmi_get_config; 2094ba55f2f5SFrançois Tigeot if (IS_CHERRYVIEW(dev)) { 209524edb884SFrançois Tigeot intel_encoder->pre_pll_enable = chv_hdmi_pre_pll_enable; 2096ba55f2f5SFrançois Tigeot intel_encoder->pre_enable = chv_hdmi_pre_enable; 2097ba55f2f5SFrançois Tigeot intel_encoder->enable = vlv_enable_hdmi; 2098ba55f2f5SFrançois Tigeot intel_encoder->post_disable = chv_hdmi_post_disable; 2099ba55f2f5SFrançois Tigeot } else if (IS_VALLEYVIEW(dev)) { 21009edbd4a0SFrançois Tigeot intel_encoder->pre_pll_enable = vlv_hdmi_pre_pll_enable; 21019edbd4a0SFrançois Tigeot intel_encoder->pre_enable = vlv_hdmi_pre_enable; 21029edbd4a0SFrançois Tigeot intel_encoder->enable = vlv_enable_hdmi; 21039edbd4a0SFrançois Tigeot intel_encoder->post_disable = vlv_hdmi_post_disable; 21049edbd4a0SFrançois Tigeot } else { 2105ba55f2f5SFrançois Tigeot intel_encoder->pre_enable = intel_hdmi_pre_enable; 2106*a05eeebfSFrançois Tigeot if (HAS_PCH_CPT(dev)) 2107*a05eeebfSFrançois Tigeot intel_encoder->enable = cpt_enable_hdmi; 2108*a05eeebfSFrançois Tigeot else if (HAS_PCH_IBX(dev)) 2109*a05eeebfSFrançois Tigeot intel_encoder->enable = ibx_enable_hdmi; 2110*a05eeebfSFrançois Tigeot else 2111*a05eeebfSFrançois Tigeot intel_encoder->enable = g4x_enable_hdmi; 21125d0b1887SFrançois Tigeot } 211319df918dSFrançois Tigeot 211419df918dSFrançois Tigeot intel_encoder->type = INTEL_OUTPUT_HDMI; 2115ba55f2f5SFrançois Tigeot if (IS_CHERRYVIEW(dev)) { 2116ba55f2f5SFrançois Tigeot if (port == PORT_D) 2117ba55f2f5SFrançois Tigeot intel_encoder->crtc_mask = 1 << 2; 2118ba55f2f5SFrançois Tigeot else 2119ba55f2f5SFrançois Tigeot intel_encoder->crtc_mask = (1 << 0) | (1 << 1); 2120ba55f2f5SFrançois Tigeot } else { 212119df918dSFrançois Tigeot intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); 2122ba55f2f5SFrançois Tigeot } 2123ba55f2f5SFrançois Tigeot intel_encoder->cloneable = 1 << INTEL_OUTPUT_ANALOG; 2124ba55f2f5SFrançois Tigeot /* 2125ba55f2f5SFrançois Tigeot * BSpec is unclear about HDMI+HDMI cloning on g4x, but it seems 2126ba55f2f5SFrançois Tigeot * to work on real hardware. And since g4x can send infoframes to 2127ba55f2f5SFrançois Tigeot * only one port anyway, nothing is lost by allowing it. 2128ba55f2f5SFrançois Tigeot */ 2129ba55f2f5SFrançois Tigeot if (IS_G4X(dev)) 2130ba55f2f5SFrançois Tigeot intel_encoder->cloneable |= 1 << INTEL_OUTPUT_HDMI; 213119df918dSFrançois Tigeot 213219df918dSFrançois Tigeot intel_dig_port->port = port; 21338e26cdf6SFrançois Tigeot intel_dig_port->hdmi.hdmi_reg = hdmi_reg; 213419df918dSFrançois Tigeot intel_dig_port->dp.output_reg = 0; 213519df918dSFrançois Tigeot 213619df918dSFrançois Tigeot intel_hdmi_init_connector(intel_dig_port, intel_connector); 213719df918dSFrançois Tigeot } 2138