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: releng/10.3/sys/dev/drm2/i915/intel_crt.c 282199 2015-04-28 19:35:05Z dumbbell $");
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
58280369Skibstatic void pch_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;
62280369Skib	u32 temp;
63235783Skib
64280369Skib	temp = I915_READ(PCH_ADPA);
65280369Skib	temp &= ~ADPA_DAC_ENABLE;
66235783Skib
67280369Skib	switch (mode) {
68280369Skib	case DRM_MODE_DPMS_ON:
69280369Skib		temp |= ADPA_DAC_ENABLE;
70280369Skib		break;
71280369Skib	case DRM_MODE_DPMS_STANDBY:
72280369Skib	case DRM_MODE_DPMS_SUSPEND:
73280369Skib	case DRM_MODE_DPMS_OFF:
74280369Skib		/* Just leave port enable cleared */
75280369Skib		break;
76280369Skib	}
77280369Skib
78280369Skib	I915_WRITE(PCH_ADPA, temp);
79280369Skib}
80280369Skib
81280369Skibstatic void gmch_crt_dpms(struct drm_encoder *encoder, int mode)
82280369Skib{
83280369Skib	struct drm_device *dev = encoder->dev;
84280369Skib	struct drm_i915_private *dev_priv = dev->dev_private;
85280369Skib	u32 temp;
86280369Skib
87280369Skib	temp = I915_READ(ADPA);
88235783Skib	temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
89235783Skib	temp &= ~ADPA_DAC_ENABLE;
90235783Skib
91235783Skib	switch (mode) {
92235783Skib	case DRM_MODE_DPMS_ON:
93235783Skib		temp |= ADPA_DAC_ENABLE;
94235783Skib		break;
95235783Skib	case DRM_MODE_DPMS_STANDBY:
96235783Skib		temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE;
97235783Skib		break;
98235783Skib	case DRM_MODE_DPMS_SUSPEND:
99235783Skib		temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE;
100235783Skib		break;
101235783Skib	case DRM_MODE_DPMS_OFF:
102235783Skib		temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE;
103235783Skib		break;
104235783Skib	}
105235783Skib
106280369Skib	I915_WRITE(ADPA, temp);
107235783Skib}
108235783Skib
109235783Skibstatic int intel_crt_mode_valid(struct drm_connector *connector,
110235783Skib				struct drm_display_mode *mode)
111235783Skib{
112235783Skib	struct drm_device *dev = connector->dev;
113235783Skib
114235783Skib	int max_clock = 0;
115235783Skib	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
116235783Skib		return MODE_NO_DBLESCAN;
117235783Skib
118235783Skib	if (mode->clock < 25000)
119235783Skib		return MODE_CLOCK_LOW;
120235783Skib
121235783Skib	if (IS_GEN2(dev))
122235783Skib		max_clock = 350000;
123235783Skib	else
124235783Skib		max_clock = 400000;
125235783Skib	if (mode->clock > max_clock)
126235783Skib		return MODE_CLOCK_HIGH;
127235783Skib
128235783Skib	return MODE_OK;
129235783Skib}
130235783Skib
131235783Skibstatic bool intel_crt_mode_fixup(struct drm_encoder *encoder,
132282199Sdumbbell				 const struct drm_display_mode *mode,
133235783Skib				 struct drm_display_mode *adjusted_mode)
134235783Skib{
135235783Skib	return true;
136235783Skib}
137235783Skib
138235783Skibstatic void intel_crt_mode_set(struct drm_encoder *encoder,
139235783Skib			       struct drm_display_mode *mode,
140235783Skib			       struct drm_display_mode *adjusted_mode)
141235783Skib{
142235783Skib
143235783Skib	struct drm_device *dev = encoder->dev;
144235783Skib	struct drm_crtc *crtc = encoder->crtc;
145235783Skib	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
146235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
147235783Skib	int dpll_md_reg;
148235783Skib	u32 adpa, dpll_md;
149235783Skib	u32 adpa_reg;
150235783Skib
151235783Skib	dpll_md_reg = DPLL_MD(intel_crtc->pipe);
152235783Skib
153235783Skib	if (HAS_PCH_SPLIT(dev))
154235783Skib		adpa_reg = PCH_ADPA;
155235783Skib	else
156235783Skib		adpa_reg = ADPA;
157235783Skib
158235783Skib	/*
159235783Skib	 * Disable separate mode multiplier used when cloning SDVO to CRT
160235783Skib	 * XXX this needs to be adjusted when we really are cloning
161235783Skib	 */
162235783Skib	if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
163235783Skib		dpll_md = I915_READ(dpll_md_reg);
164235783Skib		I915_WRITE(dpll_md_reg,
165235783Skib			   dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
166235783Skib	}
167235783Skib
168235783Skib	adpa = ADPA_HOTPLUG_BITS;
169235783Skib	if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
170235783Skib		adpa |= ADPA_HSYNC_ACTIVE_HIGH;
171235783Skib	if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
172235783Skib		adpa |= ADPA_VSYNC_ACTIVE_HIGH;
173235783Skib
174235783Skib	/* For CPT allow 3 pipe config, for others just use A or B */
175235783Skib	if (HAS_PCH_CPT(dev))
176235783Skib		adpa |= PORT_TRANS_SEL_CPT(intel_crtc->pipe);
177235783Skib	else if (intel_crtc->pipe == 0)
178235783Skib		adpa |= ADPA_PIPE_A_SELECT;
179235783Skib	else
180235783Skib		adpa |= ADPA_PIPE_B_SELECT;
181235783Skib
182235783Skib	if (!HAS_PCH_SPLIT(dev))
183235783Skib		I915_WRITE(BCLRPAT(intel_crtc->pipe), 0);
184235783Skib
185235783Skib	I915_WRITE(adpa_reg, adpa);
186235783Skib}
187235783Skib
188235783Skibstatic bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
189235783Skib{
190235783Skib	struct drm_device *dev = connector->dev;
191235783Skib	struct intel_crt *crt = intel_attached_crt(connector);
192235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
193235783Skib	u32 adpa;
194235783Skib	bool ret;
195235783Skib
196235783Skib	/* The first time through, trigger an explicit detection cycle */
197235783Skib	if (crt->force_hotplug_required) {
198235783Skib		bool turn_off_dac = HAS_PCH_SPLIT(dev);
199235783Skib		u32 save_adpa;
200235783Skib
201235783Skib		crt->force_hotplug_required = 0;
202235783Skib
203235783Skib		save_adpa = adpa = I915_READ(PCH_ADPA);
204235783Skib		DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);
205235783Skib
206235783Skib		adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER;
207235783Skib		if (turn_off_dac)
208235783Skib			adpa &= ~ADPA_DAC_ENABLE;
209235783Skib
210235783Skib		I915_WRITE(PCH_ADPA, adpa);
211235783Skib
212235783Skib		if (_intel_wait_for(dev,
213235783Skib		    (I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
214235783Skib		    1000, 1, "915crt"))
215235783Skib			DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER\n");
216235783Skib
217235783Skib		if (turn_off_dac) {
218235783Skib			I915_WRITE(PCH_ADPA, save_adpa);
219235783Skib			POSTING_READ(PCH_ADPA);
220235783Skib		}
221235783Skib	}
222235783Skib
223235783Skib	/* Check the status to see if both blue and green are on now */
224235783Skib	adpa = I915_READ(PCH_ADPA);
225235783Skib	if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0)
226235783Skib		ret = true;
227235783Skib	else
228235783Skib		ret = false;
229235783Skib	DRM_DEBUG_KMS("ironlake hotplug adpa=0x%x, result %d\n", adpa, ret);
230235783Skib
231235783Skib	return ret;
232235783Skib}
233235783Skib
234235783Skib/**
235235783Skib * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence.
236235783Skib *
237235783Skib * Not for i915G/i915GM
238235783Skib *
239235783Skib * \return true if CRT is connected.
240235783Skib * \return false if CRT is disconnected.
241235783Skib */
242235783Skibstatic bool intel_crt_detect_hotplug(struct drm_connector *connector)
243235783Skib{
244235783Skib	struct drm_device *dev = connector->dev;
245235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
246235783Skib	u32 hotplug_en, orig, stat;
247235783Skib	bool ret = false;
248235783Skib	int i, tries = 0;
249235783Skib
250235783Skib	if (HAS_PCH_SPLIT(dev))
251235783Skib		return intel_ironlake_crt_detect_hotplug(connector);
252235783Skib
253235783Skib	/*
254235783Skib	 * On 4 series desktop, CRT detect sequence need to be done twice
255235783Skib	 * to get a reliable result.
256235783Skib	 */
257235783Skib
258235783Skib	if (IS_G4X(dev) && !IS_GM45(dev))
259235783Skib		tries = 2;
260235783Skib	else
261235783Skib		tries = 1;
262235783Skib	hotplug_en = orig = I915_READ(PORT_HOTPLUG_EN);
263235783Skib	hotplug_en |= CRT_HOTPLUG_FORCE_DETECT;
264235783Skib
265235783Skib	for (i = 0; i < tries ; i++) {
266235783Skib		/* turn on the FORCE_DETECT */
267235783Skib		I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
268235783Skib		/* wait for FORCE_DETECT to go off */
269235783Skib		if (_intel_wait_for(dev,
270235783Skib		    (I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT) == 0,
271235783Skib		    1000, 1, "915cr2"))
272235783Skib			DRM_DEBUG_KMS("timed out waiting for FORCE_DETECT to go off");
273235783Skib	}
274235783Skib
275235783Skib	stat = I915_READ(PORT_HOTPLUG_STAT);
276235783Skib	if ((stat & CRT_HOTPLUG_MONITOR_MASK) != CRT_HOTPLUG_MONITOR_NONE)
277235783Skib		ret = true;
278235783Skib
279235783Skib	/* clear the interrupt we just generated, if any */
280235783Skib	I915_WRITE(PORT_HOTPLUG_STAT, CRT_HOTPLUG_INT_STATUS);
281235783Skib
282235783Skib	/* and put the bits back */
283235783Skib	I915_WRITE(PORT_HOTPLUG_EN, orig);
284235783Skib
285235783Skib	return ret;
286235783Skib}
287235783Skib
288235783Skibstatic bool intel_crt_detect_ddc(struct drm_connector *connector)
289235783Skib{
290235783Skib	struct intel_crt *crt = intel_attached_crt(connector);
291235783Skib	struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private;
292235783Skib
293235783Skib	/* CRT should always be at 0, but check anyway */
294235783Skib	if (crt->base.type != INTEL_OUTPUT_ANALOG)
295235783Skib		return false;
296235783Skib
297235783Skib	if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) {
298235783Skib		struct edid *edid;
299235783Skib		bool is_digital = false;
300280369Skib		device_t iic;
301235783Skib
302280369Skib		iic = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin);
303280369Skib		edid = drm_get_edid(connector, iic);
304235783Skib		/*
305235783Skib		 * This may be a DVI-I connector with a shared DDC
306235783Skib		 * link between analog and digital outputs, so we
307235783Skib		 * have to check the EDID input spec of the attached device.
308235783Skib		 *
309235783Skib		 * On the other hand, what should we do if it is a broken EDID?
310235783Skib		 */
311235783Skib		if (edid != NULL) {
312235783Skib			is_digital = edid->input & DRM_EDID_INPUT_DIGITAL;
313235783Skib			free(edid, DRM_MEM_KMS);
314235783Skib		}
315235783Skib
316235783Skib		if (!is_digital) {
317235783Skib			DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
318235783Skib			return true;
319235783Skib		} else {
320235783Skib			DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n");
321235783Skib		}
322235783Skib	}
323235783Skib
324235783Skib	return false;
325235783Skib}
326235783Skib
327235783Skibstatic enum drm_connector_status
328235783Skibintel_crt_load_detect(struct intel_crt *crt)
329235783Skib{
330235783Skib	struct drm_device *dev = crt->base.base.dev;
331235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
332235783Skib	uint32_t pipe = to_intel_crtc(crt->base.base.crtc)->pipe;
333235783Skib	uint32_t save_bclrpat;
334235783Skib	uint32_t save_vtotal;
335235783Skib	uint32_t vtotal, vactive;
336235783Skib	uint32_t vsample;
337235783Skib	uint32_t vblank, vblank_start, vblank_end;
338235783Skib	uint32_t dsl;
339235783Skib	uint32_t bclrpat_reg;
340235783Skib	uint32_t vtotal_reg;
341235783Skib	uint32_t vblank_reg;
342235783Skib	uint32_t vsync_reg;
343235783Skib	uint32_t pipeconf_reg;
344235783Skib	uint32_t pipe_dsl_reg;
345235783Skib	uint8_t	st00;
346235783Skib	enum drm_connector_status status;
347235783Skib
348235783Skib	DRM_DEBUG_KMS("starting load-detect on CRT\n");
349235783Skib
350235783Skib	bclrpat_reg = BCLRPAT(pipe);
351235783Skib	vtotal_reg = VTOTAL(pipe);
352235783Skib	vblank_reg = VBLANK(pipe);
353235783Skib	vsync_reg = VSYNC(pipe);
354235783Skib	pipeconf_reg = PIPECONF(pipe);
355235783Skib	pipe_dsl_reg = PIPEDSL(pipe);
356235783Skib
357235783Skib	save_bclrpat = I915_READ(bclrpat_reg);
358235783Skib	save_vtotal = I915_READ(vtotal_reg);
359235783Skib	vblank = I915_READ(vblank_reg);
360235783Skib
361235783Skib	vtotal = ((save_vtotal >> 16) & 0xfff) + 1;
362235783Skib	vactive = (save_vtotal & 0x7ff) + 1;
363235783Skib
364235783Skib	vblank_start = (vblank & 0xfff) + 1;
365235783Skib	vblank_end = ((vblank >> 16) & 0xfff) + 1;
366235783Skib
367235783Skib	/* Set the border color to purple. */
368235783Skib	I915_WRITE(bclrpat_reg, 0x500050);
369235783Skib
370235783Skib	if (!IS_GEN2(dev)) {
371235783Skib		uint32_t pipeconf = I915_READ(pipeconf_reg);
372235783Skib		I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER);
373235783Skib		POSTING_READ(pipeconf_reg);
374235783Skib		/* Wait for next Vblank to substitue
375235783Skib		 * border color for Color info */
376235783Skib		intel_wait_for_vblank(dev, pipe);
377235783Skib		st00 = I915_READ8(VGA_MSR_WRITE);
378235783Skib		status = ((st00 & (1 << 4)) != 0) ?
379235783Skib			connector_status_connected :
380235783Skib			connector_status_disconnected;
381235783Skib
382235783Skib		I915_WRITE(pipeconf_reg, pipeconf);
383235783Skib	} else {
384235783Skib		bool restore_vblank = false;
385235783Skib		int count, detect;
386235783Skib
387235783Skib		/*
388235783Skib		* If there isn't any border, add some.
389235783Skib		* Yes, this will flicker
390235783Skib		*/
391235783Skib		if (vblank_start <= vactive && vblank_end >= vtotal) {
392235783Skib			uint32_t vsync = I915_READ(vsync_reg);
393235783Skib			uint32_t vsync_start = (vsync & 0xffff) + 1;
394235783Skib
395235783Skib			vblank_start = vsync_start;
396235783Skib			I915_WRITE(vblank_reg,
397235783Skib				   (vblank_start - 1) |
398235783Skib				   ((vblank_end - 1) << 16));
399235783Skib			restore_vblank = true;
400235783Skib		}
401235783Skib		/* sample in the vertical border, selecting the larger one */
402235783Skib		if (vblank_start - vactive >= vtotal - vblank_end)
403235783Skib			vsample = (vblank_start + vactive) >> 1;
404235783Skib		else
405235783Skib			vsample = (vtotal + vblank_end) >> 1;
406235783Skib
407235783Skib		/*
408235783Skib		 * Wait for the border to be displayed
409235783Skib		 */
410235783Skib		while (I915_READ(pipe_dsl_reg) >= vactive)
411235783Skib			;
412235783Skib		while ((dsl = I915_READ(pipe_dsl_reg)) <= vsample)
413235783Skib			;
414235783Skib		/*
415235783Skib		 * Watch ST00 for an entire scanline
416235783Skib		 */
417235783Skib		detect = 0;
418235783Skib		count = 0;
419235783Skib		do {
420235783Skib			count++;
421235783Skib			/* Read the ST00 VGA status register */
422235783Skib			st00 = I915_READ8(VGA_MSR_WRITE);
423235783Skib			if (st00 & (1 << 4))
424235783Skib				detect++;
425235783Skib		} while ((I915_READ(pipe_dsl_reg) == dsl));
426235783Skib
427235783Skib		/* restore vblank if necessary */
428235783Skib		if (restore_vblank)
429235783Skib			I915_WRITE(vblank_reg, vblank);
430235783Skib		/*
431235783Skib		 * If more than 3/4 of the scanline detected a monitor,
432235783Skib		 * then it is assumed to be present. This works even on i830,
433235783Skib		 * where there isn't any way to force the border color across
434235783Skib		 * the screen
435235783Skib		 */
436235783Skib		status = detect * 4 > count * 3 ?
437235783Skib			 connector_status_connected :
438235783Skib			 connector_status_disconnected;
439235783Skib	}
440235783Skib
441235783Skib	/* Restore previous settings */
442235783Skib	I915_WRITE(bclrpat_reg, save_bclrpat);
443235783Skib
444235783Skib	return status;
445235783Skib}
446235783Skib
447235783Skibstatic enum drm_connector_status
448235783Skibintel_crt_detect(struct drm_connector *connector, bool force)
449235783Skib{
450235783Skib	struct drm_device *dev = connector->dev;
451235783Skib	struct intel_crt *crt = intel_attached_crt(connector);
452235783Skib	enum drm_connector_status status;
453235783Skib	struct intel_load_detect_pipe tmp;
454235783Skib
455235783Skib	if (I915_HAS_HOTPLUG(dev)) {
456235783Skib		if (intel_crt_detect_hotplug(connector)) {
457235783Skib			DRM_DEBUG_KMS("CRT detected via hotplug\n");
458235783Skib			return connector_status_connected;
459235783Skib		} else {
460235783Skib			DRM_DEBUG_KMS("CRT not detected via hotplug\n");
461235783Skib			return connector_status_disconnected;
462235783Skib		}
463235783Skib	}
464235783Skib
465235783Skib	if (intel_crt_detect_ddc(connector))
466235783Skib		return connector_status_connected;
467235783Skib
468235783Skib	if (!force)
469235783Skib		return connector->status;
470235783Skib
471235783Skib	/* for pre-945g platforms use load detect */
472235783Skib	if (intel_get_load_detect_pipe(&crt->base, connector, NULL,
473235783Skib				       &tmp)) {
474235783Skib		if (intel_crt_detect_ddc(connector))
475235783Skib			status = connector_status_connected;
476235783Skib		else
477235783Skib			status = intel_crt_load_detect(crt);
478235783Skib		intel_release_load_detect_pipe(&crt->base, connector,
479235783Skib					       &tmp);
480235783Skib	} else
481235783Skib		status = connector_status_unknown;
482235783Skib
483235783Skib	return status;
484235783Skib}
485235783Skib
486235783Skibstatic void intel_crt_destroy(struct drm_connector *connector)
487235783Skib{
488235783Skib
489235783Skib#if 0
490235783Skib	drm_sysfs_connector_remove(connector);
491235783Skib#endif
492235783Skib	drm_connector_cleanup(connector);
493235783Skib	free(connector, DRM_MEM_KMS);
494235783Skib}
495235783Skib
496235783Skibstatic int intel_crt_get_modes(struct drm_connector *connector)
497235783Skib{
498235783Skib	struct drm_device *dev = connector->dev;
499235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
500235783Skib	int ret;
501280369Skib	device_t iic;
502235783Skib
503280369Skib	iic = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin);
504280369Skib	ret = intel_ddc_get_modes(connector, iic);
505235783Skib	if (ret || !IS_G4X(dev))
506235783Skib		return ret;
507235783Skib
508235783Skib	/* Try to probe digital port for output in DVI-I -> VGA mode. */
509280369Skib	iic = intel_gmbus_get_adapter(dev_priv, GMBUS_PORT_DPB);
510280369Skib	return intel_ddc_get_modes(connector, iic);
511235783Skib}
512235783Skib
513235783Skibstatic int intel_crt_set_property(struct drm_connector *connector,
514235783Skib				  struct drm_property *property,
515235783Skib				  uint64_t value)
516235783Skib{
517235783Skib	return 0;
518235783Skib}
519235783Skib
520235783Skibstatic void intel_crt_reset(struct drm_connector *connector)
521235783Skib{
522235783Skib	struct drm_device *dev = connector->dev;
523235783Skib	struct intel_crt *crt = intel_attached_crt(connector);
524235783Skib
525235783Skib	if (HAS_PCH_SPLIT(dev))
526235783Skib		crt->force_hotplug_required = 1;
527235783Skib}
528235783Skib
529235783Skib/*
530235783Skib * Routines for controlling stuff on the analog port
531235783Skib */
532235783Skib
533280369Skibstatic const struct drm_encoder_helper_funcs pch_encoder_funcs = {
534235783Skib	.mode_fixup = intel_crt_mode_fixup,
535235783Skib	.prepare = intel_encoder_prepare,
536235783Skib	.commit = intel_encoder_commit,
537235783Skib	.mode_set = intel_crt_mode_set,
538280369Skib	.dpms = pch_crt_dpms,
539235783Skib};
540235783Skib
541280369Skibstatic const struct drm_encoder_helper_funcs gmch_encoder_funcs = {
542280369Skib	.mode_fixup = intel_crt_mode_fixup,
543280369Skib	.prepare = intel_encoder_prepare,
544280369Skib	.commit = intel_encoder_commit,
545280369Skib	.mode_set = intel_crt_mode_set,
546280369Skib	.dpms = gmch_crt_dpms,
547280369Skib};
548280369Skib
549235783Skibstatic const struct drm_connector_funcs intel_crt_connector_funcs = {
550235783Skib	.reset = intel_crt_reset,
551235783Skib	.dpms = drm_helper_connector_dpms,
552235783Skib	.detect = intel_crt_detect,
553235783Skib	.fill_modes = drm_helper_probe_single_connector_modes,
554235783Skib	.destroy = intel_crt_destroy,
555235783Skib	.set_property = intel_crt_set_property,
556235783Skib};
557235783Skib
558235783Skibstatic const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = {
559235783Skib	.mode_valid = intel_crt_mode_valid,
560235783Skib	.get_modes = intel_crt_get_modes,
561235783Skib	.best_encoder = intel_best_encoder,
562235783Skib};
563235783Skib
564235783Skibstatic const struct drm_encoder_funcs intel_crt_enc_funcs = {
565235783Skib	.destroy = intel_encoder_destroy,
566235783Skib};
567235783Skib
568235783Skibstatic int intel_no_crt_dmi_callback(const struct dmi_system_id *id)
569235783Skib{
570280369Skib	DRM_INFO("Skipping CRT initialization for %s\n", id->ident);
571235783Skib	return 1;
572235783Skib}
573235783Skib
574235783Skibstatic const struct dmi_system_id intel_no_crt[] = {
575235783Skib	{
576235783Skib		.callback = intel_no_crt_dmi_callback,
577235783Skib		.ident = "ACER ZGB",
578235783Skib		.matches = {
579235783Skib			DMI_MATCH(DMI_SYS_VENDOR, "ACER"),
580235783Skib			DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
581235783Skib		},
582235783Skib	},
583235783Skib	{ }
584235783Skib};
585235783Skib
586235783Skibvoid intel_crt_init(struct drm_device *dev)
587235783Skib{
588235783Skib	struct drm_connector *connector;
589235783Skib	struct intel_crt *crt;
590235783Skib	struct intel_connector *intel_connector;
591235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
592280369Skib	const struct drm_encoder_helper_funcs *encoder_helper_funcs;
593235783Skib
594235783Skib	/* Skip machines without VGA that falsely report hotplug events */
595235783Skib	if (dmi_check_system(intel_no_crt))
596235783Skib		return;
597235783Skib
598235783Skib	crt = malloc(sizeof(struct intel_crt), DRM_MEM_KMS, M_WAITOK | M_ZERO);
599235783Skib	intel_connector = malloc(sizeof(struct intel_connector), DRM_MEM_KMS,
600235783Skib	    M_WAITOK | M_ZERO);
601235783Skib
602235783Skib	connector = &intel_connector->base;
603235783Skib	drm_connector_init(dev, &intel_connector->base,
604235783Skib			   &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
605235783Skib
606235783Skib	drm_encoder_init(dev, &crt->base.base, &intel_crt_enc_funcs,
607235783Skib			 DRM_MODE_ENCODER_DAC);
608235783Skib
609235783Skib	intel_connector_attach_encoder(intel_connector, &crt->base);
610235783Skib
611235783Skib	crt->base.type = INTEL_OUTPUT_ANALOG;
612235783Skib	crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT |
613235783Skib				1 << INTEL_ANALOG_CLONE_BIT |
614235783Skib				1 << INTEL_SDVO_LVDS_CLONE_BIT);
615280369Skib	if (IS_HASWELL(dev))
616280369Skib		crt->base.crtc_mask = (1 << 0);
617280369Skib	else
618280369Skib		crt->base.crtc_mask = (1 << 0) | (1 << 1);
619280369Skib
620235783Skib	if (IS_GEN2(dev))
621235783Skib		connector->interlace_allowed = 0;
622235783Skib	else
623235783Skib		connector->interlace_allowed = 1;
624235783Skib	connector->doublescan_allowed = 0;
625235783Skib
626280369Skib	if (HAS_PCH_SPLIT(dev))
627280369Skib		encoder_helper_funcs = &pch_encoder_funcs;
628280369Skib	else
629280369Skib		encoder_helper_funcs = &gmch_encoder_funcs;
630280369Skib
631280369Skib	drm_encoder_helper_add(&crt->base.base, encoder_helper_funcs);
632235783Skib	drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
633235783Skib
634235783Skib#if 0
635235783Skib	drm_sysfs_connector_add(connector);
636235783Skib#endif
637235783Skib
638235783Skib	if (I915_HAS_HOTPLUG(dev))
639235783Skib		connector->polled = DRM_CONNECTOR_POLL_HPD;
640235783Skib	else
641235783Skib		connector->polled = DRM_CONNECTOR_POLL_CONNECT;
642235783Skib
643235783Skib	/*
644235783Skib	 * Configure the automatic hotplug detection stuff
645235783Skib	 */
646235783Skib	crt->force_hotplug_required = 0;
647235783Skib	if (HAS_PCH_SPLIT(dev)) {
648235783Skib		u32 adpa;
649235783Skib
650235783Skib		adpa = I915_READ(PCH_ADPA);
651235783Skib		adpa &= ~ADPA_CRT_HOTPLUG_MASK;
652235783Skib		adpa |= ADPA_HOTPLUG_BITS;
653235783Skib		I915_WRITE(PCH_ADPA, adpa);
654235783Skib		POSTING_READ(PCH_ADPA);
655235783Skib
656235783Skib		DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa);
657235783Skib		crt->force_hotplug_required = 1;
658235783Skib	}
659235783Skib
660235783Skib	dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
661235783Skib}
662