1235783Skib/*
2235783Skib * Copyright 2006 Dave Airlie <airlied@linux.ie>
3235783Skib * Copyright �� 2006-2009 Intel Corporation
4235783Skib *
5235783Skib * Permission is hereby granted, free of charge, to any person obtaining a
6235783Skib * copy of this software and associated documentation files (the "Software"),
7235783Skib * to deal in the Software without restriction, including without limitation
8235783Skib * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9235783Skib * and/or sell copies of the Software, and to permit persons to whom the
10235783Skib * Software is furnished to do so, subject to the following conditions:
11235783Skib *
12235783Skib * The above copyright notice and this permission notice (including the next
13235783Skib * paragraph) shall be included in all copies or substantial portions of the
14235783Skib * Software.
15235783Skib *
16235783Skib * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17235783Skib * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18235783Skib * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19235783Skib * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20235783Skib * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21235783Skib * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22235783Skib * DEALINGS IN THE SOFTWARE.
23235783Skib *
24235783Skib * Authors:
25235783Skib *	Eric Anholt <eric@anholt.net>
26235783Skib *	Jesse Barnes <jesse.barnes@intel.com>
27235783Skib */
28235783Skib
29235783Skib#include <sys/cdefs.h>
30235783Skib__FBSDID("$FreeBSD: releng/10.3/sys/dev/drm2/i915/intel_hdmi.c 282199 2015-04-28 19:35:05Z dumbbell $");
31235783Skib
32235783Skib#include <dev/drm2/drmP.h>
33235783Skib#include <dev/drm2/drm.h>
34235783Skib#include <dev/drm2/drm_crtc.h>
35235783Skib#include <dev/drm2/drm_edid.h>
36235783Skib#include <dev/drm2/i915/i915_drm.h>
37235783Skib#include <dev/drm2/i915/i915_drv.h>
38235783Skib#include <dev/drm2/i915/intel_drv.h>
39235783Skib
40280369Skibstruct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
41235783Skib{
42235783Skib	return container_of(encoder, struct intel_hdmi, base.base);
43235783Skib}
44235783Skib
45235783Skibstatic struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
46235783Skib{
47235783Skib	return container_of(intel_attached_encoder(connector),
48235783Skib			    struct intel_hdmi, base);
49235783Skib}
50235783Skib
51235783Skibvoid intel_dip_infoframe_csum(struct dip_infoframe *frame)
52235783Skib{
53235783Skib	uint8_t *data = (uint8_t *)frame;
54235783Skib	uint8_t sum = 0;
55235783Skib	unsigned i;
56235783Skib
57235783Skib	frame->checksum = 0;
58235783Skib	frame->ecc = 0;
59235783Skib
60235783Skib	for (i = 0; i < frame->len + DIP_HEADER_SIZE; i++)
61235783Skib		sum += data[i];
62235783Skib
63235783Skib	frame->checksum = 0x100 - sum;
64235783Skib}
65235783Skib
66280369Skibstatic u32 g4x_infoframe_index(struct dip_infoframe *frame)
67235783Skib{
68280369Skib	switch (frame->type) {
69280369Skib	case DIP_TYPE_AVI:
70280369Skib		return VIDEO_DIP_SELECT_AVI;
71280369Skib	case DIP_TYPE_SPD:
72280369Skib		return VIDEO_DIP_SELECT_SPD;
73280369Skib	default:
74280369Skib		DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
75280369Skib		return 0;
76280369Skib	}
77280369Skib}
78235783Skib
79280369Skibstatic u32 g4x_infoframe_enable(struct dip_infoframe *frame)
80280369Skib{
81235783Skib	switch (frame->type) {
82235783Skib	case DIP_TYPE_AVI:
83280369Skib		return VIDEO_DIP_ENABLE_AVI;
84235783Skib	case DIP_TYPE_SPD:
85280369Skib		return VIDEO_DIP_ENABLE_SPD;
86235783Skib	default:
87280369Skib		DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
88280369Skib		return 0;
89235783Skib	}
90280369Skib}
91235783Skib
92280369Skibstatic u32 hsw_infoframe_enable(struct dip_infoframe *frame)
93280369Skib{
94280369Skib	switch (frame->type) {
95280369Skib	case DIP_TYPE_AVI:
96280369Skib		return VIDEO_DIP_ENABLE_AVI_HSW;
97280369Skib	case DIP_TYPE_SPD:
98280369Skib		return VIDEO_DIP_ENABLE_SPD_HSW;
99280369Skib	default:
100280369Skib		DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
101280369Skib		return 0;
102280369Skib	}
103235783Skib}
104235783Skib
105280369Skibstatic u32 hsw_infoframe_data_reg(struct dip_infoframe *frame, enum pipe pipe)
106235783Skib{
107235783Skib	switch (frame->type) {
108235783Skib	case DIP_TYPE_AVI:
109280369Skib		return HSW_TVIDEO_DIP_AVI_DATA(pipe);
110235783Skib	case DIP_TYPE_SPD:
111280369Skib		return HSW_TVIDEO_DIP_SPD_DATA(pipe);
112235783Skib	default:
113280369Skib		DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
114280369Skib		return 0;
115235783Skib	}
116235783Skib}
117235783Skib
118280369Skibstatic void g4x_write_infoframe(struct drm_encoder *encoder,
119280369Skib				struct dip_infoframe *frame)
120235783Skib{
121235783Skib	uint32_t *data = (uint32_t *)frame;
122235783Skib	struct drm_device *dev = encoder->dev;
123235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
124235783Skib	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
125280369Skib	u32 val = I915_READ(VIDEO_DIP_CTL);
126235783Skib	unsigned i, len = DIP_HEADER_SIZE + frame->len;
127235783Skib
128280369Skib	val &= ~VIDEO_DIP_PORT_MASK;
129235783Skib	if (intel_hdmi->sdvox_reg == SDVOB)
130280369Skib		val |= VIDEO_DIP_PORT_B;
131235783Skib	else if (intel_hdmi->sdvox_reg == SDVOC)
132280369Skib		val |= VIDEO_DIP_PORT_C;
133235783Skib	else
134235783Skib		return;
135235783Skib
136280369Skib	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
137280369Skib	val |= g4x_infoframe_index(frame);
138235783Skib
139280369Skib	val &= ~g4x_infoframe_enable(frame);
140280369Skib	val |= VIDEO_DIP_ENABLE;
141235783Skib
142280369Skib	I915_WRITE(VIDEO_DIP_CTL, val);
143235783Skib
144235783Skib	for (i = 0; i < len; i += 4) {
145235783Skib		I915_WRITE(VIDEO_DIP_DATA, *data);
146235783Skib		data++;
147235783Skib	}
148235783Skib
149280369Skib	val |= g4x_infoframe_enable(frame);
150280369Skib	val &= ~VIDEO_DIP_FREQ_MASK;
151280369Skib	val |= VIDEO_DIP_FREQ_VSYNC;
152235783Skib
153280369Skib	I915_WRITE(VIDEO_DIP_CTL, val);
154235783Skib}
155235783Skib
156280369Skibstatic void ibx_write_infoframe(struct drm_encoder *encoder,
157280369Skib				struct dip_infoframe *frame)
158235783Skib{
159235783Skib	uint32_t *data = (uint32_t *)frame;
160235783Skib	struct drm_device *dev = encoder->dev;
161235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
162280369Skib	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
163280369Skib	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
164235783Skib	int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
165235783Skib	unsigned i, len = DIP_HEADER_SIZE + frame->len;
166280369Skib	u32 val = I915_READ(reg);
167235783Skib
168280369Skib	val &= ~VIDEO_DIP_PORT_MASK;
169280369Skib	switch (intel_hdmi->sdvox_reg) {
170280369Skib	case HDMIB:
171280369Skib		val |= VIDEO_DIP_PORT_B;
172280369Skib		break;
173280369Skib	case HDMIC:
174280369Skib		val |= VIDEO_DIP_PORT_C;
175280369Skib		break;
176280369Skib	case HDMID:
177280369Skib		val |= VIDEO_DIP_PORT_D;
178280369Skib		break;
179280369Skib	default:
180280369Skib		return;
181280369Skib	}
182280369Skib
183235783Skib	intel_wait_for_vblank(dev, intel_crtc->pipe);
184235783Skib
185280369Skib	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
186280369Skib	val |= g4x_infoframe_index(frame);
187235783Skib
188280369Skib	val &= ~g4x_infoframe_enable(frame);
189280369Skib	val |= VIDEO_DIP_ENABLE;
190280369Skib
191280369Skib	I915_WRITE(reg, val);
192280369Skib
193280369Skib	for (i = 0; i < len; i += 4) {
194280369Skib		I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
195280369Skib		data++;
196280369Skib	}
197280369Skib
198280369Skib	val |= g4x_infoframe_enable(frame);
199280369Skib	val &= ~VIDEO_DIP_FREQ_MASK;
200280369Skib	val |= VIDEO_DIP_FREQ_VSYNC;
201280369Skib
202280369Skib	I915_WRITE(reg, val);
203280369Skib}
204280369Skib
205280369Skibstatic void cpt_write_infoframe(struct drm_encoder *encoder,
206280369Skib				struct dip_infoframe *frame)
207280369Skib{
208280369Skib	uint32_t *data = (uint32_t *)frame;
209280369Skib	struct drm_device *dev = encoder->dev;
210280369Skib	struct drm_i915_private *dev_priv = dev->dev_private;
211280369Skib	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
212280369Skib	int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
213280369Skib	unsigned i, len = DIP_HEADER_SIZE + frame->len;
214280369Skib	u32 val = I915_READ(reg);
215280369Skib
216280369Skib	intel_wait_for_vblank(dev, intel_crtc->pipe);
217280369Skib
218235783Skib	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
219280369Skib	val |= g4x_infoframe_index(frame);
220235783Skib
221280369Skib	/* The DIP control register spec says that we need to update the AVI
222280369Skib	 * infoframe without clearing its enable bit */
223280369Skib	if (frame->type == DIP_TYPE_AVI)
224280369Skib		val |= VIDEO_DIP_ENABLE_AVI;
225280369Skib	else
226280369Skib		val &= ~g4x_infoframe_enable(frame);
227235783Skib
228280369Skib	val |= VIDEO_DIP_ENABLE;
229280369Skib
230280369Skib	I915_WRITE(reg, val);
231280369Skib
232235783Skib	for (i = 0; i < len; i += 4) {
233235783Skib		I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
234235783Skib		data++;
235235783Skib	}
236235783Skib
237280369Skib	val |= g4x_infoframe_enable(frame);
238280369Skib	val &= ~VIDEO_DIP_FREQ_MASK;
239280369Skib	val |= VIDEO_DIP_FREQ_VSYNC;
240235783Skib
241280369Skib	I915_WRITE(reg, val);
242235783Skib}
243235783Skib
244280369Skibstatic void vlv_write_infoframe(struct drm_encoder *encoder,
245280369Skib				     struct dip_infoframe *frame)
246280369Skib{
247280369Skib	uint32_t *data = (uint32_t *)frame;
248280369Skib	struct drm_device *dev = encoder->dev;
249280369Skib	struct drm_i915_private *dev_priv = dev->dev_private;
250280369Skib	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
251280369Skib	int reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
252280369Skib	unsigned i, len = DIP_HEADER_SIZE + frame->len;
253280369Skib	u32 val = I915_READ(reg);
254280369Skib
255280369Skib	intel_wait_for_vblank(dev, intel_crtc->pipe);
256280369Skib
257280369Skib	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
258280369Skib	val |= g4x_infoframe_index(frame);
259280369Skib
260280369Skib	val &= ~g4x_infoframe_enable(frame);
261280369Skib	val |= VIDEO_DIP_ENABLE;
262280369Skib
263280369Skib	I915_WRITE(reg, val);
264280369Skib
265280369Skib	for (i = 0; i < len; i += 4) {
266280369Skib		I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
267280369Skib		data++;
268280369Skib	}
269280369Skib
270280369Skib	val |= g4x_infoframe_enable(frame);
271280369Skib	val &= ~VIDEO_DIP_FREQ_MASK;
272280369Skib	val |= VIDEO_DIP_FREQ_VSYNC;
273280369Skib
274280369Skib	I915_WRITE(reg, val);
275280369Skib}
276280369Skib
277280369Skibstatic void hsw_write_infoframe(struct drm_encoder *encoder,
278280369Skib				struct dip_infoframe *frame)
279280369Skib{
280280369Skib	uint32_t *data = (uint32_t *)frame;
281280369Skib	struct drm_device *dev = encoder->dev;
282280369Skib	struct drm_i915_private *dev_priv = dev->dev_private;
283280369Skib	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
284280369Skib	u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe);
285280369Skib	u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->pipe);
286280369Skib	unsigned int i, len = DIP_HEADER_SIZE + frame->len;
287280369Skib	u32 val = I915_READ(ctl_reg);
288280369Skib
289280369Skib	if (data_reg == 0)
290280369Skib		return;
291280369Skib
292280369Skib	intel_wait_for_vblank(dev, intel_crtc->pipe);
293280369Skib
294280369Skib	val &= ~hsw_infoframe_enable(frame);
295280369Skib	I915_WRITE(ctl_reg, val);
296280369Skib
297280369Skib	for (i = 0; i < len; i += 4) {
298280369Skib		I915_WRITE(data_reg + i, *data);
299280369Skib		data++;
300280369Skib	}
301280369Skib
302280369Skib	val |= hsw_infoframe_enable(frame);
303280369Skib	I915_WRITE(ctl_reg, val);
304280369Skib}
305280369Skib
306235783Skibstatic void intel_set_infoframe(struct drm_encoder *encoder,
307235783Skib				struct dip_infoframe *frame)
308235783Skib{
309235783Skib	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
310235783Skib
311235783Skib	if (!intel_hdmi->has_hdmi_sink)
312235783Skib		return;
313235783Skib
314235783Skib	intel_dip_infoframe_csum(frame);
315235783Skib	intel_hdmi->write_infoframe(encoder, frame);
316235783Skib}
317235783Skib
318280369Skibvoid intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
319280369Skib					 struct drm_display_mode *adjusted_mode)
320235783Skib{
321235783Skib	struct dip_infoframe avi_if = {
322235783Skib		.type = DIP_TYPE_AVI,
323235783Skib		.ver = DIP_VERSION_AVI,
324235783Skib		.len = DIP_LEN_AVI,
325235783Skib	};
326235783Skib
327280369Skib	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
328280369Skib		avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2;
329280369Skib
330235783Skib	intel_set_infoframe(encoder, &avi_if);
331235783Skib}
332235783Skib
333280369Skibvoid intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
334235783Skib{
335235783Skib	struct dip_infoframe spd_if;
336235783Skib
337235783Skib	memset(&spd_if, 0, sizeof(spd_if));
338235783Skib	spd_if.type = DIP_TYPE_SPD;
339235783Skib	spd_if.ver = DIP_VERSION_SPD;
340235783Skib	spd_if.len = DIP_LEN_SPD;
341235783Skib	strcpy(spd_if.body.spd.vn, "Intel");
342235783Skib	strcpy(spd_if.body.spd.pd, "Integrated gfx");
343235783Skib	spd_if.body.spd.sdi = DIP_SPD_PC;
344235783Skib
345235783Skib	intel_set_infoframe(encoder, &spd_if);
346235783Skib}
347235783Skib
348235783Skibstatic void intel_hdmi_mode_set(struct drm_encoder *encoder,
349235783Skib				struct drm_display_mode *mode,
350235783Skib				struct drm_display_mode *adjusted_mode)
351235783Skib{
352235783Skib	struct drm_device *dev = encoder->dev;
353235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
354280369Skib	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
355235783Skib	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
356235783Skib	u32 sdvox;
357235783Skib
358235783Skib	sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE;
359235783Skib	if (!HAS_PCH_SPLIT(dev))
360235783Skib		sdvox |= intel_hdmi->color_range;
361235783Skib	if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
362235783Skib		sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
363235783Skib	if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
364235783Skib		sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
365235783Skib
366235783Skib	if (intel_crtc->bpp > 24)
367235783Skib		sdvox |= COLOR_FORMAT_12bpc;
368235783Skib	else
369235783Skib		sdvox |= COLOR_FORMAT_8bpc;
370235783Skib
371235783Skib	/* Required on CPT */
372235783Skib	if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev))
373235783Skib		sdvox |= HDMI_MODE_SELECT;
374235783Skib
375235783Skib	if (intel_hdmi->has_audio) {
376235783Skib		DRM_DEBUG_KMS("Enabling HDMI audio on pipe %c\n",
377235783Skib				 pipe_name(intel_crtc->pipe));
378235783Skib		sdvox |= SDVO_AUDIO_ENABLE;
379235783Skib		sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC;
380235783Skib		intel_write_eld(encoder, adjusted_mode);
381235783Skib	}
382235783Skib
383235783Skib	if (HAS_PCH_CPT(dev))
384235783Skib		sdvox |= PORT_TRANS_SEL_CPT(intel_crtc->pipe);
385235783Skib	else if (intel_crtc->pipe == 1)
386235783Skib		sdvox |= SDVO_PIPE_B_SELECT;
387235783Skib
388235783Skib	I915_WRITE(intel_hdmi->sdvox_reg, sdvox);
389235783Skib	POSTING_READ(intel_hdmi->sdvox_reg);
390235783Skib
391280369Skib	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
392235783Skib	intel_hdmi_set_spd_infoframe(encoder);
393235783Skib}
394235783Skib
395235783Skibstatic void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
396235783Skib{
397235783Skib	struct drm_device *dev = encoder->dev;
398235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
399235783Skib	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
400235783Skib	u32 temp;
401235783Skib	u32 enable_bits = SDVO_ENABLE;
402235783Skib
403235783Skib	if (intel_hdmi->has_audio)
404235783Skib		enable_bits |= SDVO_AUDIO_ENABLE;
405235783Skib
406235783Skib	temp = I915_READ(intel_hdmi->sdvox_reg);
407235783Skib
408235783Skib	/* HW workaround, need to toggle enable bit off and on for 12bpc, but
409235783Skib	 * we do this anyway which shows more stable in testing.
410235783Skib	 */
411235783Skib	if (HAS_PCH_SPLIT(dev)) {
412235783Skib		I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE);
413235783Skib		POSTING_READ(intel_hdmi->sdvox_reg);
414235783Skib	}
415235783Skib
416235783Skib	if (mode != DRM_MODE_DPMS_ON) {
417235783Skib		temp &= ~enable_bits;
418235783Skib	} else {
419235783Skib		temp |= enable_bits;
420235783Skib	}
421235783Skib
422235783Skib	I915_WRITE(intel_hdmi->sdvox_reg, temp);
423235783Skib	POSTING_READ(intel_hdmi->sdvox_reg);
424235783Skib
425235783Skib	/* HW workaround, need to write this twice for issue that may result
426235783Skib	 * in first write getting masked.
427235783Skib	 */
428235783Skib	if (HAS_PCH_SPLIT(dev)) {
429235783Skib		I915_WRITE(intel_hdmi->sdvox_reg, temp);
430235783Skib		POSTING_READ(intel_hdmi->sdvox_reg);
431235783Skib	}
432235783Skib}
433235783Skib
434235783Skibstatic int intel_hdmi_mode_valid(struct drm_connector *connector,
435235783Skib				 struct drm_display_mode *mode)
436235783Skib{
437235783Skib	if (mode->clock > 165000)
438235783Skib		return MODE_CLOCK_HIGH;
439235783Skib	if (mode->clock < 20000)
440235783Skib		return MODE_CLOCK_LOW;
441235783Skib
442235783Skib	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
443235783Skib		return MODE_NO_DBLESCAN;
444235783Skib
445235783Skib	return MODE_OK;
446235783Skib}
447235783Skib
448235783Skibstatic bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
449282199Sdumbbell				  const struct drm_display_mode *mode,
450235783Skib				  struct drm_display_mode *adjusted_mode)
451235783Skib{
452235783Skib	return true;
453235783Skib}
454235783Skib
455235783Skibstatic enum drm_connector_status
456235783Skibintel_hdmi_detect(struct drm_connector *connector, bool force)
457235783Skib{
458235783Skib	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
459235783Skib	struct drm_i915_private *dev_priv = connector->dev->dev_private;
460235783Skib	struct edid *edid;
461235783Skib	enum drm_connector_status status = connector_status_disconnected;
462235783Skib
463235783Skib	intel_hdmi->has_hdmi_sink = false;
464235783Skib	intel_hdmi->has_audio = false;
465280369Skib	edid = drm_get_edid(connector, intel_gmbus_get_adapter(dev_priv,
466280369Skib	    intel_hdmi->ddc_bus));
467235783Skib
468235783Skib	if (edid) {
469235783Skib		if (edid->input & DRM_EDID_INPUT_DIGITAL) {
470235783Skib			status = connector_status_connected;
471235783Skib			if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI)
472235783Skib				intel_hdmi->has_hdmi_sink =
473235783Skib						drm_detect_hdmi_monitor(edid);
474235783Skib			intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
475235783Skib		}
476235783Skib		free(edid, DRM_MEM_KMS);
477235783Skib	} else {
478235783Skib		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] got no edid, ddc port %d\n",
479235783Skib		    connector->base.id, drm_get_connector_name(connector),
480235783Skib		    intel_hdmi->ddc_bus);
481235783Skib	}
482235783Skib
483235783Skib	if (status == connector_status_connected) {
484235783Skib		if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO)
485235783Skib			intel_hdmi->has_audio =
486235783Skib				(intel_hdmi->force_audio == HDMI_AUDIO_ON);
487235783Skib	}
488235783Skib
489235783Skib	return status;
490235783Skib}
491235783Skib
492235783Skibstatic int intel_hdmi_get_modes(struct drm_connector *connector)
493235783Skib{
494235783Skib	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
495235783Skib	struct drm_i915_private *dev_priv = connector->dev->dev_private;
496235783Skib
497235783Skib	/* We should parse the EDID data and find out if it's an HDMI sink so
498235783Skib	 * we can send audio to it.
499235783Skib	 */
500235783Skib
501235783Skib	return intel_ddc_get_modes(connector,
502280369Skib				   intel_gmbus_get_adapter(dev_priv,
503280369Skib							   intel_hdmi->ddc_bus));
504235783Skib}
505235783Skib
506235783Skibstatic bool
507235783Skibintel_hdmi_detect_audio(struct drm_connector *connector)
508235783Skib{
509235783Skib	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
510235783Skib	struct drm_i915_private *dev_priv = connector->dev->dev_private;
511235783Skib	struct edid *edid;
512235783Skib	bool has_audio = false;
513235783Skib
514280369Skib	edid = drm_get_edid(connector,
515280369Skib			    intel_gmbus_get_adapter(dev_priv,
516280369Skib						    intel_hdmi->ddc_bus));
517235783Skib	if (edid) {
518235783Skib		if (edid->input & DRM_EDID_INPUT_DIGITAL)
519235783Skib			has_audio = drm_detect_monitor_audio(edid);
520235783Skib
521235783Skib		free(edid, DRM_MEM_KMS);
522235783Skib	}
523235783Skib
524235783Skib	return has_audio;
525235783Skib}
526235783Skib
527235783Skibstatic int
528235783Skibintel_hdmi_set_property(struct drm_connector *connector,
529235783Skib		      struct drm_property *property,
530235783Skib		      uint64_t val)
531235783Skib{
532235783Skib	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
533235783Skib	struct drm_i915_private *dev_priv = connector->dev->dev_private;
534235783Skib	int ret;
535235783Skib
536282199Sdumbbell	ret = drm_object_property_set_value(&connector->base, property, val);
537235783Skib	if (ret)
538235783Skib		return ret;
539235783Skib
540235783Skib	if (property == dev_priv->force_audio_property) {
541235783Skib		enum hdmi_force_audio i = val;
542235783Skib		bool has_audio;
543235783Skib
544235783Skib		if (i == intel_hdmi->force_audio)
545235783Skib			return 0;
546235783Skib
547235783Skib		intel_hdmi->force_audio = i;
548235783Skib
549235783Skib		if (i == HDMI_AUDIO_AUTO)
550235783Skib			has_audio = intel_hdmi_detect_audio(connector);
551235783Skib		else
552235783Skib			has_audio = (i == HDMI_AUDIO_ON);
553235783Skib
554235783Skib		if (i == HDMI_AUDIO_OFF_DVI)
555235783Skib			intel_hdmi->has_hdmi_sink = 0;
556235783Skib
557235783Skib		intel_hdmi->has_audio = has_audio;
558235783Skib		goto done;
559235783Skib	}
560235783Skib
561235783Skib	if (property == dev_priv->broadcast_rgb_property) {
562235783Skib		if (val == !!intel_hdmi->color_range)
563235783Skib			return 0;
564235783Skib
565235783Skib		intel_hdmi->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0;
566235783Skib		goto done;
567235783Skib	}
568235783Skib
569235783Skib	return -EINVAL;
570235783Skib
571235783Skibdone:
572235783Skib	if (intel_hdmi->base.base.crtc) {
573235783Skib		struct drm_crtc *crtc = intel_hdmi->base.base.crtc;
574235783Skib		drm_crtc_helper_set_mode(crtc, &crtc->mode,
575235783Skib					 crtc->x, crtc->y,
576235783Skib					 crtc->fb);
577235783Skib	}
578235783Skib
579235783Skib	return 0;
580235783Skib}
581235783Skib
582235783Skibstatic void intel_hdmi_destroy(struct drm_connector *connector)
583235783Skib{
584235783Skib#if 0
585235783Skib	drm_sysfs_connector_remove(connector);
586235783Skib#endif
587235783Skib	drm_connector_cleanup(connector);
588235783Skib	free(connector, DRM_MEM_KMS);
589235783Skib}
590235783Skib
591280369Skibstatic const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = {
592280369Skib	.dpms = intel_ddi_dpms,
593280369Skib	.mode_fixup = intel_hdmi_mode_fixup,
594280369Skib	.prepare = intel_encoder_prepare,
595280369Skib	.mode_set = intel_ddi_mode_set,
596280369Skib	.commit = intel_encoder_commit,
597280369Skib};
598280369Skib
599235783Skibstatic const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
600235783Skib	.dpms = intel_hdmi_dpms,
601235783Skib	.mode_fixup = intel_hdmi_mode_fixup,
602235783Skib	.prepare = intel_encoder_prepare,
603235783Skib	.mode_set = intel_hdmi_mode_set,
604235783Skib	.commit = intel_encoder_commit,
605235783Skib};
606235783Skib
607235783Skibstatic const struct drm_connector_funcs intel_hdmi_connector_funcs = {
608235783Skib	.dpms = drm_helper_connector_dpms,
609235783Skib	.detect = intel_hdmi_detect,
610235783Skib	.fill_modes = drm_helper_probe_single_connector_modes,
611235783Skib	.set_property = intel_hdmi_set_property,
612235783Skib	.destroy = intel_hdmi_destroy,
613235783Skib};
614235783Skib
615235783Skibstatic const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = {
616235783Skib	.get_modes = intel_hdmi_get_modes,
617235783Skib	.mode_valid = intel_hdmi_mode_valid,
618235783Skib	.best_encoder = intel_best_encoder,
619235783Skib};
620235783Skib
621235783Skibstatic const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
622235783Skib	.destroy = intel_encoder_destroy,
623235783Skib};
624235783Skib
625235783Skibstatic void
626235783Skibintel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector)
627235783Skib{
628235783Skib	intel_attach_force_audio_property(connector);
629235783Skib	intel_attach_broadcast_rgb_property(connector);
630235783Skib}
631235783Skib
632235783Skibvoid intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
633235783Skib{
634235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
635235783Skib	struct drm_connector *connector;
636235783Skib	struct intel_encoder *intel_encoder;
637235783Skib	struct intel_connector *intel_connector;
638235783Skib	struct intel_hdmi *intel_hdmi;
639235783Skib	int i;
640235783Skib
641235783Skib	intel_hdmi = malloc(sizeof(struct intel_hdmi), DRM_MEM_KMS,
642235783Skib	    M_WAITOK | M_ZERO);
643235783Skib	intel_connector = malloc(sizeof(struct intel_connector), DRM_MEM_KMS,
644235783Skib	    M_WAITOK | M_ZERO);
645235783Skib
646235783Skib	intel_encoder = &intel_hdmi->base;
647235783Skib	drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs,
648235783Skib			 DRM_MODE_ENCODER_TMDS);
649235783Skib
650235783Skib	connector = &intel_connector->base;
651235783Skib	drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
652235783Skib			   DRM_MODE_CONNECTOR_HDMIA);
653235783Skib	drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
654235783Skib
655235783Skib	intel_encoder->type = INTEL_OUTPUT_HDMI;
656235783Skib
657235783Skib	connector->polled = DRM_CONNECTOR_POLL_HPD;
658235783Skib	connector->interlace_allowed = 1;
659235783Skib	connector->doublescan_allowed = 0;
660235783Skib	intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
661235783Skib
662235783Skib	/* Set up the DDC bus. */
663235783Skib	if (sdvox_reg == SDVOB) {
664235783Skib		intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
665235783Skib		intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
666235783Skib		dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
667235783Skib	} else if (sdvox_reg == SDVOC) {
668235783Skib		intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
669235783Skib		intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
670235783Skib		dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
671235783Skib	} else if (sdvox_reg == HDMIB) {
672235783Skib		intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
673235783Skib		intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
674235783Skib		dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
675235783Skib	} else if (sdvox_reg == HDMIC) {
676235783Skib		intel_encoder->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT);
677235783Skib		intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
678235783Skib		dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
679235783Skib	} else if (sdvox_reg == HDMID) {
680235783Skib		intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT);
681235783Skib		intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
682235783Skib		dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
683280369Skib	} else if (sdvox_reg == DDI_BUF_CTL(PORT_B)) {
684280369Skib		DRM_DEBUG_DRIVER("LPT: detected output on DDI B\n");
685280369Skib		intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
686280369Skib		intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
687280369Skib		intel_hdmi->ddi_port = PORT_B;
688280369Skib		dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
689280369Skib	} else if (sdvox_reg == DDI_BUF_CTL(PORT_C)) {
690280369Skib		DRM_DEBUG_DRIVER("LPT: detected output on DDI C\n");
691280369Skib		intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
692280369Skib		intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
693280369Skib		intel_hdmi->ddi_port = PORT_C;
694280369Skib		dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
695280369Skib	} else if (sdvox_reg == DDI_BUF_CTL(PORT_D)) {
696280369Skib		DRM_DEBUG_DRIVER("LPT: detected output on DDI D\n");
697280369Skib		intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
698280369Skib		intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
699280369Skib		intel_hdmi->ddi_port = PORT_D;
700280369Skib		dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
701280369Skib	} else {
702280369Skib		/* If we got an unknown sdvox_reg, things are pretty much broken
703280369Skib		 * in a way that we should let the kernel know about it */
704280369Skib		DRM_DEBUG_KMS("unknown sdvox_reg %d\n", sdvox_reg);
705235783Skib	}
706235783Skib
707235783Skib	intel_hdmi->sdvox_reg = sdvox_reg;
708235783Skib	if (!HAS_PCH_SPLIT(dev)) {
709280369Skib		intel_hdmi->write_infoframe = g4x_write_infoframe;
710235783Skib		I915_WRITE(VIDEO_DIP_CTL, 0);
711280369Skib	} else if (IS_VALLEYVIEW(dev)) {
712280369Skib		intel_hdmi->write_infoframe = vlv_write_infoframe;
713280369Skib		for_each_pipe(i)
714280369Skib			I915_WRITE(VLV_TVIDEO_DIP_CTL(i), 0);
715280369Skib	} else if (IS_HASWELL(dev)) {
716280369Skib		/* FIXME: Haswell has a new set of DIP frame registers, but we are
717280369Skib		 * just doing the minimal required for HDMI to work at this stage.
718280369Skib		 */
719280369Skib		intel_hdmi->write_infoframe = hsw_write_infoframe;
720280369Skib		for_each_pipe(i)
721280369Skib			I915_WRITE(HSW_TVIDEO_DIP_CTL(i), 0);
722280369Skib	} else if (HAS_PCH_IBX(dev)) {
723280369Skib		intel_hdmi->write_infoframe = ibx_write_infoframe;
724280369Skib		for_each_pipe(i)
725280369Skib			I915_WRITE(TVIDEO_DIP_CTL(i), 0);
726235783Skib	} else {
727280369Skib		intel_hdmi->write_infoframe = cpt_write_infoframe;
728235783Skib		for_each_pipe(i)
729235783Skib			I915_WRITE(TVIDEO_DIP_CTL(i), 0);
730235783Skib	}
731235783Skib
732280369Skib	if (IS_HASWELL(dev))
733280369Skib		drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs_hsw);
734280369Skib	else
735280369Skib		drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
736235783Skib
737235783Skib	intel_hdmi_add_properties(intel_hdmi, connector);
738235783Skib
739235783Skib	intel_connector_attach_encoder(intel_connector, intel_encoder);
740235783Skib#if 0
741235783Skib	drm_sysfs_connector_add(connector);
742235783Skib#endif
743235783Skib
744235783Skib	/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
745235783Skib	 * 0xd.  Failure to do so will result in spurious interrupts being
746235783Skib	 * generated on the port when a cable is not attached.
747235783Skib	 */
748235783Skib	if (IS_G4X(dev) && !IS_GM45(dev)) {
749235783Skib		u32 temp = I915_READ(PEG_BAND_GAP_DATA);
750235783Skib		I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
751235783Skib	}
752235783Skib}
753