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>
30c59a5c48SFrançois Tigeot #include <drm/drm_dp_mst_helper.h>
3183b4b9b9SFrançois Tigeot #include <drm/radeon_drm.h>
32926deccbSFrançois Tigeot #include "radeon.h"
33c59a5c48SFrançois Tigeot #include "radeon_audio.h"
34926deccbSFrançois Tigeot #include "atom.h"
35926deccbSFrançois Tigeot 
36c6f73aabSFrançois Tigeot #include <linux/pm_runtime.h>
37d78d3a22SFrançois Tigeot #include <linux/vga_switcheroo.h>
38c6f73aabSFrançois Tigeot 
39c59a5c48SFrançois Tigeot static int radeon_dp_handle_hpd(struct drm_connector *connector)
40c59a5c48SFrançois Tigeot {
41c59a5c48SFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
42c59a5c48SFrançois Tigeot 	int ret;
43c59a5c48SFrançois Tigeot 
44c59a5c48SFrançois Tigeot 	ret = radeon_dp_mst_check_status(radeon_connector);
45c59a5c48SFrançois Tigeot 	if (ret == -EINVAL)
46c59a5c48SFrançois Tigeot 		return 1;
47c59a5c48SFrançois Tigeot 	return 0;
48c59a5c48SFrançois Tigeot }
49926deccbSFrançois Tigeot void radeon_connector_hotplug(struct drm_connector *connector)
50926deccbSFrançois Tigeot {
51926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
52926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
53926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
54926deccbSFrançois Tigeot 
55c59a5c48SFrançois Tigeot 	if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
56c59a5c48SFrançois Tigeot 		struct radeon_connector_atom_dig *dig_connector =
57c59a5c48SFrançois Tigeot 			radeon_connector->con_priv;
58c59a5c48SFrançois Tigeot 
59c59a5c48SFrançois Tigeot 		if (radeon_connector->is_mst_connector)
60c59a5c48SFrançois Tigeot 			return;
61c59a5c48SFrançois Tigeot 		if (dig_connector->is_mst) {
62c59a5c48SFrançois Tigeot 			radeon_dp_handle_hpd(connector);
63c59a5c48SFrançois Tigeot 			return;
64c59a5c48SFrançois Tigeot 		}
65c59a5c48SFrançois Tigeot 	}
66926deccbSFrançois Tigeot 	/* bail if the connector does not have hpd pin, e.g.,
67926deccbSFrançois Tigeot 	 * VGA, TV, etc.
68926deccbSFrançois Tigeot 	 */
69926deccbSFrançois Tigeot 	if (radeon_connector->hpd.hpd == RADEON_HPD_NONE)
70926deccbSFrançois Tigeot 		return;
71926deccbSFrançois Tigeot 
72926deccbSFrançois Tigeot 	radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
73926deccbSFrançois Tigeot 
74926deccbSFrançois Tigeot 	/* if the connector is already off, don't turn it back on */
75c6f73aabSFrançois Tigeot 	/* FIXME: This access isn't protected by any locks. */
76926deccbSFrançois Tigeot 	if (connector->dpms != DRM_MODE_DPMS_ON)
77926deccbSFrançois Tigeot 		return;
78926deccbSFrançois Tigeot 
79926deccbSFrançois Tigeot 	/* just deal with DP (not eDP) here. */
80926deccbSFrançois Tigeot 	if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
81926deccbSFrançois Tigeot 		struct radeon_connector_atom_dig *dig_connector =
82926deccbSFrançois Tigeot 			radeon_connector->con_priv;
83926deccbSFrançois Tigeot 
84926deccbSFrançois Tigeot 		/* if existing sink type was not DP no need to retrain */
85926deccbSFrançois Tigeot 		if (dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_DISPLAYPORT)
86926deccbSFrançois Tigeot 			return;
87926deccbSFrançois Tigeot 
88926deccbSFrançois Tigeot 		/* first get sink type as it may be reset after (un)plug */
89926deccbSFrançois Tigeot 		dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
90926deccbSFrançois Tigeot 		/* don't do anything if sink is not display port, i.e.,
91926deccbSFrançois Tigeot 		 * passive dp->(dvi|hdmi) adaptor
92926deccbSFrançois Tigeot 		 */
93c59a5c48SFrançois Tigeot 		if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT &&
94c59a5c48SFrançois Tigeot 		    radeon_hpd_sense(rdev, radeon_connector->hpd.hpd) &&
95c59a5c48SFrançois Tigeot 		    radeon_dp_needs_link_train(radeon_connector)) {
96c59a5c48SFrançois Tigeot 			/* Don't start link training before we have the DPCD */
97c59a5c48SFrançois Tigeot 			if (!radeon_dp_getdpcd(radeon_connector))
98c59a5c48SFrançois Tigeot 				return;
99c59a5c48SFrançois Tigeot 
100c59a5c48SFrançois Tigeot 			/* Turn the connector off and back on immediately, which
101c59a5c48SFrançois Tigeot 			 * will trigger link training
102926deccbSFrançois Tigeot 			 */
103c59a5c48SFrançois Tigeot 			drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
104926deccbSFrançois Tigeot 			drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
105926deccbSFrançois Tigeot 		}
106926deccbSFrançois Tigeot 	}
107926deccbSFrançois Tigeot }
108926deccbSFrançois Tigeot 
109926deccbSFrançois Tigeot static void radeon_property_change_mode(struct drm_encoder *encoder)
110926deccbSFrançois Tigeot {
111926deccbSFrançois Tigeot 	struct drm_crtc *crtc = encoder->crtc;
112926deccbSFrançois Tigeot 
113926deccbSFrançois Tigeot 	if (crtc && crtc->enabled) {
114926deccbSFrançois Tigeot 		drm_crtc_helper_set_mode(crtc, &crtc->mode,
115ba55f2f5SFrançois Tigeot 					 crtc->x, crtc->y, crtc->primary->fb);
116926deccbSFrançois Tigeot 	}
117926deccbSFrançois Tigeot }
118926deccbSFrançois Tigeot 
119926deccbSFrançois Tigeot int radeon_get_monitor_bpc(struct drm_connector *connector)
120926deccbSFrançois Tigeot {
121926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
122926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
123926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
124926deccbSFrançois Tigeot 	struct radeon_connector_atom_dig *dig_connector;
125926deccbSFrançois Tigeot 	int bpc = 8;
126c6f73aabSFrançois Tigeot 	int mode_clock, max_tmds_clock;
127926deccbSFrançois Tigeot 
128926deccbSFrançois Tigeot 	switch (connector->connector_type) {
129926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_DVII:
130926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_HDMIB:
131926deccbSFrançois Tigeot 		if (radeon_connector->use_digital) {
132c6f73aabSFrançois Tigeot 			if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
133926deccbSFrançois Tigeot 				if (connector->display_info.bpc)
134926deccbSFrançois Tigeot 					bpc = connector->display_info.bpc;
135926deccbSFrançois Tigeot 			}
136926deccbSFrançois Tigeot 		}
137926deccbSFrançois Tigeot 		break;
138926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_DVID:
139926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_HDMIA:
140c6f73aabSFrançois Tigeot 		if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
141926deccbSFrançois Tigeot 			if (connector->display_info.bpc)
142926deccbSFrançois Tigeot 				bpc = connector->display_info.bpc;
143926deccbSFrançois Tigeot 		}
144926deccbSFrançois Tigeot 		break;
145926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_DisplayPort:
146926deccbSFrançois Tigeot 		dig_connector = radeon_connector->con_priv;
147926deccbSFrançois Tigeot 		if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
148926deccbSFrançois Tigeot 		    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) ||
149c6f73aabSFrançois Tigeot 		    drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
150926deccbSFrançois Tigeot 			if (connector->display_info.bpc)
151926deccbSFrançois Tigeot 				bpc = connector->display_info.bpc;
152926deccbSFrançois Tigeot 		}
153926deccbSFrançois Tigeot 		break;
154926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_eDP:
155926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_LVDS:
156926deccbSFrançois Tigeot 		if (connector->display_info.bpc)
157926deccbSFrançois Tigeot 			bpc = connector->display_info.bpc;
158926deccbSFrançois Tigeot 		else if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) {
159c0e85e96SFrançois Tigeot 			const struct drm_connector_helper_funcs *connector_funcs =
160926deccbSFrançois Tigeot 				connector->helper_private;
161926deccbSFrançois Tigeot 			struct drm_encoder *encoder = connector_funcs->best_encoder(connector);
162926deccbSFrançois Tigeot 			struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
163926deccbSFrançois Tigeot 			struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
164926deccbSFrançois Tigeot 
165926deccbSFrançois Tigeot 			if (dig->lcd_misc & ATOM_PANEL_MISC_V13_6BIT_PER_COLOR)
166926deccbSFrançois Tigeot 				bpc = 6;
167926deccbSFrançois Tigeot 			else if (dig->lcd_misc & ATOM_PANEL_MISC_V13_8BIT_PER_COLOR)
168926deccbSFrançois Tigeot 				bpc = 8;
169926deccbSFrançois Tigeot 		}
170926deccbSFrançois Tigeot 		break;
171926deccbSFrançois Tigeot 	}
172c6f73aabSFrançois Tigeot 
173c6f73aabSFrançois Tigeot 	if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
174c6f73aabSFrançois Tigeot 		/* hdmi deep color only implemented on DCE4+ */
175c6f73aabSFrançois Tigeot 		if ((bpc > 8) && !ASIC_IS_DCE4(rdev)) {
176c6f73aabSFrançois Tigeot 			DRM_DEBUG("%s: HDMI deep color %d bpc unsupported. Using 8 bpc.\n",
177c6f73aabSFrançois Tigeot 					  connector->name, bpc);
178c6f73aabSFrançois Tigeot 			bpc = 8;
179c6f73aabSFrançois Tigeot 		}
180c6f73aabSFrançois Tigeot 
181c6f73aabSFrançois Tigeot 		/*
182c6f73aabSFrançois Tigeot 		 * Pre DCE-8 hw can't handle > 12 bpc, and more than 12 bpc doesn't make
183c6f73aabSFrançois Tigeot 		 * much sense without support for > 12 bpc framebuffers. RGB 4:4:4 at
184c6f73aabSFrançois Tigeot 		 * 12 bpc is always supported on hdmi deep color sinks, as this is
185c6f73aabSFrançois Tigeot 		 * required by the HDMI-1.3 spec. Clamp to a safe 12 bpc maximum.
186c6f73aabSFrançois Tigeot 		 */
187c6f73aabSFrançois Tigeot 		if (bpc > 12) {
188c6f73aabSFrançois Tigeot 			DRM_DEBUG("%s: HDMI deep color %d bpc unsupported. Using 12 bpc.\n",
189c6f73aabSFrançois Tigeot 					  connector->name, bpc);
190c6f73aabSFrançois Tigeot 			bpc = 12;
191c6f73aabSFrançois Tigeot 		}
192c6f73aabSFrançois Tigeot 
193c6f73aabSFrançois Tigeot 		/* Any defined maximum tmds clock limit we must not exceed? */
194*1dedbd3bSFrançois Tigeot 		if (connector->display_info.max_tmds_clock > 0) {
195c6f73aabSFrançois Tigeot 			/* mode_clock is clock in kHz for mode to be modeset on this connector */
196c6f73aabSFrançois Tigeot 			mode_clock = radeon_connector->pixelclock_for_modeset;
197c6f73aabSFrançois Tigeot 
198c6f73aabSFrançois Tigeot 			/* Maximum allowable input clock in kHz */
199*1dedbd3bSFrançois Tigeot 			max_tmds_clock = connector->display_info.max_tmds_clock;
200c6f73aabSFrançois Tigeot 
201c6f73aabSFrançois Tigeot 			DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n",
202c6f73aabSFrançois Tigeot 					  connector->name, mode_clock, max_tmds_clock);
203c6f73aabSFrançois Tigeot 
204c6f73aabSFrançois Tigeot 			/* Check if bpc is within clock limit. Try to degrade gracefully otherwise */
205c6f73aabSFrançois Tigeot 			if ((bpc == 12) && (mode_clock * 3/2 > max_tmds_clock)) {
206c6f73aabSFrançois Tigeot 				if ((connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) &&
207c6f73aabSFrançois Tigeot 					(mode_clock * 5/4 <= max_tmds_clock))
208c6f73aabSFrançois Tigeot 					bpc = 10;
209c6f73aabSFrançois Tigeot 				else
210c6f73aabSFrançois Tigeot 					bpc = 8;
211c6f73aabSFrançois Tigeot 
212c6f73aabSFrançois Tigeot 				DRM_DEBUG("%s: HDMI deep color 12 bpc exceeds max tmds clock. Using %d bpc.\n",
213c6f73aabSFrançois Tigeot 						  connector->name, bpc);
214c6f73aabSFrançois Tigeot 			}
215c6f73aabSFrançois Tigeot 
216c6f73aabSFrançois Tigeot 			if ((bpc == 10) && (mode_clock * 5/4 > max_tmds_clock)) {
217c6f73aabSFrançois Tigeot 				bpc = 8;
218c6f73aabSFrançois Tigeot 				DRM_DEBUG("%s: HDMI deep color 10 bpc exceeds max tmds clock. Using %d bpc.\n",
219c6f73aabSFrançois Tigeot 						  connector->name, bpc);
220c6f73aabSFrançois Tigeot 			}
221c6f73aabSFrançois Tigeot 		}
222c6f73aabSFrançois Tigeot 		else if (bpc > 8) {
223c6f73aabSFrançois Tigeot 			/* max_tmds_clock missing, but hdmi spec mandates it for deep color. */
224c6f73aabSFrançois Tigeot 			DRM_DEBUG("%s: Required max tmds clock for HDMI deep color missing. Using 8 bpc.\n",
225c6f73aabSFrançois Tigeot 					  connector->name);
226c6f73aabSFrançois Tigeot 			bpc = 8;
227c6f73aabSFrançois Tigeot 		}
228c6f73aabSFrançois Tigeot 	}
229c6f73aabSFrançois Tigeot 
230c6f73aabSFrançois Tigeot 	if ((radeon_deep_color == 0) && (bpc > 8)) {
231c6f73aabSFrançois Tigeot 		DRM_DEBUG("%s: Deep color disabled. Set radeon module param deep_color=1 to enable.\n",
232c6f73aabSFrançois Tigeot 				  connector->name);
233c6f73aabSFrançois Tigeot 		bpc = 8;
234c6f73aabSFrançois Tigeot 	}
235c6f73aabSFrançois Tigeot 
236c6f73aabSFrançois Tigeot 	DRM_DEBUG("%s: Display bpc=%d, returned bpc=%d\n",
237c6f73aabSFrançois Tigeot 			  connector->name, connector->display_info.bpc, bpc);
238c6f73aabSFrançois Tigeot 
239926deccbSFrançois Tigeot 	return bpc;
240926deccbSFrançois Tigeot }
241926deccbSFrançois Tigeot 
242926deccbSFrançois Tigeot static void
243926deccbSFrançois Tigeot radeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_connector_status status)
244926deccbSFrançois Tigeot {
245926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
246926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
247926deccbSFrançois Tigeot 	struct drm_encoder *best_encoder = NULL;
248926deccbSFrançois Tigeot 	struct drm_encoder *encoder = NULL;
249c0e85e96SFrançois Tigeot 	const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
250926deccbSFrançois Tigeot 	bool connected;
251926deccbSFrançois Tigeot 	int i;
252926deccbSFrançois Tigeot 
253926deccbSFrançois Tigeot 	best_encoder = connector_funcs->best_encoder(connector);
254926deccbSFrançois Tigeot 
255926deccbSFrançois Tigeot 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
256926deccbSFrançois Tigeot 		if (connector->encoder_ids[i] == 0)
257926deccbSFrançois Tigeot 			break;
258926deccbSFrançois Tigeot 
259c6f73aabSFrançois Tigeot 		encoder = drm_encoder_find(connector->dev,
260c6f73aabSFrançois Tigeot 					   connector->encoder_ids[i]);
261c6f73aabSFrançois Tigeot 		if (!encoder)
262926deccbSFrançois Tigeot 			continue;
263926deccbSFrançois Tigeot 
264926deccbSFrançois Tigeot 		if ((encoder == best_encoder) && (status == connector_status_connected))
265926deccbSFrançois Tigeot 			connected = true;
266926deccbSFrançois Tigeot 		else
267926deccbSFrançois Tigeot 			connected = false;
268926deccbSFrançois Tigeot 
269926deccbSFrançois Tigeot 		if (rdev->is_atom_bios)
270926deccbSFrançois Tigeot 			radeon_atombios_connected_scratch_regs(connector, encoder, connected);
271926deccbSFrançois Tigeot 		else
272926deccbSFrançois Tigeot 			radeon_combios_connected_scratch_regs(connector, encoder, connected);
273926deccbSFrançois Tigeot 
274926deccbSFrançois Tigeot 	}
275926deccbSFrançois Tigeot }
276926deccbSFrançois Tigeot 
277926deccbSFrançois Tigeot static struct drm_encoder *radeon_find_encoder(struct drm_connector *connector, int encoder_type)
278926deccbSFrançois Tigeot {
279926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
280926deccbSFrançois Tigeot 	int i;
281926deccbSFrançois Tigeot 
282926deccbSFrançois Tigeot 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
283926deccbSFrançois Tigeot 		if (connector->encoder_ids[i] == 0)
284926deccbSFrançois Tigeot 			break;
285926deccbSFrançois Tigeot 
286c6f73aabSFrançois Tigeot 		encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
287c6f73aabSFrançois Tigeot 		if (!encoder)
288926deccbSFrançois Tigeot 			continue;
289926deccbSFrançois Tigeot 
290926deccbSFrançois Tigeot 		if (encoder->encoder_type == encoder_type)
291926deccbSFrançois Tigeot 			return encoder;
292926deccbSFrançois Tigeot 	}
293926deccbSFrançois Tigeot 	return NULL;
294926deccbSFrançois Tigeot }
295926deccbSFrançois Tigeot 
296c6f73aabSFrançois Tigeot struct edid *radeon_connector_edid(struct drm_connector *connector)
297c6f73aabSFrançois Tigeot {
298c6f73aabSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
299c6f73aabSFrançois Tigeot 	struct drm_property_blob *edid_blob = connector->edid_blob_ptr;
300c6f73aabSFrançois Tigeot 
301c6f73aabSFrançois Tigeot 	if (radeon_connector->edid) {
302c6f73aabSFrançois Tigeot 		return radeon_connector->edid;
303c6f73aabSFrançois Tigeot 	} else if (edid_blob) {
304c6f73aabSFrançois Tigeot 		struct edid *edid = kmemdup(edid_blob->data, edid_blob->length, GFP_KERNEL);
305c6f73aabSFrançois Tigeot 		if (edid)
306c6f73aabSFrançois Tigeot 			radeon_connector->edid = edid;
307c6f73aabSFrançois Tigeot 	}
308c6f73aabSFrançois Tigeot 	return radeon_connector->edid;
309c6f73aabSFrançois Tigeot }
310c6f73aabSFrançois Tigeot 
3115ef6d7b4SFrançois Tigeot static void radeon_connector_get_edid(struct drm_connector *connector)
3127191d616Szrj {
3135ef6d7b4SFrançois Tigeot 	struct drm_device *dev = connector->dev;
3147191d616Szrj 	struct radeon_device *rdev = dev->dev_private;
3155ef6d7b4SFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
3167191d616Szrj 
3177191d616Szrj 	if (radeon_connector->edid)
3187191d616Szrj 		return;
3197191d616Szrj 
3207191d616Szrj 	/* on hw with routers, select right port */
3217191d616Szrj 	if (radeon_connector->router.ddc_valid)
3227191d616Szrj 		radeon_router_select_ddc_port(radeon_connector);
3237191d616Szrj 
3245ef6d7b4SFrançois Tigeot 	if ((radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
3255ef6d7b4SFrançois Tigeot 	     ENCODER_OBJECT_ID_NONE) &&
3265ef6d7b4SFrançois Tigeot 	    radeon_connector->ddc_bus->has_aux) {
3275ef6d7b4SFrançois Tigeot 		radeon_connector->edid = drm_get_edid(connector,
3285ef6d7b4SFrançois Tigeot 						      &radeon_connector->ddc_bus->aux.ddc);
3295ef6d7b4SFrançois Tigeot 	} else if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
3305ef6d7b4SFrançois Tigeot 		   (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
3317191d616Szrj 		struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
3327191d616Szrj 
3337191d616Szrj 		if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT ||
3345ef6d7b4SFrançois Tigeot 		     dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) &&
3355ef6d7b4SFrançois Tigeot 		    radeon_connector->ddc_bus->has_aux)
3365ef6d7b4SFrançois Tigeot 			radeon_connector->edid = drm_get_edid(&radeon_connector->base,
3375ef6d7b4SFrançois Tigeot 							      &radeon_connector->ddc_bus->aux.ddc);
3385ef6d7b4SFrançois Tigeot 		else if (radeon_connector->ddc_bus)
3395ef6d7b4SFrançois Tigeot 			radeon_connector->edid = drm_get_edid(&radeon_connector->base,
3405ef6d7b4SFrançois Tigeot 							      &radeon_connector->ddc_bus->adapter);
341d78d3a22SFrançois Tigeot 	} else if (vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC &&
342d78d3a22SFrançois Tigeot 		   connector->connector_type == DRM_MODE_CONNECTOR_LVDS &&
343d78d3a22SFrançois Tigeot 		   radeon_connector->ddc_bus) {
344d78d3a22SFrançois Tigeot 		radeon_connector->edid = drm_get_edid_switcheroo(&radeon_connector->base,
345d78d3a22SFrançois Tigeot 								 &radeon_connector->ddc_bus->adapter);
3467191d616Szrj 	} else if (radeon_connector->ddc_bus) {
3475ef6d7b4SFrançois Tigeot 		radeon_connector->edid = drm_get_edid(&radeon_connector->base,
3485ef6d7b4SFrançois Tigeot 						      &radeon_connector->ddc_bus->adapter);
3497191d616Szrj 	}
3507191d616Szrj 
3517191d616Szrj 	if (!radeon_connector->edid) {
3521cfef1a5SFrançois Tigeot 		/* don't fetch the edid from the vbios if ddc fails and runpm is
3531cfef1a5SFrançois Tigeot 		 * enabled so we report disconnected.
3541cfef1a5SFrançois Tigeot 		 */
3551cfef1a5SFrançois Tigeot 		if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0))
3561cfef1a5SFrançois Tigeot 			return;
3571cfef1a5SFrançois Tigeot 
3587191d616Szrj 		if (rdev->is_atom_bios) {
3597191d616Szrj 			/* some laptops provide a hardcoded edid in rom for LCDs */
3605ef6d7b4SFrançois Tigeot 			if (((connector->connector_type == DRM_MODE_CONNECTOR_LVDS) ||
3615ef6d7b4SFrançois Tigeot 			     (connector->connector_type == DRM_MODE_CONNECTOR_eDP)))
3627191d616Szrj 				radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev);
3637191d616Szrj 		} else {
3647191d616Szrj 			/* some servers provide a hardcoded edid in rom for KVMs */
3657191d616Szrj 			radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev);
3667191d616Szrj 		}
3677191d616Szrj 	}
3687191d616Szrj }
3697191d616Szrj 
3705ef6d7b4SFrançois Tigeot static void radeon_connector_free_edid(struct drm_connector *connector)
3717191d616Szrj {
3725ef6d7b4SFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
3735ef6d7b4SFrançois Tigeot 
3747191d616Szrj 	if (radeon_connector->edid) {
3757191d616Szrj 		kfree(radeon_connector->edid);
3767191d616Szrj 		radeon_connector->edid = NULL;
3777191d616Szrj 	}
3787191d616Szrj }
3797191d616Szrj 
3805ef6d7b4SFrançois Tigeot static int radeon_ddc_get_modes(struct drm_connector *connector)
3817191d616Szrj {
3825ef6d7b4SFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
3837191d616Szrj 	int ret;
3847191d616Szrj 
3857191d616Szrj 	if (radeon_connector->edid) {
3865ef6d7b4SFrançois Tigeot 		drm_mode_connector_update_edid_property(connector, radeon_connector->edid);
3875ef6d7b4SFrançois Tigeot 		ret = drm_add_edid_modes(connector, radeon_connector->edid);
3885ef6d7b4SFrançois Tigeot 		drm_edid_to_eld(connector, radeon_connector->edid);
3897191d616Szrj 		return ret;
3907191d616Szrj 	}
3915ef6d7b4SFrançois Tigeot 	drm_mode_connector_update_edid_property(connector, NULL);
3927191d616Szrj 	return 0;
3937191d616Szrj }
3947191d616Szrj 
395926deccbSFrançois Tigeot static struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector)
396926deccbSFrançois Tigeot {
397926deccbSFrançois Tigeot 	int enc_id = connector->encoder_ids[0];
398926deccbSFrançois Tigeot 	/* pick the encoder ids */
399c6f73aabSFrançois Tigeot 	if (enc_id)
400c6f73aabSFrançois Tigeot 		return drm_encoder_find(connector->dev, enc_id);
401926deccbSFrançois Tigeot 	return NULL;
402926deccbSFrançois Tigeot }
403c6f73aabSFrançois Tigeot 
404c6f73aabSFrançois Tigeot static void radeon_get_native_mode(struct drm_connector *connector)
405c6f73aabSFrançois Tigeot {
406c6f73aabSFrançois Tigeot 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
407c6f73aabSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
408c6f73aabSFrançois Tigeot 
409c6f73aabSFrançois Tigeot 	if (encoder == NULL)
410c6f73aabSFrançois Tigeot 		return;
411c6f73aabSFrançois Tigeot 
412c6f73aabSFrançois Tigeot 	radeon_encoder = to_radeon_encoder(encoder);
413c6f73aabSFrançois Tigeot 
414c6f73aabSFrançois Tigeot 	if (!list_empty(&connector->probed_modes)) {
415c6f73aabSFrançois Tigeot 		struct drm_display_mode *preferred_mode =
416c6f73aabSFrançois Tigeot 			list_first_entry(&connector->probed_modes,
417c6f73aabSFrançois Tigeot 					 struct drm_display_mode, head);
418c6f73aabSFrançois Tigeot 
419c6f73aabSFrançois Tigeot 		radeon_encoder->native_mode = *preferred_mode;
420c6f73aabSFrançois Tigeot 	} else {
421c6f73aabSFrançois Tigeot 		radeon_encoder->native_mode.clock = 0;
422c6f73aabSFrançois Tigeot 	}
423926deccbSFrançois Tigeot }
424926deccbSFrançois Tigeot 
425926deccbSFrançois Tigeot /*
426926deccbSFrançois Tigeot  * radeon_connector_analog_encoder_conflict_solve
427926deccbSFrançois Tigeot  * - search for other connectors sharing this encoder
428926deccbSFrançois Tigeot  *   if priority is true, then set them disconnected if this is connected
429926deccbSFrançois Tigeot  *   if priority is false, set us disconnected if they are connected
430926deccbSFrançois Tigeot  */
431926deccbSFrançois Tigeot static enum drm_connector_status
432926deccbSFrançois Tigeot radeon_connector_analog_encoder_conflict_solve(struct drm_connector *connector,
433926deccbSFrançois Tigeot 					       struct drm_encoder *encoder,
434926deccbSFrançois Tigeot 					       enum drm_connector_status current_status,
435926deccbSFrançois Tigeot 					       bool priority)
436926deccbSFrançois Tigeot {
437926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
438926deccbSFrançois Tigeot 	struct drm_connector *conflict;
439926deccbSFrançois Tigeot 	struct radeon_connector *radeon_conflict;
440926deccbSFrançois Tigeot 	int i;
441926deccbSFrançois Tigeot 
442926deccbSFrançois Tigeot 	list_for_each_entry(conflict, &dev->mode_config.connector_list, head) {
443926deccbSFrançois Tigeot 		if (conflict == connector)
444926deccbSFrançois Tigeot 			continue;
445926deccbSFrançois Tigeot 
446926deccbSFrançois Tigeot 		radeon_conflict = to_radeon_connector(conflict);
447926deccbSFrançois Tigeot 		for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
448926deccbSFrançois Tigeot 			if (conflict->encoder_ids[i] == 0)
449926deccbSFrançois Tigeot 				break;
450926deccbSFrançois Tigeot 
451926deccbSFrançois Tigeot 			/* if the IDs match */
452926deccbSFrançois Tigeot 			if (conflict->encoder_ids[i] == encoder->base.id) {
453926deccbSFrançois Tigeot 				if (conflict->status != connector_status_connected)
454926deccbSFrançois Tigeot 					continue;
455926deccbSFrançois Tigeot 
456926deccbSFrançois Tigeot 				if (radeon_conflict->use_digital)
457926deccbSFrançois Tigeot 					continue;
458926deccbSFrançois Tigeot 
459926deccbSFrançois Tigeot 				if (priority == true) {
460ba55f2f5SFrançois Tigeot 					DRM_DEBUG_KMS("1: conflicting encoders switching off %s\n",
461ba55f2f5SFrançois Tigeot 						      conflict->name);
462ba55f2f5SFrançois Tigeot 					DRM_DEBUG_KMS("in favor of %s\n",
463ba55f2f5SFrançois Tigeot 						      connector->name);
464926deccbSFrançois Tigeot 					conflict->status = connector_status_disconnected;
465926deccbSFrançois Tigeot 					radeon_connector_update_scratch_regs(conflict, connector_status_disconnected);
466926deccbSFrançois Tigeot 				} else {
467ba55f2f5SFrançois Tigeot 					DRM_DEBUG_KMS("2: conflicting encoders switching off %s\n",
468ba55f2f5SFrançois Tigeot 						      connector->name);
469ba55f2f5SFrançois Tigeot 					DRM_DEBUG_KMS("in favor of %s\n",
470ba55f2f5SFrançois Tigeot 						      conflict->name);
471926deccbSFrançois Tigeot 					current_status = connector_status_disconnected;
472926deccbSFrançois Tigeot 				}
473926deccbSFrançois Tigeot 				break;
474926deccbSFrançois Tigeot 			}
475926deccbSFrançois Tigeot 		}
476926deccbSFrançois Tigeot 	}
477926deccbSFrançois Tigeot 	return current_status;
478926deccbSFrançois Tigeot 
479926deccbSFrançois Tigeot }
480926deccbSFrançois Tigeot 
481926deccbSFrançois Tigeot static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encoder)
482926deccbSFrançois Tigeot {
483926deccbSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
484926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
485926deccbSFrançois Tigeot 	struct drm_display_mode *mode = NULL;
486926deccbSFrançois Tigeot 	struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
487926deccbSFrançois Tigeot 
488926deccbSFrançois Tigeot 	if (native_mode->hdisplay != 0 &&
489926deccbSFrançois Tigeot 	    native_mode->vdisplay != 0 &&
490926deccbSFrançois Tigeot 	    native_mode->clock != 0) {
491926deccbSFrançois Tigeot 		mode = drm_mode_duplicate(dev, native_mode);
492926deccbSFrançois Tigeot 		mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
493926deccbSFrançois Tigeot 		drm_mode_set_name(mode);
494926deccbSFrançois Tigeot 
495926deccbSFrançois Tigeot 		DRM_DEBUG_KMS("Adding native panel mode %s\n", mode->name);
496926deccbSFrançois Tigeot 	} else if (native_mode->hdisplay != 0 &&
497926deccbSFrançois Tigeot 		   native_mode->vdisplay != 0) {
498926deccbSFrançois Tigeot 		/* mac laptops without an edid */
499926deccbSFrançois Tigeot 		/* Note that this is not necessarily the exact panel mode,
500926deccbSFrançois Tigeot 		 * but an approximation based on the cvt formula.  For these
501926deccbSFrançois Tigeot 		 * systems we should ideally read the mode info out of the
502926deccbSFrançois Tigeot 		 * registers or add a mode table, but this works and is much
503926deccbSFrançois Tigeot 		 * simpler.
504926deccbSFrançois Tigeot 		 */
505926deccbSFrançois Tigeot 		mode = drm_cvt_mode(dev, native_mode->hdisplay, native_mode->vdisplay, 60, true, false, false);
506926deccbSFrançois Tigeot 		mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
507926deccbSFrançois Tigeot 		DRM_DEBUG_KMS("Adding cvt approximation of native panel mode %s\n", mode->name);
508926deccbSFrançois Tigeot 	}
509926deccbSFrançois Tigeot 	return mode;
510926deccbSFrançois Tigeot }
511926deccbSFrançois Tigeot 
512926deccbSFrançois Tigeot static void radeon_add_common_modes(struct drm_encoder *encoder, struct drm_connector *connector)
513926deccbSFrançois Tigeot {
514926deccbSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
515926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
516926deccbSFrançois Tigeot 	struct drm_display_mode *mode = NULL;
517926deccbSFrançois Tigeot 	struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
518926deccbSFrançois Tigeot 	int i;
519926deccbSFrançois Tigeot 	struct mode_size {
520926deccbSFrançois Tigeot 		int w;
521926deccbSFrançois Tigeot 		int h;
522926deccbSFrançois Tigeot 	} common_modes[17] = {
523926deccbSFrançois Tigeot 		{ 640,  480},
524926deccbSFrançois Tigeot 		{ 720,  480},
525926deccbSFrançois Tigeot 		{ 800,  600},
526926deccbSFrançois Tigeot 		{ 848,  480},
527926deccbSFrançois Tigeot 		{1024,  768},
528926deccbSFrançois Tigeot 		{1152,  768},
529926deccbSFrançois Tigeot 		{1280,  720},
530926deccbSFrançois Tigeot 		{1280,  800},
531926deccbSFrançois Tigeot 		{1280,  854},
532926deccbSFrançois Tigeot 		{1280,  960},
533926deccbSFrançois Tigeot 		{1280, 1024},
534926deccbSFrançois Tigeot 		{1440,  900},
535926deccbSFrançois Tigeot 		{1400, 1050},
536926deccbSFrançois Tigeot 		{1680, 1050},
537926deccbSFrançois Tigeot 		{1600, 1200},
538926deccbSFrançois Tigeot 		{1920, 1080},
539926deccbSFrançois Tigeot 		{1920, 1200}
540926deccbSFrançois Tigeot 	};
541926deccbSFrançois Tigeot 
542926deccbSFrançois Tigeot 	for (i = 0; i < 17; i++) {
543926deccbSFrançois Tigeot 		if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) {
544926deccbSFrançois Tigeot 			if (common_modes[i].w > 1024 ||
545926deccbSFrançois Tigeot 			    common_modes[i].h > 768)
546926deccbSFrançois Tigeot 				continue;
547926deccbSFrançois Tigeot 		}
548926deccbSFrançois Tigeot 		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
549926deccbSFrançois Tigeot 			if (common_modes[i].w > native_mode->hdisplay ||
550926deccbSFrançois Tigeot 			    common_modes[i].h > native_mode->vdisplay ||
551926deccbSFrançois Tigeot 			    (common_modes[i].w == native_mode->hdisplay &&
552926deccbSFrançois Tigeot 			     common_modes[i].h == native_mode->vdisplay))
553926deccbSFrançois Tigeot 				continue;
554926deccbSFrançois Tigeot 		}
555926deccbSFrançois Tigeot 		if (common_modes[i].w < 320 || common_modes[i].h < 200)
556926deccbSFrançois Tigeot 			continue;
557926deccbSFrançois Tigeot 
558926deccbSFrançois Tigeot 		mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false);
559926deccbSFrançois Tigeot 		drm_mode_probed_add(connector, mode);
560926deccbSFrançois Tigeot 	}
561926deccbSFrançois Tigeot }
562926deccbSFrançois Tigeot 
563926deccbSFrançois Tigeot static int radeon_connector_set_property(struct drm_connector *connector, struct drm_property *property,
564926deccbSFrançois Tigeot 				  uint64_t val)
565926deccbSFrançois Tigeot {
566926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
567926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
568926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
569926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
570926deccbSFrançois Tigeot 
571926deccbSFrançois Tigeot 	if (property == rdev->mode_info.coherent_mode_property) {
572926deccbSFrançois Tigeot 		struct radeon_encoder_atom_dig *dig;
573926deccbSFrançois Tigeot 		bool new_coherent_mode;
574926deccbSFrançois Tigeot 
575926deccbSFrançois Tigeot 		/* need to find digital encoder on connector */
576926deccbSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
577926deccbSFrançois Tigeot 		if (!encoder)
578926deccbSFrançois Tigeot 			return 0;
579926deccbSFrançois Tigeot 
580926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
581926deccbSFrançois Tigeot 
582926deccbSFrançois Tigeot 		if (!radeon_encoder->enc_priv)
583926deccbSFrançois Tigeot 			return 0;
584926deccbSFrançois Tigeot 
585926deccbSFrançois Tigeot 		dig = radeon_encoder->enc_priv;
586926deccbSFrançois Tigeot 		new_coherent_mode = val ? true : false;
587926deccbSFrançois Tigeot 		if (dig->coherent_mode != new_coherent_mode) {
588926deccbSFrançois Tigeot 			dig->coherent_mode = new_coherent_mode;
589926deccbSFrançois Tigeot 			radeon_property_change_mode(&radeon_encoder->base);
590926deccbSFrançois Tigeot 		}
591926deccbSFrançois Tigeot 	}
592926deccbSFrançois Tigeot 
5934cd92098Szrj 	if (property == rdev->mode_info.audio_property) {
5944cd92098Szrj 		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
5954cd92098Szrj 		/* need to find digital encoder on connector */
5964cd92098Szrj 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
5974cd92098Szrj 		if (!encoder)
5984cd92098Szrj 			return 0;
5994cd92098Szrj 
6004cd92098Szrj 		radeon_encoder = to_radeon_encoder(encoder);
6014cd92098Szrj 
6024cd92098Szrj 		if (radeon_connector->audio != val) {
6034cd92098Szrj 			radeon_connector->audio = val;
6044cd92098Szrj 			radeon_property_change_mode(&radeon_encoder->base);
6054cd92098Szrj 		}
6064cd92098Szrj 	}
6074cd92098Szrj 
608c6f73aabSFrançois Tigeot 	if (property == rdev->mode_info.dither_property) {
609c6f73aabSFrançois Tigeot 		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
610c6f73aabSFrançois Tigeot 		/* need to find digital encoder on connector */
611c6f73aabSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
612c6f73aabSFrançois Tigeot 		if (!encoder)
613c6f73aabSFrançois Tigeot 			return 0;
614c6f73aabSFrançois Tigeot 
615c6f73aabSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
616c6f73aabSFrançois Tigeot 
617c6f73aabSFrançois Tigeot 		if (radeon_connector->dither != val) {
618c6f73aabSFrançois Tigeot 			radeon_connector->dither = val;
619c6f73aabSFrançois Tigeot 			radeon_property_change_mode(&radeon_encoder->base);
620c6f73aabSFrançois Tigeot 		}
621c6f73aabSFrançois Tigeot 	}
622c6f73aabSFrançois Tigeot 
623926deccbSFrançois Tigeot 	if (property == rdev->mode_info.underscan_property) {
624926deccbSFrançois Tigeot 		/* need to find digital encoder on connector */
625926deccbSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
626926deccbSFrançois Tigeot 		if (!encoder)
627926deccbSFrançois Tigeot 			return 0;
628926deccbSFrançois Tigeot 
629926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
630926deccbSFrançois Tigeot 
631926deccbSFrançois Tigeot 		if (radeon_encoder->underscan_type != val) {
632926deccbSFrançois Tigeot 			radeon_encoder->underscan_type = val;
633926deccbSFrançois Tigeot 			radeon_property_change_mode(&radeon_encoder->base);
634926deccbSFrançois Tigeot 		}
635926deccbSFrançois Tigeot 	}
636926deccbSFrançois Tigeot 
637926deccbSFrançois Tigeot 	if (property == rdev->mode_info.underscan_hborder_property) {
638926deccbSFrançois Tigeot 		/* need to find digital encoder on connector */
639926deccbSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
640926deccbSFrançois Tigeot 		if (!encoder)
641926deccbSFrançois Tigeot 			return 0;
642926deccbSFrançois Tigeot 
643926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
644926deccbSFrançois Tigeot 
645926deccbSFrançois Tigeot 		if (radeon_encoder->underscan_hborder != val) {
646926deccbSFrançois Tigeot 			radeon_encoder->underscan_hborder = val;
647926deccbSFrançois Tigeot 			radeon_property_change_mode(&radeon_encoder->base);
648926deccbSFrançois Tigeot 		}
649926deccbSFrançois Tigeot 	}
650926deccbSFrançois Tigeot 
651926deccbSFrançois Tigeot 	if (property == rdev->mode_info.underscan_vborder_property) {
652926deccbSFrançois Tigeot 		/* need to find digital encoder on connector */
653926deccbSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
654926deccbSFrançois Tigeot 		if (!encoder)
655926deccbSFrançois Tigeot 			return 0;
656926deccbSFrançois Tigeot 
657926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
658926deccbSFrançois Tigeot 
659926deccbSFrançois Tigeot 		if (radeon_encoder->underscan_vborder != val) {
660926deccbSFrançois Tigeot 			radeon_encoder->underscan_vborder = val;
661926deccbSFrançois Tigeot 			radeon_property_change_mode(&radeon_encoder->base);
662926deccbSFrançois Tigeot 		}
663926deccbSFrançois Tigeot 	}
664926deccbSFrançois Tigeot 
665926deccbSFrançois Tigeot 	if (property == rdev->mode_info.tv_std_property) {
666926deccbSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TVDAC);
667926deccbSFrançois Tigeot 		if (!encoder) {
668926deccbSFrançois Tigeot 			encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_DAC);
669926deccbSFrançois Tigeot 		}
670926deccbSFrançois Tigeot 
671926deccbSFrançois Tigeot 		if (!encoder)
672926deccbSFrançois Tigeot 			return 0;
673926deccbSFrançois Tigeot 
674926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
675926deccbSFrançois Tigeot 		if (!radeon_encoder->enc_priv)
676926deccbSFrançois Tigeot 			return 0;
677926deccbSFrançois Tigeot 		if (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom) {
678926deccbSFrançois Tigeot 			struct radeon_encoder_atom_dac *dac_int;
679926deccbSFrançois Tigeot 			dac_int = radeon_encoder->enc_priv;
680926deccbSFrançois Tigeot 			dac_int->tv_std = val;
681926deccbSFrançois Tigeot 		} else {
682926deccbSFrançois Tigeot 			struct radeon_encoder_tv_dac *dac_int;
683926deccbSFrançois Tigeot 			dac_int = radeon_encoder->enc_priv;
684926deccbSFrançois Tigeot 			dac_int->tv_std = val;
685926deccbSFrançois Tigeot 		}
686926deccbSFrançois Tigeot 		radeon_property_change_mode(&radeon_encoder->base);
687926deccbSFrançois Tigeot 	}
688926deccbSFrançois Tigeot 
689926deccbSFrançois Tigeot 	if (property == rdev->mode_info.load_detect_property) {
690926deccbSFrançois Tigeot 		struct radeon_connector *radeon_connector =
691926deccbSFrançois Tigeot 			to_radeon_connector(connector);
692926deccbSFrançois Tigeot 
693926deccbSFrançois Tigeot 		if (val == 0)
694926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = false;
695926deccbSFrançois Tigeot 		else
696926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
697926deccbSFrançois Tigeot 	}
698926deccbSFrançois Tigeot 
699926deccbSFrançois Tigeot 	if (property == rdev->mode_info.tmds_pll_property) {
700926deccbSFrançois Tigeot 		struct radeon_encoder_int_tmds *tmds = NULL;
701926deccbSFrançois Tigeot 		bool ret = false;
702926deccbSFrançois Tigeot 		/* need to find digital encoder on connector */
703926deccbSFrançois Tigeot 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
704926deccbSFrançois Tigeot 		if (!encoder)
705926deccbSFrançois Tigeot 			return 0;
706926deccbSFrançois Tigeot 
707926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
708926deccbSFrançois Tigeot 
709926deccbSFrançois Tigeot 		tmds = radeon_encoder->enc_priv;
710926deccbSFrançois Tigeot 		if (!tmds)
711926deccbSFrançois Tigeot 			return 0;
712926deccbSFrançois Tigeot 
713926deccbSFrançois Tigeot 		if (val == 0) {
714926deccbSFrançois Tigeot 			if (rdev->is_atom_bios)
715926deccbSFrançois Tigeot 				ret = radeon_atombios_get_tmds_info(radeon_encoder, tmds);
716926deccbSFrançois Tigeot 			else
717926deccbSFrançois Tigeot 				ret = radeon_legacy_get_tmds_info_from_combios(radeon_encoder, tmds);
718926deccbSFrançois Tigeot 		}
719926deccbSFrançois Tigeot 		if (val == 1 || ret == false) {
720926deccbSFrançois Tigeot 			radeon_legacy_get_tmds_info_from_table(radeon_encoder, tmds);
721926deccbSFrançois Tigeot 		}
722926deccbSFrançois Tigeot 		radeon_property_change_mode(&radeon_encoder->base);
723926deccbSFrançois Tigeot 	}
724926deccbSFrançois Tigeot 
725c6f73aabSFrançois Tigeot 	if (property == dev->mode_config.scaling_mode_property) {
726c6f73aabSFrançois Tigeot 		enum radeon_rmx_type rmx_type;
727c6f73aabSFrançois Tigeot 
728c6f73aabSFrançois Tigeot 		if (connector->encoder)
729c6f73aabSFrançois Tigeot 			radeon_encoder = to_radeon_encoder(connector->encoder);
730c6f73aabSFrançois Tigeot 		else {
731c0e85e96SFrançois Tigeot 			const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
732c6f73aabSFrançois Tigeot 			radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector));
733c6f73aabSFrançois Tigeot 		}
734c6f73aabSFrançois Tigeot 
735c6f73aabSFrançois Tigeot 		switch (val) {
736c6f73aabSFrançois Tigeot 		default:
737c6f73aabSFrançois Tigeot 		case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break;
738c6f73aabSFrançois Tigeot 		case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break;
739c6f73aabSFrançois Tigeot 		case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break;
740c6f73aabSFrançois Tigeot 		case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break;
741c6f73aabSFrançois Tigeot 		}
742c6f73aabSFrançois Tigeot 		if (radeon_encoder->rmx_type == rmx_type)
743c6f73aabSFrançois Tigeot 			return 0;
744c6f73aabSFrançois Tigeot 
745c6f73aabSFrançois Tigeot 		if ((rmx_type != DRM_MODE_SCALE_NONE) &&
746c6f73aabSFrançois Tigeot 		    (radeon_encoder->native_mode.clock == 0))
747c6f73aabSFrançois Tigeot 			return 0;
748c6f73aabSFrançois Tigeot 
749c6f73aabSFrançois Tigeot 		radeon_encoder->rmx_type = rmx_type;
750c6f73aabSFrançois Tigeot 
751c6f73aabSFrançois Tigeot 		radeon_property_change_mode(&radeon_encoder->base);
752c6f73aabSFrançois Tigeot 	}
753c6f73aabSFrançois Tigeot 
754c59a5c48SFrançois Tigeot 	if (property == rdev->mode_info.output_csc_property) {
755c59a5c48SFrançois Tigeot 		if (connector->encoder)
756c59a5c48SFrançois Tigeot 			radeon_encoder = to_radeon_encoder(connector->encoder);
757c59a5c48SFrançois Tigeot 		else {
758c59a5c48SFrançois Tigeot 			const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
759c59a5c48SFrançois Tigeot 			radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector));
760c59a5c48SFrançois Tigeot 		}
761c59a5c48SFrançois Tigeot 
762c59a5c48SFrançois Tigeot 		if (radeon_encoder->output_csc == val)
763c59a5c48SFrançois Tigeot 			return 0;
764c59a5c48SFrançois Tigeot 
765c59a5c48SFrançois Tigeot 		radeon_encoder->output_csc = val;
766c59a5c48SFrançois Tigeot 
767c59a5c48SFrançois Tigeot 		if (connector->encoder->crtc) {
768c59a5c48SFrançois Tigeot 			struct drm_crtc *crtc  = connector->encoder->crtc;
769c59a5c48SFrançois Tigeot 			const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
770c59a5c48SFrançois Tigeot 			struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
771c59a5c48SFrançois Tigeot 
772c59a5c48SFrançois Tigeot 			radeon_crtc->output_csc = radeon_encoder->output_csc;
773c59a5c48SFrançois Tigeot 
774c59a5c48SFrançois Tigeot 			(*crtc_funcs->load_lut)(crtc);
775c59a5c48SFrançois Tigeot 		}
776c59a5c48SFrançois Tigeot 	}
777c59a5c48SFrançois Tigeot 
778926deccbSFrançois Tigeot 	return 0;
779926deccbSFrançois Tigeot }
780926deccbSFrançois Tigeot 
781926deccbSFrançois Tigeot static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder,
782926deccbSFrançois Tigeot 					  struct drm_connector *connector)
783926deccbSFrançois Tigeot {
784926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder =	to_radeon_encoder(encoder);
785926deccbSFrançois Tigeot 	struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
786926deccbSFrançois Tigeot 	struct drm_display_mode *t, *mode;
787926deccbSFrançois Tigeot 
788926deccbSFrançois Tigeot 	/* If the EDID preferred mode doesn't match the native mode, use it */
789926deccbSFrançois Tigeot 	list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
790926deccbSFrançois Tigeot 		if (mode->type & DRM_MODE_TYPE_PREFERRED) {
791926deccbSFrançois Tigeot 			if (mode->hdisplay != native_mode->hdisplay ||
792926deccbSFrançois Tigeot 			    mode->vdisplay != native_mode->vdisplay)
793926deccbSFrançois Tigeot 				memcpy(native_mode, mode, sizeof(*mode));
794926deccbSFrançois Tigeot 		}
795926deccbSFrançois Tigeot 	}
796926deccbSFrançois Tigeot 
797926deccbSFrançois Tigeot 	/* Try to get native mode details from EDID if necessary */
798926deccbSFrançois Tigeot 	if (!native_mode->clock) {
799926deccbSFrançois Tigeot 		list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
800926deccbSFrançois Tigeot 			if (mode->hdisplay == native_mode->hdisplay &&
801926deccbSFrançois Tigeot 			    mode->vdisplay == native_mode->vdisplay) {
802926deccbSFrançois Tigeot 				*native_mode = *mode;
803926deccbSFrançois Tigeot 				drm_mode_set_crtcinfo(native_mode, CRTC_INTERLACE_HALVE_V);
804926deccbSFrançois Tigeot 				DRM_DEBUG_KMS("Determined LVDS native mode details from EDID\n");
805926deccbSFrançois Tigeot 				break;
806926deccbSFrançois Tigeot 			}
807926deccbSFrançois Tigeot 		}
808926deccbSFrançois Tigeot 	}
809926deccbSFrançois Tigeot 
810926deccbSFrançois Tigeot 	if (!native_mode->clock) {
811926deccbSFrançois Tigeot 		DRM_DEBUG_KMS("No LVDS native mode details, disabling RMX\n");
812926deccbSFrançois Tigeot 		radeon_encoder->rmx_type = RMX_OFF;
813926deccbSFrançois Tigeot 	}
814926deccbSFrançois Tigeot }
815926deccbSFrançois Tigeot 
816926deccbSFrançois Tigeot static int radeon_lvds_get_modes(struct drm_connector *connector)
817926deccbSFrançois Tigeot {
818926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
819926deccbSFrançois Tigeot 	int ret = 0;
820926deccbSFrançois Tigeot 	struct drm_display_mode *mode;
821926deccbSFrançois Tigeot 
8225ef6d7b4SFrançois Tigeot 	radeon_connector_get_edid(connector);
8235ef6d7b4SFrançois Tigeot 	ret = radeon_ddc_get_modes(connector);
824926deccbSFrançois Tigeot 	if (ret > 0) {
825926deccbSFrançois Tigeot 		encoder = radeon_best_single_encoder(connector);
826926deccbSFrançois Tigeot 		if (encoder) {
827926deccbSFrançois Tigeot 			radeon_fixup_lvds_native_mode(encoder, connector);
828926deccbSFrançois Tigeot 			/* add scaled modes */
829926deccbSFrançois Tigeot 			radeon_add_common_modes(encoder, connector);
830926deccbSFrançois Tigeot 		}
831926deccbSFrançois Tigeot 		return ret;
832926deccbSFrançois Tigeot 	}
833926deccbSFrançois Tigeot 
834926deccbSFrançois Tigeot 	encoder = radeon_best_single_encoder(connector);
835926deccbSFrançois Tigeot 	if (!encoder)
836926deccbSFrançois Tigeot 		return 0;
837926deccbSFrançois Tigeot 
838926deccbSFrançois Tigeot 	/* we have no EDID modes */
839926deccbSFrançois Tigeot 	mode = radeon_fp_native_mode(encoder);
840926deccbSFrançois Tigeot 	if (mode) {
841926deccbSFrançois Tigeot 		ret = 1;
842926deccbSFrançois Tigeot 		drm_mode_probed_add(connector, mode);
843926deccbSFrançois Tigeot 		/* add the width/height from vbios tables if available */
844926deccbSFrançois Tigeot 		connector->display_info.width_mm = mode->width_mm;
845926deccbSFrançois Tigeot 		connector->display_info.height_mm = mode->height_mm;
846926deccbSFrançois Tigeot 		/* add scaled modes */
847926deccbSFrançois Tigeot 		radeon_add_common_modes(encoder, connector);
848926deccbSFrançois Tigeot 	}
849926deccbSFrançois Tigeot 
850926deccbSFrançois Tigeot 	return ret;
851926deccbSFrançois Tigeot }
852926deccbSFrançois Tigeot 
853c59a5c48SFrançois Tigeot static enum drm_mode_status radeon_lvds_mode_valid(struct drm_connector *connector,
854926deccbSFrançois Tigeot 				  struct drm_display_mode *mode)
855926deccbSFrançois Tigeot {
856926deccbSFrançois Tigeot 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
857926deccbSFrançois Tigeot 
858926deccbSFrançois Tigeot 	if ((mode->hdisplay < 320) || (mode->vdisplay < 240))
859926deccbSFrançois Tigeot 		return MODE_PANEL;
860926deccbSFrançois Tigeot 
861926deccbSFrançois Tigeot 	if (encoder) {
862926deccbSFrançois Tigeot 		struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
863926deccbSFrançois Tigeot 		struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
864926deccbSFrançois Tigeot 
865926deccbSFrançois Tigeot 		/* AVIVO hardware supports downscaling modes larger than the panel
866926deccbSFrançois Tigeot 		 * to the panel size, but I'm not sure this is desirable.
867926deccbSFrançois Tigeot 		 */
868926deccbSFrançois Tigeot 		if ((mode->hdisplay > native_mode->hdisplay) ||
869926deccbSFrançois Tigeot 		    (mode->vdisplay > native_mode->vdisplay))
870926deccbSFrançois Tigeot 			return MODE_PANEL;
871926deccbSFrançois Tigeot 
872926deccbSFrançois Tigeot 		/* if scaling is disabled, block non-native modes */
873926deccbSFrançois Tigeot 		if (radeon_encoder->rmx_type == RMX_OFF) {
874926deccbSFrançois Tigeot 			if ((mode->hdisplay != native_mode->hdisplay) ||
875926deccbSFrançois Tigeot 			    (mode->vdisplay != native_mode->vdisplay))
876926deccbSFrançois Tigeot 				return MODE_PANEL;
877926deccbSFrançois Tigeot 		}
878926deccbSFrançois Tigeot 	}
879926deccbSFrançois Tigeot 
880926deccbSFrançois Tigeot 	return MODE_OK;
881926deccbSFrançois Tigeot }
882926deccbSFrançois Tigeot 
883926deccbSFrançois Tigeot static enum drm_connector_status
884926deccbSFrançois Tigeot radeon_lvds_detect(struct drm_connector *connector, bool force)
885926deccbSFrançois Tigeot {
8861cfef1a5SFrançois Tigeot 	struct drm_device *dev = connector->dev;
8871cfef1a5SFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
888926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
889926deccbSFrançois Tigeot 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
890926deccbSFrançois Tigeot 	enum drm_connector_status ret = connector_status_disconnected;
891c6f73aabSFrançois Tigeot #ifdef PM_TODO
892c6f73aabSFrançois Tigeot 	int r;
893c6f73aabSFrançois Tigeot 
894c6f73aabSFrançois Tigeot 	r = pm_runtime_get_sync(connector->dev->dev);
895c6f73aabSFrançois Tigeot 	if (r < 0)
896c6f73aabSFrançois Tigeot 		return connector_status_disconnected;
897c6f73aabSFrançois Tigeot #endif
898926deccbSFrançois Tigeot 
899926deccbSFrançois Tigeot 	if (encoder) {
900926deccbSFrançois Tigeot 		struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
901926deccbSFrançois Tigeot 		struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
902926deccbSFrançois Tigeot 
903926deccbSFrançois Tigeot 		/* check if panel is valid */
904926deccbSFrançois Tigeot 		if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
905926deccbSFrançois Tigeot 			ret = connector_status_connected;
9061cfef1a5SFrançois Tigeot 		/* don't fetch the edid from the vbios if ddc fails and runpm is
9071cfef1a5SFrançois Tigeot 		 * enabled so we report disconnected.
9081cfef1a5SFrançois Tigeot 		 */
9091cfef1a5SFrançois Tigeot 		if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0))
9101cfef1a5SFrançois Tigeot 			ret = connector_status_disconnected;
911926deccbSFrançois Tigeot 	}
912926deccbSFrançois Tigeot 
913926deccbSFrançois Tigeot 	/* check for edid as well */
9145ef6d7b4SFrançois Tigeot 	radeon_connector_get_edid(connector);
915926deccbSFrançois Tigeot 	if (radeon_connector->edid)
916926deccbSFrançois Tigeot 		ret = connector_status_connected;
917926deccbSFrançois Tigeot 	/* check acpi lid status ??? */
918926deccbSFrançois Tigeot 
919926deccbSFrançois Tigeot 	radeon_connector_update_scratch_regs(connector, ret);
920c6f73aabSFrançois Tigeot #ifdef PM_TODO
921c6f73aabSFrançois Tigeot 	pm_runtime_mark_last_busy(connector->dev->dev);
922c6f73aabSFrançois Tigeot 	pm_runtime_put_autosuspend(connector->dev->dev);
923c6f73aabSFrançois Tigeot #endif
924926deccbSFrançois Tigeot 	return ret;
925926deccbSFrançois Tigeot }
926926deccbSFrançois Tigeot 
927*1dedbd3bSFrançois Tigeot static void radeon_connector_unregister(struct drm_connector *connector)
928*1dedbd3bSFrançois Tigeot {
929*1dedbd3bSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
930*1dedbd3bSFrançois Tigeot 
931*1dedbd3bSFrançois Tigeot 	if (radeon_connector->ddc_bus && radeon_connector->ddc_bus->has_aux) {
932*1dedbd3bSFrançois Tigeot 		drm_dp_aux_unregister(&radeon_connector->ddc_bus->aux);
933*1dedbd3bSFrançois Tigeot 		radeon_connector->ddc_bus->has_aux = false;
934*1dedbd3bSFrançois Tigeot 	}
935*1dedbd3bSFrançois Tigeot }
936*1dedbd3bSFrançois Tigeot 
937926deccbSFrançois Tigeot static void radeon_connector_destroy(struct drm_connector *connector)
938926deccbSFrançois Tigeot {
939926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
940926deccbSFrançois Tigeot 
9415ef6d7b4SFrançois Tigeot 	radeon_connector_free_edid(connector);
942c4ef309bSzrj 	kfree(radeon_connector->con_priv);
943c6f73aabSFrançois Tigeot 	drm_connector_unregister(connector);
944926deccbSFrançois Tigeot 	drm_connector_cleanup(connector);
945c4ef309bSzrj 	kfree(connector);
946926deccbSFrançois Tigeot }
947926deccbSFrançois Tigeot 
948926deccbSFrançois Tigeot static int radeon_lvds_set_property(struct drm_connector *connector,
949926deccbSFrançois Tigeot 				    struct drm_property *property,
950926deccbSFrançois Tigeot 				    uint64_t value)
951926deccbSFrançois Tigeot {
952926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
953926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
954926deccbSFrançois Tigeot 	enum radeon_rmx_type rmx_type;
955926deccbSFrançois Tigeot 
956926deccbSFrançois Tigeot 	DRM_DEBUG_KMS("\n");
957926deccbSFrançois Tigeot 	if (property != dev->mode_config.scaling_mode_property)
958926deccbSFrançois Tigeot 		return 0;
959926deccbSFrançois Tigeot 
960926deccbSFrançois Tigeot 	if (connector->encoder)
961926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(connector->encoder);
962926deccbSFrançois Tigeot 	else {
963c0e85e96SFrançois Tigeot 		const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
964926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector));
965926deccbSFrançois Tigeot 	}
966926deccbSFrançois Tigeot 
967926deccbSFrançois Tigeot 	switch (value) {
968926deccbSFrançois Tigeot 	case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break;
969926deccbSFrançois Tigeot 	case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break;
970926deccbSFrançois Tigeot 	case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break;
971926deccbSFrançois Tigeot 	default:
972926deccbSFrançois Tigeot 	case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break;
973926deccbSFrançois Tigeot 	}
974926deccbSFrançois Tigeot 	if (radeon_encoder->rmx_type == rmx_type)
975926deccbSFrançois Tigeot 		return 0;
976926deccbSFrançois Tigeot 
977926deccbSFrançois Tigeot 	radeon_encoder->rmx_type = rmx_type;
978926deccbSFrançois Tigeot 
979926deccbSFrançois Tigeot 	radeon_property_change_mode(&radeon_encoder->base);
980926deccbSFrançois Tigeot 	return 0;
981926deccbSFrançois Tigeot }
982926deccbSFrançois Tigeot 
983926deccbSFrançois Tigeot 
984926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_lvds_connector_helper_funcs = {
985926deccbSFrançois Tigeot 	.get_modes = radeon_lvds_get_modes,
986926deccbSFrançois Tigeot 	.mode_valid = radeon_lvds_mode_valid,
987926deccbSFrançois Tigeot 	.best_encoder = radeon_best_single_encoder,
988926deccbSFrançois Tigeot };
989926deccbSFrançois Tigeot 
990926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_lvds_connector_funcs = {
991926deccbSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
992926deccbSFrançois Tigeot 	.detect = radeon_lvds_detect,
993926deccbSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
994*1dedbd3bSFrançois Tigeot 	.early_unregister = radeon_connector_unregister,
995926deccbSFrançois Tigeot 	.destroy = radeon_connector_destroy,
996926deccbSFrançois Tigeot 	.set_property = radeon_lvds_set_property,
997926deccbSFrançois Tigeot };
998926deccbSFrançois Tigeot 
999926deccbSFrançois Tigeot static int radeon_vga_get_modes(struct drm_connector *connector)
1000926deccbSFrançois Tigeot {
1001926deccbSFrançois Tigeot 	int ret;
1002926deccbSFrançois Tigeot 
10035ef6d7b4SFrançois Tigeot 	radeon_connector_get_edid(connector);
10045ef6d7b4SFrançois Tigeot 	ret = radeon_ddc_get_modes(connector);
1005926deccbSFrançois Tigeot 
1006c6f73aabSFrançois Tigeot 	radeon_get_native_mode(connector);
1007c6f73aabSFrançois Tigeot 
1008926deccbSFrançois Tigeot 	return ret;
1009926deccbSFrançois Tigeot }
1010926deccbSFrançois Tigeot 
1011c59a5c48SFrançois Tigeot static enum drm_mode_status radeon_vga_mode_valid(struct drm_connector *connector,
1012926deccbSFrançois Tigeot 				  struct drm_display_mode *mode)
1013926deccbSFrançois Tigeot {
1014926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1015926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1016926deccbSFrançois Tigeot 
1017926deccbSFrançois Tigeot 	/* XXX check mode bandwidth */
1018926deccbSFrançois Tigeot 
1019926deccbSFrançois Tigeot 	if ((mode->clock / 10) > rdev->clock.max_pixel_clock)
1020926deccbSFrançois Tigeot 		return MODE_CLOCK_HIGH;
1021926deccbSFrançois Tigeot 
1022926deccbSFrançois Tigeot 	return MODE_OK;
1023926deccbSFrançois Tigeot }
1024926deccbSFrançois Tigeot 
1025926deccbSFrançois Tigeot static enum drm_connector_status
1026926deccbSFrançois Tigeot radeon_vga_detect(struct drm_connector *connector, bool force)
1027926deccbSFrançois Tigeot {
1028926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1029926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1030926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1031926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1032c0e85e96SFrançois Tigeot 	const struct drm_encoder_helper_funcs *encoder_funcs;
1033926deccbSFrançois Tigeot 	bool dret = false;
1034926deccbSFrançois Tigeot 	enum drm_connector_status ret = connector_status_disconnected;
1035c6f73aabSFrançois Tigeot #ifdef PM_TODO
1036c6f73aabSFrançois Tigeot 	int r;
1037c6f73aabSFrançois Tigeot 
1038c6f73aabSFrançois Tigeot 	r = pm_runtime_get_sync(connector->dev->dev);
1039c6f73aabSFrançois Tigeot 	if (r < 0)
1040c6f73aabSFrançois Tigeot 		return connector_status_disconnected;
1041c6f73aabSFrançois Tigeot #endif
1042926deccbSFrançois Tigeot 
1043926deccbSFrançois Tigeot 	encoder = radeon_best_single_encoder(connector);
1044926deccbSFrançois Tigeot 	if (!encoder)
1045926deccbSFrançois Tigeot 		ret = connector_status_disconnected;
1046926deccbSFrançois Tigeot 
1047926deccbSFrançois Tigeot 	if (radeon_connector->ddc_bus)
1048926deccbSFrançois Tigeot 		dret = radeon_ddc_probe(radeon_connector, false);
1049926deccbSFrançois Tigeot 	if (dret) {
1050926deccbSFrançois Tigeot 		radeon_connector->detected_by_load = false;
10515ef6d7b4SFrançois Tigeot 		radeon_connector_free_edid(connector);
10525ef6d7b4SFrançois Tigeot 		radeon_connector_get_edid(connector);
1053926deccbSFrançois Tigeot 
1054926deccbSFrançois Tigeot 		if (!radeon_connector->edid) {
1055926deccbSFrançois Tigeot 			DRM_ERROR("%s: probed a monitor but no|invalid EDID\n",
1056ba55f2f5SFrançois Tigeot 					connector->name);
1057926deccbSFrançois Tigeot 			ret = connector_status_connected;
1058926deccbSFrançois Tigeot 		} else {
10597191d616Szrj 			radeon_connector->use_digital =
10607191d616Szrj 				!!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
1061926deccbSFrançois Tigeot 
1062926deccbSFrançois Tigeot 			/* some oems have boards with separate digital and analog connectors
1063926deccbSFrançois Tigeot 			 * with a shared ddc line (often vga + hdmi)
1064926deccbSFrançois Tigeot 			 */
1065926deccbSFrançois Tigeot 			if (radeon_connector->use_digital && radeon_connector->shared_ddc) {
10665ef6d7b4SFrançois Tigeot 				radeon_connector_free_edid(connector);
1067926deccbSFrançois Tigeot 				ret = connector_status_disconnected;
10687191d616Szrj 			} else {
1069926deccbSFrançois Tigeot 				ret = connector_status_connected;
1070926deccbSFrançois Tigeot 			}
10717191d616Szrj 		}
1072926deccbSFrançois Tigeot 	} else {
1073926deccbSFrançois Tigeot 
1074926deccbSFrançois Tigeot 		/* if we aren't forcing don't do destructive polling */
1075926deccbSFrançois Tigeot 		if (!force) {
1076926deccbSFrançois Tigeot 			/* only return the previous status if we last
1077926deccbSFrançois Tigeot 			 * detected a monitor via load.
1078926deccbSFrançois Tigeot 			 */
1079926deccbSFrançois Tigeot 			if (radeon_connector->detected_by_load)
1080c6f73aabSFrançois Tigeot 				ret = connector->status;
1081c6f73aabSFrançois Tigeot 			goto out;
1082926deccbSFrançois Tigeot 		}
1083926deccbSFrançois Tigeot 
1084926deccbSFrançois Tigeot 		if (radeon_connector->dac_load_detect && encoder) {
1085926deccbSFrançois Tigeot 			encoder_funcs = encoder->helper_private;
1086926deccbSFrançois Tigeot 			ret = encoder_funcs->detect(encoder, connector);
1087926deccbSFrançois Tigeot 			if (ret != connector_status_disconnected)
1088926deccbSFrançois Tigeot 				radeon_connector->detected_by_load = true;
1089926deccbSFrançois Tigeot 		}
1090926deccbSFrançois Tigeot 	}
1091926deccbSFrançois Tigeot 
1092926deccbSFrançois Tigeot 	if (ret == connector_status_connected)
1093926deccbSFrançois Tigeot 		ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true);
1094926deccbSFrançois Tigeot 
1095926deccbSFrançois Tigeot 	/* RN50 and some RV100 asics in servers often have a hardcoded EDID in the
1096926deccbSFrançois Tigeot 	 * vbios to deal with KVMs. If we have one and are not able to detect a monitor
1097926deccbSFrançois Tigeot 	 * by other means, assume the CRT is connected and use that EDID.
1098926deccbSFrançois Tigeot 	 */
1099926deccbSFrançois Tigeot 	if ((!rdev->is_atom_bios) &&
1100926deccbSFrançois Tigeot 	    (ret == connector_status_disconnected) &&
1101926deccbSFrançois Tigeot 	    rdev->mode_info.bios_hardcoded_edid_size) {
1102926deccbSFrançois Tigeot 		ret = connector_status_connected;
1103926deccbSFrançois Tigeot 	}
1104926deccbSFrançois Tigeot 
1105926deccbSFrançois Tigeot 	radeon_connector_update_scratch_regs(connector, ret);
1106c6f73aabSFrançois Tigeot 
1107c6f73aabSFrançois Tigeot out:
1108c6f73aabSFrançois Tigeot #ifdef PM_TODO
1109c6f73aabSFrançois Tigeot 	pm_runtime_mark_last_busy(connector->dev->dev);
1110c6f73aabSFrançois Tigeot 	pm_runtime_put_autosuspend(connector->dev->dev);
1111c6f73aabSFrançois Tigeot #endif
1112c6f73aabSFrançois Tigeot 
1113926deccbSFrançois Tigeot 	return ret;
1114926deccbSFrançois Tigeot }
1115926deccbSFrançois Tigeot 
1116926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_vga_connector_helper_funcs = {
1117926deccbSFrançois Tigeot 	.get_modes = radeon_vga_get_modes,
1118926deccbSFrançois Tigeot 	.mode_valid = radeon_vga_mode_valid,
1119926deccbSFrançois Tigeot 	.best_encoder = radeon_best_single_encoder,
1120926deccbSFrançois Tigeot };
1121926deccbSFrançois Tigeot 
1122926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_vga_connector_funcs = {
1123926deccbSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
1124926deccbSFrançois Tigeot 	.detect = radeon_vga_detect,
1125926deccbSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
1126*1dedbd3bSFrançois Tigeot 	.early_unregister = radeon_connector_unregister,
1127926deccbSFrançois Tigeot 	.destroy = radeon_connector_destroy,
1128926deccbSFrançois Tigeot 	.set_property = radeon_connector_set_property,
1129926deccbSFrançois Tigeot };
1130926deccbSFrançois Tigeot 
1131926deccbSFrançois Tigeot static int radeon_tv_get_modes(struct drm_connector *connector)
1132926deccbSFrançois Tigeot {
1133926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1134926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1135926deccbSFrançois Tigeot 	struct drm_display_mode *tv_mode;
1136926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1137926deccbSFrançois Tigeot 
1138926deccbSFrançois Tigeot 	encoder = radeon_best_single_encoder(connector);
1139926deccbSFrançois Tigeot 	if (!encoder)
1140926deccbSFrançois Tigeot 		return 0;
1141926deccbSFrançois Tigeot 
1142926deccbSFrançois Tigeot 	/* avivo chips can scale any mode */
1143926deccbSFrançois Tigeot 	if (rdev->family >= CHIP_RS600)
1144926deccbSFrançois Tigeot 		/* add scaled modes */
1145926deccbSFrançois Tigeot 		radeon_add_common_modes(encoder, connector);
1146926deccbSFrançois Tigeot 	else {
1147926deccbSFrançois Tigeot 		/* only 800x600 is supported right now on pre-avivo chips */
1148926deccbSFrançois Tigeot 		tv_mode = drm_cvt_mode(dev, 800, 600, 60, false, false, false);
1149926deccbSFrançois Tigeot 		tv_mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
1150926deccbSFrançois Tigeot 		drm_mode_probed_add(connector, tv_mode);
1151926deccbSFrançois Tigeot 	}
1152926deccbSFrançois Tigeot 	return 1;
1153926deccbSFrançois Tigeot }
1154926deccbSFrançois Tigeot 
1155c59a5c48SFrançois Tigeot static enum drm_mode_status radeon_tv_mode_valid(struct drm_connector *connector,
1156926deccbSFrançois Tigeot 				struct drm_display_mode *mode)
1157926deccbSFrançois Tigeot {
1158926deccbSFrançois Tigeot 	if ((mode->hdisplay > 1024) || (mode->vdisplay > 768))
1159926deccbSFrançois Tigeot 		return MODE_CLOCK_RANGE;
1160926deccbSFrançois Tigeot 	return MODE_OK;
1161926deccbSFrançois Tigeot }
1162926deccbSFrançois Tigeot 
1163926deccbSFrançois Tigeot static enum drm_connector_status
1164926deccbSFrançois Tigeot radeon_tv_detect(struct drm_connector *connector, bool force)
1165926deccbSFrançois Tigeot {
1166926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1167c0e85e96SFrançois Tigeot 	const struct drm_encoder_helper_funcs *encoder_funcs;
1168926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1169926deccbSFrançois Tigeot 	enum drm_connector_status ret = connector_status_disconnected;
1170c6f73aabSFrançois Tigeot #ifdef PM_TODO
1171c6f73aabSFrançois Tigeot 	int r;
1172c6f73aabSFrançois Tigeot #endif
1173926deccbSFrançois Tigeot 
1174926deccbSFrançois Tigeot 	if (!radeon_connector->dac_load_detect)
1175926deccbSFrançois Tigeot 		return ret;
1176926deccbSFrançois Tigeot 
1177c6f73aabSFrançois Tigeot #ifdef PM_TODO
1178c6f73aabSFrançois Tigeot 	r = pm_runtime_get_sync(connector->dev->dev);
1179c6f73aabSFrançois Tigeot 	if (r < 0)
1180c6f73aabSFrançois Tigeot 		return connector_status_disconnected;
1181c6f73aabSFrançois Tigeot #endif
1182c6f73aabSFrançois Tigeot 
1183926deccbSFrançois Tigeot 	encoder = radeon_best_single_encoder(connector);
1184926deccbSFrançois Tigeot 	if (!encoder)
1185926deccbSFrançois Tigeot 		ret = connector_status_disconnected;
1186926deccbSFrançois Tigeot 	else {
1187926deccbSFrançois Tigeot 		encoder_funcs = encoder->helper_private;
1188926deccbSFrançois Tigeot 		ret = encoder_funcs->detect(encoder, connector);
1189926deccbSFrançois Tigeot 	}
1190926deccbSFrançois Tigeot 	if (ret == connector_status_connected)
1191926deccbSFrançois Tigeot 		ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false);
1192926deccbSFrançois Tigeot 	radeon_connector_update_scratch_regs(connector, ret);
1193c6f73aabSFrançois Tigeot #ifdef PM_TODO
1194c6f73aabSFrançois Tigeot 	pm_runtime_mark_last_busy(connector->dev->dev);
1195c6f73aabSFrançois Tigeot 	pm_runtime_put_autosuspend(connector->dev->dev);
1196c6f73aabSFrançois Tigeot #endif
1197926deccbSFrançois Tigeot 	return ret;
1198926deccbSFrançois Tigeot }
1199926deccbSFrançois Tigeot 
1200926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_tv_connector_helper_funcs = {
1201926deccbSFrançois Tigeot 	.get_modes = radeon_tv_get_modes,
1202926deccbSFrançois Tigeot 	.mode_valid = radeon_tv_mode_valid,
1203926deccbSFrançois Tigeot 	.best_encoder = radeon_best_single_encoder,
1204926deccbSFrançois Tigeot };
1205926deccbSFrançois Tigeot 
1206926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_tv_connector_funcs = {
1207926deccbSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
1208926deccbSFrançois Tigeot 	.detect = radeon_tv_detect,
1209926deccbSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
1210*1dedbd3bSFrançois Tigeot 	.early_unregister = radeon_connector_unregister,
1211926deccbSFrançois Tigeot 	.destroy = radeon_connector_destroy,
1212926deccbSFrançois Tigeot 	.set_property = radeon_connector_set_property,
1213926deccbSFrançois Tigeot };
1214926deccbSFrançois Tigeot 
1215926deccbSFrançois Tigeot static bool radeon_check_hpd_status_unchanged(struct drm_connector *connector)
1216926deccbSFrançois Tigeot {
1217926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1218926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1219926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1220926deccbSFrançois Tigeot 	enum drm_connector_status status;
1221926deccbSFrançois Tigeot 
1222926deccbSFrançois Tigeot 	/* We only trust HPD on R600 and newer ASICS. */
1223926deccbSFrançois Tigeot 	if (rdev->family >= CHIP_R600
1224926deccbSFrançois Tigeot 	  && radeon_connector->hpd.hpd != RADEON_HPD_NONE) {
1225926deccbSFrançois Tigeot 		if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
1226926deccbSFrançois Tigeot 			status = connector_status_connected;
1227926deccbSFrançois Tigeot 		else
1228926deccbSFrançois Tigeot 			status = connector_status_disconnected;
1229926deccbSFrançois Tigeot 		if (connector->status == status)
1230926deccbSFrançois Tigeot 			return true;
1231926deccbSFrançois Tigeot 	}
1232926deccbSFrançois Tigeot 
1233926deccbSFrançois Tigeot 	return false;
1234926deccbSFrançois Tigeot }
1235926deccbSFrançois Tigeot 
1236926deccbSFrançois Tigeot /*
1237926deccbSFrançois Tigeot  * DVI is complicated
1238926deccbSFrançois Tigeot  * Do a DDC probe, if DDC probe passes, get the full EDID so
1239926deccbSFrançois Tigeot  * we can do analog/digital monitor detection at this point.
1240926deccbSFrançois Tigeot  * If the monitor is an analog monitor or we got no DDC,
1241926deccbSFrançois Tigeot  * we need to find the DAC encoder object for this connector.
1242926deccbSFrançois Tigeot  * If we got no DDC, we do load detection on the DAC encoder object.
1243926deccbSFrançois Tigeot  * If we got analog DDC or load detection passes on the DAC encoder
1244926deccbSFrançois Tigeot  * we have to check if this analog encoder is shared with anyone else (TV)
1245926deccbSFrançois Tigeot  * if its shared we have to set the other connector to disconnected.
1246926deccbSFrançois Tigeot  */
1247926deccbSFrançois Tigeot static enum drm_connector_status
1248926deccbSFrançois Tigeot radeon_dvi_detect(struct drm_connector *connector, bool force)
1249926deccbSFrançois Tigeot {
1250926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1251926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1252926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1253926deccbSFrançois Tigeot 	struct drm_encoder *encoder = NULL;
1254c0e85e96SFrançois Tigeot 	const struct drm_encoder_helper_funcs *encoder_funcs;
1255926deccbSFrançois Tigeot 	int i;
1256926deccbSFrançois Tigeot 	enum drm_connector_status ret = connector_status_disconnected;
1257926deccbSFrançois Tigeot 	bool dret = false, broken_edid = false;
1258926deccbSFrançois Tigeot 
1259c6f73aabSFrançois Tigeot #ifdef PM_TODO
1260c6f73aabSFrançois Tigeot 	r = pm_runtime_get_sync(connector->dev->dev);
1261c6f73aabSFrançois Tigeot 	if (r < 0)
1262c6f73aabSFrançois Tigeot 		return connector_status_disconnected;
1263c6f73aabSFrançois Tigeot #endif
1264c6f73aabSFrançois Tigeot 
1265c59a5c48SFrançois Tigeot 	if (radeon_connector->detected_hpd_without_ddc) {
1266c59a5c48SFrançois Tigeot 		force = true;
1267c59a5c48SFrançois Tigeot 		radeon_connector->detected_hpd_without_ddc = false;
1268c59a5c48SFrançois Tigeot 	}
1269c59a5c48SFrançois Tigeot 
1270c6f73aabSFrançois Tigeot 	if (!force && radeon_check_hpd_status_unchanged(connector)) {
1271c6f73aabSFrançois Tigeot 		ret = connector->status;
1272c6f73aabSFrançois Tigeot 		goto exit;
1273c6f73aabSFrançois Tigeot 	}
1274926deccbSFrançois Tigeot 
1275c59a5c48SFrançois Tigeot 	if (radeon_connector->ddc_bus) {
1276926deccbSFrançois Tigeot 		dret = radeon_ddc_probe(radeon_connector, false);
1277c59a5c48SFrançois Tigeot 
1278c59a5c48SFrançois Tigeot 		/* Sometimes the pins required for the DDC probe on DVI
1279c59a5c48SFrançois Tigeot 		 * connectors don't make contact at the same time that the ones
1280c59a5c48SFrançois Tigeot 		 * for HPD do. If the DDC probe fails even though we had an HPD
1281c59a5c48SFrançois Tigeot 		 * signal, try again later */
1282c59a5c48SFrançois Tigeot 		if (!dret && !force &&
1283c59a5c48SFrançois Tigeot 		    connector->status != connector_status_connected) {
1284c59a5c48SFrançois Tigeot 			DRM_DEBUG_KMS("hpd detected without ddc, retrying in 1 second\n");
1285c59a5c48SFrançois Tigeot 			radeon_connector->detected_hpd_without_ddc = true;
1286c59a5c48SFrançois Tigeot 			schedule_delayed_work(&rdev->hotplug_work,
1287c59a5c48SFrançois Tigeot 					      msecs_to_jiffies(1000));
1288c59a5c48SFrançois Tigeot 			goto exit;
1289c59a5c48SFrançois Tigeot 		}
1290c59a5c48SFrançois Tigeot 	}
1291926deccbSFrançois Tigeot 	if (dret) {
1292926deccbSFrançois Tigeot 		radeon_connector->detected_by_load = false;
12935ef6d7b4SFrançois Tigeot 		radeon_connector_free_edid(connector);
12945ef6d7b4SFrançois Tigeot 		radeon_connector_get_edid(connector);
1295926deccbSFrançois Tigeot 
1296926deccbSFrançois Tigeot 		if (!radeon_connector->edid) {
1297926deccbSFrançois Tigeot 			DRM_ERROR("%s: probed a monitor but no|invalid EDID\n",
1298ba55f2f5SFrançois Tigeot 					connector->name);
1299926deccbSFrançois Tigeot 			/* rs690 seems to have a problem with connectors not existing and always
1300926deccbSFrançois Tigeot 			 * return a block of 0's. If we see this just stop polling on this output */
13017191d616Szrj 			if ((rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) &&
13027191d616Szrj 			    radeon_connector->base.null_edid_counter) {
1303926deccbSFrançois Tigeot 				ret = connector_status_disconnected;
1304ba55f2f5SFrançois Tigeot 				DRM_ERROR("%s: detected RS690 floating bus bug, stopping ddc detect\n",
1305ba55f2f5SFrançois Tigeot 					  connector->name);
1306926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = NULL;
1307926deccbSFrançois Tigeot 			} else {
1308926deccbSFrançois Tigeot 				ret = connector_status_connected;
1309926deccbSFrançois Tigeot 				broken_edid = true; /* defer use_digital to later */
1310926deccbSFrançois Tigeot 			}
1311926deccbSFrançois Tigeot 		} else {
13127191d616Szrj 			radeon_connector->use_digital =
13137191d616Szrj 				!!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
1314926deccbSFrançois Tigeot 
1315926deccbSFrançois Tigeot 			/* some oems have boards with separate digital and analog connectors
1316926deccbSFrançois Tigeot 			 * with a shared ddc line (often vga + hdmi)
1317926deccbSFrançois Tigeot 			 */
1318926deccbSFrançois Tigeot 			if ((!radeon_connector->use_digital) && radeon_connector->shared_ddc) {
13195ef6d7b4SFrançois Tigeot 				radeon_connector_free_edid(connector);
1320926deccbSFrançois Tigeot 				ret = connector_status_disconnected;
13217191d616Szrj 			} else {
1322926deccbSFrançois Tigeot 				ret = connector_status_connected;
13237191d616Szrj 			}
1324926deccbSFrançois Tigeot 			/* This gets complicated.  We have boards with VGA + HDMI with a
1325926deccbSFrançois Tigeot 			 * shared DDC line and we have boards with DVI-D + HDMI with a shared
1326926deccbSFrançois Tigeot 			 * DDC line.  The latter is more complex because with DVI<->HDMI adapters
1327926deccbSFrançois Tigeot 			 * you don't really know what's connected to which port as both are digital.
1328926deccbSFrançois Tigeot 			 */
1329926deccbSFrançois Tigeot 			if (radeon_connector->shared_ddc && (ret == connector_status_connected)) {
1330926deccbSFrançois Tigeot 				struct drm_connector *list_connector;
1331926deccbSFrançois Tigeot 				struct radeon_connector *list_radeon_connector;
1332926deccbSFrançois Tigeot 				list_for_each_entry(list_connector, &dev->mode_config.connector_list, head) {
1333926deccbSFrançois Tigeot 					if (connector == list_connector)
1334926deccbSFrançois Tigeot 						continue;
1335926deccbSFrançois Tigeot 					list_radeon_connector = to_radeon_connector(list_connector);
1336926deccbSFrançois Tigeot 					if (list_radeon_connector->shared_ddc &&
1337926deccbSFrançois Tigeot 					    (list_radeon_connector->ddc_bus->rec.i2c_id ==
1338926deccbSFrançois Tigeot 					     radeon_connector->ddc_bus->rec.i2c_id)) {
1339926deccbSFrançois Tigeot 						/* cases where both connectors are digital */
1340926deccbSFrançois Tigeot 						if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) {
1341926deccbSFrançois Tigeot 							/* hpd is our only option in this case */
1342926deccbSFrançois Tigeot 							if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
13435ef6d7b4SFrançois Tigeot 								radeon_connector_free_edid(connector);
1344926deccbSFrançois Tigeot 								ret = connector_status_disconnected;
1345926deccbSFrançois Tigeot 							}
1346926deccbSFrançois Tigeot 						}
1347926deccbSFrançois Tigeot 					}
1348926deccbSFrançois Tigeot 				}
1349926deccbSFrançois Tigeot 			}
1350926deccbSFrançois Tigeot 		}
1351926deccbSFrançois Tigeot 	}
1352926deccbSFrançois Tigeot 
1353926deccbSFrançois Tigeot 	if ((ret == connector_status_connected) && (radeon_connector->use_digital == true))
1354926deccbSFrançois Tigeot 		goto out;
1355926deccbSFrançois Tigeot 
1356926deccbSFrançois Tigeot 	/* DVI-D and HDMI-A are digital only */
1357926deccbSFrançois Tigeot 	if ((connector->connector_type == DRM_MODE_CONNECTOR_DVID) ||
1358926deccbSFrançois Tigeot 	    (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA))
1359926deccbSFrançois Tigeot 		goto out;
1360926deccbSFrançois Tigeot 
1361926deccbSFrançois Tigeot 	/* if we aren't forcing don't do destructive polling */
1362926deccbSFrançois Tigeot 	if (!force) {
1363926deccbSFrançois Tigeot 		/* only return the previous status if we last
1364926deccbSFrançois Tigeot 		 * detected a monitor via load.
1365926deccbSFrançois Tigeot 		 */
1366926deccbSFrançois Tigeot 		if (radeon_connector->detected_by_load)
1367926deccbSFrançois Tigeot 			ret = connector->status;
1368926deccbSFrançois Tigeot 		goto out;
1369926deccbSFrançois Tigeot 	}
1370926deccbSFrançois Tigeot 
1371926deccbSFrançois Tigeot 	/* find analog encoder */
1372926deccbSFrançois Tigeot 	if (radeon_connector->dac_load_detect) {
1373926deccbSFrançois Tigeot 		for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1374926deccbSFrançois Tigeot 			if (connector->encoder_ids[i] == 0)
1375926deccbSFrançois Tigeot 				break;
1376926deccbSFrançois Tigeot 
1377c6f73aabSFrançois Tigeot 			encoder = drm_encoder_find(connector->dev,
1378c6f73aabSFrançois Tigeot 						   connector->encoder_ids[i]);
1379c6f73aabSFrançois Tigeot 			if (!encoder)
1380926deccbSFrançois Tigeot 				continue;
1381926deccbSFrançois Tigeot 
1382926deccbSFrançois Tigeot 			if (encoder->encoder_type != DRM_MODE_ENCODER_DAC &&
1383926deccbSFrançois Tigeot 			    encoder->encoder_type != DRM_MODE_ENCODER_TVDAC)
1384926deccbSFrançois Tigeot 				continue;
1385926deccbSFrançois Tigeot 
1386926deccbSFrançois Tigeot 			encoder_funcs = encoder->helper_private;
1387926deccbSFrançois Tigeot 			if (encoder_funcs->detect) {
1388926deccbSFrançois Tigeot 				if (!broken_edid) {
1389926deccbSFrançois Tigeot 					if (ret != connector_status_connected) {
1390926deccbSFrançois Tigeot 						/* deal with analog monitors without DDC */
1391926deccbSFrançois Tigeot 						ret = encoder_funcs->detect(encoder, connector);
1392926deccbSFrançois Tigeot 						if (ret == connector_status_connected) {
1393926deccbSFrançois Tigeot 							radeon_connector->use_digital = false;
1394926deccbSFrançois Tigeot 						}
1395926deccbSFrançois Tigeot 						if (ret != connector_status_disconnected)
1396926deccbSFrançois Tigeot 							radeon_connector->detected_by_load = true;
1397926deccbSFrançois Tigeot 					}
1398926deccbSFrançois Tigeot 				} else {
1399926deccbSFrançois Tigeot 					enum drm_connector_status lret;
1400926deccbSFrançois Tigeot 					/* assume digital unless load detected otherwise */
1401926deccbSFrançois Tigeot 					radeon_connector->use_digital = true;
1402926deccbSFrançois Tigeot 					lret = encoder_funcs->detect(encoder, connector);
1403926deccbSFrançois Tigeot 					DRM_DEBUG_KMS("load_detect %x returned: %x\n",encoder->encoder_type,lret);
1404926deccbSFrançois Tigeot 					if (lret == connector_status_connected)
1405926deccbSFrançois Tigeot 						radeon_connector->use_digital = false;
1406926deccbSFrançois Tigeot 				}
1407926deccbSFrançois Tigeot 				break;
1408926deccbSFrançois Tigeot 			}
1409926deccbSFrançois Tigeot 		}
1410926deccbSFrançois Tigeot 	}
1411926deccbSFrançois Tigeot 
1412926deccbSFrançois Tigeot 	if ((ret == connector_status_connected) && (radeon_connector->use_digital == false) &&
1413926deccbSFrançois Tigeot 	    encoder) {
1414926deccbSFrançois Tigeot 		ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true);
1415926deccbSFrançois Tigeot 	}
1416926deccbSFrançois Tigeot 
1417926deccbSFrançois Tigeot 	/* RN50 and some RV100 asics in servers often have a hardcoded EDID in the
1418926deccbSFrançois Tigeot 	 * vbios to deal with KVMs. If we have one and are not able to detect a monitor
1419926deccbSFrançois Tigeot 	 * by other means, assume the DFP is connected and use that EDID.  In most
1420926deccbSFrançois Tigeot 	 * cases the DVI port is actually a virtual KVM port connected to the service
1421926deccbSFrançois Tigeot 	 * processor.
1422926deccbSFrançois Tigeot 	 */
1423926deccbSFrançois Tigeot out:
1424926deccbSFrançois Tigeot 	if ((!rdev->is_atom_bios) &&
1425926deccbSFrançois Tigeot 	    (ret == connector_status_disconnected) &&
1426926deccbSFrançois Tigeot 	    rdev->mode_info.bios_hardcoded_edid_size) {
1427926deccbSFrançois Tigeot 		radeon_connector->use_digital = true;
1428926deccbSFrançois Tigeot 		ret = connector_status_connected;
1429926deccbSFrançois Tigeot 	}
1430926deccbSFrançois Tigeot 
1431926deccbSFrançois Tigeot 	/* updated in get modes as well since we need to know if it's analog or digital */
1432926deccbSFrançois Tigeot 	radeon_connector_update_scratch_regs(connector, ret);
1433c6f73aabSFrançois Tigeot 
1434c59a5c48SFrançois Tigeot 	if ((radeon_audio != 0) && radeon_connector->use_digital) {
1435c59a5c48SFrançois Tigeot 		const struct drm_connector_helper_funcs *connector_funcs =
1436c59a5c48SFrançois Tigeot 			connector->helper_private;
1437c59a5c48SFrançois Tigeot 
1438c59a5c48SFrançois Tigeot 		encoder = connector_funcs->best_encoder(connector);
1439c59a5c48SFrançois Tigeot 		if (encoder && (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)) {
1440c59a5c48SFrançois Tigeot 			radeon_connector_get_edid(connector);
1441c59a5c48SFrançois Tigeot 			radeon_audio_detect(connector, encoder, ret);
1442c59a5c48SFrançois Tigeot 		}
1443c59a5c48SFrançois Tigeot 	}
1444c59a5c48SFrançois Tigeot 
1445c6f73aabSFrançois Tigeot exit:
1446c6f73aabSFrançois Tigeot #ifdef PM_TODO
1447c6f73aabSFrançois Tigeot 	pm_runtime_mark_last_busy(connector->dev->dev);
1448c6f73aabSFrançois Tigeot 	pm_runtime_put_autosuspend(connector->dev->dev);
1449c6f73aabSFrançois Tigeot #endif
1450c6f73aabSFrançois Tigeot 
1451926deccbSFrançois Tigeot 	return ret;
1452926deccbSFrançois Tigeot }
1453926deccbSFrançois Tigeot 
1454926deccbSFrançois Tigeot /* okay need to be smart in here about which encoder to pick */
1455926deccbSFrançois Tigeot static struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector)
1456926deccbSFrançois Tigeot {
1457926deccbSFrançois Tigeot 	int enc_id = connector->encoder_ids[0];
1458926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1459926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1460926deccbSFrançois Tigeot 	int i;
1461926deccbSFrançois Tigeot 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1462926deccbSFrançois Tigeot 		if (connector->encoder_ids[i] == 0)
1463926deccbSFrançois Tigeot 			break;
1464926deccbSFrançois Tigeot 
1465c6f73aabSFrançois Tigeot 		encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
1466c6f73aabSFrançois Tigeot 		if (!encoder)
1467926deccbSFrançois Tigeot 			continue;
1468926deccbSFrançois Tigeot 
1469926deccbSFrançois Tigeot 		if (radeon_connector->use_digital == true) {
1470926deccbSFrançois Tigeot 			if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
1471926deccbSFrançois Tigeot 				return encoder;
1472926deccbSFrançois Tigeot 		} else {
1473926deccbSFrançois Tigeot 			if (encoder->encoder_type == DRM_MODE_ENCODER_DAC ||
1474926deccbSFrançois Tigeot 			    encoder->encoder_type == DRM_MODE_ENCODER_TVDAC)
1475926deccbSFrançois Tigeot 				return encoder;
1476926deccbSFrançois Tigeot 		}
1477926deccbSFrançois Tigeot 	}
1478926deccbSFrançois Tigeot 
1479926deccbSFrançois Tigeot 	/* see if we have a default encoder  TODO */
1480926deccbSFrançois Tigeot 
1481926deccbSFrançois Tigeot 	/* then check use digitial */
1482926deccbSFrançois Tigeot 	/* pick the first one */
1483c6f73aabSFrançois Tigeot 	if (enc_id)
1484c6f73aabSFrançois Tigeot 		return drm_encoder_find(connector->dev, enc_id);
1485926deccbSFrançois Tigeot 	return NULL;
1486926deccbSFrançois Tigeot }
1487926deccbSFrançois Tigeot 
1488926deccbSFrançois Tigeot static void radeon_dvi_force(struct drm_connector *connector)
1489926deccbSFrançois Tigeot {
1490926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1491926deccbSFrançois Tigeot 	if (connector->force == DRM_FORCE_ON)
1492926deccbSFrançois Tigeot 		radeon_connector->use_digital = false;
1493926deccbSFrançois Tigeot 	if (connector->force == DRM_FORCE_ON_DIGITAL)
1494926deccbSFrançois Tigeot 		radeon_connector->use_digital = true;
1495926deccbSFrançois Tigeot }
1496926deccbSFrançois Tigeot 
1497c59a5c48SFrançois Tigeot static enum drm_mode_status radeon_dvi_mode_valid(struct drm_connector *connector,
1498926deccbSFrançois Tigeot 				  struct drm_display_mode *mode)
1499926deccbSFrançois Tigeot {
1500926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1501926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1502926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1503926deccbSFrançois Tigeot 
1504926deccbSFrançois Tigeot 	/* XXX check mode bandwidth */
1505926deccbSFrançois Tigeot 
1506926deccbSFrançois Tigeot 	/* clocks over 135 MHz have heat issues with DVI on RV100 */
1507926deccbSFrançois Tigeot 	if (radeon_connector->use_digital &&
1508926deccbSFrançois Tigeot 	    (rdev->family == CHIP_RV100) &&
1509926deccbSFrançois Tigeot 	    (mode->clock > 135000))
1510926deccbSFrançois Tigeot 		return MODE_CLOCK_HIGH;
1511926deccbSFrançois Tigeot 
1512926deccbSFrançois Tigeot 	if (radeon_connector->use_digital && (mode->clock > 165000)) {
1513926deccbSFrançois Tigeot 		if ((radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I) ||
1514926deccbSFrançois Tigeot 		    (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D) ||
1515926deccbSFrançois Tigeot 		    (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_B))
1516926deccbSFrançois Tigeot 			return MODE_OK;
1517c6f73aabSFrançois Tigeot 		else if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
1518926deccbSFrançois Tigeot 			/* HDMI 1.3+ supports max clock of 340 Mhz */
1519926deccbSFrançois Tigeot 			if (mode->clock > 340000)
1520926deccbSFrançois Tigeot 				return MODE_CLOCK_HIGH;
1521926deccbSFrançois Tigeot 			else
1522926deccbSFrançois Tigeot 				return MODE_OK;
1523c6f73aabSFrançois Tigeot 		} else {
1524926deccbSFrançois Tigeot 			return MODE_CLOCK_HIGH;
1525c6f73aabSFrançois Tigeot 		}
1526926deccbSFrançois Tigeot 	}
1527926deccbSFrançois Tigeot 
1528926deccbSFrançois Tigeot 	/* check against the max pixel clock */
1529926deccbSFrançois Tigeot 	if ((mode->clock / 10) > rdev->clock.max_pixel_clock)
1530926deccbSFrançois Tigeot 		return MODE_CLOCK_HIGH;
1531926deccbSFrançois Tigeot 
1532926deccbSFrançois Tigeot 	return MODE_OK;
1533926deccbSFrançois Tigeot }
1534926deccbSFrançois Tigeot 
1535926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = {
1536c6f73aabSFrançois Tigeot 	.get_modes = radeon_vga_get_modes,
1537926deccbSFrançois Tigeot 	.mode_valid = radeon_dvi_mode_valid,
1538926deccbSFrançois Tigeot 	.best_encoder = radeon_dvi_encoder,
1539926deccbSFrançois Tigeot };
1540926deccbSFrançois Tigeot 
1541926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_dvi_connector_funcs = {
1542926deccbSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
1543926deccbSFrançois Tigeot 	.detect = radeon_dvi_detect,
1544926deccbSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
1545926deccbSFrançois Tigeot 	.set_property = radeon_connector_set_property,
1546*1dedbd3bSFrançois Tigeot 	.early_unregister = radeon_connector_unregister,
1547926deccbSFrançois Tigeot 	.destroy = radeon_connector_destroy,
1548926deccbSFrançois Tigeot 	.force = radeon_dvi_force,
1549926deccbSFrançois Tigeot };
1550926deccbSFrançois Tigeot 
1551926deccbSFrançois Tigeot static int radeon_dp_get_modes(struct drm_connector *connector)
1552926deccbSFrançois Tigeot {
1553926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1554926deccbSFrançois Tigeot 	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
1555926deccbSFrançois Tigeot 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
1556926deccbSFrançois Tigeot 	int ret;
1557926deccbSFrançois Tigeot 
1558926deccbSFrançois Tigeot 	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
1559926deccbSFrançois Tigeot 	    (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
1560926deccbSFrançois Tigeot 		struct drm_display_mode *mode;
1561926deccbSFrançois Tigeot 
1562926deccbSFrançois Tigeot 		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
1563926deccbSFrançois Tigeot 			if (!radeon_dig_connector->edp_on)
1564926deccbSFrançois Tigeot 				atombios_set_edp_panel_power(connector,
1565926deccbSFrançois Tigeot 							     ATOM_TRANSMITTER_ACTION_POWER_ON);
15665ef6d7b4SFrançois Tigeot 			radeon_connector_get_edid(connector);
15675ef6d7b4SFrançois Tigeot 			ret = radeon_ddc_get_modes(connector);
1568926deccbSFrançois Tigeot 			if (!radeon_dig_connector->edp_on)
1569926deccbSFrançois Tigeot 				atombios_set_edp_panel_power(connector,
1570926deccbSFrançois Tigeot 							     ATOM_TRANSMITTER_ACTION_POWER_OFF);
1571926deccbSFrançois Tigeot 		} else {
1572926deccbSFrançois Tigeot 			/* need to setup ddc on the bridge */
1573926deccbSFrançois Tigeot 			if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
1574926deccbSFrançois Tigeot 			    ENCODER_OBJECT_ID_NONE) {
1575926deccbSFrançois Tigeot 				if (encoder)
1576926deccbSFrançois Tigeot 					radeon_atom_ext_encoder_setup_ddc(encoder);
1577926deccbSFrançois Tigeot 			}
15785ef6d7b4SFrançois Tigeot 			radeon_connector_get_edid(connector);
15795ef6d7b4SFrançois Tigeot 			ret = radeon_ddc_get_modes(connector);
1580926deccbSFrançois Tigeot 		}
1581926deccbSFrançois Tigeot 
1582926deccbSFrançois Tigeot 		if (ret > 0) {
1583926deccbSFrançois Tigeot 			if (encoder) {
1584926deccbSFrançois Tigeot 				radeon_fixup_lvds_native_mode(encoder, connector);
1585926deccbSFrançois Tigeot 				/* add scaled modes */
1586926deccbSFrançois Tigeot 				radeon_add_common_modes(encoder, connector);
1587926deccbSFrançois Tigeot 			}
1588926deccbSFrançois Tigeot 			return ret;
1589926deccbSFrançois Tigeot 		}
1590926deccbSFrançois Tigeot 
1591926deccbSFrançois Tigeot 		if (!encoder)
1592926deccbSFrançois Tigeot 			return 0;
1593926deccbSFrançois Tigeot 
1594926deccbSFrançois Tigeot 		/* we have no EDID modes */
1595926deccbSFrançois Tigeot 		mode = radeon_fp_native_mode(encoder);
1596926deccbSFrançois Tigeot 		if (mode) {
1597926deccbSFrançois Tigeot 			ret = 1;
1598926deccbSFrançois Tigeot 			drm_mode_probed_add(connector, mode);
1599926deccbSFrançois Tigeot 			/* add the width/height from vbios tables if available */
1600926deccbSFrançois Tigeot 			connector->display_info.width_mm = mode->width_mm;
1601926deccbSFrançois Tigeot 			connector->display_info.height_mm = mode->height_mm;
1602926deccbSFrançois Tigeot 			/* add scaled modes */
1603926deccbSFrançois Tigeot 			radeon_add_common_modes(encoder, connector);
1604926deccbSFrançois Tigeot 		}
1605926deccbSFrançois Tigeot 	} else {
1606926deccbSFrançois Tigeot 		/* need to setup ddc on the bridge */
1607926deccbSFrançois Tigeot 		if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
1608926deccbSFrançois Tigeot 			ENCODER_OBJECT_ID_NONE) {
1609926deccbSFrançois Tigeot 			if (encoder)
1610926deccbSFrançois Tigeot 				radeon_atom_ext_encoder_setup_ddc(encoder);
1611926deccbSFrançois Tigeot 		}
16125ef6d7b4SFrançois Tigeot 		radeon_connector_get_edid(connector);
16135ef6d7b4SFrançois Tigeot 		ret = radeon_ddc_get_modes(connector);
1614c6f73aabSFrançois Tigeot 
1615c6f73aabSFrançois Tigeot 		radeon_get_native_mode(connector);
1616926deccbSFrançois Tigeot 	}
1617926deccbSFrançois Tigeot 
1618926deccbSFrançois Tigeot 	return ret;
1619926deccbSFrançois Tigeot }
1620926deccbSFrançois Tigeot 
1621926deccbSFrançois Tigeot u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector)
1622926deccbSFrançois Tigeot {
1623926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1624926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
1625926deccbSFrançois Tigeot 	int i;
1626926deccbSFrançois Tigeot 
1627926deccbSFrançois Tigeot 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1628926deccbSFrançois Tigeot 		if (connector->encoder_ids[i] == 0)
1629926deccbSFrançois Tigeot 			break;
1630926deccbSFrançois Tigeot 
1631c6f73aabSFrançois Tigeot 		encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
1632c6f73aabSFrançois Tigeot 		if (!encoder)
1633926deccbSFrançois Tigeot 			continue;
1634926deccbSFrançois Tigeot 
1635926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
1636926deccbSFrançois Tigeot 
1637926deccbSFrançois Tigeot 		switch (radeon_encoder->encoder_id) {
1638926deccbSFrançois Tigeot 		case ENCODER_OBJECT_ID_TRAVIS:
1639926deccbSFrançois Tigeot 		case ENCODER_OBJECT_ID_NUTMEG:
1640926deccbSFrançois Tigeot 			return radeon_encoder->encoder_id;
1641926deccbSFrançois Tigeot 		default:
1642926deccbSFrançois Tigeot 			break;
1643926deccbSFrançois Tigeot 		}
1644926deccbSFrançois Tigeot 	}
1645926deccbSFrançois Tigeot 
1646926deccbSFrançois Tigeot 	return ENCODER_OBJECT_ID_NONE;
1647926deccbSFrançois Tigeot }
1648926deccbSFrançois Tigeot 
1649c6f73aabSFrançois Tigeot static bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector)
1650926deccbSFrançois Tigeot {
1651926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1652926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
1653926deccbSFrançois Tigeot 	int i;
1654926deccbSFrançois Tigeot 	bool found = false;
1655926deccbSFrançois Tigeot 
1656926deccbSFrançois Tigeot 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1657926deccbSFrançois Tigeot 		if (connector->encoder_ids[i] == 0)
1658926deccbSFrançois Tigeot 			break;
1659926deccbSFrançois Tigeot 
1660c6f73aabSFrançois Tigeot 		encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
1661c6f73aabSFrançois Tigeot 		if (!encoder)
1662926deccbSFrançois Tigeot 			continue;
1663926deccbSFrançois Tigeot 
1664926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
1665926deccbSFrançois Tigeot 		if (radeon_encoder->caps & ATOM_ENCODER_CAP_RECORD_HBR2)
1666926deccbSFrançois Tigeot 			found = true;
1667926deccbSFrançois Tigeot 	}
1668926deccbSFrançois Tigeot 
1669926deccbSFrançois Tigeot 	return found;
1670926deccbSFrançois Tigeot }
1671926deccbSFrançois Tigeot 
1672926deccbSFrançois Tigeot bool radeon_connector_is_dp12_capable(struct drm_connector *connector)
1673926deccbSFrançois Tigeot {
1674926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1675926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1676926deccbSFrançois Tigeot 
1677926deccbSFrançois Tigeot 	if (ASIC_IS_DCE5(rdev) &&
1678c6f73aabSFrançois Tigeot 	    (rdev->clock.default_dispclk >= 53900) &&
1679926deccbSFrançois Tigeot 	    radeon_connector_encoder_is_hbr2(connector)) {
1680926deccbSFrançois Tigeot 		return true;
1681926deccbSFrançois Tigeot 	}
1682926deccbSFrançois Tigeot 
1683926deccbSFrançois Tigeot 	return false;
1684926deccbSFrançois Tigeot }
1685926deccbSFrançois Tigeot 
1686926deccbSFrançois Tigeot static enum drm_connector_status
1687926deccbSFrançois Tigeot radeon_dp_detect(struct drm_connector *connector, bool force)
1688926deccbSFrançois Tigeot {
1689926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1690926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1691926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1692926deccbSFrançois Tigeot 	enum drm_connector_status ret = connector_status_disconnected;
1693926deccbSFrançois Tigeot 	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
1694926deccbSFrançois Tigeot 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
1695c6f73aabSFrançois Tigeot 	int r;
1696926deccbSFrançois Tigeot 
1697c59a5c48SFrançois Tigeot 	if (radeon_dig_connector->is_mst)
1698c59a5c48SFrançois Tigeot 		return connector_status_disconnected;
1699c59a5c48SFrançois Tigeot 
1700c59a5c48SFrançois Tigeot #ifdef PM_TODO
1701c6f73aabSFrançois Tigeot 	r = pm_runtime_get_sync(connector->dev->dev);
1702c6f73aabSFrançois Tigeot 	if (r < 0)
1703c6f73aabSFrançois Tigeot 		return connector_status_disconnected;
1704c6f73aabSFrançois Tigeot #endif
1705c6f73aabSFrançois Tigeot 
1706c6f73aabSFrançois Tigeot 	if (!force && radeon_check_hpd_status_unchanged(connector)) {
1707c6f73aabSFrançois Tigeot 		ret = connector->status;
1708c6f73aabSFrançois Tigeot 		goto out;
1709c6f73aabSFrançois Tigeot 	}
1710926deccbSFrançois Tigeot 
17115ef6d7b4SFrançois Tigeot 	radeon_connector_free_edid(connector);
1712926deccbSFrançois Tigeot 
1713926deccbSFrançois Tigeot 	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
1714926deccbSFrançois Tigeot 	    (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
1715926deccbSFrançois Tigeot 		if (encoder) {
1716926deccbSFrançois Tigeot 			struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
1717926deccbSFrançois Tigeot 			struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
1718926deccbSFrançois Tigeot 
1719926deccbSFrançois Tigeot 			/* check if panel is valid */
1720926deccbSFrançois Tigeot 			if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
1721926deccbSFrançois Tigeot 				ret = connector_status_connected;
17221cfef1a5SFrançois Tigeot 			/* don't fetch the edid from the vbios if ddc fails and runpm is
17231cfef1a5SFrançois Tigeot 			 * enabled so we report disconnected.
17241cfef1a5SFrançois Tigeot 			 */
17251cfef1a5SFrançois Tigeot 			if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0))
17261cfef1a5SFrançois Tigeot 				ret = connector_status_disconnected;
1727926deccbSFrançois Tigeot 		}
1728926deccbSFrançois Tigeot 		/* eDP is always DP */
1729926deccbSFrançois Tigeot 		radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
1730926deccbSFrançois Tigeot 		if (!radeon_dig_connector->edp_on)
1731926deccbSFrançois Tigeot 			atombios_set_edp_panel_power(connector,
1732926deccbSFrançois Tigeot 						     ATOM_TRANSMITTER_ACTION_POWER_ON);
1733926deccbSFrançois Tigeot 		if (radeon_dp_getdpcd(radeon_connector))
1734926deccbSFrançois Tigeot 			ret = connector_status_connected;
1735926deccbSFrançois Tigeot 		if (!radeon_dig_connector->edp_on)
1736926deccbSFrançois Tigeot 			atombios_set_edp_panel_power(connector,
1737926deccbSFrançois Tigeot 						     ATOM_TRANSMITTER_ACTION_POWER_OFF);
1738926deccbSFrançois Tigeot 	} else if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
1739926deccbSFrançois Tigeot 		   ENCODER_OBJECT_ID_NONE) {
1740926deccbSFrançois Tigeot 		/* DP bridges are always DP */
1741926deccbSFrançois Tigeot 		radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
1742926deccbSFrançois Tigeot 		/* get the DPCD from the bridge */
1743926deccbSFrançois Tigeot 		radeon_dp_getdpcd(radeon_connector);
1744926deccbSFrançois Tigeot 
1745926deccbSFrançois Tigeot 		if (encoder) {
1746926deccbSFrançois Tigeot 			/* setup ddc on the bridge */
1747926deccbSFrançois Tigeot 			radeon_atom_ext_encoder_setup_ddc(encoder);
1748926deccbSFrançois Tigeot 			/* bridge chips are always aux */
1749926deccbSFrançois Tigeot 			if (radeon_ddc_probe(radeon_connector, true)) /* try DDC */
1750926deccbSFrançois Tigeot 				ret = connector_status_connected;
1751926deccbSFrançois Tigeot 			else if (radeon_connector->dac_load_detect) { /* try load detection */
1752c0e85e96SFrançois Tigeot 				const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
1753926deccbSFrançois Tigeot 				ret = encoder_funcs->detect(encoder, connector);
1754926deccbSFrançois Tigeot 			}
1755926deccbSFrançois Tigeot 		}
1756926deccbSFrançois Tigeot 	} else {
1757926deccbSFrançois Tigeot 		radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
1758926deccbSFrançois Tigeot 		if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
1759926deccbSFrançois Tigeot 			ret = connector_status_connected;
1760c59a5c48SFrançois Tigeot 			if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
1761926deccbSFrançois Tigeot 				radeon_dp_getdpcd(radeon_connector);
1762c59a5c48SFrançois Tigeot 				r = radeon_dp_mst_probe(radeon_connector);
1763c59a5c48SFrançois Tigeot 				if (r == 1)
1764c59a5c48SFrançois Tigeot 					ret = connector_status_disconnected;
1765c59a5c48SFrançois Tigeot 			}
1766926deccbSFrançois Tigeot 		} else {
1767926deccbSFrançois Tigeot 			if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
1768c59a5c48SFrançois Tigeot 				if (radeon_dp_getdpcd(radeon_connector)) {
1769c59a5c48SFrançois Tigeot 					r = radeon_dp_mst_probe(radeon_connector);
1770c59a5c48SFrançois Tigeot 					if (r == 1)
1771c59a5c48SFrançois Tigeot 						ret = connector_status_disconnected;
1772c59a5c48SFrançois Tigeot 					else
1773926deccbSFrançois Tigeot 						ret = connector_status_connected;
1774c59a5c48SFrançois Tigeot 				}
1775926deccbSFrançois Tigeot 			} else {
17764cd92098Szrj 				/* try non-aux ddc (DP to DVI/HDMI/etc. adapter) */
1777926deccbSFrançois Tigeot 				if (radeon_ddc_probe(radeon_connector, false))
1778926deccbSFrançois Tigeot 					ret = connector_status_connected;
1779926deccbSFrançois Tigeot 			}
1780926deccbSFrançois Tigeot 		}
1781926deccbSFrançois Tigeot 	}
1782926deccbSFrançois Tigeot 
1783926deccbSFrançois Tigeot 	radeon_connector_update_scratch_regs(connector, ret);
1784c59a5c48SFrançois Tigeot 
1785c59a5c48SFrançois Tigeot 	if ((radeon_audio != 0) && encoder) {
1786c59a5c48SFrançois Tigeot 		radeon_connector_get_edid(connector);
1787c59a5c48SFrançois Tigeot 		radeon_audio_detect(connector, encoder, ret);
1788c59a5c48SFrançois Tigeot 	}
1789c59a5c48SFrançois Tigeot 
1790c6f73aabSFrançois Tigeot out:
1791c6f73aabSFrançois Tigeot #ifdef PM_TODO
1792c6f73aabSFrançois Tigeot 	pm_runtime_mark_last_busy(connector->dev->dev);
1793c6f73aabSFrançois Tigeot 	pm_runtime_put_autosuspend(connector->dev->dev);
1794c6f73aabSFrançois Tigeot #endif
1795c6f73aabSFrançois Tigeot 
1796926deccbSFrançois Tigeot 	return ret;
1797926deccbSFrançois Tigeot }
1798926deccbSFrançois Tigeot 
1799c59a5c48SFrançois Tigeot static enum drm_mode_status radeon_dp_mode_valid(struct drm_connector *connector,
1800926deccbSFrançois Tigeot 				  struct drm_display_mode *mode)
1801926deccbSFrançois Tigeot {
1802c6f73aabSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1803c6f73aabSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1804926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1805926deccbSFrançois Tigeot 	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
1806926deccbSFrançois Tigeot 
1807926deccbSFrançois Tigeot 	/* XXX check mode bandwidth */
1808926deccbSFrançois Tigeot 
1809926deccbSFrançois Tigeot 	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
1810926deccbSFrançois Tigeot 	    (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
1811926deccbSFrançois Tigeot 		struct drm_encoder *encoder = radeon_best_single_encoder(connector);
1812926deccbSFrançois Tigeot 
1813926deccbSFrançois Tigeot 		if ((mode->hdisplay < 320) || (mode->vdisplay < 240))
1814926deccbSFrançois Tigeot 			return MODE_PANEL;
1815926deccbSFrançois Tigeot 
1816926deccbSFrançois Tigeot 		if (encoder) {
1817926deccbSFrançois Tigeot 			struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
1818926deccbSFrançois Tigeot 			struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
1819926deccbSFrançois Tigeot 
1820926deccbSFrançois Tigeot 			/* AVIVO hardware supports downscaling modes larger than the panel
1821926deccbSFrançois Tigeot 			 * to the panel size, but I'm not sure this is desirable.
1822926deccbSFrançois Tigeot 			 */
1823926deccbSFrançois Tigeot 			if ((mode->hdisplay > native_mode->hdisplay) ||
1824926deccbSFrançois Tigeot 			    (mode->vdisplay > native_mode->vdisplay))
1825926deccbSFrançois Tigeot 				return MODE_PANEL;
1826926deccbSFrançois Tigeot 
1827926deccbSFrançois Tigeot 			/* if scaling is disabled, block non-native modes */
1828926deccbSFrançois Tigeot 			if (radeon_encoder->rmx_type == RMX_OFF) {
1829926deccbSFrançois Tigeot 				if ((mode->hdisplay != native_mode->hdisplay) ||
1830926deccbSFrançois Tigeot 				    (mode->vdisplay != native_mode->vdisplay))
1831926deccbSFrançois Tigeot 					return MODE_PANEL;
1832926deccbSFrançois Tigeot 			}
1833926deccbSFrançois Tigeot 		}
1834926deccbSFrançois Tigeot 	} else {
1835926deccbSFrançois Tigeot 		if ((radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
1836c6f73aabSFrançois Tigeot 		    (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
1837926deccbSFrançois Tigeot 			return radeon_dp_mode_valid_helper(connector, mode);
1838c6f73aabSFrançois Tigeot 		} else {
1839c6f73aabSFrançois Tigeot 			if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
1840c6f73aabSFrançois Tigeot 				/* HDMI 1.3+ supports max clock of 340 Mhz */
1841c6f73aabSFrançois Tigeot 				if (mode->clock > 340000)
1842c6f73aabSFrançois Tigeot 					return MODE_CLOCK_HIGH;
1843c6f73aabSFrançois Tigeot 			} else {
1844c6f73aabSFrançois Tigeot 				if (mode->clock > 165000)
1845c6f73aabSFrançois Tigeot 					return MODE_CLOCK_HIGH;
1846926deccbSFrançois Tigeot 			}
1847926deccbSFrançois Tigeot 		}
1848c6f73aabSFrançois Tigeot 	}
1849c6f73aabSFrançois Tigeot 
1850c6f73aabSFrançois Tigeot 	return MODE_OK;
1851c6f73aabSFrançois Tigeot }
1852926deccbSFrançois Tigeot 
1853926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_dp_connector_helper_funcs = {
1854926deccbSFrançois Tigeot 	.get_modes = radeon_dp_get_modes,
1855926deccbSFrançois Tigeot 	.mode_valid = radeon_dp_mode_valid,
1856926deccbSFrançois Tigeot 	.best_encoder = radeon_dvi_encoder,
1857926deccbSFrançois Tigeot };
1858926deccbSFrançois Tigeot 
1859926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_dp_connector_funcs = {
1860926deccbSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
1861926deccbSFrançois Tigeot 	.detect = radeon_dp_detect,
1862926deccbSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
1863926deccbSFrançois Tigeot 	.set_property = radeon_connector_set_property,
1864*1dedbd3bSFrançois Tigeot 	.early_unregister = radeon_connector_unregister,
18655ef6d7b4SFrançois Tigeot 	.destroy = radeon_connector_destroy,
1866926deccbSFrançois Tigeot 	.force = radeon_dvi_force,
1867926deccbSFrançois Tigeot };
1868926deccbSFrançois Tigeot 
18694cd92098Szrj static const struct drm_connector_funcs radeon_edp_connector_funcs = {
18704cd92098Szrj 	.dpms = drm_helper_connector_dpms,
18714cd92098Szrj 	.detect = radeon_dp_detect,
18724cd92098Szrj 	.fill_modes = drm_helper_probe_single_connector_modes,
18734cd92098Szrj 	.set_property = radeon_lvds_set_property,
1874*1dedbd3bSFrançois Tigeot 	.early_unregister = radeon_connector_unregister,
18755ef6d7b4SFrançois Tigeot 	.destroy = radeon_connector_destroy,
18764cd92098Szrj 	.force = radeon_dvi_force,
18774cd92098Szrj };
18784cd92098Szrj 
18794cd92098Szrj static const struct drm_connector_funcs radeon_lvds_bridge_connector_funcs = {
18804cd92098Szrj 	.dpms = drm_helper_connector_dpms,
18814cd92098Szrj 	.detect = radeon_dp_detect,
18824cd92098Szrj 	.fill_modes = drm_helper_probe_single_connector_modes,
18834cd92098Szrj 	.set_property = radeon_lvds_set_property,
18845ef6d7b4SFrançois Tigeot 	.destroy = radeon_connector_destroy,
18854cd92098Szrj 	.force = radeon_dvi_force,
18864cd92098Szrj };
18874cd92098Szrj 
1888926deccbSFrançois Tigeot void
1889926deccbSFrançois Tigeot radeon_add_atom_connector(struct drm_device *dev,
1890926deccbSFrançois Tigeot 			  uint32_t connector_id,
1891926deccbSFrançois Tigeot 			  uint32_t supported_device,
1892926deccbSFrançois Tigeot 			  int connector_type,
1893926deccbSFrançois Tigeot 			  struct radeon_i2c_bus_rec *i2c_bus,
1894926deccbSFrançois Tigeot 			  uint32_t igp_lane_info,
1895926deccbSFrançois Tigeot 			  uint16_t connector_object_id,
1896926deccbSFrançois Tigeot 			  struct radeon_hpd *hpd,
1897926deccbSFrançois Tigeot 			  struct radeon_router *router)
1898926deccbSFrançois Tigeot {
1899926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1900926deccbSFrançois Tigeot 	struct drm_connector *connector;
1901926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector;
1902926deccbSFrançois Tigeot 	struct radeon_connector_atom_dig *radeon_dig_connector;
1903926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1904926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
1905926deccbSFrançois Tigeot 	uint32_t subpixel_order = SubPixelNone;
1906926deccbSFrançois Tigeot 	bool shared_ddc = false;
1907926deccbSFrançois Tigeot 	bool is_dp_bridge = false;
19087191d616Szrj 	bool has_aux = false;
1909926deccbSFrançois Tigeot 
1910926deccbSFrançois Tigeot 	if (connector_type == DRM_MODE_CONNECTOR_Unknown)
1911926deccbSFrançois Tigeot 		return;
1912926deccbSFrançois Tigeot 
1913926deccbSFrançois Tigeot 	/* if the user selected tv=0 don't try and add the connector */
1914926deccbSFrançois Tigeot 	if (((connector_type == DRM_MODE_CONNECTOR_SVIDEO) ||
1915926deccbSFrançois Tigeot 	     (connector_type == DRM_MODE_CONNECTOR_Composite) ||
1916926deccbSFrançois Tigeot 	     (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) &&
1917926deccbSFrançois Tigeot 	    (radeon_tv == 0))
1918926deccbSFrançois Tigeot 		return;
1919926deccbSFrançois Tigeot 
1920926deccbSFrançois Tigeot 	/* see if we already added it */
1921926deccbSFrançois Tigeot 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1922926deccbSFrançois Tigeot 		radeon_connector = to_radeon_connector(connector);
1923926deccbSFrançois Tigeot 		if (radeon_connector->connector_id == connector_id) {
1924926deccbSFrançois Tigeot 			radeon_connector->devices |= supported_device;
1925926deccbSFrançois Tigeot 			return;
1926926deccbSFrançois Tigeot 		}
1927926deccbSFrançois Tigeot 		if (radeon_connector->ddc_bus && i2c_bus->valid) {
1928926deccbSFrançois Tigeot 			if (radeon_connector->ddc_bus->rec.i2c_id == i2c_bus->i2c_id) {
1929926deccbSFrançois Tigeot 				radeon_connector->shared_ddc = true;
1930926deccbSFrançois Tigeot 				shared_ddc = true;
1931926deccbSFrançois Tigeot 			}
1932926deccbSFrançois Tigeot 			if (radeon_connector->router_bus && router->ddc_valid &&
1933926deccbSFrançois Tigeot 			    (radeon_connector->router.router_id == router->router_id)) {
1934926deccbSFrançois Tigeot 				radeon_connector->shared_ddc = false;
1935926deccbSFrançois Tigeot 				shared_ddc = false;
1936926deccbSFrançois Tigeot 			}
1937926deccbSFrançois Tigeot 		}
1938926deccbSFrançois Tigeot 	}
1939926deccbSFrançois Tigeot 
1940926deccbSFrançois Tigeot 	/* check if it's a dp bridge */
1941926deccbSFrançois Tigeot 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
1942926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
1943926deccbSFrançois Tigeot 		if (radeon_encoder->devices & supported_device) {
1944926deccbSFrançois Tigeot 			switch (radeon_encoder->encoder_id) {
1945926deccbSFrançois Tigeot 			case ENCODER_OBJECT_ID_TRAVIS:
1946926deccbSFrançois Tigeot 			case ENCODER_OBJECT_ID_NUTMEG:
1947926deccbSFrançois Tigeot 				is_dp_bridge = true;
1948926deccbSFrançois Tigeot 				break;
1949926deccbSFrançois Tigeot 			default:
1950926deccbSFrançois Tigeot 				break;
1951926deccbSFrançois Tigeot 			}
1952926deccbSFrançois Tigeot 		}
1953926deccbSFrançois Tigeot 	}
1954926deccbSFrançois Tigeot 
1955c4ef309bSzrj 	radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL);
1956926deccbSFrançois Tigeot 	if (!radeon_connector)
1957926deccbSFrançois Tigeot 		return;
1958926deccbSFrançois Tigeot 
1959926deccbSFrançois Tigeot 	connector = &radeon_connector->base;
1960926deccbSFrançois Tigeot 
1961926deccbSFrançois Tigeot 	radeon_connector->connector_id = connector_id;
1962926deccbSFrançois Tigeot 	radeon_connector->devices = supported_device;
1963926deccbSFrançois Tigeot 	radeon_connector->shared_ddc = shared_ddc;
1964926deccbSFrançois Tigeot 	radeon_connector->connector_object_id = connector_object_id;
1965926deccbSFrançois Tigeot 	radeon_connector->hpd = *hpd;
1966926deccbSFrançois Tigeot 
1967926deccbSFrançois Tigeot 	radeon_connector->router = *router;
1968926deccbSFrançois Tigeot 	if (router->ddc_valid || router->cd_valid) {
1969926deccbSFrançois Tigeot 		radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info);
1970926deccbSFrançois Tigeot 		if (!radeon_connector->router_bus)
1971926deccbSFrançois Tigeot 			DRM_ERROR("Failed to assign router i2c bus! Check dmesg for i2c errors.\n");
1972926deccbSFrançois Tigeot 	}
1973926deccbSFrançois Tigeot 
1974926deccbSFrançois Tigeot 	if (is_dp_bridge) {
1975c4ef309bSzrj 		radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
1976926deccbSFrançois Tigeot 		if (!radeon_dig_connector)
1977926deccbSFrançois Tigeot 			goto failed;
1978926deccbSFrançois Tigeot 		radeon_dig_connector->igp_lane_info = igp_lane_info;
1979926deccbSFrançois Tigeot 		radeon_connector->con_priv = radeon_dig_connector;
1980926deccbSFrançois Tigeot 		if (i2c_bus->valid) {
19815ef6d7b4SFrançois Tigeot 			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
19825ef6d7b4SFrançois Tigeot 			if (radeon_connector->ddc_bus)
19837191d616Szrj 				has_aux = true;
19847191d616Szrj 			else
1985926deccbSFrançois Tigeot 				DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
1986926deccbSFrançois Tigeot 		}
1987926deccbSFrançois Tigeot 		switch (connector_type) {
1988926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_VGA:
1989926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVIA:
1990926deccbSFrançois Tigeot 		default:
19914cd92098Szrj 			drm_connector_init(dev, &radeon_connector->base,
19924cd92098Szrj 					   &radeon_dp_connector_funcs, connector_type);
19934cd92098Szrj 			drm_connector_helper_add(&radeon_connector->base,
19944cd92098Szrj 						 &radeon_dp_connector_helper_funcs);
1995926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
1996926deccbSFrançois Tigeot 			connector->doublescan_allowed = true;
1997926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
1998b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
1999926deccbSFrançois Tigeot 						      rdev->mode_info.load_detect_property,
2000926deccbSFrançois Tigeot 						      1);
2001c6f73aabSFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2002c6f73aabSFrançois Tigeot 						   dev->mode_config.scaling_mode_property,
2003c6f73aabSFrançois Tigeot 						   DRM_MODE_SCALE_NONE);
2004c59a5c48SFrançois Tigeot 			if (ASIC_IS_DCE5(rdev))
2005c59a5c48SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2006c59a5c48SFrançois Tigeot 							   rdev->mode_info.output_csc_property,
2007c59a5c48SFrançois Tigeot 							   RADEON_OUTPUT_CSC_BYPASS);
2008926deccbSFrançois Tigeot 			break;
2009926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVII:
2010926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVID:
2011926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_HDMIA:
2012926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_HDMIB:
2013926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DisplayPort:
20144cd92098Szrj 			drm_connector_init(dev, &radeon_connector->base,
20154cd92098Szrj 					   &radeon_dp_connector_funcs, connector_type);
20164cd92098Szrj 			drm_connector_helper_add(&radeon_connector->base,
20174cd92098Szrj 						 &radeon_dp_connector_helper_funcs);
2018b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2019926deccbSFrançois Tigeot 						      rdev->mode_info.underscan_property,
2020926deccbSFrançois Tigeot 						      UNDERSCAN_OFF);
2021b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2022926deccbSFrançois Tigeot 						      rdev->mode_info.underscan_hborder_property,
2023926deccbSFrançois Tigeot 						      0);
2024b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2025926deccbSFrançois Tigeot 						      rdev->mode_info.underscan_vborder_property,
2026926deccbSFrançois Tigeot 						      0);
2027c6f73aabSFrançois Tigeot 
2028c6f73aabSFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2029c6f73aabSFrançois Tigeot 						      dev->mode_config.scaling_mode_property,
2030c6f73aabSFrançois Tigeot 						      DRM_MODE_SCALE_NONE);
2031c6f73aabSFrançois Tigeot 
2032c6f73aabSFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2033c6f73aabSFrançois Tigeot 						   rdev->mode_info.dither_property,
2034c6f73aabSFrançois Tigeot 						   RADEON_FMT_DITHER_DISABLE);
2035c6f73aabSFrançois Tigeot 
2036c59a5c48SFrançois Tigeot 			if (radeon_audio != 0) {
20374cd92098Szrj 				drm_object_attach_property(&radeon_connector->base.base,
20384cd92098Szrj 							   rdev->mode_info.audio_property,
2039c6f73aabSFrançois Tigeot 							   RADEON_AUDIO_AUTO);
2040c59a5c48SFrançois Tigeot 				radeon_connector->audio = RADEON_AUDIO_AUTO;
2041c59a5c48SFrançois Tigeot 			}
2042c59a5c48SFrançois Tigeot 			if (ASIC_IS_DCE5(rdev))
2043c59a5c48SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2044c59a5c48SFrançois Tigeot 							   rdev->mode_info.output_csc_property,
2045c59a5c48SFrançois Tigeot 							   RADEON_OUTPUT_CSC_BYPASS);
2046c6f73aabSFrançois Tigeot 
2047926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2048926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2049926deccbSFrançois Tigeot 			if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
2050926deccbSFrançois Tigeot 				connector->doublescan_allowed = true;
2051926deccbSFrançois Tigeot 			else
2052926deccbSFrançois Tigeot 				connector->doublescan_allowed = false;
2053926deccbSFrançois Tigeot 			if (connector_type == DRM_MODE_CONNECTOR_DVII) {
2054926deccbSFrançois Tigeot 				radeon_connector->dac_load_detect = true;
2055b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2056926deccbSFrançois Tigeot 							      rdev->mode_info.load_detect_property,
2057926deccbSFrançois Tigeot 							      1);
2058926deccbSFrançois Tigeot 			}
2059926deccbSFrançois Tigeot 			break;
2060926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_LVDS:
2061926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_eDP:
20624cd92098Szrj 			drm_connector_init(dev, &radeon_connector->base,
20634cd92098Szrj 					   &radeon_lvds_bridge_connector_funcs, connector_type);
20644cd92098Szrj 			drm_connector_helper_add(&radeon_connector->base,
20654cd92098Szrj 						 &radeon_dp_connector_helper_funcs);
2066b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2067926deccbSFrançois Tigeot 						      dev->mode_config.scaling_mode_property,
2068926deccbSFrançois Tigeot 						      DRM_MODE_SCALE_FULLSCREEN);
2069926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2070926deccbSFrançois Tigeot 			connector->interlace_allowed = false;
2071926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2072926deccbSFrançois Tigeot 			break;
2073926deccbSFrançois Tigeot 		}
2074926deccbSFrançois Tigeot 	} else {
2075926deccbSFrançois Tigeot 		switch (connector_type) {
2076926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_VGA:
2077926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
2078926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
2079926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2080926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2081926deccbSFrançois Tigeot 				if (!radeon_connector->ddc_bus)
2082926deccbSFrançois Tigeot 					DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2083926deccbSFrançois Tigeot 			}
2084926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
2085b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2086926deccbSFrançois Tigeot 						      rdev->mode_info.load_detect_property,
2087926deccbSFrançois Tigeot 						      1);
2088c6f73aabSFrançois Tigeot 			if (ASIC_IS_AVIVO(rdev))
2089c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2090c6f73aabSFrançois Tigeot 							   dev->mode_config.scaling_mode_property,
2091c6f73aabSFrançois Tigeot 							   DRM_MODE_SCALE_NONE);
2092c59a5c48SFrançois Tigeot 			if (ASIC_IS_DCE5(rdev))
2093c59a5c48SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2094c59a5c48SFrançois Tigeot 							   rdev->mode_info.output_csc_property,
2095c59a5c48SFrançois Tigeot 							   RADEON_OUTPUT_CSC_BYPASS);
2096926deccbSFrançois Tigeot 			/* no HPD on analog connectors */
2097926deccbSFrançois Tigeot 			radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2098926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2099926deccbSFrançois Tigeot 			connector->doublescan_allowed = true;
2100926deccbSFrançois Tigeot 			break;
2101926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVIA:
2102926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
2103926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
2104926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2105926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2106926deccbSFrançois Tigeot 				if (!radeon_connector->ddc_bus)
2107926deccbSFrançois Tigeot 					DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2108926deccbSFrançois Tigeot 			}
2109926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
2110b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2111926deccbSFrançois Tigeot 						      rdev->mode_info.load_detect_property,
2112926deccbSFrançois Tigeot 						      1);
2113c6f73aabSFrançois Tigeot 			if (ASIC_IS_AVIVO(rdev))
2114c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2115c6f73aabSFrançois Tigeot 							   dev->mode_config.scaling_mode_property,
2116c6f73aabSFrançois Tigeot 							   DRM_MODE_SCALE_NONE);
2117c59a5c48SFrançois Tigeot 			if (ASIC_IS_DCE5(rdev))
2118c59a5c48SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2119c59a5c48SFrançois Tigeot 							   rdev->mode_info.output_csc_property,
2120c59a5c48SFrançois Tigeot 							   RADEON_OUTPUT_CSC_BYPASS);
2121926deccbSFrançois Tigeot 			/* no HPD on analog connectors */
2122926deccbSFrançois Tigeot 			radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2123926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2124926deccbSFrançois Tigeot 			connector->doublescan_allowed = true;
2125926deccbSFrançois Tigeot 			break;
2126926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVII:
2127926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVID:
2128c4ef309bSzrj 			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
2129926deccbSFrançois Tigeot 			if (!radeon_dig_connector)
2130926deccbSFrançois Tigeot 				goto failed;
2131926deccbSFrançois Tigeot 			radeon_dig_connector->igp_lane_info = igp_lane_info;
2132926deccbSFrançois Tigeot 			radeon_connector->con_priv = radeon_dig_connector;
2133926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
2134926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
2135926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2136926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2137926deccbSFrançois Tigeot 				if (!radeon_connector->ddc_bus)
2138926deccbSFrançois Tigeot 					DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2139926deccbSFrançois Tigeot 			}
2140926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2141b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2142926deccbSFrançois Tigeot 						      rdev->mode_info.coherent_mode_property,
2143926deccbSFrançois Tigeot 						      1);
2144926deccbSFrançois Tigeot 			if (ASIC_IS_AVIVO(rdev)) {
2145b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2146926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_property,
2147926deccbSFrançois Tigeot 							      UNDERSCAN_OFF);
2148b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2149926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_hborder_property,
2150926deccbSFrançois Tigeot 							      0);
2151b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2152926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_vborder_property,
2153926deccbSFrançois Tigeot 							      0);
2154c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2155c6f73aabSFrançois Tigeot 							   rdev->mode_info.dither_property,
2156c6f73aabSFrançois Tigeot 							   RADEON_FMT_DITHER_DISABLE);
2157c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2158c6f73aabSFrançois Tigeot 							   dev->mode_config.scaling_mode_property,
2159c6f73aabSFrançois Tigeot 							   DRM_MODE_SCALE_NONE);
2160926deccbSFrançois Tigeot 			}
21614cd92098Szrj 			if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
21624cd92098Szrj 				drm_object_attach_property(&radeon_connector->base.base,
21634cd92098Szrj 							   rdev->mode_info.audio_property,
2164c6f73aabSFrançois Tigeot 							   RADEON_AUDIO_AUTO);
2165c59a5c48SFrançois Tigeot 				radeon_connector->audio = RADEON_AUDIO_AUTO;
21664cd92098Szrj 			}
2167926deccbSFrançois Tigeot 			if (connector_type == DRM_MODE_CONNECTOR_DVII) {
2168926deccbSFrançois Tigeot 				radeon_connector->dac_load_detect = true;
2169b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2170926deccbSFrançois Tigeot 							      rdev->mode_info.load_detect_property,
2171926deccbSFrançois Tigeot 							      1);
2172926deccbSFrançois Tigeot 			}
2173c59a5c48SFrançois Tigeot 			if (ASIC_IS_DCE5(rdev))
2174c59a5c48SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2175c59a5c48SFrançois Tigeot 							   rdev->mode_info.output_csc_property,
2176c59a5c48SFrançois Tigeot 							   RADEON_OUTPUT_CSC_BYPASS);
2177926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2178926deccbSFrançois Tigeot 			if (connector_type == DRM_MODE_CONNECTOR_DVII)
2179926deccbSFrançois Tigeot 				connector->doublescan_allowed = true;
2180926deccbSFrançois Tigeot 			else
2181926deccbSFrançois Tigeot 				connector->doublescan_allowed = false;
2182926deccbSFrançois Tigeot 			break;
2183926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_HDMIA:
2184926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_HDMIB:
2185c4ef309bSzrj 			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
2186926deccbSFrançois Tigeot 			if (!radeon_dig_connector)
2187926deccbSFrançois Tigeot 				goto failed;
2188926deccbSFrançois Tigeot 			radeon_dig_connector->igp_lane_info = igp_lane_info;
2189926deccbSFrançois Tigeot 			radeon_connector->con_priv = radeon_dig_connector;
2190926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
2191926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
2192926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2193926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2194926deccbSFrançois Tigeot 				if (!radeon_connector->ddc_bus)
2195926deccbSFrançois Tigeot 					DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2196926deccbSFrançois Tigeot 			}
2197b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2198926deccbSFrançois Tigeot 						      rdev->mode_info.coherent_mode_property,
2199926deccbSFrançois Tigeot 						      1);
2200926deccbSFrançois Tigeot 			if (ASIC_IS_AVIVO(rdev)) {
2201b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2202926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_property,
2203926deccbSFrançois Tigeot 							      UNDERSCAN_OFF);
2204b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2205926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_hborder_property,
2206926deccbSFrançois Tigeot 							      0);
2207b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2208926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_vborder_property,
2209926deccbSFrançois Tigeot 							      0);
2210c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2211c6f73aabSFrançois Tigeot 							   rdev->mode_info.dither_property,
2212c6f73aabSFrançois Tigeot 							   RADEON_FMT_DITHER_DISABLE);
2213c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2214c6f73aabSFrançois Tigeot 							   dev->mode_config.scaling_mode_property,
2215c6f73aabSFrançois Tigeot 							   DRM_MODE_SCALE_NONE);
2216926deccbSFrançois Tigeot 			}
22174cd92098Szrj 			if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
22184cd92098Szrj 				drm_object_attach_property(&radeon_connector->base.base,
22194cd92098Szrj 							   rdev->mode_info.audio_property,
2220c6f73aabSFrançois Tigeot 							   RADEON_AUDIO_AUTO);
2221c59a5c48SFrançois Tigeot 				radeon_connector->audio = RADEON_AUDIO_AUTO;
22224cd92098Szrj 			}
2223c59a5c48SFrançois Tigeot 			if (ASIC_IS_DCE5(rdev))
2224c59a5c48SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2225c59a5c48SFrançois Tigeot 							   rdev->mode_info.output_csc_property,
2226c59a5c48SFrançois Tigeot 							   RADEON_OUTPUT_CSC_BYPASS);
2227926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2228926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2229926deccbSFrançois Tigeot 			if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
2230926deccbSFrançois Tigeot 				connector->doublescan_allowed = true;
2231926deccbSFrançois Tigeot 			else
2232926deccbSFrançois Tigeot 				connector->doublescan_allowed = false;
2233926deccbSFrançois Tigeot 			break;
2234926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DisplayPort:
2235c4ef309bSzrj 			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
2236926deccbSFrançois Tigeot 			if (!radeon_dig_connector)
2237926deccbSFrançois Tigeot 				goto failed;
2238926deccbSFrançois Tigeot 			radeon_dig_connector->igp_lane_info = igp_lane_info;
2239926deccbSFrançois Tigeot 			radeon_connector->con_priv = radeon_dig_connector;
2240926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
2241926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
2242926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2243926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
22447191d616Szrj 				if (radeon_connector->ddc_bus)
22457191d616Szrj 					has_aux = true;
22467191d616Szrj 				else
2247926deccbSFrançois Tigeot 					DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2248926deccbSFrançois Tigeot 			}
2249926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2250b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2251926deccbSFrançois Tigeot 						      rdev->mode_info.coherent_mode_property,
2252926deccbSFrançois Tigeot 						      1);
2253926deccbSFrançois Tigeot 			if (ASIC_IS_AVIVO(rdev)) {
2254b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2255926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_property,
2256926deccbSFrançois Tigeot 							      UNDERSCAN_OFF);
2257b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2258926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_hborder_property,
2259926deccbSFrançois Tigeot 							      0);
2260b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2261926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_vborder_property,
2262926deccbSFrançois Tigeot 							      0);
2263c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2264c6f73aabSFrançois Tigeot 							   rdev->mode_info.dither_property,
2265c6f73aabSFrançois Tigeot 							   RADEON_FMT_DITHER_DISABLE);
2266c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2267c6f73aabSFrançois Tigeot 							   dev->mode_config.scaling_mode_property,
2268c6f73aabSFrançois Tigeot 							   DRM_MODE_SCALE_NONE);
2269926deccbSFrançois Tigeot 			}
22704cd92098Szrj 			if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
22714cd92098Szrj 				drm_object_attach_property(&radeon_connector->base.base,
22724cd92098Szrj 							   rdev->mode_info.audio_property,
2273c6f73aabSFrançois Tigeot 							   RADEON_AUDIO_AUTO);
2274c59a5c48SFrançois Tigeot 				radeon_connector->audio = RADEON_AUDIO_AUTO;
22754cd92098Szrj 			}
2276c59a5c48SFrançois Tigeot 			if (ASIC_IS_DCE5(rdev))
2277c59a5c48SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2278c59a5c48SFrançois Tigeot 							   rdev->mode_info.output_csc_property,
2279c59a5c48SFrançois Tigeot 							   RADEON_OUTPUT_CSC_BYPASS);
2280926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2281926deccbSFrançois Tigeot 			/* in theory with a DP to VGA converter... */
2282926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2283926deccbSFrançois Tigeot 			break;
2284926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_eDP:
2285c4ef309bSzrj 			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
2286926deccbSFrançois Tigeot 			if (!radeon_dig_connector)
2287926deccbSFrançois Tigeot 				goto failed;
2288926deccbSFrançois Tigeot 			radeon_dig_connector->igp_lane_info = igp_lane_info;
2289926deccbSFrançois Tigeot 			radeon_connector->con_priv = radeon_dig_connector;
22904cd92098Szrj 			drm_connector_init(dev, &radeon_connector->base, &radeon_edp_connector_funcs, connector_type);
2291926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
2292926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
22935ef6d7b4SFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
22945ef6d7b4SFrançois Tigeot 				if (radeon_connector->ddc_bus)
22957191d616Szrj 					has_aux = true;
22967191d616Szrj 				else
2297926deccbSFrançois Tigeot 					DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2298926deccbSFrançois Tigeot 			}
2299b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2300926deccbSFrançois Tigeot 						      dev->mode_config.scaling_mode_property,
2301926deccbSFrançois Tigeot 						      DRM_MODE_SCALE_FULLSCREEN);
2302926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2303926deccbSFrançois Tigeot 			connector->interlace_allowed = false;
2304926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2305926deccbSFrançois Tigeot 			break;
2306926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_SVIDEO:
2307926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_Composite:
2308926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_9PinDIN:
2309926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
2310926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
2311926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
2312b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2313926deccbSFrançois Tigeot 						      rdev->mode_info.load_detect_property,
2314926deccbSFrançois Tigeot 						      1);
2315b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2316926deccbSFrançois Tigeot 						      rdev->mode_info.tv_std_property,
2317926deccbSFrançois Tigeot 						      radeon_atombios_get_tv_info(rdev));
2318926deccbSFrançois Tigeot 			/* no HPD on analog connectors */
2319926deccbSFrançois Tigeot 			radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2320926deccbSFrançois Tigeot 			connector->interlace_allowed = false;
2321926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2322926deccbSFrançois Tigeot 			break;
2323926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_LVDS:
2324c4ef309bSzrj 			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
2325926deccbSFrançois Tigeot 			if (!radeon_dig_connector)
2326926deccbSFrançois Tigeot 				goto failed;
2327926deccbSFrançois Tigeot 			radeon_dig_connector->igp_lane_info = igp_lane_info;
2328926deccbSFrançois Tigeot 			radeon_connector->con_priv = radeon_dig_connector;
2329926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
2330926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
2331926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2332926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2333926deccbSFrançois Tigeot 				if (!radeon_connector->ddc_bus)
2334926deccbSFrançois Tigeot 					DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2335926deccbSFrançois Tigeot 			}
2336b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2337926deccbSFrançois Tigeot 						      dev->mode_config.scaling_mode_property,
2338926deccbSFrançois Tigeot 						      DRM_MODE_SCALE_FULLSCREEN);
2339926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2340926deccbSFrançois Tigeot 			connector->interlace_allowed = false;
2341926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2342926deccbSFrançois Tigeot 			break;
2343926deccbSFrançois Tigeot 		}
2344926deccbSFrançois Tigeot 	}
2345926deccbSFrançois Tigeot 
2346926deccbSFrançois Tigeot 	if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
2347c59a5c48SFrançois Tigeot 		if (i2c_bus->valid) {
2348c59a5c48SFrançois Tigeot 			connector->polled = DRM_CONNECTOR_POLL_CONNECT |
2349c59a5c48SFrançois Tigeot 			                    DRM_CONNECTOR_POLL_DISCONNECT;
2350c59a5c48SFrançois Tigeot 		}
2351926deccbSFrançois Tigeot 	} else
2352926deccbSFrançois Tigeot 		connector->polled = DRM_CONNECTOR_POLL_HPD;
2353926deccbSFrançois Tigeot 
2354926deccbSFrançois Tigeot 	connector->display_info.subpixel_order = subpixel_order;
2355c6f73aabSFrançois Tigeot 	drm_connector_register(connector);
23567191d616Szrj 
23577191d616Szrj 	if (has_aux)
23587191d616Szrj 		radeon_dp_aux_init(radeon_connector);
23597191d616Szrj 
2360926deccbSFrançois Tigeot 	return;
2361926deccbSFrançois Tigeot 
2362926deccbSFrançois Tigeot failed:
2363926deccbSFrançois Tigeot 	drm_connector_cleanup(connector);
2364158486a6SFrançois Tigeot 	kfree(connector);
2365926deccbSFrançois Tigeot }
2366926deccbSFrançois Tigeot 
2367926deccbSFrançois Tigeot void
2368926deccbSFrançois Tigeot radeon_add_legacy_connector(struct drm_device *dev,
2369926deccbSFrançois Tigeot 			    uint32_t connector_id,
2370926deccbSFrançois Tigeot 			    uint32_t supported_device,
2371926deccbSFrançois Tigeot 			    int connector_type,
2372926deccbSFrançois Tigeot 			    struct radeon_i2c_bus_rec *i2c_bus,
2373926deccbSFrançois Tigeot 			    uint16_t connector_object_id,
2374926deccbSFrançois Tigeot 			    struct radeon_hpd *hpd)
2375926deccbSFrançois Tigeot {
2376926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
2377926deccbSFrançois Tigeot 	struct drm_connector *connector;
2378926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector;
2379926deccbSFrançois Tigeot 	uint32_t subpixel_order = SubPixelNone;
2380926deccbSFrançois Tigeot 
2381926deccbSFrançois Tigeot 	if (connector_type == DRM_MODE_CONNECTOR_Unknown)
2382926deccbSFrançois Tigeot 		return;
2383926deccbSFrançois Tigeot 
2384926deccbSFrançois Tigeot 	/* if the user selected tv=0 don't try and add the connector */
2385926deccbSFrançois Tigeot 	if (((connector_type == DRM_MODE_CONNECTOR_SVIDEO) ||
2386926deccbSFrançois Tigeot 	     (connector_type == DRM_MODE_CONNECTOR_Composite) ||
2387926deccbSFrançois Tigeot 	     (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) &&
2388926deccbSFrançois Tigeot 	    (radeon_tv == 0))
2389926deccbSFrançois Tigeot 		return;
2390926deccbSFrançois Tigeot 
2391926deccbSFrançois Tigeot 	/* see if we already added it */
2392926deccbSFrançois Tigeot 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
2393926deccbSFrançois Tigeot 		radeon_connector = to_radeon_connector(connector);
2394926deccbSFrançois Tigeot 		if (radeon_connector->connector_id == connector_id) {
2395926deccbSFrançois Tigeot 			radeon_connector->devices |= supported_device;
2396926deccbSFrançois Tigeot 			return;
2397926deccbSFrançois Tigeot 		}
2398926deccbSFrançois Tigeot 	}
2399926deccbSFrançois Tigeot 
2400c4ef309bSzrj 	radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL);
2401926deccbSFrançois Tigeot 	if (!radeon_connector)
2402926deccbSFrançois Tigeot 		return;
2403926deccbSFrançois Tigeot 
2404926deccbSFrançois Tigeot 	connector = &radeon_connector->base;
2405926deccbSFrançois Tigeot 
2406926deccbSFrançois Tigeot 	radeon_connector->connector_id = connector_id;
2407926deccbSFrançois Tigeot 	radeon_connector->devices = supported_device;
2408926deccbSFrançois Tigeot 	radeon_connector->connector_object_id = connector_object_id;
2409926deccbSFrançois Tigeot 	radeon_connector->hpd = *hpd;
2410926deccbSFrançois Tigeot 
2411926deccbSFrançois Tigeot 	switch (connector_type) {
2412926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_VGA:
2413926deccbSFrançois Tigeot 		drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
2414926deccbSFrançois Tigeot 		drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
2415926deccbSFrançois Tigeot 		if (i2c_bus->valid) {
2416926deccbSFrançois Tigeot 			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2417926deccbSFrançois Tigeot 			if (!radeon_connector->ddc_bus)
2418926deccbSFrançois Tigeot 				DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2419926deccbSFrançois Tigeot 		}
2420926deccbSFrançois Tigeot 		radeon_connector->dac_load_detect = true;
2421b5162e19SFrançois Tigeot 		drm_object_attach_property(&radeon_connector->base.base,
2422926deccbSFrançois Tigeot 					      rdev->mode_info.load_detect_property,
2423926deccbSFrançois Tigeot 					      1);
2424926deccbSFrançois Tigeot 		/* no HPD on analog connectors */
2425926deccbSFrançois Tigeot 		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2426926deccbSFrançois Tigeot 		connector->interlace_allowed = true;
2427926deccbSFrançois Tigeot 		connector->doublescan_allowed = true;
2428926deccbSFrançois Tigeot 		break;
2429926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_DVIA:
2430926deccbSFrançois Tigeot 		drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
2431926deccbSFrançois Tigeot 		drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
2432926deccbSFrançois Tigeot 		if (i2c_bus->valid) {
2433926deccbSFrançois Tigeot 			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2434926deccbSFrançois Tigeot 			if (!radeon_connector->ddc_bus)
2435926deccbSFrançois Tigeot 				DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2436926deccbSFrançois Tigeot 		}
2437926deccbSFrançois Tigeot 		radeon_connector->dac_load_detect = true;
2438b5162e19SFrançois Tigeot 		drm_object_attach_property(&radeon_connector->base.base,
2439926deccbSFrançois Tigeot 					      rdev->mode_info.load_detect_property,
2440926deccbSFrançois Tigeot 					      1);
2441926deccbSFrançois Tigeot 		/* no HPD on analog connectors */
2442926deccbSFrançois Tigeot 		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2443926deccbSFrançois Tigeot 		connector->interlace_allowed = true;
2444926deccbSFrançois Tigeot 		connector->doublescan_allowed = true;
2445926deccbSFrançois Tigeot 		break;
2446926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_DVII:
2447926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_DVID:
2448926deccbSFrançois Tigeot 		drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
2449926deccbSFrançois Tigeot 		drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
2450926deccbSFrançois Tigeot 		if (i2c_bus->valid) {
2451926deccbSFrançois Tigeot 			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2452926deccbSFrançois Tigeot 			if (!radeon_connector->ddc_bus)
2453926deccbSFrançois Tigeot 				DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2454926deccbSFrançois Tigeot 		}
2455926deccbSFrançois Tigeot 		if (connector_type == DRM_MODE_CONNECTOR_DVII) {
2456926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
2457b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2458926deccbSFrançois Tigeot 						      rdev->mode_info.load_detect_property,
2459926deccbSFrançois Tigeot 						      1);
2460926deccbSFrançois Tigeot 		}
2461926deccbSFrançois Tigeot 		subpixel_order = SubPixelHorizontalRGB;
2462926deccbSFrançois Tigeot 		connector->interlace_allowed = true;
2463926deccbSFrançois Tigeot 		if (connector_type == DRM_MODE_CONNECTOR_DVII)
2464926deccbSFrançois Tigeot 			connector->doublescan_allowed = true;
2465926deccbSFrançois Tigeot 		else
2466926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2467926deccbSFrançois Tigeot 		break;
2468926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_SVIDEO:
2469926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_Composite:
2470926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_9PinDIN:
2471926deccbSFrançois Tigeot 		drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
2472926deccbSFrançois Tigeot 		drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
2473926deccbSFrançois Tigeot 		radeon_connector->dac_load_detect = true;
2474926deccbSFrançois Tigeot 		/* RS400,RC410,RS480 chipset seems to report a lot
2475926deccbSFrançois Tigeot 		 * of false positive on load detect, we haven't yet
2476926deccbSFrançois Tigeot 		 * found a way to make load detect reliable on those
2477926deccbSFrançois Tigeot 		 * chipset, thus just disable it for TV.
2478926deccbSFrançois Tigeot 		 */
2479926deccbSFrançois Tigeot 		if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480)
2480926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = false;
2481b5162e19SFrançois Tigeot 		drm_object_attach_property(&radeon_connector->base.base,
2482926deccbSFrançois Tigeot 					      rdev->mode_info.load_detect_property,
2483926deccbSFrançois Tigeot 					      radeon_connector->dac_load_detect);
2484b5162e19SFrançois Tigeot 		drm_object_attach_property(&radeon_connector->base.base,
2485926deccbSFrançois Tigeot 					      rdev->mode_info.tv_std_property,
2486926deccbSFrançois Tigeot 					      radeon_combios_get_tv_info(rdev));
2487926deccbSFrançois Tigeot 		/* no HPD on analog connectors */
2488926deccbSFrançois Tigeot 		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2489926deccbSFrançois Tigeot 		connector->interlace_allowed = false;
2490926deccbSFrançois Tigeot 		connector->doublescan_allowed = false;
2491926deccbSFrançois Tigeot 		break;
2492926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_LVDS:
2493926deccbSFrançois Tigeot 		drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
2494926deccbSFrançois Tigeot 		drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
2495926deccbSFrançois Tigeot 		if (i2c_bus->valid) {
2496926deccbSFrançois Tigeot 			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2497926deccbSFrançois Tigeot 			if (!radeon_connector->ddc_bus)
2498926deccbSFrançois Tigeot 				DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2499926deccbSFrançois Tigeot 		}
2500b5162e19SFrançois Tigeot 		drm_object_attach_property(&radeon_connector->base.base,
2501926deccbSFrançois Tigeot 					      dev->mode_config.scaling_mode_property,
2502926deccbSFrançois Tigeot 					      DRM_MODE_SCALE_FULLSCREEN);
2503926deccbSFrançois Tigeot 		subpixel_order = SubPixelHorizontalRGB;
2504926deccbSFrançois Tigeot 		connector->interlace_allowed = false;
2505926deccbSFrançois Tigeot 		connector->doublescan_allowed = false;
2506926deccbSFrançois Tigeot 		break;
2507926deccbSFrançois Tigeot 	}
2508926deccbSFrançois Tigeot 
2509926deccbSFrançois Tigeot 	if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
2510c59a5c48SFrançois Tigeot 		if (i2c_bus->valid) {
2511c59a5c48SFrançois Tigeot 			connector->polled = DRM_CONNECTOR_POLL_CONNECT |
2512c59a5c48SFrançois Tigeot 			                    DRM_CONNECTOR_POLL_DISCONNECT;
2513c59a5c48SFrançois Tigeot 		}
2514926deccbSFrançois Tigeot 	} else
2515926deccbSFrançois Tigeot 		connector->polled = DRM_CONNECTOR_POLL_HPD;
2516c59a5c48SFrançois Tigeot 
2517926deccbSFrançois Tigeot 	connector->display_info.subpixel_order = subpixel_order;
2518c6f73aabSFrançois Tigeot 	drm_connector_register(connector);
2519926deccbSFrançois Tigeot }
2520c59a5c48SFrançois Tigeot 
2521c59a5c48SFrançois Tigeot void radeon_setup_mst_connector(struct drm_device *dev)
2522c59a5c48SFrançois Tigeot {
2523c59a5c48SFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
2524c59a5c48SFrançois Tigeot 	struct drm_connector *connector;
2525c59a5c48SFrançois Tigeot 	struct radeon_connector *radeon_connector;
2526c59a5c48SFrançois Tigeot 
2527c59a5c48SFrançois Tigeot 	if (!ASIC_IS_DCE5(rdev))
2528c59a5c48SFrançois Tigeot 		return;
2529c59a5c48SFrançois Tigeot 
2530c59a5c48SFrançois Tigeot 	if (radeon_mst == 0)
2531c59a5c48SFrançois Tigeot 		return;
2532c59a5c48SFrançois Tigeot 
2533c59a5c48SFrançois Tigeot 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
2534c59a5c48SFrançois Tigeot 		int ret;
2535c59a5c48SFrançois Tigeot 
2536c59a5c48SFrançois Tigeot 		radeon_connector = to_radeon_connector(connector);
2537c59a5c48SFrançois Tigeot 
2538c59a5c48SFrançois Tigeot 		if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
2539c59a5c48SFrançois Tigeot 			continue;
2540c59a5c48SFrançois Tigeot 
2541c59a5c48SFrançois Tigeot 		ret = radeon_dp_mst_init(radeon_connector);
2542c59a5c48SFrançois Tigeot 	}
2543c59a5c48SFrançois Tigeot }
2544