xref: /dflybsd-src/sys/dev/drm/radeon/radeon_connectors.c (revision 83b4b9b96d578e400ab5890b64f60d69d4429e75)
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>
30*83b4b9b9SFranç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) {
3297191d616Szrj 		if (rdev->is_atom_bios) {
3307191d616Szrj 			/* some laptops provide a hardcoded edid in rom for LCDs */
331ee479021SImre Vadász 			if (((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_LVDS) ||
332ee479021SImre Vadász 			     (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)))
3337191d616Szrj 				radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev);
3347191d616Szrj 		} else {
3357191d616Szrj 			/* some servers provide a hardcoded edid in rom for KVMs */
3367191d616Szrj 			radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev);
3377191d616Szrj 		}
3387191d616Szrj 	}
3397191d616Szrj }
3407191d616Szrj 
341ee479021SImre Vadász static void radeon_connector_free_edid(struct radeon_connector *radeon_connector)
3427191d616Szrj {
3437191d616Szrj 	if (radeon_connector->edid) {
3447191d616Szrj 		kfree(radeon_connector->edid);
3457191d616Szrj 		radeon_connector->edid = NULL;
3467191d616Szrj 	}
3477191d616Szrj }
3487191d616Szrj 
349ee479021SImre Vadász static int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
3507191d616Szrj {
3517191d616Szrj 	int ret;
3527191d616Szrj 
3537191d616Szrj 	if (radeon_connector->edid) {
354ee479021SImre Vadász 		drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid);
355ee479021SImre Vadász 		ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid);
356ee479021SImre Vadász 		drm_edid_to_eld(&radeon_connector->base, radeon_connector->edid);
3577191d616Szrj 		return ret;
3587191d616Szrj 	}
359ee479021SImre Vadász 	drm_mode_connector_update_edid_property(&radeon_connector->base, NULL);
3607191d616Szrj 	return 0;
3617191d616Szrj }
3627191d616Szrj 
363926deccbSFrançois Tigeot static struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector)
364926deccbSFrançois Tigeot {
365926deccbSFrançois Tigeot 	int enc_id = connector->encoder_ids[0];
366926deccbSFrançois Tigeot 	/* pick the encoder ids */
367c6f73aabSFrançois Tigeot 	if (enc_id)
368c6f73aabSFrançois Tigeot 		return drm_encoder_find(connector->dev, enc_id);
369926deccbSFrançois Tigeot 	return NULL;
370926deccbSFrançois Tigeot }
371c6f73aabSFrançois Tigeot 
372c6f73aabSFrançois Tigeot static void radeon_get_native_mode(struct drm_connector *connector)
373c6f73aabSFrançois Tigeot {
374c6f73aabSFrançois Tigeot 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
375c6f73aabSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
376c6f73aabSFrançois Tigeot 
377c6f73aabSFrançois Tigeot 	if (encoder == NULL)
378c6f73aabSFrançois Tigeot 		return;
379c6f73aabSFrançois Tigeot 
380c6f73aabSFrançois Tigeot 	radeon_encoder = to_radeon_encoder(encoder);
381c6f73aabSFrançois Tigeot 
382c6f73aabSFrançois Tigeot 	if (!list_empty(&connector->probed_modes)) {
383c6f73aabSFrançois Tigeot 		struct drm_display_mode *preferred_mode =
384c6f73aabSFrançois Tigeot 			list_first_entry(&connector->probed_modes,
385c6f73aabSFrançois Tigeot 					 struct drm_display_mode, head);
386c6f73aabSFrançois Tigeot 
387c6f73aabSFrançois Tigeot 		radeon_encoder->native_mode = *preferred_mode;
388c6f73aabSFrançois Tigeot 	} else {
389c6f73aabSFrançois Tigeot 		radeon_encoder->native_mode.clock = 0;
390c6f73aabSFrançois Tigeot 	}
391926deccbSFrançois Tigeot }
392926deccbSFrançois Tigeot 
393926deccbSFrançois Tigeot /*
394926deccbSFrançois Tigeot  * radeon_connector_analog_encoder_conflict_solve
395926deccbSFrançois Tigeot  * - search for other connectors sharing this encoder
396926deccbSFrançois Tigeot  *   if priority is true, then set them disconnected if this is connected
397926deccbSFrançois Tigeot  *   if priority is false, set us disconnected if they are connected
398926deccbSFrançois Tigeot  */
399926deccbSFrançois Tigeot static enum drm_connector_status
400926deccbSFrançois Tigeot radeon_connector_analog_encoder_conflict_solve(struct drm_connector *connector,
401926deccbSFrançois Tigeot 					       struct drm_encoder *encoder,
402926deccbSFrançois Tigeot 					       enum drm_connector_status current_status,
403926deccbSFrançois Tigeot 					       bool priority)
404926deccbSFrançois Tigeot {
405926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
406926deccbSFrançois Tigeot 	struct drm_connector *conflict;
407926deccbSFrançois Tigeot 	struct radeon_connector *radeon_conflict;
408926deccbSFrançois Tigeot 	int i;
409926deccbSFrançois Tigeot 
410926deccbSFrançois Tigeot 	list_for_each_entry(conflict, &dev->mode_config.connector_list, head) {
411926deccbSFrançois Tigeot 		if (conflict == connector)
412926deccbSFrançois Tigeot 			continue;
413926deccbSFrançois Tigeot 
414926deccbSFrançois Tigeot 		radeon_conflict = to_radeon_connector(conflict);
415926deccbSFrançois Tigeot 		for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
416926deccbSFrançois Tigeot 			if (conflict->encoder_ids[i] == 0)
417926deccbSFrançois Tigeot 				break;
418926deccbSFrançois Tigeot 
419926deccbSFrançois Tigeot 			/* if the IDs match */
420926deccbSFrançois Tigeot 			if (conflict->encoder_ids[i] == encoder->base.id) {
421926deccbSFrançois Tigeot 				if (conflict->status != connector_status_connected)
422926deccbSFrançois Tigeot 					continue;
423926deccbSFrançois Tigeot 
424926deccbSFrançois Tigeot 				if (radeon_conflict->use_digital)
425926deccbSFrançois Tigeot 					continue;
426926deccbSFrançois Tigeot 
427926deccbSFrançois Tigeot 				if (priority == true) {
428ba55f2f5SFrançois Tigeot 					DRM_DEBUG_KMS("1: conflicting encoders switching off %s\n",
429ba55f2f5SFrançois Tigeot 						      conflict->name);
430ba55f2f5SFrançois Tigeot 					DRM_DEBUG_KMS("in favor of %s\n",
431ba55f2f5SFrançois Tigeot 						      connector->name);
432926deccbSFrançois Tigeot 					conflict->status = connector_status_disconnected;
433926deccbSFrançois Tigeot 					radeon_connector_update_scratch_regs(conflict, connector_status_disconnected);
434926deccbSFrançois Tigeot 				} else {
435ba55f2f5SFrançois Tigeot 					DRM_DEBUG_KMS("2: conflicting encoders switching off %s\n",
436ba55f2f5SFrançois Tigeot 						      connector->name);
437ba55f2f5SFrançois Tigeot 					DRM_DEBUG_KMS("in favor of %s\n",
438ba55f2f5SFrançois Tigeot 						      conflict->name);
439926deccbSFrançois Tigeot 					current_status = connector_status_disconnected;
440926deccbSFrançois Tigeot 				}
441926deccbSFrançois Tigeot 				break;
442926deccbSFrançois Tigeot 			}
443926deccbSFrançois Tigeot 		}
444926deccbSFrançois Tigeot 	}
445926deccbSFrançois Tigeot 	return current_status;
446926deccbSFrançois Tigeot 
447926deccbSFrançois Tigeot }
448926deccbSFrançois Tigeot 
449926deccbSFrançois Tigeot static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encoder)
450926deccbSFrançois Tigeot {
451926deccbSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
452926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
453926deccbSFrançois Tigeot 	struct drm_display_mode *mode = NULL;
454926deccbSFrançois Tigeot 	struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
455926deccbSFrançois Tigeot 
456926deccbSFrançois Tigeot 	if (native_mode->hdisplay != 0 &&
457926deccbSFrançois Tigeot 	    native_mode->vdisplay != 0 &&
458926deccbSFrançois Tigeot 	    native_mode->clock != 0) {
459926deccbSFrançois Tigeot 		mode = drm_mode_duplicate(dev, native_mode);
460926deccbSFrançois Tigeot 		mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
461926deccbSFrançois Tigeot 		drm_mode_set_name(mode);
462926deccbSFrançois Tigeot 
463926deccbSFrançois Tigeot 		DRM_DEBUG_KMS("Adding native panel mode %s\n", mode->name);
464926deccbSFrançois Tigeot 	} else if (native_mode->hdisplay != 0 &&
465926deccbSFrançois Tigeot 		   native_mode->vdisplay != 0) {
466926deccbSFrançois Tigeot 		/* mac laptops without an edid */
467926deccbSFrançois Tigeot 		/* Note that this is not necessarily the exact panel mode,
468926deccbSFrançois Tigeot 		 * but an approximation based on the cvt formula.  For these
469926deccbSFrançois Tigeot 		 * systems we should ideally read the mode info out of the
470926deccbSFrançois Tigeot 		 * registers or add a mode table, but this works and is much
471926deccbSFrançois Tigeot 		 * simpler.
472926deccbSFrançois Tigeot 		 */
473926deccbSFrançois Tigeot 		mode = drm_cvt_mode(dev, native_mode->hdisplay, native_mode->vdisplay, 60, true, false, false);
474926deccbSFrançois Tigeot 		mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
475926deccbSFrançois Tigeot 		DRM_DEBUG_KMS("Adding cvt approximation of native panel mode %s\n", mode->name);
476926deccbSFrançois Tigeot 	}
477926deccbSFrançois Tigeot 	return mode;
478926deccbSFrançois Tigeot }
479926deccbSFrançois Tigeot 
480926deccbSFrançois Tigeot static void radeon_add_common_modes(struct drm_encoder *encoder, struct drm_connector *connector)
481926deccbSFrançois Tigeot {
482926deccbSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
483926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
484926deccbSFrançois Tigeot 	struct drm_display_mode *mode = NULL;
485926deccbSFrançois Tigeot 	struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
486926deccbSFrançois Tigeot 	int i;
487926deccbSFrançois Tigeot 	struct mode_size {
488926deccbSFrançois Tigeot 		int w;
489926deccbSFrançois Tigeot 		int h;
490926deccbSFrançois Tigeot 	} common_modes[17] = {
491926deccbSFrançois Tigeot 		{ 640,  480},
492926deccbSFrançois Tigeot 		{ 720,  480},
493926deccbSFrançois Tigeot 		{ 800,  600},
494926deccbSFrançois Tigeot 		{ 848,  480},
495926deccbSFrançois Tigeot 		{1024,  768},
496926deccbSFrançois Tigeot 		{1152,  768},
497926deccbSFrançois Tigeot 		{1280,  720},
498926deccbSFrançois Tigeot 		{1280,  800},
499926deccbSFrançois Tigeot 		{1280,  854},
500926deccbSFrançois Tigeot 		{1280,  960},
501926deccbSFrançois Tigeot 		{1280, 1024},
502926deccbSFrançois Tigeot 		{1440,  900},
503926deccbSFrançois Tigeot 		{1400, 1050},
504926deccbSFrançois Tigeot 		{1680, 1050},
505926deccbSFrançois Tigeot 		{1600, 1200},
506926deccbSFrançois Tigeot 		{1920, 1080},
507926deccbSFrançois Tigeot 		{1920, 1200}
508926deccbSFrançois Tigeot 	};
509926deccbSFrançois Tigeot 
510926deccbSFrançois Tigeot 	for (i = 0; i < 17; i++) {
511926deccbSFrançois Tigeot 		if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) {
512926deccbSFrançois Tigeot 			if (common_modes[i].w > 1024 ||
513926deccbSFrançois Tigeot 			    common_modes[i].h > 768)
514926deccbSFrançois Tigeot 				continue;
515926deccbSFrançois Tigeot 		}
516926deccbSFrançois Tigeot 		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
517926deccbSFrançois Tigeot 			if (common_modes[i].w > native_mode->hdisplay ||
518926deccbSFrançois Tigeot 			    common_modes[i].h > native_mode->vdisplay ||
519926deccbSFrançois Tigeot 			    (common_modes[i].w == native_mode->hdisplay &&
520926deccbSFrançois Tigeot 			     common_modes[i].h == native_mode->vdisplay))
521926deccbSFrançois Tigeot 				continue;
522926deccbSFrançois Tigeot 		}
523926deccbSFrançois Tigeot 		if (common_modes[i].w < 320 || common_modes[i].h < 200)
524926deccbSFrançois Tigeot 			continue;
525926deccbSFrançois Tigeot 
526926deccbSFrançois Tigeot 		mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false);
527926deccbSFrançois Tigeot 		drm_mode_probed_add(connector, mode);
528926deccbSFrançois Tigeot 	}
529926deccbSFrançois Tigeot }
530926deccbSFrançois Tigeot 
531926deccbSFrançois Tigeot static int radeon_connector_set_property(struct drm_connector *connector, struct drm_property *property,
532926deccbSFrançois Tigeot 				  uint64_t val)
533926deccbSFrançois Tigeot {
534926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
535926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
536926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
537926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
538926deccbSFrançois Tigeot 
539926deccbSFrançois Tigeot 	if (property == rdev->mode_info.coherent_mode_property) {
540926deccbSFrançois Tigeot 		struct radeon_encoder_atom_dig *dig;
541926deccbSFrançois Tigeot 		bool new_coherent_mode;
542926deccbSFrançois Tigeot 
543926deccbSFrançois Tigeot 		/* need to find digital encoder on connector */
544926deccbSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
545926deccbSFrançois Tigeot 		if (!encoder)
546926deccbSFrançois Tigeot 			return 0;
547926deccbSFrançois Tigeot 
548926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
549926deccbSFrançois Tigeot 
550926deccbSFrançois Tigeot 		if (!radeon_encoder->enc_priv)
551926deccbSFrançois Tigeot 			return 0;
552926deccbSFrançois Tigeot 
553926deccbSFrançois Tigeot 		dig = radeon_encoder->enc_priv;
554926deccbSFrançois Tigeot 		new_coherent_mode = val ? true : false;
555926deccbSFrançois Tigeot 		if (dig->coherent_mode != new_coherent_mode) {
556926deccbSFrançois Tigeot 			dig->coherent_mode = new_coherent_mode;
557926deccbSFrançois Tigeot 			radeon_property_change_mode(&radeon_encoder->base);
558926deccbSFrançois Tigeot 		}
559926deccbSFrançois Tigeot 	}
560926deccbSFrançois Tigeot 
5614cd92098Szrj 	if (property == rdev->mode_info.audio_property) {
5624cd92098Szrj 		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
5634cd92098Szrj 		/* need to find digital encoder on connector */
5644cd92098Szrj 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
5654cd92098Szrj 		if (!encoder)
5664cd92098Szrj 			return 0;
5674cd92098Szrj 
5684cd92098Szrj 		radeon_encoder = to_radeon_encoder(encoder);
5694cd92098Szrj 
5704cd92098Szrj 		if (radeon_connector->audio != val) {
5714cd92098Szrj 			radeon_connector->audio = val;
5724cd92098Szrj 			radeon_property_change_mode(&radeon_encoder->base);
5734cd92098Szrj 		}
5744cd92098Szrj 	}
5754cd92098Szrj 
576c6f73aabSFrançois Tigeot 	if (property == rdev->mode_info.dither_property) {
577c6f73aabSFrançois Tigeot 		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
578c6f73aabSFrançois Tigeot 		/* need to find digital encoder on connector */
579c6f73aabSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
580c6f73aabSFrançois Tigeot 		if (!encoder)
581c6f73aabSFrançois Tigeot 			return 0;
582c6f73aabSFrançois Tigeot 
583c6f73aabSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
584c6f73aabSFrançois Tigeot 
585c6f73aabSFrançois Tigeot 		if (radeon_connector->dither != val) {
586c6f73aabSFrançois Tigeot 			radeon_connector->dither = val;
587c6f73aabSFrançois Tigeot 			radeon_property_change_mode(&radeon_encoder->base);
588c6f73aabSFrançois Tigeot 		}
589c6f73aabSFrançois Tigeot 	}
590c6f73aabSFrançois Tigeot 
591926deccbSFrançois Tigeot 	if (property == rdev->mode_info.underscan_property) {
592926deccbSFrançois Tigeot 		/* need to find digital encoder on connector */
593926deccbSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
594926deccbSFrançois Tigeot 		if (!encoder)
595926deccbSFrançois Tigeot 			return 0;
596926deccbSFrançois Tigeot 
597926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
598926deccbSFrançois Tigeot 
599926deccbSFrançois Tigeot 		if (radeon_encoder->underscan_type != val) {
600926deccbSFrançois Tigeot 			radeon_encoder->underscan_type = val;
601926deccbSFrançois Tigeot 			radeon_property_change_mode(&radeon_encoder->base);
602926deccbSFrançois Tigeot 		}
603926deccbSFrançois Tigeot 	}
604926deccbSFrançois Tigeot 
605926deccbSFrançois Tigeot 	if (property == rdev->mode_info.underscan_hborder_property) {
606926deccbSFrançois Tigeot 		/* need to find digital encoder on connector */
607926deccbSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
608926deccbSFrançois Tigeot 		if (!encoder)
609926deccbSFrançois Tigeot 			return 0;
610926deccbSFrançois Tigeot 
611926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
612926deccbSFrançois Tigeot 
613926deccbSFrançois Tigeot 		if (radeon_encoder->underscan_hborder != val) {
614926deccbSFrançois Tigeot 			radeon_encoder->underscan_hborder = val;
615926deccbSFrançois Tigeot 			radeon_property_change_mode(&radeon_encoder->base);
616926deccbSFrançois Tigeot 		}
617926deccbSFrançois Tigeot 	}
618926deccbSFrançois Tigeot 
619926deccbSFrançois Tigeot 	if (property == rdev->mode_info.underscan_vborder_property) {
620926deccbSFrançois Tigeot 		/* need to find digital encoder on connector */
621926deccbSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
622926deccbSFrançois Tigeot 		if (!encoder)
623926deccbSFrançois Tigeot 			return 0;
624926deccbSFrançois Tigeot 
625926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
626926deccbSFrançois Tigeot 
627926deccbSFrançois Tigeot 		if (radeon_encoder->underscan_vborder != val) {
628926deccbSFrançois Tigeot 			radeon_encoder->underscan_vborder = val;
629926deccbSFrançois Tigeot 			radeon_property_change_mode(&radeon_encoder->base);
630926deccbSFrançois Tigeot 		}
631926deccbSFrançois Tigeot 	}
632926deccbSFrançois Tigeot 
633926deccbSFrançois Tigeot 	if (property == rdev->mode_info.tv_std_property) {
634926deccbSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TVDAC);
635926deccbSFrançois Tigeot 		if (!encoder) {
636926deccbSFrançois Tigeot 			encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_DAC);
637926deccbSFrançois Tigeot 		}
638926deccbSFrançois Tigeot 
639926deccbSFrançois Tigeot 		if (!encoder)
640926deccbSFrançois Tigeot 			return 0;
641926deccbSFrançois Tigeot 
642926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
643926deccbSFrançois Tigeot 		if (!radeon_encoder->enc_priv)
644926deccbSFrançois Tigeot 			return 0;
645926deccbSFrançois Tigeot 		if (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom) {
646926deccbSFrançois Tigeot 			struct radeon_encoder_atom_dac *dac_int;
647926deccbSFrançois Tigeot 			dac_int = radeon_encoder->enc_priv;
648926deccbSFrançois Tigeot 			dac_int->tv_std = val;
649926deccbSFrançois Tigeot 		} else {
650926deccbSFrançois Tigeot 			struct radeon_encoder_tv_dac *dac_int;
651926deccbSFrançois Tigeot 			dac_int = radeon_encoder->enc_priv;
652926deccbSFrançois Tigeot 			dac_int->tv_std = val;
653926deccbSFrançois Tigeot 		}
654926deccbSFrançois Tigeot 		radeon_property_change_mode(&radeon_encoder->base);
655926deccbSFrançois Tigeot 	}
656926deccbSFrançois Tigeot 
657926deccbSFrançois Tigeot 	if (property == rdev->mode_info.load_detect_property) {
658926deccbSFrançois Tigeot 		struct radeon_connector *radeon_connector =
659926deccbSFrançois Tigeot 			to_radeon_connector(connector);
660926deccbSFrançois Tigeot 
661926deccbSFrançois Tigeot 		if (val == 0)
662926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = false;
663926deccbSFrançois Tigeot 		else
664926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
665926deccbSFrançois Tigeot 	}
666926deccbSFrançois Tigeot 
667926deccbSFrançois Tigeot 	if (property == rdev->mode_info.tmds_pll_property) {
668926deccbSFrançois Tigeot 		struct radeon_encoder_int_tmds *tmds = NULL;
669926deccbSFrançois Tigeot 		bool ret = false;
670926deccbSFrançois Tigeot 		/* need to find digital encoder on connector */
671926deccbSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
672926deccbSFrançois Tigeot 		if (!encoder)
673926deccbSFrançois Tigeot 			return 0;
674926deccbSFrançois Tigeot 
675926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
676926deccbSFrançois Tigeot 
677926deccbSFrançois Tigeot 		tmds = radeon_encoder->enc_priv;
678926deccbSFrançois Tigeot 		if (!tmds)
679926deccbSFrançois Tigeot 			return 0;
680926deccbSFrançois Tigeot 
681926deccbSFrançois Tigeot 		if (val == 0) {
682926deccbSFrançois Tigeot 			if (rdev->is_atom_bios)
683926deccbSFrançois Tigeot 				ret = radeon_atombios_get_tmds_info(radeon_encoder, tmds);
684926deccbSFrançois Tigeot 			else
685926deccbSFrançois Tigeot 				ret = radeon_legacy_get_tmds_info_from_combios(radeon_encoder, tmds);
686926deccbSFrançois Tigeot 		}
687926deccbSFrançois Tigeot 		if (val == 1 || ret == false) {
688926deccbSFrançois Tigeot 			radeon_legacy_get_tmds_info_from_table(radeon_encoder, tmds);
689926deccbSFrançois Tigeot 		}
690926deccbSFrançois Tigeot 		radeon_property_change_mode(&radeon_encoder->base);
691926deccbSFrançois Tigeot 	}
692926deccbSFrançois Tigeot 
693c6f73aabSFrançois Tigeot 	if (property == dev->mode_config.scaling_mode_property) {
694c6f73aabSFrançois Tigeot 		enum radeon_rmx_type rmx_type;
695c6f73aabSFrançois Tigeot 
696c6f73aabSFrançois Tigeot 		if (connector->encoder)
697c6f73aabSFrançois Tigeot 			radeon_encoder = to_radeon_encoder(connector->encoder);
698c6f73aabSFrançois Tigeot 		else {
699c0e85e96SFrançois Tigeot 			const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
700c6f73aabSFrançois Tigeot 			radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector));
701c6f73aabSFrançois Tigeot 		}
702c6f73aabSFrançois Tigeot 
703c6f73aabSFrançois Tigeot 		switch (val) {
704c6f73aabSFrançois Tigeot 		default:
705c6f73aabSFrançois Tigeot 		case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break;
706c6f73aabSFrançois Tigeot 		case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break;
707c6f73aabSFrançois Tigeot 		case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break;
708c6f73aabSFrançois Tigeot 		case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break;
709c6f73aabSFrançois Tigeot 		}
710c6f73aabSFrançois Tigeot 		if (radeon_encoder->rmx_type == rmx_type)
711c6f73aabSFrançois Tigeot 			return 0;
712c6f73aabSFrançois Tigeot 
713c6f73aabSFrançois Tigeot 		if ((rmx_type != DRM_MODE_SCALE_NONE) &&
714c6f73aabSFrançois Tigeot 		    (radeon_encoder->native_mode.clock == 0))
715c6f73aabSFrançois Tigeot 			return 0;
716c6f73aabSFrançois Tigeot 
717c6f73aabSFrançois Tigeot 		radeon_encoder->rmx_type = rmx_type;
718c6f73aabSFrançois Tigeot 
719c6f73aabSFrançois Tigeot 		radeon_property_change_mode(&radeon_encoder->base);
720c6f73aabSFrançois Tigeot 	}
721c6f73aabSFrançois Tigeot 
722926deccbSFrançois Tigeot 	return 0;
723926deccbSFrançois Tigeot }
724926deccbSFrançois Tigeot 
725926deccbSFrançois Tigeot static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder,
726926deccbSFrançois Tigeot 					  struct drm_connector *connector)
727926deccbSFrançois Tigeot {
728926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder =	to_radeon_encoder(encoder);
729926deccbSFrançois Tigeot 	struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
730926deccbSFrançois Tigeot 	struct drm_display_mode *t, *mode;
731926deccbSFrançois Tigeot 
732926deccbSFrançois Tigeot 	/* If the EDID preferred mode doesn't match the native mode, use it */
733926deccbSFrançois Tigeot 	list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
734926deccbSFrançois Tigeot 		if (mode->type & DRM_MODE_TYPE_PREFERRED) {
735926deccbSFrançois Tigeot 			if (mode->hdisplay != native_mode->hdisplay ||
736926deccbSFrançois Tigeot 			    mode->vdisplay != native_mode->vdisplay)
737926deccbSFrançois Tigeot 				memcpy(native_mode, mode, sizeof(*mode));
738926deccbSFrançois Tigeot 		}
739926deccbSFrançois Tigeot 	}
740926deccbSFrançois Tigeot 
741926deccbSFrançois Tigeot 	/* Try to get native mode details from EDID if necessary */
742926deccbSFrançois Tigeot 	if (!native_mode->clock) {
743926deccbSFrançois Tigeot 		list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
744926deccbSFrançois Tigeot 			if (mode->hdisplay == native_mode->hdisplay &&
745926deccbSFrançois Tigeot 			    mode->vdisplay == native_mode->vdisplay) {
746926deccbSFrançois Tigeot 				*native_mode = *mode;
747926deccbSFrançois Tigeot 				drm_mode_set_crtcinfo(native_mode, CRTC_INTERLACE_HALVE_V);
748926deccbSFrançois Tigeot 				DRM_DEBUG_KMS("Determined LVDS native mode details from EDID\n");
749926deccbSFrançois Tigeot 				break;
750926deccbSFrançois Tigeot 			}
751926deccbSFrançois Tigeot 		}
752926deccbSFrançois Tigeot 	}
753926deccbSFrançois Tigeot 
754926deccbSFrançois Tigeot 	if (!native_mode->clock) {
755926deccbSFrançois Tigeot 		DRM_DEBUG_KMS("No LVDS native mode details, disabling RMX\n");
756926deccbSFrançois Tigeot 		radeon_encoder->rmx_type = RMX_OFF;
757926deccbSFrançois Tigeot 	}
758926deccbSFrançois Tigeot }
759926deccbSFrançois Tigeot 
760926deccbSFrançois Tigeot static int radeon_lvds_get_modes(struct drm_connector *connector)
761926deccbSFrançois Tigeot {
762ee479021SImre Vadász 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
763926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
764926deccbSFrançois Tigeot 	int ret = 0;
765926deccbSFrançois Tigeot 	struct drm_display_mode *mode;
766926deccbSFrançois Tigeot 
767ee479021SImre Vadász 	if (radeon_connector->ddc_bus) {
768ee479021SImre Vadász 		radeon_connector_get_edid(radeon_connector);
769ee479021SImre Vadász 		ret = radeon_ddc_get_modes(radeon_connector);
770926deccbSFrançois Tigeot 		if (ret > 0) {
771926deccbSFrançois Tigeot 			encoder = radeon_best_single_encoder(connector);
772926deccbSFrançois Tigeot 			if (encoder) {
773926deccbSFrançois Tigeot 				radeon_fixup_lvds_native_mode(encoder, connector);
774926deccbSFrançois Tigeot 				/* add scaled modes */
775926deccbSFrançois Tigeot 				radeon_add_common_modes(encoder, connector);
776926deccbSFrançois Tigeot 			}
777926deccbSFrançois Tigeot 			return ret;
778926deccbSFrançois Tigeot 		}
779ee479021SImre Vadász 	}
780926deccbSFrançois Tigeot 
781926deccbSFrançois Tigeot 	encoder = radeon_best_single_encoder(connector);
782926deccbSFrançois Tigeot 	if (!encoder)
783926deccbSFrançois Tigeot 		return 0;
784926deccbSFrançois Tigeot 
785926deccbSFrançois Tigeot 	/* we have no EDID modes */
786926deccbSFrançois Tigeot 	mode = radeon_fp_native_mode(encoder);
787926deccbSFrançois Tigeot 	if (mode) {
788926deccbSFrançois Tigeot 		ret = 1;
789926deccbSFrançois Tigeot 		drm_mode_probed_add(connector, mode);
790926deccbSFrançois Tigeot 		/* add the width/height from vbios tables if available */
791926deccbSFrançois Tigeot 		connector->display_info.width_mm = mode->width_mm;
792926deccbSFrançois Tigeot 		connector->display_info.height_mm = mode->height_mm;
793926deccbSFrançois Tigeot 		/* add scaled modes */
794926deccbSFrançois Tigeot 		radeon_add_common_modes(encoder, connector);
795926deccbSFrançois Tigeot 	}
796926deccbSFrançois Tigeot 
797926deccbSFrançois Tigeot 	return ret;
798926deccbSFrançois Tigeot }
799926deccbSFrançois Tigeot 
800926deccbSFrançois Tigeot static int radeon_lvds_mode_valid(struct drm_connector *connector,
801926deccbSFrançois Tigeot 				  struct drm_display_mode *mode)
802926deccbSFrançois Tigeot {
803926deccbSFrançois Tigeot 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
804926deccbSFrançois Tigeot 
805926deccbSFrançois Tigeot 	if ((mode->hdisplay < 320) || (mode->vdisplay < 240))
806926deccbSFrançois Tigeot 		return MODE_PANEL;
807926deccbSFrançois Tigeot 
808926deccbSFrançois Tigeot 	if (encoder) {
809926deccbSFrançois Tigeot 		struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
810926deccbSFrançois Tigeot 		struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
811926deccbSFrançois Tigeot 
812926deccbSFrançois Tigeot 		/* AVIVO hardware supports downscaling modes larger than the panel
813926deccbSFrançois Tigeot 		 * to the panel size, but I'm not sure this is desirable.
814926deccbSFrançois Tigeot 		 */
815926deccbSFrançois Tigeot 		if ((mode->hdisplay > native_mode->hdisplay) ||
816926deccbSFrançois Tigeot 		    (mode->vdisplay > native_mode->vdisplay))
817926deccbSFrançois Tigeot 			return MODE_PANEL;
818926deccbSFrançois Tigeot 
819926deccbSFrançois Tigeot 		/* if scaling is disabled, block non-native modes */
820926deccbSFrançois Tigeot 		if (radeon_encoder->rmx_type == RMX_OFF) {
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 	}
826926deccbSFrançois Tigeot 
827926deccbSFrançois Tigeot 	return MODE_OK;
828926deccbSFrançois Tigeot }
829926deccbSFrançois Tigeot 
830926deccbSFrançois Tigeot static enum drm_connector_status
831926deccbSFrançois Tigeot radeon_lvds_detect(struct drm_connector *connector, bool force)
832926deccbSFrançois Tigeot {
833926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
834926deccbSFrançois Tigeot 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
835926deccbSFrançois Tigeot 	enum drm_connector_status ret = connector_status_disconnected;
836c6f73aabSFrançois Tigeot #ifdef PM_TODO
837c6f73aabSFrançois Tigeot 	int r;
838c6f73aabSFrançois Tigeot 
839c6f73aabSFrançois Tigeot 	r = pm_runtime_get_sync(connector->dev->dev);
840c6f73aabSFrançois Tigeot 	if (r < 0)
841c6f73aabSFrançois Tigeot 		return connector_status_disconnected;
842c6f73aabSFrançois Tigeot #endif
843926deccbSFrançois Tigeot 
844926deccbSFrançois Tigeot 	if (encoder) {
845926deccbSFrançois Tigeot 		struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
846926deccbSFrançois Tigeot 		struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
847926deccbSFrançois Tigeot 
848926deccbSFrançois Tigeot 		/* check if panel is valid */
849926deccbSFrançois Tigeot 		if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
850926deccbSFrançois Tigeot 			ret = connector_status_connected;
851ee479021SImre Vadász 
852926deccbSFrançois Tigeot 	}
853926deccbSFrançois Tigeot 
854926deccbSFrançois Tigeot 	/* check for edid as well */
855ee479021SImre Vadász 	radeon_connector_get_edid(radeon_connector);
856926deccbSFrançois Tigeot 	if (radeon_connector->edid)
857926deccbSFrançois Tigeot 		ret = connector_status_connected;
858926deccbSFrançois Tigeot 	else {
859926deccbSFrançois Tigeot 		if (radeon_connector->ddc_bus) {
8609f4ca867SFrançois Tigeot 			radeon_connector->edid = drm_get_edid_iic(&radeon_connector->base,
861ee479021SImre Vadász 							      radeon_connector->ddc_bus->adapter);
862926deccbSFrançois Tigeot 			if (radeon_connector->edid)
863926deccbSFrançois Tigeot 				ret = connector_status_connected;
864926deccbSFrançois Tigeot 		}
865926deccbSFrançois Tigeot 	}
866926deccbSFrançois Tigeot 	/* check acpi lid status ??? */
867926deccbSFrançois Tigeot 
868926deccbSFrançois Tigeot 	radeon_connector_update_scratch_regs(connector, ret);
869c6f73aabSFrançois Tigeot #ifdef PM_TODO
870c6f73aabSFrançois Tigeot 	pm_runtime_mark_last_busy(connector->dev->dev);
871c6f73aabSFrançois Tigeot 	pm_runtime_put_autosuspend(connector->dev->dev);
872c6f73aabSFrançois Tigeot #endif
873926deccbSFrançois Tigeot 	return ret;
874926deccbSFrançois Tigeot }
875926deccbSFrançois Tigeot 
876926deccbSFrançois Tigeot static void radeon_connector_destroy(struct drm_connector *connector)
877926deccbSFrançois Tigeot {
878926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
879926deccbSFrançois Tigeot 
880ee479021SImre Vadász 	radeon_connector_free_edid(radeon_connector);
881c4ef309bSzrj 	kfree(radeon_connector->con_priv);
882c6f73aabSFrançois Tigeot 	drm_connector_unregister(connector);
883926deccbSFrançois Tigeot 	drm_connector_cleanup(connector);
884c4ef309bSzrj 	kfree(connector);
885926deccbSFrançois Tigeot }
886926deccbSFrançois Tigeot 
887926deccbSFrançois Tigeot static int radeon_lvds_set_property(struct drm_connector *connector,
888926deccbSFrançois Tigeot 				    struct drm_property *property,
889926deccbSFrançois Tigeot 				    uint64_t value)
890926deccbSFrançois Tigeot {
891926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
892926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
893926deccbSFrançois Tigeot 	enum radeon_rmx_type rmx_type;
894926deccbSFrançois Tigeot 
895926deccbSFrançois Tigeot 	DRM_DEBUG_KMS("\n");
896926deccbSFrançois Tigeot 	if (property != dev->mode_config.scaling_mode_property)
897926deccbSFrançois Tigeot 		return 0;
898926deccbSFrançois Tigeot 
899926deccbSFrançois Tigeot 	if (connector->encoder)
900926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(connector->encoder);
901926deccbSFrançois Tigeot 	else {
902c0e85e96SFrançois Tigeot 		const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
903926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector));
904926deccbSFrançois Tigeot 	}
905926deccbSFrançois Tigeot 
906926deccbSFrançois Tigeot 	switch (value) {
907926deccbSFrançois Tigeot 	case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break;
908926deccbSFrançois Tigeot 	case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break;
909926deccbSFrançois Tigeot 	case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break;
910926deccbSFrançois Tigeot 	default:
911926deccbSFrançois Tigeot 	case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break;
912926deccbSFrançois Tigeot 	}
913926deccbSFrançois Tigeot 	if (radeon_encoder->rmx_type == rmx_type)
914926deccbSFrançois Tigeot 		return 0;
915926deccbSFrançois Tigeot 
916926deccbSFrançois Tigeot 	radeon_encoder->rmx_type = rmx_type;
917926deccbSFrançois Tigeot 
918926deccbSFrançois Tigeot 	radeon_property_change_mode(&radeon_encoder->base);
919926deccbSFrançois Tigeot 	return 0;
920926deccbSFrançois Tigeot }
921926deccbSFrançois Tigeot 
922926deccbSFrançois Tigeot 
923926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_lvds_connector_helper_funcs = {
924926deccbSFrançois Tigeot 	.get_modes = radeon_lvds_get_modes,
925926deccbSFrançois Tigeot 	.mode_valid = radeon_lvds_mode_valid,
926926deccbSFrançois Tigeot 	.best_encoder = radeon_best_single_encoder,
927926deccbSFrançois Tigeot };
928926deccbSFrançois Tigeot 
929926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_lvds_connector_funcs = {
930926deccbSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
931926deccbSFrançois Tigeot 	.detect = radeon_lvds_detect,
932926deccbSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
933926deccbSFrançois Tigeot 	.destroy = radeon_connector_destroy,
934926deccbSFrançois Tigeot 	.set_property = radeon_lvds_set_property,
935926deccbSFrançois Tigeot };
936926deccbSFrançois Tigeot 
937926deccbSFrançois Tigeot static int radeon_vga_get_modes(struct drm_connector *connector)
938926deccbSFrançois Tigeot {
939ee479021SImre Vadász 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
940926deccbSFrançois Tigeot 	int ret;
941926deccbSFrançois Tigeot 
942ee479021SImre Vadász 	radeon_connector_get_edid(radeon_connector);
943ee479021SImre Vadász 	ret = radeon_ddc_get_modes(radeon_connector);
944926deccbSFrançois Tigeot 
945c6f73aabSFrançois Tigeot 	radeon_get_native_mode(connector);
946c6f73aabSFrançois Tigeot 
947926deccbSFrançois Tigeot 	return ret;
948926deccbSFrançois Tigeot }
949926deccbSFrançois Tigeot 
950926deccbSFrançois Tigeot static int radeon_vga_mode_valid(struct drm_connector *connector,
951926deccbSFrançois Tigeot 				  struct drm_display_mode *mode)
952926deccbSFrançois Tigeot {
953926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
954926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
955926deccbSFrançois Tigeot 
956926deccbSFrançois Tigeot 	/* XXX check mode bandwidth */
957926deccbSFrançois Tigeot 
958926deccbSFrançois Tigeot 	if ((mode->clock / 10) > rdev->clock.max_pixel_clock)
959926deccbSFrançois Tigeot 		return MODE_CLOCK_HIGH;
960926deccbSFrançois Tigeot 
961926deccbSFrançois Tigeot 	return MODE_OK;
962926deccbSFrançois Tigeot }
963926deccbSFrançois Tigeot 
964926deccbSFrançois Tigeot static enum drm_connector_status
965926deccbSFrançois Tigeot radeon_vga_detect(struct drm_connector *connector, bool force)
966926deccbSFrançois Tigeot {
967926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
968926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
969926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
970926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
971c0e85e96SFrançois Tigeot 	const struct drm_encoder_helper_funcs *encoder_funcs;
972926deccbSFrançois Tigeot 	bool dret = false;
973926deccbSFrançois Tigeot 	enum drm_connector_status ret = connector_status_disconnected;
974c6f73aabSFrançois Tigeot #ifdef PM_TODO
975c6f73aabSFrançois Tigeot 	int r;
976c6f73aabSFrançois Tigeot 
977c6f73aabSFrançois Tigeot 	r = pm_runtime_get_sync(connector->dev->dev);
978c6f73aabSFrançois Tigeot 	if (r < 0)
979c6f73aabSFrançois Tigeot 		return connector_status_disconnected;
980c6f73aabSFrançois Tigeot #endif
981926deccbSFrançois Tigeot 
982926deccbSFrançois Tigeot 	encoder = radeon_best_single_encoder(connector);
983926deccbSFrançois Tigeot 	if (!encoder)
984926deccbSFrançois Tigeot 		ret = connector_status_disconnected;
985926deccbSFrançois Tigeot 
986926deccbSFrançois Tigeot 	if (radeon_connector->ddc_bus)
987926deccbSFrançois Tigeot 		dret = radeon_ddc_probe(radeon_connector, false);
988926deccbSFrançois Tigeot 	if (dret) {
989926deccbSFrançois Tigeot 		radeon_connector->detected_by_load = false;
990ee479021SImre Vadász 		radeon_connector_free_edid(radeon_connector);
991ee479021SImre Vadász 		radeon_connector_get_edid(radeon_connector);
992926deccbSFrançois Tigeot 
993926deccbSFrançois Tigeot 		if (!radeon_connector->edid) {
994926deccbSFrançois Tigeot 			DRM_ERROR("%s: probed a monitor but no|invalid EDID\n",
995ba55f2f5SFrançois Tigeot 					connector->name);
996926deccbSFrançois Tigeot 			ret = connector_status_connected;
997926deccbSFrançois Tigeot 		} else {
9987191d616Szrj 			radeon_connector->use_digital =
9997191d616Szrj 				!!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
1000926deccbSFrançois Tigeot 
1001926deccbSFrançois Tigeot 			/* some oems have boards with separate digital and analog connectors
1002926deccbSFrançois Tigeot 			 * with a shared ddc line (often vga + hdmi)
1003926deccbSFrançois Tigeot 			 */
1004926deccbSFrançois Tigeot 			if (radeon_connector->use_digital && radeon_connector->shared_ddc) {
1005ee479021SImre Vadász 				radeon_connector_free_edid(radeon_connector);
1006926deccbSFrançois Tigeot 				ret = connector_status_disconnected;
10077191d616Szrj 			} else {
1008926deccbSFrançois Tigeot 				ret = connector_status_connected;
1009926deccbSFrançois Tigeot 			}
10107191d616Szrj 		}
1011926deccbSFrançois Tigeot 	} else {
1012926deccbSFrançois Tigeot 
1013926deccbSFrançois Tigeot 		/* if we aren't forcing don't do destructive polling */
1014926deccbSFrançois Tigeot 		if (!force) {
1015926deccbSFrançois Tigeot 			/* only return the previous status if we last
1016926deccbSFrançois Tigeot 			 * detected a monitor via load.
1017926deccbSFrançois Tigeot 			 */
1018926deccbSFrançois Tigeot 			if (radeon_connector->detected_by_load)
1019c6f73aabSFrançois Tigeot 				ret = connector->status;
1020c6f73aabSFrançois Tigeot 			goto out;
1021926deccbSFrançois Tigeot 		}
1022926deccbSFrançois Tigeot 
1023926deccbSFrançois Tigeot 		if (radeon_connector->dac_load_detect && encoder) {
1024926deccbSFrançois Tigeot 			encoder_funcs = encoder->helper_private;
1025926deccbSFrançois Tigeot 			ret = encoder_funcs->detect(encoder, connector);
1026926deccbSFrançois Tigeot 			if (ret != connector_status_disconnected)
1027926deccbSFrançois Tigeot 				radeon_connector->detected_by_load = true;
1028926deccbSFrançois Tigeot 		}
1029926deccbSFrançois Tigeot 	}
1030926deccbSFrançois Tigeot 
1031926deccbSFrançois Tigeot 	if (ret == connector_status_connected)
1032926deccbSFrançois Tigeot 		ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true);
1033926deccbSFrançois Tigeot 
1034926deccbSFrançois Tigeot 	/* RN50 and some RV100 asics in servers often have a hardcoded EDID in the
1035926deccbSFrançois Tigeot 	 * vbios to deal with KVMs. If we have one and are not able to detect a monitor
1036926deccbSFrançois Tigeot 	 * by other means, assume the CRT is connected and use that EDID.
1037926deccbSFrançois Tigeot 	 */
1038926deccbSFrançois Tigeot 	if ((!rdev->is_atom_bios) &&
1039926deccbSFrançois Tigeot 	    (ret == connector_status_disconnected) &&
1040926deccbSFrançois Tigeot 	    rdev->mode_info.bios_hardcoded_edid_size) {
1041926deccbSFrançois Tigeot 		ret = connector_status_connected;
1042926deccbSFrançois Tigeot 	}
1043926deccbSFrançois Tigeot 
1044926deccbSFrançois Tigeot 	radeon_connector_update_scratch_regs(connector, ret);
1045c6f73aabSFrançois Tigeot 
1046c6f73aabSFrançois Tigeot out:
1047c6f73aabSFrançois Tigeot #ifdef PM_TODO
1048c6f73aabSFrançois Tigeot 	pm_runtime_mark_last_busy(connector->dev->dev);
1049c6f73aabSFrançois Tigeot 	pm_runtime_put_autosuspend(connector->dev->dev);
1050c6f73aabSFrançois Tigeot #endif
1051c6f73aabSFrançois Tigeot 
1052926deccbSFrançois Tigeot 	return ret;
1053926deccbSFrançois Tigeot }
1054926deccbSFrançois Tigeot 
1055926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_vga_connector_helper_funcs = {
1056926deccbSFrançois Tigeot 	.get_modes = radeon_vga_get_modes,
1057926deccbSFrançois Tigeot 	.mode_valid = radeon_vga_mode_valid,
1058926deccbSFrançois Tigeot 	.best_encoder = radeon_best_single_encoder,
1059926deccbSFrançois Tigeot };
1060926deccbSFrançois Tigeot 
1061926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_vga_connector_funcs = {
1062926deccbSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
1063926deccbSFrançois Tigeot 	.detect = radeon_vga_detect,
1064926deccbSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
1065926deccbSFrançois Tigeot 	.destroy = radeon_connector_destroy,
1066926deccbSFrançois Tigeot 	.set_property = radeon_connector_set_property,
1067926deccbSFrançois Tigeot };
1068926deccbSFrançois Tigeot 
1069926deccbSFrançois Tigeot static int radeon_tv_get_modes(struct drm_connector *connector)
1070926deccbSFrançois Tigeot {
1071926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1072926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1073926deccbSFrançois Tigeot 	struct drm_display_mode *tv_mode;
1074926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1075926deccbSFrançois Tigeot 
1076926deccbSFrançois Tigeot 	encoder = radeon_best_single_encoder(connector);
1077926deccbSFrançois Tigeot 	if (!encoder)
1078926deccbSFrançois Tigeot 		return 0;
1079926deccbSFrançois Tigeot 
1080926deccbSFrançois Tigeot 	/* avivo chips can scale any mode */
1081926deccbSFrançois Tigeot 	if (rdev->family >= CHIP_RS600)
1082926deccbSFrançois Tigeot 		/* add scaled modes */
1083926deccbSFrançois Tigeot 		radeon_add_common_modes(encoder, connector);
1084926deccbSFrançois Tigeot 	else {
1085926deccbSFrançois Tigeot 		/* only 800x600 is supported right now on pre-avivo chips */
1086926deccbSFrançois Tigeot 		tv_mode = drm_cvt_mode(dev, 800, 600, 60, false, false, false);
1087926deccbSFrançois Tigeot 		tv_mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
1088926deccbSFrançois Tigeot 		drm_mode_probed_add(connector, tv_mode);
1089926deccbSFrançois Tigeot 	}
1090926deccbSFrançois Tigeot 	return 1;
1091926deccbSFrançois Tigeot }
1092926deccbSFrançois Tigeot 
1093926deccbSFrançois Tigeot static int radeon_tv_mode_valid(struct drm_connector *connector,
1094926deccbSFrançois Tigeot 				struct drm_display_mode *mode)
1095926deccbSFrançois Tigeot {
1096926deccbSFrançois Tigeot 	if ((mode->hdisplay > 1024) || (mode->vdisplay > 768))
1097926deccbSFrançois Tigeot 		return MODE_CLOCK_RANGE;
1098926deccbSFrançois Tigeot 	return MODE_OK;
1099926deccbSFrançois Tigeot }
1100926deccbSFrançois Tigeot 
1101926deccbSFrançois Tigeot static enum drm_connector_status
1102926deccbSFrançois Tigeot radeon_tv_detect(struct drm_connector *connector, bool force)
1103926deccbSFrançois Tigeot {
1104926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1105c0e85e96SFrançois Tigeot 	const struct drm_encoder_helper_funcs *encoder_funcs;
1106926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1107926deccbSFrançois Tigeot 	enum drm_connector_status ret = connector_status_disconnected;
1108c6f73aabSFrançois Tigeot #ifdef PM_TODO
1109c6f73aabSFrançois Tigeot 	int r;
1110c6f73aabSFrançois Tigeot #endif
1111926deccbSFrançois Tigeot 
1112926deccbSFrançois Tigeot 	if (!radeon_connector->dac_load_detect)
1113926deccbSFrançois Tigeot 		return ret;
1114926deccbSFrançois Tigeot 
1115c6f73aabSFrançois Tigeot #ifdef PM_TODO
1116c6f73aabSFrançois Tigeot 	r = pm_runtime_get_sync(connector->dev->dev);
1117c6f73aabSFrançois Tigeot 	if (r < 0)
1118c6f73aabSFrançois Tigeot 		return connector_status_disconnected;
1119c6f73aabSFrançois Tigeot #endif
1120c6f73aabSFrançois Tigeot 
1121926deccbSFrançois Tigeot 	encoder = radeon_best_single_encoder(connector);
1122926deccbSFrançois Tigeot 	if (!encoder)
1123926deccbSFrançois Tigeot 		ret = connector_status_disconnected;
1124926deccbSFrançois Tigeot 	else {
1125926deccbSFrançois Tigeot 		encoder_funcs = encoder->helper_private;
1126926deccbSFrançois Tigeot 		ret = encoder_funcs->detect(encoder, connector);
1127926deccbSFrançois Tigeot 	}
1128926deccbSFrançois Tigeot 	if (ret == connector_status_connected)
1129926deccbSFrançois Tigeot 		ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false);
1130926deccbSFrançois Tigeot 	radeon_connector_update_scratch_regs(connector, ret);
1131c6f73aabSFrançois Tigeot #ifdef PM_TODO
1132c6f73aabSFrançois Tigeot 	pm_runtime_mark_last_busy(connector->dev->dev);
1133c6f73aabSFrançois Tigeot 	pm_runtime_put_autosuspend(connector->dev->dev);
1134c6f73aabSFrançois Tigeot #endif
1135926deccbSFrançois Tigeot 	return ret;
1136926deccbSFrançois Tigeot }
1137926deccbSFrançois Tigeot 
1138926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_tv_connector_helper_funcs = {
1139926deccbSFrançois Tigeot 	.get_modes = radeon_tv_get_modes,
1140926deccbSFrançois Tigeot 	.mode_valid = radeon_tv_mode_valid,
1141926deccbSFrançois Tigeot 	.best_encoder = radeon_best_single_encoder,
1142926deccbSFrançois Tigeot };
1143926deccbSFrançois Tigeot 
1144926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_tv_connector_funcs = {
1145926deccbSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
1146926deccbSFrançois Tigeot 	.detect = radeon_tv_detect,
1147926deccbSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
1148926deccbSFrançois Tigeot 	.destroy = radeon_connector_destroy,
1149926deccbSFrançois Tigeot 	.set_property = radeon_connector_set_property,
1150926deccbSFrançois Tigeot };
1151926deccbSFrançois Tigeot 
1152926deccbSFrançois Tigeot static bool radeon_check_hpd_status_unchanged(struct drm_connector *connector)
1153926deccbSFrançois Tigeot {
1154926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1155926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1156926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1157926deccbSFrançois Tigeot 	enum drm_connector_status status;
1158926deccbSFrançois Tigeot 
1159926deccbSFrançois Tigeot 	/* We only trust HPD on R600 and newer ASICS. */
1160926deccbSFrançois Tigeot 	if (rdev->family >= CHIP_R600
1161926deccbSFrançois Tigeot 	  && radeon_connector->hpd.hpd != RADEON_HPD_NONE) {
1162926deccbSFrançois Tigeot 		if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
1163926deccbSFrançois Tigeot 			status = connector_status_connected;
1164926deccbSFrançois Tigeot 		else
1165926deccbSFrançois Tigeot 			status = connector_status_disconnected;
1166926deccbSFrançois Tigeot 		if (connector->status == status)
1167926deccbSFrançois Tigeot 			return true;
1168926deccbSFrançois Tigeot 	}
1169926deccbSFrançois Tigeot 
1170926deccbSFrançois Tigeot 	return false;
1171926deccbSFrançois Tigeot }
1172926deccbSFrançois Tigeot 
1173926deccbSFrançois Tigeot /*
1174926deccbSFrançois Tigeot  * DVI is complicated
1175926deccbSFrançois Tigeot  * Do a DDC probe, if DDC probe passes, get the full EDID so
1176926deccbSFrançois Tigeot  * we can do analog/digital monitor detection at this point.
1177926deccbSFrançois Tigeot  * If the monitor is an analog monitor or we got no DDC,
1178926deccbSFrançois Tigeot  * we need to find the DAC encoder object for this connector.
1179926deccbSFrançois Tigeot  * If we got no DDC, we do load detection on the DAC encoder object.
1180926deccbSFrançois Tigeot  * If we got analog DDC or load detection passes on the DAC encoder
1181926deccbSFrançois Tigeot  * we have to check if this analog encoder is shared with anyone else (TV)
1182926deccbSFrançois Tigeot  * if its shared we have to set the other connector to disconnected.
1183926deccbSFrançois Tigeot  */
1184926deccbSFrançois Tigeot static enum drm_connector_status
1185926deccbSFrançois Tigeot radeon_dvi_detect(struct drm_connector *connector, bool force)
1186926deccbSFrançois Tigeot {
1187926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1188926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1189926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1190926deccbSFrançois Tigeot 	struct drm_encoder *encoder = NULL;
1191c0e85e96SFrançois Tigeot 	const struct drm_encoder_helper_funcs *encoder_funcs;
1192926deccbSFrançois Tigeot 	int i;
1193926deccbSFrançois Tigeot 	enum drm_connector_status ret = connector_status_disconnected;
1194926deccbSFrançois Tigeot 	bool dret = false, broken_edid = false;
1195926deccbSFrançois Tigeot 
1196c6f73aabSFrançois Tigeot #ifdef PM_TODO
1197c6f73aabSFrançois Tigeot 	r = pm_runtime_get_sync(connector->dev->dev);
1198c6f73aabSFrançois Tigeot 	if (r < 0)
1199c6f73aabSFrançois Tigeot 		return connector_status_disconnected;
1200c6f73aabSFrançois Tigeot #endif
1201c6f73aabSFrançois Tigeot 
1202c6f73aabSFrançois Tigeot 	if (!force && radeon_check_hpd_status_unchanged(connector)) {
1203c6f73aabSFrançois Tigeot 		ret = connector->status;
1204c6f73aabSFrançois Tigeot 		goto exit;
1205c6f73aabSFrançois Tigeot 	}
1206926deccbSFrançois Tigeot 
1207926deccbSFrançois Tigeot 	if (radeon_connector->ddc_bus)
1208926deccbSFrançois Tigeot 		dret = radeon_ddc_probe(radeon_connector, false);
1209926deccbSFrançois Tigeot 	if (dret) {
1210926deccbSFrançois Tigeot 		radeon_connector->detected_by_load = false;
1211ee479021SImre Vadász 		radeon_connector_free_edid(radeon_connector);
1212ee479021SImre Vadász 		radeon_connector_get_edid(radeon_connector);
1213926deccbSFrançois Tigeot 
1214926deccbSFrançois Tigeot 		if (!radeon_connector->edid) {
1215926deccbSFrançois Tigeot 			DRM_ERROR("%s: probed a monitor but no|invalid EDID\n",
1216ba55f2f5SFrançois Tigeot 					connector->name);
1217926deccbSFrançois Tigeot 			/* rs690 seems to have a problem with connectors not existing and always
1218926deccbSFrançois Tigeot 			 * return a block of 0's. If we see this just stop polling on this output */
12197191d616Szrj 			if ((rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) &&
12207191d616Szrj 			    radeon_connector->base.null_edid_counter) {
1221926deccbSFrançois Tigeot 				ret = connector_status_disconnected;
1222ba55f2f5SFrançois Tigeot 				DRM_ERROR("%s: detected RS690 floating bus bug, stopping ddc detect\n",
1223ba55f2f5SFrançois Tigeot 					  connector->name);
1224926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = NULL;
1225926deccbSFrançois Tigeot 			} else {
1226926deccbSFrançois Tigeot 				ret = connector_status_connected;
1227926deccbSFrançois Tigeot 				broken_edid = true; /* defer use_digital to later */
1228926deccbSFrançois Tigeot 			}
1229926deccbSFrançois Tigeot 		} else {
12307191d616Szrj 			radeon_connector->use_digital =
12317191d616Szrj 				!!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
1232926deccbSFrançois Tigeot 
1233926deccbSFrançois Tigeot 			/* some oems have boards with separate digital and analog connectors
1234926deccbSFrançois Tigeot 			 * with a shared ddc line (often vga + hdmi)
1235926deccbSFrançois Tigeot 			 */
1236926deccbSFrançois Tigeot 			if ((!radeon_connector->use_digital) && radeon_connector->shared_ddc) {
1237ee479021SImre Vadász 				radeon_connector_free_edid(radeon_connector);
1238926deccbSFrançois Tigeot 				ret = connector_status_disconnected;
12397191d616Szrj 			} else {
1240926deccbSFrançois Tigeot 				ret = connector_status_connected;
12417191d616Szrj 			}
1242926deccbSFrançois Tigeot 			/* This gets complicated.  We have boards with VGA + HDMI with a
1243926deccbSFrançois Tigeot 			 * shared DDC line and we have boards with DVI-D + HDMI with a shared
1244926deccbSFrançois Tigeot 			 * DDC line.  The latter is more complex because with DVI<->HDMI adapters
1245926deccbSFrançois Tigeot 			 * you don't really know what's connected to which port as both are digital.
1246926deccbSFrançois Tigeot 			 */
1247926deccbSFrançois Tigeot 			if (radeon_connector->shared_ddc && (ret == connector_status_connected)) {
1248926deccbSFrançois Tigeot 				struct drm_connector *list_connector;
1249926deccbSFrançois Tigeot 				struct radeon_connector *list_radeon_connector;
1250926deccbSFrançois Tigeot 				list_for_each_entry(list_connector, &dev->mode_config.connector_list, head) {
1251926deccbSFrançois Tigeot 					if (connector == list_connector)
1252926deccbSFrançois Tigeot 						continue;
1253926deccbSFrançois Tigeot 					list_radeon_connector = to_radeon_connector(list_connector);
1254926deccbSFrançois Tigeot 					if (list_radeon_connector->shared_ddc &&
1255926deccbSFrançois Tigeot 					    (list_radeon_connector->ddc_bus->rec.i2c_id ==
1256926deccbSFrançois Tigeot 					     radeon_connector->ddc_bus->rec.i2c_id)) {
1257926deccbSFrançois Tigeot 						/* cases where both connectors are digital */
1258926deccbSFrançois Tigeot 						if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) {
1259926deccbSFrançois Tigeot 							/* hpd is our only option in this case */
1260926deccbSFrançois Tigeot 							if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
1261ee479021SImre Vadász 								radeon_connector_free_edid(radeon_connector);
1262926deccbSFrançois Tigeot 								ret = connector_status_disconnected;
1263926deccbSFrançois Tigeot 							}
1264926deccbSFrançois Tigeot 						}
1265926deccbSFrançois Tigeot 					}
1266926deccbSFrançois Tigeot 				}
1267926deccbSFrançois Tigeot 			}
1268926deccbSFrançois Tigeot 		}
1269926deccbSFrançois Tigeot 	}
1270926deccbSFrançois Tigeot 
1271926deccbSFrançois Tigeot 	if ((ret == connector_status_connected) && (radeon_connector->use_digital == true))
1272926deccbSFrançois Tigeot 		goto out;
1273926deccbSFrançois Tigeot 
1274926deccbSFrançois Tigeot 	/* DVI-D and HDMI-A are digital only */
1275926deccbSFrançois Tigeot 	if ((connector->connector_type == DRM_MODE_CONNECTOR_DVID) ||
1276926deccbSFrançois Tigeot 	    (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA))
1277926deccbSFrançois Tigeot 		goto out;
1278926deccbSFrançois Tigeot 
1279926deccbSFrançois Tigeot 	/* if we aren't forcing don't do destructive polling */
1280926deccbSFrançois Tigeot 	if (!force) {
1281926deccbSFrançois Tigeot 		/* only return the previous status if we last
1282926deccbSFrançois Tigeot 		 * detected a monitor via load.
1283926deccbSFrançois Tigeot 		 */
1284926deccbSFrançois Tigeot 		if (radeon_connector->detected_by_load)
1285926deccbSFrançois Tigeot 			ret = connector->status;
1286926deccbSFrançois Tigeot 		goto out;
1287926deccbSFrançois Tigeot 	}
1288926deccbSFrançois Tigeot 
1289926deccbSFrançois Tigeot 	/* find analog encoder */
1290926deccbSFrançois Tigeot 	if (radeon_connector->dac_load_detect) {
1291926deccbSFrançois Tigeot 		for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1292926deccbSFrançois Tigeot 			if (connector->encoder_ids[i] == 0)
1293926deccbSFrançois Tigeot 				break;
1294926deccbSFrançois Tigeot 
1295c6f73aabSFrançois Tigeot 			encoder = drm_encoder_find(connector->dev,
1296c6f73aabSFrançois Tigeot 						   connector->encoder_ids[i]);
1297c6f73aabSFrançois Tigeot 			if (!encoder)
1298926deccbSFrançois Tigeot 				continue;
1299926deccbSFrançois Tigeot 
1300926deccbSFrançois Tigeot 			if (encoder->encoder_type != DRM_MODE_ENCODER_DAC &&
1301926deccbSFrançois Tigeot 			    encoder->encoder_type != DRM_MODE_ENCODER_TVDAC)
1302926deccbSFrançois Tigeot 				continue;
1303926deccbSFrançois Tigeot 
1304926deccbSFrançois Tigeot 			encoder_funcs = encoder->helper_private;
1305926deccbSFrançois Tigeot 			if (encoder_funcs->detect) {
1306926deccbSFrançois Tigeot 				if (!broken_edid) {
1307926deccbSFrançois Tigeot 					if (ret != connector_status_connected) {
1308926deccbSFrançois Tigeot 						/* deal with analog monitors without DDC */
1309926deccbSFrançois Tigeot 						ret = encoder_funcs->detect(encoder, connector);
1310926deccbSFrançois Tigeot 						if (ret == connector_status_connected) {
1311926deccbSFrançois Tigeot 							radeon_connector->use_digital = false;
1312926deccbSFrançois Tigeot 						}
1313926deccbSFrançois Tigeot 						if (ret != connector_status_disconnected)
1314926deccbSFrançois Tigeot 							radeon_connector->detected_by_load = true;
1315926deccbSFrançois Tigeot 					}
1316926deccbSFrançois Tigeot 				} else {
1317926deccbSFrançois Tigeot 					enum drm_connector_status lret;
1318926deccbSFrançois Tigeot 					/* assume digital unless load detected otherwise */
1319926deccbSFrançois Tigeot 					radeon_connector->use_digital = true;
1320926deccbSFrançois Tigeot 					lret = encoder_funcs->detect(encoder, connector);
1321926deccbSFrançois Tigeot 					DRM_DEBUG_KMS("load_detect %x returned: %x\n",encoder->encoder_type,lret);
1322926deccbSFrançois Tigeot 					if (lret == connector_status_connected)
1323926deccbSFrançois Tigeot 						radeon_connector->use_digital = false;
1324926deccbSFrançois Tigeot 				}
1325926deccbSFrançois Tigeot 				break;
1326926deccbSFrançois Tigeot 			}
1327926deccbSFrançois Tigeot 		}
1328926deccbSFrançois Tigeot 	}
1329926deccbSFrançois Tigeot 
1330926deccbSFrançois Tigeot 	if ((ret == connector_status_connected) && (radeon_connector->use_digital == false) &&
1331926deccbSFrançois Tigeot 	    encoder) {
1332926deccbSFrançois Tigeot 		ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true);
1333926deccbSFrançois Tigeot 	}
1334926deccbSFrançois Tigeot 
1335926deccbSFrançois Tigeot 	/* RN50 and some RV100 asics in servers often have a hardcoded EDID in the
1336926deccbSFrançois Tigeot 	 * vbios to deal with KVMs. If we have one and are not able to detect a monitor
1337926deccbSFrançois Tigeot 	 * by other means, assume the DFP is connected and use that EDID.  In most
1338926deccbSFrançois Tigeot 	 * cases the DVI port is actually a virtual KVM port connected to the service
1339926deccbSFrançois Tigeot 	 * processor.
1340926deccbSFrançois Tigeot 	 */
1341926deccbSFrançois Tigeot out:
1342926deccbSFrançois Tigeot 	if ((!rdev->is_atom_bios) &&
1343926deccbSFrançois Tigeot 	    (ret == connector_status_disconnected) &&
1344926deccbSFrançois Tigeot 	    rdev->mode_info.bios_hardcoded_edid_size) {
1345926deccbSFrançois Tigeot 		radeon_connector->use_digital = true;
1346926deccbSFrançois Tigeot 		ret = connector_status_connected;
1347926deccbSFrançois Tigeot 	}
1348926deccbSFrançois Tigeot 
1349926deccbSFrançois Tigeot 	/* updated in get modes as well since we need to know if it's analog or digital */
1350926deccbSFrançois Tigeot 	radeon_connector_update_scratch_regs(connector, ret);
1351c6f73aabSFrançois Tigeot 
1352c6f73aabSFrançois Tigeot exit:
1353c6f73aabSFrançois Tigeot #ifdef PM_TODO
1354c6f73aabSFrançois Tigeot 	pm_runtime_mark_last_busy(connector->dev->dev);
1355c6f73aabSFrançois Tigeot 	pm_runtime_put_autosuspend(connector->dev->dev);
1356c6f73aabSFrançois Tigeot #endif
1357c6f73aabSFrançois Tigeot 
1358926deccbSFrançois Tigeot 	return ret;
1359926deccbSFrançois Tigeot }
1360926deccbSFrançois Tigeot 
1361926deccbSFrançois Tigeot /* okay need to be smart in here about which encoder to pick */
1362926deccbSFrançois Tigeot static struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector)
1363926deccbSFrançois Tigeot {
1364926deccbSFrançois Tigeot 	int enc_id = connector->encoder_ids[0];
1365926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1366926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1367926deccbSFrançois Tigeot 	int i;
1368926deccbSFrançois Tigeot 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1369926deccbSFrançois Tigeot 		if (connector->encoder_ids[i] == 0)
1370926deccbSFrançois Tigeot 			break;
1371926deccbSFrançois Tigeot 
1372c6f73aabSFrançois Tigeot 		encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
1373c6f73aabSFrançois Tigeot 		if (!encoder)
1374926deccbSFrançois Tigeot 			continue;
1375926deccbSFrançois Tigeot 
1376926deccbSFrançois Tigeot 		if (radeon_connector->use_digital == true) {
1377926deccbSFrançois Tigeot 			if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
1378926deccbSFrançois Tigeot 				return encoder;
1379926deccbSFrançois Tigeot 		} else {
1380926deccbSFrançois Tigeot 			if (encoder->encoder_type == DRM_MODE_ENCODER_DAC ||
1381926deccbSFrançois Tigeot 			    encoder->encoder_type == DRM_MODE_ENCODER_TVDAC)
1382926deccbSFrançois Tigeot 				return encoder;
1383926deccbSFrançois Tigeot 		}
1384926deccbSFrançois Tigeot 	}
1385926deccbSFrançois Tigeot 
1386926deccbSFrançois Tigeot 	/* see if we have a default encoder  TODO */
1387926deccbSFrançois Tigeot 
1388926deccbSFrançois Tigeot 	/* then check use digitial */
1389926deccbSFrançois Tigeot 	/* pick the first one */
1390c6f73aabSFrançois Tigeot 	if (enc_id)
1391c6f73aabSFrançois Tigeot 		return drm_encoder_find(connector->dev, enc_id);
1392926deccbSFrançois Tigeot 	return NULL;
1393926deccbSFrançois Tigeot }
1394926deccbSFrançois Tigeot 
1395926deccbSFrançois Tigeot static void radeon_dvi_force(struct drm_connector *connector)
1396926deccbSFrançois Tigeot {
1397926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1398926deccbSFrançois Tigeot 	if (connector->force == DRM_FORCE_ON)
1399926deccbSFrançois Tigeot 		radeon_connector->use_digital = false;
1400926deccbSFrançois Tigeot 	if (connector->force == DRM_FORCE_ON_DIGITAL)
1401926deccbSFrançois Tigeot 		radeon_connector->use_digital = true;
1402926deccbSFrançois Tigeot }
1403926deccbSFrançois Tigeot 
1404926deccbSFrançois Tigeot static int radeon_dvi_mode_valid(struct drm_connector *connector,
1405926deccbSFrançois Tigeot 				  struct drm_display_mode *mode)
1406926deccbSFrançois Tigeot {
1407926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1408926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1409926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1410926deccbSFrançois Tigeot 
1411926deccbSFrançois Tigeot 	/* XXX check mode bandwidth */
1412926deccbSFrançois Tigeot 
1413926deccbSFrançois Tigeot 	/* clocks over 135 MHz have heat issues with DVI on RV100 */
1414926deccbSFrançois Tigeot 	if (radeon_connector->use_digital &&
1415926deccbSFrançois Tigeot 	    (rdev->family == CHIP_RV100) &&
1416926deccbSFrançois Tigeot 	    (mode->clock > 135000))
1417926deccbSFrançois Tigeot 		return MODE_CLOCK_HIGH;
1418926deccbSFrançois Tigeot 
1419926deccbSFrançois Tigeot 	if (radeon_connector->use_digital && (mode->clock > 165000)) {
1420926deccbSFrançois Tigeot 		if ((radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I) ||
1421926deccbSFrançois Tigeot 		    (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D) ||
1422926deccbSFrançois Tigeot 		    (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_B))
1423926deccbSFrançois Tigeot 			return MODE_OK;
1424c6f73aabSFrançois Tigeot 		else if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
1425926deccbSFrançois Tigeot 			/* HDMI 1.3+ supports max clock of 340 Mhz */
1426926deccbSFrançois Tigeot 			if (mode->clock > 340000)
1427926deccbSFrançois Tigeot 				return MODE_CLOCK_HIGH;
1428926deccbSFrançois Tigeot 			else
1429926deccbSFrançois Tigeot 				return MODE_OK;
1430c6f73aabSFrançois Tigeot 		} else {
1431926deccbSFrançois Tigeot 			return MODE_CLOCK_HIGH;
1432c6f73aabSFrançois Tigeot 		}
1433926deccbSFrançois Tigeot 	}
1434926deccbSFrançois Tigeot 
1435926deccbSFrançois Tigeot 	/* check against the max pixel clock */
1436926deccbSFrançois Tigeot 	if ((mode->clock / 10) > rdev->clock.max_pixel_clock)
1437926deccbSFrançois Tigeot 		return MODE_CLOCK_HIGH;
1438926deccbSFrançois Tigeot 
1439926deccbSFrançois Tigeot 	return MODE_OK;
1440926deccbSFrançois Tigeot }
1441926deccbSFrançois Tigeot 
1442926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = {
1443c6f73aabSFrançois Tigeot 	.get_modes = radeon_vga_get_modes,
1444926deccbSFrançois Tigeot 	.mode_valid = radeon_dvi_mode_valid,
1445926deccbSFrançois Tigeot 	.best_encoder = radeon_dvi_encoder,
1446926deccbSFrançois Tigeot };
1447926deccbSFrançois Tigeot 
1448926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_dvi_connector_funcs = {
1449926deccbSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
1450926deccbSFrançois Tigeot 	.detect = radeon_dvi_detect,
1451926deccbSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
1452926deccbSFrançois Tigeot 	.set_property = radeon_connector_set_property,
1453926deccbSFrançois Tigeot 	.destroy = radeon_connector_destroy,
1454926deccbSFrançois Tigeot 	.force = radeon_dvi_force,
1455926deccbSFrançois Tigeot };
1456926deccbSFrançois Tigeot 
1457ee479021SImre Vadász static void radeon_dp_connector_destroy(struct drm_connector *connector)
1458ee479021SImre Vadász {
1459ee479021SImre Vadász 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1460ee479021SImre Vadász 	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
1461ee479021SImre Vadász 
1462ee479021SImre Vadász 	radeon_connector_free_edid(radeon_connector);
1463ee479021SImre Vadász 	if (radeon_dig_connector->dp_i2c_bus)
1464ee479021SImre Vadász 		radeon_i2c_destroy(radeon_dig_connector->dp_i2c_bus);
1465ee479021SImre Vadász 	kfree(radeon_connector->con_priv);
1466ee479021SImre Vadász 	drm_connector_unregister(connector);
1467ee479021SImre Vadász 	drm_connector_cleanup(connector);
1468ee479021SImre Vadász 	kfree(connector);
1469ee479021SImre Vadász }
1470ee479021SImre Vadász 
1471926deccbSFrançois Tigeot static int radeon_dp_get_modes(struct drm_connector *connector)
1472926deccbSFrançois Tigeot {
1473926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1474926deccbSFrançois Tigeot 	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
1475926deccbSFrançois Tigeot 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
1476926deccbSFrançois Tigeot 	int ret;
1477926deccbSFrançois Tigeot 
1478926deccbSFrançois Tigeot 	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
1479926deccbSFrançois Tigeot 	    (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
1480926deccbSFrançois Tigeot 		struct drm_display_mode *mode;
1481926deccbSFrançois Tigeot 
1482926deccbSFrançois Tigeot 		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
1483926deccbSFrançois Tigeot 			if (!radeon_dig_connector->edp_on)
1484926deccbSFrançois Tigeot 				atombios_set_edp_panel_power(connector,
1485926deccbSFrançois Tigeot 							     ATOM_TRANSMITTER_ACTION_POWER_ON);
1486ee479021SImre Vadász 			radeon_connector_get_edid(radeon_connector);
1487ee479021SImre Vadász 			ret = radeon_ddc_get_modes(radeon_connector);
1488926deccbSFrançois Tigeot 			if (!radeon_dig_connector->edp_on)
1489926deccbSFrançois Tigeot 				atombios_set_edp_panel_power(connector,
1490926deccbSFrançois Tigeot 							     ATOM_TRANSMITTER_ACTION_POWER_OFF);
1491926deccbSFrançois Tigeot 		} else {
1492926deccbSFrançois Tigeot 			/* need to setup ddc on the bridge */
1493926deccbSFrançois Tigeot 			if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
1494926deccbSFrançois Tigeot 			    ENCODER_OBJECT_ID_NONE) {
1495926deccbSFrançois Tigeot 				if (encoder)
1496926deccbSFrançois Tigeot 					radeon_atom_ext_encoder_setup_ddc(encoder);
1497926deccbSFrançois Tigeot 			}
1498ee479021SImre Vadász 			radeon_connector_get_edid(radeon_connector);
1499ee479021SImre Vadász 			ret = radeon_ddc_get_modes(radeon_connector);
1500926deccbSFrançois Tigeot 		}
1501926deccbSFrançois Tigeot 
1502926deccbSFrançois Tigeot 		if (ret > 0) {
1503926deccbSFrançois Tigeot 			if (encoder) {
1504926deccbSFrançois Tigeot 				radeon_fixup_lvds_native_mode(encoder, connector);
1505926deccbSFrançois Tigeot 				/* add scaled modes */
1506926deccbSFrançois Tigeot 				radeon_add_common_modes(encoder, connector);
1507926deccbSFrançois Tigeot 			}
1508926deccbSFrançois Tigeot 			return ret;
1509926deccbSFrançois Tigeot 		}
1510926deccbSFrançois Tigeot 
1511926deccbSFrançois Tigeot 		if (!encoder)
1512926deccbSFrançois Tigeot 			return 0;
1513926deccbSFrançois Tigeot 
1514926deccbSFrançois Tigeot 		/* we have no EDID modes */
1515926deccbSFrançois Tigeot 		mode = radeon_fp_native_mode(encoder);
1516926deccbSFrançois Tigeot 		if (mode) {
1517926deccbSFrançois Tigeot 			ret = 1;
1518926deccbSFrançois Tigeot 			drm_mode_probed_add(connector, mode);
1519926deccbSFrançois Tigeot 			/* add the width/height from vbios tables if available */
1520926deccbSFrançois Tigeot 			connector->display_info.width_mm = mode->width_mm;
1521926deccbSFrançois Tigeot 			connector->display_info.height_mm = mode->height_mm;
1522926deccbSFrançois Tigeot 			/* add scaled modes */
1523926deccbSFrançois Tigeot 			radeon_add_common_modes(encoder, connector);
1524926deccbSFrançois Tigeot 		}
1525926deccbSFrançois Tigeot 	} else {
1526926deccbSFrançois Tigeot 		/* need to setup ddc on the bridge */
1527926deccbSFrançois Tigeot 		if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
1528926deccbSFrançois Tigeot 			ENCODER_OBJECT_ID_NONE) {
1529926deccbSFrançois Tigeot 			if (encoder)
1530926deccbSFrançois Tigeot 				radeon_atom_ext_encoder_setup_ddc(encoder);
1531926deccbSFrançois Tigeot 		}
1532ee479021SImre Vadász 		radeon_connector_get_edid(radeon_connector);
1533ee479021SImre Vadász 		ret = radeon_ddc_get_modes(radeon_connector);
1534c6f73aabSFrançois Tigeot 
1535c6f73aabSFrançois Tigeot 		radeon_get_native_mode(connector);
1536926deccbSFrançois Tigeot 	}
1537926deccbSFrançois Tigeot 
1538926deccbSFrançois Tigeot 	return ret;
1539926deccbSFrançois Tigeot }
1540926deccbSFrançois Tigeot 
1541926deccbSFrançois Tigeot u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector)
1542926deccbSFrançois Tigeot {
1543926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1544926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
1545926deccbSFrançois Tigeot 	int i;
1546926deccbSFrançois Tigeot 
1547926deccbSFrançois Tigeot 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1548926deccbSFrançois Tigeot 		if (connector->encoder_ids[i] == 0)
1549926deccbSFrançois Tigeot 			break;
1550926deccbSFrançois Tigeot 
1551c6f73aabSFrançois Tigeot 		encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
1552c6f73aabSFrançois Tigeot 		if (!encoder)
1553926deccbSFrançois Tigeot 			continue;
1554926deccbSFrançois Tigeot 
1555926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
1556926deccbSFrançois Tigeot 
1557926deccbSFrançois Tigeot 		switch (radeon_encoder->encoder_id) {
1558926deccbSFrançois Tigeot 		case ENCODER_OBJECT_ID_TRAVIS:
1559926deccbSFrançois Tigeot 		case ENCODER_OBJECT_ID_NUTMEG:
1560926deccbSFrançois Tigeot 			return radeon_encoder->encoder_id;
1561926deccbSFrançois Tigeot 		default:
1562926deccbSFrançois Tigeot 			break;
1563926deccbSFrançois Tigeot 		}
1564926deccbSFrançois Tigeot 	}
1565926deccbSFrançois Tigeot 
1566926deccbSFrançois Tigeot 	return ENCODER_OBJECT_ID_NONE;
1567926deccbSFrançois Tigeot }
1568926deccbSFrançois Tigeot 
1569c6f73aabSFrançois Tigeot static bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector)
1570926deccbSFrançois Tigeot {
1571926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1572926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
1573926deccbSFrançois Tigeot 	int i;
1574926deccbSFrançois Tigeot 	bool found = false;
1575926deccbSFrançois Tigeot 
1576926deccbSFrançois Tigeot 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1577926deccbSFrançois Tigeot 		if (connector->encoder_ids[i] == 0)
1578926deccbSFrançois Tigeot 			break;
1579926deccbSFrançois Tigeot 
1580c6f73aabSFrançois Tigeot 		encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
1581c6f73aabSFrançois Tigeot 		if (!encoder)
1582926deccbSFrançois Tigeot 			continue;
1583926deccbSFrançois Tigeot 
1584926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
1585926deccbSFrançois Tigeot 		if (radeon_encoder->caps & ATOM_ENCODER_CAP_RECORD_HBR2)
1586926deccbSFrançois Tigeot 			found = true;
1587926deccbSFrançois Tigeot 	}
1588926deccbSFrançois Tigeot 
1589926deccbSFrançois Tigeot 	return found;
1590926deccbSFrançois Tigeot }
1591926deccbSFrançois Tigeot 
1592926deccbSFrançois Tigeot bool radeon_connector_is_dp12_capable(struct drm_connector *connector)
1593926deccbSFrançois Tigeot {
1594926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1595926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1596926deccbSFrançois Tigeot 
1597926deccbSFrançois Tigeot 	if (ASIC_IS_DCE5(rdev) &&
1598c6f73aabSFrançois Tigeot 	    (rdev->clock.default_dispclk >= 53900) &&
1599926deccbSFrançois Tigeot 	    radeon_connector_encoder_is_hbr2(connector)) {
1600926deccbSFrançois Tigeot 		return true;
1601926deccbSFrançois Tigeot 	}
1602926deccbSFrançois Tigeot 
1603926deccbSFrançois Tigeot 	return false;
1604926deccbSFrançois Tigeot }
1605926deccbSFrançois Tigeot 
1606926deccbSFrançois Tigeot static enum drm_connector_status
1607926deccbSFrançois Tigeot radeon_dp_detect(struct drm_connector *connector, bool force)
1608926deccbSFrançois Tigeot {
1609926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1610926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1611926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1612926deccbSFrançois Tigeot 	enum drm_connector_status ret = connector_status_disconnected;
1613926deccbSFrançois Tigeot 	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
1614926deccbSFrançois Tigeot 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
1615c6f73aabSFrançois Tigeot #ifdef PM_TODO
1616c6f73aabSFrançois Tigeot 	int r;
1617926deccbSFrançois Tigeot 
1618c6f73aabSFrançois Tigeot 	r = pm_runtime_get_sync(connector->dev->dev);
1619c6f73aabSFrançois Tigeot 	if (r < 0)
1620c6f73aabSFrançois Tigeot 		return connector_status_disconnected;
1621c6f73aabSFrançois Tigeot #endif
1622c6f73aabSFrançois Tigeot 
1623c6f73aabSFrançois Tigeot 	if (!force && radeon_check_hpd_status_unchanged(connector)) {
1624c6f73aabSFrançois Tigeot 		ret = connector->status;
1625c6f73aabSFrançois Tigeot 		goto out;
1626c6f73aabSFrançois Tigeot 	}
1627926deccbSFrançois Tigeot 
1628ee479021SImre Vadász 	radeon_connector_free_edid(radeon_connector);
1629926deccbSFrançois Tigeot 
1630926deccbSFrançois Tigeot 	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
1631926deccbSFrançois Tigeot 	    (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
1632926deccbSFrançois Tigeot 		if (encoder) {
1633926deccbSFrançois Tigeot 			struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
1634926deccbSFrançois Tigeot 			struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
1635926deccbSFrançois Tigeot 
1636926deccbSFrançois Tigeot 			/* check if panel is valid */
1637926deccbSFrançois Tigeot 			if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
1638926deccbSFrançois Tigeot 				ret = connector_status_connected;
1639926deccbSFrançois Tigeot 		}
1640926deccbSFrançois Tigeot 		/* eDP is always DP */
1641926deccbSFrançois Tigeot 		radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
1642926deccbSFrançois Tigeot 		if (!radeon_dig_connector->edp_on)
1643926deccbSFrançois Tigeot 			atombios_set_edp_panel_power(connector,
1644926deccbSFrançois Tigeot 						     ATOM_TRANSMITTER_ACTION_POWER_ON);
1645926deccbSFrançois Tigeot 		if (radeon_dp_getdpcd(radeon_connector))
1646926deccbSFrançois Tigeot 			ret = connector_status_connected;
1647926deccbSFrançois Tigeot 		if (!radeon_dig_connector->edp_on)
1648926deccbSFrançois Tigeot 			atombios_set_edp_panel_power(connector,
1649926deccbSFrançois Tigeot 						     ATOM_TRANSMITTER_ACTION_POWER_OFF);
1650926deccbSFrançois Tigeot 	} else if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
1651926deccbSFrançois Tigeot 		   ENCODER_OBJECT_ID_NONE) {
1652926deccbSFrançois Tigeot 		/* DP bridges are always DP */
1653926deccbSFrançois Tigeot 		radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
1654926deccbSFrançois Tigeot 		/* get the DPCD from the bridge */
1655926deccbSFrançois Tigeot 		radeon_dp_getdpcd(radeon_connector);
1656926deccbSFrançois Tigeot 
1657926deccbSFrançois Tigeot 		if (encoder) {
1658926deccbSFrançois Tigeot 			/* setup ddc on the bridge */
1659926deccbSFrançois Tigeot 			radeon_atom_ext_encoder_setup_ddc(encoder);
1660926deccbSFrançois Tigeot 			/* bridge chips are always aux */
1661926deccbSFrançois Tigeot 			if (radeon_ddc_probe(radeon_connector, true)) /* try DDC */
1662926deccbSFrançois Tigeot 				ret = connector_status_connected;
1663926deccbSFrançois Tigeot 			else if (radeon_connector->dac_load_detect) { /* try load detection */
1664c0e85e96SFrançois Tigeot 				const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
1665926deccbSFrançois Tigeot 				ret = encoder_funcs->detect(encoder, connector);
1666926deccbSFrançois Tigeot 			}
1667926deccbSFrançois Tigeot 		}
1668926deccbSFrançois Tigeot 	} else {
1669926deccbSFrançois Tigeot 		radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
1670926deccbSFrançois Tigeot 		if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
1671926deccbSFrançois Tigeot 			ret = connector_status_connected;
1672926deccbSFrançois Tigeot 			if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT)
1673926deccbSFrançois Tigeot 				radeon_dp_getdpcd(radeon_connector);
1674926deccbSFrançois Tigeot 		} else {
1675926deccbSFrançois Tigeot 			if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
1676926deccbSFrançois Tigeot 				if (radeon_dp_getdpcd(radeon_connector))
1677926deccbSFrançois Tigeot 					ret = connector_status_connected;
1678926deccbSFrançois Tigeot 			} else {
16794cd92098Szrj 				/* try non-aux ddc (DP to DVI/HDMI/etc. adapter) */
1680926deccbSFrançois Tigeot 				if (radeon_ddc_probe(radeon_connector, false))
1681926deccbSFrançois Tigeot 					ret = connector_status_connected;
1682926deccbSFrançois Tigeot 			}
1683926deccbSFrançois Tigeot 		}
1684926deccbSFrançois Tigeot 	}
1685926deccbSFrançois Tigeot 
1686926deccbSFrançois Tigeot 	radeon_connector_update_scratch_regs(connector, ret);
1687c6f73aabSFrançois Tigeot out:
1688c6f73aabSFrançois Tigeot #ifdef PM_TODO
1689c6f73aabSFrançois Tigeot 	pm_runtime_mark_last_busy(connector->dev->dev);
1690c6f73aabSFrançois Tigeot 	pm_runtime_put_autosuspend(connector->dev->dev);
1691c6f73aabSFrançois Tigeot #endif
1692c6f73aabSFrançois Tigeot 
1693926deccbSFrançois Tigeot 	return ret;
1694926deccbSFrançois Tigeot }
1695926deccbSFrançois Tigeot 
1696926deccbSFrançois Tigeot static int radeon_dp_mode_valid(struct drm_connector *connector,
1697926deccbSFrançois Tigeot 				  struct drm_display_mode *mode)
1698926deccbSFrançois Tigeot {
1699c6f73aabSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1700c6f73aabSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1701926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1702926deccbSFrançois Tigeot 	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
1703926deccbSFrançois Tigeot 
1704926deccbSFrançois Tigeot 	/* XXX check mode bandwidth */
1705926deccbSFrançois Tigeot 
1706926deccbSFrançois Tigeot 	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
1707926deccbSFrançois Tigeot 	    (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
1708926deccbSFrançois Tigeot 		struct drm_encoder *encoder = radeon_best_single_encoder(connector);
1709926deccbSFrançois Tigeot 
1710926deccbSFrançois Tigeot 		if ((mode->hdisplay < 320) || (mode->vdisplay < 240))
1711926deccbSFrançois Tigeot 			return MODE_PANEL;
1712926deccbSFrançois Tigeot 
1713926deccbSFrançois Tigeot 		if (encoder) {
1714926deccbSFrançois Tigeot 			struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
1715926deccbSFrançois Tigeot 			struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
1716926deccbSFrançois Tigeot 
1717926deccbSFrançois Tigeot 			/* AVIVO hardware supports downscaling modes larger than the panel
1718926deccbSFrançois Tigeot 			 * to the panel size, but I'm not sure this is desirable.
1719926deccbSFrançois Tigeot 			 */
1720926deccbSFrançois Tigeot 			if ((mode->hdisplay > native_mode->hdisplay) ||
1721926deccbSFrançois Tigeot 			    (mode->vdisplay > native_mode->vdisplay))
1722926deccbSFrançois Tigeot 				return MODE_PANEL;
1723926deccbSFrançois Tigeot 
1724926deccbSFrançois Tigeot 			/* if scaling is disabled, block non-native modes */
1725926deccbSFrançois Tigeot 			if (radeon_encoder->rmx_type == RMX_OFF) {
1726926deccbSFrançois Tigeot 				if ((mode->hdisplay != native_mode->hdisplay) ||
1727926deccbSFrançois Tigeot 				    (mode->vdisplay != native_mode->vdisplay))
1728926deccbSFrançois Tigeot 					return MODE_PANEL;
1729926deccbSFrançois Tigeot 			}
1730926deccbSFrançois Tigeot 		}
1731926deccbSFrançois Tigeot 	} else {
1732926deccbSFrançois Tigeot 		if ((radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
1733c6f73aabSFrançois Tigeot 		    (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
1734926deccbSFrançois Tigeot 			return radeon_dp_mode_valid_helper(connector, mode);
1735c6f73aabSFrançois Tigeot 		} else {
1736c6f73aabSFrançois Tigeot 			if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
1737c6f73aabSFrançois Tigeot 				/* HDMI 1.3+ supports max clock of 340 Mhz */
1738c6f73aabSFrançois Tigeot 				if (mode->clock > 340000)
1739c6f73aabSFrançois Tigeot 					return MODE_CLOCK_HIGH;
1740c6f73aabSFrançois Tigeot 			} else {
1741c6f73aabSFrançois Tigeot 				if (mode->clock > 165000)
1742c6f73aabSFrançois Tigeot 					return MODE_CLOCK_HIGH;
1743926deccbSFrançois Tigeot 			}
1744926deccbSFrançois Tigeot 		}
1745c6f73aabSFrançois Tigeot 	}
1746c6f73aabSFrançois Tigeot 
1747c6f73aabSFrançois Tigeot 	return MODE_OK;
1748c6f73aabSFrançois Tigeot }
1749926deccbSFrançois Tigeot 
1750926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_dp_connector_helper_funcs = {
1751926deccbSFrançois Tigeot 	.get_modes = radeon_dp_get_modes,
1752926deccbSFrançois Tigeot 	.mode_valid = radeon_dp_mode_valid,
1753926deccbSFrançois Tigeot 	.best_encoder = radeon_dvi_encoder,
1754926deccbSFrançois Tigeot };
1755926deccbSFrançois Tigeot 
1756926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_dp_connector_funcs = {
1757926deccbSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
1758926deccbSFrançois Tigeot 	.detect = radeon_dp_detect,
1759926deccbSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
1760926deccbSFrançois Tigeot 	.set_property = radeon_connector_set_property,
1761ee479021SImre Vadász 	.destroy = radeon_dp_connector_destroy,
1762926deccbSFrançois Tigeot 	.force = radeon_dvi_force,
1763926deccbSFrançois Tigeot };
1764926deccbSFrançois Tigeot 
17654cd92098Szrj static const struct drm_connector_funcs radeon_edp_connector_funcs = {
17664cd92098Szrj 	.dpms = drm_helper_connector_dpms,
17674cd92098Szrj 	.detect = radeon_dp_detect,
17684cd92098Szrj 	.fill_modes = drm_helper_probe_single_connector_modes,
17694cd92098Szrj 	.set_property = radeon_lvds_set_property,
1770ee479021SImre Vadász 	.destroy = radeon_dp_connector_destroy,
17714cd92098Szrj 	.force = radeon_dvi_force,
17724cd92098Szrj };
17734cd92098Szrj 
17744cd92098Szrj static const struct drm_connector_funcs radeon_lvds_bridge_connector_funcs = {
17754cd92098Szrj 	.dpms = drm_helper_connector_dpms,
17764cd92098Szrj 	.detect = radeon_dp_detect,
17774cd92098Szrj 	.fill_modes = drm_helper_probe_single_connector_modes,
17784cd92098Szrj 	.set_property = radeon_lvds_set_property,
1779ee479021SImre Vadász 	.destroy = radeon_dp_connector_destroy,
17804cd92098Szrj 	.force = radeon_dvi_force,
17814cd92098Szrj };
17824cd92098Szrj 
1783926deccbSFrançois Tigeot void
1784926deccbSFrançois Tigeot radeon_add_atom_connector(struct drm_device *dev,
1785926deccbSFrançois Tigeot 			  uint32_t connector_id,
1786926deccbSFrançois Tigeot 			  uint32_t supported_device,
1787926deccbSFrançois Tigeot 			  int connector_type,
1788926deccbSFrançois Tigeot 			  struct radeon_i2c_bus_rec *i2c_bus,
1789926deccbSFrançois Tigeot 			  uint32_t igp_lane_info,
1790926deccbSFrançois Tigeot 			  uint16_t connector_object_id,
1791926deccbSFrançois Tigeot 			  struct radeon_hpd *hpd,
1792926deccbSFrançois Tigeot 			  struct radeon_router *router)
1793926deccbSFrançois Tigeot {
1794926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1795926deccbSFrançois Tigeot 	struct drm_connector *connector;
1796926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector;
1797926deccbSFrançois Tigeot 	struct radeon_connector_atom_dig *radeon_dig_connector;
1798926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1799926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
1800926deccbSFrançois Tigeot 	uint32_t subpixel_order = SubPixelNone;
1801926deccbSFrançois Tigeot 	bool shared_ddc = false;
1802926deccbSFrançois Tigeot 	bool is_dp_bridge = false;
18037191d616Szrj 	bool has_aux = false;
1804926deccbSFrançois Tigeot 
1805926deccbSFrançois Tigeot 	if (connector_type == DRM_MODE_CONNECTOR_Unknown)
1806926deccbSFrançois Tigeot 		return;
1807926deccbSFrançois Tigeot 
1808926deccbSFrançois Tigeot 	/* if the user selected tv=0 don't try and add the connector */
1809926deccbSFrançois Tigeot 	if (((connector_type == DRM_MODE_CONNECTOR_SVIDEO) ||
1810926deccbSFrançois Tigeot 	     (connector_type == DRM_MODE_CONNECTOR_Composite) ||
1811926deccbSFrançois Tigeot 	     (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) &&
1812926deccbSFrançois Tigeot 	    (radeon_tv == 0))
1813926deccbSFrançois Tigeot 		return;
1814926deccbSFrançois Tigeot 
1815926deccbSFrançois Tigeot 	/* see if we already added it */
1816926deccbSFrançois Tigeot 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1817926deccbSFrançois Tigeot 		radeon_connector = to_radeon_connector(connector);
1818926deccbSFrançois Tigeot 		if (radeon_connector->connector_id == connector_id) {
1819926deccbSFrançois Tigeot 			radeon_connector->devices |= supported_device;
1820926deccbSFrançois Tigeot 			return;
1821926deccbSFrançois Tigeot 		}
1822926deccbSFrançois Tigeot 		if (radeon_connector->ddc_bus && i2c_bus->valid) {
1823926deccbSFrançois Tigeot 			if (radeon_connector->ddc_bus->rec.i2c_id == i2c_bus->i2c_id) {
1824926deccbSFrançois Tigeot 				radeon_connector->shared_ddc = true;
1825926deccbSFrançois Tigeot 				shared_ddc = true;
1826926deccbSFrançois Tigeot 			}
1827926deccbSFrançois Tigeot 			if (radeon_connector->router_bus && router->ddc_valid &&
1828926deccbSFrançois Tigeot 			    (radeon_connector->router.router_id == router->router_id)) {
1829926deccbSFrançois Tigeot 				radeon_connector->shared_ddc = false;
1830926deccbSFrançois Tigeot 				shared_ddc = false;
1831926deccbSFrançois Tigeot 			}
1832926deccbSFrançois Tigeot 		}
1833926deccbSFrançois Tigeot 	}
1834926deccbSFrançois Tigeot 
1835926deccbSFrançois Tigeot 	/* check if it's a dp bridge */
1836926deccbSFrançois Tigeot 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
1837926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
1838926deccbSFrançois Tigeot 		if (radeon_encoder->devices & supported_device) {
1839926deccbSFrançois Tigeot 			switch (radeon_encoder->encoder_id) {
1840926deccbSFrançois Tigeot 			case ENCODER_OBJECT_ID_TRAVIS:
1841926deccbSFrançois Tigeot 			case ENCODER_OBJECT_ID_NUTMEG:
1842926deccbSFrançois Tigeot 				is_dp_bridge = true;
1843926deccbSFrançois Tigeot 				break;
1844926deccbSFrançois Tigeot 			default:
1845926deccbSFrançois Tigeot 				break;
1846926deccbSFrançois Tigeot 			}
1847926deccbSFrançois Tigeot 		}
1848926deccbSFrançois Tigeot 	}
1849926deccbSFrançois Tigeot 
1850c4ef309bSzrj 	radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL);
1851926deccbSFrançois Tigeot 	if (!radeon_connector)
1852926deccbSFrançois Tigeot 		return;
1853926deccbSFrançois Tigeot 
1854926deccbSFrançois Tigeot 	connector = &radeon_connector->base;
1855926deccbSFrançois Tigeot 
1856926deccbSFrançois Tigeot 	radeon_connector->connector_id = connector_id;
1857926deccbSFrançois Tigeot 	radeon_connector->devices = supported_device;
1858926deccbSFrançois Tigeot 	radeon_connector->shared_ddc = shared_ddc;
1859926deccbSFrançois Tigeot 	radeon_connector->connector_object_id = connector_object_id;
1860926deccbSFrançois Tigeot 	radeon_connector->hpd = *hpd;
1861926deccbSFrançois Tigeot 
1862926deccbSFrançois Tigeot 	radeon_connector->router = *router;
1863926deccbSFrançois Tigeot 	if (router->ddc_valid || router->cd_valid) {
1864926deccbSFrançois Tigeot 		radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info);
1865926deccbSFrançois Tigeot 		if (!radeon_connector->router_bus)
1866926deccbSFrançois Tigeot 			DRM_ERROR("Failed to assign router i2c bus! Check dmesg for i2c errors.\n");
1867926deccbSFrançois Tigeot 	}
1868926deccbSFrançois Tigeot 
1869926deccbSFrançois Tigeot 	if (is_dp_bridge) {
1870c4ef309bSzrj 		radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
1871926deccbSFrançois Tigeot 		if (!radeon_dig_connector)
1872926deccbSFrançois Tigeot 			goto failed;
1873926deccbSFrançois Tigeot 		radeon_dig_connector->igp_lane_info = igp_lane_info;
1874926deccbSFrançois Tigeot 		radeon_connector->con_priv = radeon_dig_connector;
1875926deccbSFrançois Tigeot 		if (i2c_bus->valid) {
1876ee479021SImre Vadász 			/* add DP i2c bus */
1877ee479021SImre Vadász 			if (connector_type == DRM_MODE_CONNECTOR_eDP)
1878ee479021SImre Vadász 				radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch");
1879ee479021SImre Vadász 			else
1880ee479021SImre Vadász 				radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch");
1881ee479021SImre Vadász 			if (radeon_dig_connector->dp_i2c_bus)
18827191d616Szrj 				has_aux = true;
18837191d616Szrj 			else
1884ee479021SImre Vadász 				DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
1885ee479021SImre Vadász 			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
1886ee479021SImre Vadász 			if (!radeon_connector->ddc_bus)
1887926deccbSFrançois Tigeot 				DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
1888926deccbSFrançois Tigeot 		}
1889926deccbSFrançois Tigeot 		switch (connector_type) {
1890926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_VGA:
1891926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVIA:
1892926deccbSFrançois Tigeot 		default:
18934cd92098Szrj 			drm_connector_init(dev, &radeon_connector->base,
18944cd92098Szrj 					   &radeon_dp_connector_funcs, connector_type);
18954cd92098Szrj 			drm_connector_helper_add(&radeon_connector->base,
18964cd92098Szrj 						 &radeon_dp_connector_helper_funcs);
1897926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
1898926deccbSFrançois Tigeot 			connector->doublescan_allowed = true;
1899926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
1900b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
1901926deccbSFrançois Tigeot 						      rdev->mode_info.load_detect_property,
1902926deccbSFrançois Tigeot 						      1);
1903c6f73aabSFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
1904c6f73aabSFrançois Tigeot 						   dev->mode_config.scaling_mode_property,
1905c6f73aabSFrançois Tigeot 						   DRM_MODE_SCALE_NONE);
1906926deccbSFrançois Tigeot 			break;
1907926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVII:
1908926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVID:
1909926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_HDMIA:
1910926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_HDMIB:
1911926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DisplayPort:
19124cd92098Szrj 			drm_connector_init(dev, &radeon_connector->base,
19134cd92098Szrj 					   &radeon_dp_connector_funcs, connector_type);
19144cd92098Szrj 			drm_connector_helper_add(&radeon_connector->base,
19154cd92098Szrj 						 &radeon_dp_connector_helper_funcs);
1916b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
1917926deccbSFrançois Tigeot 						      rdev->mode_info.underscan_property,
1918926deccbSFrançois Tigeot 						      UNDERSCAN_OFF);
1919b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
1920926deccbSFrançois Tigeot 						      rdev->mode_info.underscan_hborder_property,
1921926deccbSFrançois Tigeot 						      0);
1922b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
1923926deccbSFrançois Tigeot 						      rdev->mode_info.underscan_vborder_property,
1924926deccbSFrançois Tigeot 						      0);
1925c6f73aabSFrançois Tigeot 
1926c6f73aabSFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
1927c6f73aabSFrançois Tigeot 						      dev->mode_config.scaling_mode_property,
1928c6f73aabSFrançois Tigeot 						      DRM_MODE_SCALE_NONE);
1929c6f73aabSFrançois Tigeot 
1930c6f73aabSFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
1931c6f73aabSFrançois Tigeot 						   rdev->mode_info.dither_property,
1932c6f73aabSFrançois Tigeot 						   RADEON_FMT_DITHER_DISABLE);
1933c6f73aabSFrançois Tigeot 
1934ee479021SImre Vadász 			if (radeon_audio != 0)
19354cd92098Szrj 				drm_object_attach_property(&radeon_connector->base.base,
19364cd92098Szrj 							   rdev->mode_info.audio_property,
1937c6f73aabSFrançois Tigeot 							   RADEON_AUDIO_AUTO);
1938c6f73aabSFrançois Tigeot 
1939926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
1940926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
1941926deccbSFrançois Tigeot 			if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
1942926deccbSFrançois Tigeot 				connector->doublescan_allowed = true;
1943926deccbSFrançois Tigeot 			else
1944926deccbSFrançois Tigeot 				connector->doublescan_allowed = false;
1945926deccbSFrançois Tigeot 			if (connector_type == DRM_MODE_CONNECTOR_DVII) {
1946926deccbSFrançois Tigeot 				radeon_connector->dac_load_detect = true;
1947b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
1948926deccbSFrançois Tigeot 							      rdev->mode_info.load_detect_property,
1949926deccbSFrançois Tigeot 							      1);
1950926deccbSFrançois Tigeot 			}
1951926deccbSFrançois Tigeot 			break;
1952926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_LVDS:
1953926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_eDP:
19544cd92098Szrj 			drm_connector_init(dev, &radeon_connector->base,
19554cd92098Szrj 					   &radeon_lvds_bridge_connector_funcs, connector_type);
19564cd92098Szrj 			drm_connector_helper_add(&radeon_connector->base,
19574cd92098Szrj 						 &radeon_dp_connector_helper_funcs);
1958b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
1959926deccbSFrançois Tigeot 						      dev->mode_config.scaling_mode_property,
1960926deccbSFrançois Tigeot 						      DRM_MODE_SCALE_FULLSCREEN);
1961926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
1962926deccbSFrançois Tigeot 			connector->interlace_allowed = false;
1963926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
1964926deccbSFrançois Tigeot 			break;
1965926deccbSFrançois Tigeot 		}
1966926deccbSFrançois Tigeot 	} else {
1967926deccbSFrançois Tigeot 		switch (connector_type) {
1968926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_VGA:
1969926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
1970926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
1971926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
1972926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
1973926deccbSFrançois Tigeot 				if (!radeon_connector->ddc_bus)
1974926deccbSFrançois Tigeot 					DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
1975926deccbSFrançois Tigeot 			}
1976926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
1977b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
1978926deccbSFrançois Tigeot 						      rdev->mode_info.load_detect_property,
1979926deccbSFrançois Tigeot 						      1);
1980c6f73aabSFrançois Tigeot 			if (ASIC_IS_AVIVO(rdev))
1981c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
1982c6f73aabSFrançois Tigeot 							   dev->mode_config.scaling_mode_property,
1983c6f73aabSFrançois Tigeot 							   DRM_MODE_SCALE_NONE);
1984926deccbSFrançois Tigeot 			/* no HPD on analog connectors */
1985926deccbSFrançois Tigeot 			radeon_connector->hpd.hpd = RADEON_HPD_NONE;
1986ee479021SImre Vadász 			connector->polled = DRM_CONNECTOR_POLL_CONNECT;
1987926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
1988926deccbSFrançois Tigeot 			connector->doublescan_allowed = true;
1989926deccbSFrançois Tigeot 			break;
1990926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVIA:
1991926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
1992926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
1993926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
1994926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
1995926deccbSFrançois Tigeot 				if (!radeon_connector->ddc_bus)
1996926deccbSFrançois Tigeot 					DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
1997926deccbSFrançois Tigeot 			}
1998926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
1999b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2000926deccbSFrançois Tigeot 						      rdev->mode_info.load_detect_property,
2001926deccbSFrançois Tigeot 						      1);
2002c6f73aabSFrançois Tigeot 			if (ASIC_IS_AVIVO(rdev))
2003c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2004c6f73aabSFrançois Tigeot 							   dev->mode_config.scaling_mode_property,
2005c6f73aabSFrançois Tigeot 							   DRM_MODE_SCALE_NONE);
2006926deccbSFrançois Tigeot 			/* no HPD on analog connectors */
2007926deccbSFrançois Tigeot 			radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2008926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2009926deccbSFrançois Tigeot 			connector->doublescan_allowed = true;
2010926deccbSFrançois Tigeot 			break;
2011926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVII:
2012926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVID:
2013c4ef309bSzrj 			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
2014926deccbSFrançois Tigeot 			if (!radeon_dig_connector)
2015926deccbSFrançois Tigeot 				goto failed;
2016926deccbSFrançois Tigeot 			radeon_dig_connector->igp_lane_info = igp_lane_info;
2017926deccbSFrançois Tigeot 			radeon_connector->con_priv = radeon_dig_connector;
2018926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
2019926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
2020926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2021926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2022926deccbSFrançois Tigeot 				if (!radeon_connector->ddc_bus)
2023926deccbSFrançois Tigeot 					DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2024926deccbSFrançois Tigeot 			}
2025926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2026b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2027926deccbSFrançois Tigeot 						      rdev->mode_info.coherent_mode_property,
2028926deccbSFrançois Tigeot 						      1);
2029926deccbSFrançois Tigeot 			if (ASIC_IS_AVIVO(rdev)) {
2030b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2031926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_property,
2032926deccbSFrançois Tigeot 							      UNDERSCAN_OFF);
2033b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2034926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_hborder_property,
2035926deccbSFrançois Tigeot 							      0);
2036b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2037926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_vborder_property,
2038926deccbSFrançois Tigeot 							      0);
2039c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2040c6f73aabSFrançois Tigeot 							   rdev->mode_info.dither_property,
2041c6f73aabSFrançois Tigeot 							   RADEON_FMT_DITHER_DISABLE);
2042c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2043c6f73aabSFrançois Tigeot 							   dev->mode_config.scaling_mode_property,
2044c6f73aabSFrançois Tigeot 							   DRM_MODE_SCALE_NONE);
2045926deccbSFrançois Tigeot 			}
20464cd92098Szrj 			if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
20474cd92098Szrj 				drm_object_attach_property(&radeon_connector->base.base,
20484cd92098Szrj 							   rdev->mode_info.audio_property,
2049c6f73aabSFrançois Tigeot 							   RADEON_AUDIO_AUTO);
20504cd92098Szrj 			}
2051926deccbSFrançois Tigeot 			if (connector_type == DRM_MODE_CONNECTOR_DVII) {
2052926deccbSFrançois Tigeot 				radeon_connector->dac_load_detect = true;
2053b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2054926deccbSFrançois Tigeot 							      rdev->mode_info.load_detect_property,
2055926deccbSFrançois Tigeot 							      1);
2056926deccbSFrançois Tigeot 			}
2057926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2058926deccbSFrançois Tigeot 			if (connector_type == DRM_MODE_CONNECTOR_DVII)
2059926deccbSFrançois Tigeot 				connector->doublescan_allowed = true;
2060926deccbSFrançois Tigeot 			else
2061926deccbSFrançois Tigeot 				connector->doublescan_allowed = false;
2062926deccbSFrançois Tigeot 			break;
2063926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_HDMIA:
2064926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_HDMIB:
2065c4ef309bSzrj 			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
2066926deccbSFrançois Tigeot 			if (!radeon_dig_connector)
2067926deccbSFrançois Tigeot 				goto failed;
2068926deccbSFrançois Tigeot 			radeon_dig_connector->igp_lane_info = igp_lane_info;
2069926deccbSFrançois Tigeot 			radeon_connector->con_priv = radeon_dig_connector;
2070926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
2071926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
2072926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2073926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2074926deccbSFrançois Tigeot 				if (!radeon_connector->ddc_bus)
2075926deccbSFrançois Tigeot 					DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2076926deccbSFrançois Tigeot 			}
2077b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2078926deccbSFrançois Tigeot 						      rdev->mode_info.coherent_mode_property,
2079926deccbSFrançois Tigeot 						      1);
2080926deccbSFrançois Tigeot 			if (ASIC_IS_AVIVO(rdev)) {
2081b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2082926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_property,
2083926deccbSFrançois Tigeot 							      UNDERSCAN_OFF);
2084b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2085926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_hborder_property,
2086926deccbSFrançois Tigeot 							      0);
2087b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2088926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_vborder_property,
2089926deccbSFrançois Tigeot 							      0);
2090c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2091c6f73aabSFrançois Tigeot 							   rdev->mode_info.dither_property,
2092c6f73aabSFrançois Tigeot 							   RADEON_FMT_DITHER_DISABLE);
2093c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2094c6f73aabSFrançois Tigeot 							   dev->mode_config.scaling_mode_property,
2095c6f73aabSFrançois Tigeot 							   DRM_MODE_SCALE_NONE);
2096926deccbSFrançois Tigeot 			}
20974cd92098Szrj 			if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
20984cd92098Szrj 				drm_object_attach_property(&radeon_connector->base.base,
20994cd92098Szrj 							   rdev->mode_info.audio_property,
2100c6f73aabSFrançois Tigeot 							   RADEON_AUDIO_AUTO);
21014cd92098Szrj 			}
2102926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2103926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2104926deccbSFrançois Tigeot 			if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
2105926deccbSFrançois Tigeot 				connector->doublescan_allowed = true;
2106926deccbSFrançois Tigeot 			else
2107926deccbSFrançois Tigeot 				connector->doublescan_allowed = false;
2108926deccbSFrançois Tigeot 			break;
2109926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DisplayPort:
2110c4ef309bSzrj 			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
2111926deccbSFrançois Tigeot 			if (!radeon_dig_connector)
2112926deccbSFrançois Tigeot 				goto failed;
2113926deccbSFrançois Tigeot 			radeon_dig_connector->igp_lane_info = igp_lane_info;
2114926deccbSFrançois Tigeot 			radeon_connector->con_priv = radeon_dig_connector;
2115926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
2116926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
2117926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2118ee479021SImre Vadász 				/* add DP i2c bus */
2119ee479021SImre Vadász 				radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch");
2120ee479021SImre Vadász 				if (!radeon_dig_connector->dp_i2c_bus)
2121ee479021SImre Vadász 					DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
2122926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
21237191d616Szrj 				if (radeon_connector->ddc_bus)
21247191d616Szrj 					has_aux = true;
21257191d616Szrj 				else
2126926deccbSFrançois Tigeot 					DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2127926deccbSFrançois Tigeot 			}
2128926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2129b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2130926deccbSFrançois Tigeot 						      rdev->mode_info.coherent_mode_property,
2131926deccbSFrançois Tigeot 						      1);
2132926deccbSFrançois Tigeot 			if (ASIC_IS_AVIVO(rdev)) {
2133b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2134926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_property,
2135926deccbSFrançois Tigeot 							      UNDERSCAN_OFF);
2136b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2137926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_hborder_property,
2138926deccbSFrançois Tigeot 							      0);
2139b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2140926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_vborder_property,
2141926deccbSFrançois Tigeot 							      0);
2142c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2143c6f73aabSFrançois Tigeot 							   rdev->mode_info.dither_property,
2144c6f73aabSFrançois Tigeot 							   RADEON_FMT_DITHER_DISABLE);
2145c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2146c6f73aabSFrançois Tigeot 							   dev->mode_config.scaling_mode_property,
2147c6f73aabSFrançois Tigeot 							   DRM_MODE_SCALE_NONE);
2148926deccbSFrançois Tigeot 			}
21494cd92098Szrj 			if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
21504cd92098Szrj 				drm_object_attach_property(&radeon_connector->base.base,
21514cd92098Szrj 							   rdev->mode_info.audio_property,
2152c6f73aabSFrançois Tigeot 							   RADEON_AUDIO_AUTO);
21534cd92098Szrj 			}
2154926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2155926deccbSFrançois Tigeot 			/* in theory with a DP to VGA converter... */
2156926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2157926deccbSFrançois Tigeot 			break;
2158926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_eDP:
2159c4ef309bSzrj 			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
2160926deccbSFrançois Tigeot 			if (!radeon_dig_connector)
2161926deccbSFrançois Tigeot 				goto failed;
2162926deccbSFrançois Tigeot 			radeon_dig_connector->igp_lane_info = igp_lane_info;
2163926deccbSFrançois Tigeot 			radeon_connector->con_priv = radeon_dig_connector;
21644cd92098Szrj 			drm_connector_init(dev, &radeon_connector->base, &radeon_edp_connector_funcs, connector_type);
2165926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
2166926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2167ee479021SImre Vadász 				/* add DP i2c bus */
2168ee479021SImre Vadász 				radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch");
2169ee479021SImre Vadász 				if (radeon_dig_connector->dp_i2c_bus)
21707191d616Szrj 					has_aux = true;
21717191d616Szrj 				else
2172ee479021SImre Vadász 					DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
2173ee479021SImre Vadász 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2174ee479021SImre Vadász 				if (!radeon_connector->ddc_bus)
2175926deccbSFrançois Tigeot 					DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2176926deccbSFrançois Tigeot 			}
2177b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2178926deccbSFrançois Tigeot 						      dev->mode_config.scaling_mode_property,
2179926deccbSFrançois Tigeot 						      DRM_MODE_SCALE_FULLSCREEN);
2180926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2181926deccbSFrançois Tigeot 			connector->interlace_allowed = false;
2182926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2183926deccbSFrançois Tigeot 			break;
2184926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_SVIDEO:
2185926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_Composite:
2186926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_9PinDIN:
2187926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
2188926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
2189926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
2190b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2191926deccbSFrançois Tigeot 						      rdev->mode_info.load_detect_property,
2192926deccbSFrançois Tigeot 						      1);
2193b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2194926deccbSFrançois Tigeot 						      rdev->mode_info.tv_std_property,
2195926deccbSFrançois Tigeot 						      radeon_atombios_get_tv_info(rdev));
2196926deccbSFrançois Tigeot 			/* no HPD on analog connectors */
2197926deccbSFrançois Tigeot 			radeon_connector->hpd.hpd = RADEON_HPD_NONE;
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_LVDS:
2202c4ef309bSzrj 			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
2203926deccbSFrançois Tigeot 			if (!radeon_dig_connector)
2204926deccbSFrançois Tigeot 				goto failed;
2205926deccbSFrançois Tigeot 			radeon_dig_connector->igp_lane_info = igp_lane_info;
2206926deccbSFrançois Tigeot 			radeon_connector->con_priv = radeon_dig_connector;
2207926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
2208926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
2209926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2210926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2211926deccbSFrançois Tigeot 				if (!radeon_connector->ddc_bus)
2212926deccbSFrançois Tigeot 					DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2213926deccbSFrançois Tigeot 			}
2214b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2215926deccbSFrançois Tigeot 						      dev->mode_config.scaling_mode_property,
2216926deccbSFrançois Tigeot 						      DRM_MODE_SCALE_FULLSCREEN);
2217926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2218926deccbSFrançois Tigeot 			connector->interlace_allowed = false;
2219926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2220926deccbSFrançois Tigeot 			break;
2221926deccbSFrançois Tigeot 		}
2222926deccbSFrançois Tigeot 	}
2223926deccbSFrançois Tigeot 
2224926deccbSFrançois Tigeot 	if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
2225ee479021SImre Vadász 		if (i2c_bus->valid)
2226ee479021SImre Vadász 			connector->polled = DRM_CONNECTOR_POLL_CONNECT;
2227926deccbSFrançois Tigeot 	} else
2228926deccbSFrançois Tigeot 		connector->polled = DRM_CONNECTOR_POLL_HPD;
2229926deccbSFrançois Tigeot 
2230926deccbSFrançois Tigeot 	connector->display_info.subpixel_order = subpixel_order;
2231c6f73aabSFrançois Tigeot 	drm_connector_register(connector);
22327191d616Szrj 
22337191d616Szrj 	if (has_aux)
22347191d616Szrj 		radeon_dp_aux_init(radeon_connector);
22357191d616Szrj 
2236926deccbSFrançois Tigeot 	return;
2237926deccbSFrançois Tigeot 
2238926deccbSFrançois Tigeot failed:
2239926deccbSFrançois Tigeot 	drm_connector_cleanup(connector);
2240158486a6SFrançois Tigeot 	kfree(connector);
2241926deccbSFrançois Tigeot }
2242926deccbSFrançois Tigeot 
2243926deccbSFrançois Tigeot void
2244926deccbSFrançois Tigeot radeon_add_legacy_connector(struct drm_device *dev,
2245926deccbSFrançois Tigeot 			    uint32_t connector_id,
2246926deccbSFrançois Tigeot 			    uint32_t supported_device,
2247926deccbSFrançois Tigeot 			    int connector_type,
2248926deccbSFrançois Tigeot 			    struct radeon_i2c_bus_rec *i2c_bus,
2249926deccbSFrançois Tigeot 			    uint16_t connector_object_id,
2250926deccbSFrançois Tigeot 			    struct radeon_hpd *hpd)
2251926deccbSFrançois Tigeot {
2252926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
2253926deccbSFrançois Tigeot 	struct drm_connector *connector;
2254926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector;
2255926deccbSFrançois Tigeot 	uint32_t subpixel_order = SubPixelNone;
2256926deccbSFrançois Tigeot 
2257926deccbSFrançois Tigeot 	if (connector_type == DRM_MODE_CONNECTOR_Unknown)
2258926deccbSFrançois Tigeot 		return;
2259926deccbSFrançois Tigeot 
2260926deccbSFrançois Tigeot 	/* if the user selected tv=0 don't try and add the connector */
2261926deccbSFrançois Tigeot 	if (((connector_type == DRM_MODE_CONNECTOR_SVIDEO) ||
2262926deccbSFrançois Tigeot 	     (connector_type == DRM_MODE_CONNECTOR_Composite) ||
2263926deccbSFrançois Tigeot 	     (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) &&
2264926deccbSFrançois Tigeot 	    (radeon_tv == 0))
2265926deccbSFrançois Tigeot 		return;
2266926deccbSFrançois Tigeot 
2267926deccbSFrançois Tigeot 	/* see if we already added it */
2268926deccbSFrançois Tigeot 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
2269926deccbSFrançois Tigeot 		radeon_connector = to_radeon_connector(connector);
2270926deccbSFrançois Tigeot 		if (radeon_connector->connector_id == connector_id) {
2271926deccbSFrançois Tigeot 			radeon_connector->devices |= supported_device;
2272926deccbSFrançois Tigeot 			return;
2273926deccbSFrançois Tigeot 		}
2274926deccbSFrançois Tigeot 	}
2275926deccbSFrançois Tigeot 
2276c4ef309bSzrj 	radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL);
2277926deccbSFrançois Tigeot 	if (!radeon_connector)
2278926deccbSFrançois Tigeot 		return;
2279926deccbSFrançois Tigeot 
2280926deccbSFrançois Tigeot 	connector = &radeon_connector->base;
2281926deccbSFrançois Tigeot 
2282926deccbSFrançois Tigeot 	radeon_connector->connector_id = connector_id;
2283926deccbSFrançois Tigeot 	radeon_connector->devices = supported_device;
2284926deccbSFrançois Tigeot 	radeon_connector->connector_object_id = connector_object_id;
2285926deccbSFrançois Tigeot 	radeon_connector->hpd = *hpd;
2286926deccbSFrançois Tigeot 
2287926deccbSFrançois Tigeot 	switch (connector_type) {
2288926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_VGA:
2289926deccbSFrançois Tigeot 		drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
2290926deccbSFrançois Tigeot 		drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
2291926deccbSFrançois Tigeot 		if (i2c_bus->valid) {
2292926deccbSFrançois Tigeot 			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2293926deccbSFrançois Tigeot 			if (!radeon_connector->ddc_bus)
2294926deccbSFrançois Tigeot 				DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2295926deccbSFrançois Tigeot 		}
2296926deccbSFrançois Tigeot 		radeon_connector->dac_load_detect = true;
2297b5162e19SFrançois Tigeot 		drm_object_attach_property(&radeon_connector->base.base,
2298926deccbSFrançois Tigeot 					      rdev->mode_info.load_detect_property,
2299926deccbSFrançois Tigeot 					      1);
2300926deccbSFrançois Tigeot 		/* no HPD on analog connectors */
2301926deccbSFrançois Tigeot 		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2302ee479021SImre Vadász 		connector->polled = DRM_CONNECTOR_POLL_CONNECT;
2303926deccbSFrançois Tigeot 		connector->interlace_allowed = true;
2304926deccbSFrançois Tigeot 		connector->doublescan_allowed = true;
2305926deccbSFrançois Tigeot 		break;
2306926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_DVIA:
2307926deccbSFrançois Tigeot 		drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
2308926deccbSFrançois Tigeot 		drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
2309926deccbSFrançois Tigeot 		if (i2c_bus->valid) {
2310926deccbSFrançois Tigeot 			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2311926deccbSFrançois Tigeot 			if (!radeon_connector->ddc_bus)
2312926deccbSFrançois Tigeot 				DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2313926deccbSFrançois Tigeot 		}
2314926deccbSFrançois Tigeot 		radeon_connector->dac_load_detect = true;
2315b5162e19SFrançois Tigeot 		drm_object_attach_property(&radeon_connector->base.base,
2316926deccbSFrançois Tigeot 					      rdev->mode_info.load_detect_property,
2317926deccbSFrançois Tigeot 					      1);
2318926deccbSFrançois Tigeot 		/* no HPD on analog connectors */
2319926deccbSFrançois Tigeot 		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
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_DVII:
2324926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_DVID:
2325926deccbSFrançois Tigeot 		drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
2326926deccbSFrançois Tigeot 		drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
2327926deccbSFrançois Tigeot 		if (i2c_bus->valid) {
2328926deccbSFrançois Tigeot 			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2329926deccbSFrançois Tigeot 			if (!radeon_connector->ddc_bus)
2330926deccbSFrançois Tigeot 				DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2331926deccbSFrançois Tigeot 		}
2332926deccbSFrançois Tigeot 		if (connector_type == DRM_MODE_CONNECTOR_DVII) {
2333926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
2334b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2335926deccbSFrançois Tigeot 						      rdev->mode_info.load_detect_property,
2336926deccbSFrançois Tigeot 						      1);
2337926deccbSFrançois Tigeot 		}
2338926deccbSFrançois Tigeot 		subpixel_order = SubPixelHorizontalRGB;
2339926deccbSFrançois Tigeot 		connector->interlace_allowed = true;
2340926deccbSFrançois Tigeot 		if (connector_type == DRM_MODE_CONNECTOR_DVII)
2341926deccbSFrançois Tigeot 			connector->doublescan_allowed = true;
2342926deccbSFrançois Tigeot 		else
2343926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2344926deccbSFrançois Tigeot 		break;
2345926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_SVIDEO:
2346926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_Composite:
2347926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_9PinDIN:
2348926deccbSFrançois Tigeot 		drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
2349926deccbSFrançois Tigeot 		drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
2350926deccbSFrançois Tigeot 		radeon_connector->dac_load_detect = true;
2351926deccbSFrançois Tigeot 		/* RS400,RC410,RS480 chipset seems to report a lot
2352926deccbSFrançois Tigeot 		 * of false positive on load detect, we haven't yet
2353926deccbSFrançois Tigeot 		 * found a way to make load detect reliable on those
2354926deccbSFrançois Tigeot 		 * chipset, thus just disable it for TV.
2355926deccbSFrançois Tigeot 		 */
2356926deccbSFrançois Tigeot 		if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480)
2357926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = false;
2358b5162e19SFrançois Tigeot 		drm_object_attach_property(&radeon_connector->base.base,
2359926deccbSFrançois Tigeot 					      rdev->mode_info.load_detect_property,
2360926deccbSFrançois Tigeot 					      radeon_connector->dac_load_detect);
2361b5162e19SFrançois Tigeot 		drm_object_attach_property(&radeon_connector->base.base,
2362926deccbSFrançois Tigeot 					      rdev->mode_info.tv_std_property,
2363926deccbSFrançois Tigeot 					      radeon_combios_get_tv_info(rdev));
2364926deccbSFrançois Tigeot 		/* no HPD on analog connectors */
2365926deccbSFrançois Tigeot 		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2366926deccbSFrançois Tigeot 		connector->interlace_allowed = false;
2367926deccbSFrançois Tigeot 		connector->doublescan_allowed = false;
2368926deccbSFrançois Tigeot 		break;
2369926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_LVDS:
2370926deccbSFrançois Tigeot 		drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
2371926deccbSFrançois Tigeot 		drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
2372926deccbSFrançois Tigeot 		if (i2c_bus->valid) {
2373926deccbSFrançois Tigeot 			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2374926deccbSFrançois Tigeot 			if (!radeon_connector->ddc_bus)
2375926deccbSFrançois Tigeot 				DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2376926deccbSFrançois Tigeot 		}
2377b5162e19SFrançois Tigeot 		drm_object_attach_property(&radeon_connector->base.base,
2378926deccbSFrançois Tigeot 					      dev->mode_config.scaling_mode_property,
2379926deccbSFrançois Tigeot 					      DRM_MODE_SCALE_FULLSCREEN);
2380926deccbSFrançois Tigeot 		subpixel_order = SubPixelHorizontalRGB;
2381926deccbSFrançois Tigeot 		connector->interlace_allowed = false;
2382926deccbSFrançois Tigeot 		connector->doublescan_allowed = false;
2383926deccbSFrançois Tigeot 		break;
2384926deccbSFrançois Tigeot 	}
2385926deccbSFrançois Tigeot 
2386926deccbSFrançois Tigeot 	if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
2387ee479021SImre Vadász 		if (i2c_bus->valid)
2388ee479021SImre Vadász 			connector->polled = DRM_CONNECTOR_POLL_CONNECT;
2389926deccbSFrançois Tigeot 	} else
2390926deccbSFrançois Tigeot 		connector->polled = DRM_CONNECTOR_POLL_HPD;
2391926deccbSFrançois Tigeot 	connector->display_info.subpixel_order = subpixel_order;
2392c6f73aabSFrançois Tigeot 	drm_connector_register(connector);
2393926deccbSFrançois Tigeot }
2394