intel_hdmi.c revision 3f43c48d333777e815ae68d66396cb6dfbc2dd79
17d57382e65994ab7d01741373bd1c420370aed9fEric Anholt/* 27d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * Copyright 2006 Dave Airlie <airlied@linux.ie> 37d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * Copyright © 2006-2009 Intel Corporation 47d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * 57d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * Permission is hereby granted, free of charge, to any person obtaining a 67d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * copy of this software and associated documentation files (the "Software"), 77d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * to deal in the Software without restriction, including without limitation 87d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * the rights to use, copy, modify, merge, publish, distribute, sublicense, 97d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * and/or sell copies of the Software, and to permit persons to whom the 107d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * Software is furnished to do so, subject to the following conditions: 117d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * 127d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * The above copyright notice and this permission notice (including the next 137d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * paragraph) shall be included in all copies or substantial portions of the 147d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * Software. 157d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * 167d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 177d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 187d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 197d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 207d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 217d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 227d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * DEALINGS IN THE SOFTWARE. 237d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * 247d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * Authors: 257d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * Eric Anholt <eric@anholt.net> 267d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * Jesse Barnes <jesse.barnes@intel.com> 277d57382e65994ab7d01741373bd1c420370aed9fEric Anholt */ 287d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 297d57382e65994ab7d01741373bd1c420370aed9fEric Anholt#include <linux/i2c.h> 305a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 317d57382e65994ab7d01741373bd1c420370aed9fEric Anholt#include <linux/delay.h> 327d57382e65994ab7d01741373bd1c420370aed9fEric Anholt#include "drmP.h" 337d57382e65994ab7d01741373bd1c420370aed9fEric Anholt#include "drm.h" 347d57382e65994ab7d01741373bd1c420370aed9fEric Anholt#include "drm_crtc.h" 35aa93d632c496184e5b779dbcf961bf1c6ececf0bKeith Packard#include "drm_edid.h" 367d57382e65994ab7d01741373bd1c420370aed9fEric Anholt#include "intel_drv.h" 377d57382e65994ab7d01741373bd1c420370aed9fEric Anholt#include "i915_drm.h" 387d57382e65994ab7d01741373bd1c420370aed9fEric Anholt#include "i915_drv.h" 397d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 40ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilsonstruct intel_hdmi { 41ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson struct intel_encoder base; 427d57382e65994ab7d01741373bd1c420370aed9fEric Anholt u32 sdvox_reg; 43f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson int ddc_bus; 44e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson uint32_t color_range; 459dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling bool has_hdmi_sink; 462e3d6006aca163db3eeb931cec631974aaa3c293Zhenyu Wang bool has_audio; 4755b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson int force_audio; 487d57382e65994ab7d01741373bd1c420370aed9fEric Anholt}; 497d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 50ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilsonstatic struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) 51ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson{ 524ef69c7a64b78d477d1666eba258ca049e8bac91Chris Wilson return container_of(encoder, struct intel_hdmi, base.base); 53ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson} 54ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson 55df0e924883d029a8651a2a0c7b8da67a07611ed2Chris Wilsonstatic struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector) 56df0e924883d029a8651a2a0c7b8da67a07611ed2Chris Wilson{ 57df0e924883d029a8651a2a0c7b8da67a07611ed2Chris Wilson return container_of(intel_attached_encoder(connector), 58df0e924883d029a8651a2a0c7b8da67a07611ed2Chris Wilson struct intel_hdmi, base); 59df0e924883d029a8651a2a0c7b8da67a07611ed2Chris Wilson} 60df0e924883d029a8651a2a0c7b8da67a07611ed2Chris Wilson 613c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdemanvoid intel_dip_infoframe_csum(struct dip_infoframe *avi_if) 623c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman{ 633c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman uint8_t *data = (uint8_t *)avi_if; 643c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman uint8_t sum = 0; 653c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman unsigned i; 663c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 673c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman avi_if->checksum = 0; 683c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman avi_if->ecc = 0; 693c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 703c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman for (i = 0; i < sizeof(*avi_if); i++) 713c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman sum += data[i]; 723c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 733c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman avi_if->checksum = 0x100 - sum; 743c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman} 753c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 763c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdemanstatic void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) 773c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman{ 783c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman struct dip_infoframe avi_if = { 793c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman .type = DIP_TYPE_AVI, 803c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman .ver = DIP_VERSION_AVI, 813c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman .len = DIP_LEN_AVI, 823c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman }; 833c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman uint32_t *data = (uint32_t *)&avi_if; 843c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman struct drm_device *dev = encoder->dev; 853c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman struct drm_i915_private *dev_priv = dev->dev_private; 863c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 873c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman u32 port; 883c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman unsigned i; 893c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 903c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman if (!intel_hdmi->has_hdmi_sink) 913c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman return; 923c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 933c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman /* XXX first guess at handling video port, is this corrent? */ 943c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman if (intel_hdmi->sdvox_reg == SDVOB) 953c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman port = VIDEO_DIP_PORT_B; 963c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman else if (intel_hdmi->sdvox_reg == SDVOC) 973c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman port = VIDEO_DIP_PORT_C; 983c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman else 993c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman return; 1003c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 1013c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port | 1023c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC); 1033c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 1043c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman intel_dip_infoframe_csum(&avi_if); 1053c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman for (i = 0; i < sizeof(avi_if); i += 4) { 1063c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman I915_WRITE(VIDEO_DIP_DATA, *data); 1073c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman data++; 1083c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman } 1093c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 1103c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port | 1113c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC | 1123c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman VIDEO_DIP_ENABLE_AVI); 1133c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman} 1143c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 1157d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic void intel_hdmi_mode_set(struct drm_encoder *encoder, 1167d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_display_mode *mode, 1177d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_display_mode *adjusted_mode) 1187d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 1197d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_device *dev = encoder->dev; 1207d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_i915_private *dev_priv = dev->dev_private; 1217d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_crtc *crtc = encoder->crtc; 1227d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 123ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 1247d57382e65994ab7d01741373bd1c420370aed9fEric Anholt u32 sdvox; 1257d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 126b599c0bca1e08a89a7fc4305bc84f4be30ada368Adam Jackson sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE; 127e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson sdvox |= intel_hdmi->color_range; 128b599c0bca1e08a89a7fc4305bc84f4be30ada368Adam Jackson if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) 129b599c0bca1e08a89a7fc4305bc84f4be30ada368Adam Jackson sdvox |= SDVO_VSYNC_ACTIVE_HIGH; 130b599c0bca1e08a89a7fc4305bc84f4be30ada368Adam Jackson if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) 131b599c0bca1e08a89a7fc4305bc84f4be30ada368Adam Jackson sdvox |= SDVO_HSYNC_ACTIVE_HIGH; 1327d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1332e3d6006aca163db3eeb931cec631974aaa3c293Zhenyu Wang /* Required on CPT */ 1342e3d6006aca163db3eeb931cec631974aaa3c293Zhenyu Wang if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev)) 1352e3d6006aca163db3eeb931cec631974aaa3c293Zhenyu Wang sdvox |= HDMI_MODE_SELECT; 1362e3d6006aca163db3eeb931cec631974aaa3c293Zhenyu Wang 1373c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman if (intel_hdmi->has_audio) { 1387d57382e65994ab7d01741373bd1c420370aed9fEric Anholt sdvox |= SDVO_AUDIO_ENABLE; 1393c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC; 1403c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman } 1417d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1420f229062a13204120dcd23168ad008e559bb1376Zhenyu Wang if (intel_crtc->pipe == 1) { 1430f229062a13204120dcd23168ad008e559bb1376Zhenyu Wang if (HAS_PCH_CPT(dev)) 1440f229062a13204120dcd23168ad008e559bb1376Zhenyu Wang sdvox |= PORT_TRANS_B_SEL_CPT; 1450f229062a13204120dcd23168ad008e559bb1376Zhenyu Wang else 1460f229062a13204120dcd23168ad008e559bb1376Zhenyu Wang sdvox |= SDVO_PIPE_B_SELECT; 1470f229062a13204120dcd23168ad008e559bb1376Zhenyu Wang } 1487d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 149ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson I915_WRITE(intel_hdmi->sdvox_reg, sdvox); 150ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson POSTING_READ(intel_hdmi->sdvox_reg); 1513c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 1523c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman intel_hdmi_set_avi_infoframe(encoder); 1537d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 1547d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1557d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) 1567d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 1577d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_device *dev = encoder->dev; 1587d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_i915_private *dev_priv = dev->dev_private; 159ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 1607d57382e65994ab7d01741373bd1c420370aed9fEric Anholt u32 temp; 1617d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 162ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson temp = I915_READ(intel_hdmi->sdvox_reg); 163d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang 164d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang /* HW workaround, need to toggle enable bit off and on for 12bpc, but 165d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang * we do this anyway which shows more stable in testing. 166d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang */ 167c619eed4b2ee1b2bde3e02464eb81632a08bb976Eric Anholt if (HAS_PCH_SPLIT(dev)) { 168ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE); 169ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson POSTING_READ(intel_hdmi->sdvox_reg); 170d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang } 171d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang 172d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang if (mode != DRM_MODE_DPMS_ON) { 173d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang temp &= ~SDVO_ENABLE; 1747d57382e65994ab7d01741373bd1c420370aed9fEric Anholt } else { 175d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang temp |= SDVO_ENABLE; 1767d57382e65994ab7d01741373bd1c420370aed9fEric Anholt } 177d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang 178ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson I915_WRITE(intel_hdmi->sdvox_reg, temp); 179ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson POSTING_READ(intel_hdmi->sdvox_reg); 180d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang 181d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang /* HW workaround, need to write this twice for issue that may result 182d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang * in first write getting masked. 183d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang */ 184c619eed4b2ee1b2bde3e02464eb81632a08bb976Eric Anholt if (HAS_PCH_SPLIT(dev)) { 185ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson I915_WRITE(intel_hdmi->sdvox_reg, temp); 186ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson POSTING_READ(intel_hdmi->sdvox_reg); 187d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang } 1887d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 1897d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1907d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic int intel_hdmi_mode_valid(struct drm_connector *connector, 1917d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_display_mode *mode) 1927d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 1937d57382e65994ab7d01741373bd1c420370aed9fEric Anholt if (mode->clock > 165000) 1947d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return MODE_CLOCK_HIGH; 1957d57382e65994ab7d01741373bd1c420370aed9fEric Anholt if (mode->clock < 20000) 1965cbba41d2857477bd9a008f2d82c0622db1a8deeNicolas Kaiser return MODE_CLOCK_LOW; 1977d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 1987d57382e65994ab7d01741373bd1c420370aed9fEric Anholt if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 1997d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return MODE_NO_DBLESCAN; 2007d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2017d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return MODE_OK; 2027d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 2037d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2047d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, 2057d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_display_mode *mode, 2067d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_display_mode *adjusted_mode) 2077d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 2087d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return true; 2097d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 2107d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 211aa93d632c496184e5b779dbcf961bf1c6ececf0bKeith Packardstatic enum drm_connector_status 212930a9e283516a3a3595c0c515113f1b78d07f695Chris Wilsonintel_hdmi_detect(struct drm_connector *connector, bool force) 2139dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling{ 214df0e924883d029a8651a2a0c7b8da67a07611ed2Chris Wilson struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 215f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson struct drm_i915_private *dev_priv = connector->dev->dev_private; 216f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson struct edid *edid; 217aa93d632c496184e5b779dbcf961bf1c6ececf0bKeith Packard enum drm_connector_status status = connector_status_disconnected; 2189dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling 219ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson intel_hdmi->has_hdmi_sink = false; 2202e3d6006aca163db3eeb931cec631974aaa3c293Zhenyu Wang intel_hdmi->has_audio = false; 221f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson edid = drm_get_edid(connector, 222f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter); 2232ded9e2747d0a390d281bb5b16ff7f640ec85f78ling.ma@intel.com 224aa93d632c496184e5b779dbcf961bf1c6ececf0bKeith Packard if (edid) { 225be9f1c4f738a715abbd8ea742f3ec60a1ce73f4bEric Anholt if (edid->input & DRM_EDID_INPUT_DIGITAL) { 226aa93d632c496184e5b779dbcf961bf1c6ececf0bKeith Packard status = connector_status_connected; 227ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid); 2282e3d6006aca163db3eeb931cec631974aaa3c293Zhenyu Wang intel_hdmi->has_audio = drm_detect_monitor_audio(edid); 229aa93d632c496184e5b779dbcf961bf1c6ececf0bKeith Packard } 230674e2d0885e009c078d89f789f28f63374a4f337Zhenyu Wang connector->display_info.raw_edid = NULL; 231aa93d632c496184e5b779dbcf961bf1c6ececf0bKeith Packard kfree(edid); 2329dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling } 23330ad48b7334a2eb2edf22f6c91f7b3f22a22a837Zhenyu Wang 23455b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson if (status == connector_status_connected) { 23555b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson if (intel_hdmi->force_audio) 23655b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson intel_hdmi->has_audio = intel_hdmi->force_audio > 0; 23755b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson } 23855b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 2392ded9e2747d0a390d281bb5b16ff7f640ec85f78ling.ma@intel.com return status; 2407d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 2417d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2427d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic int intel_hdmi_get_modes(struct drm_connector *connector) 2437d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 244df0e924883d029a8651a2a0c7b8da67a07611ed2Chris Wilson struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 245f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson struct drm_i915_private *dev_priv = connector->dev->dev_private; 2467d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2477d57382e65994ab7d01741373bd1c420370aed9fEric Anholt /* We should parse the EDID data and find out if it's an HDMI sink so 2487d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * we can send audio to it. 2497d57382e65994ab7d01741373bd1c420370aed9fEric Anholt */ 2507d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 251f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson return intel_ddc_get_modes(connector, 252f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter); 2537d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 2547d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2551aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilsonstatic bool 2561aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilsonintel_hdmi_detect_audio(struct drm_connector *connector) 2571aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson{ 2581aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 2591aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson struct drm_i915_private *dev_priv = connector->dev->dev_private; 2601aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson struct edid *edid; 2611aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson bool has_audio = false; 2621aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson 2631aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson edid = drm_get_edid(connector, 2641aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter); 2651aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson if (edid) { 2661aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson if (edid->input & DRM_EDID_INPUT_DIGITAL) 2671aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson has_audio = drm_detect_monitor_audio(edid); 2681aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson 2691aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson connector->display_info.raw_edid = NULL; 2701aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson kfree(edid); 2711aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson } 2721aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson 2731aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson return has_audio; 2741aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson} 2751aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson 27655b7d6e8c4690047ac001026cb75a47f747db816Chris Wilsonstatic int 27755b7d6e8c4690047ac001026cb75a47f747db816Chris Wilsonintel_hdmi_set_property(struct drm_connector *connector, 27855b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson struct drm_property *property, 27955b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson uint64_t val) 28055b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson{ 28155b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 282e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson struct drm_i915_private *dev_priv = connector->dev->dev_private; 28355b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson int ret; 28455b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 28555b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson ret = drm_connector_property_set_value(connector, property, val); 28655b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson if (ret) 28755b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson return ret; 28855b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 2893f43c48d333777e815ae68d66396cb6dfbc2dd79Chris Wilson if (property == dev_priv->force_audio_property) { 2901aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson int i = val; 2911aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson bool has_audio; 2921aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson 2931aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson if (i == intel_hdmi->force_audio) 29455b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson return 0; 29555b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 2961aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson intel_hdmi->force_audio = i; 29755b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 2981aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson if (i == 0) 2991aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson has_audio = intel_hdmi_detect_audio(connector); 3001aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson else 3011aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson has_audio = i > 0; 3021aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson 3031aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson if (has_audio == intel_hdmi->has_audio) 30455b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson return 0; 30555b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 3061aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson intel_hdmi->has_audio = has_audio; 30755b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson goto done; 30855b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson } 30955b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 310e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson if (property == dev_priv->broadcast_rgb_property) { 311e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson if (val == !!intel_hdmi->color_range) 312e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson return 0; 313e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson 314e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson intel_hdmi->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0; 315e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson goto done; 316e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson } 317e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson 31855b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson return -EINVAL; 31955b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 32055b7d6e8c4690047ac001026cb75a47f747db816Chris Wilsondone: 32155b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson if (intel_hdmi->base.base.crtc) { 32255b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson struct drm_crtc *crtc = intel_hdmi->base.base.crtc; 32355b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson drm_crtc_helper_set_mode(crtc, &crtc->mode, 32455b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson crtc->x, crtc->y, 32555b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson crtc->fb); 32655b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson } 32755b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 32855b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson return 0; 32955b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson} 33055b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 3317d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic void intel_hdmi_destroy(struct drm_connector *connector) 3327d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 3337d57382e65994ab7d01741373bd1c420370aed9fEric Anholt drm_sysfs_connector_remove(connector); 3347d57382e65994ab7d01741373bd1c420370aed9fEric Anholt drm_connector_cleanup(connector); 335674e2d0885e009c078d89f789f28f63374a4f337Zhenyu Wang kfree(connector); 3367d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 3377d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 3387d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { 3397d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .dpms = intel_hdmi_dpms, 3407d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .mode_fixup = intel_hdmi_mode_fixup, 3417d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .prepare = intel_encoder_prepare, 3427d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .mode_set = intel_hdmi_mode_set, 3437d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .commit = intel_encoder_commit, 3447d57382e65994ab7d01741373bd1c420370aed9fEric Anholt}; 3457d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 3467d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic const struct drm_connector_funcs intel_hdmi_connector_funcs = { 347c9fb15f60eb517c958dec64dca9357bf62bf2201Keith Packard .dpms = drm_helper_connector_dpms, 3487d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .detect = intel_hdmi_detect, 3497d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .fill_modes = drm_helper_probe_single_connector_modes, 35055b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson .set_property = intel_hdmi_set_property, 3517d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .destroy = intel_hdmi_destroy, 3527d57382e65994ab7d01741373bd1c420370aed9fEric Anholt}; 3537d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 3547d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = { 3557d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .get_modes = intel_hdmi_get_modes, 3567d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .mode_valid = intel_hdmi_mode_valid, 357df0e924883d029a8651a2a0c7b8da67a07611ed2Chris Wilson .best_encoder = intel_best_encoder, 3587d57382e65994ab7d01741373bd1c420370aed9fEric Anholt}; 3597d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 3607d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic const struct drm_encoder_funcs intel_hdmi_enc_funcs = { 361ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson .destroy = intel_encoder_destroy, 3627d57382e65994ab7d01741373bd1c420370aed9fEric Anholt}; 3637d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 36455b7d6e8c4690047ac001026cb75a47f747db816Chris Wilsonstatic void 36555b7d6e8c4690047ac001026cb75a47f747db816Chris Wilsonintel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector) 36655b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson{ 3673f43c48d333777e815ae68d66396cb6dfbc2dd79Chris Wilson intel_attach_force_audio_property(connector); 368e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson intel_attach_broadcast_rgb_property(connector); 36955b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson} 37055b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 3717d57382e65994ab7d01741373bd1c420370aed9fEric Anholtvoid intel_hdmi_init(struct drm_device *dev, int sdvox_reg) 3727d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 3737d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_i915_private *dev_priv = dev->dev_private; 3747d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_connector *connector; 37521d40d37eca86872f2bf0af995809ebdef25c9d9Eric Anholt struct intel_encoder *intel_encoder; 376674e2d0885e009c078d89f789f28f63374a4f337Zhenyu Wang struct intel_connector *intel_connector; 377ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson struct intel_hdmi *intel_hdmi; 3787d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 379ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson intel_hdmi = kzalloc(sizeof(struct intel_hdmi), GFP_KERNEL); 380ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson if (!intel_hdmi) 3817d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return; 382674e2d0885e009c078d89f789f28f63374a4f337Zhenyu Wang 383674e2d0885e009c078d89f789f28f63374a4f337Zhenyu Wang intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); 384674e2d0885e009c078d89f789f28f63374a4f337Zhenyu Wang if (!intel_connector) { 385ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson kfree(intel_hdmi); 386674e2d0885e009c078d89f789f28f63374a4f337Zhenyu Wang return; 387674e2d0885e009c078d89f789f28f63374a4f337Zhenyu Wang } 388674e2d0885e009c078d89f789f28f63374a4f337Zhenyu Wang 389ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson intel_encoder = &intel_hdmi->base; 390373a3cf744c774478f44921c50011b896ab08f9dChris Wilson drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs, 391373a3cf744c774478f44921c50011b896ab08f9dChris Wilson DRM_MODE_ENCODER_TMDS); 392373a3cf744c774478f44921c50011b896ab08f9dChris Wilson 393674e2d0885e009c078d89f789f28f63374a4f337Zhenyu Wang connector = &intel_connector->base; 3947d57382e65994ab7d01741373bd1c420370aed9fEric Anholt drm_connector_init(dev, connector, &intel_hdmi_connector_funcs, 3958d91104aac6e21e6ca2a56124e2e47b0db043ea8Adam Jackson DRM_MODE_CONNECTOR_HDMIA); 3967d57382e65994ab7d01741373bd1c420370aed9fEric Anholt drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs); 3977d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 39821d40d37eca86872f2bf0af995809ebdef25c9d9Eric Anholt intel_encoder->type = INTEL_OUTPUT_HDMI; 3997d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 400eb1f8e4f3be898df808e2dfc131099f5831d491dDave Airlie connector->polled = DRM_CONNECTOR_POLL_HPD; 4017d57382e65994ab7d01741373bd1c420370aed9fEric Anholt connector->interlace_allowed = 0; 4027d57382e65994ab7d01741373bd1c420370aed9fEric Anholt connector->doublescan_allowed = 0; 40321d40d37eca86872f2bf0af995809ebdef25c9d9Eric Anholt intel_encoder->crtc_mask = (1 << 0) | (1 << 1); 4047d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 4057d57382e65994ab7d01741373bd1c420370aed9fEric Anholt /* Set up the DDC bus. */ 406f8aed700c6ec46ddade6570004ce25332283b306Ma Ling if (sdvox_reg == SDVOB) { 40721d40d37eca86872f2bf0af995809ebdef25c9d9Eric Anholt intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT); 408f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson intel_hdmi->ddc_bus = GMBUS_PORT_DPB; 409b01f2c3a4a37d09a47ad73ccbb46d554d21cfeb0Jesse Barnes dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; 410f8aed700c6ec46ddade6570004ce25332283b306Ma Ling } else if (sdvox_reg == SDVOC) { 41121d40d37eca86872f2bf0af995809ebdef25c9d9Eric Anholt intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT); 412f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson intel_hdmi->ddc_bus = GMBUS_PORT_DPC; 413b01f2c3a4a37d09a47ad73ccbb46d554d21cfeb0Jesse Barnes dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; 414f8aed700c6ec46ddade6570004ce25332283b306Ma Ling } else if (sdvox_reg == HDMIB) { 41521d40d37eca86872f2bf0af995809ebdef25c9d9Eric Anholt intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT); 416f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson intel_hdmi->ddc_bus = GMBUS_PORT_DPB; 417b01f2c3a4a37d09a47ad73ccbb46d554d21cfeb0Jesse Barnes dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; 418f8aed700c6ec46ddade6570004ce25332283b306Ma Ling } else if (sdvox_reg == HDMIC) { 41921d40d37eca86872f2bf0af995809ebdef25c9d9Eric Anholt intel_encoder->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT); 420f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson intel_hdmi->ddc_bus = GMBUS_PORT_DPC; 421b01f2c3a4a37d09a47ad73ccbb46d554d21cfeb0Jesse Barnes dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; 422f8aed700c6ec46ddade6570004ce25332283b306Ma Ling } else if (sdvox_reg == HDMID) { 42321d40d37eca86872f2bf0af995809ebdef25c9d9Eric Anholt intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT); 424f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson intel_hdmi->ddc_bus = GMBUS_PORT_DPD; 425b01f2c3a4a37d09a47ad73ccbb46d554d21cfeb0Jesse Barnes dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS; 426f8aed700c6ec46ddade6570004ce25332283b306Ma Ling } 4277d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 428ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson intel_hdmi->sdvox_reg = sdvox_reg; 4297d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 4304ef69c7a64b78d477d1666eba258ca049e8bac91Chris Wilson drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); 4317d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 43255b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson intel_hdmi_add_properties(intel_hdmi, connector); 43355b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 434df0e924883d029a8651a2a0c7b8da67a07611ed2Chris Wilson intel_connector_attach_encoder(intel_connector, intel_encoder); 4357d57382e65994ab7d01741373bd1c420370aed9fEric Anholt drm_sysfs_connector_add(connector); 4367d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 4377d57382e65994ab7d01741373bd1c420370aed9fEric Anholt /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written 4387d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * 0xd. Failure to do so will result in spurious interrupts being 4397d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * generated on the port when a cable is not attached. 4407d57382e65994ab7d01741373bd1c420370aed9fEric Anholt */ 4417d57382e65994ab7d01741373bd1c420370aed9fEric Anholt if (IS_G4X(dev) && !IS_GM45(dev)) { 4427d57382e65994ab7d01741373bd1c420370aed9fEric Anholt u32 temp = I915_READ(PEG_BAND_GAP_DATA); 4437d57382e65994ab7d01741373bd1c420370aed9fEric Anholt I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); 4447d57382e65994ab7d01741373bd1c420370aed9fEric Anholt } 4457d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 446