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 
radeon_dp_handle_hpd(struct drm_connector * connector)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 }
radeon_connector_hotplug(struct drm_connector * connector)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 		 */
93*3f2dd94aSFrançois Tigeot 		if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT &&
94*3f2dd94aSFrançois Tigeot 		    radeon_hpd_sense(rdev, radeon_connector->hpd.hpd) &&
95*3f2dd94aSFrançois Tigeot 		    radeon_dp_needs_link_train(radeon_connector)) {
96*3f2dd94aSFranç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 
100*3f2dd94aSFrançois Tigeot 			/* Turn the connector off and back on immediately, which
101*3f2dd94aSFrançois Tigeot 			 * will trigger link training
102926deccbSFrançois Tigeot 			 */
103*3f2dd94aSFranç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 
radeon_property_change_mode(struct drm_encoder * encoder)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 
radeon_get_monitor_bpc(struct drm_connector * connector)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? */
1941dedbd3bSFranç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 */
1991dedbd3bSFranç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
radeon_connector_update_scratch_regs(struct drm_connector * connector,enum drm_connector_status status)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 
259*3f2dd94aSFrançois Tigeot 		encoder = drm_encoder_find(connector->dev, NULL,
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 
radeon_find_encoder(struct drm_connector * connector,int encoder_type)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 
286*3f2dd94aSFrançois Tigeot 		encoder = drm_encoder_find(connector->dev, NULL, 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 
radeon_connector_edid(struct drm_connector * connector)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 
radeon_connector_get_edid(struct drm_connector * connector)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 
radeon_connector_free_edid(struct drm_connector * connector)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 
radeon_ddc_get_modes(struct drm_connector * connector)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 
radeon_best_single_encoder(struct drm_connector * connector)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)
400*3f2dd94aSFrançois Tigeot 		return drm_encoder_find(connector->dev, NULL, enc_id);
401926deccbSFrançois Tigeot 	return NULL;
402926deccbSFrançois Tigeot }
403c6f73aabSFrançois Tigeot 
radeon_get_native_mode(struct drm_connector * connector)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
radeon_connector_analog_encoder_conflict_solve(struct drm_connector * connector,struct drm_encoder * encoder,enum drm_connector_status current_status,bool priority)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 
radeon_fp_native_mode(struct drm_encoder * encoder)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 
radeon_add_common_modes(struct drm_encoder * encoder,struct drm_connector * connector)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 
radeon_connector_set_property(struct drm_connector * connector,struct drm_property * property,uint64_t val)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 			struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
770c59a5c48SFrançois Tigeot 
771c59a5c48SFrançois Tigeot 			radeon_crtc->output_csc = radeon_encoder->output_csc;
772c59a5c48SFrançois Tigeot 
773*3f2dd94aSFrançois Tigeot 			/*
774*3f2dd94aSFrançois Tigeot 			 * Our .gamma_set assumes the .gamma_store has been
775*3f2dd94aSFrançois Tigeot 			 * prefilled and don't care about its arguments.
776*3f2dd94aSFrançois Tigeot 			 */
777*3f2dd94aSFrançois Tigeot 			crtc->funcs->gamma_set(crtc, NULL, NULL, NULL, 0, NULL);
778c59a5c48SFrançois Tigeot 		}
779c59a5c48SFrançois Tigeot 	}
780c59a5c48SFrançois Tigeot 
781926deccbSFrançois Tigeot 	return 0;
782926deccbSFrançois Tigeot }
783926deccbSFrançois Tigeot 
radeon_fixup_lvds_native_mode(struct drm_encoder * encoder,struct drm_connector * connector)784926deccbSFrançois Tigeot static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder,
785926deccbSFrançois Tigeot 					  struct drm_connector *connector)
786926deccbSFrançois Tigeot {
787926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder =	to_radeon_encoder(encoder);
788926deccbSFrançois Tigeot 	struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
789926deccbSFrançois Tigeot 	struct drm_display_mode *t, *mode;
790926deccbSFrançois Tigeot 
791926deccbSFrançois Tigeot 	/* If the EDID preferred mode doesn't match the native mode, use it */
792926deccbSFrançois Tigeot 	list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
793926deccbSFrançois Tigeot 		if (mode->type & DRM_MODE_TYPE_PREFERRED) {
794926deccbSFrançois Tigeot 			if (mode->hdisplay != native_mode->hdisplay ||
795926deccbSFrançois Tigeot 			    mode->vdisplay != native_mode->vdisplay)
796926deccbSFrançois Tigeot 				memcpy(native_mode, mode, sizeof(*mode));
797926deccbSFrançois Tigeot 		}
798926deccbSFrançois Tigeot 	}
799926deccbSFrançois Tigeot 
800926deccbSFrançois Tigeot 	/* Try to get native mode details from EDID if necessary */
801926deccbSFrançois Tigeot 	if (!native_mode->clock) {
802926deccbSFrançois Tigeot 		list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
803926deccbSFrançois Tigeot 			if (mode->hdisplay == native_mode->hdisplay &&
804926deccbSFrançois Tigeot 			    mode->vdisplay == native_mode->vdisplay) {
805926deccbSFrançois Tigeot 				*native_mode = *mode;
806926deccbSFrançois Tigeot 				drm_mode_set_crtcinfo(native_mode, CRTC_INTERLACE_HALVE_V);
807926deccbSFrançois Tigeot 				DRM_DEBUG_KMS("Determined LVDS native mode details from EDID\n");
808926deccbSFrançois Tigeot 				break;
809926deccbSFrançois Tigeot 			}
810926deccbSFrançois Tigeot 		}
811926deccbSFrançois Tigeot 	}
812926deccbSFrançois Tigeot 
813926deccbSFrançois Tigeot 	if (!native_mode->clock) {
814926deccbSFrançois Tigeot 		DRM_DEBUG_KMS("No LVDS native mode details, disabling RMX\n");
815926deccbSFrançois Tigeot 		radeon_encoder->rmx_type = RMX_OFF;
816926deccbSFrançois Tigeot 	}
817926deccbSFrançois Tigeot }
818926deccbSFrançois Tigeot 
radeon_lvds_get_modes(struct drm_connector * connector)819926deccbSFrançois Tigeot static int radeon_lvds_get_modes(struct drm_connector *connector)
820926deccbSFrançois Tigeot {
821926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
822926deccbSFrançois Tigeot 	int ret = 0;
823926deccbSFrançois Tigeot 	struct drm_display_mode *mode;
824926deccbSFrançois Tigeot 
8255ef6d7b4SFrançois Tigeot 	radeon_connector_get_edid(connector);
8265ef6d7b4SFrançois Tigeot 	ret = radeon_ddc_get_modes(connector);
827926deccbSFrançois Tigeot 	if (ret > 0) {
828926deccbSFrançois Tigeot 		encoder = radeon_best_single_encoder(connector);
829926deccbSFrançois Tigeot 		if (encoder) {
830926deccbSFrançois Tigeot 			radeon_fixup_lvds_native_mode(encoder, connector);
831926deccbSFrançois Tigeot 			/* add scaled modes */
832926deccbSFrançois Tigeot 			radeon_add_common_modes(encoder, connector);
833926deccbSFrançois Tigeot 		}
834926deccbSFrançois Tigeot 		return ret;
835926deccbSFrançois Tigeot 	}
836926deccbSFrançois Tigeot 
837926deccbSFrançois Tigeot 	encoder = radeon_best_single_encoder(connector);
838926deccbSFrançois Tigeot 	if (!encoder)
839926deccbSFrançois Tigeot 		return 0;
840926deccbSFrançois Tigeot 
841926deccbSFrançois Tigeot 	/* we have no EDID modes */
842926deccbSFrançois Tigeot 	mode = radeon_fp_native_mode(encoder);
843926deccbSFrançois Tigeot 	if (mode) {
844926deccbSFrançois Tigeot 		ret = 1;
845926deccbSFrançois Tigeot 		drm_mode_probed_add(connector, mode);
846926deccbSFrançois Tigeot 		/* add the width/height from vbios tables if available */
847926deccbSFrançois Tigeot 		connector->display_info.width_mm = mode->width_mm;
848926deccbSFrançois Tigeot 		connector->display_info.height_mm = mode->height_mm;
849926deccbSFrançois Tigeot 		/* add scaled modes */
850926deccbSFrançois Tigeot 		radeon_add_common_modes(encoder, connector);
851926deccbSFrançois Tigeot 	}
852926deccbSFrançois Tigeot 
853926deccbSFrançois Tigeot 	return ret;
854926deccbSFrançois Tigeot }
855926deccbSFrançois Tigeot 
radeon_lvds_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)856*3f2dd94aSFrançois Tigeot static int radeon_lvds_mode_valid(struct drm_connector *connector,
857926deccbSFrançois Tigeot 				  struct drm_display_mode *mode)
858926deccbSFrançois Tigeot {
859926deccbSFrançois Tigeot 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
860926deccbSFrançois Tigeot 
861926deccbSFrançois Tigeot 	if ((mode->hdisplay < 320) || (mode->vdisplay < 240))
862926deccbSFrançois Tigeot 		return MODE_PANEL;
863926deccbSFrançois Tigeot 
864926deccbSFrançois Tigeot 	if (encoder) {
865926deccbSFrançois Tigeot 		struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
866926deccbSFrançois Tigeot 		struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
867926deccbSFrançois Tigeot 
868926deccbSFrançois Tigeot 		/* AVIVO hardware supports downscaling modes larger than the panel
869926deccbSFrançois Tigeot 		 * to the panel size, but I'm not sure this is desirable.
870926deccbSFrançois Tigeot 		 */
871926deccbSFrançois Tigeot 		if ((mode->hdisplay > native_mode->hdisplay) ||
872926deccbSFrançois Tigeot 		    (mode->vdisplay > native_mode->vdisplay))
873926deccbSFrançois Tigeot 			return MODE_PANEL;
874926deccbSFrançois Tigeot 
875926deccbSFrançois Tigeot 		/* if scaling is disabled, block non-native modes */
876926deccbSFrançois Tigeot 		if (radeon_encoder->rmx_type == RMX_OFF) {
877926deccbSFrançois Tigeot 			if ((mode->hdisplay != native_mode->hdisplay) ||
878926deccbSFrançois Tigeot 			    (mode->vdisplay != native_mode->vdisplay))
879926deccbSFrançois Tigeot 				return MODE_PANEL;
880926deccbSFrançois Tigeot 		}
881926deccbSFrançois Tigeot 	}
882926deccbSFrançois Tigeot 
883926deccbSFrançois Tigeot 	return MODE_OK;
884926deccbSFrançois Tigeot }
885926deccbSFrançois Tigeot 
886926deccbSFrançois Tigeot static enum drm_connector_status
radeon_lvds_detect(struct drm_connector * connector,bool force)887926deccbSFrançois Tigeot radeon_lvds_detect(struct drm_connector *connector, bool force)
888926deccbSFrançois Tigeot {
8891cfef1a5SFrançois Tigeot 	struct drm_device *dev = connector->dev;
8901cfef1a5SFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
891926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
892926deccbSFrançois Tigeot 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
893926deccbSFrançois Tigeot 	enum drm_connector_status ret = connector_status_disconnected;
894c6f73aabSFrançois Tigeot 	int r;
895c6f73aabSFrançois Tigeot 
896*3f2dd94aSFrançois Tigeot 	if (!drm_kms_helper_is_poll_worker()) {
897c6f73aabSFrançois Tigeot 		r = pm_runtime_get_sync(connector->dev->dev);
898c6f73aabSFrançois Tigeot 		if (r < 0)
899c6f73aabSFrançois Tigeot 			return connector_status_disconnected;
900*3f2dd94aSFrançois Tigeot 	}
901926deccbSFrançois Tigeot 
902926deccbSFrançois Tigeot 	if (encoder) {
903926deccbSFrançois Tigeot 		struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
904926deccbSFrançois Tigeot 		struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
905926deccbSFrançois Tigeot 
906926deccbSFrançois Tigeot 		/* check if panel is valid */
907926deccbSFrançois Tigeot 		if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
908926deccbSFrançois Tigeot 			ret = connector_status_connected;
9091cfef1a5SFrançois Tigeot 		/* don't fetch the edid from the vbios if ddc fails and runpm is
9101cfef1a5SFrançois Tigeot 		 * enabled so we report disconnected.
9111cfef1a5SFrançois Tigeot 		 */
9121cfef1a5SFrançois Tigeot 		if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0))
9131cfef1a5SFrançois Tigeot 			ret = connector_status_disconnected;
914926deccbSFrançois Tigeot 	}
915926deccbSFrançois Tigeot 
916926deccbSFrançois Tigeot 	/* check for edid as well */
9175ef6d7b4SFrançois Tigeot 	radeon_connector_get_edid(connector);
918926deccbSFrançois Tigeot 	if (radeon_connector->edid)
919926deccbSFrançois Tigeot 		ret = connector_status_connected;
920926deccbSFrançois Tigeot 	/* check acpi lid status ??? */
921926deccbSFrançois Tigeot 
922926deccbSFrançois Tigeot 	radeon_connector_update_scratch_regs(connector, ret);
923*3f2dd94aSFrançois Tigeot 
924*3f2dd94aSFrançois Tigeot 	if (!drm_kms_helper_is_poll_worker()) {
925c6f73aabSFrançois Tigeot 		pm_runtime_mark_last_busy(connector->dev->dev);
926c6f73aabSFrançois Tigeot 		pm_runtime_put_autosuspend(connector->dev->dev);
927*3f2dd94aSFrançois Tigeot 	}
928*3f2dd94aSFrançois Tigeot 
929926deccbSFrançois Tigeot 	return ret;
930926deccbSFrançois Tigeot }
931926deccbSFrançois Tigeot 
radeon_connector_unregister(struct drm_connector * connector)9321dedbd3bSFrançois Tigeot static void radeon_connector_unregister(struct drm_connector *connector)
9331dedbd3bSFrançois Tigeot {
9341dedbd3bSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
9351dedbd3bSFrançois Tigeot 
9361dedbd3bSFrançois Tigeot 	if (radeon_connector->ddc_bus && radeon_connector->ddc_bus->has_aux) {
9371dedbd3bSFrançois Tigeot 		drm_dp_aux_unregister(&radeon_connector->ddc_bus->aux);
9381dedbd3bSFrançois Tigeot 		radeon_connector->ddc_bus->has_aux = false;
9391dedbd3bSFrançois Tigeot 	}
9401dedbd3bSFrançois Tigeot }
9411dedbd3bSFrançois Tigeot 
radeon_connector_destroy(struct drm_connector * connector)942926deccbSFrançois Tigeot static void radeon_connector_destroy(struct drm_connector *connector)
943926deccbSFrançois Tigeot {
944926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
945926deccbSFrançois Tigeot 
9465ef6d7b4SFrançois Tigeot 	radeon_connector_free_edid(connector);
947c4ef309bSzrj 	kfree(radeon_connector->con_priv);
948c6f73aabSFrançois Tigeot 	drm_connector_unregister(connector);
949926deccbSFrançois Tigeot 	drm_connector_cleanup(connector);
950c4ef309bSzrj 	kfree(connector);
951926deccbSFrançois Tigeot }
952926deccbSFrançois Tigeot 
radeon_lvds_set_property(struct drm_connector * connector,struct drm_property * property,uint64_t value)953926deccbSFrançois Tigeot static int radeon_lvds_set_property(struct drm_connector *connector,
954926deccbSFrançois Tigeot 				    struct drm_property *property,
955926deccbSFrançois Tigeot 				    uint64_t value)
956926deccbSFrançois Tigeot {
957926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
958926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
959926deccbSFrançois Tigeot 	enum radeon_rmx_type rmx_type;
960926deccbSFrançois Tigeot 
961926deccbSFrançois Tigeot 	DRM_DEBUG_KMS("\n");
962926deccbSFrançois Tigeot 	if (property != dev->mode_config.scaling_mode_property)
963926deccbSFrançois Tigeot 		return 0;
964926deccbSFrançois Tigeot 
965926deccbSFrançois Tigeot 	if (connector->encoder)
966926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(connector->encoder);
967926deccbSFrançois Tigeot 	else {
968c0e85e96SFrançois Tigeot 		const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
969926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector));
970926deccbSFrançois Tigeot 	}
971926deccbSFrançois Tigeot 
972926deccbSFrançois Tigeot 	switch (value) {
973926deccbSFrançois Tigeot 	case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break;
974926deccbSFrançois Tigeot 	case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break;
975926deccbSFrançois Tigeot 	case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break;
976926deccbSFrançois Tigeot 	default:
977926deccbSFrançois Tigeot 	case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break;
978926deccbSFrançois Tigeot 	}
979926deccbSFrançois Tigeot 	if (radeon_encoder->rmx_type == rmx_type)
980926deccbSFrançois Tigeot 		return 0;
981926deccbSFrançois Tigeot 
982926deccbSFrançois Tigeot 	radeon_encoder->rmx_type = rmx_type;
983926deccbSFrançois Tigeot 
984926deccbSFrançois Tigeot 	radeon_property_change_mode(&radeon_encoder->base);
985926deccbSFrançois Tigeot 	return 0;
986926deccbSFrançois Tigeot }
987926deccbSFrançois Tigeot 
988926deccbSFrançois Tigeot 
989926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_lvds_connector_helper_funcs = {
990926deccbSFrançois Tigeot 	.get_modes = radeon_lvds_get_modes,
991926deccbSFrançois Tigeot 	.mode_valid = radeon_lvds_mode_valid,
992926deccbSFrançois Tigeot 	.best_encoder = radeon_best_single_encoder,
993926deccbSFrançois Tigeot };
994926deccbSFrançois Tigeot 
995926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_lvds_connector_funcs = {
996926deccbSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
997926deccbSFrançois Tigeot 	.detect = radeon_lvds_detect,
998926deccbSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
9991dedbd3bSFrançois Tigeot 	.early_unregister = radeon_connector_unregister,
1000926deccbSFrançois Tigeot 	.destroy = radeon_connector_destroy,
1001926deccbSFrançois Tigeot 	.set_property = radeon_lvds_set_property,
1002926deccbSFrançois Tigeot };
1003926deccbSFrançois Tigeot 
radeon_vga_get_modes(struct drm_connector * connector)1004926deccbSFrançois Tigeot static int radeon_vga_get_modes(struct drm_connector *connector)
1005926deccbSFrançois Tigeot {
1006926deccbSFrançois Tigeot 	int ret;
1007926deccbSFrançois Tigeot 
10085ef6d7b4SFrançois Tigeot 	radeon_connector_get_edid(connector);
10095ef6d7b4SFrançois Tigeot 	ret = radeon_ddc_get_modes(connector);
1010926deccbSFrançois Tigeot 
1011c6f73aabSFrançois Tigeot 	radeon_get_native_mode(connector);
1012c6f73aabSFrançois Tigeot 
1013926deccbSFrançois Tigeot 	return ret;
1014926deccbSFrançois Tigeot }
1015926deccbSFrançois Tigeot 
radeon_vga_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)1016*3f2dd94aSFrançois Tigeot static int radeon_vga_mode_valid(struct drm_connector *connector,
1017926deccbSFrançois Tigeot 				  struct drm_display_mode *mode)
1018926deccbSFrançois Tigeot {
1019926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1020926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1021926deccbSFrançois Tigeot 
1022926deccbSFrançois Tigeot 	/* XXX check mode bandwidth */
1023926deccbSFrançois Tigeot 
1024926deccbSFrançois Tigeot 	if ((mode->clock / 10) > rdev->clock.max_pixel_clock)
1025926deccbSFrançois Tigeot 		return MODE_CLOCK_HIGH;
1026926deccbSFrançois Tigeot 
1027926deccbSFrançois Tigeot 	return MODE_OK;
1028926deccbSFrançois Tigeot }
1029926deccbSFrançois Tigeot 
1030926deccbSFrançois Tigeot static enum drm_connector_status
radeon_vga_detect(struct drm_connector * connector,bool force)1031926deccbSFrançois Tigeot radeon_vga_detect(struct drm_connector *connector, bool force)
1032926deccbSFrançois Tigeot {
1033926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1034926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1035926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1036926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1037c0e85e96SFrançois Tigeot 	const struct drm_encoder_helper_funcs *encoder_funcs;
1038926deccbSFrançois Tigeot 	bool dret = false;
1039926deccbSFrançois Tigeot 	enum drm_connector_status ret = connector_status_disconnected;
1040c6f73aabSFrançois Tigeot 	int r;
1041c6f73aabSFrançois Tigeot 
1042*3f2dd94aSFrançois Tigeot 	if (!drm_kms_helper_is_poll_worker()) {
1043c6f73aabSFrançois Tigeot 		r = pm_runtime_get_sync(connector->dev->dev);
1044c6f73aabSFrançois Tigeot 		if (r < 0)
1045c6f73aabSFrançois Tigeot 			return connector_status_disconnected;
1046*3f2dd94aSFrançois Tigeot 	}
1047926deccbSFrançois Tigeot 
1048926deccbSFrançois Tigeot 	encoder = radeon_best_single_encoder(connector);
1049926deccbSFrançois Tigeot 	if (!encoder)
1050926deccbSFrançois Tigeot 		ret = connector_status_disconnected;
1051926deccbSFrançois Tigeot 
1052926deccbSFrançois Tigeot 	if (radeon_connector->ddc_bus)
1053926deccbSFrançois Tigeot 		dret = radeon_ddc_probe(radeon_connector, false);
1054926deccbSFrançois Tigeot 	if (dret) {
1055926deccbSFrançois Tigeot 		radeon_connector->detected_by_load = false;
10565ef6d7b4SFrançois Tigeot 		radeon_connector_free_edid(connector);
10575ef6d7b4SFrançois Tigeot 		radeon_connector_get_edid(connector);
1058926deccbSFrançois Tigeot 
1059926deccbSFrançois Tigeot 		if (!radeon_connector->edid) {
1060926deccbSFrançois Tigeot 			DRM_ERROR("%s: probed a monitor but no|invalid EDID\n",
1061ba55f2f5SFrançois Tigeot 					connector->name);
1062926deccbSFrançois Tigeot 			ret = connector_status_connected;
1063926deccbSFrançois Tigeot 		} else {
10647191d616Szrj 			radeon_connector->use_digital =
10657191d616Szrj 				!!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
1066926deccbSFrançois Tigeot 
1067926deccbSFrançois Tigeot 			/* some oems have boards with separate digital and analog connectors
1068926deccbSFrançois Tigeot 			 * with a shared ddc line (often vga + hdmi)
1069926deccbSFrançois Tigeot 			 */
1070926deccbSFrançois Tigeot 			if (radeon_connector->use_digital && radeon_connector->shared_ddc) {
10715ef6d7b4SFrançois Tigeot 				radeon_connector_free_edid(connector);
1072926deccbSFrançois Tigeot 				ret = connector_status_disconnected;
10737191d616Szrj 			} else {
1074926deccbSFrançois Tigeot 				ret = connector_status_connected;
1075926deccbSFrançois Tigeot 			}
10767191d616Szrj 		}
1077926deccbSFrançois Tigeot 	} else {
1078926deccbSFrançois Tigeot 
1079926deccbSFrançois Tigeot 		/* if we aren't forcing don't do destructive polling */
1080926deccbSFrançois Tigeot 		if (!force) {
1081926deccbSFrançois Tigeot 			/* only return the previous status if we last
1082926deccbSFrançois Tigeot 			 * detected a monitor via load.
1083926deccbSFrançois Tigeot 			 */
1084926deccbSFrançois Tigeot 			if (radeon_connector->detected_by_load)
1085c6f73aabSFrançois Tigeot 				ret = connector->status;
1086c6f73aabSFrançois Tigeot 			goto out;
1087926deccbSFrançois Tigeot 		}
1088926deccbSFrançois Tigeot 
1089926deccbSFrançois Tigeot 		if (radeon_connector->dac_load_detect && encoder) {
1090926deccbSFrançois Tigeot 			encoder_funcs = encoder->helper_private;
1091926deccbSFrançois Tigeot 			ret = encoder_funcs->detect(encoder, connector);
1092926deccbSFrançois Tigeot 			if (ret != connector_status_disconnected)
1093926deccbSFrançois Tigeot 				radeon_connector->detected_by_load = true;
1094926deccbSFrançois Tigeot 		}
1095926deccbSFrançois Tigeot 	}
1096926deccbSFrançois Tigeot 
1097926deccbSFrançois Tigeot 	if (ret == connector_status_connected)
1098926deccbSFrançois Tigeot 		ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true);
1099926deccbSFrançois Tigeot 
1100926deccbSFrançois Tigeot 	/* RN50 and some RV100 asics in servers often have a hardcoded EDID in the
1101926deccbSFrançois Tigeot 	 * vbios to deal with KVMs. If we have one and are not able to detect a monitor
1102926deccbSFrançois Tigeot 	 * by other means, assume the CRT is connected and use that EDID.
1103926deccbSFrançois Tigeot 	 */
1104926deccbSFrançois Tigeot 	if ((!rdev->is_atom_bios) &&
1105926deccbSFrançois Tigeot 	    (ret == connector_status_disconnected) &&
1106926deccbSFrançois Tigeot 	    rdev->mode_info.bios_hardcoded_edid_size) {
1107926deccbSFrançois Tigeot 		ret = connector_status_connected;
1108926deccbSFrançois Tigeot 	}
1109926deccbSFrançois Tigeot 
1110926deccbSFrançois Tigeot 	radeon_connector_update_scratch_regs(connector, ret);
1111c6f73aabSFrançois Tigeot 
1112c6f73aabSFrançois Tigeot out:
1113*3f2dd94aSFrançois Tigeot 	if (!drm_kms_helper_is_poll_worker()) {
1114c6f73aabSFrançois Tigeot 		pm_runtime_mark_last_busy(connector->dev->dev);
1115c6f73aabSFrançois Tigeot 		pm_runtime_put_autosuspend(connector->dev->dev);
1116*3f2dd94aSFrançois Tigeot 	}
1117c6f73aabSFrançois Tigeot 
1118926deccbSFrançois Tigeot 	return ret;
1119926deccbSFrançois Tigeot }
1120926deccbSFrançois Tigeot 
1121926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_vga_connector_helper_funcs = {
1122926deccbSFrançois Tigeot 	.get_modes = radeon_vga_get_modes,
1123926deccbSFrançois Tigeot 	.mode_valid = radeon_vga_mode_valid,
1124926deccbSFrançois Tigeot 	.best_encoder = radeon_best_single_encoder,
1125926deccbSFrançois Tigeot };
1126926deccbSFrançois Tigeot 
1127926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_vga_connector_funcs = {
1128926deccbSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
1129926deccbSFrançois Tigeot 	.detect = radeon_vga_detect,
1130926deccbSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
11311dedbd3bSFrançois Tigeot 	.early_unregister = radeon_connector_unregister,
1132926deccbSFrançois Tigeot 	.destroy = radeon_connector_destroy,
1133926deccbSFrançois Tigeot 	.set_property = radeon_connector_set_property,
1134926deccbSFrançois Tigeot };
1135926deccbSFrançois Tigeot 
radeon_tv_get_modes(struct drm_connector * connector)1136926deccbSFrançois Tigeot static int radeon_tv_get_modes(struct drm_connector *connector)
1137926deccbSFrançois Tigeot {
1138926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1139926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1140926deccbSFrançois Tigeot 	struct drm_display_mode *tv_mode;
1141926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1142926deccbSFrançois Tigeot 
1143926deccbSFrançois Tigeot 	encoder = radeon_best_single_encoder(connector);
1144926deccbSFrançois Tigeot 	if (!encoder)
1145926deccbSFrançois Tigeot 		return 0;
1146926deccbSFrançois Tigeot 
1147926deccbSFrançois Tigeot 	/* avivo chips can scale any mode */
1148926deccbSFrançois Tigeot 	if (rdev->family >= CHIP_RS600)
1149926deccbSFrançois Tigeot 		/* add scaled modes */
1150926deccbSFrançois Tigeot 		radeon_add_common_modes(encoder, connector);
1151926deccbSFrançois Tigeot 	else {
1152926deccbSFrançois Tigeot 		/* only 800x600 is supported right now on pre-avivo chips */
1153926deccbSFrançois Tigeot 		tv_mode = drm_cvt_mode(dev, 800, 600, 60, false, false, false);
1154926deccbSFrançois Tigeot 		tv_mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
1155926deccbSFrançois Tigeot 		drm_mode_probed_add(connector, tv_mode);
1156926deccbSFrançois Tigeot 	}
1157926deccbSFrançois Tigeot 	return 1;
1158926deccbSFrançois Tigeot }
1159926deccbSFrançois Tigeot 
radeon_tv_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)1160*3f2dd94aSFrançois Tigeot static int radeon_tv_mode_valid(struct drm_connector *connector,
1161926deccbSFrançois Tigeot 				struct drm_display_mode *mode)
1162926deccbSFrançois Tigeot {
1163926deccbSFrançois Tigeot 	if ((mode->hdisplay > 1024) || (mode->vdisplay > 768))
1164926deccbSFrançois Tigeot 		return MODE_CLOCK_RANGE;
1165926deccbSFrançois Tigeot 	return MODE_OK;
1166926deccbSFrançois Tigeot }
1167926deccbSFrançois Tigeot 
1168926deccbSFrançois Tigeot static enum drm_connector_status
radeon_tv_detect(struct drm_connector * connector,bool force)1169926deccbSFrançois Tigeot radeon_tv_detect(struct drm_connector *connector, bool force)
1170926deccbSFrançois Tigeot {
1171926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1172c0e85e96SFrançois Tigeot 	const struct drm_encoder_helper_funcs *encoder_funcs;
1173926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1174926deccbSFrançois Tigeot 	enum drm_connector_status ret = connector_status_disconnected;
1175c6f73aabSFrançois Tigeot 	int r;
1176926deccbSFrançois Tigeot 
1177926deccbSFrançois Tigeot 	if (!radeon_connector->dac_load_detect)
1178926deccbSFrançois Tigeot 		return ret;
1179926deccbSFrançois Tigeot 
1180*3f2dd94aSFrançois Tigeot 	if (!drm_kms_helper_is_poll_worker()) {
1181c6f73aabSFrançois Tigeot 		r = pm_runtime_get_sync(connector->dev->dev);
1182c6f73aabSFrançois Tigeot 		if (r < 0)
1183c6f73aabSFrançois Tigeot 			return connector_status_disconnected;
1184*3f2dd94aSFrançois Tigeot 	}
1185c6f73aabSFrançois Tigeot 
1186926deccbSFrançois Tigeot 	encoder = radeon_best_single_encoder(connector);
1187926deccbSFrançois Tigeot 	if (!encoder)
1188926deccbSFrançois Tigeot 		ret = connector_status_disconnected;
1189926deccbSFrançois Tigeot 	else {
1190926deccbSFrançois Tigeot 		encoder_funcs = encoder->helper_private;
1191926deccbSFrançois Tigeot 		ret = encoder_funcs->detect(encoder, connector);
1192926deccbSFrançois Tigeot 	}
1193926deccbSFrançois Tigeot 	if (ret == connector_status_connected)
1194926deccbSFrançois Tigeot 		ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false);
1195926deccbSFrançois Tigeot 	radeon_connector_update_scratch_regs(connector, ret);
1196*3f2dd94aSFrançois Tigeot 
1197*3f2dd94aSFrançois Tigeot 	if (!drm_kms_helper_is_poll_worker()) {
1198c6f73aabSFrançois Tigeot 		pm_runtime_mark_last_busy(connector->dev->dev);
1199c6f73aabSFrançois Tigeot 		pm_runtime_put_autosuspend(connector->dev->dev);
1200*3f2dd94aSFrançois Tigeot 	}
1201*3f2dd94aSFrançois Tigeot 
1202926deccbSFrançois Tigeot 	return ret;
1203926deccbSFrançois Tigeot }
1204926deccbSFrançois Tigeot 
1205926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_tv_connector_helper_funcs = {
1206926deccbSFrançois Tigeot 	.get_modes = radeon_tv_get_modes,
1207926deccbSFrançois Tigeot 	.mode_valid = radeon_tv_mode_valid,
1208926deccbSFrançois Tigeot 	.best_encoder = radeon_best_single_encoder,
1209926deccbSFrançois Tigeot };
1210926deccbSFrançois Tigeot 
1211926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_tv_connector_funcs = {
1212926deccbSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
1213926deccbSFrançois Tigeot 	.detect = radeon_tv_detect,
1214926deccbSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
12151dedbd3bSFrançois Tigeot 	.early_unregister = radeon_connector_unregister,
1216926deccbSFrançois Tigeot 	.destroy = radeon_connector_destroy,
1217926deccbSFrançois Tigeot 	.set_property = radeon_connector_set_property,
1218926deccbSFrançois Tigeot };
1219926deccbSFrançois Tigeot 
radeon_check_hpd_status_unchanged(struct drm_connector * connector)1220926deccbSFrançois Tigeot static bool radeon_check_hpd_status_unchanged(struct drm_connector *connector)
1221926deccbSFrançois Tigeot {
1222926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1223926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1224926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1225926deccbSFrançois Tigeot 	enum drm_connector_status status;
1226926deccbSFrançois Tigeot 
1227926deccbSFrançois Tigeot 	/* We only trust HPD on R600 and newer ASICS. */
1228926deccbSFrançois Tigeot 	if (rdev->family >= CHIP_R600
1229926deccbSFrançois Tigeot 	  && radeon_connector->hpd.hpd != RADEON_HPD_NONE) {
1230926deccbSFrançois Tigeot 		if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
1231926deccbSFrançois Tigeot 			status = connector_status_connected;
1232926deccbSFrançois Tigeot 		else
1233926deccbSFrançois Tigeot 			status = connector_status_disconnected;
1234926deccbSFrançois Tigeot 		if (connector->status == status)
1235926deccbSFrançois Tigeot 			return true;
1236926deccbSFrançois Tigeot 	}
1237926deccbSFrançois Tigeot 
1238926deccbSFrançois Tigeot 	return false;
1239926deccbSFrançois Tigeot }
1240926deccbSFrançois Tigeot 
1241926deccbSFrançois Tigeot /*
1242926deccbSFrançois Tigeot  * DVI is complicated
1243926deccbSFrançois Tigeot  * Do a DDC probe, if DDC probe passes, get the full EDID so
1244926deccbSFrançois Tigeot  * we can do analog/digital monitor detection at this point.
1245926deccbSFrançois Tigeot  * If the monitor is an analog monitor or we got no DDC,
1246926deccbSFrançois Tigeot  * we need to find the DAC encoder object for this connector.
1247926deccbSFrançois Tigeot  * If we got no DDC, we do load detection on the DAC encoder object.
1248926deccbSFrançois Tigeot  * If we got analog DDC or load detection passes on the DAC encoder
1249926deccbSFrançois Tigeot  * we have to check if this analog encoder is shared with anyone else (TV)
1250926deccbSFrançois Tigeot  * if its shared we have to set the other connector to disconnected.
1251926deccbSFrançois Tigeot  */
1252926deccbSFrançois Tigeot static enum drm_connector_status
radeon_dvi_detect(struct drm_connector * connector,bool force)1253926deccbSFrançois Tigeot radeon_dvi_detect(struct drm_connector *connector, bool force)
1254926deccbSFrançois Tigeot {
1255926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1256926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1257926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1258926deccbSFrançois Tigeot 	struct drm_encoder *encoder = NULL;
1259c0e85e96SFrançois Tigeot 	const struct drm_encoder_helper_funcs *encoder_funcs;
1260*3f2dd94aSFrançois Tigeot 	int i, r;
1261926deccbSFrançois Tigeot 	enum drm_connector_status ret = connector_status_disconnected;
1262926deccbSFrançois Tigeot 	bool dret = false, broken_edid = false;
1263926deccbSFrançois Tigeot 
1264*3f2dd94aSFrançois Tigeot 	if (!drm_kms_helper_is_poll_worker()) {
1265c6f73aabSFrançois Tigeot 		r = pm_runtime_get_sync(connector->dev->dev);
1266c6f73aabSFrançois Tigeot 		if (r < 0)
1267c6f73aabSFrançois Tigeot 			return connector_status_disconnected;
1268*3f2dd94aSFrançois Tigeot 	}
1269c6f73aabSFrançois Tigeot 
1270c59a5c48SFrançois Tigeot 	if (radeon_connector->detected_hpd_without_ddc) {
1271c59a5c48SFrançois Tigeot 		force = true;
1272c59a5c48SFrançois Tigeot 		radeon_connector->detected_hpd_without_ddc = false;
1273c59a5c48SFrançois Tigeot 	}
1274c59a5c48SFrançois Tigeot 
1275c6f73aabSFrançois Tigeot 	if (!force && radeon_check_hpd_status_unchanged(connector)) {
1276c6f73aabSFrançois Tigeot 		ret = connector->status;
1277c6f73aabSFrançois Tigeot 		goto exit;
1278c6f73aabSFrançois Tigeot 	}
1279926deccbSFrançois Tigeot 
1280c59a5c48SFrançois Tigeot 	if (radeon_connector->ddc_bus) {
1281926deccbSFrançois Tigeot 		dret = radeon_ddc_probe(radeon_connector, false);
1282c59a5c48SFrançois Tigeot 
1283c59a5c48SFrançois Tigeot 		/* Sometimes the pins required for the DDC probe on DVI
1284c59a5c48SFrançois Tigeot 		 * connectors don't make contact at the same time that the ones
1285c59a5c48SFrançois Tigeot 		 * for HPD do. If the DDC probe fails even though we had an HPD
1286c59a5c48SFrançois Tigeot 		 * signal, try again later */
1287c59a5c48SFrançois Tigeot 		if (!dret && !force &&
1288c59a5c48SFrançois Tigeot 		    connector->status != connector_status_connected) {
1289c59a5c48SFrançois Tigeot 			DRM_DEBUG_KMS("hpd detected without ddc, retrying in 1 second\n");
1290c59a5c48SFrançois Tigeot 			radeon_connector->detected_hpd_without_ddc = true;
1291c59a5c48SFrançois Tigeot 			schedule_delayed_work(&rdev->hotplug_work,
1292c59a5c48SFrançois Tigeot 					      msecs_to_jiffies(1000));
1293c59a5c48SFrançois Tigeot 			goto exit;
1294c59a5c48SFrançois Tigeot 		}
1295c59a5c48SFrançois Tigeot 	}
1296926deccbSFrançois Tigeot 	if (dret) {
1297926deccbSFrançois Tigeot 		radeon_connector->detected_by_load = false;
12985ef6d7b4SFrançois Tigeot 		radeon_connector_free_edid(connector);
12995ef6d7b4SFrançois Tigeot 		radeon_connector_get_edid(connector);
1300926deccbSFrançois Tigeot 
1301926deccbSFrançois Tigeot 		if (!radeon_connector->edid) {
1302926deccbSFrançois Tigeot 			DRM_ERROR("%s: probed a monitor but no|invalid EDID\n",
1303ba55f2f5SFrançois Tigeot 					connector->name);
1304926deccbSFrançois Tigeot 			/* rs690 seems to have a problem with connectors not existing and always
1305926deccbSFrançois Tigeot 			 * return a block of 0's. If we see this just stop polling on this output */
13067191d616Szrj 			if ((rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) &&
13077191d616Szrj 			    radeon_connector->base.null_edid_counter) {
1308926deccbSFrançois Tigeot 				ret = connector_status_disconnected;
1309ba55f2f5SFrançois Tigeot 				DRM_ERROR("%s: detected RS690 floating bus bug, stopping ddc detect\n",
1310ba55f2f5SFrançois Tigeot 					  connector->name);
1311926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = NULL;
1312926deccbSFrançois Tigeot 			} else {
1313926deccbSFrançois Tigeot 				ret = connector_status_connected;
1314926deccbSFrançois Tigeot 				broken_edid = true; /* defer use_digital to later */
1315926deccbSFrançois Tigeot 			}
1316926deccbSFrançois Tigeot 		} else {
13177191d616Szrj 			radeon_connector->use_digital =
13187191d616Szrj 				!!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
1319926deccbSFrançois Tigeot 
1320926deccbSFrançois Tigeot 			/* some oems have boards with separate digital and analog connectors
1321926deccbSFrançois Tigeot 			 * with a shared ddc line (often vga + hdmi)
1322926deccbSFrançois Tigeot 			 */
1323926deccbSFrançois Tigeot 			if ((!radeon_connector->use_digital) && radeon_connector->shared_ddc) {
13245ef6d7b4SFrançois Tigeot 				radeon_connector_free_edid(connector);
1325926deccbSFrançois Tigeot 				ret = connector_status_disconnected;
13267191d616Szrj 			} else {
1327926deccbSFrançois Tigeot 				ret = connector_status_connected;
13287191d616Szrj 			}
1329926deccbSFrançois Tigeot 			/* This gets complicated.  We have boards with VGA + HDMI with a
1330926deccbSFrançois Tigeot 			 * shared DDC line and we have boards with DVI-D + HDMI with a shared
1331926deccbSFrançois Tigeot 			 * DDC line.  The latter is more complex because with DVI<->HDMI adapters
1332926deccbSFrançois Tigeot 			 * you don't really know what's connected to which port as both are digital.
1333926deccbSFrançois Tigeot 			 */
1334926deccbSFrançois Tigeot 			if (radeon_connector->shared_ddc && (ret == connector_status_connected)) {
1335926deccbSFrançois Tigeot 				struct drm_connector *list_connector;
1336926deccbSFrançois Tigeot 				struct radeon_connector *list_radeon_connector;
1337926deccbSFrançois Tigeot 				list_for_each_entry(list_connector, &dev->mode_config.connector_list, head) {
1338926deccbSFrançois Tigeot 					if (connector == list_connector)
1339926deccbSFrançois Tigeot 						continue;
1340926deccbSFrançois Tigeot 					list_radeon_connector = to_radeon_connector(list_connector);
1341926deccbSFrançois Tigeot 					if (list_radeon_connector->shared_ddc &&
1342926deccbSFrançois Tigeot 					    (list_radeon_connector->ddc_bus->rec.i2c_id ==
1343926deccbSFrançois Tigeot 					     radeon_connector->ddc_bus->rec.i2c_id)) {
1344926deccbSFrançois Tigeot 						/* cases where both connectors are digital */
1345926deccbSFrançois Tigeot 						if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) {
1346926deccbSFrançois Tigeot 							/* hpd is our only option in this case */
1347926deccbSFrançois Tigeot 							if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
13485ef6d7b4SFrançois Tigeot 								radeon_connector_free_edid(connector);
1349926deccbSFrançois Tigeot 								ret = connector_status_disconnected;
1350926deccbSFrançois Tigeot 							}
1351926deccbSFrançois Tigeot 						}
1352926deccbSFrançois Tigeot 					}
1353926deccbSFrançois Tigeot 				}
1354926deccbSFrançois Tigeot 			}
1355926deccbSFrançois Tigeot 		}
1356926deccbSFrançois Tigeot 	}
1357926deccbSFrançois Tigeot 
1358926deccbSFrançois Tigeot 	if ((ret == connector_status_connected) && (radeon_connector->use_digital == true))
1359926deccbSFrançois Tigeot 		goto out;
1360926deccbSFrançois Tigeot 
1361926deccbSFrançois Tigeot 	/* DVI-D and HDMI-A are digital only */
1362926deccbSFrançois Tigeot 	if ((connector->connector_type == DRM_MODE_CONNECTOR_DVID) ||
1363926deccbSFrançois Tigeot 	    (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA))
1364926deccbSFrançois Tigeot 		goto out;
1365926deccbSFrançois Tigeot 
1366926deccbSFrançois Tigeot 	/* if we aren't forcing don't do destructive polling */
1367926deccbSFrançois Tigeot 	if (!force) {
1368926deccbSFrançois Tigeot 		/* only return the previous status if we last
1369926deccbSFrançois Tigeot 		 * detected a monitor via load.
1370926deccbSFrançois Tigeot 		 */
1371926deccbSFrançois Tigeot 		if (radeon_connector->detected_by_load)
1372926deccbSFrançois Tigeot 			ret = connector->status;
1373926deccbSFrançois Tigeot 		goto out;
1374926deccbSFrançois Tigeot 	}
1375926deccbSFrançois Tigeot 
1376926deccbSFrançois Tigeot 	/* find analog encoder */
1377926deccbSFrançois Tigeot 	if (radeon_connector->dac_load_detect) {
1378926deccbSFrançois Tigeot 		for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1379926deccbSFrançois Tigeot 			if (connector->encoder_ids[i] == 0)
1380926deccbSFrançois Tigeot 				break;
1381926deccbSFrançois Tigeot 
1382*3f2dd94aSFrançois Tigeot 			encoder = drm_encoder_find(connector->dev, NULL,
1383c6f73aabSFrançois Tigeot 						   connector->encoder_ids[i]);
1384c6f73aabSFrançois Tigeot 			if (!encoder)
1385926deccbSFrançois Tigeot 				continue;
1386926deccbSFrançois Tigeot 
1387926deccbSFrançois Tigeot 			if (encoder->encoder_type != DRM_MODE_ENCODER_DAC &&
1388926deccbSFrançois Tigeot 			    encoder->encoder_type != DRM_MODE_ENCODER_TVDAC)
1389926deccbSFrançois Tigeot 				continue;
1390926deccbSFrançois Tigeot 
1391926deccbSFrançois Tigeot 			encoder_funcs = encoder->helper_private;
1392926deccbSFrançois Tigeot 			if (encoder_funcs->detect) {
1393926deccbSFrançois Tigeot 				if (!broken_edid) {
1394926deccbSFrançois Tigeot 					if (ret != connector_status_connected) {
1395926deccbSFrançois Tigeot 						/* deal with analog monitors without DDC */
1396926deccbSFrançois Tigeot 						ret = encoder_funcs->detect(encoder, connector);
1397926deccbSFrançois Tigeot 						if (ret == connector_status_connected) {
1398926deccbSFrançois Tigeot 							radeon_connector->use_digital = false;
1399926deccbSFrançois Tigeot 						}
1400926deccbSFrançois Tigeot 						if (ret != connector_status_disconnected)
1401926deccbSFrançois Tigeot 							radeon_connector->detected_by_load = true;
1402926deccbSFrançois Tigeot 					}
1403926deccbSFrançois Tigeot 				} else {
1404926deccbSFrançois Tigeot 					enum drm_connector_status lret;
1405926deccbSFrançois Tigeot 					/* assume digital unless load detected otherwise */
1406926deccbSFrançois Tigeot 					radeon_connector->use_digital = true;
1407926deccbSFrançois Tigeot 					lret = encoder_funcs->detect(encoder, connector);
1408926deccbSFrançois Tigeot 					DRM_DEBUG_KMS("load_detect %x returned: %x\n",encoder->encoder_type,lret);
1409926deccbSFrançois Tigeot 					if (lret == connector_status_connected)
1410926deccbSFrançois Tigeot 						radeon_connector->use_digital = false;
1411926deccbSFrançois Tigeot 				}
1412926deccbSFrançois Tigeot 				break;
1413926deccbSFrançois Tigeot 			}
1414926deccbSFrançois Tigeot 		}
1415926deccbSFrançois Tigeot 	}
1416926deccbSFrançois Tigeot 
1417926deccbSFrançois Tigeot 	if ((ret == connector_status_connected) && (radeon_connector->use_digital == false) &&
1418926deccbSFrançois Tigeot 	    encoder) {
1419926deccbSFrançois Tigeot 		ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true);
1420926deccbSFrançois Tigeot 	}
1421926deccbSFrançois Tigeot 
1422926deccbSFrançois Tigeot 	/* RN50 and some RV100 asics in servers often have a hardcoded EDID in the
1423926deccbSFrançois Tigeot 	 * vbios to deal with KVMs. If we have one and are not able to detect a monitor
1424926deccbSFrançois Tigeot 	 * by other means, assume the DFP is connected and use that EDID.  In most
1425926deccbSFrançois Tigeot 	 * cases the DVI port is actually a virtual KVM port connected to the service
1426926deccbSFrançois Tigeot 	 * processor.
1427926deccbSFrançois Tigeot 	 */
1428926deccbSFrançois Tigeot out:
1429926deccbSFrançois Tigeot 	if ((!rdev->is_atom_bios) &&
1430926deccbSFrançois Tigeot 	    (ret == connector_status_disconnected) &&
1431926deccbSFrançois Tigeot 	    rdev->mode_info.bios_hardcoded_edid_size) {
1432926deccbSFrançois Tigeot 		radeon_connector->use_digital = true;
1433926deccbSFrançois Tigeot 		ret = connector_status_connected;
1434926deccbSFrançois Tigeot 	}
1435926deccbSFrançois Tigeot 
1436926deccbSFrançois Tigeot 	/* updated in get modes as well since we need to know if it's analog or digital */
1437926deccbSFrançois Tigeot 	radeon_connector_update_scratch_regs(connector, ret);
1438c6f73aabSFrançois Tigeot 
1439c59a5c48SFrançois Tigeot 	if ((radeon_audio != 0) && radeon_connector->use_digital) {
1440c59a5c48SFrançois Tigeot 		const struct drm_connector_helper_funcs *connector_funcs =
1441c59a5c48SFrançois Tigeot 			connector->helper_private;
1442c59a5c48SFrançois Tigeot 
1443c59a5c48SFrançois Tigeot 		encoder = connector_funcs->best_encoder(connector);
1444c59a5c48SFrançois Tigeot 		if (encoder && (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)) {
1445c59a5c48SFrançois Tigeot 			radeon_connector_get_edid(connector);
1446c59a5c48SFrançois Tigeot 			radeon_audio_detect(connector, encoder, ret);
1447c59a5c48SFrançois Tigeot 		}
1448c59a5c48SFrançois Tigeot 	}
1449c59a5c48SFrançois Tigeot 
1450c6f73aabSFrançois Tigeot exit:
1451*3f2dd94aSFrançois Tigeot 	if (!drm_kms_helper_is_poll_worker()) {
1452c6f73aabSFrançois Tigeot 		pm_runtime_mark_last_busy(connector->dev->dev);
1453c6f73aabSFrançois Tigeot 		pm_runtime_put_autosuspend(connector->dev->dev);
1454*3f2dd94aSFrançois Tigeot 	}
1455c6f73aabSFrançois Tigeot 
1456926deccbSFrançois Tigeot 	return ret;
1457926deccbSFrançois Tigeot }
1458926deccbSFrançois Tigeot 
1459926deccbSFrançois Tigeot /* okay need to be smart in here about which encoder to pick */
radeon_dvi_encoder(struct drm_connector * connector)1460926deccbSFrançois Tigeot static struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector)
1461926deccbSFrançois Tigeot {
1462926deccbSFrançois Tigeot 	int enc_id = connector->encoder_ids[0];
1463926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1464926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1465926deccbSFrançois Tigeot 	int i;
1466926deccbSFrançois Tigeot 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1467926deccbSFrançois Tigeot 		if (connector->encoder_ids[i] == 0)
1468926deccbSFrançois Tigeot 			break;
1469926deccbSFrançois Tigeot 
1470*3f2dd94aSFrançois Tigeot 		encoder = drm_encoder_find(connector->dev, NULL, connector->encoder_ids[i]);
1471c6f73aabSFrançois Tigeot 		if (!encoder)
1472926deccbSFrançois Tigeot 			continue;
1473926deccbSFrançois Tigeot 
1474926deccbSFrançois Tigeot 		if (radeon_connector->use_digital == true) {
1475926deccbSFrançois Tigeot 			if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
1476926deccbSFrançois Tigeot 				return encoder;
1477926deccbSFrançois Tigeot 		} else {
1478926deccbSFrançois Tigeot 			if (encoder->encoder_type == DRM_MODE_ENCODER_DAC ||
1479926deccbSFrançois Tigeot 			    encoder->encoder_type == DRM_MODE_ENCODER_TVDAC)
1480926deccbSFrançois Tigeot 				return encoder;
1481926deccbSFrançois Tigeot 		}
1482926deccbSFrançois Tigeot 	}
1483926deccbSFrançois Tigeot 
1484926deccbSFrançois Tigeot 	/* see if we have a default encoder  TODO */
1485926deccbSFrançois Tigeot 
1486926deccbSFrançois Tigeot 	/* then check use digitial */
1487926deccbSFrançois Tigeot 	/* pick the first one */
1488c6f73aabSFrançois Tigeot 	if (enc_id)
1489*3f2dd94aSFrançois Tigeot 		return drm_encoder_find(connector->dev, NULL, enc_id);
1490926deccbSFrançois Tigeot 	return NULL;
1491926deccbSFrançois Tigeot }
1492926deccbSFrançois Tigeot 
radeon_dvi_force(struct drm_connector * connector)1493926deccbSFrançois Tigeot static void radeon_dvi_force(struct drm_connector *connector)
1494926deccbSFrançois Tigeot {
1495926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1496926deccbSFrançois Tigeot 	if (connector->force == DRM_FORCE_ON)
1497926deccbSFrançois Tigeot 		radeon_connector->use_digital = false;
1498926deccbSFrançois Tigeot 	if (connector->force == DRM_FORCE_ON_DIGITAL)
1499926deccbSFrançois Tigeot 		radeon_connector->use_digital = true;
1500926deccbSFrançois Tigeot }
1501926deccbSFrançois Tigeot 
radeon_dvi_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)1502*3f2dd94aSFrançois Tigeot static int radeon_dvi_mode_valid(struct drm_connector *connector,
1503926deccbSFrançois Tigeot 				  struct drm_display_mode *mode)
1504926deccbSFrançois Tigeot {
1505926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1506926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1507926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1508926deccbSFrançois Tigeot 
1509926deccbSFrançois Tigeot 	/* XXX check mode bandwidth */
1510926deccbSFrançois Tigeot 
1511926deccbSFrançois Tigeot 	/* clocks over 135 MHz have heat issues with DVI on RV100 */
1512926deccbSFrançois Tigeot 	if (radeon_connector->use_digital &&
1513926deccbSFrançois Tigeot 	    (rdev->family == CHIP_RV100) &&
1514926deccbSFrançois Tigeot 	    (mode->clock > 135000))
1515926deccbSFrançois Tigeot 		return MODE_CLOCK_HIGH;
1516926deccbSFrançois Tigeot 
1517926deccbSFrançois Tigeot 	if (radeon_connector->use_digital && (mode->clock > 165000)) {
1518926deccbSFrançois Tigeot 		if ((radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I) ||
1519926deccbSFrançois Tigeot 		    (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D) ||
1520926deccbSFrançois Tigeot 		    (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_B))
1521926deccbSFrançois Tigeot 			return MODE_OK;
1522c6f73aabSFrançois Tigeot 		else if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
1523926deccbSFrançois Tigeot 			/* HDMI 1.3+ supports max clock of 340 Mhz */
1524926deccbSFrançois Tigeot 			if (mode->clock > 340000)
1525926deccbSFrançois Tigeot 				return MODE_CLOCK_HIGH;
1526926deccbSFrançois Tigeot 			else
1527926deccbSFrançois Tigeot 				return MODE_OK;
1528c6f73aabSFrançois Tigeot 		} else {
1529926deccbSFrançois Tigeot 			return MODE_CLOCK_HIGH;
1530c6f73aabSFrançois Tigeot 		}
1531926deccbSFrançois Tigeot 	}
1532926deccbSFrançois Tigeot 
1533926deccbSFrançois Tigeot 	/* check against the max pixel clock */
1534926deccbSFrançois Tigeot 	if ((mode->clock / 10) > rdev->clock.max_pixel_clock)
1535926deccbSFrançois Tigeot 		return MODE_CLOCK_HIGH;
1536926deccbSFrançois Tigeot 
1537926deccbSFrançois Tigeot 	return MODE_OK;
1538926deccbSFrançois Tigeot }
1539926deccbSFrançois Tigeot 
1540926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = {
1541c6f73aabSFrançois Tigeot 	.get_modes = radeon_vga_get_modes,
1542926deccbSFrançois Tigeot 	.mode_valid = radeon_dvi_mode_valid,
1543926deccbSFrançois Tigeot 	.best_encoder = radeon_dvi_encoder,
1544926deccbSFrançois Tigeot };
1545926deccbSFrançois Tigeot 
1546926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_dvi_connector_funcs = {
1547926deccbSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
1548926deccbSFrançois Tigeot 	.detect = radeon_dvi_detect,
1549926deccbSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
1550926deccbSFrançois Tigeot 	.set_property = radeon_connector_set_property,
15511dedbd3bSFrançois Tigeot 	.early_unregister = radeon_connector_unregister,
1552926deccbSFrançois Tigeot 	.destroy = radeon_connector_destroy,
1553926deccbSFrançois Tigeot 	.force = radeon_dvi_force,
1554926deccbSFrançois Tigeot };
1555926deccbSFrançois Tigeot 
radeon_dp_get_modes(struct drm_connector * connector)1556926deccbSFrançois Tigeot static int radeon_dp_get_modes(struct drm_connector *connector)
1557926deccbSFrançois Tigeot {
1558926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1559926deccbSFrançois Tigeot 	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
1560926deccbSFrançois Tigeot 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
1561926deccbSFrançois Tigeot 	int ret;
1562926deccbSFrançois Tigeot 
1563926deccbSFrançois Tigeot 	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
1564926deccbSFrançois Tigeot 	    (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
1565926deccbSFrançois Tigeot 		struct drm_display_mode *mode;
1566926deccbSFrançois Tigeot 
1567926deccbSFrançois Tigeot 		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
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_ON);
15715ef6d7b4SFrançois Tigeot 			radeon_connector_get_edid(connector);
15725ef6d7b4SFrançois Tigeot 			ret = radeon_ddc_get_modes(connector);
1573926deccbSFrançois Tigeot 			if (!radeon_dig_connector->edp_on)
1574926deccbSFrançois Tigeot 				atombios_set_edp_panel_power(connector,
1575926deccbSFrançois Tigeot 							     ATOM_TRANSMITTER_ACTION_POWER_OFF);
1576926deccbSFrançois Tigeot 		} else {
1577926deccbSFrançois Tigeot 			/* need to setup ddc on the bridge */
1578926deccbSFrançois Tigeot 			if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
1579926deccbSFrançois Tigeot 			    ENCODER_OBJECT_ID_NONE) {
1580926deccbSFrançois Tigeot 				if (encoder)
1581926deccbSFrançois Tigeot 					radeon_atom_ext_encoder_setup_ddc(encoder);
1582926deccbSFrançois Tigeot 			}
15835ef6d7b4SFrançois Tigeot 			radeon_connector_get_edid(connector);
15845ef6d7b4SFrançois Tigeot 			ret = radeon_ddc_get_modes(connector);
1585926deccbSFrançois Tigeot 		}
1586926deccbSFrançois Tigeot 
1587926deccbSFrançois Tigeot 		if (ret > 0) {
1588926deccbSFrançois Tigeot 			if (encoder) {
1589926deccbSFrançois Tigeot 				radeon_fixup_lvds_native_mode(encoder, connector);
1590926deccbSFrançois Tigeot 				/* add scaled modes */
1591926deccbSFrançois Tigeot 				radeon_add_common_modes(encoder, connector);
1592926deccbSFrançois Tigeot 			}
1593926deccbSFrançois Tigeot 			return ret;
1594926deccbSFrançois Tigeot 		}
1595926deccbSFrançois Tigeot 
1596926deccbSFrançois Tigeot 		if (!encoder)
1597926deccbSFrançois Tigeot 			return 0;
1598926deccbSFrançois Tigeot 
1599926deccbSFrançois Tigeot 		/* we have no EDID modes */
1600926deccbSFrançois Tigeot 		mode = radeon_fp_native_mode(encoder);
1601926deccbSFrançois Tigeot 		if (mode) {
1602926deccbSFrançois Tigeot 			ret = 1;
1603926deccbSFrançois Tigeot 			drm_mode_probed_add(connector, mode);
1604926deccbSFrançois Tigeot 			/* add the width/height from vbios tables if available */
1605926deccbSFrançois Tigeot 			connector->display_info.width_mm = mode->width_mm;
1606926deccbSFrançois Tigeot 			connector->display_info.height_mm = mode->height_mm;
1607926deccbSFrançois Tigeot 			/* add scaled modes */
1608926deccbSFrançois Tigeot 			radeon_add_common_modes(encoder, connector);
1609926deccbSFrançois Tigeot 		}
1610926deccbSFrançois Tigeot 	} else {
1611926deccbSFrançois Tigeot 		/* need to setup ddc on the bridge */
1612926deccbSFrançois Tigeot 		if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
1613926deccbSFrançois Tigeot 			ENCODER_OBJECT_ID_NONE) {
1614926deccbSFrançois Tigeot 			if (encoder)
1615926deccbSFrançois Tigeot 				radeon_atom_ext_encoder_setup_ddc(encoder);
1616926deccbSFrançois Tigeot 		}
16175ef6d7b4SFrançois Tigeot 		radeon_connector_get_edid(connector);
16185ef6d7b4SFrançois Tigeot 		ret = radeon_ddc_get_modes(connector);
1619c6f73aabSFrançois Tigeot 
1620c6f73aabSFrançois Tigeot 		radeon_get_native_mode(connector);
1621926deccbSFrançois Tigeot 	}
1622926deccbSFrançois Tigeot 
1623926deccbSFrançois Tigeot 	return ret;
1624926deccbSFrançois Tigeot }
1625926deccbSFrançois Tigeot 
radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector * connector)1626926deccbSFrançois Tigeot u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector)
1627926deccbSFrançois Tigeot {
1628926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1629926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
1630926deccbSFrançois Tigeot 	int i;
1631926deccbSFrançois Tigeot 
1632926deccbSFrançois Tigeot 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1633926deccbSFrançois Tigeot 		if (connector->encoder_ids[i] == 0)
1634926deccbSFrançois Tigeot 			break;
1635926deccbSFrançois Tigeot 
1636*3f2dd94aSFrançois Tigeot 		encoder = drm_encoder_find(connector->dev, NULL, connector->encoder_ids[i]);
1637c6f73aabSFrançois Tigeot 		if (!encoder)
1638926deccbSFrançois Tigeot 			continue;
1639926deccbSFrançois Tigeot 
1640926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
1641926deccbSFrançois Tigeot 
1642926deccbSFrançois Tigeot 		switch (radeon_encoder->encoder_id) {
1643926deccbSFrançois Tigeot 		case ENCODER_OBJECT_ID_TRAVIS:
1644926deccbSFrançois Tigeot 		case ENCODER_OBJECT_ID_NUTMEG:
1645926deccbSFrançois Tigeot 			return radeon_encoder->encoder_id;
1646926deccbSFrançois Tigeot 		default:
1647926deccbSFrançois Tigeot 			break;
1648926deccbSFrançois Tigeot 		}
1649926deccbSFrançois Tigeot 	}
1650926deccbSFrançois Tigeot 
1651926deccbSFrançois Tigeot 	return ENCODER_OBJECT_ID_NONE;
1652926deccbSFrançois Tigeot }
1653926deccbSFrançois Tigeot 
radeon_connector_encoder_is_hbr2(struct drm_connector * connector)1654c6f73aabSFrançois Tigeot static bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector)
1655926deccbSFrançois Tigeot {
1656926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1657926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
1658926deccbSFrançois Tigeot 	int i;
1659926deccbSFrançois Tigeot 	bool found = false;
1660926deccbSFrançois Tigeot 
1661926deccbSFrançois Tigeot 	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1662926deccbSFrançois Tigeot 		if (connector->encoder_ids[i] == 0)
1663926deccbSFrançois Tigeot 			break;
1664926deccbSFrançois Tigeot 
1665*3f2dd94aSFrançois Tigeot 		encoder = drm_encoder_find(connector->dev, NULL, connector->encoder_ids[i]);
1666c6f73aabSFrançois Tigeot 		if (!encoder)
1667926deccbSFrançois Tigeot 			continue;
1668926deccbSFrançois Tigeot 
1669926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
1670926deccbSFrançois Tigeot 		if (radeon_encoder->caps & ATOM_ENCODER_CAP_RECORD_HBR2)
1671926deccbSFrançois Tigeot 			found = true;
1672926deccbSFrançois Tigeot 	}
1673926deccbSFrançois Tigeot 
1674926deccbSFrançois Tigeot 	return found;
1675926deccbSFrançois Tigeot }
1676926deccbSFrançois Tigeot 
radeon_connector_is_dp12_capable(struct drm_connector * connector)1677926deccbSFrançois Tigeot bool radeon_connector_is_dp12_capable(struct drm_connector *connector)
1678926deccbSFrançois Tigeot {
1679926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1680926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1681926deccbSFrançois Tigeot 
1682926deccbSFrançois Tigeot 	if (ASIC_IS_DCE5(rdev) &&
1683c6f73aabSFrançois Tigeot 	    (rdev->clock.default_dispclk >= 53900) &&
1684926deccbSFrançois Tigeot 	    radeon_connector_encoder_is_hbr2(connector)) {
1685926deccbSFrançois Tigeot 		return true;
1686926deccbSFrançois Tigeot 	}
1687926deccbSFrançois Tigeot 
1688926deccbSFrançois Tigeot 	return false;
1689926deccbSFrançois Tigeot }
1690926deccbSFrançois Tigeot 
1691926deccbSFrançois Tigeot static enum drm_connector_status
radeon_dp_detect(struct drm_connector * connector,bool force)1692926deccbSFrançois Tigeot radeon_dp_detect(struct drm_connector *connector, bool force)
1693926deccbSFrançois Tigeot {
1694926deccbSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1695926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1696926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1697926deccbSFrançois Tigeot 	enum drm_connector_status ret = connector_status_disconnected;
1698926deccbSFrançois Tigeot 	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
1699926deccbSFrançois Tigeot 	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
1700c6f73aabSFrançois Tigeot 	int r;
1701926deccbSFrançois Tigeot 
1702c59a5c48SFrançois Tigeot 	if (radeon_dig_connector->is_mst)
1703c59a5c48SFrançois Tigeot 		return connector_status_disconnected;
1704c59a5c48SFrançois Tigeot 
1705*3f2dd94aSFrançois Tigeot 	if (!drm_kms_helper_is_poll_worker()) {
1706c6f73aabSFrançois Tigeot 		r = pm_runtime_get_sync(connector->dev->dev);
1707c6f73aabSFrançois Tigeot 		if (r < 0)
1708c6f73aabSFrançois Tigeot 			return connector_status_disconnected;
1709*3f2dd94aSFrançois Tigeot 	}
1710c6f73aabSFrançois Tigeot 
1711c6f73aabSFrançois Tigeot 	if (!force && radeon_check_hpd_status_unchanged(connector)) {
1712c6f73aabSFrançois Tigeot 		ret = connector->status;
1713c6f73aabSFrançois Tigeot 		goto out;
1714c6f73aabSFrançois Tigeot 	}
1715926deccbSFrançois Tigeot 
17165ef6d7b4SFrançois Tigeot 	radeon_connector_free_edid(connector);
1717926deccbSFrançois Tigeot 
1718926deccbSFrançois Tigeot 	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
1719926deccbSFrançois Tigeot 	    (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
1720926deccbSFrançois Tigeot 		if (encoder) {
1721926deccbSFrançois Tigeot 			struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
1722926deccbSFrançois Tigeot 			struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
1723926deccbSFrançois Tigeot 
1724926deccbSFrançois Tigeot 			/* check if panel is valid */
1725926deccbSFrançois Tigeot 			if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
1726926deccbSFrançois Tigeot 				ret = connector_status_connected;
17271cfef1a5SFrançois Tigeot 			/* don't fetch the edid from the vbios if ddc fails and runpm is
17281cfef1a5SFrançois Tigeot 			 * enabled so we report disconnected.
17291cfef1a5SFrançois Tigeot 			 */
17301cfef1a5SFrançois Tigeot 			if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0))
17311cfef1a5SFrançois Tigeot 				ret = connector_status_disconnected;
1732926deccbSFrançois Tigeot 		}
1733926deccbSFrançois Tigeot 		/* eDP is always DP */
1734926deccbSFrançois Tigeot 		radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
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_ON);
1738926deccbSFrançois Tigeot 		if (radeon_dp_getdpcd(radeon_connector))
1739926deccbSFrançois Tigeot 			ret = connector_status_connected;
1740926deccbSFrançois Tigeot 		if (!radeon_dig_connector->edp_on)
1741926deccbSFrançois Tigeot 			atombios_set_edp_panel_power(connector,
1742926deccbSFrançois Tigeot 						     ATOM_TRANSMITTER_ACTION_POWER_OFF);
1743926deccbSFrançois Tigeot 	} else if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
1744926deccbSFrançois Tigeot 		   ENCODER_OBJECT_ID_NONE) {
1745926deccbSFrançois Tigeot 		/* DP bridges are always DP */
1746926deccbSFrançois Tigeot 		radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
1747926deccbSFrançois Tigeot 		/* get the DPCD from the bridge */
1748926deccbSFrançois Tigeot 		radeon_dp_getdpcd(radeon_connector);
1749926deccbSFrançois Tigeot 
1750926deccbSFrançois Tigeot 		if (encoder) {
1751926deccbSFrançois Tigeot 			/* setup ddc on the bridge */
1752926deccbSFrançois Tigeot 			radeon_atom_ext_encoder_setup_ddc(encoder);
1753926deccbSFrançois Tigeot 			/* bridge chips are always aux */
1754926deccbSFrançois Tigeot 			if (radeon_ddc_probe(radeon_connector, true)) /* try DDC */
1755926deccbSFrançois Tigeot 				ret = connector_status_connected;
1756926deccbSFrançois Tigeot 			else if (radeon_connector->dac_load_detect) { /* try load detection */
1757c0e85e96SFrançois Tigeot 				const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
1758926deccbSFrançois Tigeot 				ret = encoder_funcs->detect(encoder, connector);
1759926deccbSFrançois Tigeot 			}
1760926deccbSFrançois Tigeot 		}
1761926deccbSFrançois Tigeot 	} else {
1762926deccbSFrançois Tigeot 		radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
1763926deccbSFrançois Tigeot 		if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
1764926deccbSFrançois Tigeot 			ret = connector_status_connected;
1765c59a5c48SFrançois Tigeot 			if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
1766926deccbSFrançois Tigeot 				radeon_dp_getdpcd(radeon_connector);
1767c59a5c48SFrançois Tigeot 				r = radeon_dp_mst_probe(radeon_connector);
1768c59a5c48SFrançois Tigeot 				if (r == 1)
1769c59a5c48SFrançois Tigeot 					ret = connector_status_disconnected;
1770c59a5c48SFrançois Tigeot 			}
1771926deccbSFrançois Tigeot 		} else {
1772926deccbSFrançois Tigeot 			if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
1773c59a5c48SFrançois Tigeot 				if (radeon_dp_getdpcd(radeon_connector)) {
1774c59a5c48SFrançois Tigeot 					r = radeon_dp_mst_probe(radeon_connector);
1775c59a5c48SFrançois Tigeot 					if (r == 1)
1776c59a5c48SFrançois Tigeot 						ret = connector_status_disconnected;
1777c59a5c48SFrançois Tigeot 					else
1778926deccbSFrançois Tigeot 						ret = connector_status_connected;
1779c59a5c48SFrançois Tigeot 				}
1780926deccbSFrançois Tigeot 			} else {
17814cd92098Szrj 				/* try non-aux ddc (DP to DVI/HDMI/etc. adapter) */
1782926deccbSFrançois Tigeot 				if (radeon_ddc_probe(radeon_connector, false))
1783926deccbSFrançois Tigeot 					ret = connector_status_connected;
1784926deccbSFrançois Tigeot 			}
1785926deccbSFrançois Tigeot 		}
1786926deccbSFrançois Tigeot 	}
1787926deccbSFrançois Tigeot 
1788926deccbSFrançois Tigeot 	radeon_connector_update_scratch_regs(connector, ret);
1789c59a5c48SFrançois Tigeot 
1790c59a5c48SFrançois Tigeot 	if ((radeon_audio != 0) && encoder) {
1791c59a5c48SFrançois Tigeot 		radeon_connector_get_edid(connector);
1792c59a5c48SFrançois Tigeot 		radeon_audio_detect(connector, encoder, ret);
1793c59a5c48SFrançois Tigeot 	}
1794c59a5c48SFrançois Tigeot 
1795c6f73aabSFrançois Tigeot out:
1796*3f2dd94aSFrançois Tigeot 	if (!drm_kms_helper_is_poll_worker()) {
1797c6f73aabSFrançois Tigeot 		pm_runtime_mark_last_busy(connector->dev->dev);
1798c6f73aabSFrançois Tigeot 		pm_runtime_put_autosuspend(connector->dev->dev);
1799*3f2dd94aSFrançois Tigeot 	}
1800c6f73aabSFrançois Tigeot 
1801926deccbSFrançois Tigeot 	return ret;
1802926deccbSFrançois Tigeot }
1803926deccbSFrançois Tigeot 
radeon_dp_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)1804*3f2dd94aSFrançois Tigeot static int radeon_dp_mode_valid(struct drm_connector *connector,
1805926deccbSFrançois Tigeot 				  struct drm_display_mode *mode)
1806926deccbSFrançois Tigeot {
1807c6f73aabSFrançois Tigeot 	struct drm_device *dev = connector->dev;
1808c6f73aabSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1809926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1810926deccbSFrançois Tigeot 	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
1811926deccbSFrançois Tigeot 
1812926deccbSFrançois Tigeot 	/* XXX check mode bandwidth */
1813926deccbSFrançois Tigeot 
1814926deccbSFrançois Tigeot 	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
1815926deccbSFrançois Tigeot 	    (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
1816926deccbSFrançois Tigeot 		struct drm_encoder *encoder = radeon_best_single_encoder(connector);
1817926deccbSFrançois Tigeot 
1818926deccbSFrançois Tigeot 		if ((mode->hdisplay < 320) || (mode->vdisplay < 240))
1819926deccbSFrançois Tigeot 			return MODE_PANEL;
1820926deccbSFrançois Tigeot 
1821926deccbSFrançois Tigeot 		if (encoder) {
1822926deccbSFrançois Tigeot 			struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
1823926deccbSFrançois Tigeot 			struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
1824926deccbSFrançois Tigeot 
1825926deccbSFrançois Tigeot 			/* AVIVO hardware supports downscaling modes larger than the panel
1826926deccbSFrançois Tigeot 			 * to the panel size, but I'm not sure this is desirable.
1827926deccbSFrançois Tigeot 			 */
1828926deccbSFrançois Tigeot 			if ((mode->hdisplay > native_mode->hdisplay) ||
1829926deccbSFrançois Tigeot 			    (mode->vdisplay > native_mode->vdisplay))
1830926deccbSFrançois Tigeot 				return MODE_PANEL;
1831926deccbSFrançois Tigeot 
1832926deccbSFrançois Tigeot 			/* if scaling is disabled, block non-native modes */
1833926deccbSFrançois Tigeot 			if (radeon_encoder->rmx_type == RMX_OFF) {
1834926deccbSFrançois Tigeot 				if ((mode->hdisplay != native_mode->hdisplay) ||
1835926deccbSFrançois Tigeot 				    (mode->vdisplay != native_mode->vdisplay))
1836926deccbSFrançois Tigeot 					return MODE_PANEL;
1837926deccbSFrançois Tigeot 			}
1838926deccbSFrançois Tigeot 		}
1839926deccbSFrançois Tigeot 	} else {
1840926deccbSFrançois Tigeot 		if ((radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
1841c6f73aabSFrançois Tigeot 		    (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
1842926deccbSFrançois Tigeot 			return radeon_dp_mode_valid_helper(connector, mode);
1843c6f73aabSFrançois Tigeot 		} else {
1844c6f73aabSFrançois Tigeot 			if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
1845c6f73aabSFrançois Tigeot 				/* HDMI 1.3+ supports max clock of 340 Mhz */
1846c6f73aabSFrançois Tigeot 				if (mode->clock > 340000)
1847c6f73aabSFrançois Tigeot 					return MODE_CLOCK_HIGH;
1848c6f73aabSFrançois Tigeot 			} else {
1849c6f73aabSFrançois Tigeot 				if (mode->clock > 165000)
1850c6f73aabSFrançois Tigeot 					return MODE_CLOCK_HIGH;
1851926deccbSFrançois Tigeot 			}
1852926deccbSFrançois Tigeot 		}
1853c6f73aabSFrançois Tigeot 	}
1854c6f73aabSFrançois Tigeot 
1855c6f73aabSFrançois Tigeot 	return MODE_OK;
1856c6f73aabSFrançois Tigeot }
1857926deccbSFrançois Tigeot 
1858926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_dp_connector_helper_funcs = {
1859926deccbSFrançois Tigeot 	.get_modes = radeon_dp_get_modes,
1860926deccbSFrançois Tigeot 	.mode_valid = radeon_dp_mode_valid,
1861926deccbSFrançois Tigeot 	.best_encoder = radeon_dvi_encoder,
1862926deccbSFrançois Tigeot };
1863926deccbSFrançois Tigeot 
1864926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_dp_connector_funcs = {
1865926deccbSFrançois Tigeot 	.dpms = drm_helper_connector_dpms,
1866926deccbSFrançois Tigeot 	.detect = radeon_dp_detect,
1867926deccbSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
1868926deccbSFrançois Tigeot 	.set_property = radeon_connector_set_property,
18691dedbd3bSFrançois Tigeot 	.early_unregister = radeon_connector_unregister,
18705ef6d7b4SFrançois Tigeot 	.destroy = radeon_connector_destroy,
1871926deccbSFrançois Tigeot 	.force = radeon_dvi_force,
1872926deccbSFrançois Tigeot };
1873926deccbSFrançois Tigeot 
18744cd92098Szrj static const struct drm_connector_funcs radeon_edp_connector_funcs = {
18754cd92098Szrj 	.dpms = drm_helper_connector_dpms,
18764cd92098Szrj 	.detect = radeon_dp_detect,
18774cd92098Szrj 	.fill_modes = drm_helper_probe_single_connector_modes,
18784cd92098Szrj 	.set_property = radeon_lvds_set_property,
18791dedbd3bSFrançois Tigeot 	.early_unregister = radeon_connector_unregister,
18805ef6d7b4SFrançois Tigeot 	.destroy = radeon_connector_destroy,
18814cd92098Szrj 	.force = radeon_dvi_force,
18824cd92098Szrj };
18834cd92098Szrj 
18844cd92098Szrj static const struct drm_connector_funcs radeon_lvds_bridge_connector_funcs = {
18854cd92098Szrj 	.dpms = drm_helper_connector_dpms,
18864cd92098Szrj 	.detect = radeon_dp_detect,
18874cd92098Szrj 	.fill_modes = drm_helper_probe_single_connector_modes,
18884cd92098Szrj 	.set_property = radeon_lvds_set_property,
1889*3f2dd94aSFrançois Tigeot 	.early_unregister = radeon_connector_unregister,
18905ef6d7b4SFrançois Tigeot 	.destroy = radeon_connector_destroy,
18914cd92098Szrj 	.force = radeon_dvi_force,
18924cd92098Szrj };
18934cd92098Szrj 
1894926deccbSFrançois Tigeot void
radeon_add_atom_connector(struct drm_device * dev,uint32_t connector_id,uint32_t supported_device,int connector_type,struct radeon_i2c_bus_rec * i2c_bus,uint32_t igp_lane_info,uint16_t connector_object_id,struct radeon_hpd * hpd,struct radeon_router * router)1895926deccbSFrançois Tigeot radeon_add_atom_connector(struct drm_device *dev,
1896926deccbSFrançois Tigeot 			  uint32_t connector_id,
1897926deccbSFrançois Tigeot 			  uint32_t supported_device,
1898926deccbSFrançois Tigeot 			  int connector_type,
1899926deccbSFrançois Tigeot 			  struct radeon_i2c_bus_rec *i2c_bus,
1900926deccbSFrançois Tigeot 			  uint32_t igp_lane_info,
1901926deccbSFrançois Tigeot 			  uint16_t connector_object_id,
1902926deccbSFrançois Tigeot 			  struct radeon_hpd *hpd,
1903926deccbSFrançois Tigeot 			  struct radeon_router *router)
1904926deccbSFrançois Tigeot {
1905926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
1906926deccbSFrançois Tigeot 	struct drm_connector *connector;
1907926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector;
1908926deccbSFrançois Tigeot 	struct radeon_connector_atom_dig *radeon_dig_connector;
1909926deccbSFrançois Tigeot 	struct drm_encoder *encoder;
1910926deccbSFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
1911926deccbSFrançois Tigeot 	uint32_t subpixel_order = SubPixelNone;
1912926deccbSFrançois Tigeot 	bool shared_ddc = false;
1913926deccbSFrançois Tigeot 	bool is_dp_bridge = false;
19147191d616Szrj 	bool has_aux = false;
1915926deccbSFrançois Tigeot 
1916926deccbSFrançois Tigeot 	if (connector_type == DRM_MODE_CONNECTOR_Unknown)
1917926deccbSFrançois Tigeot 		return;
1918926deccbSFrançois Tigeot 
1919926deccbSFrançois Tigeot 	/* if the user selected tv=0 don't try and add the connector */
1920926deccbSFrançois Tigeot 	if (((connector_type == DRM_MODE_CONNECTOR_SVIDEO) ||
1921926deccbSFrançois Tigeot 	     (connector_type == DRM_MODE_CONNECTOR_Composite) ||
1922926deccbSFrançois Tigeot 	     (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) &&
1923926deccbSFrançois Tigeot 	    (radeon_tv == 0))
1924926deccbSFrançois Tigeot 		return;
1925926deccbSFrançois Tigeot 
1926926deccbSFrançois Tigeot 	/* see if we already added it */
1927926deccbSFrançois Tigeot 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1928926deccbSFrançois Tigeot 		radeon_connector = to_radeon_connector(connector);
1929926deccbSFrançois Tigeot 		if (radeon_connector->connector_id == connector_id) {
1930926deccbSFrançois Tigeot 			radeon_connector->devices |= supported_device;
1931926deccbSFrançois Tigeot 			return;
1932926deccbSFrançois Tigeot 		}
1933926deccbSFrançois Tigeot 		if (radeon_connector->ddc_bus && i2c_bus->valid) {
1934926deccbSFrançois Tigeot 			if (radeon_connector->ddc_bus->rec.i2c_id == i2c_bus->i2c_id) {
1935926deccbSFrançois Tigeot 				radeon_connector->shared_ddc = true;
1936926deccbSFrançois Tigeot 				shared_ddc = true;
1937926deccbSFrançois Tigeot 			}
1938926deccbSFrançois Tigeot 			if (radeon_connector->router_bus && router->ddc_valid &&
1939926deccbSFrançois Tigeot 			    (radeon_connector->router.router_id == router->router_id)) {
1940926deccbSFrançois Tigeot 				radeon_connector->shared_ddc = false;
1941926deccbSFrançois Tigeot 				shared_ddc = false;
1942926deccbSFrançois Tigeot 			}
1943926deccbSFrançois Tigeot 		}
1944926deccbSFrançois Tigeot 	}
1945926deccbSFrançois Tigeot 
1946926deccbSFrançois Tigeot 	/* check if it's a dp bridge */
1947926deccbSFrançois Tigeot 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
1948926deccbSFrançois Tigeot 		radeon_encoder = to_radeon_encoder(encoder);
1949926deccbSFrançois Tigeot 		if (radeon_encoder->devices & supported_device) {
1950926deccbSFrançois Tigeot 			switch (radeon_encoder->encoder_id) {
1951926deccbSFrançois Tigeot 			case ENCODER_OBJECT_ID_TRAVIS:
1952926deccbSFrançois Tigeot 			case ENCODER_OBJECT_ID_NUTMEG:
1953926deccbSFrançois Tigeot 				is_dp_bridge = true;
1954926deccbSFrançois Tigeot 				break;
1955926deccbSFrançois Tigeot 			default:
1956926deccbSFrançois Tigeot 				break;
1957926deccbSFrançois Tigeot 			}
1958926deccbSFrançois Tigeot 		}
1959926deccbSFrançois Tigeot 	}
1960926deccbSFrançois Tigeot 
1961c4ef309bSzrj 	radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL);
1962926deccbSFrançois Tigeot 	if (!radeon_connector)
1963926deccbSFrançois Tigeot 		return;
1964926deccbSFrançois Tigeot 
1965926deccbSFrançois Tigeot 	connector = &radeon_connector->base;
1966926deccbSFrançois Tigeot 
1967926deccbSFrançois Tigeot 	radeon_connector->connector_id = connector_id;
1968926deccbSFrançois Tigeot 	radeon_connector->devices = supported_device;
1969926deccbSFrançois Tigeot 	radeon_connector->shared_ddc = shared_ddc;
1970926deccbSFrançois Tigeot 	radeon_connector->connector_object_id = connector_object_id;
1971926deccbSFrançois Tigeot 	radeon_connector->hpd = *hpd;
1972926deccbSFrançois Tigeot 
1973926deccbSFrançois Tigeot 	radeon_connector->router = *router;
1974926deccbSFrançois Tigeot 	if (router->ddc_valid || router->cd_valid) {
1975926deccbSFrançois Tigeot 		radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info);
1976926deccbSFrançois Tigeot 		if (!radeon_connector->router_bus)
1977926deccbSFrançois Tigeot 			DRM_ERROR("Failed to assign router i2c bus! Check dmesg for i2c errors.\n");
1978926deccbSFrançois Tigeot 	}
1979926deccbSFrançois Tigeot 
1980926deccbSFrançois Tigeot 	if (is_dp_bridge) {
1981c4ef309bSzrj 		radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
1982926deccbSFrançois Tigeot 		if (!radeon_dig_connector)
1983926deccbSFrançois Tigeot 			goto failed;
1984926deccbSFrançois Tigeot 		radeon_dig_connector->igp_lane_info = igp_lane_info;
1985926deccbSFrançois Tigeot 		radeon_connector->con_priv = radeon_dig_connector;
1986926deccbSFrançois Tigeot 		if (i2c_bus->valid) {
19875ef6d7b4SFrançois Tigeot 			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
19885ef6d7b4SFrançois Tigeot 			if (radeon_connector->ddc_bus)
19897191d616Szrj 				has_aux = true;
19907191d616Szrj 			else
1991926deccbSFrançois Tigeot 				DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
1992926deccbSFrançois Tigeot 		}
1993926deccbSFrançois Tigeot 		switch (connector_type) {
1994926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_VGA:
1995926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVIA:
1996926deccbSFrançois Tigeot 		default:
19974cd92098Szrj 			drm_connector_init(dev, &radeon_connector->base,
19984cd92098Szrj 					   &radeon_dp_connector_funcs, connector_type);
19994cd92098Szrj 			drm_connector_helper_add(&radeon_connector->base,
20004cd92098Szrj 						 &radeon_dp_connector_helper_funcs);
2001926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2002926deccbSFrançois Tigeot 			connector->doublescan_allowed = true;
2003926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
2004b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2005926deccbSFrançois Tigeot 						      rdev->mode_info.load_detect_property,
2006926deccbSFrançois Tigeot 						      1);
2007c6f73aabSFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2008c6f73aabSFrançois Tigeot 						   dev->mode_config.scaling_mode_property,
2009c6f73aabSFrançois Tigeot 						   DRM_MODE_SCALE_NONE);
2010c59a5c48SFrançois Tigeot 			if (ASIC_IS_DCE5(rdev))
2011c59a5c48SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2012c59a5c48SFrançois Tigeot 							   rdev->mode_info.output_csc_property,
2013c59a5c48SFrançois Tigeot 							   RADEON_OUTPUT_CSC_BYPASS);
2014926deccbSFrançois Tigeot 			break;
2015926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVII:
2016926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVID:
2017926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_HDMIA:
2018926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_HDMIB:
2019926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DisplayPort:
20204cd92098Szrj 			drm_connector_init(dev, &radeon_connector->base,
20214cd92098Szrj 					   &radeon_dp_connector_funcs, connector_type);
20224cd92098Szrj 			drm_connector_helper_add(&radeon_connector->base,
20234cd92098Szrj 						 &radeon_dp_connector_helper_funcs);
2024b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2025926deccbSFrançois Tigeot 						      rdev->mode_info.underscan_property,
2026926deccbSFrançois Tigeot 						      UNDERSCAN_OFF);
2027b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2028926deccbSFrançois Tigeot 						      rdev->mode_info.underscan_hborder_property,
2029926deccbSFrançois Tigeot 						      0);
2030b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2031926deccbSFrançois Tigeot 						      rdev->mode_info.underscan_vborder_property,
2032926deccbSFrançois Tigeot 						      0);
2033c6f73aabSFrançois Tigeot 
2034c6f73aabSFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2035c6f73aabSFrançois Tigeot 						      dev->mode_config.scaling_mode_property,
2036c6f73aabSFrançois Tigeot 						      DRM_MODE_SCALE_NONE);
2037c6f73aabSFrançois Tigeot 
2038c6f73aabSFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2039c6f73aabSFrançois Tigeot 						   rdev->mode_info.dither_property,
2040c6f73aabSFrançois Tigeot 						   RADEON_FMT_DITHER_DISABLE);
2041c6f73aabSFrançois Tigeot 
2042c59a5c48SFrançois Tigeot 			if (radeon_audio != 0) {
20434cd92098Szrj 				drm_object_attach_property(&radeon_connector->base.base,
20444cd92098Szrj 							   rdev->mode_info.audio_property,
2045c6f73aabSFrançois Tigeot 							   RADEON_AUDIO_AUTO);
2046c59a5c48SFrançois Tigeot 				radeon_connector->audio = RADEON_AUDIO_AUTO;
2047c59a5c48SFrançois Tigeot 			}
2048c59a5c48SFrançois Tigeot 			if (ASIC_IS_DCE5(rdev))
2049c59a5c48SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2050c59a5c48SFrançois Tigeot 							   rdev->mode_info.output_csc_property,
2051c59a5c48SFrançois Tigeot 							   RADEON_OUTPUT_CSC_BYPASS);
2052c6f73aabSFrançois Tigeot 
2053926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2054926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2055926deccbSFrançois Tigeot 			if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
2056926deccbSFrançois Tigeot 				connector->doublescan_allowed = true;
2057926deccbSFrançois Tigeot 			else
2058926deccbSFrançois Tigeot 				connector->doublescan_allowed = false;
2059926deccbSFrançois Tigeot 			if (connector_type == DRM_MODE_CONNECTOR_DVII) {
2060926deccbSFrançois Tigeot 				radeon_connector->dac_load_detect = true;
2061b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2062926deccbSFrançois Tigeot 							      rdev->mode_info.load_detect_property,
2063926deccbSFrançois Tigeot 							      1);
2064926deccbSFrançois Tigeot 			}
2065926deccbSFrançois Tigeot 			break;
2066926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_LVDS:
2067926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_eDP:
20684cd92098Szrj 			drm_connector_init(dev, &radeon_connector->base,
20694cd92098Szrj 					   &radeon_lvds_bridge_connector_funcs, connector_type);
20704cd92098Szrj 			drm_connector_helper_add(&radeon_connector->base,
20714cd92098Szrj 						 &radeon_dp_connector_helper_funcs);
2072b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2073926deccbSFrançois Tigeot 						      dev->mode_config.scaling_mode_property,
2074926deccbSFrançois Tigeot 						      DRM_MODE_SCALE_FULLSCREEN);
2075926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2076926deccbSFrançois Tigeot 			connector->interlace_allowed = false;
2077926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2078926deccbSFrançois Tigeot 			break;
2079926deccbSFrançois Tigeot 		}
2080926deccbSFrançois Tigeot 	} else {
2081926deccbSFrançois Tigeot 		switch (connector_type) {
2082926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_VGA:
2083926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
2084926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
2085926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2086926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2087926deccbSFrançois Tigeot 				if (!radeon_connector->ddc_bus)
2088926deccbSFrançois Tigeot 					DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2089926deccbSFrançois Tigeot 			}
2090926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
2091b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2092926deccbSFrançois Tigeot 						      rdev->mode_info.load_detect_property,
2093926deccbSFrançois Tigeot 						      1);
2094c6f73aabSFrançois Tigeot 			if (ASIC_IS_AVIVO(rdev))
2095c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2096c6f73aabSFrançois Tigeot 							   dev->mode_config.scaling_mode_property,
2097c6f73aabSFrançois Tigeot 							   DRM_MODE_SCALE_NONE);
2098c59a5c48SFrançois Tigeot 			if (ASIC_IS_DCE5(rdev))
2099c59a5c48SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2100c59a5c48SFrançois Tigeot 							   rdev->mode_info.output_csc_property,
2101c59a5c48SFrançois Tigeot 							   RADEON_OUTPUT_CSC_BYPASS);
2102926deccbSFrançois Tigeot 			/* no HPD on analog connectors */
2103926deccbSFrançois Tigeot 			radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2104926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2105926deccbSFrançois Tigeot 			connector->doublescan_allowed = true;
2106926deccbSFrançois Tigeot 			break;
2107926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVIA:
2108926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
2109926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
2110926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2111926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2112926deccbSFrançois Tigeot 				if (!radeon_connector->ddc_bus)
2113926deccbSFrançois Tigeot 					DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2114926deccbSFrançois Tigeot 			}
2115926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
2116b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2117926deccbSFrançois Tigeot 						      rdev->mode_info.load_detect_property,
2118926deccbSFrançois Tigeot 						      1);
2119c6f73aabSFrançois Tigeot 			if (ASIC_IS_AVIVO(rdev))
2120c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2121c6f73aabSFrançois Tigeot 							   dev->mode_config.scaling_mode_property,
2122c6f73aabSFrançois Tigeot 							   DRM_MODE_SCALE_NONE);
2123c59a5c48SFrançois Tigeot 			if (ASIC_IS_DCE5(rdev))
2124c59a5c48SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2125c59a5c48SFrançois Tigeot 							   rdev->mode_info.output_csc_property,
2126c59a5c48SFrançois Tigeot 							   RADEON_OUTPUT_CSC_BYPASS);
2127926deccbSFrançois Tigeot 			/* no HPD on analog connectors */
2128926deccbSFrançois Tigeot 			radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2129926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2130926deccbSFrançois Tigeot 			connector->doublescan_allowed = true;
2131926deccbSFrançois Tigeot 			break;
2132926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVII:
2133926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DVID:
2134c4ef309bSzrj 			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
2135926deccbSFrançois Tigeot 			if (!radeon_dig_connector)
2136926deccbSFrançois Tigeot 				goto failed;
2137926deccbSFrançois Tigeot 			radeon_dig_connector->igp_lane_info = igp_lane_info;
2138926deccbSFrançois Tigeot 			radeon_connector->con_priv = radeon_dig_connector;
2139926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
2140926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
2141926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2142926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2143926deccbSFrançois Tigeot 				if (!radeon_connector->ddc_bus)
2144926deccbSFrançois Tigeot 					DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2145926deccbSFrançois Tigeot 			}
2146926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2147b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2148926deccbSFrançois Tigeot 						      rdev->mode_info.coherent_mode_property,
2149926deccbSFrançois Tigeot 						      1);
2150926deccbSFrançois Tigeot 			if (ASIC_IS_AVIVO(rdev)) {
2151b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2152926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_property,
2153926deccbSFrançois Tigeot 							      UNDERSCAN_OFF);
2154b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2155926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_hborder_property,
2156926deccbSFrançois Tigeot 							      0);
2157b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2158926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_vborder_property,
2159926deccbSFrançois Tigeot 							      0);
2160c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2161c6f73aabSFrançois Tigeot 							   rdev->mode_info.dither_property,
2162c6f73aabSFrançois Tigeot 							   RADEON_FMT_DITHER_DISABLE);
2163c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2164c6f73aabSFrançois Tigeot 							   dev->mode_config.scaling_mode_property,
2165c6f73aabSFrançois Tigeot 							   DRM_MODE_SCALE_NONE);
2166926deccbSFrançois Tigeot 			}
21674cd92098Szrj 			if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
21684cd92098Szrj 				drm_object_attach_property(&radeon_connector->base.base,
21694cd92098Szrj 							   rdev->mode_info.audio_property,
2170c6f73aabSFrançois Tigeot 							   RADEON_AUDIO_AUTO);
2171c59a5c48SFrançois Tigeot 				radeon_connector->audio = RADEON_AUDIO_AUTO;
21724cd92098Szrj 			}
2173926deccbSFrançois Tigeot 			if (connector_type == DRM_MODE_CONNECTOR_DVII) {
2174926deccbSFrançois Tigeot 				radeon_connector->dac_load_detect = true;
2175b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2176926deccbSFrançois Tigeot 							      rdev->mode_info.load_detect_property,
2177926deccbSFrançois Tigeot 							      1);
2178926deccbSFrançois Tigeot 			}
2179c59a5c48SFrançois Tigeot 			if (ASIC_IS_DCE5(rdev))
2180c59a5c48SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2181c59a5c48SFrançois Tigeot 							   rdev->mode_info.output_csc_property,
2182c59a5c48SFrançois Tigeot 							   RADEON_OUTPUT_CSC_BYPASS);
2183926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2184926deccbSFrançois Tigeot 			if (connector_type == DRM_MODE_CONNECTOR_DVII)
2185926deccbSFrançois Tigeot 				connector->doublescan_allowed = true;
2186926deccbSFrançois Tigeot 			else
2187926deccbSFrançois Tigeot 				connector->doublescan_allowed = false;
2188926deccbSFrançois Tigeot 			break;
2189926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_HDMIA:
2190926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_HDMIB:
2191c4ef309bSzrj 			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
2192926deccbSFrançois Tigeot 			if (!radeon_dig_connector)
2193926deccbSFrançois Tigeot 				goto failed;
2194926deccbSFrançois Tigeot 			radeon_dig_connector->igp_lane_info = igp_lane_info;
2195926deccbSFrançois Tigeot 			radeon_connector->con_priv = radeon_dig_connector;
2196926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
2197926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
2198926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2199926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2200926deccbSFrançois Tigeot 				if (!radeon_connector->ddc_bus)
2201926deccbSFrançois Tigeot 					DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2202926deccbSFrançois Tigeot 			}
2203b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2204926deccbSFrançois Tigeot 						      rdev->mode_info.coherent_mode_property,
2205926deccbSFrançois Tigeot 						      1);
2206926deccbSFrançois Tigeot 			if (ASIC_IS_AVIVO(rdev)) {
2207b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2208926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_property,
2209926deccbSFrançois Tigeot 							      UNDERSCAN_OFF);
2210b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2211926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_hborder_property,
2212926deccbSFrançois Tigeot 							      0);
2213b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2214926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_vborder_property,
2215926deccbSFrançois Tigeot 							      0);
2216c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2217c6f73aabSFrançois Tigeot 							   rdev->mode_info.dither_property,
2218c6f73aabSFrançois Tigeot 							   RADEON_FMT_DITHER_DISABLE);
2219c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2220c6f73aabSFrançois Tigeot 							   dev->mode_config.scaling_mode_property,
2221c6f73aabSFrançois Tigeot 							   DRM_MODE_SCALE_NONE);
2222926deccbSFrançois Tigeot 			}
22234cd92098Szrj 			if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
22244cd92098Szrj 				drm_object_attach_property(&radeon_connector->base.base,
22254cd92098Szrj 							   rdev->mode_info.audio_property,
2226c6f73aabSFrançois Tigeot 							   RADEON_AUDIO_AUTO);
2227c59a5c48SFrançois Tigeot 				radeon_connector->audio = RADEON_AUDIO_AUTO;
22284cd92098Szrj 			}
2229c59a5c48SFrançois Tigeot 			if (ASIC_IS_DCE5(rdev))
2230c59a5c48SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2231c59a5c48SFrançois Tigeot 							   rdev->mode_info.output_csc_property,
2232c59a5c48SFrançois Tigeot 							   RADEON_OUTPUT_CSC_BYPASS);
2233926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2234926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2235926deccbSFrançois Tigeot 			if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
2236926deccbSFrançois Tigeot 				connector->doublescan_allowed = true;
2237926deccbSFrançois Tigeot 			else
2238926deccbSFrançois Tigeot 				connector->doublescan_allowed = false;
2239926deccbSFrançois Tigeot 			break;
2240926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_DisplayPort:
2241c4ef309bSzrj 			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
2242926deccbSFrançois Tigeot 			if (!radeon_dig_connector)
2243926deccbSFrançois Tigeot 				goto failed;
2244926deccbSFrançois Tigeot 			radeon_dig_connector->igp_lane_info = igp_lane_info;
2245926deccbSFrançois Tigeot 			radeon_connector->con_priv = radeon_dig_connector;
2246926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
2247926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
2248926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2249926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
22507191d616Szrj 				if (radeon_connector->ddc_bus)
22517191d616Szrj 					has_aux = true;
22527191d616Szrj 				else
2253926deccbSFrançois Tigeot 					DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2254926deccbSFrançois Tigeot 			}
2255926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2256b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2257926deccbSFrançois Tigeot 						      rdev->mode_info.coherent_mode_property,
2258926deccbSFrançois Tigeot 						      1);
2259926deccbSFrançois Tigeot 			if (ASIC_IS_AVIVO(rdev)) {
2260b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2261926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_property,
2262926deccbSFrançois Tigeot 							      UNDERSCAN_OFF);
2263b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2264926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_hborder_property,
2265926deccbSFrançois Tigeot 							      0);
2266b5162e19SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2267926deccbSFrançois Tigeot 							      rdev->mode_info.underscan_vborder_property,
2268926deccbSFrançois Tigeot 							      0);
2269c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2270c6f73aabSFrançois Tigeot 							   rdev->mode_info.dither_property,
2271c6f73aabSFrançois Tigeot 							   RADEON_FMT_DITHER_DISABLE);
2272c6f73aabSFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2273c6f73aabSFrançois Tigeot 							   dev->mode_config.scaling_mode_property,
2274c6f73aabSFrançois Tigeot 							   DRM_MODE_SCALE_NONE);
2275926deccbSFrançois Tigeot 			}
22764cd92098Szrj 			if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
22774cd92098Szrj 				drm_object_attach_property(&radeon_connector->base.base,
22784cd92098Szrj 							   rdev->mode_info.audio_property,
2279c6f73aabSFrançois Tigeot 							   RADEON_AUDIO_AUTO);
2280c59a5c48SFrançois Tigeot 				radeon_connector->audio = RADEON_AUDIO_AUTO;
22814cd92098Szrj 			}
2282c59a5c48SFrançois Tigeot 			if (ASIC_IS_DCE5(rdev))
2283c59a5c48SFrançois Tigeot 				drm_object_attach_property(&radeon_connector->base.base,
2284c59a5c48SFrançois Tigeot 							   rdev->mode_info.output_csc_property,
2285c59a5c48SFrançois Tigeot 							   RADEON_OUTPUT_CSC_BYPASS);
2286926deccbSFrançois Tigeot 			connector->interlace_allowed = true;
2287926deccbSFrançois Tigeot 			/* in theory with a DP to VGA converter... */
2288926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2289926deccbSFrançois Tigeot 			break;
2290926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_eDP:
2291c4ef309bSzrj 			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
2292926deccbSFrançois Tigeot 			if (!radeon_dig_connector)
2293926deccbSFrançois Tigeot 				goto failed;
2294926deccbSFrançois Tigeot 			radeon_dig_connector->igp_lane_info = igp_lane_info;
2295926deccbSFrançois Tigeot 			radeon_connector->con_priv = radeon_dig_connector;
22964cd92098Szrj 			drm_connector_init(dev, &radeon_connector->base, &radeon_edp_connector_funcs, connector_type);
2297926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
2298926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
22995ef6d7b4SFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
23005ef6d7b4SFrançois Tigeot 				if (radeon_connector->ddc_bus)
23017191d616Szrj 					has_aux = true;
23027191d616Szrj 				else
2303926deccbSFrançois Tigeot 					DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2304926deccbSFrançois Tigeot 			}
2305b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2306926deccbSFrançois Tigeot 						      dev->mode_config.scaling_mode_property,
2307926deccbSFrançois Tigeot 						      DRM_MODE_SCALE_FULLSCREEN);
2308926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2309926deccbSFrançois Tigeot 			connector->interlace_allowed = false;
2310926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2311926deccbSFrançois Tigeot 			break;
2312926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_SVIDEO:
2313926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_Composite:
2314926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_9PinDIN:
2315926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
2316926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
2317926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
2318b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2319926deccbSFrançois Tigeot 						      rdev->mode_info.load_detect_property,
2320926deccbSFrançois Tigeot 						      1);
2321b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2322926deccbSFrançois Tigeot 						      rdev->mode_info.tv_std_property,
2323926deccbSFrançois Tigeot 						      radeon_atombios_get_tv_info(rdev));
2324926deccbSFrançois Tigeot 			/* no HPD on analog connectors */
2325926deccbSFrançois Tigeot 			radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2326926deccbSFrançois Tigeot 			connector->interlace_allowed = false;
2327926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2328926deccbSFrançois Tigeot 			break;
2329926deccbSFrançois Tigeot 		case DRM_MODE_CONNECTOR_LVDS:
2330c4ef309bSzrj 			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
2331926deccbSFrançois Tigeot 			if (!radeon_dig_connector)
2332926deccbSFrançois Tigeot 				goto failed;
2333926deccbSFrançois Tigeot 			radeon_dig_connector->igp_lane_info = igp_lane_info;
2334926deccbSFrançois Tigeot 			radeon_connector->con_priv = radeon_dig_connector;
2335926deccbSFrançois Tigeot 			drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
2336926deccbSFrançois Tigeot 			drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
2337926deccbSFrançois Tigeot 			if (i2c_bus->valid) {
2338926deccbSFrançois Tigeot 				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2339926deccbSFrançois Tigeot 				if (!radeon_connector->ddc_bus)
2340926deccbSFrançois Tigeot 					DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2341926deccbSFrançois Tigeot 			}
2342b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2343926deccbSFrançois Tigeot 						      dev->mode_config.scaling_mode_property,
2344926deccbSFrançois Tigeot 						      DRM_MODE_SCALE_FULLSCREEN);
2345926deccbSFrançois Tigeot 			subpixel_order = SubPixelHorizontalRGB;
2346926deccbSFrançois Tigeot 			connector->interlace_allowed = false;
2347926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2348926deccbSFrançois Tigeot 			break;
2349926deccbSFrançois Tigeot 		}
2350926deccbSFrançois Tigeot 	}
2351926deccbSFrançois Tigeot 
2352926deccbSFrançois Tigeot 	if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
2353c59a5c48SFrançois Tigeot 		if (i2c_bus->valid) {
2354c59a5c48SFrançois Tigeot 			connector->polled = DRM_CONNECTOR_POLL_CONNECT |
2355c59a5c48SFrançois Tigeot 			                    DRM_CONNECTOR_POLL_DISCONNECT;
2356c59a5c48SFrançois Tigeot 		}
2357926deccbSFrançois Tigeot 	} else
2358926deccbSFrançois Tigeot 		connector->polled = DRM_CONNECTOR_POLL_HPD;
2359926deccbSFrançois Tigeot 
2360926deccbSFrançois Tigeot 	connector->display_info.subpixel_order = subpixel_order;
2361c6f73aabSFrançois Tigeot 	drm_connector_register(connector);
23627191d616Szrj 
23637191d616Szrj 	if (has_aux)
23647191d616Szrj 		radeon_dp_aux_init(radeon_connector);
23657191d616Szrj 
2366926deccbSFrançois Tigeot 	return;
2367926deccbSFrançois Tigeot 
2368926deccbSFrançois Tigeot failed:
2369926deccbSFrançois Tigeot 	drm_connector_cleanup(connector);
2370158486a6SFrançois Tigeot 	kfree(connector);
2371926deccbSFrançois Tigeot }
2372926deccbSFrançois Tigeot 
2373926deccbSFrançois Tigeot void
radeon_add_legacy_connector(struct drm_device * dev,uint32_t connector_id,uint32_t supported_device,int connector_type,struct radeon_i2c_bus_rec * i2c_bus,uint16_t connector_object_id,struct radeon_hpd * hpd)2374926deccbSFrançois Tigeot radeon_add_legacy_connector(struct drm_device *dev,
2375926deccbSFrançois Tigeot 			    uint32_t connector_id,
2376926deccbSFrançois Tigeot 			    uint32_t supported_device,
2377926deccbSFrançois Tigeot 			    int connector_type,
2378926deccbSFrançois Tigeot 			    struct radeon_i2c_bus_rec *i2c_bus,
2379926deccbSFrançois Tigeot 			    uint16_t connector_object_id,
2380926deccbSFrançois Tigeot 			    struct radeon_hpd *hpd)
2381926deccbSFrançois Tigeot {
2382926deccbSFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
2383926deccbSFrançois Tigeot 	struct drm_connector *connector;
2384926deccbSFrançois Tigeot 	struct radeon_connector *radeon_connector;
2385926deccbSFrançois Tigeot 	uint32_t subpixel_order = SubPixelNone;
2386926deccbSFrançois Tigeot 
2387926deccbSFrançois Tigeot 	if (connector_type == DRM_MODE_CONNECTOR_Unknown)
2388926deccbSFrançois Tigeot 		return;
2389926deccbSFrançois Tigeot 
2390926deccbSFrançois Tigeot 	/* if the user selected tv=0 don't try and add the connector */
2391926deccbSFrançois Tigeot 	if (((connector_type == DRM_MODE_CONNECTOR_SVIDEO) ||
2392926deccbSFrançois Tigeot 	     (connector_type == DRM_MODE_CONNECTOR_Composite) ||
2393926deccbSFrançois Tigeot 	     (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) &&
2394926deccbSFrançois Tigeot 	    (radeon_tv == 0))
2395926deccbSFrançois Tigeot 		return;
2396926deccbSFrançois Tigeot 
2397926deccbSFrançois Tigeot 	/* see if we already added it */
2398926deccbSFrançois Tigeot 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
2399926deccbSFrançois Tigeot 		radeon_connector = to_radeon_connector(connector);
2400926deccbSFrançois Tigeot 		if (radeon_connector->connector_id == connector_id) {
2401926deccbSFrançois Tigeot 			radeon_connector->devices |= supported_device;
2402926deccbSFrançois Tigeot 			return;
2403926deccbSFrançois Tigeot 		}
2404926deccbSFrançois Tigeot 	}
2405926deccbSFrançois Tigeot 
2406c4ef309bSzrj 	radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL);
2407926deccbSFrançois Tigeot 	if (!radeon_connector)
2408926deccbSFrançois Tigeot 		return;
2409926deccbSFrançois Tigeot 
2410926deccbSFrançois Tigeot 	connector = &radeon_connector->base;
2411926deccbSFrançois Tigeot 
2412926deccbSFrançois Tigeot 	radeon_connector->connector_id = connector_id;
2413926deccbSFrançois Tigeot 	radeon_connector->devices = supported_device;
2414926deccbSFrançois Tigeot 	radeon_connector->connector_object_id = connector_object_id;
2415926deccbSFrançois Tigeot 	radeon_connector->hpd = *hpd;
2416926deccbSFrançois Tigeot 
2417926deccbSFrançois Tigeot 	switch (connector_type) {
2418926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_VGA:
2419926deccbSFrançois Tigeot 		drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
2420926deccbSFrançois Tigeot 		drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
2421926deccbSFrançois Tigeot 		if (i2c_bus->valid) {
2422926deccbSFrançois Tigeot 			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2423926deccbSFrançois Tigeot 			if (!radeon_connector->ddc_bus)
2424926deccbSFrançois Tigeot 				DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2425926deccbSFrançois Tigeot 		}
2426926deccbSFrançois Tigeot 		radeon_connector->dac_load_detect = true;
2427b5162e19SFrançois Tigeot 		drm_object_attach_property(&radeon_connector->base.base,
2428926deccbSFrançois Tigeot 					      rdev->mode_info.load_detect_property,
2429926deccbSFrançois Tigeot 					      1);
2430926deccbSFrançois Tigeot 		/* no HPD on analog connectors */
2431926deccbSFrançois Tigeot 		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2432926deccbSFrançois Tigeot 		connector->interlace_allowed = true;
2433926deccbSFrançois Tigeot 		connector->doublescan_allowed = true;
2434926deccbSFrançois Tigeot 		break;
2435926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_DVIA:
2436926deccbSFrançois Tigeot 		drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
2437926deccbSFrançois Tigeot 		drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
2438926deccbSFrançois Tigeot 		if (i2c_bus->valid) {
2439926deccbSFrançois Tigeot 			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2440926deccbSFrançois Tigeot 			if (!radeon_connector->ddc_bus)
2441926deccbSFrançois Tigeot 				DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2442926deccbSFrançois Tigeot 		}
2443926deccbSFrançois Tigeot 		radeon_connector->dac_load_detect = true;
2444b5162e19SFrançois Tigeot 		drm_object_attach_property(&radeon_connector->base.base,
2445926deccbSFrançois Tigeot 					      rdev->mode_info.load_detect_property,
2446926deccbSFrançois Tigeot 					      1);
2447926deccbSFrançois Tigeot 		/* no HPD on analog connectors */
2448926deccbSFrançois Tigeot 		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2449926deccbSFrançois Tigeot 		connector->interlace_allowed = true;
2450926deccbSFrançois Tigeot 		connector->doublescan_allowed = true;
2451926deccbSFrançois Tigeot 		break;
2452926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_DVII:
2453926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_DVID:
2454926deccbSFrançois Tigeot 		drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
2455926deccbSFrançois Tigeot 		drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
2456926deccbSFrançois Tigeot 		if (i2c_bus->valid) {
2457926deccbSFrançois Tigeot 			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2458926deccbSFrançois Tigeot 			if (!radeon_connector->ddc_bus)
2459926deccbSFrançois Tigeot 				DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2460926deccbSFrançois Tigeot 		}
2461926deccbSFrançois Tigeot 		if (connector_type == DRM_MODE_CONNECTOR_DVII) {
2462926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = true;
2463b5162e19SFrançois Tigeot 			drm_object_attach_property(&radeon_connector->base.base,
2464926deccbSFrançois Tigeot 						      rdev->mode_info.load_detect_property,
2465926deccbSFrançois Tigeot 						      1);
2466926deccbSFrançois Tigeot 		}
2467926deccbSFrançois Tigeot 		subpixel_order = SubPixelHorizontalRGB;
2468926deccbSFrançois Tigeot 		connector->interlace_allowed = true;
2469926deccbSFrançois Tigeot 		if (connector_type == DRM_MODE_CONNECTOR_DVII)
2470926deccbSFrançois Tigeot 			connector->doublescan_allowed = true;
2471926deccbSFrançois Tigeot 		else
2472926deccbSFrançois Tigeot 			connector->doublescan_allowed = false;
2473926deccbSFrançois Tigeot 		break;
2474926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_SVIDEO:
2475926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_Composite:
2476926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_9PinDIN:
2477926deccbSFrançois Tigeot 		drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
2478926deccbSFrançois Tigeot 		drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
2479926deccbSFrançois Tigeot 		radeon_connector->dac_load_detect = true;
2480926deccbSFrançois Tigeot 		/* RS400,RC410,RS480 chipset seems to report a lot
2481926deccbSFrançois Tigeot 		 * of false positive on load detect, we haven't yet
2482926deccbSFrançois Tigeot 		 * found a way to make load detect reliable on those
2483926deccbSFrançois Tigeot 		 * chipset, thus just disable it for TV.
2484926deccbSFrançois Tigeot 		 */
2485926deccbSFrançois Tigeot 		if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480)
2486926deccbSFrançois Tigeot 			radeon_connector->dac_load_detect = false;
2487b5162e19SFrançois Tigeot 		drm_object_attach_property(&radeon_connector->base.base,
2488926deccbSFrançois Tigeot 					      rdev->mode_info.load_detect_property,
2489926deccbSFrançois Tigeot 					      radeon_connector->dac_load_detect);
2490b5162e19SFrançois Tigeot 		drm_object_attach_property(&radeon_connector->base.base,
2491926deccbSFrançois Tigeot 					      rdev->mode_info.tv_std_property,
2492926deccbSFrançois Tigeot 					      radeon_combios_get_tv_info(rdev));
2493926deccbSFrançois Tigeot 		/* no HPD on analog connectors */
2494926deccbSFrançois Tigeot 		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
2495926deccbSFrançois Tigeot 		connector->interlace_allowed = false;
2496926deccbSFrançois Tigeot 		connector->doublescan_allowed = false;
2497926deccbSFrançois Tigeot 		break;
2498926deccbSFrançois Tigeot 	case DRM_MODE_CONNECTOR_LVDS:
2499926deccbSFrançois Tigeot 		drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
2500926deccbSFrançois Tigeot 		drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
2501926deccbSFrançois Tigeot 		if (i2c_bus->valid) {
2502926deccbSFrançois Tigeot 			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
2503926deccbSFrançois Tigeot 			if (!radeon_connector->ddc_bus)
2504926deccbSFrançois Tigeot 				DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
2505926deccbSFrançois Tigeot 		}
2506b5162e19SFrançois Tigeot 		drm_object_attach_property(&radeon_connector->base.base,
2507926deccbSFrançois Tigeot 					      dev->mode_config.scaling_mode_property,
2508926deccbSFrançois Tigeot 					      DRM_MODE_SCALE_FULLSCREEN);
2509926deccbSFrançois Tigeot 		subpixel_order = SubPixelHorizontalRGB;
2510926deccbSFrançois Tigeot 		connector->interlace_allowed = false;
2511926deccbSFrançois Tigeot 		connector->doublescan_allowed = false;
2512926deccbSFrançois Tigeot 		break;
2513926deccbSFrançois Tigeot 	}
2514926deccbSFrançois Tigeot 
2515926deccbSFrançois Tigeot 	if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
2516c59a5c48SFrançois Tigeot 		if (i2c_bus->valid) {
2517c59a5c48SFrançois Tigeot 			connector->polled = DRM_CONNECTOR_POLL_CONNECT |
2518c59a5c48SFrançois Tigeot 			                    DRM_CONNECTOR_POLL_DISCONNECT;
2519c59a5c48SFrançois Tigeot 		}
2520926deccbSFrançois Tigeot 	} else
2521926deccbSFrançois Tigeot 		connector->polled = DRM_CONNECTOR_POLL_HPD;
2522c59a5c48SFrançois Tigeot 
2523926deccbSFrançois Tigeot 	connector->display_info.subpixel_order = subpixel_order;
2524c6f73aabSFrançois Tigeot 	drm_connector_register(connector);
2525926deccbSFrançois Tigeot }
2526c59a5c48SFrançois Tigeot 
radeon_setup_mst_connector(struct drm_device * dev)2527c59a5c48SFrançois Tigeot void radeon_setup_mst_connector(struct drm_device *dev)
2528c59a5c48SFrançois Tigeot {
2529c59a5c48SFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
2530c59a5c48SFrançois Tigeot 	struct drm_connector *connector;
2531c59a5c48SFrançois Tigeot 	struct radeon_connector *radeon_connector;
2532c59a5c48SFrançois Tigeot 
2533c59a5c48SFrançois Tigeot 	if (!ASIC_IS_DCE5(rdev))
2534c59a5c48SFrançois Tigeot 		return;
2535c59a5c48SFrançois Tigeot 
2536c59a5c48SFrançois Tigeot 	if (radeon_mst == 0)
2537c59a5c48SFrançois Tigeot 		return;
2538c59a5c48SFrançois Tigeot 
2539c59a5c48SFrançois Tigeot 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
2540c59a5c48SFrançois Tigeot 		int ret;
2541c59a5c48SFrançois Tigeot 
2542c59a5c48SFrançois Tigeot 		radeon_connector = to_radeon_connector(connector);
2543c59a5c48SFrançois Tigeot 
2544c59a5c48SFrançois Tigeot 		if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
2545c59a5c48SFrançois Tigeot 			continue;
2546c59a5c48SFrançois Tigeot 
2547c59a5c48SFrançois Tigeot 		ret = radeon_dp_mst_init(radeon_connector);
2548c59a5c48SFrançois Tigeot 	}
2549c59a5c48SFrançois Tigeot }
2550