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> 3318e26a6dSFrançois Tigeot #include <drm/drm_crtc.h> 3418e26a6dSFrançois Tigeot #include <drm/drm_edid.h> 3518e26a6dSFrançois Tigeot #include "intel_drv.h" 365c6c6f23SFrançois Tigeot #include <drm/i915_drm.h> 37e3adcf8fSFrançois Tigeot #include "i915_drv.h" 38e3adcf8fSFrançois Tigeot 3919df918dSFrançois Tigeot static struct drm_device *intel_hdmi_to_dev(struct intel_hdmi *intel_hdmi) 40e3adcf8fSFrançois Tigeot { 4119df918dSFrançois Tigeot return hdmi_to_dig_port(intel_hdmi)->base.base.dev; 4219df918dSFrançois Tigeot } 4319df918dSFrançois Tigeot 4419df918dSFrançois Tigeot static void 4519df918dSFrançois Tigeot assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi) 4619df918dSFrançois Tigeot { 4719df918dSFrançois Tigeot struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi); 4819df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 4919df918dSFrançois Tigeot uint32_t enabled_bits; 5019df918dSFrançois Tigeot 51a2fdbec6SFrançois Tigeot enabled_bits = HAS_DDI(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE; 5219df918dSFrançois Tigeot 538e26cdf6SFrançois Tigeot WARN(I915_READ(intel_hdmi->hdmi_reg) & enabled_bits, 5419df918dSFrançois Tigeot "HDMI port enabled, expecting disabled\n"); 5519df918dSFrançois Tigeot } 5619df918dSFrançois Tigeot 5719df918dSFrançois Tigeot struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) 5819df918dSFrançois Tigeot { 5919df918dSFrançois Tigeot struct intel_digital_port *intel_dig_port = 6019df918dSFrançois Tigeot container_of(encoder, struct intel_digital_port, base.base); 6119df918dSFrançois Tigeot return &intel_dig_port->hdmi; 62e3adcf8fSFrançois Tigeot } 63e3adcf8fSFrançois Tigeot 64e3adcf8fSFrançois Tigeot static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector) 65e3adcf8fSFrançois Tigeot { 6619df918dSFrançois Tigeot return enc_to_intel_hdmi(&intel_attached_encoder(connector)->base); 67e3adcf8fSFrançois Tigeot } 68e3adcf8fSFrançois Tigeot 699edbd4a0SFrançois Tigeot static u32 g4x_infoframe_index(enum hdmi_infoframe_type type) 70e3adcf8fSFrançois Tigeot { 719edbd4a0SFrançois Tigeot switch (type) { 729edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_AVI: 7319df918dSFrançois Tigeot return VIDEO_DIP_SELECT_AVI; 749edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_SPD: 7519df918dSFrançois Tigeot return VIDEO_DIP_SELECT_SPD; 769edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_VENDOR: 779edbd4a0SFrançois Tigeot return VIDEO_DIP_SELECT_VENDOR; 78e3adcf8fSFrançois Tigeot default: 799edbd4a0SFrançois Tigeot DRM_DEBUG_DRIVER("unknown info frame type %d\n", type); 8019df918dSFrançois Tigeot return 0; 8119df918dSFrançois Tigeot } 82e3adcf8fSFrançois Tigeot } 83e3adcf8fSFrançois Tigeot 849edbd4a0SFrançois Tigeot static u32 g4x_infoframe_enable(enum hdmi_infoframe_type type) 85e3adcf8fSFrançois Tigeot { 869edbd4a0SFrançois Tigeot switch (type) { 879edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_AVI: 8819df918dSFrançois Tigeot return VIDEO_DIP_ENABLE_AVI; 899edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_SPD: 9019df918dSFrançois Tigeot return VIDEO_DIP_ENABLE_SPD; 919edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_VENDOR: 929edbd4a0SFrançois Tigeot return VIDEO_DIP_ENABLE_VENDOR; 93e3adcf8fSFrançois Tigeot default: 949edbd4a0SFrançois Tigeot DRM_DEBUG_DRIVER("unknown info frame type %d\n", type); 9519df918dSFrançois Tigeot return 0; 9619df918dSFrançois Tigeot } 97e3adcf8fSFrançois Tigeot } 98e3adcf8fSFrançois Tigeot 999edbd4a0SFrançois Tigeot static u32 hsw_infoframe_enable(enum hdmi_infoframe_type type) 10019df918dSFrançois Tigeot { 1019edbd4a0SFrançois Tigeot switch (type) { 1029edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_AVI: 10319df918dSFrançois Tigeot return VIDEO_DIP_ENABLE_AVI_HSW; 1049edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_SPD: 10519df918dSFrançois Tigeot return VIDEO_DIP_ENABLE_SPD_HSW; 1069edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_VENDOR: 1079edbd4a0SFrançois Tigeot return VIDEO_DIP_ENABLE_VS_HSW; 10819df918dSFrançois Tigeot default: 1099edbd4a0SFrançois Tigeot DRM_DEBUG_DRIVER("unknown info frame type %d\n", type); 11019df918dSFrançois Tigeot return 0; 11119df918dSFrançois Tigeot } 112e3adcf8fSFrançois Tigeot } 113e3adcf8fSFrançois Tigeot 1149edbd4a0SFrançois Tigeot static u32 hsw_infoframe_data_reg(enum hdmi_infoframe_type type, 115*ba55f2f5SFrançois Tigeot enum transcoder cpu_transcoder, 116*ba55f2f5SFrançois Tigeot struct drm_i915_private *dev_priv) 11719df918dSFrançois Tigeot { 1189edbd4a0SFrançois Tigeot switch (type) { 1199edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_AVI: 1208e26cdf6SFrançois Tigeot return HSW_TVIDEO_DIP_AVI_DATA(cpu_transcoder); 1219edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_SPD: 1228e26cdf6SFrançois Tigeot return HSW_TVIDEO_DIP_SPD_DATA(cpu_transcoder); 1239edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_VENDOR: 1249edbd4a0SFrançois Tigeot return HSW_TVIDEO_DIP_VS_DATA(cpu_transcoder); 12519df918dSFrançois Tigeot default: 1269edbd4a0SFrançois Tigeot DRM_DEBUG_DRIVER("unknown info frame type %d\n", type); 12719df918dSFrançois Tigeot return 0; 12819df918dSFrançois Tigeot } 12919df918dSFrançois Tigeot } 13019df918dSFrançois Tigeot 13119df918dSFrançois Tigeot static void g4x_write_infoframe(struct drm_encoder *encoder, 1329edbd4a0SFrançois Tigeot enum hdmi_infoframe_type type, 1339edbd4a0SFrançois Tigeot const void *frame, ssize_t len) 134e3adcf8fSFrançois Tigeot { 1359edbd4a0SFrançois Tigeot const uint32_t *data = frame; 136e3adcf8fSFrançois Tigeot struct drm_device *dev = encoder->dev; 137e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 13819df918dSFrançois Tigeot u32 val = I915_READ(VIDEO_DIP_CTL); 1399edbd4a0SFrançois Tigeot int i; 140e3adcf8fSFrançois Tigeot 14119df918dSFrançois Tigeot WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n"); 142e3adcf8fSFrançois Tigeot 14319df918dSFrançois Tigeot val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ 1449edbd4a0SFrançois Tigeot val |= g4x_infoframe_index(type); 145e3adcf8fSFrançois Tigeot 1469edbd4a0SFrançois Tigeot val &= ~g4x_infoframe_enable(type); 147e3adcf8fSFrançois Tigeot 14819df918dSFrançois Tigeot I915_WRITE(VIDEO_DIP_CTL, val); 149e3adcf8fSFrançois Tigeot 15019df918dSFrançois Tigeot mmiowb(); 151e3adcf8fSFrançois Tigeot for (i = 0; i < len; i += 4) { 152e3adcf8fSFrançois Tigeot I915_WRITE(VIDEO_DIP_DATA, *data); 153e3adcf8fSFrançois Tigeot data++; 154e3adcf8fSFrançois Tigeot } 15519df918dSFrançois Tigeot /* Write every possible data byte to force correct ECC calculation. */ 15619df918dSFrançois Tigeot for (; i < VIDEO_DIP_DATA_SIZE; i += 4) 15719df918dSFrançois Tigeot I915_WRITE(VIDEO_DIP_DATA, 0); 15819df918dSFrançois Tigeot mmiowb(); 159e3adcf8fSFrançois Tigeot 1609edbd4a0SFrançois Tigeot val |= g4x_infoframe_enable(type); 16119df918dSFrançois Tigeot val &= ~VIDEO_DIP_FREQ_MASK; 16219df918dSFrançois Tigeot val |= VIDEO_DIP_FREQ_VSYNC; 163e3adcf8fSFrançois Tigeot 16419df918dSFrançois Tigeot I915_WRITE(VIDEO_DIP_CTL, val); 16519df918dSFrançois Tigeot POSTING_READ(VIDEO_DIP_CTL); 166e3adcf8fSFrançois Tigeot } 167e3adcf8fSFrançois Tigeot 16819df918dSFrançois Tigeot static void ibx_write_infoframe(struct drm_encoder *encoder, 1699edbd4a0SFrançois Tigeot enum hdmi_infoframe_type type, 1709edbd4a0SFrançois Tigeot const void *frame, ssize_t len) 171e3adcf8fSFrançois Tigeot { 1729edbd4a0SFrançois Tigeot const uint32_t *data = frame; 173e3adcf8fSFrançois Tigeot struct drm_device *dev = encoder->dev; 174e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 17519df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 1769edbd4a0SFrançois Tigeot int i, reg = TVIDEO_DIP_CTL(intel_crtc->pipe); 17719df918dSFrançois Tigeot u32 val = I915_READ(reg); 178e3adcf8fSFrançois Tigeot 17919df918dSFrançois Tigeot WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n"); 180e3adcf8fSFrançois Tigeot 181e3adcf8fSFrançois Tigeot val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ 1829edbd4a0SFrançois Tigeot val |= g4x_infoframe_index(type); 183e3adcf8fSFrançois Tigeot 1849edbd4a0SFrançois Tigeot val &= ~g4x_infoframe_enable(type); 185e3adcf8fSFrançois Tigeot 18619df918dSFrançois Tigeot I915_WRITE(reg, val); 18719df918dSFrançois Tigeot 18819df918dSFrançois Tigeot mmiowb(); 189e3adcf8fSFrançois Tigeot for (i = 0; i < len; i += 4) { 190e3adcf8fSFrançois Tigeot I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); 191e3adcf8fSFrançois Tigeot data++; 192e3adcf8fSFrançois Tigeot } 19319df918dSFrançois Tigeot /* Write every possible data byte to force correct ECC calculation. */ 19419df918dSFrançois Tigeot for (; i < VIDEO_DIP_DATA_SIZE; i += 4) 19519df918dSFrançois Tigeot I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0); 19619df918dSFrançois Tigeot mmiowb(); 197e3adcf8fSFrançois Tigeot 1989edbd4a0SFrançois Tigeot val |= g4x_infoframe_enable(type); 19919df918dSFrançois Tigeot val &= ~VIDEO_DIP_FREQ_MASK; 20019df918dSFrançois Tigeot val |= VIDEO_DIP_FREQ_VSYNC; 201e3adcf8fSFrançois Tigeot 20219df918dSFrançois Tigeot I915_WRITE(reg, val); 20319df918dSFrançois Tigeot POSTING_READ(reg); 20419df918dSFrançois Tigeot } 20519df918dSFrançois Tigeot 20619df918dSFrançois Tigeot static void cpt_write_infoframe(struct drm_encoder *encoder, 2079edbd4a0SFrançois Tigeot enum hdmi_infoframe_type type, 2089edbd4a0SFrançois Tigeot const void *frame, ssize_t len) 20919df918dSFrançois Tigeot { 2109edbd4a0SFrançois Tigeot const uint32_t *data = frame; 21119df918dSFrançois Tigeot struct drm_device *dev = encoder->dev; 21219df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 21319df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 2149edbd4a0SFrançois Tigeot int i, reg = TVIDEO_DIP_CTL(intel_crtc->pipe); 21519df918dSFrançois Tigeot u32 val = I915_READ(reg); 21619df918dSFrançois Tigeot 21719df918dSFrançois Tigeot WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n"); 21819df918dSFrançois Tigeot 21919df918dSFrançois Tigeot val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ 2209edbd4a0SFrançois Tigeot val |= g4x_infoframe_index(type); 22119df918dSFrançois Tigeot 22219df918dSFrançois Tigeot /* The DIP control register spec says that we need to update the AVI 22319df918dSFrançois Tigeot * infoframe without clearing its enable bit */ 2249edbd4a0SFrançois Tigeot if (type != HDMI_INFOFRAME_TYPE_AVI) 2259edbd4a0SFrançois Tigeot val &= ~g4x_infoframe_enable(type); 22619df918dSFrançois Tigeot 22719df918dSFrançois Tigeot I915_WRITE(reg, val); 22819df918dSFrançois Tigeot 22919df918dSFrançois Tigeot mmiowb(); 23019df918dSFrançois Tigeot for (i = 0; i < len; i += 4) { 23119df918dSFrançois Tigeot I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); 23219df918dSFrançois Tigeot data++; 23319df918dSFrançois Tigeot } 23419df918dSFrançois Tigeot /* Write every possible data byte to force correct ECC calculation. */ 23519df918dSFrançois Tigeot for (; i < VIDEO_DIP_DATA_SIZE; i += 4) 23619df918dSFrançois Tigeot I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0); 23719df918dSFrançois Tigeot mmiowb(); 23819df918dSFrançois Tigeot 2399edbd4a0SFrançois Tigeot val |= g4x_infoframe_enable(type); 24019df918dSFrançois Tigeot val &= ~VIDEO_DIP_FREQ_MASK; 24119df918dSFrançois Tigeot val |= VIDEO_DIP_FREQ_VSYNC; 24219df918dSFrançois Tigeot 24319df918dSFrançois Tigeot I915_WRITE(reg, val); 24419df918dSFrançois Tigeot POSTING_READ(reg); 24519df918dSFrançois Tigeot } 24619df918dSFrançois Tigeot 24719df918dSFrançois Tigeot static void vlv_write_infoframe(struct drm_encoder *encoder, 2489edbd4a0SFrançois Tigeot enum hdmi_infoframe_type type, 2499edbd4a0SFrançois Tigeot const void *frame, ssize_t len) 25019df918dSFrançois Tigeot { 2519edbd4a0SFrançois Tigeot const uint32_t *data = frame; 25219df918dSFrançois Tigeot struct drm_device *dev = encoder->dev; 25319df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 25419df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 2559edbd4a0SFrançois Tigeot int i, reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); 25619df918dSFrançois Tigeot u32 val = I915_READ(reg); 25719df918dSFrançois Tigeot 25819df918dSFrançois Tigeot WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n"); 25919df918dSFrançois Tigeot 26019df918dSFrançois Tigeot val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ 2619edbd4a0SFrançois Tigeot val |= g4x_infoframe_index(type); 26219df918dSFrançois Tigeot 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(VLV_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(VLV_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 28519df918dSFrançois Tigeot static void hsw_write_infoframe(struct drm_encoder *encoder, 2869edbd4a0SFrançois Tigeot enum hdmi_infoframe_type type, 2879edbd4a0SFrançois Tigeot const void *frame, ssize_t len) 28819df918dSFrançois Tigeot { 2899edbd4a0SFrançois Tigeot const uint32_t *data = frame; 29019df918dSFrançois Tigeot struct drm_device *dev = encoder->dev; 29119df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 29219df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 2938e26cdf6SFrançois Tigeot u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder); 2949edbd4a0SFrançois Tigeot u32 data_reg; 2959edbd4a0SFrançois Tigeot int i; 29619df918dSFrançois Tigeot u32 val = I915_READ(ctl_reg); 29719df918dSFrançois Tigeot 2989edbd4a0SFrançois Tigeot data_reg = hsw_infoframe_data_reg(type, 299*ba55f2f5SFrançois Tigeot intel_crtc->config.cpu_transcoder, 300*ba55f2f5SFrançois Tigeot dev_priv); 30119df918dSFrançois Tigeot if (data_reg == 0) 30219df918dSFrançois Tigeot return; 30319df918dSFrançois Tigeot 3049edbd4a0SFrançois Tigeot val &= ~hsw_infoframe_enable(type); 30519df918dSFrançois Tigeot I915_WRITE(ctl_reg, val); 30619df918dSFrançois Tigeot 30719df918dSFrançois Tigeot mmiowb(); 30819df918dSFrançois Tigeot for (i = 0; i < len; i += 4) { 30919df918dSFrançois Tigeot I915_WRITE(data_reg + i, *data); 31019df918dSFrançois Tigeot data++; 31119df918dSFrançois Tigeot } 31219df918dSFrançois Tigeot /* Write every possible data byte to force correct ECC calculation. */ 31319df918dSFrançois Tigeot for (; i < VIDEO_DIP_DATA_SIZE; i += 4) 31419df918dSFrançois Tigeot I915_WRITE(data_reg + i, 0); 31519df918dSFrançois Tigeot mmiowb(); 31619df918dSFrançois Tigeot 3179edbd4a0SFrançois Tigeot val |= hsw_infoframe_enable(type); 31819df918dSFrançois Tigeot I915_WRITE(ctl_reg, val); 31919df918dSFrançois Tigeot POSTING_READ(ctl_reg); 320e3adcf8fSFrançois Tigeot } 321e3adcf8fSFrançois Tigeot 3229edbd4a0SFrançois Tigeot /* 3239edbd4a0SFrançois Tigeot * The data we write to the DIP data buffer registers is 1 byte bigger than the 3249edbd4a0SFrançois Tigeot * HDMI infoframe size because of an ECC/reserved byte at position 3 (starting 3259edbd4a0SFrançois Tigeot * at 0). It's also a byte used by DisplayPort so the same DIP registers can be 3269edbd4a0SFrançois Tigeot * used for both technologies. 3279edbd4a0SFrançois Tigeot * 3289edbd4a0SFrançois Tigeot * DW0: Reserved/ECC/DP | HB2 | HB1 | HB0 3299edbd4a0SFrançois Tigeot * DW1: DB3 | DB2 | DB1 | DB0 3309edbd4a0SFrançois Tigeot * DW2: DB7 | DB6 | DB5 | DB4 3319edbd4a0SFrançois Tigeot * DW3: ... 3329edbd4a0SFrançois Tigeot * 3339edbd4a0SFrançois Tigeot * (HB is Header Byte, DB is Data Byte) 3349edbd4a0SFrançois Tigeot * 3359edbd4a0SFrançois Tigeot * The hdmi pack() functions don't know about that hardware specific hole so we 3369edbd4a0SFrançois Tigeot * trick them by giving an offset into the buffer and moving back the header 3379edbd4a0SFrançois Tigeot * bytes by one. 3389edbd4a0SFrançois Tigeot */ 3399edbd4a0SFrançois Tigeot static void intel_write_infoframe(struct drm_encoder *encoder, 3409edbd4a0SFrançois Tigeot union hdmi_infoframe *frame) 341e3adcf8fSFrançois Tigeot { 342e3adcf8fSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 3439edbd4a0SFrançois Tigeot uint8_t buffer[VIDEO_DIP_DATA_SIZE]; 3449edbd4a0SFrançois Tigeot ssize_t len; 345e3adcf8fSFrançois Tigeot 3469edbd4a0SFrançois Tigeot /* see comment above for the reason for this offset */ 3479edbd4a0SFrançois Tigeot len = hdmi_infoframe_pack(frame, buffer + 1, sizeof(buffer) - 1); 3489edbd4a0SFrançois Tigeot if (len < 0) 3499edbd4a0SFrançois Tigeot return; 3509edbd4a0SFrançois Tigeot 3519edbd4a0SFrançois Tigeot /* Insert the 'hole' (see big comment above) at position 3 */ 3529edbd4a0SFrançois Tigeot buffer[0] = buffer[1]; 3539edbd4a0SFrançois Tigeot buffer[1] = buffer[2]; 3549edbd4a0SFrançois Tigeot buffer[2] = buffer[3]; 3559edbd4a0SFrançois Tigeot buffer[3] = 0; 3569edbd4a0SFrançois Tigeot len++; 3579edbd4a0SFrançois Tigeot 3589edbd4a0SFrançois Tigeot intel_hdmi->write_infoframe(encoder, frame->any.type, buffer, len); 359e3adcf8fSFrançois Tigeot } 360e3adcf8fSFrançois Tigeot 36119df918dSFrançois Tigeot static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, 36219df918dSFrançois Tigeot struct drm_display_mode *adjusted_mode) 363e3adcf8fSFrançois Tigeot { 364a2fdbec6SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 3658e26cdf6SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 3669edbd4a0SFrançois Tigeot union hdmi_infoframe frame; 3679edbd4a0SFrançois Tigeot int ret; 368e3adcf8fSFrançois Tigeot 3699edbd4a0SFrançois Tigeot ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, 3709edbd4a0SFrançois Tigeot adjusted_mode); 3719edbd4a0SFrançois Tigeot if (ret < 0) { 3729edbd4a0SFrançois Tigeot DRM_ERROR("couldn't fill AVI infoframe\n"); 3739edbd4a0SFrançois Tigeot return; 3749edbd4a0SFrançois Tigeot } 37519df918dSFrançois Tigeot 376a2fdbec6SFrançois Tigeot if (intel_hdmi->rgb_quant_range_selectable) { 3778e26cdf6SFrançois Tigeot if (intel_crtc->config.limited_color_range) 3789edbd4a0SFrançois Tigeot frame.avi.quantization_range = 3799edbd4a0SFrançois Tigeot HDMI_QUANTIZATION_RANGE_LIMITED; 380a2fdbec6SFrançois Tigeot else 3819edbd4a0SFrançois Tigeot frame.avi.quantization_range = 3829edbd4a0SFrançois Tigeot HDMI_QUANTIZATION_RANGE_FULL; 383a2fdbec6SFrançois Tigeot } 384a2fdbec6SFrançois Tigeot 3859edbd4a0SFrançois Tigeot intel_write_infoframe(encoder, &frame); 386e3adcf8fSFrançois Tigeot } 387e3adcf8fSFrançois Tigeot 388e3adcf8fSFrançois Tigeot static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder) 389e3adcf8fSFrançois Tigeot { 3909edbd4a0SFrançois Tigeot union hdmi_infoframe frame; 3919edbd4a0SFrançois Tigeot int ret; 392e3adcf8fSFrançois Tigeot 3939edbd4a0SFrançois Tigeot ret = hdmi_spd_infoframe_init(&frame.spd, "Intel", "Integrated gfx"); 3949edbd4a0SFrançois Tigeot if (ret < 0) { 3959edbd4a0SFrançois Tigeot DRM_ERROR("couldn't fill SPD infoframe\n"); 3969edbd4a0SFrançois Tigeot return; 3979edbd4a0SFrançois Tigeot } 398e3adcf8fSFrançois Tigeot 3999edbd4a0SFrançois Tigeot frame.spd.sdi = HDMI_SPD_SDI_PC; 4009edbd4a0SFrançois Tigeot 4019edbd4a0SFrançois Tigeot intel_write_infoframe(encoder, &frame); 4029edbd4a0SFrançois Tigeot } 4039edbd4a0SFrançois Tigeot 4049edbd4a0SFrançois Tigeot static void 4059edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder, 4069edbd4a0SFrançois Tigeot struct drm_display_mode *adjusted_mode) 4079edbd4a0SFrançois Tigeot { 4089edbd4a0SFrançois Tigeot union hdmi_infoframe frame; 4099edbd4a0SFrançois Tigeot int ret; 4109edbd4a0SFrançois Tigeot 4119edbd4a0SFrançois Tigeot ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi, 4129edbd4a0SFrançois Tigeot adjusted_mode); 4139edbd4a0SFrançois Tigeot if (ret < 0) 4149edbd4a0SFrançois Tigeot return; 4159edbd4a0SFrançois Tigeot 4169edbd4a0SFrançois Tigeot intel_write_infoframe(encoder, &frame); 417e3adcf8fSFrançois Tigeot } 418e3adcf8fSFrançois Tigeot 41919df918dSFrançois Tigeot static void g4x_set_infoframes(struct drm_encoder *encoder, 420*ba55f2f5SFrançois Tigeot bool enable, 42119df918dSFrançois Tigeot struct drm_display_mode *adjusted_mode) 42219df918dSFrançois Tigeot { 42319df918dSFrançois Tigeot struct drm_i915_private *dev_priv = encoder->dev->dev_private; 424a2fdbec6SFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); 425a2fdbec6SFrançois Tigeot struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; 42619df918dSFrançois Tigeot u32 reg = VIDEO_DIP_CTL; 42719df918dSFrançois Tigeot u32 val = I915_READ(reg); 428*ba55f2f5SFrançois Tigeot u32 port = VIDEO_DIP_PORT(intel_dig_port->port); 42919df918dSFrançois Tigeot 43019df918dSFrançois Tigeot assert_hdmi_port_disabled(intel_hdmi); 43119df918dSFrançois Tigeot 43219df918dSFrançois Tigeot /* If the registers were not initialized yet, they might be zeroes, 43319df918dSFrançois Tigeot * which means we're selecting the AVI DIP and we're setting its 43419df918dSFrançois Tigeot * frequency to once. This seems to really confuse the HW and make 43519df918dSFrançois Tigeot * things stop working (the register spec says the AVI always needs to 43619df918dSFrançois Tigeot * be sent every VSync). So here we avoid writing to the register more 43719df918dSFrançois Tigeot * than we need and also explicitly select the AVI DIP and explicitly 43819df918dSFrançois Tigeot * set its frequency to every VSync. Avoiding to write it twice seems to 43919df918dSFrançois Tigeot * be enough to solve the problem, but being defensive shouldn't hurt us 44019df918dSFrançois Tigeot * either. */ 44119df918dSFrançois Tigeot val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; 44219df918dSFrançois Tigeot 443*ba55f2f5SFrançois Tigeot if (!enable) { 44419df918dSFrançois Tigeot if (!(val & VIDEO_DIP_ENABLE)) 44519df918dSFrançois Tigeot return; 44619df918dSFrançois Tigeot val &= ~VIDEO_DIP_ENABLE; 44719df918dSFrançois Tigeot I915_WRITE(reg, val); 44819df918dSFrançois Tigeot POSTING_READ(reg); 44919df918dSFrançois Tigeot return; 45019df918dSFrançois Tigeot } 45119df918dSFrançois Tigeot 45219df918dSFrançois Tigeot if (port != (val & VIDEO_DIP_PORT_MASK)) { 45319df918dSFrançois Tigeot if (val & VIDEO_DIP_ENABLE) { 45419df918dSFrançois Tigeot val &= ~VIDEO_DIP_ENABLE; 45519df918dSFrançois Tigeot I915_WRITE(reg, val); 45619df918dSFrançois Tigeot POSTING_READ(reg); 45719df918dSFrançois Tigeot } 45819df918dSFrançois Tigeot val &= ~VIDEO_DIP_PORT_MASK; 45919df918dSFrançois Tigeot val |= port; 46019df918dSFrançois Tigeot } 46119df918dSFrançois Tigeot 46219df918dSFrançois Tigeot val |= VIDEO_DIP_ENABLE; 46319df918dSFrançois Tigeot val &= ~VIDEO_DIP_ENABLE_VENDOR; 46419df918dSFrançois Tigeot 46519df918dSFrançois Tigeot I915_WRITE(reg, val); 46619df918dSFrançois Tigeot POSTING_READ(reg); 46719df918dSFrançois Tigeot 46819df918dSFrançois Tigeot intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); 46919df918dSFrançois Tigeot intel_hdmi_set_spd_infoframe(encoder); 4709edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode); 47119df918dSFrançois Tigeot } 47219df918dSFrançois Tigeot 47319df918dSFrançois Tigeot static void ibx_set_infoframes(struct drm_encoder *encoder, 474*ba55f2f5SFrançois Tigeot bool enable, 47519df918dSFrançois Tigeot struct drm_display_mode *adjusted_mode) 47619df918dSFrançois Tigeot { 47719df918dSFrançois Tigeot struct drm_i915_private *dev_priv = encoder->dev->dev_private; 47819df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 479a2fdbec6SFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); 480a2fdbec6SFrançois Tigeot struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; 48119df918dSFrançois Tigeot u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe); 48219df918dSFrançois Tigeot u32 val = I915_READ(reg); 483*ba55f2f5SFrançois Tigeot u32 port = VIDEO_DIP_PORT(intel_dig_port->port); 48419df918dSFrançois Tigeot 48519df918dSFrançois Tigeot assert_hdmi_port_disabled(intel_hdmi); 48619df918dSFrançois Tigeot 48719df918dSFrançois Tigeot /* See the big comment in g4x_set_infoframes() */ 48819df918dSFrançois Tigeot val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; 48919df918dSFrançois Tigeot 490*ba55f2f5SFrançois Tigeot if (!enable) { 49119df918dSFrançois Tigeot if (!(val & VIDEO_DIP_ENABLE)) 49219df918dSFrançois Tigeot return; 49319df918dSFrançois Tigeot val &= ~VIDEO_DIP_ENABLE; 49419df918dSFrançois Tigeot I915_WRITE(reg, val); 49519df918dSFrançois Tigeot POSTING_READ(reg); 49619df918dSFrançois Tigeot return; 49719df918dSFrançois Tigeot } 49819df918dSFrançois Tigeot 49919df918dSFrançois Tigeot if (port != (val & VIDEO_DIP_PORT_MASK)) { 50019df918dSFrançois Tigeot if (val & VIDEO_DIP_ENABLE) { 50119df918dSFrançois Tigeot val &= ~VIDEO_DIP_ENABLE; 50219df918dSFrançois Tigeot I915_WRITE(reg, val); 50319df918dSFrançois Tigeot POSTING_READ(reg); 50419df918dSFrançois Tigeot } 50519df918dSFrançois Tigeot val &= ~VIDEO_DIP_PORT_MASK; 50619df918dSFrançois Tigeot val |= port; 50719df918dSFrançois Tigeot } 50819df918dSFrançois Tigeot 50919df918dSFrançois Tigeot val |= VIDEO_DIP_ENABLE; 51019df918dSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | 51119df918dSFrançois Tigeot VIDEO_DIP_ENABLE_GCP); 51219df918dSFrançois Tigeot 51319df918dSFrançois Tigeot I915_WRITE(reg, val); 51419df918dSFrançois Tigeot POSTING_READ(reg); 51519df918dSFrançois Tigeot 51619df918dSFrançois Tigeot intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); 51719df918dSFrançois Tigeot intel_hdmi_set_spd_infoframe(encoder); 5189edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode); 51919df918dSFrançois Tigeot } 52019df918dSFrançois Tigeot 52119df918dSFrançois Tigeot static void cpt_set_infoframes(struct drm_encoder *encoder, 522*ba55f2f5SFrançois Tigeot bool enable, 52319df918dSFrançois Tigeot struct drm_display_mode *adjusted_mode) 52419df918dSFrançois Tigeot { 52519df918dSFrançois Tigeot struct drm_i915_private *dev_priv = encoder->dev->dev_private; 52619df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 52719df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 52819df918dSFrançois Tigeot u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe); 52919df918dSFrançois Tigeot u32 val = I915_READ(reg); 53019df918dSFrançois Tigeot 53119df918dSFrançois Tigeot assert_hdmi_port_disabled(intel_hdmi); 53219df918dSFrançois Tigeot 53319df918dSFrançois Tigeot /* See the big comment in g4x_set_infoframes() */ 53419df918dSFrançois Tigeot val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; 53519df918dSFrançois Tigeot 536*ba55f2f5SFrançois Tigeot if (!enable) { 53719df918dSFrançois Tigeot if (!(val & VIDEO_DIP_ENABLE)) 53819df918dSFrançois Tigeot return; 53919df918dSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI); 54019df918dSFrançois Tigeot I915_WRITE(reg, val); 54119df918dSFrançois Tigeot POSTING_READ(reg); 54219df918dSFrançois Tigeot return; 54319df918dSFrançois Tigeot } 54419df918dSFrançois Tigeot 54519df918dSFrançois Tigeot /* Set both together, unset both together: see the spec. */ 54619df918dSFrançois Tigeot val |= VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI; 54719df918dSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | 54819df918dSFrançois Tigeot VIDEO_DIP_ENABLE_GCP); 54919df918dSFrançois Tigeot 55019df918dSFrançois Tigeot I915_WRITE(reg, val); 55119df918dSFrançois Tigeot POSTING_READ(reg); 55219df918dSFrançois Tigeot 55319df918dSFrançois Tigeot intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); 55419df918dSFrançois Tigeot intel_hdmi_set_spd_infoframe(encoder); 5559edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode); 55619df918dSFrançois Tigeot } 55719df918dSFrançois Tigeot 55819df918dSFrançois Tigeot static void vlv_set_infoframes(struct drm_encoder *encoder, 559*ba55f2f5SFrançois Tigeot bool enable, 56019df918dSFrançois Tigeot struct drm_display_mode *adjusted_mode) 56119df918dSFrançois Tigeot { 56219df918dSFrançois Tigeot struct drm_i915_private *dev_priv = encoder->dev->dev_private; 563*ba55f2f5SFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); 56419df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 56519df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 56619df918dSFrançois Tigeot u32 reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); 56719df918dSFrançois Tigeot u32 val = I915_READ(reg); 568*ba55f2f5SFrançois Tigeot u32 port = VIDEO_DIP_PORT(intel_dig_port->port); 56919df918dSFrançois Tigeot 57019df918dSFrançois Tigeot assert_hdmi_port_disabled(intel_hdmi); 57119df918dSFrançois Tigeot 57219df918dSFrançois Tigeot /* See the big comment in g4x_set_infoframes() */ 57319df918dSFrançois Tigeot val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; 57419df918dSFrançois Tigeot 575*ba55f2f5SFrançois Tigeot if (!enable) { 57619df918dSFrançois Tigeot if (!(val & VIDEO_DIP_ENABLE)) 57719df918dSFrançois Tigeot return; 57819df918dSFrançois Tigeot val &= ~VIDEO_DIP_ENABLE; 57919df918dSFrançois Tigeot I915_WRITE(reg, val); 58019df918dSFrançois Tigeot POSTING_READ(reg); 58119df918dSFrançois Tigeot return; 58219df918dSFrançois Tigeot } 58319df918dSFrançois Tigeot 584*ba55f2f5SFrançois Tigeot if (port != (val & VIDEO_DIP_PORT_MASK)) { 585*ba55f2f5SFrançois Tigeot if (val & VIDEO_DIP_ENABLE) { 586*ba55f2f5SFrançois Tigeot val &= ~VIDEO_DIP_ENABLE; 587*ba55f2f5SFrançois Tigeot I915_WRITE(reg, val); 588*ba55f2f5SFrançois Tigeot POSTING_READ(reg); 589*ba55f2f5SFrançois Tigeot } 590*ba55f2f5SFrançois Tigeot val &= ~VIDEO_DIP_PORT_MASK; 591*ba55f2f5SFrançois Tigeot val |= port; 592*ba55f2f5SFrançois Tigeot } 593*ba55f2f5SFrançois Tigeot 59419df918dSFrançois Tigeot val |= VIDEO_DIP_ENABLE; 595*ba55f2f5SFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_ENABLE_VENDOR | 596*ba55f2f5SFrançois Tigeot VIDEO_DIP_ENABLE_GAMUT | VIDEO_DIP_ENABLE_GCP); 59719df918dSFrançois Tigeot 59819df918dSFrançois Tigeot I915_WRITE(reg, val); 59919df918dSFrançois Tigeot POSTING_READ(reg); 60019df918dSFrançois Tigeot 60119df918dSFrançois Tigeot intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); 60219df918dSFrançois Tigeot intel_hdmi_set_spd_infoframe(encoder); 6039edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode); 60419df918dSFrançois Tigeot } 60519df918dSFrançois Tigeot 60619df918dSFrançois Tigeot static void hsw_set_infoframes(struct drm_encoder *encoder, 607*ba55f2f5SFrançois Tigeot bool enable, 60819df918dSFrançois Tigeot struct drm_display_mode *adjusted_mode) 60919df918dSFrançois Tigeot { 61019df918dSFrançois Tigeot struct drm_i915_private *dev_priv = encoder->dev->dev_private; 61119df918dSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 61219df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 6138e26cdf6SFrançois Tigeot u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder); 61419df918dSFrançois Tigeot u32 val = I915_READ(reg); 61519df918dSFrançois Tigeot 61619df918dSFrançois Tigeot assert_hdmi_port_disabled(intel_hdmi); 61719df918dSFrançois Tigeot 618*ba55f2f5SFrançois Tigeot if (!enable) { 61919df918dSFrançois Tigeot I915_WRITE(reg, 0); 62019df918dSFrançois Tigeot POSTING_READ(reg); 62119df918dSFrançois Tigeot return; 62219df918dSFrançois Tigeot } 62319df918dSFrançois Tigeot 62419df918dSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_GCP_HSW | 62519df918dSFrançois Tigeot VIDEO_DIP_ENABLE_VS_HSW | VIDEO_DIP_ENABLE_GMP_HSW); 62619df918dSFrançois Tigeot 62719df918dSFrançois Tigeot I915_WRITE(reg, val); 62819df918dSFrançois Tigeot POSTING_READ(reg); 62919df918dSFrançois Tigeot 63019df918dSFrançois Tigeot intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); 63119df918dSFrançois Tigeot intel_hdmi_set_spd_infoframe(encoder); 6329edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode); 63319df918dSFrançois Tigeot } 63419df918dSFrançois Tigeot 635*ba55f2f5SFrançois Tigeot static void intel_hdmi_prepare(struct intel_encoder *encoder) 636e3adcf8fSFrançois Tigeot { 6379edbd4a0SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 638e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 6399edbd4a0SFrançois Tigeot struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); 6409edbd4a0SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 6419edbd4a0SFrançois Tigeot struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode; 6428e26cdf6SFrançois Tigeot u32 hdmi_val; 643e3adcf8fSFrançois Tigeot 6448e26cdf6SFrançois Tigeot hdmi_val = SDVO_ENCODING_HDMI; 6455d0b1887SFrançois Tigeot if (!HAS_PCH_SPLIT(dev)) 6468e26cdf6SFrançois Tigeot hdmi_val |= intel_hdmi->color_range; 647e3adcf8fSFrançois Tigeot if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) 6488e26cdf6SFrançois Tigeot hdmi_val |= SDVO_VSYNC_ACTIVE_HIGH; 649e3adcf8fSFrançois Tigeot if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) 6508e26cdf6SFrançois Tigeot hdmi_val |= SDVO_HSYNC_ACTIVE_HIGH; 651e3adcf8fSFrançois Tigeot 6529edbd4a0SFrançois Tigeot if (crtc->config.pipe_bpp > 24) 6538e26cdf6SFrançois Tigeot hdmi_val |= HDMI_COLOR_FORMAT_12bpc; 654e3adcf8fSFrançois Tigeot else 6558e26cdf6SFrançois Tigeot hdmi_val |= SDVO_COLOR_FORMAT_8bpc; 656e3adcf8fSFrançois Tigeot 657*ba55f2f5SFrançois Tigeot if (crtc->config.has_hdmi_sink) 6588e26cdf6SFrançois Tigeot hdmi_val |= HDMI_MODE_SELECT_HDMI; 659e3adcf8fSFrançois Tigeot 660*ba55f2f5SFrançois Tigeot if (crtc->config.has_audio) { 661*ba55f2f5SFrançois Tigeot WARN_ON(!crtc->config.has_hdmi_sink); 66219df918dSFrançois Tigeot DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", 6639edbd4a0SFrançois Tigeot pipe_name(crtc->pipe)); 6648e26cdf6SFrançois Tigeot hdmi_val |= SDVO_AUDIO_ENABLE; 6659edbd4a0SFrançois Tigeot intel_write_eld(&encoder->base, adjusted_mode); 666e3adcf8fSFrançois Tigeot } 667e3adcf8fSFrançois Tigeot 668e3adcf8fSFrançois Tigeot if (HAS_PCH_CPT(dev)) 6699edbd4a0SFrançois Tigeot hdmi_val |= SDVO_PIPE_SEL_CPT(crtc->pipe); 670*ba55f2f5SFrançois Tigeot else if (IS_CHERRYVIEW(dev)) 671*ba55f2f5SFrançois Tigeot hdmi_val |= SDVO_PIPE_SEL_CHV(crtc->pipe); 6728e26cdf6SFrançois Tigeot else 6739edbd4a0SFrançois Tigeot hdmi_val |= SDVO_PIPE_SEL(crtc->pipe); 674e3adcf8fSFrançois Tigeot 6758e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, hdmi_val); 6768e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 677e3adcf8fSFrançois Tigeot } 678e3adcf8fSFrançois Tigeot 67919df918dSFrançois Tigeot static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder, 68019df918dSFrançois Tigeot enum i915_pipe *pipe) 681e3adcf8fSFrançois Tigeot { 68219df918dSFrançois Tigeot struct drm_device *dev = encoder->base.dev; 683e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 68419df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 685*ba55f2f5SFrançois Tigeot enum intel_display_power_domain power_domain; 68619df918dSFrançois Tigeot u32 tmp; 68719df918dSFrançois Tigeot 688*ba55f2f5SFrançois Tigeot power_domain = intel_display_port_power_domain(encoder); 689*ba55f2f5SFrançois Tigeot if (!intel_display_power_enabled(dev_priv, power_domain)) 690*ba55f2f5SFrançois Tigeot return false; 691*ba55f2f5SFrançois Tigeot 6928e26cdf6SFrançois Tigeot tmp = I915_READ(intel_hdmi->hdmi_reg); 69319df918dSFrançois Tigeot 69419df918dSFrançois Tigeot if (!(tmp & SDVO_ENABLE)) 69519df918dSFrançois Tigeot return false; 69619df918dSFrançois Tigeot 69719df918dSFrançois Tigeot if (HAS_PCH_CPT(dev)) 69819df918dSFrançois Tigeot *pipe = PORT_TO_PIPE_CPT(tmp); 699*ba55f2f5SFrançois Tigeot else if (IS_CHERRYVIEW(dev)) 700*ba55f2f5SFrançois Tigeot *pipe = SDVO_PORT_TO_PIPE_CHV(tmp); 70119df918dSFrançois Tigeot else 70219df918dSFrançois Tigeot *pipe = PORT_TO_PIPE(tmp); 70319df918dSFrançois Tigeot 70419df918dSFrançois Tigeot return true; 70519df918dSFrançois Tigeot } 70619df918dSFrançois Tigeot 7075d0b1887SFrançois Tigeot static void intel_hdmi_get_config(struct intel_encoder *encoder, 7085d0b1887SFrançois Tigeot struct intel_crtc_config *pipe_config) 7095d0b1887SFrançois Tigeot { 7105d0b1887SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 7115d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; 7125d0b1887SFrançois Tigeot u32 tmp, flags = 0; 7139edbd4a0SFrançois Tigeot int dotclock; 7145d0b1887SFrançois Tigeot 7155d0b1887SFrançois Tigeot tmp = I915_READ(intel_hdmi->hdmi_reg); 7165d0b1887SFrançois Tigeot 7175d0b1887SFrançois Tigeot if (tmp & SDVO_HSYNC_ACTIVE_HIGH) 7185d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_PHSYNC; 7195d0b1887SFrançois Tigeot else 7205d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_NHSYNC; 7215d0b1887SFrançois Tigeot 7225d0b1887SFrançois Tigeot if (tmp & SDVO_VSYNC_ACTIVE_HIGH) 7235d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_PVSYNC; 7245d0b1887SFrançois Tigeot else 7255d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_NVSYNC; 7265d0b1887SFrançois Tigeot 727*ba55f2f5SFrançois Tigeot if (tmp & HDMI_MODE_SELECT_HDMI) 728*ba55f2f5SFrançois Tigeot pipe_config->has_hdmi_sink = true; 729*ba55f2f5SFrançois Tigeot 730*ba55f2f5SFrançois Tigeot if (tmp & HDMI_MODE_SELECT_HDMI) 731*ba55f2f5SFrançois Tigeot pipe_config->has_audio = true; 732*ba55f2f5SFrançois Tigeot 7335d0b1887SFrançois Tigeot pipe_config->adjusted_mode.flags |= flags; 7349edbd4a0SFrançois Tigeot 7359edbd4a0SFrançois Tigeot if ((tmp & SDVO_COLOR_FORMAT_MASK) == HDMI_COLOR_FORMAT_12bpc) 7369edbd4a0SFrançois Tigeot dotclock = pipe_config->port_clock * 2 / 3; 7379edbd4a0SFrançois Tigeot else 7389edbd4a0SFrançois Tigeot dotclock = pipe_config->port_clock; 7399edbd4a0SFrançois Tigeot 7409edbd4a0SFrançois Tigeot if (HAS_PCH_SPLIT(dev_priv->dev)) 7419edbd4a0SFrançois Tigeot ironlake_check_encoder_dotclock(pipe_config, dotclock); 7429edbd4a0SFrançois Tigeot 7439edbd4a0SFrançois Tigeot pipe_config->adjusted_mode.crtc_clock = dotclock; 7445d0b1887SFrançois Tigeot } 7455d0b1887SFrançois Tigeot 74619df918dSFrançois Tigeot static void intel_enable_hdmi(struct intel_encoder *encoder) 74719df918dSFrançois Tigeot { 74819df918dSFrançois Tigeot struct drm_device *dev = encoder->base.dev; 74919df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 7508e26cdf6SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); 75119df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 752e3adcf8fSFrançois Tigeot u32 temp; 753e3adcf8fSFrançois Tigeot u32 enable_bits = SDVO_ENABLE; 754e3adcf8fSFrançois Tigeot 755*ba55f2f5SFrançois Tigeot if (intel_crtc->config.has_audio) 756e3adcf8fSFrançois Tigeot enable_bits |= SDVO_AUDIO_ENABLE; 757e3adcf8fSFrançois Tigeot 7588e26cdf6SFrançois Tigeot temp = I915_READ(intel_hdmi->hdmi_reg); 759e3adcf8fSFrançois Tigeot 76019df918dSFrançois Tigeot /* HW workaround for IBX, we need to move the port to transcoder A 7618e26cdf6SFrançois Tigeot * before disabling it, so restore the transcoder select bit here. */ 7628e26cdf6SFrançois Tigeot if (HAS_PCH_IBX(dev)) 7638e26cdf6SFrançois Tigeot enable_bits |= SDVO_PIPE_SEL(intel_crtc->pipe); 76419df918dSFrançois Tigeot 765e3adcf8fSFrançois Tigeot /* HW workaround, need to toggle enable bit off and on for 12bpc, but 766e3adcf8fSFrançois Tigeot * we do this anyway which shows more stable in testing. 767e3adcf8fSFrançois Tigeot */ 768e3adcf8fSFrançois Tigeot if (HAS_PCH_SPLIT(dev)) { 7698e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE); 7708e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 771e3adcf8fSFrançois Tigeot } 772e3adcf8fSFrançois Tigeot 773e3adcf8fSFrançois Tigeot temp |= enable_bits; 77419df918dSFrançois Tigeot 7758e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 7768e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 77719df918dSFrançois Tigeot 77819df918dSFrançois Tigeot /* HW workaround, need to write this twice for issue that may result 77919df918dSFrançois Tigeot * in first write getting masked. 78019df918dSFrançois Tigeot */ 78119df918dSFrançois Tigeot if (HAS_PCH_SPLIT(dev)) { 7828e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 7838e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 784e3adcf8fSFrançois Tigeot } 7855d0b1887SFrançois Tigeot } 7869edbd4a0SFrançois Tigeot 7879edbd4a0SFrançois Tigeot static void vlv_enable_hdmi(struct intel_encoder *encoder) 7889edbd4a0SFrançois Tigeot { 78919df918dSFrançois Tigeot } 79019df918dSFrançois Tigeot 79119df918dSFrançois Tigeot static void intel_disable_hdmi(struct intel_encoder *encoder) 79219df918dSFrançois Tigeot { 79319df918dSFrançois Tigeot struct drm_device *dev = encoder->base.dev; 79419df918dSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 79519df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 79619df918dSFrançois Tigeot u32 temp; 79719df918dSFrançois Tigeot u32 enable_bits = SDVO_ENABLE | SDVO_AUDIO_ENABLE; 79819df918dSFrançois Tigeot 7998e26cdf6SFrançois Tigeot temp = I915_READ(intel_hdmi->hdmi_reg); 80019df918dSFrançois Tigeot 80119df918dSFrançois Tigeot /* HW workaround for IBX, we need to move the port to transcoder A 80219df918dSFrançois Tigeot * before disabling it. */ 80319df918dSFrançois Tigeot if (HAS_PCH_IBX(dev)) { 80419df918dSFrançois Tigeot struct drm_crtc *crtc = encoder->base.crtc; 80519df918dSFrançois Tigeot int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1; 80619df918dSFrançois Tigeot 80719df918dSFrançois Tigeot if (temp & SDVO_PIPE_B_SELECT) { 80819df918dSFrançois Tigeot temp &= ~SDVO_PIPE_B_SELECT; 8098e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 8108e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 81119df918dSFrançois Tigeot 81219df918dSFrançois Tigeot /* Again we need to write this twice. */ 8138e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 8148e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 81519df918dSFrançois Tigeot 81619df918dSFrançois Tigeot /* Transcoder selection bits only update 81719df918dSFrançois Tigeot * effectively on vblank. */ 81819df918dSFrançois Tigeot if (crtc) 81919df918dSFrançois Tigeot intel_wait_for_vblank(dev, pipe); 82019df918dSFrançois Tigeot else 82119df918dSFrançois Tigeot msleep(50); 82219df918dSFrançois Tigeot } 82319df918dSFrançois Tigeot } 82419df918dSFrançois Tigeot 82519df918dSFrançois Tigeot /* HW workaround, need to toggle enable bit off and on for 12bpc, but 82619df918dSFrançois Tigeot * we do this anyway which shows more stable in testing. 82719df918dSFrançois Tigeot */ 82819df918dSFrançois Tigeot if (HAS_PCH_SPLIT(dev)) { 8298e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE); 8308e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 83119df918dSFrançois Tigeot } 83219df918dSFrançois Tigeot 83319df918dSFrançois Tigeot temp &= ~enable_bits; 834e3adcf8fSFrançois Tigeot 8358e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 8368e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 837e3adcf8fSFrançois Tigeot 838e3adcf8fSFrançois Tigeot /* HW workaround, need to write this twice for issue that may result 839e3adcf8fSFrançois Tigeot * in first write getting masked. 840e3adcf8fSFrançois Tigeot */ 841e3adcf8fSFrançois Tigeot if (HAS_PCH_SPLIT(dev)) { 8428e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp); 8438e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg); 844e3adcf8fSFrançois Tigeot } 845e3adcf8fSFrançois Tigeot } 846e3adcf8fSFrançois Tigeot 847*ba55f2f5SFrançois Tigeot static int hdmi_portclock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit) 8485d0b1887SFrançois Tigeot { 8495d0b1887SFrançois Tigeot struct drm_device *dev = intel_hdmi_to_dev(hdmi); 8505d0b1887SFrançois Tigeot 851*ba55f2f5SFrançois Tigeot if ((respect_dvi_limit && !hdmi->has_hdmi_sink) || IS_G4X(dev)) 8525d0b1887SFrançois Tigeot return 165000; 8539edbd4a0SFrançois Tigeot else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8) 8545d0b1887SFrançois Tigeot return 300000; 8555d0b1887SFrançois Tigeot else 8565d0b1887SFrançois Tigeot return 225000; 8575d0b1887SFrançois Tigeot } 8585d0b1887SFrançois Tigeot 8599edbd4a0SFrançois Tigeot static enum drm_mode_status 8609edbd4a0SFrançois Tigeot intel_hdmi_mode_valid(struct drm_connector *connector, 861e3adcf8fSFrançois Tigeot struct drm_display_mode *mode) 862e3adcf8fSFrançois Tigeot { 863*ba55f2f5SFrançois Tigeot if (mode->clock > hdmi_portclock_limit(intel_attached_hdmi(connector), 864*ba55f2f5SFrançois Tigeot true)) 865e3adcf8fSFrançois Tigeot return MODE_CLOCK_HIGH; 866e3adcf8fSFrançois Tigeot if (mode->clock < 20000) 867e3adcf8fSFrançois Tigeot return MODE_CLOCK_LOW; 868e3adcf8fSFrançois Tigeot 869e3adcf8fSFrançois Tigeot if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 870e3adcf8fSFrançois Tigeot return MODE_NO_DBLESCAN; 871e3adcf8fSFrançois Tigeot 872e3adcf8fSFrançois Tigeot return MODE_OK; 873e3adcf8fSFrançois Tigeot } 874e3adcf8fSFrançois Tigeot 875*ba55f2f5SFrançois Tigeot static bool hdmi_12bpc_possible(struct intel_crtc *crtc) 876*ba55f2f5SFrançois Tigeot { 877*ba55f2f5SFrançois Tigeot struct drm_device *dev = crtc->base.dev; 878*ba55f2f5SFrançois Tigeot struct intel_encoder *encoder; 879*ba55f2f5SFrançois Tigeot int count = 0, count_hdmi = 0; 880*ba55f2f5SFrançois Tigeot 881*ba55f2f5SFrançois Tigeot if (!HAS_PCH_SPLIT(dev)) 882*ba55f2f5SFrançois Tigeot return false; 883*ba55f2f5SFrançois Tigeot 884*ba55f2f5SFrançois Tigeot list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { 885*ba55f2f5SFrançois Tigeot if (encoder->new_crtc != crtc) 886*ba55f2f5SFrançois Tigeot continue; 887*ba55f2f5SFrançois Tigeot 888*ba55f2f5SFrançois Tigeot count_hdmi += encoder->type == INTEL_OUTPUT_HDMI; 889*ba55f2f5SFrançois Tigeot count++; 890*ba55f2f5SFrançois Tigeot } 891*ba55f2f5SFrançois Tigeot 892*ba55f2f5SFrançois Tigeot /* 893*ba55f2f5SFrançois Tigeot * HDMI 12bpc affects the clocks, so it's only possible 894*ba55f2f5SFrançois Tigeot * when not cloning with other encoder types. 895*ba55f2f5SFrançois Tigeot */ 896*ba55f2f5SFrançois Tigeot return count_hdmi > 0 && count_hdmi == count; 897*ba55f2f5SFrançois Tigeot } 898*ba55f2f5SFrançois Tigeot 8998e26cdf6SFrançois Tigeot bool intel_hdmi_compute_config(struct intel_encoder *encoder, 9008e26cdf6SFrançois Tigeot struct intel_crtc_config *pipe_config) 901e3adcf8fSFrançois Tigeot { 9028e26cdf6SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 9038e26cdf6SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 9048e26cdf6SFrançois Tigeot struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; 9059edbd4a0SFrançois Tigeot int clock_12bpc = pipe_config->adjusted_mode.crtc_clock * 3 / 2; 906*ba55f2f5SFrançois Tigeot int portclock_limit = hdmi_portclock_limit(intel_hdmi, false); 9075d0b1887SFrançois Tigeot int desired_bpp; 908a2fdbec6SFrançois Tigeot 909*ba55f2f5SFrançois Tigeot pipe_config->has_hdmi_sink = intel_hdmi->has_hdmi_sink; 910*ba55f2f5SFrançois Tigeot 911a2fdbec6SFrançois Tigeot if (intel_hdmi->color_range_auto) { 912a2fdbec6SFrançois Tigeot /* See CEA-861-E - 5.1 Default Encoding Parameters */ 913*ba55f2f5SFrançois Tigeot if (pipe_config->has_hdmi_sink && 914a2fdbec6SFrançois Tigeot drm_match_cea_mode(adjusted_mode) > 1) 9158e26cdf6SFrançois Tigeot intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235; 916a2fdbec6SFrançois Tigeot else 917a2fdbec6SFrançois Tigeot intel_hdmi->color_range = 0; 918a2fdbec6SFrançois Tigeot } 919a2fdbec6SFrançois Tigeot 920a2fdbec6SFrançois Tigeot if (intel_hdmi->color_range) 9218e26cdf6SFrançois Tigeot pipe_config->limited_color_range = true; 9228e26cdf6SFrançois Tigeot 9238e26cdf6SFrançois Tigeot if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev)) 9248e26cdf6SFrançois Tigeot pipe_config->has_pch_encoder = true; 9258e26cdf6SFrançois Tigeot 926*ba55f2f5SFrançois Tigeot if (pipe_config->has_hdmi_sink && intel_hdmi->has_audio) 927*ba55f2f5SFrançois Tigeot pipe_config->has_audio = true; 928*ba55f2f5SFrançois Tigeot 9298e26cdf6SFrançois Tigeot /* 9308e26cdf6SFrançois Tigeot * HDMI is either 12 or 8, so if the display lets 10bpc sneak 9318e26cdf6SFrançois Tigeot * through, clamp it down. Note that g4x/vlv don't support 12bpc hdmi 9325d0b1887SFrançois Tigeot * outputs. We also need to check that the higher clock still fits 9335d0b1887SFrançois Tigeot * within limits. 9348e26cdf6SFrançois Tigeot */ 935*ba55f2f5SFrançois Tigeot if (pipe_config->pipe_bpp > 8*3 && pipe_config->has_hdmi_sink && 936*ba55f2f5SFrançois Tigeot clock_12bpc <= portclock_limit && 937*ba55f2f5SFrançois Tigeot hdmi_12bpc_possible(encoder->new_crtc)) { 9385d0b1887SFrançois Tigeot DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n"); 9395d0b1887SFrançois Tigeot desired_bpp = 12*3; 9405d0b1887SFrançois Tigeot 9415d0b1887SFrançois Tigeot /* Need to adjust the port link by 1.5x for 12bpc. */ 9425d0b1887SFrançois Tigeot pipe_config->port_clock = clock_12bpc; 9438e26cdf6SFrançois Tigeot } else { 9445d0b1887SFrançois Tigeot DRM_DEBUG_KMS("picking bpc to 8 for HDMI output\n"); 9455d0b1887SFrançois Tigeot desired_bpp = 8*3; 9465d0b1887SFrançois Tigeot } 9475d0b1887SFrançois Tigeot 9485d0b1887SFrançois Tigeot if (!pipe_config->bw_constrained) { 9495d0b1887SFrançois Tigeot DRM_DEBUG_KMS("forcing pipe bpc to %i for HDMI\n", desired_bpp); 9505d0b1887SFrançois Tigeot pipe_config->pipe_bpp = desired_bpp; 9515d0b1887SFrançois Tigeot } 9525d0b1887SFrançois Tigeot 9539edbd4a0SFrançois Tigeot if (adjusted_mode->crtc_clock > portclock_limit) { 9545d0b1887SFrançois Tigeot DRM_DEBUG_KMS("too high HDMI clock, rejecting mode\n"); 9555d0b1887SFrançois Tigeot return false; 9568e26cdf6SFrançois Tigeot } 957a2fdbec6SFrançois Tigeot 958e3adcf8fSFrançois Tigeot return true; 959e3adcf8fSFrançois Tigeot } 960e3adcf8fSFrançois Tigeot 961e3adcf8fSFrançois Tigeot static enum drm_connector_status 962e3adcf8fSFrançois Tigeot intel_hdmi_detect(struct drm_connector *connector, bool force) 963e3adcf8fSFrançois Tigeot { 964a2fdbec6SFrançois Tigeot struct drm_device *dev = connector->dev; 965e3adcf8fSFrançois Tigeot struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 96619df918dSFrançois Tigeot struct intel_digital_port *intel_dig_port = 96719df918dSFrançois Tigeot hdmi_to_dig_port(intel_hdmi); 96819df918dSFrançois Tigeot struct intel_encoder *intel_encoder = &intel_dig_port->base; 969a2fdbec6SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 970e3adcf8fSFrançois Tigeot struct edid *edid; 971*ba55f2f5SFrançois Tigeot enum intel_display_power_domain power_domain; 972e3adcf8fSFrançois Tigeot enum drm_connector_status status = connector_status_disconnected; 973e3adcf8fSFrançois Tigeot 9749edbd4a0SFrançois Tigeot DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 975*ba55f2f5SFrançois Tigeot connector->base.id, "connector->name"); 976*ba55f2f5SFrançois Tigeot 977*ba55f2f5SFrançois Tigeot power_domain = intel_display_port_power_domain(intel_encoder); 978*ba55f2f5SFrançois Tigeot intel_display_power_get(dev_priv, power_domain); 9799edbd4a0SFrançois Tigeot 980e3adcf8fSFrançois Tigeot intel_hdmi->has_hdmi_sink = false; 981e3adcf8fSFrançois Tigeot intel_hdmi->has_audio = false; 982a2fdbec6SFrançois Tigeot intel_hdmi->rgb_quant_range_selectable = false; 98319df918dSFrançois Tigeot edid = drm_get_edid(connector, 98419df918dSFrançois Tigeot intel_gmbus_get_adapter(dev_priv, 98519df918dSFrançois Tigeot intel_hdmi->ddc_bus)); 986e3adcf8fSFrançois Tigeot 987e3adcf8fSFrançois Tigeot if (edid) { 988e3adcf8fSFrançois Tigeot if (edid->input & DRM_EDID_INPUT_DIGITAL) { 989e3adcf8fSFrançois Tigeot status = connector_status_connected; 990e3adcf8fSFrançois Tigeot if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI) 991e3adcf8fSFrançois Tigeot intel_hdmi->has_hdmi_sink = 992e3adcf8fSFrançois Tigeot drm_detect_hdmi_monitor(edid); 993e3adcf8fSFrançois Tigeot intel_hdmi->has_audio = drm_detect_monitor_audio(edid); 994a2fdbec6SFrançois Tigeot intel_hdmi->rgb_quant_range_selectable = 995a2fdbec6SFrançois Tigeot drm_rgb_quant_range_selectable(edid); 996e3adcf8fSFrançois Tigeot } 9978e26cdf6SFrançois Tigeot kfree(edid); 998e3adcf8fSFrançois Tigeot } 999e3adcf8fSFrançois Tigeot 1000e3adcf8fSFrançois Tigeot if (status == connector_status_connected) { 1001e3adcf8fSFrançois Tigeot if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO) 1002e3adcf8fSFrançois Tigeot intel_hdmi->has_audio = 1003e3adcf8fSFrançois Tigeot (intel_hdmi->force_audio == HDMI_AUDIO_ON); 100419df918dSFrançois Tigeot intel_encoder->type = INTEL_OUTPUT_HDMI; 1005e3adcf8fSFrançois Tigeot } 1006e3adcf8fSFrançois Tigeot 1007*ba55f2f5SFrançois Tigeot intel_display_power_put(dev_priv, power_domain); 1008*ba55f2f5SFrançois Tigeot 1009e3adcf8fSFrançois Tigeot return status; 1010e3adcf8fSFrançois Tigeot } 1011e3adcf8fSFrançois Tigeot 1012e3adcf8fSFrançois Tigeot static int intel_hdmi_get_modes(struct drm_connector *connector) 1013e3adcf8fSFrançois Tigeot { 1014*ba55f2f5SFrançois Tigeot struct intel_encoder *intel_encoder = intel_attached_encoder(connector); 1015*ba55f2f5SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base); 1016e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = connector->dev->dev_private; 1017*ba55f2f5SFrançois Tigeot enum intel_display_power_domain power_domain; 1018*ba55f2f5SFrançois Tigeot int ret; 1019e3adcf8fSFrançois Tigeot 1020e3adcf8fSFrançois Tigeot /* We should parse the EDID data and find out if it's an HDMI sink so 1021e3adcf8fSFrançois Tigeot * we can send audio to it. 1022e3adcf8fSFrançois Tigeot */ 1023e3adcf8fSFrançois Tigeot 1024*ba55f2f5SFrançois Tigeot power_domain = intel_display_port_power_domain(intel_encoder); 1025*ba55f2f5SFrançois Tigeot intel_display_power_get(dev_priv, power_domain); 1026*ba55f2f5SFrançois Tigeot 1027*ba55f2f5SFrançois Tigeot ret = intel_ddc_get_modes(connector, 102819df918dSFrançois Tigeot intel_gmbus_get_adapter(dev_priv, 102919df918dSFrançois Tigeot intel_hdmi->ddc_bus)); 1030*ba55f2f5SFrançois Tigeot 1031*ba55f2f5SFrançois Tigeot intel_display_power_put(dev_priv, power_domain); 1032*ba55f2f5SFrançois Tigeot 1033*ba55f2f5SFrançois Tigeot return ret; 1034e3adcf8fSFrançois Tigeot } 1035e3adcf8fSFrançois Tigeot 1036e3adcf8fSFrançois Tigeot static bool 1037e3adcf8fSFrançois Tigeot intel_hdmi_detect_audio(struct drm_connector *connector) 1038e3adcf8fSFrançois Tigeot { 1039*ba55f2f5SFrançois Tigeot struct intel_encoder *intel_encoder = intel_attached_encoder(connector); 1040*ba55f2f5SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base); 1041e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = connector->dev->dev_private; 1042*ba55f2f5SFrançois Tigeot enum intel_display_power_domain power_domain; 1043e3adcf8fSFrançois Tigeot struct edid *edid; 1044e3adcf8fSFrançois Tigeot bool has_audio = false; 1045e3adcf8fSFrançois Tigeot 1046*ba55f2f5SFrançois Tigeot power_domain = intel_display_port_power_domain(intel_encoder); 1047*ba55f2f5SFrançois Tigeot intel_display_power_get(dev_priv, power_domain); 1048*ba55f2f5SFrançois Tigeot 104919df918dSFrançois Tigeot edid = drm_get_edid(connector, 105019df918dSFrançois Tigeot intel_gmbus_get_adapter(dev_priv, 105119df918dSFrançois Tigeot intel_hdmi->ddc_bus)); 1052e3adcf8fSFrançois Tigeot if (edid) { 1053e3adcf8fSFrançois Tigeot if (edid->input & DRM_EDID_INPUT_DIGITAL) 1054e3adcf8fSFrançois Tigeot has_audio = drm_detect_monitor_audio(edid); 10558e26cdf6SFrançois Tigeot kfree(edid); 1056e3adcf8fSFrançois Tigeot } 1057e3adcf8fSFrançois Tigeot 1058*ba55f2f5SFrançois Tigeot intel_display_power_put(dev_priv, power_domain); 1059*ba55f2f5SFrançois Tigeot 1060e3adcf8fSFrançois Tigeot return has_audio; 1061e3adcf8fSFrançois Tigeot } 1062e3adcf8fSFrançois Tigeot 1063e3adcf8fSFrançois Tigeot static int 1064e3adcf8fSFrançois Tigeot intel_hdmi_set_property(struct drm_connector *connector, 1065e3adcf8fSFrançois Tigeot struct drm_property *property, 1066e3adcf8fSFrançois Tigeot uint64_t val) 1067e3adcf8fSFrançois Tigeot { 1068e3adcf8fSFrançois Tigeot struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 106919df918dSFrançois Tigeot struct intel_digital_port *intel_dig_port = 107019df918dSFrançois Tigeot hdmi_to_dig_port(intel_hdmi); 1071e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = connector->dev->dev_private; 1072e3adcf8fSFrançois Tigeot int ret; 1073e3adcf8fSFrançois Tigeot 1074b5162e19SFrançois Tigeot ret = drm_object_property_set_value(&connector->base, property, val); 1075e3adcf8fSFrançois Tigeot if (ret) 1076e3adcf8fSFrançois Tigeot return ret; 1077e3adcf8fSFrançois Tigeot 1078e3adcf8fSFrançois Tigeot if (property == dev_priv->force_audio_property) { 1079e3adcf8fSFrançois Tigeot enum hdmi_force_audio i = val; 1080e3adcf8fSFrançois Tigeot bool has_audio; 1081e3adcf8fSFrançois Tigeot 1082e3adcf8fSFrançois Tigeot if (i == intel_hdmi->force_audio) 1083e3adcf8fSFrançois Tigeot return 0; 1084e3adcf8fSFrançois Tigeot 1085e3adcf8fSFrançois Tigeot intel_hdmi->force_audio = i; 1086e3adcf8fSFrançois Tigeot 1087e3adcf8fSFrançois Tigeot if (i == HDMI_AUDIO_AUTO) 1088e3adcf8fSFrançois Tigeot has_audio = intel_hdmi_detect_audio(connector); 1089e3adcf8fSFrançois Tigeot else 1090e3adcf8fSFrançois Tigeot has_audio = (i == HDMI_AUDIO_ON); 1091e3adcf8fSFrançois Tigeot 1092e3adcf8fSFrançois Tigeot if (i == HDMI_AUDIO_OFF_DVI) 1093e3adcf8fSFrançois Tigeot intel_hdmi->has_hdmi_sink = 0; 1094e3adcf8fSFrançois Tigeot 1095e3adcf8fSFrançois Tigeot intel_hdmi->has_audio = has_audio; 1096e3adcf8fSFrançois Tigeot goto done; 1097e3adcf8fSFrançois Tigeot } 1098e3adcf8fSFrançois Tigeot 1099e3adcf8fSFrançois Tigeot if (property == dev_priv->broadcast_rgb_property) { 11008e26cdf6SFrançois Tigeot bool old_auto = intel_hdmi->color_range_auto; 11018e26cdf6SFrançois Tigeot uint32_t old_range = intel_hdmi->color_range; 11028e26cdf6SFrançois Tigeot 1103a2fdbec6SFrançois Tigeot switch (val) { 1104a2fdbec6SFrançois Tigeot case INTEL_BROADCAST_RGB_AUTO: 1105a2fdbec6SFrançois Tigeot intel_hdmi->color_range_auto = true; 1106a2fdbec6SFrançois Tigeot break; 1107a2fdbec6SFrançois Tigeot case INTEL_BROADCAST_RGB_FULL: 1108a2fdbec6SFrançois Tigeot intel_hdmi->color_range_auto = false; 1109a2fdbec6SFrançois Tigeot intel_hdmi->color_range = 0; 1110a2fdbec6SFrançois Tigeot break; 1111a2fdbec6SFrançois Tigeot case INTEL_BROADCAST_RGB_LIMITED: 1112a2fdbec6SFrançois Tigeot intel_hdmi->color_range_auto = false; 11138e26cdf6SFrançois Tigeot intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235; 1114a2fdbec6SFrançois Tigeot break; 1115a2fdbec6SFrançois Tigeot default: 1116a2fdbec6SFrançois Tigeot return -EINVAL; 1117a2fdbec6SFrançois Tigeot } 11188e26cdf6SFrançois Tigeot 11198e26cdf6SFrançois Tigeot if (old_auto == intel_hdmi->color_range_auto && 11208e26cdf6SFrançois Tigeot old_range == intel_hdmi->color_range) 11218e26cdf6SFrançois Tigeot return 0; 11228e26cdf6SFrançois Tigeot 1123e3adcf8fSFrançois Tigeot goto done; 1124e3adcf8fSFrançois Tigeot } 1125e3adcf8fSFrançois Tigeot 1126e3adcf8fSFrançois Tigeot return -EINVAL; 1127e3adcf8fSFrançois Tigeot 1128e3adcf8fSFrançois Tigeot done: 1129a2fdbec6SFrançois Tigeot if (intel_dig_port->base.base.crtc) 1130a2fdbec6SFrançois Tigeot intel_crtc_restore_mode(intel_dig_port->base.base.crtc); 1131e3adcf8fSFrançois Tigeot 1132e3adcf8fSFrançois Tigeot return 0; 1133e3adcf8fSFrançois Tigeot } 1134e3adcf8fSFrançois Tigeot 1135*ba55f2f5SFrançois Tigeot static void intel_hdmi_pre_enable(struct intel_encoder *encoder) 1136*ba55f2f5SFrançois Tigeot { 1137*ba55f2f5SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); 1138*ba55f2f5SFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); 1139*ba55f2f5SFrançois Tigeot struct drm_display_mode *adjusted_mode = 1140*ba55f2f5SFrançois Tigeot &intel_crtc->config.adjusted_mode; 1141*ba55f2f5SFrançois Tigeot 1142*ba55f2f5SFrançois Tigeot intel_hdmi_prepare(encoder); 1143*ba55f2f5SFrançois Tigeot 1144*ba55f2f5SFrançois Tigeot intel_hdmi->set_infoframes(&encoder->base, 1145*ba55f2f5SFrançois Tigeot intel_crtc->config.has_hdmi_sink, 1146*ba55f2f5SFrançois Tigeot adjusted_mode); 1147*ba55f2f5SFrançois Tigeot } 1148*ba55f2f5SFrançois Tigeot 11499edbd4a0SFrançois Tigeot static void vlv_hdmi_pre_enable(struct intel_encoder *encoder) 11505d0b1887SFrançois Tigeot { 11515d0b1887SFrançois Tigeot struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); 1152*ba55f2f5SFrançois Tigeot struct intel_hdmi *intel_hdmi = &dport->hdmi; 11535d0b1887SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 11545d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 11555d0b1887SFrançois Tigeot struct intel_crtc *intel_crtc = 11565d0b1887SFrançois Tigeot to_intel_crtc(encoder->base.crtc); 1157*ba55f2f5SFrançois Tigeot struct drm_display_mode *adjusted_mode = 1158*ba55f2f5SFrançois Tigeot &intel_crtc->config.adjusted_mode; 11599edbd4a0SFrançois Tigeot enum dpio_channel port = vlv_dport_to_channel(dport); 11605d0b1887SFrançois Tigeot int pipe = intel_crtc->pipe; 11615d0b1887SFrançois Tigeot u32 val; 11625d0b1887SFrançois Tigeot 11635d0b1887SFrançois Tigeot /* Enable clock channels for this port */ 11649edbd4a0SFrançois Tigeot mutex_lock(&dev_priv->dpio_lock); 11659edbd4a0SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(port)); 11665d0b1887SFrançois Tigeot val = 0; 11675d0b1887SFrançois Tigeot if (pipe) 11685d0b1887SFrançois Tigeot val |= (1<<21); 11695d0b1887SFrançois Tigeot else 11705d0b1887SFrançois Tigeot val &= ~(1<<21); 11715d0b1887SFrançois Tigeot val |= 0x001000c4; 11729edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW8(port), val); 11735d0b1887SFrançois Tigeot 11745d0b1887SFrançois Tigeot /* HDMI 1.0V-2dB */ 11759edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), 0); 11769edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW4(port), 0x2b245f5f); 11779edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW2(port), 0x5578b83a); 11789edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW3(port), 0x0c782040); 11799edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX3_DW4(port), 0x2b247878); 11809edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW11(port), 0x00030000); 11819edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW9(port), 0x00002000); 11829edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), DPIO_TX_OCALINIT_EN); 11835d0b1887SFrançois Tigeot 11845d0b1887SFrançois Tigeot /* Program lane clock */ 11859edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW14(port), 0x00760018); 11869edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW23(port), 0x00400888); 11879edbd4a0SFrançois Tigeot mutex_unlock(&dev_priv->dpio_lock); 11889edbd4a0SFrançois Tigeot 1189*ba55f2f5SFrançois Tigeot intel_hdmi->set_infoframes(&encoder->base, 1190*ba55f2f5SFrançois Tigeot intel_crtc->config.has_hdmi_sink, 1191*ba55f2f5SFrançois Tigeot adjusted_mode); 1192*ba55f2f5SFrançois Tigeot 11939edbd4a0SFrançois Tigeot intel_enable_hdmi(encoder); 11949edbd4a0SFrançois Tigeot 11959edbd4a0SFrançois Tigeot vlv_wait_port_ready(dev_priv, dport); 11965d0b1887SFrançois Tigeot } 11975d0b1887SFrançois Tigeot 11989edbd4a0SFrançois Tigeot static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder) 11995d0b1887SFrançois Tigeot { 12005d0b1887SFrançois Tigeot struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); 12015d0b1887SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 12025d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 12039edbd4a0SFrançois Tigeot struct intel_crtc *intel_crtc = 12049edbd4a0SFrançois Tigeot to_intel_crtc(encoder->base.crtc); 12059edbd4a0SFrançois Tigeot enum dpio_channel port = vlv_dport_to_channel(dport); 12069edbd4a0SFrançois Tigeot int pipe = intel_crtc->pipe; 12075d0b1887SFrançois Tigeot 1208*ba55f2f5SFrançois Tigeot intel_hdmi_prepare(encoder); 12095d0b1887SFrançois Tigeot 12105d0b1887SFrançois Tigeot /* Program Tx lane resets to default */ 12119edbd4a0SFrançois Tigeot mutex_lock(&dev_priv->dpio_lock); 12129edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), 12135d0b1887SFrançois Tigeot DPIO_PCS_TX_LANE2_RESET | 12145d0b1887SFrançois Tigeot DPIO_PCS_TX_LANE1_RESET); 12159edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), 12165d0b1887SFrançois Tigeot DPIO_PCS_CLK_CRI_RXEB_EIOS_EN | 12175d0b1887SFrançois Tigeot DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN | 12185d0b1887SFrançois Tigeot (1<<DPIO_PCS_CLK_DATAWIDTH_SHIFT) | 12195d0b1887SFrançois Tigeot DPIO_PCS_CLK_SOFT_RESET); 12205d0b1887SFrançois Tigeot 12215d0b1887SFrançois Tigeot /* Fix up inter-pair skew failure */ 12229edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW12(port), 0x00750f00); 12239edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW11(port), 0x00001500); 12249edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW14(port), 0x40400000); 12255d0b1887SFrançois Tigeot 12269edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW9(port), 0x00002000); 12279edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), DPIO_TX_OCALINIT_EN); 12289edbd4a0SFrançois Tigeot mutex_unlock(&dev_priv->dpio_lock); 12295d0b1887SFrançois Tigeot } 12305d0b1887SFrançois Tigeot 12319edbd4a0SFrançois Tigeot static void vlv_hdmi_post_disable(struct intel_encoder *encoder) 12325d0b1887SFrançois Tigeot { 12335d0b1887SFrançois Tigeot struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); 12345d0b1887SFrançois Tigeot struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; 12359edbd4a0SFrançois Tigeot struct intel_crtc *intel_crtc = 12369edbd4a0SFrançois Tigeot to_intel_crtc(encoder->base.crtc); 12379edbd4a0SFrançois Tigeot enum dpio_channel port = vlv_dport_to_channel(dport); 12389edbd4a0SFrançois Tigeot int pipe = intel_crtc->pipe; 12395d0b1887SFrançois Tigeot 12405d0b1887SFrançois Tigeot /* Reset lanes to avoid HDMI flicker (VLV w/a) */ 12415d0b1887SFrançois Tigeot mutex_lock(&dev_priv->dpio_lock); 12429edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), 0x00000000); 12439edbd4a0SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), 0x00e00060); 12445d0b1887SFrançois Tigeot mutex_unlock(&dev_priv->dpio_lock); 12455d0b1887SFrançois Tigeot } 12465d0b1887SFrançois Tigeot 1247*ba55f2f5SFrançois Tigeot static void chv_hdmi_post_disable(struct intel_encoder *encoder) 1248*ba55f2f5SFrançois Tigeot { 1249*ba55f2f5SFrançois Tigeot struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); 1250*ba55f2f5SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 1251*ba55f2f5SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1252*ba55f2f5SFrançois Tigeot struct intel_crtc *intel_crtc = 1253*ba55f2f5SFrançois Tigeot to_intel_crtc(encoder->base.crtc); 1254*ba55f2f5SFrançois Tigeot enum dpio_channel ch = vlv_dport_to_channel(dport); 1255*ba55f2f5SFrançois Tigeot enum i915_pipe pipe = intel_crtc->pipe; 1256*ba55f2f5SFrançois Tigeot u32 val; 1257*ba55f2f5SFrançois Tigeot 1258*ba55f2f5SFrançois Tigeot mutex_lock(&dev_priv->dpio_lock); 1259*ba55f2f5SFrançois Tigeot 1260*ba55f2f5SFrançois Tigeot /* Propagate soft reset to data lane reset */ 1261*ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch)); 1262*ba55f2f5SFrançois Tigeot val |= CHV_PCS_REQ_SOFTRESET_EN; 1263*ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val); 1264*ba55f2f5SFrançois Tigeot 1265*ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch)); 1266*ba55f2f5SFrançois Tigeot val |= CHV_PCS_REQ_SOFTRESET_EN; 1267*ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val); 1268*ba55f2f5SFrançois Tigeot 1269*ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch)); 1270*ba55f2f5SFrançois Tigeot val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); 1271*ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val); 1272*ba55f2f5SFrançois Tigeot 1273*ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch)); 1274*ba55f2f5SFrançois Tigeot val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); 1275*ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val); 1276*ba55f2f5SFrançois Tigeot 1277*ba55f2f5SFrançois Tigeot mutex_unlock(&dev_priv->dpio_lock); 1278*ba55f2f5SFrançois Tigeot } 1279*ba55f2f5SFrançois Tigeot 1280*ba55f2f5SFrançois Tigeot static void chv_hdmi_pre_enable(struct intel_encoder *encoder) 1281*ba55f2f5SFrançois Tigeot { 1282*ba55f2f5SFrançois Tigeot struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); 1283*ba55f2f5SFrançois Tigeot struct drm_device *dev = encoder->base.dev; 1284*ba55f2f5SFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 1285*ba55f2f5SFrançois Tigeot struct intel_crtc *intel_crtc = 1286*ba55f2f5SFrançois Tigeot to_intel_crtc(encoder->base.crtc); 1287*ba55f2f5SFrançois Tigeot enum dpio_channel ch = vlv_dport_to_channel(dport); 1288*ba55f2f5SFrançois Tigeot int pipe = intel_crtc->pipe; 1289*ba55f2f5SFrançois Tigeot int data, i; 1290*ba55f2f5SFrançois Tigeot u32 val; 1291*ba55f2f5SFrançois Tigeot 1292*ba55f2f5SFrançois Tigeot mutex_lock(&dev_priv->dpio_lock); 1293*ba55f2f5SFrançois Tigeot 1294*ba55f2f5SFrançois Tigeot /* Deassert soft data lane reset*/ 1295*ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch)); 1296*ba55f2f5SFrançois Tigeot val |= CHV_PCS_REQ_SOFTRESET_EN; 1297*ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val); 1298*ba55f2f5SFrançois Tigeot 1299*ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch)); 1300*ba55f2f5SFrançois Tigeot val |= CHV_PCS_REQ_SOFTRESET_EN; 1301*ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val); 1302*ba55f2f5SFrançois Tigeot 1303*ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch)); 1304*ba55f2f5SFrançois Tigeot val |= (DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); 1305*ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val); 1306*ba55f2f5SFrançois Tigeot 1307*ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch)); 1308*ba55f2f5SFrançois Tigeot val |= (DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); 1309*ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val); 1310*ba55f2f5SFrançois Tigeot 1311*ba55f2f5SFrançois Tigeot /* Program Tx latency optimal setting */ 1312*ba55f2f5SFrançois Tigeot for (i = 0; i < 4; i++) { 1313*ba55f2f5SFrançois Tigeot /* Set the latency optimal bit */ 1314*ba55f2f5SFrançois Tigeot data = (i == 1) ? 0x0 : 0x6; 1315*ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, CHV_TX_DW11(ch, i), 1316*ba55f2f5SFrançois Tigeot data << DPIO_FRC_LATENCY_SHFIT); 1317*ba55f2f5SFrançois Tigeot 1318*ba55f2f5SFrançois Tigeot /* Set the upar bit */ 1319*ba55f2f5SFrançois Tigeot data = (i == 1) ? 0x0 : 0x1; 1320*ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, CHV_TX_DW14(ch, i), 1321*ba55f2f5SFrançois Tigeot data << DPIO_UPAR_SHIFT); 1322*ba55f2f5SFrançois Tigeot } 1323*ba55f2f5SFrançois Tigeot 1324*ba55f2f5SFrançois Tigeot /* Data lane stagger programming */ 1325*ba55f2f5SFrançois Tigeot /* FIXME: Fix up value only after power analysis */ 1326*ba55f2f5SFrançois Tigeot 1327*ba55f2f5SFrançois Tigeot /* Clear calc init */ 1328*ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW10(ch)); 1329*ba55f2f5SFrançois Tigeot val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3); 1330*ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val); 1331*ba55f2f5SFrançois Tigeot 1332*ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch)); 1333*ba55f2f5SFrançois Tigeot val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3); 1334*ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val); 1335*ba55f2f5SFrançois Tigeot 1336*ba55f2f5SFrançois Tigeot /* FIXME: Program the support xxx V-dB */ 1337*ba55f2f5SFrançois Tigeot /* Use 800mV-0dB */ 1338*ba55f2f5SFrançois Tigeot for (i = 0; i < 4; i++) { 1339*ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW4(ch, i)); 1340*ba55f2f5SFrançois Tigeot val &= ~DPIO_SWING_DEEMPH9P5_MASK; 1341*ba55f2f5SFrançois Tigeot val |= 128 << DPIO_SWING_DEEMPH9P5_SHIFT; 1342*ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, CHV_TX_DW4(ch, i), val); 1343*ba55f2f5SFrançois Tigeot } 1344*ba55f2f5SFrançois Tigeot 1345*ba55f2f5SFrançois Tigeot for (i = 0; i < 4; i++) { 1346*ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i)); 1347*ba55f2f5SFrançois Tigeot val &= ~DPIO_SWING_MARGIN_MASK; 1348*ba55f2f5SFrançois Tigeot val |= 102 << DPIO_SWING_MARGIN_SHIFT; 1349*ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, CHV_TX_DW2(ch, i), val); 1350*ba55f2f5SFrançois Tigeot } 1351*ba55f2f5SFrançois Tigeot 1352*ba55f2f5SFrançois Tigeot /* Disable unique transition scale */ 1353*ba55f2f5SFrançois Tigeot for (i = 0; i < 4; i++) { 1354*ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW3(ch, i)); 1355*ba55f2f5SFrançois Tigeot val &= ~DPIO_TX_UNIQ_TRANS_SCALE_EN; 1356*ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, CHV_TX_DW3(ch, i), val); 1357*ba55f2f5SFrançois Tigeot } 1358*ba55f2f5SFrançois Tigeot 1359*ba55f2f5SFrançois Tigeot /* Additional steps for 1200mV-0dB */ 1360*ba55f2f5SFrançois Tigeot #if 0 1361*ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_TX_DW3(ch)); 1362*ba55f2f5SFrançois Tigeot if (ch) 1363*ba55f2f5SFrançois Tigeot val |= DPIO_TX_UNIQ_TRANS_SCALE_CH1; 1364*ba55f2f5SFrançois Tigeot else 1365*ba55f2f5SFrançois Tigeot val |= DPIO_TX_UNIQ_TRANS_SCALE_CH0; 1366*ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW3(ch), val); 1367*ba55f2f5SFrançois Tigeot 1368*ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_TX_DW2(ch), 1369*ba55f2f5SFrançois Tigeot vlv_dpio_read(dev_priv, pipe, VLV_TX_DW2(ch)) | 1370*ba55f2f5SFrançois Tigeot (0x9a << DPIO_UNIQ_TRANS_SCALE_SHIFT)); 1371*ba55f2f5SFrançois Tigeot #endif 1372*ba55f2f5SFrançois Tigeot /* Start swing calculation */ 1373*ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW10(ch)); 1374*ba55f2f5SFrançois Tigeot val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3; 1375*ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val); 1376*ba55f2f5SFrançois Tigeot 1377*ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch)); 1378*ba55f2f5SFrançois Tigeot val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3; 1379*ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val); 1380*ba55f2f5SFrançois Tigeot 1381*ba55f2f5SFrançois Tigeot /* LRC Bypass */ 1382*ba55f2f5SFrançois Tigeot val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW30); 1383*ba55f2f5SFrançois Tigeot val |= DPIO_LRC_BYPASS; 1384*ba55f2f5SFrançois Tigeot vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW30, val); 1385*ba55f2f5SFrançois Tigeot 1386*ba55f2f5SFrançois Tigeot mutex_unlock(&dev_priv->dpio_lock); 1387*ba55f2f5SFrançois Tigeot 1388*ba55f2f5SFrançois Tigeot intel_enable_hdmi(encoder); 1389*ba55f2f5SFrançois Tigeot 1390*ba55f2f5SFrançois Tigeot vlv_wait_port_ready(dev_priv, dport); 1391*ba55f2f5SFrançois Tigeot } 1392*ba55f2f5SFrançois Tigeot 1393e3adcf8fSFrançois Tigeot static void intel_hdmi_destroy(struct drm_connector *connector) 1394e3adcf8fSFrançois Tigeot { 1395e3adcf8fSFrançois Tigeot drm_connector_cleanup(connector); 13968e26cdf6SFrançois Tigeot kfree(connector); 1397e3adcf8fSFrançois Tigeot } 1398e3adcf8fSFrançois Tigeot 1399e3adcf8fSFrançois Tigeot static const struct drm_connector_funcs intel_hdmi_connector_funcs = { 140019df918dSFrançois Tigeot .dpms = intel_connector_dpms, 1401e3adcf8fSFrançois Tigeot .detect = intel_hdmi_detect, 1402e3adcf8fSFrançois Tigeot .fill_modes = drm_helper_probe_single_connector_modes, 1403e3adcf8fSFrançois Tigeot .set_property = intel_hdmi_set_property, 1404e3adcf8fSFrançois Tigeot .destroy = intel_hdmi_destroy, 1405e3adcf8fSFrançois Tigeot }; 1406e3adcf8fSFrançois Tigeot 1407e3adcf8fSFrançois Tigeot static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = { 1408e3adcf8fSFrançois Tigeot .get_modes = intel_hdmi_get_modes, 1409e3adcf8fSFrançois Tigeot .mode_valid = intel_hdmi_mode_valid, 1410e3adcf8fSFrançois Tigeot .best_encoder = intel_best_encoder, 1411e3adcf8fSFrançois Tigeot }; 1412e3adcf8fSFrançois Tigeot 1413e3adcf8fSFrançois Tigeot static const struct drm_encoder_funcs intel_hdmi_enc_funcs = { 1414e3adcf8fSFrançois Tigeot .destroy = intel_encoder_destroy, 1415e3adcf8fSFrançois Tigeot }; 1416e3adcf8fSFrançois Tigeot 1417e3adcf8fSFrançois Tigeot static void 1418e3adcf8fSFrançois Tigeot intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector) 1419e3adcf8fSFrançois Tigeot { 1420e3adcf8fSFrançois Tigeot intel_attach_force_audio_property(connector); 1421e3adcf8fSFrançois Tigeot intel_attach_broadcast_rgb_property(connector); 1422a2fdbec6SFrançois Tigeot intel_hdmi->color_range_auto = true; 1423e3adcf8fSFrançois Tigeot } 1424e3adcf8fSFrançois Tigeot 142519df918dSFrançois Tigeot void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, 142619df918dSFrançois Tigeot struct intel_connector *intel_connector) 1427e3adcf8fSFrançois Tigeot { 142819df918dSFrançois Tigeot struct drm_connector *connector = &intel_connector->base; 142919df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; 143019df918dSFrançois Tigeot struct intel_encoder *intel_encoder = &intel_dig_port->base; 143119df918dSFrançois Tigeot struct drm_device *dev = intel_encoder->base.dev; 1432e3adcf8fSFrançois Tigeot struct drm_i915_private *dev_priv = dev->dev_private; 143319df918dSFrançois Tigeot enum port port = intel_dig_port->port; 1434e3adcf8fSFrançois Tigeot 1435e3adcf8fSFrançois Tigeot drm_connector_init(dev, connector, &intel_hdmi_connector_funcs, 1436e3adcf8fSFrançois Tigeot DRM_MODE_CONNECTOR_HDMIA); 1437e3adcf8fSFrançois Tigeot drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs); 1438e3adcf8fSFrançois Tigeot 1439e3adcf8fSFrançois Tigeot connector->interlace_allowed = 1; 1440e3adcf8fSFrançois Tigeot connector->doublescan_allowed = 0; 14419edbd4a0SFrançois Tigeot connector->stereo_allowed = 1; 1442e3adcf8fSFrançois Tigeot 144319df918dSFrançois Tigeot switch (port) { 144419df918dSFrançois Tigeot case PORT_B: 1445e3adcf8fSFrançois Tigeot intel_hdmi->ddc_bus = GMBUS_PORT_DPB; 14468e26cdf6SFrançois Tigeot intel_encoder->hpd_pin = HPD_PORT_B; 144719df918dSFrançois Tigeot break; 144819df918dSFrançois Tigeot case PORT_C: 1449e3adcf8fSFrançois Tigeot intel_hdmi->ddc_bus = GMBUS_PORT_DPC; 14508e26cdf6SFrançois Tigeot intel_encoder->hpd_pin = HPD_PORT_C; 145119df918dSFrançois Tigeot break; 145219df918dSFrançois Tigeot case PORT_D: 1453*ba55f2f5SFrançois Tigeot if (IS_CHERRYVIEW(dev)) 1454*ba55f2f5SFrançois Tigeot intel_hdmi->ddc_bus = GMBUS_PORT_DPD_CHV; 1455*ba55f2f5SFrançois Tigeot else 1456e3adcf8fSFrançois Tigeot intel_hdmi->ddc_bus = GMBUS_PORT_DPD; 14578e26cdf6SFrançois Tigeot intel_encoder->hpd_pin = HPD_PORT_D; 145819df918dSFrançois Tigeot break; 145919df918dSFrançois Tigeot case PORT_A: 14608e26cdf6SFrançois Tigeot intel_encoder->hpd_pin = HPD_PORT_A; 146119df918dSFrançois Tigeot /* Internal port only for eDP. */ 146219df918dSFrançois Tigeot default: 146319df918dSFrançois Tigeot BUG(); 1464e3adcf8fSFrançois Tigeot } 1465e3adcf8fSFrançois Tigeot 14668e26cdf6SFrançois Tigeot if (IS_VALLEYVIEW(dev)) { 146719df918dSFrançois Tigeot intel_hdmi->write_infoframe = vlv_write_infoframe; 146819df918dSFrançois Tigeot intel_hdmi->set_infoframes = vlv_set_infoframes; 14698e26cdf6SFrançois Tigeot } else if (!HAS_PCH_SPLIT(dev)) { 14708e26cdf6SFrançois Tigeot intel_hdmi->write_infoframe = g4x_write_infoframe; 14718e26cdf6SFrançois Tigeot intel_hdmi->set_infoframes = g4x_set_infoframes; 14728e26cdf6SFrançois Tigeot } else if (HAS_DDI(dev)) { 147319df918dSFrançois Tigeot intel_hdmi->write_infoframe = hsw_write_infoframe; 147419df918dSFrançois Tigeot intel_hdmi->set_infoframes = hsw_set_infoframes; 147519df918dSFrançois Tigeot } else if (HAS_PCH_IBX(dev)) { 147619df918dSFrançois Tigeot intel_hdmi->write_infoframe = ibx_write_infoframe; 147719df918dSFrançois Tigeot intel_hdmi->set_infoframes = ibx_set_infoframes; 1478e3adcf8fSFrançois Tigeot } else { 147919df918dSFrançois Tigeot intel_hdmi->write_infoframe = cpt_write_infoframe; 148019df918dSFrançois Tigeot intel_hdmi->set_infoframes = cpt_set_infoframes; 1481e3adcf8fSFrançois Tigeot } 1482e3adcf8fSFrançois Tigeot 1483a2fdbec6SFrançois Tigeot if (HAS_DDI(dev)) 148419df918dSFrançois Tigeot intel_connector->get_hw_state = intel_ddi_connector_get_hw_state; 148519df918dSFrançois Tigeot else 148619df918dSFrançois Tigeot intel_connector->get_hw_state = intel_connector_get_hw_state; 1487*ba55f2f5SFrançois Tigeot intel_connector->unregister = intel_connector_unregister; 1488e3adcf8fSFrançois Tigeot 1489e3adcf8fSFrançois Tigeot intel_hdmi_add_properties(intel_hdmi, connector); 1490e3adcf8fSFrançois Tigeot 1491e3adcf8fSFrançois Tigeot intel_connector_attach_encoder(intel_connector, intel_encoder); 1492e3adcf8fSFrançois Tigeot drm_sysfs_connector_add(connector); 1493e3adcf8fSFrançois Tigeot 1494e3adcf8fSFrançois Tigeot /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written 1495e3adcf8fSFrançois Tigeot * 0xd. Failure to do so will result in spurious interrupts being 1496e3adcf8fSFrançois Tigeot * generated on the port when a cable is not attached. 1497e3adcf8fSFrançois Tigeot */ 1498e3adcf8fSFrançois Tigeot if (IS_G4X(dev) && !IS_GM45(dev)) { 1499e3adcf8fSFrançois Tigeot u32 temp = I915_READ(PEG_BAND_GAP_DATA); 1500e3adcf8fSFrançois Tigeot I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); 1501e3adcf8fSFrançois Tigeot } 1502e3adcf8fSFrançois Tigeot } 150319df918dSFrançois Tigeot 15048e26cdf6SFrançois Tigeot void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) 150519df918dSFrançois Tigeot { 150619df918dSFrançois Tigeot struct intel_digital_port *intel_dig_port; 150719df918dSFrançois Tigeot struct intel_encoder *intel_encoder; 150819df918dSFrançois Tigeot struct intel_connector *intel_connector; 150919df918dSFrançois Tigeot 15109edbd4a0SFrançois Tigeot intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL); 151119df918dSFrançois Tigeot if (!intel_dig_port) 151219df918dSFrançois Tigeot return; 151319df918dSFrançois Tigeot 15149edbd4a0SFrançois Tigeot intel_connector = kzalloc(sizeof(*intel_connector), GFP_KERNEL); 151519df918dSFrançois Tigeot if (!intel_connector) { 1516158486a6SFrançois Tigeot kfree(intel_dig_port); 151719df918dSFrançois Tigeot return; 151819df918dSFrançois Tigeot } 151919df918dSFrançois Tigeot 152019df918dSFrançois Tigeot intel_encoder = &intel_dig_port->base; 152119df918dSFrançois Tigeot 152219df918dSFrançois Tigeot drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs, 152319df918dSFrançois Tigeot DRM_MODE_ENCODER_TMDS); 152419df918dSFrançois Tigeot 15258e26cdf6SFrançois Tigeot intel_encoder->compute_config = intel_hdmi_compute_config; 152619df918dSFrançois Tigeot intel_encoder->disable = intel_disable_hdmi; 152719df918dSFrançois Tigeot intel_encoder->get_hw_state = intel_hdmi_get_hw_state; 15285d0b1887SFrançois Tigeot intel_encoder->get_config = intel_hdmi_get_config; 1529*ba55f2f5SFrançois Tigeot if (IS_CHERRYVIEW(dev)) { 1530*ba55f2f5SFrançois Tigeot intel_encoder->pre_enable = chv_hdmi_pre_enable; 1531*ba55f2f5SFrançois Tigeot intel_encoder->enable = vlv_enable_hdmi; 1532*ba55f2f5SFrançois Tigeot intel_encoder->post_disable = chv_hdmi_post_disable; 1533*ba55f2f5SFrançois Tigeot } else if (IS_VALLEYVIEW(dev)) { 15349edbd4a0SFrançois Tigeot intel_encoder->pre_pll_enable = vlv_hdmi_pre_pll_enable; 15359edbd4a0SFrançois Tigeot intel_encoder->pre_enable = vlv_hdmi_pre_enable; 15369edbd4a0SFrançois Tigeot intel_encoder->enable = vlv_enable_hdmi; 15379edbd4a0SFrançois Tigeot intel_encoder->post_disable = vlv_hdmi_post_disable; 15389edbd4a0SFrançois Tigeot } else { 1539*ba55f2f5SFrançois Tigeot intel_encoder->pre_enable = intel_hdmi_pre_enable; 15409edbd4a0SFrançois Tigeot intel_encoder->enable = intel_enable_hdmi; 15415d0b1887SFrançois Tigeot } 154219df918dSFrançois Tigeot 154319df918dSFrançois Tigeot intel_encoder->type = INTEL_OUTPUT_HDMI; 1544*ba55f2f5SFrançois Tigeot if (IS_CHERRYVIEW(dev)) { 1545*ba55f2f5SFrançois Tigeot if (port == PORT_D) 1546*ba55f2f5SFrançois Tigeot intel_encoder->crtc_mask = 1 << 2; 1547*ba55f2f5SFrançois Tigeot else 1548*ba55f2f5SFrançois Tigeot intel_encoder->crtc_mask = (1 << 0) | (1 << 1); 1549*ba55f2f5SFrançois Tigeot } else { 155019df918dSFrançois Tigeot intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); 1551*ba55f2f5SFrançois Tigeot } 1552*ba55f2f5SFrançois Tigeot intel_encoder->cloneable = 1 << INTEL_OUTPUT_ANALOG; 1553*ba55f2f5SFrançois Tigeot /* 1554*ba55f2f5SFrançois Tigeot * BSpec is unclear about HDMI+HDMI cloning on g4x, but it seems 1555*ba55f2f5SFrançois Tigeot * to work on real hardware. And since g4x can send infoframes to 1556*ba55f2f5SFrançois Tigeot * only one port anyway, nothing is lost by allowing it. 1557*ba55f2f5SFrançois Tigeot */ 1558*ba55f2f5SFrançois Tigeot if (IS_G4X(dev)) 1559*ba55f2f5SFrançois Tigeot intel_encoder->cloneable |= 1 << INTEL_OUTPUT_HDMI; 156019df918dSFrançois Tigeot 156119df918dSFrançois Tigeot intel_dig_port->port = port; 15628e26cdf6SFrançois Tigeot intel_dig_port->hdmi.hdmi_reg = hdmi_reg; 156319df918dSFrançois Tigeot intel_dig_port->dp.output_reg = 0; 156419df918dSFrançois Tigeot 156519df918dSFrançois Tigeot intel_hdmi_init_connector(intel_dig_port, intel_connector); 156619df918dSFrançois Tigeot } 1567