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; 47b1d7e4b41fd0f72ea8149056778db5d737739305Wu Fengguang enum hdmi_force_audio force_audio; 4845187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes void (*write_infoframe)(struct drm_encoder *encoder, 4945187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes struct dip_infoframe *frame); 507d57382e65994ab7d01741373bd1c420370aed9fEric Anholt}; 517d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 52ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilsonstatic struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) 53ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson{ 544ef69c7a64b78d477d1666eba258ca049e8bac91Chris Wilson return container_of(encoder, struct intel_hdmi, base.base); 55ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson} 56ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson 57df0e924883d029a8651a2a0c7b8da67a07611ed2Chris Wilsonstatic struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector) 58df0e924883d029a8651a2a0c7b8da67a07611ed2Chris Wilson{ 59df0e924883d029a8651a2a0c7b8da67a07611ed2Chris Wilson return container_of(intel_attached_encoder(connector), 60df0e924883d029a8651a2a0c7b8da67a07611ed2Chris Wilson struct intel_hdmi, base); 61df0e924883d029a8651a2a0c7b8da67a07611ed2Chris Wilson} 62df0e924883d029a8651a2a0c7b8da67a07611ed2Chris Wilson 6345187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnesvoid intel_dip_infoframe_csum(struct dip_infoframe *frame) 643c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman{ 6545187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes uint8_t *data = (uint8_t *)frame; 663c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman uint8_t sum = 0; 673c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman unsigned i; 683c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 6945187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes frame->checksum = 0; 7045187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes frame->ecc = 0; 713c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 7264a8fc0145a1d0fdc25fc9367c2e6c621955fb3bJesse Barnes for (i = 0; i < frame->len + DIP_HEADER_SIZE; i++) 733c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman sum += data[i]; 743c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 7545187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes frame->checksum = 0x100 - sum; 763c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman} 773c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 7845187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnesstatic u32 intel_infoframe_index(struct dip_infoframe *frame) 793c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman{ 8045187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes u32 flags = 0; 8145187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes 8245187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes switch (frame->type) { 8345187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes case DIP_TYPE_AVI: 8445187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes flags |= VIDEO_DIP_SELECT_AVI; 8545187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes break; 8645187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes case DIP_TYPE_SPD: 8745187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes flags |= VIDEO_DIP_SELECT_SPD; 8845187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes break; 8945187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes default: 9045187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); 9145187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes break; 9245187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes } 9345187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes 9445187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes return flags; 9545187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes} 9645187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes 9745187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnesstatic u32 intel_infoframe_flags(struct dip_infoframe *frame) 9845187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes{ 9945187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes u32 flags = 0; 10045187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes 10145187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes switch (frame->type) { 10245187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes case DIP_TYPE_AVI: 10345187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes flags |= VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_FREQ_VSYNC; 10445187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes break; 10545187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes case DIP_TYPE_SPD: 10664a8fc0145a1d0fdc25fc9367c2e6c621955fb3bJesse Barnes flags |= VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_FREQ_VSYNC; 10745187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes break; 10845187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes default: 10945187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); 11045187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes break; 11145187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes } 11245187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes 11345187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes return flags; 11445187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes} 11545187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes 11645187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnesstatic void i9xx_write_infoframe(struct drm_encoder *encoder, 11745187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes struct dip_infoframe *frame) 11845187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes{ 11945187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes uint32_t *data = (uint32_t *)frame; 1203c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman struct drm_device *dev = encoder->dev; 1213c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman struct drm_i915_private *dev_priv = dev->dev_private; 1223c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 12345187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes u32 port, flags, val = I915_READ(VIDEO_DIP_CTL); 12445187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes unsigned i, len = DIP_HEADER_SIZE + frame->len; 1253c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 1263c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 1273c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman /* XXX first guess at handling video port, is this corrent? */ 1283c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman if (intel_hdmi->sdvox_reg == SDVOB) 1293c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman port = VIDEO_DIP_PORT_B; 1303c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman else if (intel_hdmi->sdvox_reg == SDVOC) 1313c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman port = VIDEO_DIP_PORT_C; 1323c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman else 1333c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman return; 1343c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 13545187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes flags = intel_infoframe_index(frame); 13645187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes 13745187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes val &= ~VIDEO_DIP_SELECT_MASK; 13845187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes 139c1230df7e19e0f27655c0eb9d966c7e03be7cc50Paulo Zanoni I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags); 1403c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 14145187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes for (i = 0; i < len; i += 4) { 1423c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman I915_WRITE(VIDEO_DIP_DATA, *data); 1433c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman data++; 1443c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman } 1453c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 14645187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes flags |= intel_infoframe_flags(frame); 14745187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes 14845187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags); 1493c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman} 1503c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 15145187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnesstatic void ironlake_write_infoframe(struct drm_encoder *encoder, 15245187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes struct dip_infoframe *frame) 153b055c8f3ef9f7bc6ba415d900f298d7801a9d1d4Jesse Barnes{ 15445187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes uint32_t *data = (uint32_t *)frame; 155b055c8f3ef9f7bc6ba415d900f298d7801a9d1d4Jesse Barnes struct drm_device *dev = encoder->dev; 156b055c8f3ef9f7bc6ba415d900f298d7801a9d1d4Jesse Barnes struct drm_i915_private *dev_priv = dev->dev_private; 157b055c8f3ef9f7bc6ba415d900f298d7801a9d1d4Jesse Barnes struct drm_crtc *crtc = encoder->crtc; 158b055c8f3ef9f7bc6ba415d900f298d7801a9d1d4Jesse Barnes struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 159b055c8f3ef9f7bc6ba415d900f298d7801a9d1d4Jesse Barnes int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); 16045187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes unsigned i, len = DIP_HEADER_SIZE + frame->len; 16145187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes u32 flags, val = I915_READ(reg); 162b055c8f3ef9f7bc6ba415d900f298d7801a9d1d4Jesse Barnes 163b055c8f3ef9f7bc6ba415d900f298d7801a9d1d4Jesse Barnes intel_wait_for_vblank(dev, intel_crtc->pipe); 164b055c8f3ef9f7bc6ba415d900f298d7801a9d1d4Jesse Barnes 16545187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes flags = intel_infoframe_index(frame); 166b055c8f3ef9f7bc6ba415d900f298d7801a9d1d4Jesse Barnes 16764a8fc0145a1d0fdc25fc9367c2e6c621955fb3bJesse Barnes val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ 16845187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes 16964a8fc0145a1d0fdc25fc9367c2e6c621955fb3bJesse Barnes I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags); 17045187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes 17145187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes for (i = 0; i < len; i += 4) { 172b055c8f3ef9f7bc6ba415d900f298d7801a9d1d4Jesse Barnes I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); 173b055c8f3ef9f7bc6ba415d900f298d7801a9d1d4Jesse Barnes data++; 174b055c8f3ef9f7bc6ba415d900f298d7801a9d1d4Jesse Barnes } 175b055c8f3ef9f7bc6ba415d900f298d7801a9d1d4Jesse Barnes 17645187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes flags |= intel_infoframe_flags(frame); 17745187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes 17845187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags); 17945187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes} 18045187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnesstatic void intel_set_infoframe(struct drm_encoder *encoder, 18145187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes struct dip_infoframe *frame) 18245187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes{ 18345187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 18445187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes 18545187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes if (!intel_hdmi->has_hdmi_sink) 18645187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes return; 18745187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes 18845187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes intel_dip_infoframe_csum(frame); 18945187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes intel_hdmi->write_infoframe(encoder, frame); 19045187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes} 19145187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes 19245187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnesstatic void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) 19345187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes{ 19445187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes struct dip_infoframe avi_if = { 19545187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes .type = DIP_TYPE_AVI, 19645187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes .ver = DIP_VERSION_AVI, 19745187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes .len = DIP_LEN_AVI, 19845187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes }; 19945187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes 20045187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes intel_set_infoframe(encoder, &avi_if); 201b055c8f3ef9f7bc6ba415d900f298d7801a9d1d4Jesse Barnes} 202b055c8f3ef9f7bc6ba415d900f298d7801a9d1d4Jesse Barnes 203c0864cb39c68696e80657360eba63da5e743b7aaJesse Barnesstatic void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder) 204c0864cb39c68696e80657360eba63da5e743b7aaJesse Barnes{ 205c0864cb39c68696e80657360eba63da5e743b7aaJesse Barnes struct dip_infoframe spd_if; 206c0864cb39c68696e80657360eba63da5e743b7aaJesse Barnes 207c0864cb39c68696e80657360eba63da5e743b7aaJesse Barnes memset(&spd_if, 0, sizeof(spd_if)); 208c0864cb39c68696e80657360eba63da5e743b7aaJesse Barnes spd_if.type = DIP_TYPE_SPD; 209c0864cb39c68696e80657360eba63da5e743b7aaJesse Barnes spd_if.ver = DIP_VERSION_SPD; 210c0864cb39c68696e80657360eba63da5e743b7aaJesse Barnes spd_if.len = DIP_LEN_SPD; 211c0864cb39c68696e80657360eba63da5e743b7aaJesse Barnes strcpy(spd_if.body.spd.vn, "Intel"); 212c0864cb39c68696e80657360eba63da5e743b7aaJesse Barnes strcpy(spd_if.body.spd.pd, "Integrated gfx"); 213c0864cb39c68696e80657360eba63da5e743b7aaJesse Barnes spd_if.body.spd.sdi = DIP_SPD_PC; 214c0864cb39c68696e80657360eba63da5e743b7aaJesse Barnes 215c0864cb39c68696e80657360eba63da5e743b7aaJesse Barnes intel_set_infoframe(encoder, &spd_if); 216c0864cb39c68696e80657360eba63da5e743b7aaJesse Barnes} 217c0864cb39c68696e80657360eba63da5e743b7aaJesse Barnes 2187d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic void intel_hdmi_mode_set(struct drm_encoder *encoder, 2197d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_display_mode *mode, 2207d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_display_mode *adjusted_mode) 2217d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 2227d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_device *dev = encoder->dev; 2237d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_i915_private *dev_priv = dev->dev_private; 2247d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_crtc *crtc = encoder->crtc; 2257d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 226ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 2277d57382e65994ab7d01741373bd1c420370aed9fEric Anholt u32 sdvox; 2287d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 229b599c0bca1e08a89a7fc4305bc84f4be30ada368Adam Jackson sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE; 2305d4fac9716988dc7a26dddcd994f4dc7ee651e3cJesse Barnes if (!HAS_PCH_SPLIT(dev)) 2315d4fac9716988dc7a26dddcd994f4dc7ee651e3cJesse Barnes sdvox |= intel_hdmi->color_range; 232b599c0bca1e08a89a7fc4305bc84f4be30ada368Adam Jackson if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) 233b599c0bca1e08a89a7fc4305bc84f4be30ada368Adam Jackson sdvox |= SDVO_VSYNC_ACTIVE_HIGH; 234b599c0bca1e08a89a7fc4305bc84f4be30ada368Adam Jackson if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) 235b599c0bca1e08a89a7fc4305bc84f4be30ada368Adam Jackson sdvox |= SDVO_HSYNC_ACTIVE_HIGH; 2367d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 237020f6704b5fbf687534ce53aeedc0364a995ae8aJesse Barnes if (intel_crtc->bpp > 24) 238020f6704b5fbf687534ce53aeedc0364a995ae8aJesse Barnes sdvox |= COLOR_FORMAT_12bpc; 239020f6704b5fbf687534ce53aeedc0364a995ae8aJesse Barnes else 240020f6704b5fbf687534ce53aeedc0364a995ae8aJesse Barnes sdvox |= COLOR_FORMAT_8bpc; 241020f6704b5fbf687534ce53aeedc0364a995ae8aJesse Barnes 2422e3d6006aca163db3eeb931cec631974aaa3c293Zhenyu Wang /* Required on CPT */ 2432e3d6006aca163db3eeb931cec631974aaa3c293Zhenyu Wang if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev)) 2442e3d6006aca163db3eeb931cec631974aaa3c293Zhenyu Wang sdvox |= HDMI_MODE_SELECT; 2452e3d6006aca163db3eeb931cec631974aaa3c293Zhenyu Wang 2463c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman if (intel_hdmi->has_audio) { 247e0dac65ed45e72fe34cc7ccc76de0ba220bd38bbWu Fengguang DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", 248e0dac65ed45e72fe34cc7ccc76de0ba220bd38bbWu Fengguang pipe_name(intel_crtc->pipe)); 2497d57382e65994ab7d01741373bd1c420370aed9fEric Anholt sdvox |= SDVO_AUDIO_ENABLE; 2503c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC; 251e0dac65ed45e72fe34cc7ccc76de0ba220bd38bbWu Fengguang intel_write_eld(encoder, adjusted_mode); 2523c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman } 2537d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 25475770564c90c45618003267f4cdde4bbc090f1bdJesse Barnes if (HAS_PCH_CPT(dev)) 25575770564c90c45618003267f4cdde4bbc090f1bdJesse Barnes sdvox |= PORT_TRANS_SEL_CPT(intel_crtc->pipe); 25675770564c90c45618003267f4cdde4bbc090f1bdJesse Barnes else if (intel_crtc->pipe == 1) 25775770564c90c45618003267f4cdde4bbc090f1bdJesse Barnes sdvox |= SDVO_PIPE_B_SELECT; 2587d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 259ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson I915_WRITE(intel_hdmi->sdvox_reg, sdvox); 260ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson POSTING_READ(intel_hdmi->sdvox_reg); 2613c17fe4b8f40a112a85758a9ab2aebf772bdd647David Härdeman 26245187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes intel_hdmi_set_avi_infoframe(encoder); 263c0864cb39c68696e80657360eba63da5e743b7aaJesse Barnes intel_hdmi_set_spd_infoframe(encoder); 2647d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 2657d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 2667d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) 2677d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 2687d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_device *dev = encoder->dev; 2697d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_i915_private *dev_priv = dev->dev_private; 270ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); 2717d57382e65994ab7d01741373bd1c420370aed9fEric Anholt u32 temp; 2722deed761188d7480eb5f7efbfe7aa77f09322ed8Wu Fengguang u32 enable_bits = SDVO_ENABLE; 2732deed761188d7480eb5f7efbfe7aa77f09322ed8Wu Fengguang 2742deed761188d7480eb5f7efbfe7aa77f09322ed8Wu Fengguang if (intel_hdmi->has_audio) 2752deed761188d7480eb5f7efbfe7aa77f09322ed8Wu Fengguang enable_bits |= SDVO_AUDIO_ENABLE; 2767d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 277ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson temp = I915_READ(intel_hdmi->sdvox_reg); 278d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang 279d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang /* HW workaround, need to toggle enable bit off and on for 12bpc, but 280d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang * we do this anyway which shows more stable in testing. 281d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang */ 282c619eed4b2ee1b2bde3e02464eb81632a08bb976Eric Anholt if (HAS_PCH_SPLIT(dev)) { 283ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE); 284ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson POSTING_READ(intel_hdmi->sdvox_reg); 285d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang } 286d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang 287d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang if (mode != DRM_MODE_DPMS_ON) { 2882deed761188d7480eb5f7efbfe7aa77f09322ed8Wu Fengguang temp &= ~enable_bits; 2897d57382e65994ab7d01741373bd1c420370aed9fEric Anholt } else { 2902deed761188d7480eb5f7efbfe7aa77f09322ed8Wu Fengguang temp |= enable_bits; 2917d57382e65994ab7d01741373bd1c420370aed9fEric Anholt } 292d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang 293ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson I915_WRITE(intel_hdmi->sdvox_reg, temp); 294ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson POSTING_READ(intel_hdmi->sdvox_reg); 295d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang 296d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang /* HW workaround, need to write this twice for issue that may result 297d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang * in first write getting masked. 298d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang */ 299c619eed4b2ee1b2bde3e02464eb81632a08bb976Eric Anholt if (HAS_PCH_SPLIT(dev)) { 300ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson I915_WRITE(intel_hdmi->sdvox_reg, temp); 301ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson POSTING_READ(intel_hdmi->sdvox_reg); 302d8a2d0e00c0d5a0d55e14b884bff034205015e51Zhenyu Wang } 3037d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 3047d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 3057d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic int intel_hdmi_mode_valid(struct drm_connector *connector, 3067d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_display_mode *mode) 3077d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 3087d57382e65994ab7d01741373bd1c420370aed9fEric Anholt if (mode->clock > 165000) 3097d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return MODE_CLOCK_HIGH; 3107d57382e65994ab7d01741373bd1c420370aed9fEric Anholt if (mode->clock < 20000) 3115cbba41d2857477bd9a008f2d82c0622db1a8deeNicolas Kaiser return MODE_CLOCK_LOW; 3127d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 3137d57382e65994ab7d01741373bd1c420370aed9fEric Anholt if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 3147d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return MODE_NO_DBLESCAN; 3157d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 3167d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return MODE_OK; 3177d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 3187d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 3197d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, 3207d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_display_mode *mode, 3217d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_display_mode *adjusted_mode) 3227d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 3237d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return true; 3247d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 3257d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 326aa93d632c496184e5b779dbcf961bf1c6ececf0bKeith Packardstatic enum drm_connector_status 327930a9e283516a3a3595c0c515113f1b78d07f695Chris Wilsonintel_hdmi_detect(struct drm_connector *connector, bool force) 3289dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling{ 329df0e924883d029a8651a2a0c7b8da67a07611ed2Chris Wilson struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 330f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson struct drm_i915_private *dev_priv = connector->dev->dev_private; 331f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson struct edid *edid; 332aa93d632c496184e5b779dbcf961bf1c6ececf0bKeith Packard enum drm_connector_status status = connector_status_disconnected; 3339dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling 334ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson intel_hdmi->has_hdmi_sink = false; 3352e3d6006aca163db3eeb931cec631974aaa3c293Zhenyu Wang intel_hdmi->has_audio = false; 336f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson edid = drm_get_edid(connector, 337f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter); 3382ded9e2747d0a390d281bb5b16ff7f640ec85f78ling.ma@intel.com 339aa93d632c496184e5b779dbcf961bf1c6ececf0bKeith Packard if (edid) { 340be9f1c4f738a715abbd8ea742f3ec60a1ce73f4bEric Anholt if (edid->input & DRM_EDID_INPUT_DIGITAL) { 341aa93d632c496184e5b779dbcf961bf1c6ececf0bKeith Packard status = connector_status_connected; 342b1d7e4b41fd0f72ea8149056778db5d737739305Wu Fengguang if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI) 343b1d7e4b41fd0f72ea8149056778db5d737739305Wu Fengguang intel_hdmi->has_hdmi_sink = 344b1d7e4b41fd0f72ea8149056778db5d737739305Wu Fengguang drm_detect_hdmi_monitor(edid); 3452e3d6006aca163db3eeb931cec631974aaa3c293Zhenyu Wang intel_hdmi->has_audio = drm_detect_monitor_audio(edid); 346aa93d632c496184e5b779dbcf961bf1c6ececf0bKeith Packard } 347674e2d0885e009c078d89f789f28f63374a4f337Zhenyu Wang connector->display_info.raw_edid = NULL; 348aa93d632c496184e5b779dbcf961bf1c6ececf0bKeith Packard kfree(edid); 3499dff6af860d6b7f661d4360eb859837afaca0a1bMa Ling } 35030ad48b7334a2eb2edf22f6c91f7b3f22a22a837Zhenyu Wang 35155b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson if (status == connector_status_connected) { 352b1d7e4b41fd0f72ea8149056778db5d737739305Wu Fengguang if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO) 353b1d7e4b41fd0f72ea8149056778db5d737739305Wu Fengguang intel_hdmi->has_audio = 354b1d7e4b41fd0f72ea8149056778db5d737739305Wu Fengguang (intel_hdmi->force_audio == HDMI_AUDIO_ON); 35555b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson } 35655b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 3572ded9e2747d0a390d281bb5b16ff7f640ec85f78ling.ma@intel.com return status; 3587d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 3597d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 3607d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic int intel_hdmi_get_modes(struct drm_connector *connector) 3617d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 362df0e924883d029a8651a2a0c7b8da67a07611ed2Chris Wilson struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 363f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson struct drm_i915_private *dev_priv = connector->dev->dev_private; 3647d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 3657d57382e65994ab7d01741373bd1c420370aed9fEric Anholt /* We should parse the EDID data and find out if it's an HDMI sink so 3667d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * we can send audio to it. 3677d57382e65994ab7d01741373bd1c420370aed9fEric Anholt */ 3687d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 369f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson return intel_ddc_get_modes(connector, 370f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter); 3717d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 3727d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 3731aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilsonstatic bool 3741aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilsonintel_hdmi_detect_audio(struct drm_connector *connector) 3751aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson{ 3761aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 3771aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson struct drm_i915_private *dev_priv = connector->dev->dev_private; 3781aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson struct edid *edid; 3791aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson bool has_audio = false; 3801aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson 3811aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson edid = drm_get_edid(connector, 3821aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter); 3831aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson if (edid) { 3841aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson if (edid->input & DRM_EDID_INPUT_DIGITAL) 3851aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson has_audio = drm_detect_monitor_audio(edid); 3861aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson 3871aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson connector->display_info.raw_edid = NULL; 3881aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson kfree(edid); 3891aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson } 3901aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson 3911aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson return has_audio; 3921aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson} 3931aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson 39455b7d6e8c4690047ac001026cb75a47f747db816Chris Wilsonstatic int 39555b7d6e8c4690047ac001026cb75a47f747db816Chris Wilsonintel_hdmi_set_property(struct drm_connector *connector, 39655b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson struct drm_property *property, 39755b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson uint64_t val) 39855b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson{ 39955b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); 400e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson struct drm_i915_private *dev_priv = connector->dev->dev_private; 40155b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson int ret; 40255b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 40355b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson ret = drm_connector_property_set_value(connector, property, val); 40455b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson if (ret) 40555b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson return ret; 40655b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 4073f43c48d333777e815ae68d66396cb6dfbc2dd79Chris Wilson if (property == dev_priv->force_audio_property) { 408b1d7e4b41fd0f72ea8149056778db5d737739305Wu Fengguang enum hdmi_force_audio i = val; 4091aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson bool has_audio; 4101aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson 4111aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson if (i == intel_hdmi->force_audio) 41255b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson return 0; 41355b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 4141aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson intel_hdmi->force_audio = i; 41555b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 416b1d7e4b41fd0f72ea8149056778db5d737739305Wu Fengguang if (i == HDMI_AUDIO_AUTO) 4171aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson has_audio = intel_hdmi_detect_audio(connector); 4181aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson else 419b1d7e4b41fd0f72ea8149056778db5d737739305Wu Fengguang has_audio = (i == HDMI_AUDIO_ON); 4201aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson 421b1d7e4b41fd0f72ea8149056778db5d737739305Wu Fengguang if (i == HDMI_AUDIO_OFF_DVI) 422b1d7e4b41fd0f72ea8149056778db5d737739305Wu Fengguang intel_hdmi->has_hdmi_sink = 0; 42355b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 4241aad7ac0458f40e2d0365d488620084f3965f6e7Chris Wilson intel_hdmi->has_audio = has_audio; 42555b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson goto done; 42655b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson } 42755b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 428e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson if (property == dev_priv->broadcast_rgb_property) { 429e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson if (val == !!intel_hdmi->color_range) 430e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson return 0; 431e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson 432e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson intel_hdmi->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0; 433e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson goto done; 434e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson } 435e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson 43655b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson return -EINVAL; 43755b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 43855b7d6e8c4690047ac001026cb75a47f747db816Chris Wilsondone: 43955b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson if (intel_hdmi->base.base.crtc) { 44055b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson struct drm_crtc *crtc = intel_hdmi->base.base.crtc; 44155b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson drm_crtc_helper_set_mode(crtc, &crtc->mode, 44255b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson crtc->x, crtc->y, 44355b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson crtc->fb); 44455b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson } 44555b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 44655b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson return 0; 44755b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson} 44855b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 4497d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic void intel_hdmi_destroy(struct drm_connector *connector) 4507d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 4517d57382e65994ab7d01741373bd1c420370aed9fEric Anholt drm_sysfs_connector_remove(connector); 4527d57382e65994ab7d01741373bd1c420370aed9fEric Anholt drm_connector_cleanup(connector); 453674e2d0885e009c078d89f789f28f63374a4f337Zhenyu Wang kfree(connector); 4547d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 4557d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 4567d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { 4577d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .dpms = intel_hdmi_dpms, 4587d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .mode_fixup = intel_hdmi_mode_fixup, 4597d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .prepare = intel_encoder_prepare, 4607d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .mode_set = intel_hdmi_mode_set, 4617d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .commit = intel_encoder_commit, 4627d57382e65994ab7d01741373bd1c420370aed9fEric Anholt}; 4637d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 4647d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic const struct drm_connector_funcs intel_hdmi_connector_funcs = { 465c9fb15f60eb517c958dec64dca9357bf62bf2201Keith Packard .dpms = drm_helper_connector_dpms, 4667d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .detect = intel_hdmi_detect, 4677d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .fill_modes = drm_helper_probe_single_connector_modes, 46855b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson .set_property = intel_hdmi_set_property, 4697d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .destroy = intel_hdmi_destroy, 4707d57382e65994ab7d01741373bd1c420370aed9fEric Anholt}; 4717d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 4727d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = { 4737d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .get_modes = intel_hdmi_get_modes, 4747d57382e65994ab7d01741373bd1c420370aed9fEric Anholt .mode_valid = intel_hdmi_mode_valid, 475df0e924883d029a8651a2a0c7b8da67a07611ed2Chris Wilson .best_encoder = intel_best_encoder, 4767d57382e65994ab7d01741373bd1c420370aed9fEric Anholt}; 4777d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 4787d57382e65994ab7d01741373bd1c420370aed9fEric Anholtstatic const struct drm_encoder_funcs intel_hdmi_enc_funcs = { 479ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson .destroy = intel_encoder_destroy, 4807d57382e65994ab7d01741373bd1c420370aed9fEric Anholt}; 4817d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 48255b7d6e8c4690047ac001026cb75a47f747db816Chris Wilsonstatic void 48355b7d6e8c4690047ac001026cb75a47f747db816Chris Wilsonintel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector) 48455b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson{ 4853f43c48d333777e815ae68d66396cb6dfbc2dd79Chris Wilson intel_attach_force_audio_property(connector); 486e953fd7bb32f55309a96abd5ceba9cf68d221434Chris Wilson intel_attach_broadcast_rgb_property(connector); 48755b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson} 48855b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 4897d57382e65994ab7d01741373bd1c420370aed9fEric Anholtvoid intel_hdmi_init(struct drm_device *dev, int sdvox_reg) 4907d57382e65994ab7d01741373bd1c420370aed9fEric Anholt{ 4917d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_i915_private *dev_priv = dev->dev_private; 4927d57382e65994ab7d01741373bd1c420370aed9fEric Anholt struct drm_connector *connector; 49321d40d37eca86872f2bf0af995809ebdef25c9d9Eric Anholt struct intel_encoder *intel_encoder; 494674e2d0885e009c078d89f789f28f63374a4f337Zhenyu Wang struct intel_connector *intel_connector; 495ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson struct intel_hdmi *intel_hdmi; 49664a8fc0145a1d0fdc25fc9367c2e6c621955fb3bJesse Barnes int i; 4977d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 498ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson intel_hdmi = kzalloc(sizeof(struct intel_hdmi), GFP_KERNEL); 499ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson if (!intel_hdmi) 5007d57382e65994ab7d01741373bd1c420370aed9fEric Anholt return; 501674e2d0885e009c078d89f789f28f63374a4f337Zhenyu Wang 502674e2d0885e009c078d89f789f28f63374a4f337Zhenyu Wang intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); 503674e2d0885e009c078d89f789f28f63374a4f337Zhenyu Wang if (!intel_connector) { 504ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson kfree(intel_hdmi); 505674e2d0885e009c078d89f789f28f63374a4f337Zhenyu Wang return; 506674e2d0885e009c078d89f789f28f63374a4f337Zhenyu Wang } 507674e2d0885e009c078d89f789f28f63374a4f337Zhenyu Wang 508ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson intel_encoder = &intel_hdmi->base; 509373a3cf744c774478f44921c50011b896ab08f9dChris Wilson drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs, 510373a3cf744c774478f44921c50011b896ab08f9dChris Wilson DRM_MODE_ENCODER_TMDS); 511373a3cf744c774478f44921c50011b896ab08f9dChris Wilson 512674e2d0885e009c078d89f789f28f63374a4f337Zhenyu Wang connector = &intel_connector->base; 5137d57382e65994ab7d01741373bd1c420370aed9fEric Anholt drm_connector_init(dev, connector, &intel_hdmi_connector_funcs, 5148d91104aac6e21e6ca2a56124e2e47b0db043ea8Adam Jackson DRM_MODE_CONNECTOR_HDMIA); 5157d57382e65994ab7d01741373bd1c420370aed9fEric Anholt drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs); 5167d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 51721d40d37eca86872f2bf0af995809ebdef25c9d9Eric Anholt intel_encoder->type = INTEL_OUTPUT_HDMI; 5187d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 519eb1f8e4f3be898df808e2dfc131099f5831d491dDave Airlie connector->polled = DRM_CONNECTOR_POLL_HPD; 520c3febcc438ba0878b164c74310bd77c50dbb0ba8Peter Ross connector->interlace_allowed = 1; 5217d57382e65994ab7d01741373bd1c420370aed9fEric Anholt connector->doublescan_allowed = 0; 52227f8227b1e2b326a9a0995dd9c1f14893c61ee01Jesse Barnes intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); 5237d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 5247d57382e65994ab7d01741373bd1c420370aed9fEric Anholt /* Set up the DDC bus. */ 525f8aed700c6ec46ddade6570004ce25332283b306Ma Ling if (sdvox_reg == SDVOB) { 52621d40d37eca86872f2bf0af995809ebdef25c9d9Eric Anholt intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT); 527f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson intel_hdmi->ddc_bus = GMBUS_PORT_DPB; 528b01f2c3a4a37d09a47ad73ccbb46d554d21cfeb0Jesse Barnes dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; 529f8aed700c6ec46ddade6570004ce25332283b306Ma Ling } else if (sdvox_reg == SDVOC) { 53021d40d37eca86872f2bf0af995809ebdef25c9d9Eric Anholt intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT); 531f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson intel_hdmi->ddc_bus = GMBUS_PORT_DPC; 532b01f2c3a4a37d09a47ad73ccbb46d554d21cfeb0Jesse Barnes dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; 533f8aed700c6ec46ddade6570004ce25332283b306Ma Ling } else if (sdvox_reg == HDMIB) { 53421d40d37eca86872f2bf0af995809ebdef25c9d9Eric Anholt intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT); 535f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson intel_hdmi->ddc_bus = GMBUS_PORT_DPB; 536b01f2c3a4a37d09a47ad73ccbb46d554d21cfeb0Jesse Barnes dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; 537f8aed700c6ec46ddade6570004ce25332283b306Ma Ling } else if (sdvox_reg == HDMIC) { 53821d40d37eca86872f2bf0af995809ebdef25c9d9Eric Anholt intel_encoder->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT); 539f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson intel_hdmi->ddc_bus = GMBUS_PORT_DPC; 540b01f2c3a4a37d09a47ad73ccbb46d554d21cfeb0Jesse Barnes dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; 541f8aed700c6ec46ddade6570004ce25332283b306Ma Ling } else if (sdvox_reg == HDMID) { 54221d40d37eca86872f2bf0af995809ebdef25c9d9Eric Anholt intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT); 543f899fc64cda8569d0529452aafc0da31c042df2eChris Wilson intel_hdmi->ddc_bus = GMBUS_PORT_DPD; 544b01f2c3a4a37d09a47ad73ccbb46d554d21cfeb0Jesse Barnes dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS; 545f8aed700c6ec46ddade6570004ce25332283b306Ma Ling } 5467d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 547ea5b213ad4b161463e76b63dbb115ea20e2200f0Chris Wilson intel_hdmi->sdvox_reg = sdvox_reg; 5487d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 54964a8fc0145a1d0fdc25fc9367c2e6c621955fb3bJesse Barnes if (!HAS_PCH_SPLIT(dev)) { 55045187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes intel_hdmi->write_infoframe = i9xx_write_infoframe; 55164a8fc0145a1d0fdc25fc9367c2e6c621955fb3bJesse Barnes I915_WRITE(VIDEO_DIP_CTL, 0); 55264a8fc0145a1d0fdc25fc9367c2e6c621955fb3bJesse Barnes } else { 55345187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes intel_hdmi->write_infoframe = ironlake_write_infoframe; 55464a8fc0145a1d0fdc25fc9367c2e6c621955fb3bJesse Barnes for_each_pipe(i) 55564a8fc0145a1d0fdc25fc9367c2e6c621955fb3bJesse Barnes I915_WRITE(TVIDEO_DIP_CTL(i), 0); 55664a8fc0145a1d0fdc25fc9367c2e6c621955fb3bJesse Barnes } 55745187ace97f7b3deb559b25348ccb7e301c158c9Jesse Barnes 5584ef69c7a64b78d477d1666eba258ca049e8bac91Chris Wilson drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); 5597d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 56055b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson intel_hdmi_add_properties(intel_hdmi, connector); 56155b7d6e8c4690047ac001026cb75a47f747db816Chris Wilson 562df0e924883d029a8651a2a0c7b8da67a07611ed2Chris Wilson intel_connector_attach_encoder(intel_connector, intel_encoder); 5637d57382e65994ab7d01741373bd1c420370aed9fEric Anholt drm_sysfs_connector_add(connector); 5647d57382e65994ab7d01741373bd1c420370aed9fEric Anholt 5657d57382e65994ab7d01741373bd1c420370aed9fEric Anholt /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written 5667d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * 0xd. Failure to do so will result in spurious interrupts being 5677d57382e65994ab7d01741373bd1c420370aed9fEric Anholt * generated on the port when a cable is not attached. 5687d57382e65994ab7d01741373bd1c420370aed9fEric Anholt */ 5697d57382e65994ab7d01741373bd1c420370aed9fEric Anholt if (IS_G4X(dev) && !IS_GM45(dev)) { 5707d57382e65994ab7d01741373bd1c420370aed9fEric Anholt u32 temp = I915_READ(PEG_BAND_GAP_DATA); 5717d57382e65994ab7d01741373bd1c420370aed9fEric Anholt I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); 5727d57382e65994ab7d01741373bd1c420370aed9fEric Anholt } 5737d57382e65994ab7d01741373bd1c420370aed9fEric Anholt} 574