xref: /dflybsd-src/sys/dev/drm/i915/intel_crt.c (revision 18e26a6d64e907d16611297f1177265f67b49795)
1e3adcf8fSFrançois Tigeot /*
2e3adcf8fSFrançois Tigeot  * Copyright © 2006-2007 Intel Corporation
3e3adcf8fSFrançois Tigeot  *
4e3adcf8fSFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
5e3adcf8fSFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
6e3adcf8fSFrançois Tigeot  * to deal in the Software without restriction, including without limitation
7e3adcf8fSFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8e3adcf8fSFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
9e3adcf8fSFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
10e3adcf8fSFrançois Tigeot  *
11e3adcf8fSFrançois Tigeot  * The above copyright notice and this permission notice (including the next
12e3adcf8fSFrançois Tigeot  * paragraph) shall be included in all copies or substantial portions of the
13e3adcf8fSFrançois Tigeot  * Software.
14e3adcf8fSFrançois Tigeot  *
15e3adcf8fSFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16e3adcf8fSFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17e3adcf8fSFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18e3adcf8fSFrançois Tigeot  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19e3adcf8fSFrançois Tigeot  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20e3adcf8fSFrançois Tigeot  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21e3adcf8fSFrançois Tigeot  * DEALINGS IN THE SOFTWARE.
22e3adcf8fSFrançois Tigeot  *
23e3adcf8fSFrançois Tigeot  * Authors:
24e3adcf8fSFrançois Tigeot  *	Eric Anholt <eric@anholt.net>
25e3adcf8fSFrançois Tigeot  *
26e3adcf8fSFrançois Tigeot  * $FreeBSD: src/sys/dev/drm2/i915/intel_crt.c,v 1.1 2012/05/22 11:07:44 kib Exp $
27e3adcf8fSFrançois Tigeot  */
28e3adcf8fSFrançois Tigeot 
29*18e26a6dSFrançois Tigeot #include <drm/drmP.h>
30*18e26a6dSFrançois Tigeot #include <drm/drm_crtc.h>
31*18e26a6dSFrançois Tigeot #include <drm/drm_crtc_helper.h>
32*18e26a6dSFrançois Tigeot #include <drm/drm_edid.h>
33*18e26a6dSFrançois Tigeot #include "intel_drv.h"
34e3adcf8fSFrançois Tigeot #include "i915_drm.h"
35e3adcf8fSFrançois Tigeot #include "i915_drv.h"
36e3adcf8fSFrançois Tigeot 
37e3adcf8fSFrançois Tigeot /* Here's the desired hotplug mode */
38e3adcf8fSFrançois Tigeot #define ADPA_HOTPLUG_BITS (ADPA_CRT_HOTPLUG_PERIOD_128 |		\
39e3adcf8fSFrançois Tigeot 			   ADPA_CRT_HOTPLUG_WARMUP_10MS |		\
40e3adcf8fSFrançois Tigeot 			   ADPA_CRT_HOTPLUG_SAMPLE_4S |			\
41e3adcf8fSFrançois Tigeot 			   ADPA_CRT_HOTPLUG_VOLTAGE_50 |		\
42e3adcf8fSFrançois Tigeot 			   ADPA_CRT_HOTPLUG_VOLREF_325MV |		\
43e3adcf8fSFrançois Tigeot 			   ADPA_CRT_HOTPLUG_ENABLE)
44e3adcf8fSFrançois Tigeot 
45e3adcf8fSFrançois Tigeot struct intel_crt {
46e3adcf8fSFrançois Tigeot 	struct intel_encoder base;
47e3adcf8fSFrançois Tigeot 	bool force_hotplug_required;
48e3adcf8fSFrançois Tigeot };
49e3adcf8fSFrançois Tigeot 
50e3adcf8fSFrançois Tigeot static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
51e3adcf8fSFrançois Tigeot {
52e3adcf8fSFrançois Tigeot 	return container_of(intel_attached_encoder(connector),
53e3adcf8fSFrançois Tigeot 			    struct intel_crt, base);
54e3adcf8fSFrançois Tigeot }
55e3adcf8fSFrançois Tigeot 
56e3adcf8fSFrançois Tigeot static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
57e3adcf8fSFrançois Tigeot {
58e3adcf8fSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
59e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
60e3adcf8fSFrançois Tigeot 	u32 temp, reg;
61e3adcf8fSFrançois Tigeot 
62e3adcf8fSFrançois Tigeot 	if (HAS_PCH_SPLIT(dev))
63e3adcf8fSFrançois Tigeot 		reg = PCH_ADPA;
64e3adcf8fSFrançois Tigeot 	else
65e3adcf8fSFrançois Tigeot 		reg = ADPA;
66e3adcf8fSFrançois Tigeot 
67e3adcf8fSFrançois Tigeot 	temp = I915_READ(reg);
68e3adcf8fSFrançois Tigeot 	temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
69e3adcf8fSFrançois Tigeot 	temp &= ~ADPA_DAC_ENABLE;
70e3adcf8fSFrançois Tigeot 
71e3adcf8fSFrançois Tigeot 	switch (mode) {
72e3adcf8fSFrançois Tigeot 	case DRM_MODE_DPMS_ON:
73e3adcf8fSFrançois Tigeot 		temp |= ADPA_DAC_ENABLE;
74e3adcf8fSFrançois Tigeot 		break;
75e3adcf8fSFrançois Tigeot 	case DRM_MODE_DPMS_STANDBY:
76e3adcf8fSFrançois Tigeot 		temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE;
77e3adcf8fSFrançois Tigeot 		break;
78e3adcf8fSFrançois Tigeot 	case DRM_MODE_DPMS_SUSPEND:
79e3adcf8fSFrançois Tigeot 		temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE;
80e3adcf8fSFrançois Tigeot 		break;
81e3adcf8fSFrançois Tigeot 	case DRM_MODE_DPMS_OFF:
82e3adcf8fSFrançois Tigeot 		temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE;
83e3adcf8fSFrançois Tigeot 		break;
84e3adcf8fSFrançois Tigeot 	}
85e3adcf8fSFrançois Tigeot 
86e3adcf8fSFrançois Tigeot 	I915_WRITE(reg, temp);
87e3adcf8fSFrançois Tigeot }
88e3adcf8fSFrançois Tigeot 
89e3adcf8fSFrançois Tigeot static int intel_crt_mode_valid(struct drm_connector *connector,
90e3adcf8fSFrançois Tigeot 				struct drm_display_mode *mode)
91e3adcf8fSFrançois Tigeot {
92e3adcf8fSFrançois Tigeot 	struct drm_device *dev = connector->dev;
93e3adcf8fSFrançois Tigeot 
94e3adcf8fSFrançois Tigeot 	int max_clock = 0;
95e3adcf8fSFrançois Tigeot 	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
96e3adcf8fSFrançois Tigeot 		return MODE_NO_DBLESCAN;
97e3adcf8fSFrançois Tigeot 
98e3adcf8fSFrançois Tigeot 	if (mode->clock < 25000)
99e3adcf8fSFrançois Tigeot 		return MODE_CLOCK_LOW;
100e3adcf8fSFrançois Tigeot 
101e3adcf8fSFrançois Tigeot 	if (IS_GEN2(dev))
102e3adcf8fSFrançois Tigeot 		max_clock = 350000;
103e3adcf8fSFrançois Tigeot 	else
104e3adcf8fSFrançois Tigeot 		max_clock = 400000;
105e3adcf8fSFrançois Tigeot 	if (mode->clock > max_clock)
106e3adcf8fSFrançois Tigeot 		return MODE_CLOCK_HIGH;
107e3adcf8fSFrançois Tigeot 
108e3adcf8fSFrançois Tigeot 	return MODE_OK;
109e3adcf8fSFrançois Tigeot }
110e3adcf8fSFrançois Tigeot 
111e3adcf8fSFrançois Tigeot static bool intel_crt_mode_fixup(struct drm_encoder *encoder,
1126f486c69SFrançois Tigeot 				 const struct drm_display_mode *mode,
113e3adcf8fSFrançois Tigeot 				 struct drm_display_mode *adjusted_mode)
114e3adcf8fSFrançois Tigeot {
115e3adcf8fSFrançois Tigeot 	return true;
116e3adcf8fSFrançois Tigeot }
117e3adcf8fSFrançois Tigeot 
118e3adcf8fSFrançois Tigeot static void intel_crt_mode_set(struct drm_encoder *encoder,
119e3adcf8fSFrançois Tigeot 			       struct drm_display_mode *mode,
120e3adcf8fSFrançois Tigeot 			       struct drm_display_mode *adjusted_mode)
121e3adcf8fSFrançois Tigeot {
122e3adcf8fSFrançois Tigeot 
123e3adcf8fSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
124e3adcf8fSFrançois Tigeot 	struct drm_crtc *crtc = encoder->crtc;
125e3adcf8fSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
126e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
127e3adcf8fSFrançois Tigeot 	int dpll_md_reg;
128e3adcf8fSFrançois Tigeot 	u32 adpa, dpll_md;
129e3adcf8fSFrançois Tigeot 	u32 adpa_reg;
130e3adcf8fSFrançois Tigeot 
131e3adcf8fSFrançois Tigeot 	dpll_md_reg = DPLL_MD(intel_crtc->pipe);
132e3adcf8fSFrançois Tigeot 
133e3adcf8fSFrançois Tigeot 	if (HAS_PCH_SPLIT(dev))
134e3adcf8fSFrançois Tigeot 		adpa_reg = PCH_ADPA;
135e3adcf8fSFrançois Tigeot 	else
136e3adcf8fSFrançois Tigeot 		adpa_reg = ADPA;
137e3adcf8fSFrançois Tigeot 
138e3adcf8fSFrançois Tigeot 	/*
139e3adcf8fSFrançois Tigeot 	 * Disable separate mode multiplier used when cloning SDVO to CRT
140e3adcf8fSFrançois Tigeot 	 * XXX this needs to be adjusted when we really are cloning
141e3adcf8fSFrançois Tigeot 	 */
142e3adcf8fSFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
143e3adcf8fSFrançois Tigeot 		dpll_md = I915_READ(dpll_md_reg);
144e3adcf8fSFrançois Tigeot 		I915_WRITE(dpll_md_reg,
145e3adcf8fSFrançois Tigeot 			   dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
146e3adcf8fSFrançois Tigeot 	}
147e3adcf8fSFrançois Tigeot 
148e3adcf8fSFrançois Tigeot 	adpa = ADPA_HOTPLUG_BITS;
149e3adcf8fSFrançois Tigeot 	if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
150e3adcf8fSFrançois Tigeot 		adpa |= ADPA_HSYNC_ACTIVE_HIGH;
151e3adcf8fSFrançois Tigeot 	if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
152e3adcf8fSFrançois Tigeot 		adpa |= ADPA_VSYNC_ACTIVE_HIGH;
153e3adcf8fSFrançois Tigeot 
154e3adcf8fSFrançois Tigeot 	/* For CPT allow 3 pipe config, for others just use A or B */
155e3adcf8fSFrançois Tigeot 	if (HAS_PCH_CPT(dev))
156e3adcf8fSFrançois Tigeot 		adpa |= PORT_TRANS_SEL_CPT(intel_crtc->pipe);
157e3adcf8fSFrançois Tigeot 	else if (intel_crtc->pipe == 0)
158e3adcf8fSFrançois Tigeot 		adpa |= ADPA_PIPE_A_SELECT;
159e3adcf8fSFrançois Tigeot 	else
160e3adcf8fSFrançois Tigeot 		adpa |= ADPA_PIPE_B_SELECT;
161e3adcf8fSFrançois Tigeot 
162e3adcf8fSFrançois Tigeot 	if (!HAS_PCH_SPLIT(dev))
163e3adcf8fSFrançois Tigeot 		I915_WRITE(BCLRPAT(intel_crtc->pipe), 0);
164e3adcf8fSFrançois Tigeot 
165e3adcf8fSFrançois Tigeot 	I915_WRITE(adpa_reg, adpa);
166e3adcf8fSFrançois Tigeot }
167e3adcf8fSFrançois Tigeot 
168e3adcf8fSFrançois Tigeot static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
169e3adcf8fSFrançois Tigeot {
170e3adcf8fSFrançois Tigeot 	struct drm_device *dev = connector->dev;
171e3adcf8fSFrançois Tigeot 	struct intel_crt *crt = intel_attached_crt(connector);
172e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
173e3adcf8fSFrançois Tigeot 	u32 adpa;
174e3adcf8fSFrançois Tigeot 	bool ret;
175e3adcf8fSFrançois Tigeot 
176e3adcf8fSFrançois Tigeot 	/* The first time through, trigger an explicit detection cycle */
177e3adcf8fSFrançois Tigeot 	if (crt->force_hotplug_required) {
178e3adcf8fSFrançois Tigeot 		bool turn_off_dac = HAS_PCH_SPLIT(dev);
179e3adcf8fSFrançois Tigeot 		u32 save_adpa;
180e3adcf8fSFrançois Tigeot 
181e3adcf8fSFrançois Tigeot 		crt->force_hotplug_required = 0;
182e3adcf8fSFrançois Tigeot 
183e3adcf8fSFrançois Tigeot 		save_adpa = adpa = I915_READ(PCH_ADPA);
184e3adcf8fSFrançois Tigeot 		DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);
185e3adcf8fSFrançois Tigeot 
186e3adcf8fSFrançois Tigeot 		adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER;
187e3adcf8fSFrançois Tigeot 		if (turn_off_dac)
188e3adcf8fSFrançois Tigeot 			adpa &= ~ADPA_DAC_ENABLE;
189e3adcf8fSFrançois Tigeot 
190e3adcf8fSFrançois Tigeot 		I915_WRITE(PCH_ADPA, adpa);
191e3adcf8fSFrançois Tigeot 
192e3adcf8fSFrançois Tigeot 		if (_intel_wait_for(dev,
193e3adcf8fSFrançois Tigeot 		    (I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
194e3adcf8fSFrançois Tigeot 		    1000, 1, "915crt"))
195e3adcf8fSFrançois Tigeot 			DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER\n");
196e3adcf8fSFrançois Tigeot 
197e3adcf8fSFrançois Tigeot 		if (turn_off_dac) {
198e3adcf8fSFrançois Tigeot 			I915_WRITE(PCH_ADPA, save_adpa);
199e3adcf8fSFrançois Tigeot 			POSTING_READ(PCH_ADPA);
200e3adcf8fSFrançois Tigeot 		}
201e3adcf8fSFrançois Tigeot 	}
202e3adcf8fSFrançois Tigeot 
203e3adcf8fSFrançois Tigeot 	/* Check the status to see if both blue and green are on now */
204e3adcf8fSFrançois Tigeot 	adpa = I915_READ(PCH_ADPA);
205e3adcf8fSFrançois Tigeot 	if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0)
206e3adcf8fSFrançois Tigeot 		ret = true;
207e3adcf8fSFrançois Tigeot 	else
208e3adcf8fSFrançois Tigeot 		ret = false;
209e3adcf8fSFrançois Tigeot 	DRM_DEBUG_KMS("ironlake hotplug adpa=0x%x, result %d\n", adpa, ret);
210e3adcf8fSFrançois Tigeot 
211e3adcf8fSFrançois Tigeot 	return ret;
212e3adcf8fSFrançois Tigeot }
213e3adcf8fSFrançois Tigeot 
214e3adcf8fSFrançois Tigeot /**
215e3adcf8fSFrançois Tigeot  * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence.
216e3adcf8fSFrançois Tigeot  *
217e3adcf8fSFrançois Tigeot  * Not for i915G/i915GM
218e3adcf8fSFrançois Tigeot  *
219e3adcf8fSFrançois Tigeot  * \return true if CRT is connected.
220e3adcf8fSFrançois Tigeot  * \return false if CRT is disconnected.
221e3adcf8fSFrançois Tigeot  */
222e3adcf8fSFrançois Tigeot static bool intel_crt_detect_hotplug(struct drm_connector *connector)
223e3adcf8fSFrançois Tigeot {
224e3adcf8fSFrançois Tigeot 	struct drm_device *dev = connector->dev;
225e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
226e3adcf8fSFrançois Tigeot 	u32 hotplug_en, orig, stat;
227e3adcf8fSFrançois Tigeot 	bool ret = false;
228e3adcf8fSFrançois Tigeot 	int i, tries = 0;
229e3adcf8fSFrançois Tigeot 
230e3adcf8fSFrançois Tigeot 	if (HAS_PCH_SPLIT(dev))
231e3adcf8fSFrançois Tigeot 		return intel_ironlake_crt_detect_hotplug(connector);
232e3adcf8fSFrançois Tigeot 
233e3adcf8fSFrançois Tigeot 	/*
234e3adcf8fSFrançois Tigeot 	 * On 4 series desktop, CRT detect sequence need to be done twice
235e3adcf8fSFrançois Tigeot 	 * to get a reliable result.
236e3adcf8fSFrançois Tigeot 	 */
237e3adcf8fSFrançois Tigeot 
238e3adcf8fSFrançois Tigeot 	if (IS_G4X(dev) && !IS_GM45(dev))
239e3adcf8fSFrançois Tigeot 		tries = 2;
240e3adcf8fSFrançois Tigeot 	else
241e3adcf8fSFrançois Tigeot 		tries = 1;
242e3adcf8fSFrançois Tigeot 	hotplug_en = orig = I915_READ(PORT_HOTPLUG_EN);
243e3adcf8fSFrançois Tigeot 	hotplug_en |= CRT_HOTPLUG_FORCE_DETECT;
244e3adcf8fSFrançois Tigeot 
245e3adcf8fSFrançois Tigeot 	for (i = 0; i < tries ; i++) {
246e3adcf8fSFrançois Tigeot 		/* turn on the FORCE_DETECT */
247e3adcf8fSFrançois Tigeot 		I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
248e3adcf8fSFrançois Tigeot 		/* wait for FORCE_DETECT to go off */
249e3adcf8fSFrançois Tigeot 		if (_intel_wait_for(dev,
250e3adcf8fSFrançois Tigeot 		    (I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT) == 0,
251e3adcf8fSFrançois Tigeot 		    1000, 1, "915cr2"))
252e3adcf8fSFrançois Tigeot 			DRM_DEBUG_KMS("timed out waiting for FORCE_DETECT to go off");
253e3adcf8fSFrançois Tigeot 	}
254e3adcf8fSFrançois Tigeot 
255e3adcf8fSFrançois Tigeot 	stat = I915_READ(PORT_HOTPLUG_STAT);
256e3adcf8fSFrançois Tigeot 	if ((stat & CRT_HOTPLUG_MONITOR_MASK) != CRT_HOTPLUG_MONITOR_NONE)
257e3adcf8fSFrançois Tigeot 		ret = true;
258e3adcf8fSFrançois Tigeot 
259e3adcf8fSFrançois Tigeot 	/* clear the interrupt we just generated, if any */
260e3adcf8fSFrançois Tigeot 	I915_WRITE(PORT_HOTPLUG_STAT, CRT_HOTPLUG_INT_STATUS);
261e3adcf8fSFrançois Tigeot 
262e3adcf8fSFrançois Tigeot 	/* and put the bits back */
263e3adcf8fSFrançois Tigeot 	I915_WRITE(PORT_HOTPLUG_EN, orig);
264e3adcf8fSFrançois Tigeot 
265e3adcf8fSFrançois Tigeot 	return ret;
266e3adcf8fSFrançois Tigeot }
267e3adcf8fSFrançois Tigeot 
268e3adcf8fSFrançois Tigeot static bool intel_crt_detect_ddc(struct drm_connector *connector)
269e3adcf8fSFrançois Tigeot {
270e3adcf8fSFrançois Tigeot 	struct intel_crt *crt = intel_attached_crt(connector);
271e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private;
272e3adcf8fSFrançois Tigeot 
273e3adcf8fSFrançois Tigeot 	/* CRT should always be at 0, but check anyway */
274e3adcf8fSFrançois Tigeot 	if (crt->base.type != INTEL_OUTPUT_ANALOG)
275e3adcf8fSFrançois Tigeot 		return false;
276e3adcf8fSFrançois Tigeot 
277e3adcf8fSFrançois Tigeot 	if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) {
278e3adcf8fSFrançois Tigeot 		struct edid *edid;
279e3adcf8fSFrançois Tigeot 		bool is_digital = false;
280e3adcf8fSFrançois Tigeot 
281e3adcf8fSFrançois Tigeot 		edid = drm_get_edid(connector,
282e3adcf8fSFrançois Tigeot 		    dev_priv->gmbus[dev_priv->crt_ddc_pin]);
283e3adcf8fSFrançois Tigeot 		/*
284e3adcf8fSFrançois Tigeot 		 * This may be a DVI-I connector with a shared DDC
285e3adcf8fSFrançois Tigeot 		 * link between analog and digital outputs, so we
286e3adcf8fSFrançois Tigeot 		 * have to check the EDID input spec of the attached device.
287e3adcf8fSFrançois Tigeot 		 *
288e3adcf8fSFrançois Tigeot 		 * On the other hand, what should we do if it is a broken EDID?
289e3adcf8fSFrançois Tigeot 		 */
290e3adcf8fSFrançois Tigeot 		if (edid != NULL) {
291e3adcf8fSFrançois Tigeot 			is_digital = edid->input & DRM_EDID_INPUT_DIGITAL;
292e3adcf8fSFrançois Tigeot 			connector->display_info.raw_edid = NULL;
293e3adcf8fSFrançois Tigeot 			drm_free(edid, DRM_MEM_KMS);
294e3adcf8fSFrançois Tigeot 		}
295e3adcf8fSFrançois Tigeot 
296e3adcf8fSFrançois Tigeot 		if (!is_digital) {
297e3adcf8fSFrançois Tigeot 			DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
298e3adcf8fSFrançois Tigeot 			return true;
299e3adcf8fSFrançois Tigeot 		} else {
300e3adcf8fSFrançois Tigeot 			DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n");
301e3adcf8fSFrançois Tigeot 		}
302e3adcf8fSFrançois Tigeot 	}
303e3adcf8fSFrançois Tigeot 
304e3adcf8fSFrançois Tigeot 	return false;
305e3adcf8fSFrançois Tigeot }
306e3adcf8fSFrançois Tigeot 
307e3adcf8fSFrançois Tigeot static enum drm_connector_status
308e3adcf8fSFrançois Tigeot intel_crt_load_detect(struct intel_crt *crt)
309e3adcf8fSFrançois Tigeot {
310e3adcf8fSFrançois Tigeot 	struct drm_device *dev = crt->base.base.dev;
311e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
312e3adcf8fSFrançois Tigeot 	uint32_t pipe = to_intel_crtc(crt->base.base.crtc)->pipe;
313e3adcf8fSFrançois Tigeot 	uint32_t save_bclrpat;
314e3adcf8fSFrançois Tigeot 	uint32_t save_vtotal;
315e3adcf8fSFrançois Tigeot 	uint32_t vtotal, vactive;
316e3adcf8fSFrançois Tigeot 	uint32_t vsample;
317e3adcf8fSFrançois Tigeot 	uint32_t vblank, vblank_start, vblank_end;
318e3adcf8fSFrançois Tigeot 	uint32_t dsl;
319e3adcf8fSFrançois Tigeot 	uint32_t bclrpat_reg;
320e3adcf8fSFrançois Tigeot 	uint32_t vtotal_reg;
321e3adcf8fSFrançois Tigeot 	uint32_t vblank_reg;
322e3adcf8fSFrançois Tigeot 	uint32_t vsync_reg;
323e3adcf8fSFrançois Tigeot 	uint32_t pipeconf_reg;
324e3adcf8fSFrançois Tigeot 	uint32_t pipe_dsl_reg;
325e3adcf8fSFrançois Tigeot 	uint8_t	st00;
326e3adcf8fSFrançois Tigeot 	enum drm_connector_status status;
327e3adcf8fSFrançois Tigeot 
328e3adcf8fSFrançois Tigeot 	DRM_DEBUG_KMS("starting load-detect on CRT\n");
329e3adcf8fSFrançois Tigeot 
330e3adcf8fSFrançois Tigeot 	bclrpat_reg = BCLRPAT(pipe);
331e3adcf8fSFrançois Tigeot 	vtotal_reg = VTOTAL(pipe);
332e3adcf8fSFrançois Tigeot 	vblank_reg = VBLANK(pipe);
333e3adcf8fSFrançois Tigeot 	vsync_reg = VSYNC(pipe);
334e3adcf8fSFrançois Tigeot 	pipeconf_reg = PIPECONF(pipe);
335e3adcf8fSFrançois Tigeot 	pipe_dsl_reg = PIPEDSL(pipe);
336e3adcf8fSFrançois Tigeot 
337e3adcf8fSFrançois Tigeot 	save_bclrpat = I915_READ(bclrpat_reg);
338e3adcf8fSFrançois Tigeot 	save_vtotal = I915_READ(vtotal_reg);
339e3adcf8fSFrançois Tigeot 	vblank = I915_READ(vblank_reg);
340e3adcf8fSFrançois Tigeot 
341e3adcf8fSFrançois Tigeot 	vtotal = ((save_vtotal >> 16) & 0xfff) + 1;
342e3adcf8fSFrançois Tigeot 	vactive = (save_vtotal & 0x7ff) + 1;
343e3adcf8fSFrançois Tigeot 
344e3adcf8fSFrançois Tigeot 	vblank_start = (vblank & 0xfff) + 1;
345e3adcf8fSFrançois Tigeot 	vblank_end = ((vblank >> 16) & 0xfff) + 1;
346e3adcf8fSFrançois Tigeot 
347e3adcf8fSFrançois Tigeot 	/* Set the border color to purple. */
348e3adcf8fSFrançois Tigeot 	I915_WRITE(bclrpat_reg, 0x500050);
349e3adcf8fSFrançois Tigeot 
350e3adcf8fSFrançois Tigeot 	if (!IS_GEN2(dev)) {
351e3adcf8fSFrançois Tigeot 		uint32_t pipeconf = I915_READ(pipeconf_reg);
352e3adcf8fSFrançois Tigeot 		I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER);
353e3adcf8fSFrançois Tigeot 		POSTING_READ(pipeconf_reg);
354e3adcf8fSFrançois Tigeot 		/* Wait for next Vblank to substitue
355e3adcf8fSFrançois Tigeot 		 * border color for Color info */
356e3adcf8fSFrançois Tigeot 		intel_wait_for_vblank(dev, pipe);
357e3adcf8fSFrançois Tigeot 		st00 = I915_READ8(VGA_MSR_WRITE);
358e3adcf8fSFrançois Tigeot 		status = ((st00 & (1 << 4)) != 0) ?
359e3adcf8fSFrançois Tigeot 			connector_status_connected :
360e3adcf8fSFrançois Tigeot 			connector_status_disconnected;
361e3adcf8fSFrançois Tigeot 
362e3adcf8fSFrançois Tigeot 		I915_WRITE(pipeconf_reg, pipeconf);
363e3adcf8fSFrançois Tigeot 	} else {
364e3adcf8fSFrançois Tigeot 		bool restore_vblank = false;
365e3adcf8fSFrançois Tigeot 		int count, detect;
366e3adcf8fSFrançois Tigeot 
367e3adcf8fSFrançois Tigeot 		/*
368e3adcf8fSFrançois Tigeot 		* If there isn't any border, add some.
369e3adcf8fSFrançois Tigeot 		* Yes, this will flicker
370e3adcf8fSFrançois Tigeot 		*/
371e3adcf8fSFrançois Tigeot 		if (vblank_start <= vactive && vblank_end >= vtotal) {
372e3adcf8fSFrançois Tigeot 			uint32_t vsync = I915_READ(vsync_reg);
373e3adcf8fSFrançois Tigeot 			uint32_t vsync_start = (vsync & 0xffff) + 1;
374e3adcf8fSFrançois Tigeot 
375e3adcf8fSFrançois Tigeot 			vblank_start = vsync_start;
376e3adcf8fSFrançois Tigeot 			I915_WRITE(vblank_reg,
377e3adcf8fSFrançois Tigeot 				   (vblank_start - 1) |
378e3adcf8fSFrançois Tigeot 				   ((vblank_end - 1) << 16));
379e3adcf8fSFrançois Tigeot 			restore_vblank = true;
380e3adcf8fSFrançois Tigeot 		}
381e3adcf8fSFrançois Tigeot 		/* sample in the vertical border, selecting the larger one */
382e3adcf8fSFrançois Tigeot 		if (vblank_start - vactive >= vtotal - vblank_end)
383e3adcf8fSFrançois Tigeot 			vsample = (vblank_start + vactive) >> 1;
384e3adcf8fSFrançois Tigeot 		else
385e3adcf8fSFrançois Tigeot 			vsample = (vtotal + vblank_end) >> 1;
386e3adcf8fSFrançois Tigeot 
387e3adcf8fSFrançois Tigeot 		/*
388e3adcf8fSFrançois Tigeot 		 * Wait for the border to be displayed
389e3adcf8fSFrançois Tigeot 		 */
390e3adcf8fSFrançois Tigeot 		while (I915_READ(pipe_dsl_reg) >= vactive)
391e3adcf8fSFrançois Tigeot 			;
392e3adcf8fSFrançois Tigeot 		while ((dsl = I915_READ(pipe_dsl_reg)) <= vsample)
393e3adcf8fSFrançois Tigeot 			;
394e3adcf8fSFrançois Tigeot 		/*
395e3adcf8fSFrançois Tigeot 		 * Watch ST00 for an entire scanline
396e3adcf8fSFrançois Tigeot 		 */
397e3adcf8fSFrançois Tigeot 		detect = 0;
398e3adcf8fSFrançois Tigeot 		count = 0;
399e3adcf8fSFrançois Tigeot 		do {
400e3adcf8fSFrançois Tigeot 			count++;
401e3adcf8fSFrançois Tigeot 			/* Read the ST00 VGA status register */
402e3adcf8fSFrançois Tigeot 			st00 = I915_READ8(VGA_MSR_WRITE);
403e3adcf8fSFrançois Tigeot 			if (st00 & (1 << 4))
404e3adcf8fSFrançois Tigeot 				detect++;
405e3adcf8fSFrançois Tigeot 		} while ((I915_READ(pipe_dsl_reg) == dsl));
406e3adcf8fSFrançois Tigeot 
407e3adcf8fSFrançois Tigeot 		/* restore vblank if necessary */
408e3adcf8fSFrançois Tigeot 		if (restore_vblank)
409e3adcf8fSFrançois Tigeot 			I915_WRITE(vblank_reg, vblank);
410e3adcf8fSFrançois Tigeot 		/*
411e3adcf8fSFrançois Tigeot 		 * If more than 3/4 of the scanline detected a monitor,
412e3adcf8fSFrançois Tigeot 		 * then it is assumed to be present. This works even on i830,
413e3adcf8fSFrançois Tigeot 		 * where there isn't any way to force the border color across
414e3adcf8fSFrançois Tigeot 		 * the screen
415e3adcf8fSFrançois Tigeot 		 */
416e3adcf8fSFrançois Tigeot 		status = detect * 4 > count * 3 ?
417e3adcf8fSFrançois Tigeot 			 connector_status_connected :
418e3adcf8fSFrançois Tigeot 			 connector_status_disconnected;
419e3adcf8fSFrançois Tigeot 	}
420e3adcf8fSFrançois Tigeot 
421e3adcf8fSFrançois Tigeot 	/* Restore previous settings */
422e3adcf8fSFrançois Tigeot 	I915_WRITE(bclrpat_reg, save_bclrpat);
423e3adcf8fSFrançois Tigeot 
424e3adcf8fSFrançois Tigeot 	return status;
425e3adcf8fSFrançois Tigeot }
426e3adcf8fSFrançois Tigeot 
427e3adcf8fSFrançois Tigeot static enum drm_connector_status
428e3adcf8fSFrançois Tigeot intel_crt_detect(struct drm_connector *connector, bool force)
429e3adcf8fSFrançois Tigeot {
430e3adcf8fSFrançois Tigeot 	struct drm_device *dev = connector->dev;
431e3adcf8fSFrançois Tigeot 	struct intel_crt *crt = intel_attached_crt(connector);
432e3adcf8fSFrançois Tigeot 	enum drm_connector_status status;
433e3adcf8fSFrançois Tigeot 	struct intel_load_detect_pipe tmp;
434e3adcf8fSFrançois Tigeot 
435e3adcf8fSFrançois Tigeot 	if (I915_HAS_HOTPLUG(dev)) {
436e3adcf8fSFrançois Tigeot 		if (intel_crt_detect_hotplug(connector)) {
437e3adcf8fSFrançois Tigeot 			DRM_DEBUG_KMS("CRT detected via hotplug\n");
438e3adcf8fSFrançois Tigeot 			return connector_status_connected;
439e3adcf8fSFrançois Tigeot 		} else {
440e3adcf8fSFrançois Tigeot 			DRM_DEBUG_KMS("CRT not detected via hotplug\n");
441e3adcf8fSFrançois Tigeot 			return connector_status_disconnected;
442e3adcf8fSFrançois Tigeot 		}
443e3adcf8fSFrançois Tigeot 	}
444e3adcf8fSFrançois Tigeot 
445e3adcf8fSFrançois Tigeot 	if (intel_crt_detect_ddc(connector))
446e3adcf8fSFrançois Tigeot 		return connector_status_connected;
447e3adcf8fSFrançois Tigeot 
448e3adcf8fSFrançois Tigeot 	if (!force)
449e3adcf8fSFrançois Tigeot 		return connector->status;
450e3adcf8fSFrançois Tigeot 
451e3adcf8fSFrançois Tigeot 	/* for pre-945g platforms use load detect */
452e3adcf8fSFrançois Tigeot 	if (intel_get_load_detect_pipe(&crt->base, connector, NULL,
453e3adcf8fSFrançois Tigeot 				       &tmp)) {
454e3adcf8fSFrançois Tigeot 		if (intel_crt_detect_ddc(connector))
455e3adcf8fSFrançois Tigeot 			status = connector_status_connected;
456e3adcf8fSFrançois Tigeot 		else
457e3adcf8fSFrançois Tigeot 			status = intel_crt_load_detect(crt);
458e3adcf8fSFrançois Tigeot 		intel_release_load_detect_pipe(&crt->base, connector,
459e3adcf8fSFrançois Tigeot 					       &tmp);
460e3adcf8fSFrançois Tigeot 	} else
461e3adcf8fSFrançois Tigeot 		status = connector_status_unknown;
462e3adcf8fSFrançois Tigeot 
463e3adcf8fSFrançois Tigeot 	return status;
464e3adcf8fSFrançois Tigeot }
465e3adcf8fSFrançois Tigeot 
466e3adcf8fSFrançois Tigeot static void intel_crt_destroy(struct drm_connector *connector)
467e3adcf8fSFrançois Tigeot {
468e3adcf8fSFrançois Tigeot 
469e3adcf8fSFrançois Tigeot #if 0
470e3adcf8fSFrançois Tigeot 	drm_sysfs_connector_remove(connector);
471e3adcf8fSFrançois Tigeot #endif
472e3adcf8fSFrançois Tigeot 	drm_connector_cleanup(connector);
473e3adcf8fSFrançois Tigeot 	drm_free(connector, DRM_MEM_KMS);
474e3adcf8fSFrançois Tigeot }
475e3adcf8fSFrançois Tigeot 
476e3adcf8fSFrançois Tigeot static int intel_crt_get_modes(struct drm_connector *connector)
477e3adcf8fSFrançois Tigeot {
478e3adcf8fSFrançois Tigeot 	struct drm_device *dev = connector->dev;
479e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
480e3adcf8fSFrançois Tigeot 	int ret;
481e3adcf8fSFrançois Tigeot 
482e3adcf8fSFrançois Tigeot 	ret = intel_ddc_get_modes(connector,
483e3adcf8fSFrançois Tigeot 	    dev_priv->gmbus[dev_priv->crt_ddc_pin]);
484e3adcf8fSFrançois Tigeot 	if (ret || !IS_G4X(dev))
485e3adcf8fSFrançois Tigeot 		return ret;
486e3adcf8fSFrançois Tigeot 
487e3adcf8fSFrançois Tigeot 	/* Try to probe digital port for output in DVI-I -> VGA mode. */
488e3adcf8fSFrançois Tigeot 	return (intel_ddc_get_modes(connector,
489e3adcf8fSFrançois Tigeot 	    dev_priv->gmbus[GMBUS_PORT_DPB]));
490e3adcf8fSFrançois Tigeot }
491e3adcf8fSFrançois Tigeot 
492e3adcf8fSFrançois Tigeot static int intel_crt_set_property(struct drm_connector *connector,
493e3adcf8fSFrançois Tigeot 				  struct drm_property *property,
494e3adcf8fSFrançois Tigeot 				  uint64_t value)
495e3adcf8fSFrançois Tigeot {
496e3adcf8fSFrançois Tigeot 	return 0;
497e3adcf8fSFrançois Tigeot }
498e3adcf8fSFrançois Tigeot 
499e3adcf8fSFrançois Tigeot static void intel_crt_reset(struct drm_connector *connector)
500e3adcf8fSFrançois Tigeot {
501e3adcf8fSFrançois Tigeot 	struct drm_device *dev = connector->dev;
502e3adcf8fSFrançois Tigeot 	struct intel_crt *crt = intel_attached_crt(connector);
503e3adcf8fSFrançois Tigeot 
504e3adcf8fSFrançois Tigeot 	if (HAS_PCH_SPLIT(dev))
505e3adcf8fSFrançois Tigeot 		crt->force_hotplug_required = 1;
506e3adcf8fSFrançois Tigeot }
507e3adcf8fSFrançois Tigeot 
508e3adcf8fSFrançois Tigeot /*
509e3adcf8fSFrançois Tigeot  * Routines for controlling stuff on the analog port
510e3adcf8fSFrançois Tigeot  */
511e3adcf8fSFrançois Tigeot 
512e3adcf8fSFrançois Tigeot static const struct drm_encoder_helper_funcs intel_crt_helper_funcs = {
513e3adcf8fSFrançois Tigeot 	.dpms = intel_crt_dpms,
514e3adcf8fSFrançois Tigeot 	.mode_fixup = intel_crt_mode_fixup,
515e3adcf8fSFrançois Tigeot 	.prepare = intel_encoder_prepare,
516e3adcf8fSFrançois Tigeot 	.commit = intel_encoder_commit,
517e3adcf8fSFrançois Tigeot 	.mode_set = intel_crt_mode_set,
518e3adcf8fSFrançois Tigeot };
519e3adcf8fSFrançois Tigeot 
520e3adcf8fSFrançois Tigeot static const struct drm_connector_funcs intel_crt_connector_funcs = {
521e3adcf8fSFrançois Tigeot 	.reset = intel_crt_reset,
522e3adcf8fSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
523e3adcf8fSFrançois Tigeot 	.detect = intel_crt_detect,
524e3adcf8fSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
525e3adcf8fSFrançois Tigeot 	.destroy = intel_crt_destroy,
526e3adcf8fSFrançois Tigeot 	.set_property = intel_crt_set_property,
527e3adcf8fSFrançois Tigeot };
528e3adcf8fSFrançois Tigeot 
529e3adcf8fSFrançois Tigeot static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = {
530e3adcf8fSFrançois Tigeot 	.mode_valid = intel_crt_mode_valid,
531e3adcf8fSFrançois Tigeot 	.get_modes = intel_crt_get_modes,
532e3adcf8fSFrançois Tigeot 	.best_encoder = intel_best_encoder,
533e3adcf8fSFrançois Tigeot };
534e3adcf8fSFrançois Tigeot 
535e3adcf8fSFrançois Tigeot static const struct drm_encoder_funcs intel_crt_enc_funcs = {
536e3adcf8fSFrançois Tigeot 	.destroy = intel_encoder_destroy,
537e3adcf8fSFrançois Tigeot };
538e3adcf8fSFrançois Tigeot 
539e3adcf8fSFrançois Tigeot static int intel_no_crt_dmi_callback(const struct dmi_system_id *id)
540e3adcf8fSFrançois Tigeot {
541e3adcf8fSFrançois Tigeot 	DRM_DEBUG_KMS("Skipping CRT initialization for %s\n", id->ident);
542e3adcf8fSFrançois Tigeot 	return 1;
543e3adcf8fSFrançois Tigeot }
544e3adcf8fSFrançois Tigeot 
545e3adcf8fSFrançois Tigeot static const struct dmi_system_id intel_no_crt[] = {
546e3adcf8fSFrançois Tigeot 	{
547e3adcf8fSFrançois Tigeot 		.callback = intel_no_crt_dmi_callback,
548e3adcf8fSFrançois Tigeot 		.ident = "ACER ZGB",
549e3adcf8fSFrançois Tigeot 		.matches = {
550e3adcf8fSFrançois Tigeot 			DMI_MATCH(DMI_SYS_VENDOR, "ACER"),
551e3adcf8fSFrançois Tigeot 			DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
552e3adcf8fSFrançois Tigeot 		},
553e3adcf8fSFrançois Tigeot 	},
554e3adcf8fSFrançois Tigeot 	{ }
555e3adcf8fSFrançois Tigeot };
556e3adcf8fSFrançois Tigeot 
557e3adcf8fSFrançois Tigeot void intel_crt_init(struct drm_device *dev)
558e3adcf8fSFrançois Tigeot {
559e3adcf8fSFrançois Tigeot 	struct drm_connector *connector;
560e3adcf8fSFrançois Tigeot 	struct intel_crt *crt;
561e3adcf8fSFrançois Tigeot 	struct intel_connector *intel_connector;
562e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
563e3adcf8fSFrançois Tigeot 
564e3adcf8fSFrançois Tigeot 	/* Skip machines without VGA that falsely report hotplug events */
565e3adcf8fSFrançois Tigeot 	if (dmi_check_system(intel_no_crt))
566e3adcf8fSFrançois Tigeot 		return;
567e3adcf8fSFrançois Tigeot 
568e3adcf8fSFrançois Tigeot 	crt = kmalloc(sizeof(struct intel_crt), DRM_MEM_KMS, M_WAITOK | M_ZERO);
569e3adcf8fSFrançois Tigeot 	intel_connector = kmalloc(sizeof(struct intel_connector), DRM_MEM_KMS,
570e3adcf8fSFrançois Tigeot 	    M_WAITOK | M_ZERO);
571e3adcf8fSFrançois Tigeot 
572e3adcf8fSFrançois Tigeot 	connector = &intel_connector->base;
573e3adcf8fSFrançois Tigeot 	drm_connector_init(dev, &intel_connector->base,
574e3adcf8fSFrançois Tigeot 			   &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
575e3adcf8fSFrançois Tigeot 
576e3adcf8fSFrançois Tigeot 	drm_encoder_init(dev, &crt->base.base, &intel_crt_enc_funcs,
577e3adcf8fSFrançois Tigeot 			 DRM_MODE_ENCODER_DAC);
578e3adcf8fSFrançois Tigeot 
579e3adcf8fSFrançois Tigeot 	intel_connector_attach_encoder(intel_connector, &crt->base);
580e3adcf8fSFrançois Tigeot 
581e3adcf8fSFrançois Tigeot 	crt->base.type = INTEL_OUTPUT_ANALOG;
582e3adcf8fSFrançois Tigeot 	crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT |
583e3adcf8fSFrançois Tigeot 				1 << INTEL_ANALOG_CLONE_BIT |
584e3adcf8fSFrançois Tigeot 				1 << INTEL_SDVO_LVDS_CLONE_BIT);
585e3adcf8fSFrançois Tigeot 	crt->base.crtc_mask = (1 << 0) | (1 << 1);
586e3adcf8fSFrançois Tigeot 	if (IS_GEN2(dev))
587e3adcf8fSFrançois Tigeot 		connector->interlace_allowed = 0;
588e3adcf8fSFrançois Tigeot 	else
589e3adcf8fSFrançois Tigeot 		connector->interlace_allowed = 1;
590e3adcf8fSFrançois Tigeot 	connector->doublescan_allowed = 0;
591e3adcf8fSFrançois Tigeot 
592e3adcf8fSFrançois Tigeot 	drm_encoder_helper_add(&crt->base.base, &intel_crt_helper_funcs);
593e3adcf8fSFrançois Tigeot 	drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
594e3adcf8fSFrançois Tigeot 
595e3adcf8fSFrançois Tigeot #if 0
596e3adcf8fSFrançois Tigeot 	drm_sysfs_connector_add(connector);
597e3adcf8fSFrançois Tigeot #endif
598e3adcf8fSFrançois Tigeot 
599e3adcf8fSFrançois Tigeot 	if (I915_HAS_HOTPLUG(dev))
600e3adcf8fSFrançois Tigeot 		connector->polled = DRM_CONNECTOR_POLL_HPD;
601e3adcf8fSFrançois Tigeot 	else
602e3adcf8fSFrançois Tigeot 		connector->polled = DRM_CONNECTOR_POLL_CONNECT;
603e3adcf8fSFrançois Tigeot 
604e3adcf8fSFrançois Tigeot 	/*
605e3adcf8fSFrançois Tigeot 	 * Configure the automatic hotplug detection stuff
606e3adcf8fSFrançois Tigeot 	 */
607e3adcf8fSFrançois Tigeot 	crt->force_hotplug_required = 0;
608e3adcf8fSFrançois Tigeot 	if (HAS_PCH_SPLIT(dev)) {
609e3adcf8fSFrançois Tigeot 		u32 adpa;
610e3adcf8fSFrançois Tigeot 
611e3adcf8fSFrançois Tigeot 		adpa = I915_READ(PCH_ADPA);
612e3adcf8fSFrançois Tigeot 		adpa &= ~ADPA_CRT_HOTPLUG_MASK;
613e3adcf8fSFrançois Tigeot 		adpa |= ADPA_HOTPLUG_BITS;
614e3adcf8fSFrançois Tigeot 		I915_WRITE(PCH_ADPA, adpa);
615e3adcf8fSFrançois Tigeot 		POSTING_READ(PCH_ADPA);
616e3adcf8fSFrançois Tigeot 
617e3adcf8fSFrançois Tigeot 		DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa);
618e3adcf8fSFrançois Tigeot 		crt->force_hotplug_required = 1;
619e3adcf8fSFrançois Tigeot 	}
620e3adcf8fSFrançois Tigeot 
621e3adcf8fSFrançois Tigeot 	dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
622e3adcf8fSFrançois Tigeot }
623