1235783Skib/*
2235783Skib * Copyright �� 2006-2007 Intel Corporation
3235783Skib *
4235783Skib * Permission is hereby granted, free of charge, to any person obtaining a
5235783Skib * copy of this software and associated documentation files (the "Software"),
6235783Skib * to deal in the Software without restriction, including without limitation
7235783Skib * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8235783Skib * and/or sell copies of the Software, and to permit persons to whom the
9235783Skib * Software is furnished to do so, subject to the following conditions:
10235783Skib *
11235783Skib * The above copyright notice and this permission notice (including the next
12235783Skib * paragraph) shall be included in all copies or substantial portions of the
13235783Skib * Software.
14235783Skib *
15235783Skib * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16235783Skib * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17235783Skib * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18235783Skib * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19235783Skib * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20235783Skib * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21235783Skib * DEALINGS IN THE SOFTWARE.
22235783Skib *
23235783Skib * Authors:
24235783Skib *	Eric Anholt <eric@anholt.net>
25235783Skib */
26235783Skib
27235783Skib#include <sys/cdefs.h>
28235783Skib__FBSDID("$FreeBSD$");
29235783Skib
30235783Skib#include <dev/drm2/drmP.h>
31235783Skib#include <dev/drm2/drm.h>
32235783Skib#include <dev/drm2/drm_crtc.h>
33235783Skib#include <dev/drm2/drm_crtc_helper.h>
34235783Skib#include <dev/drm2/drm_edid.h>
35235783Skib#include <dev/drm2/i915/i915_drm.h>
36235783Skib#include <dev/drm2/i915/i915_drv.h>
37235783Skib#include <dev/drm2/i915/intel_drv.h>
38235783Skib
39235783Skib/* Here's the desired hotplug mode */
40235783Skib#define ADPA_HOTPLUG_BITS (ADPA_CRT_HOTPLUG_PERIOD_128 |		\
41235783Skib			   ADPA_CRT_HOTPLUG_WARMUP_10MS |		\
42235783Skib			   ADPA_CRT_HOTPLUG_SAMPLE_4S |			\
43235783Skib			   ADPA_CRT_HOTPLUG_VOLTAGE_50 |		\
44235783Skib			   ADPA_CRT_HOTPLUG_VOLREF_325MV |		\
45235783Skib			   ADPA_CRT_HOTPLUG_ENABLE)
46235783Skib
47235783Skibstruct intel_crt {
48235783Skib	struct intel_encoder base;
49235783Skib	bool force_hotplug_required;
50235783Skib};
51235783Skib
52235783Skibstatic struct intel_crt *intel_attached_crt(struct drm_connector *connector)
53235783Skib{
54235783Skib	return container_of(intel_attached_encoder(connector),
55235783Skib			    struct intel_crt, base);
56235783Skib}
57235783Skib
58235783Skibstatic void intel_crt_dpms(struct drm_encoder *encoder, int mode)
59235783Skib{
60235783Skib	struct drm_device *dev = encoder->dev;
61235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
62235783Skib	u32 temp, reg;
63235783Skib
64235783Skib	if (HAS_PCH_SPLIT(dev))
65235783Skib		reg = PCH_ADPA;
66235783Skib	else
67235783Skib		reg = ADPA;
68235783Skib
69235783Skib	temp = I915_READ(reg);
70235783Skib	temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
71235783Skib	temp &= ~ADPA_DAC_ENABLE;
72235783Skib
73235783Skib	switch (mode) {
74235783Skib	case DRM_MODE_DPMS_ON:
75235783Skib		temp |= ADPA_DAC_ENABLE;
76235783Skib		break;
77235783Skib	case DRM_MODE_DPMS_STANDBY:
78235783Skib		temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE;
79235783Skib		break;
80235783Skib	case DRM_MODE_DPMS_SUSPEND:
81235783Skib		temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE;
82235783Skib		break;
83235783Skib	case DRM_MODE_DPMS_OFF:
84235783Skib		temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE;
85235783Skib		break;
86235783Skib	}
87235783Skib
88235783Skib	I915_WRITE(reg, temp);
89235783Skib}
90235783Skib
91235783Skibstatic int intel_crt_mode_valid(struct drm_connector *connector,
92235783Skib				struct drm_display_mode *mode)
93235783Skib{
94235783Skib	struct drm_device *dev = connector->dev;
95235783Skib
96235783Skib	int max_clock = 0;
97235783Skib	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
98235783Skib		return MODE_NO_DBLESCAN;
99235783Skib
100235783Skib	if (mode->clock < 25000)
101235783Skib		return MODE_CLOCK_LOW;
102235783Skib
103235783Skib	if (IS_GEN2(dev))
104235783Skib		max_clock = 350000;
105235783Skib	else
106235783Skib		max_clock = 400000;
107235783Skib	if (mode->clock > max_clock)
108235783Skib		return MODE_CLOCK_HIGH;
109235783Skib
110235783Skib	return MODE_OK;
111235783Skib}
112235783Skib
113235783Skibstatic bool intel_crt_mode_fixup(struct drm_encoder *encoder,
114261631Sdumbbell				 const struct drm_display_mode *mode,
115235783Skib				 struct drm_display_mode *adjusted_mode)
116235783Skib{
117235783Skib	return true;
118235783Skib}
119235783Skib
120235783Skibstatic void intel_crt_mode_set(struct drm_encoder *encoder,
121235783Skib			       struct drm_display_mode *mode,
122235783Skib			       struct drm_display_mode *adjusted_mode)
123235783Skib{
124235783Skib
125235783Skib	struct drm_device *dev = encoder->dev;
126235783Skib	struct drm_crtc *crtc = encoder->crtc;
127235783Skib	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
128235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
129235783Skib	int dpll_md_reg;
130235783Skib	u32 adpa, dpll_md;
131235783Skib	u32 adpa_reg;
132235783Skib
133235783Skib	dpll_md_reg = DPLL_MD(intel_crtc->pipe);
134235783Skib
135235783Skib	if (HAS_PCH_SPLIT(dev))
136235783Skib		adpa_reg = PCH_ADPA;
137235783Skib	else
138235783Skib		adpa_reg = ADPA;
139235783Skib
140235783Skib	/*
141235783Skib	 * Disable separate mode multiplier used when cloning SDVO to CRT
142235783Skib	 * XXX this needs to be adjusted when we really are cloning
143235783Skib	 */
144235783Skib	if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
145235783Skib		dpll_md = I915_READ(dpll_md_reg);
146235783Skib		I915_WRITE(dpll_md_reg,
147235783Skib			   dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
148235783Skib	}
149235783Skib
150235783Skib	adpa = ADPA_HOTPLUG_BITS;
151235783Skib	if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
152235783Skib		adpa |= ADPA_HSYNC_ACTIVE_HIGH;
153235783Skib	if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
154235783Skib		adpa |= ADPA_VSYNC_ACTIVE_HIGH;
155235783Skib
156235783Skib	/* For CPT allow 3 pipe config, for others just use A or B */
157235783Skib	if (HAS_PCH_CPT(dev))
158235783Skib		adpa |= PORT_TRANS_SEL_CPT(intel_crtc->pipe);
159235783Skib	else if (intel_crtc->pipe == 0)
160235783Skib		adpa |= ADPA_PIPE_A_SELECT;
161235783Skib	else
162235783Skib		adpa |= ADPA_PIPE_B_SELECT;
163235783Skib
164235783Skib	if (!HAS_PCH_SPLIT(dev))
165235783Skib		I915_WRITE(BCLRPAT(intel_crtc->pipe), 0);
166235783Skib
167235783Skib	I915_WRITE(adpa_reg, adpa);
168235783Skib}
169235783Skib
170235783Skibstatic bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
171235783Skib{
172235783Skib	struct drm_device *dev = connector->dev;
173235783Skib	struct intel_crt *crt = intel_attached_crt(connector);
174235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
175235783Skib	u32 adpa;
176235783Skib	bool ret;
177235783Skib
178235783Skib	/* The first time through, trigger an explicit detection cycle */
179235783Skib	if (crt->force_hotplug_required) {
180235783Skib		bool turn_off_dac = HAS_PCH_SPLIT(dev);
181235783Skib		u32 save_adpa;
182235783Skib
183235783Skib		crt->force_hotplug_required = 0;
184235783Skib
185235783Skib		save_adpa = adpa = I915_READ(PCH_ADPA);
186235783Skib		DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);
187235783Skib
188235783Skib		adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER;
189235783Skib		if (turn_off_dac)
190235783Skib			adpa &= ~ADPA_DAC_ENABLE;
191235783Skib
192235783Skib		I915_WRITE(PCH_ADPA, adpa);
193235783Skib
194235783Skib		if (_intel_wait_for(dev,
195235783Skib		    (I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
196235783Skib		    1000, 1, "915crt"))
197235783Skib			DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER\n");
198235783Skib
199235783Skib		if (turn_off_dac) {
200235783Skib			I915_WRITE(PCH_ADPA, save_adpa);
201235783Skib			POSTING_READ(PCH_ADPA);
202235783Skib		}
203235783Skib	}
204235783Skib
205235783Skib	/* Check the status to see if both blue and green are on now */
206235783Skib	adpa = I915_READ(PCH_ADPA);
207235783Skib	if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0)
208235783Skib		ret = true;
209235783Skib	else
210235783Skib		ret = false;
211235783Skib	DRM_DEBUG_KMS("ironlake hotplug adpa=0x%x, result %d\n", adpa, ret);
212235783Skib
213235783Skib	return ret;
214235783Skib}
215235783Skib
216235783Skib/**
217235783Skib * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence.
218235783Skib *
219235783Skib * Not for i915G/i915GM
220235783Skib *
221235783Skib * \return true if CRT is connected.
222235783Skib * \return false if CRT is disconnected.
223235783Skib */
224235783Skibstatic bool intel_crt_detect_hotplug(struct drm_connector *connector)
225235783Skib{
226235783Skib	struct drm_device *dev = connector->dev;
227235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
228235783Skib	u32 hotplug_en, orig, stat;
229235783Skib	bool ret = false;
230235783Skib	int i, tries = 0;
231235783Skib
232235783Skib	if (HAS_PCH_SPLIT(dev))
233235783Skib		return intel_ironlake_crt_detect_hotplug(connector);
234235783Skib
235235783Skib	/*
236235783Skib	 * On 4 series desktop, CRT detect sequence need to be done twice
237235783Skib	 * to get a reliable result.
238235783Skib	 */
239235783Skib
240235783Skib	if (IS_G4X(dev) && !IS_GM45(dev))
241235783Skib		tries = 2;
242235783Skib	else
243235783Skib		tries = 1;
244235783Skib	hotplug_en = orig = I915_READ(PORT_HOTPLUG_EN);
245235783Skib	hotplug_en |= CRT_HOTPLUG_FORCE_DETECT;
246235783Skib
247235783Skib	for (i = 0; i < tries ; i++) {
248235783Skib		/* turn on the FORCE_DETECT */
249235783Skib		I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
250235783Skib		/* wait for FORCE_DETECT to go off */
251235783Skib		if (_intel_wait_for(dev,
252235783Skib		    (I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT) == 0,
253235783Skib		    1000, 1, "915cr2"))
254235783Skib			DRM_DEBUG_KMS("timed out waiting for FORCE_DETECT to go off");
255235783Skib	}
256235783Skib
257235783Skib	stat = I915_READ(PORT_HOTPLUG_STAT);
258235783Skib	if ((stat & CRT_HOTPLUG_MONITOR_MASK) != CRT_HOTPLUG_MONITOR_NONE)
259235783Skib		ret = true;
260235783Skib
261235783Skib	/* clear the interrupt we just generated, if any */
262235783Skib	I915_WRITE(PORT_HOTPLUG_STAT, CRT_HOTPLUG_INT_STATUS);
263235783Skib
264235783Skib	/* and put the bits back */
265235783Skib	I915_WRITE(PORT_HOTPLUG_EN, orig);
266235783Skib
267235783Skib	return ret;
268235783Skib}
269235783Skib
270235783Skibstatic bool intel_crt_detect_ddc(struct drm_connector *connector)
271235783Skib{
272235783Skib	struct intel_crt *crt = intel_attached_crt(connector);
273235783Skib	struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private;
274235783Skib
275235783Skib	/* CRT should always be at 0, but check anyway */
276235783Skib	if (crt->base.type != INTEL_OUTPUT_ANALOG)
277235783Skib		return false;
278235783Skib
279235783Skib	if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) {
280235783Skib		struct edid *edid;
281235783Skib		bool is_digital = false;
282235783Skib
283235783Skib		edid = drm_get_edid(connector,
284235783Skib		    dev_priv->gmbus[dev_priv->crt_ddc_pin]);
285235783Skib		/*
286235783Skib		 * This may be a DVI-I connector with a shared DDC
287235783Skib		 * link between analog and digital outputs, so we
288235783Skib		 * have to check the EDID input spec of the attached device.
289235783Skib		 *
290235783Skib		 * On the other hand, what should we do if it is a broken EDID?
291235783Skib		 */
292235783Skib		if (edid != NULL) {
293235783Skib			is_digital = edid->input & DRM_EDID_INPUT_DIGITAL;
294235783Skib			connector->display_info.raw_edid = NULL;
295235783Skib			free(edid, DRM_MEM_KMS);
296235783Skib		}
297235783Skib
298235783Skib		if (!is_digital) {
299235783Skib			DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
300235783Skib			return true;
301235783Skib		} else {
302235783Skib			DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n");
303235783Skib		}
304235783Skib	}
305235783Skib
306235783Skib	return false;
307235783Skib}
308235783Skib
309235783Skibstatic enum drm_connector_status
310235783Skibintel_crt_load_detect(struct intel_crt *crt)
311235783Skib{
312235783Skib	struct drm_device *dev = crt->base.base.dev;
313235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
314235783Skib	uint32_t pipe = to_intel_crtc(crt->base.base.crtc)->pipe;
315235783Skib	uint32_t save_bclrpat;
316235783Skib	uint32_t save_vtotal;
317235783Skib	uint32_t vtotal, vactive;
318235783Skib	uint32_t vsample;
319235783Skib	uint32_t vblank, vblank_start, vblank_end;
320235783Skib	uint32_t dsl;
321235783Skib	uint32_t bclrpat_reg;
322235783Skib	uint32_t vtotal_reg;
323235783Skib	uint32_t vblank_reg;
324235783Skib	uint32_t vsync_reg;
325235783Skib	uint32_t pipeconf_reg;
326235783Skib	uint32_t pipe_dsl_reg;
327235783Skib	uint8_t	st00;
328235783Skib	enum drm_connector_status status;
329235783Skib
330235783Skib	DRM_DEBUG_KMS("starting load-detect on CRT\n");
331235783Skib
332235783Skib	bclrpat_reg = BCLRPAT(pipe);
333235783Skib	vtotal_reg = VTOTAL(pipe);
334235783Skib	vblank_reg = VBLANK(pipe);
335235783Skib	vsync_reg = VSYNC(pipe);
336235783Skib	pipeconf_reg = PIPECONF(pipe);
337235783Skib	pipe_dsl_reg = PIPEDSL(pipe);
338235783Skib
339235783Skib	save_bclrpat = I915_READ(bclrpat_reg);
340235783Skib	save_vtotal = I915_READ(vtotal_reg);
341235783Skib	vblank = I915_READ(vblank_reg);
342235783Skib
343235783Skib	vtotal = ((save_vtotal >> 16) & 0xfff) + 1;
344235783Skib	vactive = (save_vtotal & 0x7ff) + 1;
345235783Skib
346235783Skib	vblank_start = (vblank & 0xfff) + 1;
347235783Skib	vblank_end = ((vblank >> 16) & 0xfff) + 1;
348235783Skib
349235783Skib	/* Set the border color to purple. */
350235783Skib	I915_WRITE(bclrpat_reg, 0x500050);
351235783Skib
352235783Skib	if (!IS_GEN2(dev)) {
353235783Skib		uint32_t pipeconf = I915_READ(pipeconf_reg);
354235783Skib		I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER);
355235783Skib		POSTING_READ(pipeconf_reg);
356235783Skib		/* Wait for next Vblank to substitue
357235783Skib		 * border color for Color info */
358235783Skib		intel_wait_for_vblank(dev, pipe);
359235783Skib		st00 = I915_READ8(VGA_MSR_WRITE);
360235783Skib		status = ((st00 & (1 << 4)) != 0) ?
361235783Skib			connector_status_connected :
362235783Skib			connector_status_disconnected;
363235783Skib
364235783Skib		I915_WRITE(pipeconf_reg, pipeconf);
365235783Skib	} else {
366235783Skib		bool restore_vblank = false;
367235783Skib		int count, detect;
368235783Skib
369235783Skib		/*
370235783Skib		* If there isn't any border, add some.
371235783Skib		* Yes, this will flicker
372235783Skib		*/
373235783Skib		if (vblank_start <= vactive && vblank_end >= vtotal) {
374235783Skib			uint32_t vsync = I915_READ(vsync_reg);
375235783Skib			uint32_t vsync_start = (vsync & 0xffff) + 1;
376235783Skib
377235783Skib			vblank_start = vsync_start;
378235783Skib			I915_WRITE(vblank_reg,
379235783Skib				   (vblank_start - 1) |
380235783Skib				   ((vblank_end - 1) << 16));
381235783Skib			restore_vblank = true;
382235783Skib		}
383235783Skib		/* sample in the vertical border, selecting the larger one */
384235783Skib		if (vblank_start - vactive >= vtotal - vblank_end)
385235783Skib			vsample = (vblank_start + vactive) >> 1;
386235783Skib		else
387235783Skib			vsample = (vtotal + vblank_end) >> 1;
388235783Skib
389235783Skib		/*
390235783Skib		 * Wait for the border to be displayed
391235783Skib		 */
392235783Skib		while (I915_READ(pipe_dsl_reg) >= vactive)
393235783Skib			;
394235783Skib		while ((dsl = I915_READ(pipe_dsl_reg)) <= vsample)
395235783Skib			;
396235783Skib		/*
397235783Skib		 * Watch ST00 for an entire scanline
398235783Skib		 */
399235783Skib		detect = 0;
400235783Skib		count = 0;
401235783Skib		do {
402235783Skib			count++;
403235783Skib			/* Read the ST00 VGA status register */
404235783Skib			st00 = I915_READ8(VGA_MSR_WRITE);
405235783Skib			if (st00 & (1 << 4))
406235783Skib				detect++;
407235783Skib		} while ((I915_READ(pipe_dsl_reg) == dsl));
408235783Skib
409235783Skib		/* restore vblank if necessary */
410235783Skib		if (restore_vblank)
411235783Skib			I915_WRITE(vblank_reg, vblank);
412235783Skib		/*
413235783Skib		 * If more than 3/4 of the scanline detected a monitor,
414235783Skib		 * then it is assumed to be present. This works even on i830,
415235783Skib		 * where there isn't any way to force the border color across
416235783Skib		 * the screen
417235783Skib		 */
418235783Skib		status = detect * 4 > count * 3 ?
419235783Skib			 connector_status_connected :
420235783Skib			 connector_status_disconnected;
421235783Skib	}
422235783Skib
423235783Skib	/* Restore previous settings */
424235783Skib	I915_WRITE(bclrpat_reg, save_bclrpat);
425235783Skib
426235783Skib	return status;
427235783Skib}
428235783Skib
429235783Skibstatic enum drm_connector_status
430235783Skibintel_crt_detect(struct drm_connector *connector, bool force)
431235783Skib{
432235783Skib	struct drm_device *dev = connector->dev;
433235783Skib	struct intel_crt *crt = intel_attached_crt(connector);
434235783Skib	enum drm_connector_status status;
435235783Skib	struct intel_load_detect_pipe tmp;
436235783Skib
437235783Skib	if (I915_HAS_HOTPLUG(dev)) {
438235783Skib		if (intel_crt_detect_hotplug(connector)) {
439235783Skib			DRM_DEBUG_KMS("CRT detected via hotplug\n");
440235783Skib			return connector_status_connected;
441235783Skib		} else {
442235783Skib			DRM_DEBUG_KMS("CRT not detected via hotplug\n");
443235783Skib			return connector_status_disconnected;
444235783Skib		}
445235783Skib	}
446235783Skib
447235783Skib	if (intel_crt_detect_ddc(connector))
448235783Skib		return connector_status_connected;
449235783Skib
450235783Skib	if (!force)
451235783Skib		return connector->status;
452235783Skib
453235783Skib	/* for pre-945g platforms use load detect */
454235783Skib	if (intel_get_load_detect_pipe(&crt->base, connector, NULL,
455235783Skib				       &tmp)) {
456235783Skib		if (intel_crt_detect_ddc(connector))
457235783Skib			status = connector_status_connected;
458235783Skib		else
459235783Skib			status = intel_crt_load_detect(crt);
460235783Skib		intel_release_load_detect_pipe(&crt->base, connector,
461235783Skib					       &tmp);
462235783Skib	} else
463235783Skib		status = connector_status_unknown;
464235783Skib
465235783Skib	return status;
466235783Skib}
467235783Skib
468235783Skibstatic void intel_crt_destroy(struct drm_connector *connector)
469235783Skib{
470235783Skib
471235783Skib#if 0
472235783Skib	drm_sysfs_connector_remove(connector);
473235783Skib#endif
474235783Skib	drm_connector_cleanup(connector);
475235783Skib	free(connector, DRM_MEM_KMS);
476235783Skib}
477235783Skib
478235783Skibstatic int intel_crt_get_modes(struct drm_connector *connector)
479235783Skib{
480235783Skib	struct drm_device *dev = connector->dev;
481235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
482235783Skib	int ret;
483235783Skib
484235783Skib	ret = intel_ddc_get_modes(connector,
485235783Skib	    dev_priv->gmbus[dev_priv->crt_ddc_pin]);
486235783Skib	if (ret || !IS_G4X(dev))
487235783Skib		return ret;
488235783Skib
489235783Skib	/* Try to probe digital port for output in DVI-I -> VGA mode. */
490235783Skib	return (intel_ddc_get_modes(connector,
491235783Skib	    dev_priv->gmbus[GMBUS_PORT_DPB]));
492235783Skib}
493235783Skib
494235783Skibstatic int intel_crt_set_property(struct drm_connector *connector,
495235783Skib				  struct drm_property *property,
496235783Skib				  uint64_t value)
497235783Skib{
498235783Skib	return 0;
499235783Skib}
500235783Skib
501235783Skibstatic void intel_crt_reset(struct drm_connector *connector)
502235783Skib{
503235783Skib	struct drm_device *dev = connector->dev;
504235783Skib	struct intel_crt *crt = intel_attached_crt(connector);
505235783Skib
506235783Skib	if (HAS_PCH_SPLIT(dev))
507235783Skib		crt->force_hotplug_required = 1;
508235783Skib}
509235783Skib
510235783Skib/*
511235783Skib * Routines for controlling stuff on the analog port
512235783Skib */
513235783Skib
514235783Skibstatic const struct drm_encoder_helper_funcs intel_crt_helper_funcs = {
515235783Skib	.dpms = intel_crt_dpms,
516235783Skib	.mode_fixup = intel_crt_mode_fixup,
517235783Skib	.prepare = intel_encoder_prepare,
518235783Skib	.commit = intel_encoder_commit,
519235783Skib	.mode_set = intel_crt_mode_set,
520235783Skib};
521235783Skib
522235783Skibstatic const struct drm_connector_funcs intel_crt_connector_funcs = {
523235783Skib	.reset = intel_crt_reset,
524235783Skib	.dpms = drm_helper_connector_dpms,
525235783Skib	.detect = intel_crt_detect,
526235783Skib	.fill_modes = drm_helper_probe_single_connector_modes,
527235783Skib	.destroy = intel_crt_destroy,
528235783Skib	.set_property = intel_crt_set_property,
529235783Skib};
530235783Skib
531235783Skibstatic const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = {
532235783Skib	.mode_valid = intel_crt_mode_valid,
533235783Skib	.get_modes = intel_crt_get_modes,
534235783Skib	.best_encoder = intel_best_encoder,
535235783Skib};
536235783Skib
537235783Skibstatic const struct drm_encoder_funcs intel_crt_enc_funcs = {
538235783Skib	.destroy = intel_encoder_destroy,
539235783Skib};
540235783Skib
541235783Skibstatic int intel_no_crt_dmi_callback(const struct dmi_system_id *id)
542235783Skib{
543235783Skib	DRM_DEBUG_KMS("Skipping CRT initialization for %s\n", id->ident);
544235783Skib	return 1;
545235783Skib}
546235783Skib
547235783Skibstatic const struct dmi_system_id intel_no_crt[] = {
548235783Skib	{
549235783Skib		.callback = intel_no_crt_dmi_callback,
550235783Skib		.ident = "ACER ZGB",
551235783Skib		.matches = {
552235783Skib			DMI_MATCH(DMI_SYS_VENDOR, "ACER"),
553235783Skib			DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
554235783Skib		},
555235783Skib	},
556235783Skib	{ }
557235783Skib};
558235783Skib
559235783Skibvoid intel_crt_init(struct drm_device *dev)
560235783Skib{
561235783Skib	struct drm_connector *connector;
562235783Skib	struct intel_crt *crt;
563235783Skib	struct intel_connector *intel_connector;
564235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
565235783Skib
566235783Skib	/* Skip machines without VGA that falsely report hotplug events */
567235783Skib	if (dmi_check_system(intel_no_crt))
568235783Skib		return;
569235783Skib
570235783Skib	crt = malloc(sizeof(struct intel_crt), DRM_MEM_KMS, M_WAITOK | M_ZERO);
571235783Skib	intel_connector = malloc(sizeof(struct intel_connector), DRM_MEM_KMS,
572235783Skib	    M_WAITOK | M_ZERO);
573235783Skib
574235783Skib	connector = &intel_connector->base;
575235783Skib	drm_connector_init(dev, &intel_connector->base,
576235783Skib			   &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
577235783Skib
578235783Skib	drm_encoder_init(dev, &crt->base.base, &intel_crt_enc_funcs,
579235783Skib			 DRM_MODE_ENCODER_DAC);
580235783Skib
581235783Skib	intel_connector_attach_encoder(intel_connector, &crt->base);
582235783Skib
583235783Skib	crt->base.type = INTEL_OUTPUT_ANALOG;
584235783Skib	crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT |
585235783Skib				1 << INTEL_ANALOG_CLONE_BIT |
586235783Skib				1 << INTEL_SDVO_LVDS_CLONE_BIT);
587235783Skib	crt->base.crtc_mask = (1 << 0) | (1 << 1);
588235783Skib	if (IS_GEN2(dev))
589235783Skib		connector->interlace_allowed = 0;
590235783Skib	else
591235783Skib		connector->interlace_allowed = 1;
592235783Skib	connector->doublescan_allowed = 0;
593235783Skib
594235783Skib	drm_encoder_helper_add(&crt->base.base, &intel_crt_helper_funcs);
595235783Skib	drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
596235783Skib
597235783Skib#if 0
598235783Skib	drm_sysfs_connector_add(connector);
599235783Skib#endif
600235783Skib
601235783Skib	if (I915_HAS_HOTPLUG(dev))
602235783Skib		connector->polled = DRM_CONNECTOR_POLL_HPD;
603235783Skib	else
604235783Skib		connector->polled = DRM_CONNECTOR_POLL_CONNECT;
605235783Skib
606235783Skib	/*
607235783Skib	 * Configure the automatic hotplug detection stuff
608235783Skib	 */
609235783Skib	crt->force_hotplug_required = 0;
610235783Skib	if (HAS_PCH_SPLIT(dev)) {
611235783Skib		u32 adpa;
612235783Skib
613235783Skib		adpa = I915_READ(PCH_ADPA);
614235783Skib		adpa &= ~ADPA_CRT_HOTPLUG_MASK;
615235783Skib		adpa |= ADPA_HOTPLUG_BITS;
616235783Skib		I915_WRITE(PCH_ADPA, adpa);
617235783Skib		POSTING_READ(PCH_ADPA);
618235783Skib
619235783Skib		DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa);
620235783Skib		crt->force_hotplug_required = 1;
621235783Skib	}
622235783Skib
623235783Skib	dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
624235783Skib}
625