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