xref: /dflybsd-src/sys/dev/drm/radeon/radeon_connectors.c (revision 1cfef1a587a371344cf93e80367482432b0933a2)
1926deccbSFrançois Tigeot /*
2926deccbSFrançois Tigeot  * Copyright 2007-8 Advanced Micro Devices, Inc.
3926deccbSFrançois Tigeot  * Copyright 2008 Red Hat Inc.
4926deccbSFrançois Tigeot  *
5926deccbSFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
6926deccbSFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
7926deccbSFrançois Tigeot  * to deal in the Software without restriction, including without limitation
8926deccbSFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9926deccbSFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
10926deccbSFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
11926deccbSFrançois Tigeot  *
12926deccbSFrançois Tigeot  * The above copyright notice and this permission notice shall be included in
13926deccbSFrançois Tigeot  * all copies or substantial portions of the Software.
14926deccbSFrançois Tigeot  *
15926deccbSFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16926deccbSFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17926deccbSFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18926deccbSFrançois Tigeot  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19926deccbSFrançois Tigeot  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20926deccbSFrançois Tigeot  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21926deccbSFrançois Tigeot  * OTHER DEALINGS IN THE SOFTWARE.
22926deccbSFrançois Tigeot  *
23926deccbSFrançois Tigeot  * Authors: Dave Airlie
24926deccbSFrançois Tigeot  *          Alex Deucher
25926deccbSFrançois Tigeot  */
26926deccbSFrançois Tigeot #include <drm/drmP.h>
27926deccbSFrançois Tigeot #include <drm/drm_edid.h>
28926deccbSFrançois Tigeot #include <drm/drm_crtc_helper.h>
29926deccbSFrançois Tigeot #include <drm/drm_fb_helper.h>
3083b4b9b9SFrançois Tigeot #include <drm/radeon_drm.h>
31926deccbSFrançois Tigeot #include "radeon.h"
32926deccbSFrançois Tigeot #include "atom.h"
33926deccbSFrançois Tigeot 
34c6f73aabSFrançois Tigeot #include <linux/string.h>
35c6f73aabSFrançois Tigeot 
36c6f73aabSFrançois Tigeot #ifdef PM_TODO
37c6f73aabSFrançois Tigeot #include <linux/pm_runtime.h>
38c6f73aabSFrançois Tigeot #endif
39c6f73aabSFrançois Tigeot 
40926deccbSFrançois Tigeot void radeon_connector_hotplug(struct drm_connector *connector)
41926deccbSFrançois Tigeot {
42926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
43926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
44926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
45926deccbSFrançois Tigeot 
46926deccbSFrançois Tigeot 	/* bail if the connector does not have hpd pin, e.g.,
47926deccbSFrançois Tigeot 	 * VGA, TV, etc.
48926deccbSFrançois Tigeot 	 */
49926deccbSFrançois Tigeot 	if (radeon_connector->hpd.hpd == RADEON_HPD_NONE)
50926deccbSFrançois Tigeot 		return;
51926deccbSFrançois Tigeot 
52926deccbSFrançois Tigeot 	radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
53926deccbSFrançois Tigeot 
54926deccbSFrançois Tigeot 	/* if the connector is already off, don't turn it back on */
55c6f73aabSFrançois Tigeot 	/* FIXME: This access isn't protected by any locks. */
56926deccbSFrançois Tigeot 	if (connector->dpms != DRM_MODE_DPMS_ON)
57926deccbSFrançois Tigeot 		return;
58926deccbSFrançois Tigeot 
59926deccbSFrançois Tigeot 	/* just deal with DP (not eDP) here. */
60926deccbSFrançois Tigeot 	if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
61926deccbSFrançois Tigeot 		struct radeon_connector_atom_dig *dig_connector =
62926deccbSFrançois Tigeot 			radeon_connector->con_priv;
63926deccbSFrançois Tigeot 
64926deccbSFrançois Tigeot 		/* if existing sink type was not DP no need to retrain */
65926deccbSFrançois Tigeot 		if (dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_DISPLAYPORT)
66926deccbSFrançois Tigeot 			return;
67926deccbSFrançois Tigeot 
68926deccbSFrançois Tigeot 		/* first get sink type as it may be reset after (un)plug */
69926deccbSFrançois Tigeot 		dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
70926deccbSFrançois Tigeot 		/* don't do anything if sink is not display port, i.e.,
71926deccbSFrançois Tigeot 		 * passive dp->(dvi|hdmi) adaptor
72926deccbSFrançois Tigeot 		 */
73926deccbSFrançois Tigeot 		if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
74926deccbSFrançois Tigeot 			int saved_dpms = connector->dpms;
75926deccbSFrançois Tigeot 			/* Only turn off the display if it's physically disconnected */
76926deccbSFrançois Tigeot 			if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
77926deccbSFrançois Tigeot 				drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
78926deccbSFrançois Tigeot 			} else if (radeon_dp_needs_link_train(radeon_connector)) {
79926deccbSFrançois Tigeot 				/* set it to OFF so that drm_helper_connector_dpms()
80926deccbSFrançois Tigeot 				 * won't return immediately since the current state
81926deccbSFrançois Tigeot 				 * is ON at this point.
82926deccbSFrançois Tigeot 				 */
83926deccbSFrançois Tigeot 				connector->dpms = DRM_MODE_DPMS_OFF;
84926deccbSFrançois Tigeot 				drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
85926deccbSFrançois Tigeot 			}
86926deccbSFrançois Tigeot 			connector->dpms = saved_dpms;
87926deccbSFrançois Tigeot 		}
88926deccbSFrançois Tigeot 	}
89926deccbSFrançois Tigeot }
90926deccbSFrançois Tigeot 
91926deccbSFrançois Tigeot static void radeon_property_change_mode(struct drm_encoder *encoder)
92926deccbSFrançois Tigeot {
93926deccbSFrançois Tigeot 	struct drm_crtc *crtc = encoder->crtc;
94926deccbSFrançois Tigeot 
95926deccbSFrançois Tigeot 	if (crtc && crtc->enabled) {
96926deccbSFrançois Tigeot 		drm_crtc_helper_set_mode(crtc, &crtc->mode,
97ba55f2f5SFrançois Tigeot 					 crtc->x, crtc->y, crtc->primary->fb);
98926deccbSFrançois Tigeot 	}
99926deccbSFrançois Tigeot }
100926deccbSFrançois Tigeot 
101926deccbSFrançois Tigeot int radeon_get_monitor_bpc(struct drm_connector *connector)
102926deccbSFrançois Tigeot {
103926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
104926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
105926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
106926deccbSFrançois Tigeot 	struct radeon_connector_atom_dig *dig_connector;
107926deccbSFrançois Tigeot 	int bpc = 8;
108c6f73aabSFrançois Tigeot 	int mode_clock, max_tmds_clock;
109926deccbSFrançois Tigeot 
110926deccbSFrançois Tigeot 	switch (connector->connector_type) {
111926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_DVII:
112926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_HDMIB:
113926deccbSFrançois Tigeot 		if (radeon_connector->use_digital) {
114c6f73aabSFrançois Tigeot 			if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
115926deccbSFrançois Tigeot 				if (connector->display_info.bpc)
116926deccbSFrançois Tigeot 					bpc = connector->display_info.bpc;
117926deccbSFrançois Tigeot 			}
118926deccbSFrançois Tigeot 		}
119926deccbSFrançois Tigeot 		break;
120926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_DVID:
121926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_HDMIA:
122c6f73aabSFrançois Tigeot 		if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
123926deccbSFrançois Tigeot 			if (connector->display_info.bpc)
124926deccbSFrançois Tigeot 				bpc = connector->display_info.bpc;
125926deccbSFrançois Tigeot 		}
126926deccbSFrançois Tigeot 		break;
127926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_DisplayPort:
128926deccbSFrançois Tigeot 		dig_connector = radeon_connector->con_priv;
129926deccbSFrançois Tigeot 		if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
130926deccbSFrançois Tigeot 		    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) ||
131c6f73aabSFrançois Tigeot 		    drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
132926deccbSFrançois Tigeot 			if (connector->display_info.bpc)
133926deccbSFrançois Tigeot 				bpc = connector->display_info.bpc;
134926deccbSFrançois Tigeot 		}
135926deccbSFrançois Tigeot 		break;
136926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_eDP:
137926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_LVDS:
138926deccbSFrançois Tigeot 		if (connector->display_info.bpc)
139926deccbSFrançois Tigeot 			bpc = connector->display_info.bpc;
140926deccbSFrançois Tigeot 		else if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) {
141c0e85e96SFrançois Tigeot 			const struct drm_connector_helper_funcs *connector_funcs =
142926deccbSFrançois Tigeot 				connector->helper_private;
143926deccbSFrançois Tigeot 			struct drm_encoder *encoder = connector_funcs->best_encoder(connector);
144926deccbSFrançois Tigeot 			struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
145926deccbSFrançois Tigeot 			struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
146926deccbSFrançois Tigeot 
147926deccbSFrançois Tigeot 			if (dig->lcd_misc & ATOM_PANEL_MISC_V13_6BIT_PER_COLOR)
148926deccbSFrançois Tigeot 				bpc = 6;
149926deccbSFrançois Tigeot 			else if (dig->lcd_misc & ATOM_PANEL_MISC_V13_8BIT_PER_COLOR)
150926deccbSFrançois Tigeot 				bpc = 8;
151926deccbSFrançois Tigeot 		}
152926deccbSFrançois Tigeot 		break;
153926deccbSFrançois Tigeot 	}
154c6f73aabSFrançois Tigeot 
155c6f73aabSFrançois Tigeot 	if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
156c6f73aabSFrançois Tigeot 		/* hdmi deep color only implemented on DCE4+ */
157c6f73aabSFrançois Tigeot 		if ((bpc > 8) && !ASIC_IS_DCE4(rdev)) {
158c6f73aabSFrançois Tigeot 			DRM_DEBUG("%s: HDMI deep color %d bpc unsupported. Using 8 bpc.\n",
159c6f73aabSFrançois Tigeot 					  connector->name, bpc);
160c6f73aabSFrançois Tigeot 			bpc = 8;
161c6f73aabSFrançois Tigeot 		}
162c6f73aabSFrançois Tigeot 
163c6f73aabSFrançois Tigeot 		/*
164c6f73aabSFrançois Tigeot 		 * Pre DCE-8 hw can't handle > 12 bpc, and more than 12 bpc doesn't make
165c6f73aabSFrançois Tigeot 		 * much sense without support for > 12 bpc framebuffers. RGB 4:4:4 at
166c6f73aabSFrançois Tigeot 		 * 12 bpc is always supported on hdmi deep color sinks, as this is
167c6f73aabSFrançois Tigeot 		 * required by the HDMI-1.3 spec. Clamp to a safe 12 bpc maximum.
168c6f73aabSFrançois Tigeot 		 */
169c6f73aabSFrançois Tigeot 		if (bpc > 12) {
170c6f73aabSFrançois Tigeot 			DRM_DEBUG("%s: HDMI deep color %d bpc unsupported. Using 12 bpc.\n",
171c6f73aabSFrançois Tigeot 					  connector->name, bpc);
172c6f73aabSFrançois Tigeot 			bpc = 12;
173c6f73aabSFrançois Tigeot 		}
174c6f73aabSFrançois Tigeot 
175c6f73aabSFrançois Tigeot 		/* Any defined maximum tmds clock limit we must not exceed? */
176c6f73aabSFrançois Tigeot 		if (connector->max_tmds_clock > 0) {
177c6f73aabSFrançois Tigeot 			/* mode_clock is clock in kHz for mode to be modeset on this connector */
178c6f73aabSFrançois Tigeot 			mode_clock = radeon_connector->pixelclock_for_modeset;
179c6f73aabSFrançois Tigeot 
180c6f73aabSFrançois Tigeot 			/* Maximum allowable input clock in kHz */
181c6f73aabSFrançois Tigeot 			max_tmds_clock = connector->max_tmds_clock * 1000;
182c6f73aabSFrançois Tigeot 
183c6f73aabSFrançois Tigeot 			DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n",
184c6f73aabSFrançois Tigeot 					  connector->name, mode_clock, max_tmds_clock);
185c6f73aabSFrançois Tigeot 
186c6f73aabSFrançois Tigeot 			/* Check if bpc is within clock limit. Try to degrade gracefully otherwise */
187c6f73aabSFrançois Tigeot 			if ((bpc == 12) && (mode_clock * 3/2 > max_tmds_clock)) {
188c6f73aabSFrançois Tigeot 				if ((connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) &&
189c6f73aabSFrançois Tigeot 					(mode_clock * 5/4 <= max_tmds_clock))
190c6f73aabSFrançois Tigeot 					bpc = 10;
191c6f73aabSFrançois Tigeot 				else
192c6f73aabSFrançois Tigeot 					bpc = 8;
193c6f73aabSFrançois Tigeot 
194c6f73aabSFrançois Tigeot 				DRM_DEBUG("%s: HDMI deep color 12 bpc exceeds max tmds clock. Using %d bpc.\n",
195c6f73aabSFrançois Tigeot 						  connector->name, bpc);
196c6f73aabSFrançois Tigeot 			}
197c6f73aabSFrançois Tigeot 
198c6f73aabSFrançois Tigeot 			if ((bpc == 10) && (mode_clock * 5/4 > max_tmds_clock)) {
199c6f73aabSFrançois Tigeot 				bpc = 8;
200c6f73aabSFrançois Tigeot 				DRM_DEBUG("%s: HDMI deep color 10 bpc exceeds max tmds clock. Using %d bpc.\n",
201c6f73aabSFrançois Tigeot 						  connector->name, bpc);
202c6f73aabSFrançois Tigeot 			}
203c6f73aabSFrançois Tigeot 		}
204c6f73aabSFrançois Tigeot 		else if (bpc > 8) {
205c6f73aabSFrançois Tigeot 			/* max_tmds_clock missing, but hdmi spec mandates it for deep color. */
206c6f73aabSFrançois Tigeot 			DRM_DEBUG("%s: Required max tmds clock for HDMI deep color missing. Using 8 bpc.\n",
207c6f73aabSFrançois Tigeot 					  connector->name);
208c6f73aabSFrançois Tigeot 			bpc = 8;
209c6f73aabSFrançois Tigeot 		}
210c6f73aabSFrançois Tigeot 	}
211c6f73aabSFrançois Tigeot 
212c6f73aabSFrançois Tigeot 	if ((radeon_deep_color == 0) && (bpc > 8)) {
213c6f73aabSFrançois Tigeot 		DRM_DEBUG("%s: Deep color disabled. Set radeon module param deep_color=1 to enable.\n",
214c6f73aabSFrançois Tigeot 				  connector->name);
215c6f73aabSFrançois Tigeot 		bpc = 8;
216c6f73aabSFrançois Tigeot 	}
217c6f73aabSFrançois Tigeot 
218c6f73aabSFrançois Tigeot 	DRM_DEBUG("%s: Display bpc=%d, returned bpc=%d\n",
219c6f73aabSFrançois Tigeot 			  connector->name, connector->display_info.bpc, bpc);
220c6f73aabSFrançois Tigeot 
221926deccbSFrançois Tigeot 	return bpc;
222926deccbSFrançois Tigeot }
223926deccbSFrançois Tigeot 
224926deccbSFrançois Tigeot static void
225926deccbSFrançois Tigeot radeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_connector_status status)
226926deccbSFrançois Tigeot {
227926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
228926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
229926deccbSFrançois Tigeot 	struct drm_encoder *best_encoder = NULL;
230926deccbSFrançois Tigeot 	struct drm_encoder *encoder = NULL;
231c0e85e96SFrançois Tigeot 	const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
232926deccbSFrançois Tigeot 	bool connected;
233926deccbSFrançois Tigeot 	int i;
234926deccbSFrançois Tigeot 
235926deccbSFrançois Tigeot 	best_encoder = connector_funcs->best_encoder(connector);
236926deccbSFrançois Tigeot 
237926deccbSFrançois Tigeot 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
238926deccbSFrançois Tigeot 		if (connector->encoder_ids[i] == 0)
239926deccbSFrançois Tigeot 			break;
240926deccbSFrançois Tigeot 
241c6f73aabSFrançois Tigeot 		encoder = drm_encoder_find(connector->dev,
242c6f73aabSFrançois Tigeot 					   connector->encoder_ids[i]);
243c6f73aabSFrançois Tigeot 		if (!encoder)
244926deccbSFrançois Tigeot 			continue;
245926deccbSFrançois Tigeot 
246926deccbSFrançois Tigeot 		if ((encoder == best_encoder) && (status == connector_status_connected))
247926deccbSFrançois Tigeot 			connected = true;
248926deccbSFrançois Tigeot 		else
249926deccbSFrançois Tigeot 			connected = false;
250926deccbSFrançois Tigeot 
251926deccbSFrançois Tigeot 		if (rdev->is_atom_bios)
252926deccbSFrançois Tigeot 			radeon_atombios_connected_scratch_regs(connector, encoder, connected);
253926deccbSFrançois Tigeot 		else
254926deccbSFrançois Tigeot 			radeon_combios_connected_scratch_regs(connector, encoder, connected);
255926deccbSFrançois Tigeot 
256926deccbSFrançois Tigeot 	}
257926deccbSFrançois Tigeot }
258926deccbSFrançois Tigeot 
259926deccbSFrançois Tigeot static struct drm_encoder *radeon_find_encoder(struct drm_connector *connector, int encoder_type)
260926deccbSFrançois Tigeot {
261926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
262926deccbSFrançois Tigeot 	int i;
263926deccbSFrançois Tigeot 
264926deccbSFrançois Tigeot 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
265926deccbSFrançois Tigeot 		if (connector->encoder_ids[i] == 0)
266926deccbSFrançois Tigeot 			break;
267926deccbSFrançois Tigeot 
268c6f73aabSFrançois Tigeot 		encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
269c6f73aabSFrançois Tigeot 		if (!encoder)
270926deccbSFrançois Tigeot 			continue;
271926deccbSFrançois Tigeot 
272926deccbSFrançois Tigeot 		if (encoder->encoder_type == encoder_type)
273926deccbSFrançois Tigeot 			return encoder;
274926deccbSFrançois Tigeot 	}
275926deccbSFrançois Tigeot 	return NULL;
276926deccbSFrançois Tigeot }
277926deccbSFrançois Tigeot 
278c6f73aabSFrançois Tigeot struct edid *radeon_connector_edid(struct drm_connector *connector)
279c6f73aabSFrançois Tigeot {
280c6f73aabSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
281c6f73aabSFrançois Tigeot 	struct drm_property_blob *edid_blob = connector->edid_blob_ptr;
282c6f73aabSFrançois Tigeot 
283c6f73aabSFrançois Tigeot 	if (radeon_connector->edid) {
284c6f73aabSFrançois Tigeot 		return radeon_connector->edid;
285c6f73aabSFrançois Tigeot 	} else if (edid_blob) {
286c6f73aabSFrançois Tigeot 		struct edid *edid = kmemdup(edid_blob->data, edid_blob->length, GFP_KERNEL);
287c6f73aabSFrançois Tigeot 		if (edid)
288c6f73aabSFrançois Tigeot 			radeon_connector->edid = edid;
289c6f73aabSFrançois Tigeot 	}
290c6f73aabSFrançois Tigeot 	return radeon_connector->edid;
291c6f73aabSFrançois Tigeot }
292c6f73aabSFrançois Tigeot 
293ee479021SImre Vadász static void radeon_connector_get_edid(struct radeon_connector *radeon_connector)
2947191d616Szrj {
295ee479021SImre Vadász 	struct drm_device *dev = radeon_connector->base.dev;
2967191d616Szrj 	struct radeon_device *rdev = dev->dev_private;
2977191d616Szrj 
2987191d616Szrj 	if (radeon_connector->edid)
2997191d616Szrj 		return;
3007191d616Szrj 
3017191d616Szrj 	/* on hw with routers, select right port */
3027191d616Szrj 	if (radeon_connector->router.ddc_valid)
3037191d616Szrj 		radeon_router_select_ddc_port(radeon_connector);
3047191d616Szrj 
305ee479021SImre Vadász 	if (radeon_connector_encoder_get_dp_bridge_encoder_id(&radeon_connector->base) !=
306ee479021SImre Vadász 	    ENCODER_OBJECT_ID_NONE) {
307ee479021SImre Vadász 		struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
308ee479021SImre Vadász 
309ee479021SImre Vadász 		if (dig->dp_i2c_bus)
310ee479021SImre Vadász 			radeon_connector->edid = drm_get_edid_iic(&radeon_connector->base,
311ee479021SImre Vadász 							      dig->dp_i2c_bus->adapter);
312ee479021SImre Vadász 	} else if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
313ee479021SImre Vadász 		   (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) {
3147191d616Szrj 		struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
3157191d616Szrj 
3167191d616Szrj 		if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT ||
317ee479021SImre Vadász 		     dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && dig->dp_i2c_bus)
3189f4ca867SFrançois Tigeot 			radeon_connector->edid = drm_get_edid_iic(&radeon_connector->base,
319ee479021SImre Vadász 							      dig->dp_i2c_bus->adapter);
320ee479021SImre Vadász 		else if (radeon_connector->ddc_bus && !radeon_connector->edid)
3219f4ca867SFrançois Tigeot 			radeon_connector->edid = drm_get_edid_iic(&radeon_connector->base,
322ee479021SImre Vadász 							      radeon_connector->ddc_bus->adapter);
3237191d616Szrj 	} else if (radeon_connector->ddc_bus) {
3249f4ca867SFrançois Tigeot 		radeon_connector->edid = drm_get_edid_iic(&radeon_connector->base,
325ee479021SImre Vadász 						      radeon_connector->ddc_bus->adapter);
3267191d616Szrj 	}
3277191d616Szrj 
3287191d616Szrj 	if (!radeon_connector->edid) {
329*1cfef1a5SFrançois Tigeot 		/* don't fetch the edid from the vbios if ddc fails and runpm is
330*1cfef1a5SFrançois Tigeot 		 * enabled so we report disconnected.
331*1cfef1a5SFrançois Tigeot 		 */
332*1cfef1a5SFrançois Tigeot 		if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0))
333*1cfef1a5SFrançois Tigeot 			return;
334*1cfef1a5SFrançois Tigeot 
3357191d616Szrj 		if (rdev->is_atom_bios) {
3367191d616Szrj 			/* some laptops provide a hardcoded edid in rom for LCDs */
337ee479021SImre Vadász 			if (((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_LVDS) ||
338ee479021SImre Vadász 			     (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)))
3397191d616Szrj 				radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev);
3407191d616Szrj 		} else {
3417191d616Szrj 			/* some servers provide a hardcoded edid in rom for KVMs */
3427191d616Szrj 			radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev);
3437191d616Szrj 		}
3447191d616Szrj 	}
3457191d616Szrj }
3467191d616Szrj 
347ee479021SImre Vadász static void radeon_connector_free_edid(struct radeon_connector *radeon_connector)
3487191d616Szrj {
3497191d616Szrj 	if (radeon_connector->edid) {
3507191d616Szrj 		kfree(radeon_connector->edid);
3517191d616Szrj 		radeon_connector->edid = NULL;
3527191d616Szrj 	}
3537191d616Szrj }
3547191d616Szrj 
355ee479021SImre Vadász static int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
3567191d616Szrj {
3577191d616Szrj 	int ret;
3587191d616Szrj 
3597191d616Szrj 	if (radeon_connector->edid) {
360ee479021SImre Vadász 		drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid);
361ee479021SImre Vadász 		ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid);
362ee479021SImre Vadász 		drm_edid_to_eld(&radeon_connector->base, radeon_connector->edid);
3637191d616Szrj 		return ret;
3647191d616Szrj 	}
365ee479021SImre Vadász 	drm_mode_connector_update_edid_property(&radeon_connector->base, NULL);
3667191d616Szrj 	return 0;
3677191d616Szrj }
3687191d616Szrj 
369926deccbSFrançois Tigeot static struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector)
370926deccbSFrançois Tigeot {
371926deccbSFrançois Tigeot 	int enc_id = connector->encoder_ids[0];
372926deccbSFrançois Tigeot 	/* pick the encoder ids */
373c6f73aabSFrançois Tigeot 	if (enc_id)
374c6f73aabSFrançois Tigeot 		return drm_encoder_find(connector->dev, enc_id);
375926deccbSFrançois Tigeot 	return NULL;
376926deccbSFrançois Tigeot }
377c6f73aabSFrançois Tigeot 
378c6f73aabSFrançois Tigeot static void radeon_get_native_mode(struct drm_connector *connector)
379c6f73aabSFrançois Tigeot {
380c6f73aabSFrançois Tigeot 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
381c6f73aabSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
382c6f73aabSFrançois Tigeot 
383c6f73aabSFrançois Tigeot 	if (encoder == NULL)
384c6f73aabSFrançois Tigeot 		return;
385c6f73aabSFrançois Tigeot 
386c6f73aabSFrançois Tigeot 	radeon_encoder = to_radeon_encoder(encoder);
387c6f73aabSFrançois Tigeot 
388c6f73aabSFrançois Tigeot 	if (!list_empty(&connector->probed_modes)) {
389c6f73aabSFrançois Tigeot 		struct drm_display_mode *preferred_mode =
390c6f73aabSFrançois Tigeot 			list_first_entry(&connector->probed_modes,
391c6f73aabSFrançois Tigeot 					 struct drm_display_mode, head);
392c6f73aabSFrançois Tigeot 
393c6f73aabSFrançois Tigeot 		radeon_encoder->native_mode = *preferred_mode;
394c6f73aabSFrançois Tigeot 	} else {
395c6f73aabSFrançois Tigeot 		radeon_encoder->native_mode.clock = 0;
396c6f73aabSFrançois Tigeot 	}
397926deccbSFrançois Tigeot }
398926deccbSFrançois Tigeot 
399926deccbSFrançois Tigeot /*
400926deccbSFrançois Tigeot  * radeon_connector_analog_encoder_conflict_solve
401926deccbSFrançois Tigeot  * - search for other connectors sharing this encoder
402926deccbSFrançois Tigeot  *   if priority is true, then set them disconnected if this is connected
403926deccbSFrançois Tigeot  *   if priority is false, set us disconnected if they are connected
404926deccbSFrançois Tigeot  */
405926deccbSFrançois Tigeot static enum drm_connector_status
406926deccbSFrançois Tigeot radeon_connector_analog_encoder_conflict_solve(struct drm_connector *connector,
407926deccbSFrançois Tigeot 					       struct drm_encoder *encoder,
408926deccbSFrançois Tigeot 					       enum drm_connector_status current_status,
409926deccbSFrançois Tigeot 					       bool priority)
410926deccbSFrançois Tigeot {
411926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
412926deccbSFrançois Tigeot 	struct drm_connector *conflict;
413926deccbSFrançois Tigeot 	struct radeon_connector *radeon_conflict;
414926deccbSFrançois Tigeot 	int i;
415926deccbSFrançois Tigeot 
416926deccbSFrançois Tigeot 	list_for_each_entry(conflict, &dev->mode_config.connector_list, head) {
417926deccbSFrançois Tigeot 		if (conflict == connector)
418926deccbSFrançois Tigeot 			continue;
419926deccbSFrançois Tigeot 
420926deccbSFrançois Tigeot 		radeon_conflict = to_radeon_connector(conflict);
421926deccbSFrançois Tigeot 		for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
422926deccbSFrançois Tigeot 			if (conflict->encoder_ids[i] == 0)
423926deccbSFrançois Tigeot 				break;
424926deccbSFrançois Tigeot 
425926deccbSFrançois Tigeot 			/* if the IDs match */
426926deccbSFrançois Tigeot 			if (conflict->encoder_ids[i] == encoder->base.id) {
427926deccbSFrançois Tigeot 				if (conflict->status != connector_status_connected)
428926deccbSFrançois Tigeot 					continue;
429926deccbSFrançois Tigeot 
430926deccbSFrançois Tigeot 				if (radeon_conflict->use_digital)
431926deccbSFrançois Tigeot 					continue;
432926deccbSFrançois Tigeot 
433926deccbSFrançois Tigeot 				if (priority == true) {
434ba55f2f5SFrançois Tigeot 					DRM_DEBUG_KMS("1: conflicting encoders switching off %s\n",
435ba55f2f5SFrançois Tigeot 						      conflict->name);
436ba55f2f5SFrançois Tigeot 					DRM_DEBUG_KMS("in favor of %s\n",
437ba55f2f5SFrançois Tigeot 						      connector->name);
438926deccbSFrançois Tigeot 					conflict->status = connector_status_disconnected;
439926deccbSFrançois Tigeot 					radeon_connector_update_scratch_regs(conflict, connector_status_disconnected);
440926deccbSFrançois Tigeot 				} else {
441ba55f2f5SFrançois Tigeot 					DRM_DEBUG_KMS("2: conflicting encoders switching off %s\n",
442ba55f2f5SFrançois Tigeot 						      connector->name);
443ba55f2f5SFrançois Tigeot 					DRM_DEBUG_KMS("in favor of %s\n",
444ba55f2f5SFrançois Tigeot 						      conflict->name);
445926deccbSFrançois Tigeot 					current_status = connector_status_disconnected;
446926deccbSFrançois Tigeot 				}
447926deccbSFrançois Tigeot 				break;
448926deccbSFrançois Tigeot 			}
449926deccbSFrançois Tigeot 		}
450926deccbSFrançois Tigeot 	}
451926deccbSFrançois Tigeot 	return current_status;
452926deccbSFrançois Tigeot 
453926deccbSFrançois Tigeot }
454926deccbSFrançois Tigeot 
455926deccbSFrançois Tigeot static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encoder)
456926deccbSFrançois Tigeot {
457926deccbSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
458926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
459926deccbSFrançois Tigeot 	struct drm_display_mode *mode = NULL;
460926deccbSFrançois Tigeot 	struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
461926deccbSFrançois Tigeot 
462926deccbSFrançois Tigeot 	if (native_mode->hdisplay != 0 &&
463926deccbSFrançois Tigeot 	    native_mode->vdisplay != 0 &&
464926deccbSFrançois Tigeot 	    native_mode->clock != 0) {
465926deccbSFrançois Tigeot 		mode = drm_mode_duplicate(dev, native_mode);
466926deccbSFrançois Tigeot 		mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
467926deccbSFrançois Tigeot 		drm_mode_set_name(mode);
468926deccbSFrançois Tigeot 
469926deccbSFrançois Tigeot 		DRM_DEBUG_KMS("Adding native panel mode %s\n", mode->name);
470926deccbSFrançois Tigeot 	} else if (native_mode->hdisplay != 0 &&
471926deccbSFrançois Tigeot 		   native_mode->vdisplay != 0) {
472926deccbSFrançois Tigeot 		/* mac laptops without an edid */
473926deccbSFrançois Tigeot 		/* Note that this is not necessarily the exact panel mode,
474926deccbSFrançois Tigeot 		 * but an approximation based on the cvt formula.  For these
475926deccbSFrançois Tigeot 		 * systems we should ideally read the mode info out of the
476926deccbSFrançois Tigeot 		 * registers or add a mode table, but this works and is much
477926deccbSFrançois Tigeot 		 * simpler.
478926deccbSFrançois Tigeot 		 */
479926deccbSFrançois Tigeot 		mode = drm_cvt_mode(dev, native_mode->hdisplay, native_mode->vdisplay, 60, true, false, false);
480926deccbSFrançois Tigeot 		mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
481926deccbSFrançois Tigeot 		DRM_DEBUG_KMS("Adding cvt approximation of native panel mode %s\n", mode->name);
482926deccbSFrançois Tigeot 	}
483926deccbSFrançois Tigeot 	return mode;
484926deccbSFrançois Tigeot }
485926deccbSFrançois Tigeot 
486926deccbSFrançois Tigeot static void radeon_add_common_modes(struct drm_encoder *encoder, struct drm_connector *connector)
487926deccbSFrançois Tigeot {
488926deccbSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
489926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
490926deccbSFrançois Tigeot 	struct drm_display_mode *mode = NULL;
491926deccbSFrançois Tigeot 	struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
492926deccbSFrançois Tigeot 	int i;
493926deccbSFrançois Tigeot 	struct mode_size {
494926deccbSFrançois Tigeot 		int w;
495926deccbSFrançois Tigeot 		int h;
496926deccbSFrançois Tigeot 	} common_modes[17] = {
497926deccbSFrançois Tigeot 		{ 640,  480},
498926deccbSFrançois Tigeot 		{ 720,  480},
499926deccbSFrançois Tigeot 		{ 800,  600},
500926deccbSFrançois Tigeot 		{ 848,  480},
501926deccbSFrançois Tigeot 		{1024,  768},
502926deccbSFrançois Tigeot 		{1152,  768},
503926deccbSFrançois Tigeot 		{1280,  720},
504926deccbSFrançois Tigeot 		{1280,  800},
505926deccbSFrançois Tigeot 		{1280,  854},
506926deccbSFrançois Tigeot 		{1280,  960},
507926deccbSFrançois Tigeot 		{1280, 1024},
508926deccbSFrançois Tigeot 		{1440,  900},
509926deccbSFrançois Tigeot 		{1400, 1050},
510926deccbSFrançois Tigeot 		{1680, 1050},
511926deccbSFrançois Tigeot 		{1600, 1200},
512926deccbSFrançois Tigeot 		{1920, 1080},
513926deccbSFrançois Tigeot 		{1920, 1200}
514926deccbSFrançois Tigeot 	};
515926deccbSFrançois Tigeot 
516926deccbSFrançois Tigeot 	for (i = 0; i < 17; i++) {
517926deccbSFrançois Tigeot 		if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) {
518926deccbSFrançois Tigeot 			if (common_modes[i].w > 1024 ||
519926deccbSFrançois Tigeot 			    common_modes[i].h > 768)
520926deccbSFrançois Tigeot 				continue;
521926deccbSFrançois Tigeot 		}
522926deccbSFrançois Tigeot 		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
523926deccbSFrançois Tigeot 			if (common_modes[i].w > native_mode->hdisplay ||
524926deccbSFrançois Tigeot 			    common_modes[i].h > native_mode->vdisplay ||
525926deccbSFrançois Tigeot 			    (common_modes[i].w == native_mode->hdisplay &&
526926deccbSFrançois Tigeot 			     common_modes[i].h == native_mode->vdisplay))
527926deccbSFrançois Tigeot 				continue;
528926deccbSFrançois Tigeot 		}
529926deccbSFrançois Tigeot 		if (common_modes[i].w < 320 || common_modes[i].h < 200)
530926deccbSFrançois Tigeot 			continue;
531926deccbSFrançois Tigeot 
532926deccbSFrançois Tigeot 		mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false);
533926deccbSFrançois Tigeot 		drm_mode_probed_add(connector, mode);
534926deccbSFrançois Tigeot 	}
535926deccbSFrançois Tigeot }
536926deccbSFrançois Tigeot 
537926deccbSFrançois Tigeot static int radeon_connector_set_property(struct drm_connector *connector, struct drm_property *property,
538926deccbSFrançois Tigeot 				  uint64_t val)
539926deccbSFrançois Tigeot {
540926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
541926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
542926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
543926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
544926deccbSFrançois Tigeot 
545926deccbSFrançois Tigeot 	if (property == rdev->mode_info.coherent_mode_property) {
546926deccbSFrançois Tigeot 		struct radeon_encoder_atom_dig *dig;
547926deccbSFrançois Tigeot 		bool new_coherent_mode;
548926deccbSFrançois Tigeot 
549926deccbSFrançois Tigeot 		/* need to find digital encoder on connector */
550926deccbSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
551926deccbSFrançois Tigeot 		if (!encoder)
552926deccbSFrançois Tigeot 			return 0;
553926deccbSFrançois Tigeot 
554926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
555926deccbSFrançois Tigeot 
556926deccbSFrançois Tigeot 		if (!radeon_encoder->enc_priv)
557926deccbSFrançois Tigeot 			return 0;
558926deccbSFrançois Tigeot 
559926deccbSFrançois Tigeot 		dig = radeon_encoder->enc_priv;
560926deccbSFrançois Tigeot 		new_coherent_mode = val ? true : false;
561926deccbSFrançois Tigeot 		if (dig->coherent_mode != new_coherent_mode) {
562926deccbSFrançois Tigeot 			dig->coherent_mode = new_coherent_mode;
563926deccbSFrançois Tigeot 			radeon_property_change_mode(&radeon_encoder->base);
564926deccbSFrançois Tigeot 		}
565926deccbSFrançois Tigeot 	}
566926deccbSFrançois Tigeot 
5674cd92098Szrj 	if (property == rdev->mode_info.audio_property) {
5684cd92098Szrj 		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
5694cd92098Szrj 		/* need to find digital encoder on connector */
5704cd92098Szrj 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
5714cd92098Szrj 		if (!encoder)
5724cd92098Szrj 			return 0;
5734cd92098Szrj 
5744cd92098Szrj 		radeon_encoder = to_radeon_encoder(encoder);
5754cd92098Szrj 
5764cd92098Szrj 		if (radeon_connector->audio != val) {
5774cd92098Szrj 			radeon_connector->audio = val;
5784cd92098Szrj 			radeon_property_change_mode(&radeon_encoder->base);
5794cd92098Szrj 		}
5804cd92098Szrj 	}
5814cd92098Szrj 
582c6f73aabSFrançois Tigeot 	if (property == rdev->mode_info.dither_property) {
583c6f73aabSFrançois Tigeot 		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
584c6f73aabSFrançois Tigeot 		/* need to find digital encoder on connector */
585c6f73aabSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
586c6f73aabSFrançois Tigeot 		if (!encoder)
587c6f73aabSFrançois Tigeot 			return 0;
588c6f73aabSFrançois Tigeot 
589c6f73aabSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
590c6f73aabSFrançois Tigeot 
591c6f73aabSFrançois Tigeot 		if (radeon_connector->dither != val) {
592c6f73aabSFrançois Tigeot 			radeon_connector->dither = val;
593c6f73aabSFrançois Tigeot 			radeon_property_change_mode(&radeon_encoder->base);
594c6f73aabSFrançois Tigeot 		}
595c6f73aabSFrançois Tigeot 	}
596c6f73aabSFrançois Tigeot 
597926deccbSFrançois Tigeot 	if (property == rdev->mode_info.underscan_property) {
598926deccbSFrançois Tigeot 		/* need to find digital encoder on connector */
599926deccbSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
600926deccbSFrançois Tigeot 		if (!encoder)
601926deccbSFrançois Tigeot 			return 0;
602926deccbSFrançois Tigeot 
603926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
604926deccbSFrançois Tigeot 
605926deccbSFrançois Tigeot 		if (radeon_encoder->underscan_type != val) {
606926deccbSFrançois Tigeot 			radeon_encoder->underscan_type = val;
607926deccbSFrançois Tigeot 			radeon_property_change_mode(&radeon_encoder->base);
608926deccbSFrançois Tigeot 		}
609926deccbSFrançois Tigeot 	}
610926deccbSFrançois Tigeot 
611926deccbSFrançois Tigeot 	if (property == rdev->mode_info.underscan_hborder_property) {
612926deccbSFrançois Tigeot 		/* need to find digital encoder on connector */
613926deccbSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
614926deccbSFrançois Tigeot 		if (!encoder)
615926deccbSFrançois Tigeot 			return 0;
616926deccbSFrançois Tigeot 
617926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
618926deccbSFrançois Tigeot 
619926deccbSFrançois Tigeot 		if (radeon_encoder->underscan_hborder != val) {
620926deccbSFrançois Tigeot 			radeon_encoder->underscan_hborder = val;
621926deccbSFrançois Tigeot 			radeon_property_change_mode(&radeon_encoder->base);
622926deccbSFrançois Tigeot 		}
623926deccbSFrançois Tigeot 	}
624926deccbSFrançois Tigeot 
625926deccbSFrançois Tigeot 	if (property == rdev->mode_info.underscan_vborder_property) {
626926deccbSFrançois Tigeot 		/* need to find digital encoder on connector */
627926deccbSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
628926deccbSFrançois Tigeot 		if (!encoder)
629926deccbSFrançois Tigeot 			return 0;
630926deccbSFrançois Tigeot 
631926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
632926deccbSFrançois Tigeot 
633926deccbSFrançois Tigeot 		if (radeon_encoder->underscan_vborder != val) {
634926deccbSFrançois Tigeot 			radeon_encoder->underscan_vborder = val;
635926deccbSFrançois Tigeot 			radeon_property_change_mode(&radeon_encoder->base);
636926deccbSFrançois Tigeot 		}
637926deccbSFrançois Tigeot 	}
638926deccbSFrançois Tigeot 
639926deccbSFrançois Tigeot 	if (property == rdev->mode_info.tv_std_property) {
640926deccbSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TVDAC);
641926deccbSFrançois Tigeot 		if (!encoder) {
642926deccbSFrançois Tigeot 			encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_DAC);
643926deccbSFrançois Tigeot 		}
644926deccbSFrançois Tigeot 
645926deccbSFrançois Tigeot 		if (!encoder)
646926deccbSFrançois Tigeot 			return 0;
647926deccbSFrançois Tigeot 
648926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
649926deccbSFrançois Tigeot 		if (!radeon_encoder->enc_priv)
650926deccbSFrançois Tigeot 			return 0;
651926deccbSFrançois Tigeot 		if (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom) {
652926deccbSFrançois Tigeot 			struct radeon_encoder_atom_dac *dac_int;
653926deccbSFrançois Tigeot 			dac_int = radeon_encoder->enc_priv;
654926deccbSFrançois Tigeot 			dac_int->tv_std = val;
655926deccbSFrançois Tigeot 		} else {
656926deccbSFrançois Tigeot 			struct radeon_encoder_tv_dac *dac_int;
657926deccbSFrançois Tigeot 			dac_int = radeon_encoder->enc_priv;
658926deccbSFrançois Tigeot 			dac_int->tv_std = val;
659926deccbSFrançois Tigeot 		}
660926deccbSFrançois Tigeot 		radeon_property_change_mode(&radeon_encoder->base);
661926deccbSFrançois Tigeot 	}
662926deccbSFrançois Tigeot 
663926deccbSFrançois Tigeot 	if (property == rdev->mode_info.load_detect_property) {
664926deccbSFrançois Tigeot 		struct radeon_connector *radeon_connector =
665926deccbSFrançois Tigeot 			to_radeon_connector(connector);
666926deccbSFrançois Tigeot 
667926deccbSFrançois Tigeot 		if (val == 0)
668926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = false;
669926deccbSFrançois Tigeot 		else
670926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
671926deccbSFrançois Tigeot 	}
672926deccbSFrançois Tigeot 
673926deccbSFrançois Tigeot 	if (property == rdev->mode_info.tmds_pll_property) {
674926deccbSFrançois Tigeot 		struct radeon_encoder_int_tmds *tmds = NULL;
675926deccbSFrançois Tigeot 		bool ret = false;
676926deccbSFrançois Tigeot 		/* need to find digital encoder on connector */
677926deccbSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
678926deccbSFrançois Tigeot 		if (!encoder)
679926deccbSFrançois Tigeot 			return 0;
680926deccbSFrançois Tigeot 
681926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
682926deccbSFrançois Tigeot 
683926deccbSFrançois Tigeot 		tmds = radeon_encoder->enc_priv;
684926deccbSFrançois Tigeot 		if (!tmds)
685926deccbSFrançois Tigeot 			return 0;
686926deccbSFrançois Tigeot 
687926deccbSFrançois Tigeot 		if (val == 0) {
688926deccbSFrançois Tigeot 			if (rdev->is_atom_bios)
689926deccbSFrançois Tigeot 				ret = radeon_atombios_get_tmds_info(radeon_encoder, tmds);
690926deccbSFrançois Tigeot 			else
691926deccbSFrançois Tigeot 				ret = radeon_legacy_get_tmds_info_from_combios(radeon_encoder, tmds);
692926deccbSFrançois Tigeot 		}
693926deccbSFrançois Tigeot 		if (val == 1 || ret == false) {
694926deccbSFrançois Tigeot 			radeon_legacy_get_tmds_info_from_table(radeon_encoder, tmds);
695926deccbSFrançois Tigeot 		}
696926deccbSFrançois Tigeot 		radeon_property_change_mode(&radeon_encoder->base);
697926deccbSFrançois Tigeot 	}
698926deccbSFrançois Tigeot 
699c6f73aabSFrançois Tigeot 	if (property == dev->mode_config.scaling_mode_property) {
700c6f73aabSFrançois Tigeot 		enum radeon_rmx_type rmx_type;
701c6f73aabSFrançois Tigeot 
702c6f73aabSFrançois Tigeot 		if (connector->encoder)
703c6f73aabSFrançois Tigeot 			radeon_encoder = to_radeon_encoder(connector->encoder);
704c6f73aabSFrançois Tigeot 		else {
705c0e85e96SFrançois Tigeot 			const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
706c6f73aabSFrançois Tigeot 			radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector));
707c6f73aabSFrançois Tigeot 		}
708c6f73aabSFrançois Tigeot 
709c6f73aabSFrançois Tigeot 		switch (val) {
710c6f73aabSFrançois Tigeot 		default:
711c6f73aabSFrançois Tigeot 		case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break;
712c6f73aabSFrançois Tigeot 		case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break;
713c6f73aabSFrançois Tigeot 		case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break;
714c6f73aabSFrançois Tigeot 		case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break;
715c6f73aabSFrançois Tigeot 		}
716c6f73aabSFrançois Tigeot 		if (radeon_encoder->rmx_type == rmx_type)
717c6f73aabSFrançois Tigeot 			return 0;
718c6f73aabSFrançois Tigeot 
719c6f73aabSFrançois Tigeot 		if ((rmx_type != DRM_MODE_SCALE_NONE) &&
720c6f73aabSFrançois Tigeot 		    (radeon_encoder->native_mode.clock == 0))
721c6f73aabSFrançois Tigeot 			return 0;
722c6f73aabSFrançois Tigeot 
723c6f73aabSFrançois Tigeot 		radeon_encoder->rmx_type = rmx_type;
724c6f73aabSFrançois Tigeot 
725c6f73aabSFrançois Tigeot 		radeon_property_change_mode(&radeon_encoder->base);
726c6f73aabSFrançois Tigeot 	}
727c6f73aabSFrançois Tigeot 
728926deccbSFrançois Tigeot 	return 0;
729926deccbSFrançois Tigeot }
730926deccbSFrançois Tigeot 
731926deccbSFrançois Tigeot static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder,
732926deccbSFrançois Tigeot 					  struct drm_connector *connector)
733926deccbSFrançois Tigeot {
734926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder =	to_radeon_encoder(encoder);
735926deccbSFrançois Tigeot 	struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
736926deccbSFrançois Tigeot 	struct drm_display_mode *t, *mode;
737926deccbSFrançois Tigeot 
738926deccbSFrançois Tigeot 	/* If the EDID preferred mode doesn't match the native mode, use it */
739926deccbSFrançois Tigeot 	list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
740926deccbSFrançois Tigeot 		if (mode->type & DRM_MODE_TYPE_PREFERRED) {
741926deccbSFrançois Tigeot 			if (mode->hdisplay != native_mode->hdisplay ||
742926deccbSFrançois Tigeot 			    mode->vdisplay != native_mode->vdisplay)
743926deccbSFrançois Tigeot 				memcpy(native_mode, mode, sizeof(*mode));
744926deccbSFrançois Tigeot 		}
745926deccbSFrançois Tigeot 	}
746926deccbSFrançois Tigeot 
747926deccbSFrançois Tigeot 	/* Try to get native mode details from EDID if necessary */
748926deccbSFrançois Tigeot 	if (!native_mode->clock) {
749926deccbSFrançois Tigeot 		list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
750926deccbSFrançois Tigeot 			if (mode->hdisplay == native_mode->hdisplay &&
751926deccbSFrançois Tigeot 			    mode->vdisplay == native_mode->vdisplay) {
752926deccbSFrançois Tigeot 				*native_mode = *mode;
753926deccbSFrançois Tigeot 				drm_mode_set_crtcinfo(native_mode, CRTC_INTERLACE_HALVE_V);
754926deccbSFrançois Tigeot 				DRM_DEBUG_KMS("Determined LVDS native mode details from EDID\n");
755926deccbSFrançois Tigeot 				break;
756926deccbSFrançois Tigeot 			}
757926deccbSFrançois Tigeot 		}
758926deccbSFrançois Tigeot 	}
759926deccbSFrançois Tigeot 
760926deccbSFrançois Tigeot 	if (!native_mode->clock) {
761926deccbSFrançois Tigeot 		DRM_DEBUG_KMS("No LVDS native mode details, disabling RMX\n");
762926deccbSFrançois Tigeot 		radeon_encoder->rmx_type = RMX_OFF;
763926deccbSFrançois Tigeot 	}
764926deccbSFrançois Tigeot }
765926deccbSFrançois Tigeot 
766926deccbSFrançois Tigeot static int radeon_lvds_get_modes(struct drm_connector *connector)
767926deccbSFrançois Tigeot {
768ee479021SImre Vadász 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
769926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
770926deccbSFrançois Tigeot 	int ret = 0;
771926deccbSFrançois Tigeot 	struct drm_display_mode *mode;
772926deccbSFrançois Tigeot 
773ee479021SImre Vadász 	if (radeon_connector->ddc_bus) {
774ee479021SImre Vadász 		radeon_connector_get_edid(radeon_connector);
775ee479021SImre Vadász 		ret = radeon_ddc_get_modes(radeon_connector);
776926deccbSFrançois Tigeot 		if (ret > 0) {
777926deccbSFrançois Tigeot 			encoder = radeon_best_single_encoder(connector);
778926deccbSFrançois Tigeot 			if (encoder) {
779926deccbSFrançois Tigeot 				radeon_fixup_lvds_native_mode(encoder, connector);
780926deccbSFrançois Tigeot 				/* add scaled modes */
781926deccbSFrançois Tigeot 				radeon_add_common_modes(encoder, connector);
782926deccbSFrançois Tigeot 			}
783926deccbSFrançois Tigeot 			return ret;
784926deccbSFrançois Tigeot 		}
785ee479021SImre Vadász 	}
786926deccbSFrançois Tigeot 
787926deccbSFrançois Tigeot 	encoder = radeon_best_single_encoder(connector);
788926deccbSFrançois Tigeot 	if (!encoder)
789926deccbSFrançois Tigeot 		return 0;
790926deccbSFrançois Tigeot 
791926deccbSFrançois Tigeot 	/* we have no EDID modes */
792926deccbSFrançois Tigeot 	mode = radeon_fp_native_mode(encoder);
793926deccbSFrançois Tigeot 	if (mode) {
794926deccbSFrançois Tigeot 		ret = 1;
795926deccbSFrançois Tigeot 		drm_mode_probed_add(connector, mode);
796926deccbSFrançois Tigeot 		/* add the width/height from vbios tables if available */
797926deccbSFrançois Tigeot 		connector->display_info.width_mm = mode->width_mm;
798926deccbSFrançois Tigeot 		connector->display_info.height_mm = mode->height_mm;
799926deccbSFrançois Tigeot 		/* add scaled modes */
800926deccbSFrançois Tigeot 		radeon_add_common_modes(encoder, connector);
801926deccbSFrançois Tigeot 	}
802926deccbSFrançois Tigeot 
803926deccbSFrançois Tigeot 	return ret;
804926deccbSFrançois Tigeot }
805926deccbSFrançois Tigeot 
806926deccbSFrançois Tigeot static int radeon_lvds_mode_valid(struct drm_connector *connector,
807926deccbSFrançois Tigeot 				  struct drm_display_mode *mode)
808926deccbSFrançois Tigeot {
809926deccbSFrançois Tigeot 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
810926deccbSFrançois Tigeot 
811926deccbSFrançois Tigeot 	if ((mode->hdisplay < 320) || (mode->vdisplay < 240))
812926deccbSFrançois Tigeot 		return MODE_PANEL;
813926deccbSFrançois Tigeot 
814926deccbSFrançois Tigeot 	if (encoder) {
815926deccbSFrançois Tigeot 		struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
816926deccbSFrançois Tigeot 		struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
817926deccbSFrançois Tigeot 
818926deccbSFrançois Tigeot 		/* AVIVO hardware supports downscaling modes larger than the panel
819926deccbSFrançois Tigeot 		 * to the panel size, but I'm not sure this is desirable.
820926deccbSFrançois Tigeot 		 */
821926deccbSFrançois Tigeot 		if ((mode->hdisplay > native_mode->hdisplay) ||
822926deccbSFrançois Tigeot 		    (mode->vdisplay > native_mode->vdisplay))
823926deccbSFrançois Tigeot 			return MODE_PANEL;
824926deccbSFrançois Tigeot 
825926deccbSFrançois Tigeot 		/* if scaling is disabled, block non-native modes */
826926deccbSFrançois Tigeot 		if (radeon_encoder->rmx_type == RMX_OFF) {
827926deccbSFrançois Tigeot 			if ((mode->hdisplay != native_mode->hdisplay) ||
828926deccbSFrançois Tigeot 			    (mode->vdisplay != native_mode->vdisplay))
829926deccbSFrançois Tigeot 				return MODE_PANEL;
830926deccbSFrançois Tigeot 		}
831926deccbSFrançois Tigeot 	}
832926deccbSFrançois Tigeot 
833926deccbSFrançois Tigeot 	return MODE_OK;
834926deccbSFrançois Tigeot }
835926deccbSFrançois Tigeot 
836926deccbSFrançois Tigeot static enum drm_connector_status
837926deccbSFrançois Tigeot radeon_lvds_detect(struct drm_connector *connector, bool force)
838926deccbSFrançois Tigeot {
839*1cfef1a5SFrançois Tigeot 	struct drm_device *dev = connector->dev;
840*1cfef1a5SFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
841926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
842926deccbSFrançois Tigeot 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
843926deccbSFrançois Tigeot 	enum drm_connector_status ret = connector_status_disconnected;
844c6f73aabSFrançois Tigeot #ifdef PM_TODO
845c6f73aabSFrançois Tigeot 	int r;
846c6f73aabSFrançois Tigeot 
847c6f73aabSFrançois Tigeot 	r = pm_runtime_get_sync(connector->dev->dev);
848c6f73aabSFrançois Tigeot 	if (r < 0)
849c6f73aabSFrançois Tigeot 		return connector_status_disconnected;
850c6f73aabSFrançois Tigeot #endif
851926deccbSFrançois Tigeot 
852926deccbSFrançois Tigeot 	if (encoder) {
853926deccbSFrançois Tigeot 		struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
854926deccbSFrançois Tigeot 		struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
855926deccbSFrançois Tigeot 
856926deccbSFrançois Tigeot 		/* check if panel is valid */
857926deccbSFrançois Tigeot 		if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
858926deccbSFrançois Tigeot 			ret = connector_status_connected;
859*1cfef1a5SFrançois Tigeot 		/* don't fetch the edid from the vbios if ddc fails and runpm is
860*1cfef1a5SFrançois Tigeot 		 * enabled so we report disconnected.
861*1cfef1a5SFrançois Tigeot 		 */
862*1cfef1a5SFrançois Tigeot 		if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0))
863*1cfef1a5SFrançois Tigeot 			ret = connector_status_disconnected;
864926deccbSFrançois Tigeot 	}
865926deccbSFrançois Tigeot 
866926deccbSFrançois Tigeot 	/* check for edid as well */
867ee479021SImre Vadász 	radeon_connector_get_edid(radeon_connector);
868926deccbSFrançois Tigeot 	if (radeon_connector->edid)
869926deccbSFrançois Tigeot 		ret = connector_status_connected;
870926deccbSFrançois Tigeot 	else {
871926deccbSFrançois Tigeot 		if (radeon_connector->ddc_bus) {
8729f4ca867SFrançois Tigeot 			radeon_connector->edid = drm_get_edid_iic(&radeon_connector->base,
873ee479021SImre Vadász 							      radeon_connector->ddc_bus->adapter);
874926deccbSFrançois Tigeot 			if (radeon_connector->edid)
875926deccbSFrançois Tigeot 				ret = connector_status_connected;
876926deccbSFrançois Tigeot 		}
877926deccbSFrançois Tigeot 	}
878926deccbSFrançois Tigeot 	/* check acpi lid status ??? */
879926deccbSFrançois Tigeot 
880926deccbSFrançois Tigeot 	radeon_connector_update_scratch_regs(connector, ret);
881c6f73aabSFrançois Tigeot #ifdef PM_TODO
882c6f73aabSFrançois Tigeot 	pm_runtime_mark_last_busy(connector->dev->dev);
883c6f73aabSFrançois Tigeot 	pm_runtime_put_autosuspend(connector->dev->dev);
884c6f73aabSFrançois Tigeot #endif
885926deccbSFrançois Tigeot 	return ret;
886926deccbSFrançois Tigeot }
887926deccbSFrançois Tigeot 
888926deccbSFrançois Tigeot static void radeon_connector_destroy(struct drm_connector *connector)
889926deccbSFrançois Tigeot {
890926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
891926deccbSFrançois Tigeot 
892ee479021SImre Vadász 	radeon_connector_free_edid(radeon_connector);
893c4ef309bSzrj 	kfree(radeon_connector->con_priv);
894c6f73aabSFrançois Tigeot 	drm_connector_unregister(connector);
895926deccbSFrançois Tigeot 	drm_connector_cleanup(connector);
896c4ef309bSzrj 	kfree(connector);
897926deccbSFrançois Tigeot }
898926deccbSFrançois Tigeot 
899926deccbSFrançois Tigeot static int radeon_lvds_set_property(struct drm_connector *connector,
900926deccbSFrançois Tigeot 				    struct drm_property *property,
901926deccbSFrançois Tigeot 				    uint64_t value)
902926deccbSFrançois Tigeot {
903926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
904926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
905926deccbSFrançois Tigeot 	enum radeon_rmx_type rmx_type;
906926deccbSFrançois Tigeot 
907926deccbSFrançois Tigeot 	DRM_DEBUG_KMS("\n");
908926deccbSFrançois Tigeot 	if (property != dev->mode_config.scaling_mode_property)
909926deccbSFrançois Tigeot 		return 0;
910926deccbSFrançois Tigeot 
911926deccbSFrançois Tigeot 	if (connector->encoder)
912926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(connector->encoder);
913926deccbSFrançois Tigeot 	else {
914c0e85e96SFrançois Tigeot 		const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
915926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector));
916926deccbSFrançois Tigeot 	}
917926deccbSFrançois Tigeot 
918926deccbSFrançois Tigeot 	switch (value) {
919926deccbSFrançois Tigeot 	case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break;
920926deccbSFrançois Tigeot 	case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break;
921926deccbSFrançois Tigeot 	case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break;
922926deccbSFrançois Tigeot 	default:
923926deccbSFrançois Tigeot 	case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break;
924926deccbSFrançois Tigeot 	}
925926deccbSFrançois Tigeot 	if (radeon_encoder->rmx_type == rmx_type)
926926deccbSFrançois Tigeot 		return 0;
927926deccbSFrançois Tigeot 
928926deccbSFrançois Tigeot 	radeon_encoder->rmx_type = rmx_type;
929926deccbSFrançois Tigeot 
930926deccbSFrançois Tigeot 	radeon_property_change_mode(&radeon_encoder->base);
931926deccbSFrançois Tigeot 	return 0;
932926deccbSFrançois Tigeot }
933926deccbSFrançois Tigeot 
934926deccbSFrançois Tigeot 
935926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_lvds_connector_helper_funcs = {
936926deccbSFrançois Tigeot 	.get_modes = radeon_lvds_get_modes,
937926deccbSFrançois Tigeot 	.mode_valid = radeon_lvds_mode_valid,
938926deccbSFrançois Tigeot 	.best_encoder = radeon_best_single_encoder,
939926deccbSFrançois Tigeot };
940926deccbSFrançois Tigeot 
941926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_lvds_connector_funcs = {
942926deccbSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
943926deccbSFrançois Tigeot 	.detect = radeon_lvds_detect,
944926deccbSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
945926deccbSFrançois Tigeot 	.destroy = radeon_connector_destroy,
946926deccbSFrançois Tigeot 	.set_property = radeon_lvds_set_property,
947926deccbSFrançois Tigeot };
948926deccbSFrançois Tigeot 
949926deccbSFrançois Tigeot static int radeon_vga_get_modes(struct drm_connector *connector)
950926deccbSFrançois Tigeot {
951ee479021SImre Vadász 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
952926deccbSFrançois Tigeot 	int ret;
953926deccbSFrançois Tigeot 
954ee479021SImre Vadász 	radeon_connector_get_edid(radeon_connector);
955ee479021SImre Vadász 	ret = radeon_ddc_get_modes(radeon_connector);
956926deccbSFrançois Tigeot 
957c6f73aabSFrançois Tigeot 	radeon_get_native_mode(connector);
958c6f73aabSFrançois Tigeot 
959926deccbSFrançois Tigeot 	return ret;
960926deccbSFrançois Tigeot }
961926deccbSFrançois Tigeot 
962926deccbSFrançois Tigeot static int radeon_vga_mode_valid(struct drm_connector *connector,
963926deccbSFrançois Tigeot 				  struct drm_display_mode *mode)
964926deccbSFrançois Tigeot {
965926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
966926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
967926deccbSFrançois Tigeot 
968926deccbSFrançois Tigeot 	/* XXX check mode bandwidth */
969926deccbSFrançois Tigeot 
970926deccbSFrançois Tigeot 	if ((mode->clock / 10) > rdev->clock.max_pixel_clock)
971926deccbSFrançois Tigeot 		return MODE_CLOCK_HIGH;
972926deccbSFrançois Tigeot 
973926deccbSFrançois Tigeot 	return MODE_OK;
974926deccbSFrançois Tigeot }
975926deccbSFrançois Tigeot 
976926deccbSFrançois Tigeot static enum drm_connector_status
977926deccbSFrançois Tigeot radeon_vga_detect(struct drm_connector *connector, bool force)
978926deccbSFrançois Tigeot {
979926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
980926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
981926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
982926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
983c0e85e96SFrançois Tigeot 	const struct drm_encoder_helper_funcs *encoder_funcs;
984926deccbSFrançois Tigeot 	bool dret = false;
985926deccbSFrançois Tigeot 	enum drm_connector_status ret = connector_status_disconnected;
986c6f73aabSFrançois Tigeot #ifdef PM_TODO
987c6f73aabSFrançois Tigeot 	int r;
988c6f73aabSFrançois Tigeot 
989c6f73aabSFrançois Tigeot 	r = pm_runtime_get_sync(connector->dev->dev);
990c6f73aabSFrançois Tigeot 	if (r < 0)
991c6f73aabSFrançois Tigeot 		return connector_status_disconnected;
992c6f73aabSFrançois Tigeot #endif
993926deccbSFrançois Tigeot 
994926deccbSFrançois Tigeot 	encoder = radeon_best_single_encoder(connector);
995926deccbSFrançois Tigeot 	if (!encoder)
996926deccbSFrançois Tigeot 		ret = connector_status_disconnected;
997926deccbSFrançois Tigeot 
998926deccbSFrançois Tigeot 	if (radeon_connector->ddc_bus)
999926deccbSFrançois Tigeot 		dret = radeon_ddc_probe(radeon_connector, false);
1000926deccbSFrançois Tigeot 	if (dret) {
1001926deccbSFrançois Tigeot 		radeon_connector->detected_by_load = false;
1002ee479021SImre Vadász 		radeon_connector_free_edid(radeon_connector);
1003ee479021SImre Vadász 		radeon_connector_get_edid(radeon_connector);
1004926deccbSFrançois Tigeot 
1005926deccbSFrançois Tigeot 		if (!radeon_connector->edid) {
1006926deccbSFrançois Tigeot 			DRM_ERROR("%s: probed a monitor but no|invalid EDID\n",
1007ba55f2f5SFrançois Tigeot 					connector->name);
1008926deccbSFrançois Tigeot 			ret = connector_status_connected;
1009926deccbSFrançois Tigeot 		} else {
10107191d616Szrj 			radeon_connector->use_digital =
10117191d616Szrj 				!!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
1012926deccbSFrançois Tigeot 
1013926deccbSFrançois Tigeot 			/* some oems have boards with separate digital and analog connectors
1014926deccbSFrançois Tigeot 			 * with a shared ddc line (often vga + hdmi)
1015926deccbSFrançois Tigeot 			 */
1016926deccbSFrançois Tigeot 			if (radeon_connector->use_digital && radeon_connector->shared_ddc) {
1017ee479021SImre Vadász 				radeon_connector_free_edid(radeon_connector);
1018926deccbSFrançois Tigeot 				ret = connector_status_disconnected;
10197191d616Szrj 			} else {
1020926deccbSFrançois Tigeot 				ret = connector_status_connected;
1021926deccbSFrançois Tigeot 			}
10227191d616Szrj 		}
1023926deccbSFrançois Tigeot 	} else {
1024926deccbSFrançois Tigeot 
1025926deccbSFrançois Tigeot 		/* if we aren't forcing don't do destructive polling */
1026926deccbSFrançois Tigeot 		if (!force) {
1027926deccbSFrançois Tigeot 			/* only return the previous status if we last
1028926deccbSFrançois Tigeot 			 * detected a monitor via load.
1029926deccbSFrançois Tigeot 			 */
1030926deccbSFrançois Tigeot 			if (radeon_connector->detected_by_load)
1031c6f73aabSFrançois Tigeot 				ret = connector->status;
1032c6f73aabSFrançois Tigeot 			goto out;
1033926deccbSFrançois Tigeot 		}
1034926deccbSFrançois Tigeot 
1035926deccbSFrançois Tigeot 		if (radeon_connector->dac_load_detect && encoder) {
1036926deccbSFrançois Tigeot 			encoder_funcs = encoder->helper_private;
1037926deccbSFrançois Tigeot 			ret = encoder_funcs->detect(encoder, connector);
1038926deccbSFrançois Tigeot 			if (ret != connector_status_disconnected)
1039926deccbSFrançois Tigeot 				radeon_connector->detected_by_load = true;
1040926deccbSFrançois Tigeot 		}
1041926deccbSFrançois Tigeot 	}
1042926deccbSFrançois Tigeot 
1043926deccbSFrançois Tigeot 	if (ret == connector_status_connected)
1044926deccbSFrançois Tigeot 		ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true);
1045926deccbSFrançois Tigeot 
1046926deccbSFrançois Tigeot 	/* RN50 and some RV100 asics in servers often have a hardcoded EDID in the
1047926deccbSFrançois Tigeot 	 * vbios to deal with KVMs. If we have one and are not able to detect a monitor
1048926deccbSFrançois Tigeot 	 * by other means, assume the CRT is connected and use that EDID.
1049926deccbSFrançois Tigeot 	 */
1050926deccbSFrançois Tigeot 	if ((!rdev->is_atom_bios) &&
1051926deccbSFrançois Tigeot 	    (ret == connector_status_disconnected) &&
1052926deccbSFrançois Tigeot 	    rdev->mode_info.bios_hardcoded_edid_size) {
1053926deccbSFrançois Tigeot 		ret = connector_status_connected;
1054926deccbSFrançois Tigeot 	}
1055926deccbSFrançois Tigeot 
1056926deccbSFrançois Tigeot 	radeon_connector_update_scratch_regs(connector, ret);
1057c6f73aabSFrançois Tigeot 
1058c6f73aabSFrançois Tigeot out:
1059c6f73aabSFrançois Tigeot #ifdef PM_TODO
1060c6f73aabSFrançois Tigeot 	pm_runtime_mark_last_busy(connector->dev->dev);
1061c6f73aabSFrançois Tigeot 	pm_runtime_put_autosuspend(connector->dev->dev);
1062c6f73aabSFrançois Tigeot #endif
1063c6f73aabSFrançois Tigeot 
1064926deccbSFrançois Tigeot 	return ret;
1065926deccbSFrançois Tigeot }
1066926deccbSFrançois Tigeot 
1067926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_vga_connector_helper_funcs = {
1068926deccbSFrançois Tigeot 	.get_modes = radeon_vga_get_modes,
1069926deccbSFrançois Tigeot 	.mode_valid = radeon_vga_mode_valid,
1070926deccbSFrançois Tigeot 	.best_encoder = radeon_best_single_encoder,
1071926deccbSFrançois Tigeot };
1072926deccbSFrançois Tigeot 
1073926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_vga_connector_funcs = {
1074926deccbSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
1075926deccbSFrançois Tigeot 	.detect = radeon_vga_detect,
1076926deccbSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
1077926deccbSFrançois Tigeot 	.destroy = radeon_connector_destroy,
1078926deccbSFrançois Tigeot 	.set_property = radeon_connector_set_property,
1079926deccbSFrançois Tigeot };
1080926deccbSFrançois Tigeot 
1081926deccbSFrançois Tigeot static int radeon_tv_get_modes(struct drm_connector *connector)
1082926deccbSFrançois Tigeot {
1083926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1084926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1085926deccbSFrançois Tigeot 	struct drm_display_mode *tv_mode;
1086926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1087926deccbSFrançois Tigeot 
1088926deccbSFrançois Tigeot 	encoder = radeon_best_single_encoder(connector);
1089926deccbSFrançois Tigeot 	if (!encoder)
1090926deccbSFrançois Tigeot 		return 0;
1091926deccbSFrançois Tigeot 
1092926deccbSFrançois Tigeot 	/* avivo chips can scale any mode */
1093926deccbSFrançois Tigeot 	if (rdev->family >= CHIP_RS600)
1094926deccbSFrançois Tigeot 		/* add scaled modes */
1095926deccbSFrançois Tigeot 		radeon_add_common_modes(encoder, connector);
1096926deccbSFrançois Tigeot 	else {
1097926deccbSFrançois Tigeot 		/* only 800x600 is supported right now on pre-avivo chips */
1098926deccbSFrançois Tigeot 		tv_mode = drm_cvt_mode(dev, 800, 600, 60, false, false, false);
1099926deccbSFrançois Tigeot 		tv_mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
1100926deccbSFrançois Tigeot 		drm_mode_probed_add(connector, tv_mode);
1101926deccbSFrançois Tigeot 	}
1102926deccbSFrançois Tigeot 	return 1;
1103926deccbSFrançois Tigeot }
1104926deccbSFrançois Tigeot 
1105926deccbSFrançois Tigeot static int radeon_tv_mode_valid(struct drm_connector *connector,
1106926deccbSFrançois Tigeot 				struct drm_display_mode *mode)
1107926deccbSFrançois Tigeot {
1108926deccbSFrançois Tigeot 	if ((mode->hdisplay > 1024) || (mode->vdisplay > 768))
1109926deccbSFrançois Tigeot 		return MODE_CLOCK_RANGE;
1110926deccbSFrançois Tigeot 	return MODE_OK;
1111926deccbSFrançois Tigeot }
1112926deccbSFrançois Tigeot 
1113926deccbSFrançois Tigeot static enum drm_connector_status
1114926deccbSFrançois Tigeot radeon_tv_detect(struct drm_connector *connector, bool force)
1115926deccbSFrançois Tigeot {
1116926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1117c0e85e96SFrançois Tigeot 	const struct drm_encoder_helper_funcs *encoder_funcs;
1118926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1119926deccbSFrançois Tigeot 	enum drm_connector_status ret = connector_status_disconnected;
1120c6f73aabSFrançois Tigeot #ifdef PM_TODO
1121c6f73aabSFrançois Tigeot 	int r;
1122c6f73aabSFrançois Tigeot #endif
1123926deccbSFrançois Tigeot 
1124926deccbSFrançois Tigeot 	if (!radeon_connector->dac_load_detect)
1125926deccbSFrançois Tigeot 		return ret;
1126926deccbSFrançois Tigeot 
1127c6f73aabSFrançois Tigeot #ifdef PM_TODO
1128c6f73aabSFrançois Tigeot 	r = pm_runtime_get_sync(connector->dev->dev);
1129c6f73aabSFrançois Tigeot 	if (r < 0)
1130c6f73aabSFrançois Tigeot 		return connector_status_disconnected;
1131c6f73aabSFrançois Tigeot #endif
1132c6f73aabSFrançois Tigeot 
1133926deccbSFrançois Tigeot 	encoder = radeon_best_single_encoder(connector);
1134926deccbSFrançois Tigeot 	if (!encoder)
1135926deccbSFrançois Tigeot 		ret = connector_status_disconnected;
1136926deccbSFrançois Tigeot 	else {
1137926deccbSFrançois Tigeot 		encoder_funcs = encoder->helper_private;
1138926deccbSFrançois Tigeot 		ret = encoder_funcs->detect(encoder, connector);
1139926deccbSFrançois Tigeot 	}
1140926deccbSFrançois Tigeot 	if (ret == connector_status_connected)
1141926deccbSFrançois Tigeot 		ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false);
1142926deccbSFrançois Tigeot 	radeon_connector_update_scratch_regs(connector, ret);
1143c6f73aabSFrançois Tigeot #ifdef PM_TODO
1144c6f73aabSFrançois Tigeot 	pm_runtime_mark_last_busy(connector->dev->dev);
1145c6f73aabSFrançois Tigeot 	pm_runtime_put_autosuspend(connector->dev->dev);
1146c6f73aabSFrançois Tigeot #endif
1147926deccbSFrançois Tigeot 	return ret;
1148926deccbSFrançois Tigeot }
1149926deccbSFrançois Tigeot 
1150926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_tv_connector_helper_funcs = {
1151926deccbSFrançois Tigeot 	.get_modes = radeon_tv_get_modes,
1152926deccbSFrançois Tigeot 	.mode_valid = radeon_tv_mode_valid,
1153926deccbSFrançois Tigeot 	.best_encoder = radeon_best_single_encoder,
1154926deccbSFrançois Tigeot };
1155926deccbSFrançois Tigeot 
1156926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_tv_connector_funcs = {
1157926deccbSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
1158926deccbSFrançois Tigeot 	.detect = radeon_tv_detect,
1159926deccbSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
1160926deccbSFrançois Tigeot 	.destroy = radeon_connector_destroy,
1161926deccbSFrançois Tigeot 	.set_property = radeon_connector_set_property,
1162926deccbSFrançois Tigeot };
1163926deccbSFrançois Tigeot 
1164926deccbSFrançois Tigeot static bool radeon_check_hpd_status_unchanged(struct drm_connector *connector)
1165926deccbSFrançois Tigeot {
1166926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1167926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1168926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1169926deccbSFrançois Tigeot 	enum drm_connector_status status;
1170926deccbSFrançois Tigeot 
1171926deccbSFrançois Tigeot 	/* We only trust HPD on R600 and newer ASICS. */
1172926deccbSFrançois Tigeot 	if (rdev->family >= CHIP_R600
1173926deccbSFrançois Tigeot 	  && radeon_connector->hpd.hpd != RADEON_HPD_NONE) {
1174926deccbSFrançois Tigeot 		if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
1175926deccbSFrançois Tigeot 			status = connector_status_connected;
1176926deccbSFrançois Tigeot 		else
1177926deccbSFrançois Tigeot 			status = connector_status_disconnected;
1178926deccbSFrançois Tigeot 		if (connector->status == status)
1179926deccbSFrançois Tigeot 			return true;
1180926deccbSFrançois Tigeot 	}
1181926deccbSFrançois Tigeot 
1182926deccbSFrançois Tigeot 	return false;
1183926deccbSFrançois Tigeot }
1184926deccbSFrançois Tigeot 
1185926deccbSFrançois Tigeot /*
1186926deccbSFrançois Tigeot  * DVI is complicated
1187926deccbSFrançois Tigeot  * Do a DDC probe, if DDC probe passes, get the full EDID so
1188926deccbSFrançois Tigeot  * we can do analog/digital monitor detection at this point.
1189926deccbSFrançois Tigeot  * If the monitor is an analog monitor or we got no DDC,
1190926deccbSFrançois Tigeot  * we need to find the DAC encoder object for this connector.
1191926deccbSFrançois Tigeot  * If we got no DDC, we do load detection on the DAC encoder object.
1192926deccbSFrançois Tigeot  * If we got analog DDC or load detection passes on the DAC encoder
1193926deccbSFrançois Tigeot  * we have to check if this analog encoder is shared with anyone else (TV)
1194926deccbSFrançois Tigeot  * if its shared we have to set the other connector to disconnected.
1195926deccbSFrançois Tigeot  */
1196926deccbSFrançois Tigeot static enum drm_connector_status
1197926deccbSFrançois Tigeot radeon_dvi_detect(struct drm_connector *connector, bool force)
1198926deccbSFrançois Tigeot {
1199926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1200926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1201926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1202926deccbSFrançois Tigeot 	struct drm_encoder *encoder = NULL;
1203c0e85e96SFrançois Tigeot 	const struct drm_encoder_helper_funcs *encoder_funcs;
1204926deccbSFrançois Tigeot 	int i;
1205926deccbSFrançois Tigeot 	enum drm_connector_status ret = connector_status_disconnected;
1206926deccbSFrançois Tigeot 	bool dret = false, broken_edid = false;
1207926deccbSFrançois Tigeot 
1208c6f73aabSFrançois Tigeot #ifdef PM_TODO
1209c6f73aabSFrançois Tigeot 	r = pm_runtime_get_sync(connector->dev->dev);
1210c6f73aabSFrançois Tigeot 	if (r < 0)
1211c6f73aabSFrançois Tigeot 		return connector_status_disconnected;
1212c6f73aabSFrançois Tigeot #endif
1213c6f73aabSFrançois Tigeot 
1214c6f73aabSFrançois Tigeot 	if (!force && radeon_check_hpd_status_unchanged(connector)) {
1215c6f73aabSFrançois Tigeot 		ret = connector->status;
1216c6f73aabSFrançois Tigeot 		goto exit;
1217c6f73aabSFrançois Tigeot 	}
1218926deccbSFrançois Tigeot 
1219926deccbSFrançois Tigeot 	if (radeon_connector->ddc_bus)
1220926deccbSFrançois Tigeot 		dret = radeon_ddc_probe(radeon_connector, false);
1221926deccbSFrançois Tigeot 	if (dret) {
1222926deccbSFrançois Tigeot 		radeon_connector->detected_by_load = false;
1223ee479021SImre Vadász 		radeon_connector_free_edid(radeon_connector);
1224ee479021SImre Vadász 		radeon_connector_get_edid(radeon_connector);
1225926deccbSFrançois Tigeot 
1226926deccbSFrançois Tigeot 		if (!radeon_connector->edid) {
1227926deccbSFrançois Tigeot 			DRM_ERROR("%s: probed a monitor but no|invalid EDID\n",
1228ba55f2f5SFrançois Tigeot 					connector->name);
1229926deccbSFrançois Tigeot 			/* rs690 seems to have a problem with connectors not existing and always
1230926deccbSFrançois Tigeot 			 * return a block of 0's. If we see this just stop polling on this output */
12317191d616Szrj 			if ((rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) &&
12327191d616Szrj 			    radeon_connector->base.null_edid_counter) {
1233926deccbSFrançois Tigeot 				ret = connector_status_disconnected;
1234ba55f2f5SFrançois Tigeot 				DRM_ERROR("%s: detected RS690 floating bus bug, stopping ddc detect\n",
1235ba55f2f5SFrançois Tigeot 					  connector->name);
1236926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = NULL;
1237926deccbSFrançois Tigeot 			} else {
1238926deccbSFrançois Tigeot 				ret = connector_status_connected;
1239926deccbSFrançois Tigeot 				broken_edid = true; /* defer use_digital to later */
1240926deccbSFrançois Tigeot 			}
1241926deccbSFrançois Tigeot 		} else {
12427191d616Szrj 			radeon_connector->use_digital =
12437191d616Szrj 				!!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
1244926deccbSFrançois Tigeot 
1245926deccbSFrançois Tigeot 			/* some oems have boards with separate digital and analog connectors
1246926deccbSFrançois Tigeot 			 * with a shared ddc line (often vga + hdmi)
1247926deccbSFrançois Tigeot 			 */
1248926deccbSFrançois Tigeot 			if ((!radeon_connector->use_digital) && radeon_connector->shared_ddc) {
1249ee479021SImre Vadász 				radeon_connector_free_edid(radeon_connector);
1250926deccbSFrançois Tigeot 				ret = connector_status_disconnected;
12517191d616Szrj 			} else {
1252926deccbSFrançois Tigeot 				ret = connector_status_connected;
12537191d616Szrj 			}
1254926deccbSFrançois Tigeot 			/* This gets complicated.  We have boards with VGA + HDMI with a
1255926deccbSFrançois Tigeot 			 * shared DDC line and we have boards with DVI-D + HDMI with a shared
1256926deccbSFrançois Tigeot 			 * DDC line.  The latter is more complex because with DVI<->HDMI adapters
1257926deccbSFrançois Tigeot 			 * you don't really know what's connected to which port as both are digital.
1258926deccbSFrançois Tigeot 			 */
1259926deccbSFrançois Tigeot 			if (radeon_connector->shared_ddc && (ret == connector_status_connected)) {
1260926deccbSFrançois Tigeot 				struct drm_connector *list_connector;
1261926deccbSFrançois Tigeot 				struct radeon_connector *list_radeon_connector;
1262926deccbSFrançois Tigeot 				list_for_each_entry(list_connector, &dev->mode_config.connector_list, head) {
1263926deccbSFrançois Tigeot 					if (connector == list_connector)
1264926deccbSFrançois Tigeot 						continue;
1265926deccbSFrançois Tigeot 					list_radeon_connector = to_radeon_connector(list_connector);
1266926deccbSFrançois Tigeot 					if (list_radeon_connector->shared_ddc &&
1267926deccbSFrançois Tigeot 					    (list_radeon_connector->ddc_bus->rec.i2c_id ==
1268926deccbSFrançois Tigeot 					     radeon_connector->ddc_bus->rec.i2c_id)) {
1269926deccbSFrançois Tigeot 						/* cases where both connectors are digital */
1270926deccbSFrançois Tigeot 						if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) {
1271926deccbSFrançois Tigeot 							/* hpd is our only option in this case */
1272926deccbSFrançois Tigeot 							if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
1273ee479021SImre Vadász 								radeon_connector_free_edid(radeon_connector);
1274926deccbSFrançois Tigeot 								ret = connector_status_disconnected;
1275926deccbSFrançois Tigeot 							}
1276926deccbSFrançois Tigeot 						}
1277926deccbSFrançois Tigeot 					}
1278926deccbSFrançois Tigeot 				}
1279926deccbSFrançois Tigeot 			}
1280926deccbSFrançois Tigeot 		}
1281926deccbSFrançois Tigeot 	}
1282926deccbSFrançois Tigeot 
1283926deccbSFrançois Tigeot 	if ((ret == connector_status_connected) && (radeon_connector->use_digital == true))
1284926deccbSFrançois Tigeot 		goto out;
1285926deccbSFrançois Tigeot 
1286926deccbSFrançois Tigeot 	/* DVI-D and HDMI-A are digital only */
1287926deccbSFrançois Tigeot 	if ((connector->connector_type == DRM_MODE_CONNECTOR_DVID) ||
1288926deccbSFrançois Tigeot 	    (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA))
1289926deccbSFrançois Tigeot 		goto out;
1290926deccbSFrançois Tigeot 
1291926deccbSFrançois Tigeot 	/* if we aren't forcing don't do destructive polling */
1292926deccbSFrançois Tigeot 	if (!force) {
1293926deccbSFrançois Tigeot 		/* only return the previous status if we last
1294926deccbSFrançois Tigeot 		 * detected a monitor via load.
1295926deccbSFrançois Tigeot 		 */
1296926deccbSFrançois Tigeot 		if (radeon_connector->detected_by_load)
1297926deccbSFrançois Tigeot 			ret = connector->status;
1298926deccbSFrançois Tigeot 		goto out;
1299926deccbSFrançois Tigeot 	}
1300926deccbSFrançois Tigeot 
1301926deccbSFrançois Tigeot 	/* find analog encoder */
1302926deccbSFrançois Tigeot 	if (radeon_connector->dac_load_detect) {
1303926deccbSFrançois Tigeot 		for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1304926deccbSFrançois Tigeot 			if (connector->encoder_ids[i] == 0)
1305926deccbSFrançois Tigeot 				break;
1306926deccbSFrançois Tigeot 
1307c6f73aabSFrançois Tigeot 			encoder = drm_encoder_find(connector->dev,
1308c6f73aabSFrançois Tigeot 						   connector->encoder_ids[i]);
1309c6f73aabSFrançois Tigeot 			if (!encoder)
1310926deccbSFrançois Tigeot 				continue;
1311926deccbSFrançois Tigeot 
1312926deccbSFrançois Tigeot 			if (encoder->encoder_type != DRM_MODE_ENCODER_DAC &&
1313926deccbSFrançois Tigeot 			    encoder->encoder_type != DRM_MODE_ENCODER_TVDAC)
1314926deccbSFrançois Tigeot 				continue;
1315926deccbSFrançois Tigeot 
1316926deccbSFrançois Tigeot 			encoder_funcs = encoder->helper_private;
1317926deccbSFrançois Tigeot 			if (encoder_funcs->detect) {
1318926deccbSFrançois Tigeot 				if (!broken_edid) {
1319926deccbSFrançois Tigeot 					if (ret != connector_status_connected) {
1320926deccbSFrançois Tigeot 						/* deal with analog monitors without DDC */
1321926deccbSFrançois Tigeot 						ret = encoder_funcs->detect(encoder, connector);
1322926deccbSFrançois Tigeot 						if (ret == connector_status_connected) {
1323926deccbSFrançois Tigeot 							radeon_connector->use_digital = false;
1324926deccbSFrançois Tigeot 						}
1325926deccbSFrançois Tigeot 						if (ret != connector_status_disconnected)
1326926deccbSFrançois Tigeot 							radeon_connector->detected_by_load = true;
1327926deccbSFrançois Tigeot 					}
1328926deccbSFrançois Tigeot 				} else {
1329926deccbSFrançois Tigeot 					enum drm_connector_status lret;
1330926deccbSFrançois Tigeot 					/* assume digital unless load detected otherwise */
1331926deccbSFrançois Tigeot 					radeon_connector->use_digital = true;
1332926deccbSFrançois Tigeot 					lret = encoder_funcs->detect(encoder, connector);
1333926deccbSFrançois Tigeot 					DRM_DEBUG_KMS("load_detect %x returned: %x\n",encoder->encoder_type,lret);
1334926deccbSFrançois Tigeot 					if (lret == connector_status_connected)
1335926deccbSFrançois Tigeot 						radeon_connector->use_digital = false;
1336926deccbSFrançois Tigeot 				}
1337926deccbSFrançois Tigeot 				break;
1338926deccbSFrançois Tigeot 			}
1339926deccbSFrançois Tigeot 		}
1340926deccbSFrançois Tigeot 	}
1341926deccbSFrançois Tigeot 
1342926deccbSFrançois Tigeot 	if ((ret == connector_status_connected) && (radeon_connector->use_digital == false) &&
1343926deccbSFrançois Tigeot 	    encoder) {
1344926deccbSFrançois Tigeot 		ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true);
1345926deccbSFrançois Tigeot 	}
1346926deccbSFrançois Tigeot 
1347926deccbSFrançois Tigeot 	/* RN50 and some RV100 asics in servers often have a hardcoded EDID in the
1348926deccbSFrançois Tigeot 	 * vbios to deal with KVMs. If we have one and are not able to detect a monitor
1349926deccbSFrançois Tigeot 	 * by other means, assume the DFP is connected and use that EDID.  In most
1350926deccbSFrançois Tigeot 	 * cases the DVI port is actually a virtual KVM port connected to the service
1351926deccbSFrançois Tigeot 	 * processor.
1352926deccbSFrançois Tigeot 	 */
1353926deccbSFrançois Tigeot out:
1354926deccbSFrançois Tigeot 	if ((!rdev->is_atom_bios) &&
1355926deccbSFrançois Tigeot 	    (ret == connector_status_disconnected) &&
1356926deccbSFrançois Tigeot 	    rdev->mode_info.bios_hardcoded_edid_size) {
1357926deccbSFrançois Tigeot 		radeon_connector->use_digital = true;
1358926deccbSFrançois Tigeot 		ret = connector_status_connected;
1359926deccbSFrançois Tigeot 	}
1360926deccbSFrançois Tigeot 
1361926deccbSFrançois Tigeot 	/* updated in get modes as well since we need to know if it's analog or digital */
1362926deccbSFrançois Tigeot 	radeon_connector_update_scratch_regs(connector, ret);
1363c6f73aabSFrançois Tigeot 
1364c6f73aabSFrançois Tigeot exit:
1365c6f73aabSFrançois Tigeot #ifdef PM_TODO
1366c6f73aabSFrançois Tigeot 	pm_runtime_mark_last_busy(connector->dev->dev);
1367c6f73aabSFrançois Tigeot 	pm_runtime_put_autosuspend(connector->dev->dev);
1368c6f73aabSFrançois Tigeot #endif
1369c6f73aabSFrançois Tigeot 
1370926deccbSFrançois Tigeot 	return ret;
1371926deccbSFrançois Tigeot }
1372926deccbSFrançois Tigeot 
1373926deccbSFrançois Tigeot /* okay need to be smart in here about which encoder to pick */
1374926deccbSFrançois Tigeot static struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector)
1375926deccbSFrançois Tigeot {
1376926deccbSFrançois Tigeot 	int enc_id = connector->encoder_ids[0];
1377926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1378926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1379926deccbSFrançois Tigeot 	int i;
1380926deccbSFrançois Tigeot 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1381926deccbSFrançois Tigeot 		if (connector->encoder_ids[i] == 0)
1382926deccbSFrançois Tigeot 			break;
1383926deccbSFrançois Tigeot 
1384c6f73aabSFrançois Tigeot 		encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
1385c6f73aabSFrançois Tigeot 		if (!encoder)
1386926deccbSFrançois Tigeot 			continue;
1387926deccbSFrançois Tigeot 
1388926deccbSFrançois Tigeot 		if (radeon_connector->use_digital == true) {
1389926deccbSFrançois Tigeot 			if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
1390926deccbSFrançois Tigeot 				return encoder;
1391926deccbSFrançois Tigeot 		} else {
1392926deccbSFrançois Tigeot 			if (encoder->encoder_type == DRM_MODE_ENCODER_DAC ||
1393926deccbSFrançois Tigeot 			    encoder->encoder_type == DRM_MODE_ENCODER_TVDAC)
1394926deccbSFrançois Tigeot 				return encoder;
1395926deccbSFrançois Tigeot 		}
1396926deccbSFrançois Tigeot 	}
1397926deccbSFrançois Tigeot 
1398926deccbSFrançois Tigeot 	/* see if we have a default encoder  TODO */
1399926deccbSFrançois Tigeot 
1400926deccbSFrançois Tigeot 	/* then check use digitial */
1401926deccbSFrançois Tigeot 	/* pick the first one */
1402c6f73aabSFrançois Tigeot 	if (enc_id)
1403c6f73aabSFrançois Tigeot 		return drm_encoder_find(connector->dev, enc_id);
1404926deccbSFrançois Tigeot 	return NULL;
1405926deccbSFrançois Tigeot }
1406926deccbSFrançois Tigeot 
1407926deccbSFrançois Tigeot static void radeon_dvi_force(struct drm_connector *connector)
1408926deccbSFrançois Tigeot {
1409926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1410926deccbSFrançois Tigeot 	if (connector->force == DRM_FORCE_ON)
1411926deccbSFrançois Tigeot 		radeon_connector->use_digital = false;
1412926deccbSFrançois Tigeot 	if (connector->force == DRM_FORCE_ON_DIGITAL)
1413926deccbSFrançois Tigeot 		radeon_connector->use_digital = true;
1414926deccbSFrançois Tigeot }
1415926deccbSFrançois Tigeot 
1416926deccbSFrançois Tigeot static int radeon_dvi_mode_valid(struct drm_connector *connector,
1417926deccbSFrançois Tigeot 				  struct drm_display_mode *mode)
1418926deccbSFrançois Tigeot {
1419926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1420926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1421926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1422926deccbSFrançois Tigeot 
1423926deccbSFrançois Tigeot 	/* XXX check mode bandwidth */
1424926deccbSFrançois Tigeot 
1425926deccbSFrançois Tigeot 	/* clocks over 135 MHz have heat issues with DVI on RV100 */
1426926deccbSFrançois Tigeot 	if (radeon_connector->use_digital &&
1427926deccbSFrançois Tigeot 	    (rdev->family == CHIP_RV100) &&
1428926deccbSFrançois Tigeot 	    (mode->clock > 135000))
1429926deccbSFrançois Tigeot 		return MODE_CLOCK_HIGH;
1430926deccbSFrançois Tigeot 
1431926deccbSFrançois Tigeot 	if (radeon_connector->use_digital && (mode->clock > 165000)) {
1432926deccbSFrançois Tigeot 		if ((radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I) ||
1433926deccbSFrançois Tigeot 		    (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D) ||
1434926deccbSFrançois Tigeot 		    (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_B))
1435926deccbSFrançois Tigeot 			return MODE_OK;
1436c6f73aabSFrançois Tigeot 		else if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
1437926deccbSFrançois Tigeot 			/* HDMI 1.3+ supports max clock of 340 Mhz */
1438926deccbSFrançois Tigeot 			if (mode->clock > 340000)
1439926deccbSFrançois Tigeot 				return MODE_CLOCK_HIGH;
1440926deccbSFrançois Tigeot 			else
1441926deccbSFrançois Tigeot 				return MODE_OK;
1442c6f73aabSFrançois Tigeot 		} else {
1443926deccbSFrançois Tigeot 			return MODE_CLOCK_HIGH;
1444c6f73aabSFrançois Tigeot 		}
1445926deccbSFrançois Tigeot 	}
1446926deccbSFrançois Tigeot 
1447926deccbSFrançois Tigeot 	/* check against the max pixel clock */
1448926deccbSFrançois Tigeot 	if ((mode->clock / 10) > rdev->clock.max_pixel_clock)
1449926deccbSFrançois Tigeot 		return MODE_CLOCK_HIGH;
1450926deccbSFrançois Tigeot 
1451926deccbSFrançois Tigeot 	return MODE_OK;
1452926deccbSFrançois Tigeot }
1453926deccbSFrançois Tigeot 
1454926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = {
1455c6f73aabSFrançois Tigeot 	.get_modes = radeon_vga_get_modes,
1456926deccbSFrançois Tigeot 	.mode_valid = radeon_dvi_mode_valid,
1457926deccbSFrançois Tigeot 	.best_encoder = radeon_dvi_encoder,
1458926deccbSFrançois Tigeot };
1459926deccbSFrançois Tigeot 
1460926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_dvi_connector_funcs = {
1461926deccbSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
1462926deccbSFrançois Tigeot 	.detect = radeon_dvi_detect,
1463926deccbSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
1464926deccbSFrançois Tigeot 	.set_property = radeon_connector_set_property,
1465926deccbSFrançois Tigeot 	.destroy = radeon_connector_destroy,
1466926deccbSFrançois Tigeot 	.force = radeon_dvi_force,
1467926deccbSFrançois Tigeot };
1468926deccbSFrançois Tigeot 
1469ee479021SImre Vadász static void radeon_dp_connector_destroy(struct drm_connector *connector)
1470ee479021SImre Vadász {
1471ee479021SImre Vadász 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1472ee479021SImre Vadász 	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
1473ee479021SImre Vadász 
1474ee479021SImre Vadász 	radeon_connector_free_edid(radeon_connector);
1475ee479021SImre Vadász 	if (radeon_dig_connector->dp_i2c_bus)
1476ee479021SImre Vadász 		radeon_i2c_destroy(radeon_dig_connector->dp_i2c_bus);
1477ee479021SImre Vadász 	kfree(radeon_connector->con_priv);
1478ee479021SImre Vadász 	drm_connector_unregister(connector);
1479ee479021SImre Vadász 	drm_connector_cleanup(connector);
1480ee479021SImre Vadász 	kfree(connector);
1481ee479021SImre Vadász }
1482ee479021SImre Vadász 
1483926deccbSFrançois Tigeot static int radeon_dp_get_modes(struct drm_connector *connector)
1484926deccbSFrançois Tigeot {
1485926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1486926deccbSFrançois Tigeot 	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
1487926deccbSFrançois Tigeot 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
1488926deccbSFrançois Tigeot 	int ret;
1489926deccbSFrançois Tigeot 
1490926deccbSFrançois Tigeot 	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
1491926deccbSFrançois Tigeot 	    (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
1492926deccbSFrançois Tigeot 		struct drm_display_mode *mode;
1493926deccbSFrançois Tigeot 
1494926deccbSFrançois Tigeot 		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
1495926deccbSFrançois Tigeot 			if (!radeon_dig_connector->edp_on)
1496926deccbSFrançois Tigeot 				atombios_set_edp_panel_power(connector,
1497926deccbSFrançois Tigeot 							     ATOM_TRANSMITTER_ACTION_POWER_ON);
1498ee479021SImre Vadász 			radeon_connector_get_edid(radeon_connector);
1499ee479021SImre Vadász 			ret = radeon_ddc_get_modes(radeon_connector);
1500926deccbSFrançois Tigeot 			if (!radeon_dig_connector->edp_on)
1501926deccbSFrançois Tigeot 				atombios_set_edp_panel_power(connector,
1502926deccbSFrançois Tigeot 							     ATOM_TRANSMITTER_ACTION_POWER_OFF);
1503926deccbSFrançois Tigeot 		} else {
1504926deccbSFrançois Tigeot 			/* need to setup ddc on the bridge */
1505926deccbSFrançois Tigeot 			if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
1506926deccbSFrançois Tigeot 			    ENCODER_OBJECT_ID_NONE) {
1507926deccbSFrançois Tigeot 				if (encoder)
1508926deccbSFrançois Tigeot 					radeon_atom_ext_encoder_setup_ddc(encoder);
1509926deccbSFrançois Tigeot 			}
1510ee479021SImre Vadász 			radeon_connector_get_edid(radeon_connector);
1511ee479021SImre Vadász 			ret = radeon_ddc_get_modes(radeon_connector);
1512926deccbSFrançois Tigeot 		}
1513926deccbSFrançois Tigeot 
1514926deccbSFrançois Tigeot 		if (ret > 0) {
1515926deccbSFrançois Tigeot 			if (encoder) {
1516926deccbSFrançois Tigeot 				radeon_fixup_lvds_native_mode(encoder, connector);
1517926deccbSFrançois Tigeot 				/* add scaled modes */
1518926deccbSFrançois Tigeot 				radeon_add_common_modes(encoder, connector);
1519926deccbSFrançois Tigeot 			}
1520926deccbSFrançois Tigeot 			return ret;
1521926deccbSFrançois Tigeot 		}
1522926deccbSFrançois Tigeot 
1523926deccbSFrançois Tigeot 		if (!encoder)
1524926deccbSFrançois Tigeot 			return 0;
1525926deccbSFrançois Tigeot 
1526926deccbSFrançois Tigeot 		/* we have no EDID modes */
1527926deccbSFrançois Tigeot 		mode = radeon_fp_native_mode(encoder);
1528926deccbSFrançois Tigeot 		if (mode) {
1529926deccbSFrançois Tigeot 			ret = 1;
1530926deccbSFrançois Tigeot 			drm_mode_probed_add(connector, mode);
1531926deccbSFrançois Tigeot 			/* add the width/height from vbios tables if available */
1532926deccbSFrançois Tigeot 			connector->display_info.width_mm = mode->width_mm;
1533926deccbSFrançois Tigeot 			connector->display_info.height_mm = mode->height_mm;
1534926deccbSFrançois Tigeot 			/* add scaled modes */
1535926deccbSFrançois Tigeot 			radeon_add_common_modes(encoder, connector);
1536926deccbSFrançois Tigeot 		}
1537926deccbSFrançois Tigeot 	} else {
1538926deccbSFrançois Tigeot 		/* need to setup ddc on the bridge */
1539926deccbSFrançois Tigeot 		if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
1540926deccbSFrançois Tigeot 			ENCODER_OBJECT_ID_NONE) {
1541926deccbSFrançois Tigeot 			if (encoder)
1542926deccbSFrançois Tigeot 				radeon_atom_ext_encoder_setup_ddc(encoder);
1543926deccbSFrançois Tigeot 		}
1544ee479021SImre Vadász 		radeon_connector_get_edid(radeon_connector);
1545ee479021SImre Vadász 		ret = radeon_ddc_get_modes(radeon_connector);
1546c6f73aabSFrançois Tigeot 
1547c6f73aabSFrançois Tigeot 		radeon_get_native_mode(connector);
1548926deccbSFrançois Tigeot 	}
1549926deccbSFrançois Tigeot 
1550926deccbSFrançois Tigeot 	return ret;
1551926deccbSFrançois Tigeot }
1552926deccbSFrançois Tigeot 
1553926deccbSFrançois Tigeot u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector)
1554926deccbSFrançois Tigeot {
1555926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1556926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
1557926deccbSFrançois Tigeot 	int i;
1558926deccbSFrançois Tigeot 
1559926deccbSFrançois Tigeot 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1560926deccbSFrançois Tigeot 		if (connector->encoder_ids[i] == 0)
1561926deccbSFrançois Tigeot 			break;
1562926deccbSFrançois Tigeot 
1563c6f73aabSFrançois Tigeot 		encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
1564c6f73aabSFrançois Tigeot 		if (!encoder)
1565926deccbSFrançois Tigeot 			continue;
1566926deccbSFrançois Tigeot 
1567926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
1568926deccbSFrançois Tigeot 
1569926deccbSFrançois Tigeot 		switch (radeon_encoder->encoder_id) {
1570926deccbSFrançois Tigeot 		case ENCODER_OBJECT_ID_TRAVIS:
1571926deccbSFrançois Tigeot 		case ENCODER_OBJECT_ID_NUTMEG:
1572926deccbSFrançois Tigeot 			return radeon_encoder->encoder_id;
1573926deccbSFrançois Tigeot 		default:
1574926deccbSFrançois Tigeot 			break;
1575926deccbSFrançois Tigeot 		}
1576926deccbSFrançois Tigeot 	}
1577926deccbSFrançois Tigeot 
1578926deccbSFrançois Tigeot 	return ENCODER_OBJECT_ID_NONE;
1579926deccbSFrançois Tigeot }
1580926deccbSFrançois Tigeot 
1581c6f73aabSFrançois Tigeot static bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector)
1582926deccbSFrançois Tigeot {
1583926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1584926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
1585926deccbSFrançois Tigeot 	int i;
1586926deccbSFrançois Tigeot 	bool found = false;
1587926deccbSFrançois Tigeot 
1588926deccbSFrançois Tigeot 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1589926deccbSFrançois Tigeot 		if (connector->encoder_ids[i] == 0)
1590926deccbSFrançois Tigeot 			break;
1591926deccbSFrançois Tigeot 
1592c6f73aabSFrançois Tigeot 		encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
1593c6f73aabSFrançois Tigeot 		if (!encoder)
1594926deccbSFrançois Tigeot 			continue;
1595926deccbSFrançois Tigeot 
1596926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
1597926deccbSFrançois Tigeot 		if (radeon_encoder->caps & ATOM_ENCODER_CAP_RECORD_HBR2)
1598926deccbSFrançois Tigeot 			found = true;
1599926deccbSFrançois Tigeot 	}
1600926deccbSFrançois Tigeot 
1601926deccbSFrançois Tigeot 	return found;
1602926deccbSFrançois Tigeot }
1603926deccbSFrançois Tigeot 
1604926deccbSFrançois Tigeot bool radeon_connector_is_dp12_capable(struct drm_connector *connector)
1605926deccbSFrançois Tigeot {
1606926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1607926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1608926deccbSFrançois Tigeot 
1609926deccbSFrançois Tigeot 	if (ASIC_IS_DCE5(rdev) &&
1610c6f73aabSFrançois Tigeot 	    (rdev->clock.default_dispclk >= 53900) &&
1611926deccbSFrançois Tigeot 	    radeon_connector_encoder_is_hbr2(connector)) {
1612926deccbSFrançois Tigeot 		return true;
1613926deccbSFrançois Tigeot 	}
1614926deccbSFrançois Tigeot 
1615926deccbSFrançois Tigeot 	return false;
1616926deccbSFrançois Tigeot }
1617926deccbSFrançois Tigeot 
1618926deccbSFrançois Tigeot static enum drm_connector_status
1619926deccbSFrançois Tigeot radeon_dp_detect(struct drm_connector *connector, bool force)
1620926deccbSFrançois Tigeot {
1621926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1622926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1623926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1624926deccbSFrançois Tigeot 	enum drm_connector_status ret = connector_status_disconnected;
1625926deccbSFrançois Tigeot 	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
1626926deccbSFrançois Tigeot 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
1627c6f73aabSFrançois Tigeot #ifdef PM_TODO
1628c6f73aabSFrançois Tigeot 	int r;
1629926deccbSFrançois Tigeot 
1630c6f73aabSFrançois Tigeot 	r = pm_runtime_get_sync(connector->dev->dev);
1631c6f73aabSFrançois Tigeot 	if (r < 0)
1632c6f73aabSFrançois Tigeot 		return connector_status_disconnected;
1633c6f73aabSFrançois Tigeot #endif
1634c6f73aabSFrançois Tigeot 
1635c6f73aabSFrançois Tigeot 	if (!force && radeon_check_hpd_status_unchanged(connector)) {
1636c6f73aabSFrançois Tigeot 		ret = connector->status;
1637c6f73aabSFrançois Tigeot 		goto out;
1638c6f73aabSFrançois Tigeot 	}
1639926deccbSFrançois Tigeot 
1640ee479021SImre Vadász 	radeon_connector_free_edid(radeon_connector);
1641926deccbSFrançois Tigeot 
1642926deccbSFrançois Tigeot 	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
1643926deccbSFrançois Tigeot 	    (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
1644926deccbSFrançois Tigeot 		if (encoder) {
1645926deccbSFrançois Tigeot 			struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
1646926deccbSFrançois Tigeot 			struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
1647926deccbSFrançois Tigeot 
1648926deccbSFrançois Tigeot 			/* check if panel is valid */
1649926deccbSFrançois Tigeot 			if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
1650926deccbSFrançois Tigeot 				ret = connector_status_connected;
1651*1cfef1a5SFrançois Tigeot 			/* don't fetch the edid from the vbios if ddc fails and runpm is
1652*1cfef1a5SFrançois Tigeot 			 * enabled so we report disconnected.
1653*1cfef1a5SFrançois Tigeot 			 */
1654*1cfef1a5SFrançois Tigeot 			if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0))
1655*1cfef1a5SFrançois Tigeot 				ret = connector_status_disconnected;
1656926deccbSFrançois Tigeot 		}
1657926deccbSFrançois Tigeot 		/* eDP is always DP */
1658926deccbSFrançois Tigeot 		radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
1659926deccbSFrançois Tigeot 		if (!radeon_dig_connector->edp_on)
1660926deccbSFrançois Tigeot 			atombios_set_edp_panel_power(connector,
1661926deccbSFrançois Tigeot 						     ATOM_TRANSMITTER_ACTION_POWER_ON);
1662926deccbSFrançois Tigeot 		if (radeon_dp_getdpcd(radeon_connector))
1663926deccbSFrançois Tigeot 			ret = connector_status_connected;
1664926deccbSFrançois Tigeot 		if (!radeon_dig_connector->edp_on)
1665926deccbSFrançois Tigeot 			atombios_set_edp_panel_power(connector,
1666926deccbSFrançois Tigeot 						     ATOM_TRANSMITTER_ACTION_POWER_OFF);
1667926deccbSFrançois Tigeot 	} else if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
1668926deccbSFrançois Tigeot 		   ENCODER_OBJECT_ID_NONE) {
1669926deccbSFrançois Tigeot 		/* DP bridges are always DP */
1670926deccbSFrançois Tigeot 		radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
1671926deccbSFrançois Tigeot 		/* get the DPCD from the bridge */
1672926deccbSFrançois Tigeot 		radeon_dp_getdpcd(radeon_connector);
1673926deccbSFrançois Tigeot 
1674926deccbSFrançois Tigeot 		if (encoder) {
1675926deccbSFrançois Tigeot 			/* setup ddc on the bridge */
1676926deccbSFrançois Tigeot 			radeon_atom_ext_encoder_setup_ddc(encoder);
1677926deccbSFrançois Tigeot 			/* bridge chips are always aux */
1678926deccbSFrançois Tigeot 			if (radeon_ddc_probe(radeon_connector, true)) /* try DDC */
1679926deccbSFrançois Tigeot 				ret = connector_status_connected;
1680926deccbSFrançois Tigeot 			else if (radeon_connector->dac_load_detect) { /* try load detection */
1681c0e85e96SFrançois Tigeot 				const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
1682926deccbSFrançois Tigeot 				ret = encoder_funcs->detect(encoder, connector);
1683926deccbSFrançois Tigeot 			}
1684926deccbSFrançois Tigeot 		}
1685926deccbSFrançois Tigeot 	} else {
1686926deccbSFrançois Tigeot 		radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
1687926deccbSFrançois Tigeot 		if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
1688926deccbSFrançois Tigeot 			ret = connector_status_connected;
1689926deccbSFrançois Tigeot 			if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT)
1690926deccbSFrançois Tigeot 				radeon_dp_getdpcd(radeon_connector);
1691926deccbSFrançois Tigeot 		} else {
1692926deccbSFrançois Tigeot 			if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
1693926deccbSFrançois Tigeot 				if (radeon_dp_getdpcd(radeon_connector))
1694926deccbSFrançois Tigeot 					ret = connector_status_connected;
1695926deccbSFrançois Tigeot 			} else {
16964cd92098Szrj 				/* try non-aux ddc (DP to DVI/HDMI/etc. adapter) */
1697926deccbSFrançois Tigeot 				if (radeon_ddc_probe(radeon_connector, false))
1698926deccbSFrançois Tigeot 					ret = connector_status_connected;
1699926deccbSFrançois Tigeot 			}
1700926deccbSFrançois Tigeot 		}
1701926deccbSFrançois Tigeot 	}
1702926deccbSFrançois Tigeot 
1703926deccbSFrançois Tigeot 	radeon_connector_update_scratch_regs(connector, ret);
1704c6f73aabSFrançois Tigeot out:
1705c6f73aabSFrançois Tigeot #ifdef PM_TODO
1706c6f73aabSFrançois Tigeot 	pm_runtime_mark_last_busy(connector->dev->dev);
1707c6f73aabSFrançois Tigeot 	pm_runtime_put_autosuspend(connector->dev->dev);
1708c6f73aabSFrançois Tigeot #endif
1709c6f73aabSFrançois Tigeot 
1710926deccbSFrançois Tigeot 	return ret;
1711926deccbSFrançois Tigeot }
1712926deccbSFrançois Tigeot 
1713926deccbSFrançois Tigeot static int radeon_dp_mode_valid(struct drm_connector *connector,
1714926deccbSFrançois Tigeot 				  struct drm_display_mode *mode)
1715926deccbSFrançois Tigeot {
1716c6f73aabSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1717c6f73aabSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1718926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1719926deccbSFrançois Tigeot 	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
1720926deccbSFrançois Tigeot 
1721926deccbSFrançois Tigeot 	/* XXX check mode bandwidth */
1722926deccbSFrançois Tigeot 
1723926deccbSFrançois Tigeot 	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
1724926deccbSFrançois Tigeot 	    (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
1725926deccbSFrançois Tigeot 		struct drm_encoder *encoder = radeon_best_single_encoder(connector);
1726926deccbSFrançois Tigeot 
1727926deccbSFrançois Tigeot 		if ((mode->hdisplay < 320) || (mode->vdisplay < 240))
1728926deccbSFrançois Tigeot 			return MODE_PANEL;
1729926deccbSFrançois Tigeot 
1730926deccbSFrançois Tigeot 		if (encoder) {
1731926deccbSFrançois Tigeot 			struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
1732926deccbSFrançois Tigeot 			struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
1733926deccbSFrançois Tigeot 
1734926deccbSFrançois Tigeot 			/* AVIVO hardware supports downscaling modes larger than the panel
1735926deccbSFrançois Tigeot 			 * to the panel size, but I'm not sure this is desirable.
1736926deccbSFrançois Tigeot 			 */
1737926deccbSFrançois Tigeot 			if ((mode->hdisplay > native_mode->hdisplay) ||
1738926deccbSFrançois Tigeot 			    (mode->vdisplay > native_mode->vdisplay))
1739926deccbSFrançois Tigeot 				return MODE_PANEL;
1740926deccbSFrançois Tigeot 
1741926deccbSFrançois Tigeot 			/* if scaling is disabled, block non-native modes */
1742926deccbSFrançois Tigeot 			if (radeon_encoder->rmx_type == RMX_OFF) {
1743926deccbSFrançois Tigeot 				if ((mode->hdisplay != native_mode->hdisplay) ||
1744926deccbSFrançois Tigeot 				    (mode->vdisplay != native_mode->vdisplay))
1745926deccbSFrançois Tigeot 					return MODE_PANEL;
1746926deccbSFrançois Tigeot 			}
1747926deccbSFrançois Tigeot 		}
1748926deccbSFrançois Tigeot 	} else {
1749926deccbSFrançois Tigeot 		if ((radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
1750c6f73aabSFrançois Tigeot 		    (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
1751926deccbSFrançois Tigeot 			return radeon_dp_mode_valid_helper(connector, mode);
1752c6f73aabSFrançois Tigeot 		} else {
1753c6f73aabSFrançois Tigeot 			if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
1754c6f73aabSFrançois Tigeot 				/* HDMI 1.3+ supports max clock of 340 Mhz */
1755c6f73aabSFrançois Tigeot 				if (mode->clock > 340000)
1756c6f73aabSFrançois Tigeot 					return MODE_CLOCK_HIGH;
1757c6f73aabSFrançois Tigeot 			} else {
1758c6f73aabSFrançois Tigeot 				if (mode->clock > 165000)
1759c6f73aabSFrançois Tigeot 					return MODE_CLOCK_HIGH;
1760926deccbSFrançois Tigeot 			}
1761926deccbSFrançois Tigeot 		}
1762c6f73aabSFrançois Tigeot 	}
1763c6f73aabSFrançois Tigeot 
1764c6f73aabSFrançois Tigeot 	return MODE_OK;
1765c6f73aabSFrançois Tigeot }
1766926deccbSFrançois Tigeot 
1767926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_dp_connector_helper_funcs = {
1768926deccbSFrançois Tigeot 	.get_modes = radeon_dp_get_modes,
1769926deccbSFrançois Tigeot 	.mode_valid = radeon_dp_mode_valid,
1770926deccbSFrançois Tigeot 	.best_encoder = radeon_dvi_encoder,
1771926deccbSFrançois Tigeot };
1772926deccbSFrançois Tigeot 
1773926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_dp_connector_funcs = {
1774926deccbSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
1775926deccbSFrançois Tigeot 	.detect = radeon_dp_detect,
1776926deccbSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
1777926deccbSFrançois Tigeot 	.set_property = radeon_connector_set_property,
1778ee479021SImre Vadász 	.destroy = radeon_dp_connector_destroy,
1779926deccbSFrançois Tigeot 	.force = radeon_dvi_force,
1780926deccbSFrançois Tigeot };
1781926deccbSFrançois Tigeot 
17824cd92098Szrj static const struct drm_connector_funcs radeon_edp_connector_funcs = {
17834cd92098Szrj 	.dpms = drm_helper_connector_dpms,
17844cd92098Szrj 	.detect = radeon_dp_detect,
17854cd92098Szrj 	.fill_modes = drm_helper_probe_single_connector_modes,
17864cd92098Szrj 	.set_property = radeon_lvds_set_property,
1787ee479021SImre Vadász 	.destroy = radeon_dp_connector_destroy,
17884cd92098Szrj 	.force = radeon_dvi_force,
17894cd92098Szrj };
17904cd92098Szrj 
17914cd92098Szrj static const struct drm_connector_funcs radeon_lvds_bridge_connector_funcs = {
17924cd92098Szrj 	.dpms = drm_helper_connector_dpms,
17934cd92098Szrj 	.detect = radeon_dp_detect,
17944cd92098Szrj 	.fill_modes = drm_helper_probe_single_connector_modes,
17954cd92098Szrj 	.set_property = radeon_lvds_set_property,
1796ee479021SImre Vadász 	.destroy = radeon_dp_connector_destroy,
17974cd92098Szrj 	.force = radeon_dvi_force,
17984cd92098Szrj };
17994cd92098Szrj 
1800926deccbSFrançois Tigeot void
1801926deccbSFrançois Tigeot radeon_add_atom_connector(struct drm_device *dev,
1802926deccbSFrançois Tigeot 			  uint32_t connector_id,
1803926deccbSFrançois Tigeot 			  uint32_t supported_device,
1804926deccbSFrançois Tigeot 			  int connector_type,
1805926deccbSFrançois Tigeot 			  struct radeon_i2c_bus_rec *i2c_bus,
1806926deccbSFrançois Tigeot 			  uint32_t igp_lane_info,
1807926deccbSFrançois Tigeot 			  uint16_t connector_object_id,
1808926deccbSFrançois Tigeot 			  struct radeon_hpd *hpd,
1809926deccbSFrançois Tigeot 			  struct radeon_router *router)
1810926deccbSFrançois Tigeot {
1811926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1812926deccbSFrançois Tigeot 	struct drm_connector *connector;
1813926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector;
1814926deccbSFrançois Tigeot 	struct radeon_connector_atom_dig *radeon_dig_connector;
1815926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1816926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
1817926deccbSFrançois Tigeot 	uint32_t subpixel_order = SubPixelNone;
1818926deccbSFrançois Tigeot 	bool shared_ddc = false;
1819926deccbSFrançois Tigeot 	bool is_dp_bridge = false;
18207191d616Szrj 	bool has_aux = false;
1821926deccbSFrançois Tigeot 
1822926deccbSFrançois Tigeot 	if (connector_type == DRM_MODE_CONNECTOR_Unknown)
1823926deccbSFrançois Tigeot 		return;
1824926deccbSFrançois Tigeot 
1825926deccbSFrançois Tigeot 	/* if the user selected tv=0 don't try and add the connector */
1826926deccbSFrançois Tigeot 	if (((connector_type == DRM_MODE_CONNECTOR_SVIDEO) ||
1827926deccbSFrançois Tigeot 	     (connector_type == DRM_MODE_CONNECTOR_Composite) ||
1828926deccbSFrançois Tigeot 	     (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) &&
1829926deccbSFrançois Tigeot 	    (radeon_tv == 0))
1830926deccbSFrançois Tigeot 		return;
1831926deccbSFrançois Tigeot 
1832926deccbSFrançois Tigeot 	/* see if we already added it */
1833926deccbSFrançois Tigeot 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1834926deccbSFrançois Tigeot 		radeon_connector = to_radeon_connector(connector);
1835926deccbSFrançois Tigeot 		if (radeon_connector->connector_id == connector_id) {
1836926deccbSFrançois Tigeot 			radeon_connector->devices |= supported_device;
1837926deccbSFrançois Tigeot 			return;
1838926deccbSFrançois Tigeot 		}
1839926deccbSFrançois Tigeot 		if (radeon_connector->ddc_bus && i2c_bus->valid) {
1840926deccbSFrançois Tigeot 			if (radeon_connector->ddc_bus->rec.i2c_id == i2c_bus->i2c_id) {
1841926deccbSFrançois Tigeot 				radeon_connector->shared_ddc = true;
1842926deccbSFrançois Tigeot 				shared_ddc = true;
1843926deccbSFrançois Tigeot 			}
1844926deccbSFrançois Tigeot 			if (radeon_connector->router_bus && router->ddc_valid &&
1845926deccbSFrançois Tigeot 			    (radeon_connector->router.router_id == router->router_id)) {
1846926deccbSFrançois Tigeot 				radeon_connector->shared_ddc = false;
1847926deccbSFrançois Tigeot 				shared_ddc = false;
1848926deccbSFrançois Tigeot 			}
1849926deccbSFrançois Tigeot 		}
1850926deccbSFrançois Tigeot 	}
1851926deccbSFrançois Tigeot 
1852926deccbSFrançois Tigeot 	/* check if it's a dp bridge */
1853926deccbSFrançois Tigeot 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
1854926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
1855926deccbSFrançois Tigeot 		if (radeon_encoder->devices & supported_device) {
1856926deccbSFrançois Tigeot 			switch (radeon_encoder->encoder_id) {
1857926deccbSFrançois Tigeot 			case ENCODER_OBJECT_ID_TRAVIS:
1858926deccbSFrançois Tigeot 			case ENCODER_OBJECT_ID_NUTMEG:
1859926deccbSFrançois Tigeot 				is_dp_bridge = true;
1860926deccbSFrançois Tigeot 				break;
1861926deccbSFrançois Tigeot 			default:
1862926deccbSFrançois Tigeot 				break;
1863926deccbSFrançois Tigeot 			}
1864926deccbSFrançois Tigeot 		}
1865926deccbSFrançois Tigeot 	}
1866926deccbSFrançois Tigeot 
1867c4ef309bSzrj 	radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL);
1868926deccbSFrançois Tigeot 	if (!radeon_connector)
1869926deccbSFrançois Tigeot 		return;
1870926deccbSFrançois Tigeot 
1871926deccbSFrançois Tigeot 	connector = &radeon_connector->base;
1872926deccbSFrançois Tigeot 
1873926deccbSFrançois Tigeot 	radeon_connector->connector_id = connector_id;
1874926deccbSFrançois Tigeot 	radeon_connector->devices = supported_device;
1875926deccbSFrançois Tigeot 	radeon_connector->shared_ddc = shared_ddc;
1876926deccbSFrançois Tigeot 	radeon_connector->connector_object_id = connector_object_id;
1877926deccbSFrançois Tigeot 	radeon_connector->hpd = *hpd;
1878926deccbSFrançois Tigeot 
1879926deccbSFrançois Tigeot 	radeon_connector->router = *router;
1880926deccbSFrançois Tigeot 	if (router->ddc_valid || router->cd_valid) {
1881926deccbSFrançois Tigeot 		radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info);
1882926deccbSFrançois Tigeot 		if (!radeon_connector->router_bus)
1883926deccbSFrançois Tigeot 			DRM_ERROR("Failed to assign router i2c bus! Check dmesg for i2c errors.\n");
1884926deccbSFrançois Tigeot 	}
1885926deccbSFrançois Tigeot 
1886926deccbSFrançois Tigeot 	if (is_dp_bridge) {
1887c4ef309bSzrj 		radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
1888926deccbSFrançois Tigeot 		if (!radeon_dig_connector)
1889926deccbSFrançois Tigeot 			goto failed;
1890926deccbSFrançois Tigeot 		radeon_dig_connector->igp_lane_info = igp_lane_info;
1891926deccbSFrançois Tigeot 		radeon_connector->con_priv = radeon_dig_connector;
1892926deccbSFrançois Tigeot 		if (i2c_bus->valid) {
1893ee479021SImre Vadász 			/* add DP i2c bus */
1894ee479021SImre Vadász 			if (connector_type == DRM_MODE_CONNECTOR_eDP)
1895ee479021SImre Vadász 				radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch");
1896ee479021SImre Vadász 			else
1897ee479021SImre Vadász 				radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch");
1898ee479021SImre Vadász 			if (radeon_dig_connector->dp_i2c_bus)
18997191d616Szrj 				has_aux = true;
19007191d616Szrj 			else
1901ee479021SImre Vadász 				DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
1902ee479021SImre Vadász 			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
1903ee479021SImre Vadász 			if (!radeon_connector->ddc_bus)
1904926deccbSFrançois Tigeot 				DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
1905926deccbSFrançois Tigeot 		}
1906926deccbSFrançois Tigeot 		switch (connector_type) {
1907926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_VGA:
1908926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVIA:
1909926deccbSFrançois Tigeot 		default:
19104cd92098Szrj 			drm_connector_init(dev, &radeon_connector->base,
19114cd92098Szrj 					   &radeon_dp_connector_funcs, connector_type);
19124cd92098Szrj 			drm_connector_helper_add(&radeon_connector->base,
19134cd92098Szrj 						 &radeon_dp_connector_helper_funcs);
1914926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
1915926deccbSFrançois Tigeot 			connector->doublescan_allowed = true;
1916926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
1917b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
1918926deccbSFrançois Tigeot 						      rdev->mode_info.load_detect_property,
1919926deccbSFrançois Tigeot 						      1);
1920c6f73aabSFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
1921c6f73aabSFrançois Tigeot 						   dev->mode_config.scaling_mode_property,
1922c6f73aabSFrançois Tigeot 						   DRM_MODE_SCALE_NONE);
1923926deccbSFrançois Tigeot 			break;
1924926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVII:
1925926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVID:
1926926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_HDMIA:
1927926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_HDMIB:
1928926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DisplayPort:
19294cd92098Szrj 			drm_connector_init(dev, &radeon_connector->base,
19304cd92098Szrj 					   &radeon_dp_connector_funcs, connector_type);
19314cd92098Szrj 			drm_connector_helper_add(&radeon_connector->base,
19324cd92098Szrj 						 &radeon_dp_connector_helper_funcs);
1933b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
1934926deccbSFrançois Tigeot 						      rdev->mode_info.underscan_property,
1935926deccbSFrançois Tigeot 						      UNDERSCAN_OFF);
1936b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
1937926deccbSFrançois Tigeot 						      rdev->mode_info.underscan_hborder_property,
1938926deccbSFrançois Tigeot 						      0);
1939b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
1940926deccbSFrançois Tigeot 						      rdev->mode_info.underscan_vborder_property,
1941926deccbSFrançois Tigeot 						      0);
1942c6f73aabSFrançois Tigeot 
1943c6f73aabSFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
1944c6f73aabSFrançois Tigeot 						      dev->mode_config.scaling_mode_property,
1945c6f73aabSFrançois Tigeot 						      DRM_MODE_SCALE_NONE);
1946c6f73aabSFrançois Tigeot 
1947c6f73aabSFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
1948c6f73aabSFrançois Tigeot 						   rdev->mode_info.dither_property,
1949c6f73aabSFrançois Tigeot 						   RADEON_FMT_DITHER_DISABLE);
1950c6f73aabSFrançois Tigeot 
1951ee479021SImre Vadász 			if (radeon_audio != 0)
19524cd92098Szrj 				drm_object_attach_property(&radeon_connector->base.base,
19534cd92098Szrj 							   rdev->mode_info.audio_property,
1954c6f73aabSFrançois Tigeot 							   RADEON_AUDIO_AUTO);
1955c6f73aabSFrançois Tigeot 
1956926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
1957926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
1958926deccbSFrançois Tigeot 			if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
1959926deccbSFrançois Tigeot 				connector->doublescan_allowed = true;
1960926deccbSFrançois Tigeot 			else
1961926deccbSFrançois Tigeot 				connector->doublescan_allowed = false;
1962926deccbSFrançois Tigeot 			if (connector_type == DRM_MODE_CONNECTOR_DVII) {
1963926deccbSFrançois Tigeot 				radeon_connector->dac_load_detect = true;
1964b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
1965926deccbSFrançois Tigeot 							      rdev->mode_info.load_detect_property,
1966926deccbSFrançois Tigeot 							      1);
1967926deccbSFrançois Tigeot 			}
1968926deccbSFrançois Tigeot 			break;
1969926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_LVDS:
1970926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_eDP:
19714cd92098Szrj 			drm_connector_init(dev, &radeon_connector->base,
19724cd92098Szrj 					   &radeon_lvds_bridge_connector_funcs, connector_type);
19734cd92098Szrj 			drm_connector_helper_add(&radeon_connector->base,
19744cd92098Szrj 						 &radeon_dp_connector_helper_funcs);
1975b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
1976926deccbSFrançois Tigeot 						      dev->mode_config.scaling_mode_property,
1977926deccbSFrançois Tigeot 						      DRM_MODE_SCALE_FULLSCREEN);
1978926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
1979926deccbSFrançois Tigeot 			connector->interlace_allowed = false;
1980926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
1981926deccbSFrançois Tigeot 			break;
1982926deccbSFrançois Tigeot 		}
1983926deccbSFrançois Tigeot 	} else {
1984926deccbSFrançois Tigeot 		switch (connector_type) {
1985926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_VGA:
1986926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
1987926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
1988926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
1989926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
1990926deccbSFrançois Tigeot 				if (!radeon_connector->ddc_bus)
1991926deccbSFrançois Tigeot 					DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
1992926deccbSFrançois Tigeot 			}
1993926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
1994b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
1995926deccbSFrançois Tigeot 						      rdev->mode_info.load_detect_property,
1996926deccbSFrançois Tigeot 						      1);
1997c6f73aabSFrançois Tigeot 			if (ASIC_IS_AVIVO(rdev))
1998c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
1999c6f73aabSFrançois Tigeot 							   dev->mode_config.scaling_mode_property,
2000c6f73aabSFrançois Tigeot 							   DRM_MODE_SCALE_NONE);
2001926deccbSFrançois Tigeot 			/* no HPD on analog connectors */
2002926deccbSFrançois Tigeot 			radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2003ee479021SImre Vadász 			connector->polled = DRM_CONNECTOR_POLL_CONNECT;
2004926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2005926deccbSFrançois Tigeot 			connector->doublescan_allowed = true;
2006926deccbSFrançois Tigeot 			break;
2007926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVIA:
2008926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
2009926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
2010926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2011926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2012926deccbSFrançois Tigeot 				if (!radeon_connector->ddc_bus)
2013926deccbSFrançois Tigeot 					DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2014926deccbSFrançois Tigeot 			}
2015926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
2016b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2017926deccbSFrançois Tigeot 						      rdev->mode_info.load_detect_property,
2018926deccbSFrançois Tigeot 						      1);
2019c6f73aabSFrançois Tigeot 			if (ASIC_IS_AVIVO(rdev))
2020c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2021c6f73aabSFrançois Tigeot 							   dev->mode_config.scaling_mode_property,
2022c6f73aabSFrançois Tigeot 							   DRM_MODE_SCALE_NONE);
2023926deccbSFrançois Tigeot 			/* no HPD on analog connectors */
2024926deccbSFrançois Tigeot 			radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2025926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2026926deccbSFrançois Tigeot 			connector->doublescan_allowed = true;
2027926deccbSFrançois Tigeot 			break;
2028926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVII:
2029926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVID:
2030c4ef309bSzrj 			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
2031926deccbSFrançois Tigeot 			if (!radeon_dig_connector)
2032926deccbSFrançois Tigeot 				goto failed;
2033926deccbSFrançois Tigeot 			radeon_dig_connector->igp_lane_info = igp_lane_info;
2034926deccbSFrançois Tigeot 			radeon_connector->con_priv = radeon_dig_connector;
2035926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
2036926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
2037926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2038926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2039926deccbSFrançois Tigeot 				if (!radeon_connector->ddc_bus)
2040926deccbSFrançois Tigeot 					DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2041926deccbSFrançois Tigeot 			}
2042926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2043b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2044926deccbSFrançois Tigeot 						      rdev->mode_info.coherent_mode_property,
2045926deccbSFrançois Tigeot 						      1);
2046926deccbSFrançois Tigeot 			if (ASIC_IS_AVIVO(rdev)) {
2047b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2048926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_property,
2049926deccbSFrançois Tigeot 							      UNDERSCAN_OFF);
2050b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2051926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_hborder_property,
2052926deccbSFrançois Tigeot 							      0);
2053b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2054926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_vborder_property,
2055926deccbSFrançois Tigeot 							      0);
2056c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2057c6f73aabSFrançois Tigeot 							   rdev->mode_info.dither_property,
2058c6f73aabSFrançois Tigeot 							   RADEON_FMT_DITHER_DISABLE);
2059c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2060c6f73aabSFrançois Tigeot 							   dev->mode_config.scaling_mode_property,
2061c6f73aabSFrançois Tigeot 							   DRM_MODE_SCALE_NONE);
2062926deccbSFrançois Tigeot 			}
20634cd92098Szrj 			if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
20644cd92098Szrj 				drm_object_attach_property(&radeon_connector->base.base,
20654cd92098Szrj 							   rdev->mode_info.audio_property,
2066c6f73aabSFrançois Tigeot 							   RADEON_AUDIO_AUTO);
20674cd92098Szrj 			}
2068926deccbSFrançois Tigeot 			if (connector_type == DRM_MODE_CONNECTOR_DVII) {
2069926deccbSFrançois Tigeot 				radeon_connector->dac_load_detect = true;
2070b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2071926deccbSFrançois Tigeot 							      rdev->mode_info.load_detect_property,
2072926deccbSFrançois Tigeot 							      1);
2073926deccbSFrançois Tigeot 			}
2074926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2075926deccbSFrançois Tigeot 			if (connector_type == DRM_MODE_CONNECTOR_DVII)
2076926deccbSFrançois Tigeot 				connector->doublescan_allowed = true;
2077926deccbSFrançois Tigeot 			else
2078926deccbSFrançois Tigeot 				connector->doublescan_allowed = false;
2079926deccbSFrançois Tigeot 			break;
2080926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_HDMIA:
2081926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_HDMIB:
2082c4ef309bSzrj 			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
2083926deccbSFrançois Tigeot 			if (!radeon_dig_connector)
2084926deccbSFrançois Tigeot 				goto failed;
2085926deccbSFrançois Tigeot 			radeon_dig_connector->igp_lane_info = igp_lane_info;
2086926deccbSFrançois Tigeot 			radeon_connector->con_priv = radeon_dig_connector;
2087926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
2088926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
2089926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2090926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2091926deccbSFrançois Tigeot 				if (!radeon_connector->ddc_bus)
2092926deccbSFrançois Tigeot 					DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2093926deccbSFrançois Tigeot 			}
2094b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2095926deccbSFrançois Tigeot 						      rdev->mode_info.coherent_mode_property,
2096926deccbSFrançois Tigeot 						      1);
2097926deccbSFrançois Tigeot 			if (ASIC_IS_AVIVO(rdev)) {
2098b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2099926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_property,
2100926deccbSFrançois Tigeot 							      UNDERSCAN_OFF);
2101b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2102926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_hborder_property,
2103926deccbSFrançois Tigeot 							      0);
2104b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2105926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_vborder_property,
2106926deccbSFrançois Tigeot 							      0);
2107c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2108c6f73aabSFrançois Tigeot 							   rdev->mode_info.dither_property,
2109c6f73aabSFrançois Tigeot 							   RADEON_FMT_DITHER_DISABLE);
2110c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2111c6f73aabSFrançois Tigeot 							   dev->mode_config.scaling_mode_property,
2112c6f73aabSFrançois Tigeot 							   DRM_MODE_SCALE_NONE);
2113926deccbSFrançois Tigeot 			}
21144cd92098Szrj 			if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
21154cd92098Szrj 				drm_object_attach_property(&radeon_connector->base.base,
21164cd92098Szrj 							   rdev->mode_info.audio_property,
2117c6f73aabSFrançois Tigeot 							   RADEON_AUDIO_AUTO);
21184cd92098Szrj 			}
2119926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2120926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2121926deccbSFrançois Tigeot 			if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
2122926deccbSFrançois Tigeot 				connector->doublescan_allowed = true;
2123926deccbSFrançois Tigeot 			else
2124926deccbSFrançois Tigeot 				connector->doublescan_allowed = false;
2125926deccbSFrançois Tigeot 			break;
2126926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DisplayPort:
2127c4ef309bSzrj 			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
2128926deccbSFrançois Tigeot 			if (!radeon_dig_connector)
2129926deccbSFrançois Tigeot 				goto failed;
2130926deccbSFrançois Tigeot 			radeon_dig_connector->igp_lane_info = igp_lane_info;
2131926deccbSFrançois Tigeot 			radeon_connector->con_priv = radeon_dig_connector;
2132926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
2133926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
2134926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2135ee479021SImre Vadász 				/* add DP i2c bus */
2136ee479021SImre Vadász 				radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch");
2137ee479021SImre Vadász 				if (!radeon_dig_connector->dp_i2c_bus)
2138ee479021SImre Vadász 					DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
2139926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
21407191d616Szrj 				if (radeon_connector->ddc_bus)
21417191d616Szrj 					has_aux = true;
21427191d616Szrj 				else
2143926deccbSFrançois Tigeot 					DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2144926deccbSFrançois Tigeot 			}
2145926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2146b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2147926deccbSFrançois Tigeot 						      rdev->mode_info.coherent_mode_property,
2148926deccbSFrançois Tigeot 						      1);
2149926deccbSFrançois Tigeot 			if (ASIC_IS_AVIVO(rdev)) {
2150b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2151926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_property,
2152926deccbSFrançois Tigeot 							      UNDERSCAN_OFF);
2153b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2154926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_hborder_property,
2155926deccbSFrançois Tigeot 							      0);
2156b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2157926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_vborder_property,
2158926deccbSFrançois Tigeot 							      0);
2159c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2160c6f73aabSFrançois Tigeot 							   rdev->mode_info.dither_property,
2161c6f73aabSFrançois Tigeot 							   RADEON_FMT_DITHER_DISABLE);
2162c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2163c6f73aabSFrançois Tigeot 							   dev->mode_config.scaling_mode_property,
2164c6f73aabSFrançois Tigeot 							   DRM_MODE_SCALE_NONE);
2165926deccbSFrançois Tigeot 			}
21664cd92098Szrj 			if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
21674cd92098Szrj 				drm_object_attach_property(&radeon_connector->base.base,
21684cd92098Szrj 							   rdev->mode_info.audio_property,
2169c6f73aabSFrançois Tigeot 							   RADEON_AUDIO_AUTO);
21704cd92098Szrj 			}
2171926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2172926deccbSFrançois Tigeot 			/* in theory with a DP to VGA converter... */
2173926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2174926deccbSFrançois Tigeot 			break;
2175926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_eDP:
2176c4ef309bSzrj 			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
2177926deccbSFrançois Tigeot 			if (!radeon_dig_connector)
2178926deccbSFrançois Tigeot 				goto failed;
2179926deccbSFrançois Tigeot 			radeon_dig_connector->igp_lane_info = igp_lane_info;
2180926deccbSFrançois Tigeot 			radeon_connector->con_priv = radeon_dig_connector;
21814cd92098Szrj 			drm_connector_init(dev, &radeon_connector->base, &radeon_edp_connector_funcs, connector_type);
2182926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
2183926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2184ee479021SImre Vadász 				/* add DP i2c bus */
2185ee479021SImre Vadász 				radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch");
2186ee479021SImre Vadász 				if (radeon_dig_connector->dp_i2c_bus)
21877191d616Szrj 					has_aux = true;
21887191d616Szrj 				else
2189ee479021SImre Vadász 					DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
2190ee479021SImre Vadász 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2191ee479021SImre Vadász 				if (!radeon_connector->ddc_bus)
2192926deccbSFrançois Tigeot 					DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2193926deccbSFrançois Tigeot 			}
2194b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2195926deccbSFrançois Tigeot 						      dev->mode_config.scaling_mode_property,
2196926deccbSFrançois Tigeot 						      DRM_MODE_SCALE_FULLSCREEN);
2197926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2198926deccbSFrançois Tigeot 			connector->interlace_allowed = false;
2199926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2200926deccbSFrançois Tigeot 			break;
2201926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_SVIDEO:
2202926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_Composite:
2203926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_9PinDIN:
2204926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
2205926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
2206926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
2207b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2208926deccbSFrançois Tigeot 						      rdev->mode_info.load_detect_property,
2209926deccbSFrançois Tigeot 						      1);
2210b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2211926deccbSFrançois Tigeot 						      rdev->mode_info.tv_std_property,
2212926deccbSFrançois Tigeot 						      radeon_atombios_get_tv_info(rdev));
2213926deccbSFrançois Tigeot 			/* no HPD on analog connectors */
2214926deccbSFrançois Tigeot 			radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2215926deccbSFrançois Tigeot 			connector->interlace_allowed = false;
2216926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2217926deccbSFrançois Tigeot 			break;
2218926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_LVDS:
2219c4ef309bSzrj 			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
2220926deccbSFrançois Tigeot 			if (!radeon_dig_connector)
2221926deccbSFrançois Tigeot 				goto failed;
2222926deccbSFrançois Tigeot 			radeon_dig_connector->igp_lane_info = igp_lane_info;
2223926deccbSFrançois Tigeot 			radeon_connector->con_priv = radeon_dig_connector;
2224926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
2225926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
2226926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2227926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2228926deccbSFrançois Tigeot 				if (!radeon_connector->ddc_bus)
2229926deccbSFrançois Tigeot 					DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2230926deccbSFrançois Tigeot 			}
2231b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2232926deccbSFrançois Tigeot 						      dev->mode_config.scaling_mode_property,
2233926deccbSFrançois Tigeot 						      DRM_MODE_SCALE_FULLSCREEN);
2234926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2235926deccbSFrançois Tigeot 			connector->interlace_allowed = false;
2236926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2237926deccbSFrançois Tigeot 			break;
2238926deccbSFrançois Tigeot 		}
2239926deccbSFrançois Tigeot 	}
2240926deccbSFrançois Tigeot 
2241926deccbSFrançois Tigeot 	if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
2242ee479021SImre Vadász 		if (i2c_bus->valid)
2243ee479021SImre Vadász 			connector->polled = DRM_CONNECTOR_POLL_CONNECT;
2244926deccbSFrançois Tigeot 	} else
2245926deccbSFrançois Tigeot 		connector->polled = DRM_CONNECTOR_POLL_HPD;
2246926deccbSFrançois Tigeot 
2247926deccbSFrançois Tigeot 	connector->display_info.subpixel_order = subpixel_order;
2248c6f73aabSFrançois Tigeot 	drm_connector_register(connector);
22497191d616Szrj 
22507191d616Szrj 	if (has_aux)
22517191d616Szrj 		radeon_dp_aux_init(radeon_connector);
22527191d616Szrj 
2253926deccbSFrançois Tigeot 	return;
2254926deccbSFrançois Tigeot 
2255926deccbSFrançois Tigeot failed:
2256926deccbSFrançois Tigeot 	drm_connector_cleanup(connector);
2257158486a6SFrançois Tigeot 	kfree(connector);
2258926deccbSFrançois Tigeot }
2259926deccbSFrançois Tigeot 
2260926deccbSFrançois Tigeot void
2261926deccbSFrançois Tigeot radeon_add_legacy_connector(struct drm_device *dev,
2262926deccbSFrançois Tigeot 			    uint32_t connector_id,
2263926deccbSFrançois Tigeot 			    uint32_t supported_device,
2264926deccbSFrançois Tigeot 			    int connector_type,
2265926deccbSFrançois Tigeot 			    struct radeon_i2c_bus_rec *i2c_bus,
2266926deccbSFrançois Tigeot 			    uint16_t connector_object_id,
2267926deccbSFrançois Tigeot 			    struct radeon_hpd *hpd)
2268926deccbSFrançois Tigeot {
2269926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
2270926deccbSFrançois Tigeot 	struct drm_connector *connector;
2271926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector;
2272926deccbSFrançois Tigeot 	uint32_t subpixel_order = SubPixelNone;
2273926deccbSFrançois Tigeot 
2274926deccbSFrançois Tigeot 	if (connector_type == DRM_MODE_CONNECTOR_Unknown)
2275926deccbSFrançois Tigeot 		return;
2276926deccbSFrançois Tigeot 
2277926deccbSFrançois Tigeot 	/* if the user selected tv=0 don't try and add the connector */
2278926deccbSFrançois Tigeot 	if (((connector_type == DRM_MODE_CONNECTOR_SVIDEO) ||
2279926deccbSFrançois Tigeot 	     (connector_type == DRM_MODE_CONNECTOR_Composite) ||
2280926deccbSFrançois Tigeot 	     (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) &&
2281926deccbSFrançois Tigeot 	    (radeon_tv == 0))
2282926deccbSFrançois Tigeot 		return;
2283926deccbSFrançois Tigeot 
2284926deccbSFrançois Tigeot 	/* see if we already added it */
2285926deccbSFrançois Tigeot 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
2286926deccbSFrançois Tigeot 		radeon_connector = to_radeon_connector(connector);
2287926deccbSFrançois Tigeot 		if (radeon_connector->connector_id == connector_id) {
2288926deccbSFrançois Tigeot 			radeon_connector->devices |= supported_device;
2289926deccbSFrançois Tigeot 			return;
2290926deccbSFrançois Tigeot 		}
2291926deccbSFrançois Tigeot 	}
2292926deccbSFrançois Tigeot 
2293c4ef309bSzrj 	radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL);
2294926deccbSFrançois Tigeot 	if (!radeon_connector)
2295926deccbSFrançois Tigeot 		return;
2296926deccbSFrançois Tigeot 
2297926deccbSFrançois Tigeot 	connector = &radeon_connector->base;
2298926deccbSFrançois Tigeot 
2299926deccbSFrançois Tigeot 	radeon_connector->connector_id = connector_id;
2300926deccbSFrançois Tigeot 	radeon_connector->devices = supported_device;
2301926deccbSFrançois Tigeot 	radeon_connector->connector_object_id = connector_object_id;
2302926deccbSFrançois Tigeot 	radeon_connector->hpd = *hpd;
2303926deccbSFrançois Tigeot 
2304926deccbSFrançois Tigeot 	switch (connector_type) {
2305926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_VGA:
2306926deccbSFrançois Tigeot 		drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
2307926deccbSFrançois Tigeot 		drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
2308926deccbSFrançois Tigeot 		if (i2c_bus->valid) {
2309926deccbSFrançois Tigeot 			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2310926deccbSFrançois Tigeot 			if (!radeon_connector->ddc_bus)
2311926deccbSFrançois Tigeot 				DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2312926deccbSFrançois Tigeot 		}
2313926deccbSFrançois Tigeot 		radeon_connector->dac_load_detect = true;
2314b5162e19SFrançois Tigeot 		drm_object_attach_property(&radeon_connector->base.base,
2315926deccbSFrançois Tigeot 					      rdev->mode_info.load_detect_property,
2316926deccbSFrançois Tigeot 					      1);
2317926deccbSFrançois Tigeot 		/* no HPD on analog connectors */
2318926deccbSFrançois Tigeot 		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2319ee479021SImre Vadász 		connector->polled = DRM_CONNECTOR_POLL_CONNECT;
2320926deccbSFrançois Tigeot 		connector->interlace_allowed = true;
2321926deccbSFrançois Tigeot 		connector->doublescan_allowed = true;
2322926deccbSFrançois Tigeot 		break;
2323926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_DVIA:
2324926deccbSFrançois Tigeot 		drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
2325926deccbSFrançois Tigeot 		drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
2326926deccbSFrançois Tigeot 		if (i2c_bus->valid) {
2327926deccbSFrançois Tigeot 			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2328926deccbSFrançois Tigeot 			if (!radeon_connector->ddc_bus)
2329926deccbSFrançois Tigeot 				DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2330926deccbSFrançois Tigeot 		}
2331926deccbSFrançois Tigeot 		radeon_connector->dac_load_detect = true;
2332b5162e19SFrançois Tigeot 		drm_object_attach_property(&radeon_connector->base.base,
2333926deccbSFrançois Tigeot 					      rdev->mode_info.load_detect_property,
2334926deccbSFrançois Tigeot 					      1);
2335926deccbSFrançois Tigeot 		/* no HPD on analog connectors */
2336926deccbSFrançois Tigeot 		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2337926deccbSFrançois Tigeot 		connector->interlace_allowed = true;
2338926deccbSFrançois Tigeot 		connector->doublescan_allowed = true;
2339926deccbSFrançois Tigeot 		break;
2340926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_DVII:
2341926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_DVID:
2342926deccbSFrançois Tigeot 		drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
2343926deccbSFrançois Tigeot 		drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
2344926deccbSFrançois Tigeot 		if (i2c_bus->valid) {
2345926deccbSFrançois Tigeot 			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2346926deccbSFrançois Tigeot 			if (!radeon_connector->ddc_bus)
2347926deccbSFrançois Tigeot 				DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2348926deccbSFrançois Tigeot 		}
2349926deccbSFrançois Tigeot 		if (connector_type == DRM_MODE_CONNECTOR_DVII) {
2350926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
2351b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2352926deccbSFrançois Tigeot 						      rdev->mode_info.load_detect_property,
2353926deccbSFrançois Tigeot 						      1);
2354926deccbSFrançois Tigeot 		}
2355926deccbSFrançois Tigeot 		subpixel_order = SubPixelHorizontalRGB;
2356926deccbSFrançois Tigeot 		connector->interlace_allowed = true;
2357926deccbSFrançois Tigeot 		if (connector_type == DRM_MODE_CONNECTOR_DVII)
2358926deccbSFrançois Tigeot 			connector->doublescan_allowed = true;
2359926deccbSFrançois Tigeot 		else
2360926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2361926deccbSFrançois Tigeot 		break;
2362926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_SVIDEO:
2363926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_Composite:
2364926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_9PinDIN:
2365926deccbSFrançois Tigeot 		drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
2366926deccbSFrançois Tigeot 		drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
2367926deccbSFrançois Tigeot 		radeon_connector->dac_load_detect = true;
2368926deccbSFrançois Tigeot 		/* RS400,RC410,RS480 chipset seems to report a lot
2369926deccbSFrançois Tigeot 		 * of false positive on load detect, we haven't yet
2370926deccbSFrançois Tigeot 		 * found a way to make load detect reliable on those
2371926deccbSFrançois Tigeot 		 * chipset, thus just disable it for TV.
2372926deccbSFrançois Tigeot 		 */
2373926deccbSFrançois Tigeot 		if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480)
2374926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = false;
2375b5162e19SFrançois Tigeot 		drm_object_attach_property(&radeon_connector->base.base,
2376926deccbSFrançois Tigeot 					      rdev->mode_info.load_detect_property,
2377926deccbSFrançois Tigeot 					      radeon_connector->dac_load_detect);
2378b5162e19SFrançois Tigeot 		drm_object_attach_property(&radeon_connector->base.base,
2379926deccbSFrançois Tigeot 					      rdev->mode_info.tv_std_property,
2380926deccbSFrançois Tigeot 					      radeon_combios_get_tv_info(rdev));
2381926deccbSFrançois Tigeot 		/* no HPD on analog connectors */
2382926deccbSFrançois Tigeot 		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2383926deccbSFrançois Tigeot 		connector->interlace_allowed = false;
2384926deccbSFrançois Tigeot 		connector->doublescan_allowed = false;
2385926deccbSFrançois Tigeot 		break;
2386926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_LVDS:
2387926deccbSFrançois Tigeot 		drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
2388926deccbSFrançois Tigeot 		drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
2389926deccbSFrançois Tigeot 		if (i2c_bus->valid) {
2390926deccbSFrançois Tigeot 			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2391926deccbSFrançois Tigeot 			if (!radeon_connector->ddc_bus)
2392926deccbSFrançois Tigeot 				DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2393926deccbSFrançois Tigeot 		}
2394b5162e19SFrançois Tigeot 		drm_object_attach_property(&radeon_connector->base.base,
2395926deccbSFrançois Tigeot 					      dev->mode_config.scaling_mode_property,
2396926deccbSFrançois Tigeot 					      DRM_MODE_SCALE_FULLSCREEN);
2397926deccbSFrançois Tigeot 		subpixel_order = SubPixelHorizontalRGB;
2398926deccbSFrançois Tigeot 		connector->interlace_allowed = false;
2399926deccbSFrançois Tigeot 		connector->doublescan_allowed = false;
2400926deccbSFrançois Tigeot 		break;
2401926deccbSFrançois Tigeot 	}
2402926deccbSFrançois Tigeot 
2403926deccbSFrançois Tigeot 	if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
2404ee479021SImre Vadász 		if (i2c_bus->valid)
2405ee479021SImre Vadász 			connector->polled = DRM_CONNECTOR_POLL_CONNECT;
2406926deccbSFrançois Tigeot 	} else
2407926deccbSFrançois Tigeot 		connector->polled = DRM_CONNECTOR_POLL_HPD;
2408926deccbSFrançois Tigeot 	connector->display_info.subpixel_order = subpixel_order;
2409c6f73aabSFrançois Tigeot 	drm_connector_register(connector);
2410926deccbSFrançois Tigeot }
2411