1b843c749SSergey Zigachev /*
2b843c749SSergey Zigachev  * Copyright 2007-8 Advanced Micro Devices, Inc.
3b843c749SSergey Zigachev  * Copyright 2008 Red Hat Inc.
4b843c749SSergey Zigachev  *
5b843c749SSergey Zigachev  * Permission is hereby granted, free of charge, to any person obtaining a
6b843c749SSergey Zigachev  * copy of this software and associated documentation files (the "Software"),
7b843c749SSergey Zigachev  * to deal in the Software without restriction, including without limitation
8b843c749SSergey Zigachev  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9b843c749SSergey Zigachev  * and/or sell copies of the Software, and to permit persons to whom the
10b843c749SSergey Zigachev  * Software is furnished to do so, subject to the following conditions:
11b843c749SSergey Zigachev  *
12b843c749SSergey Zigachev  * The above copyright notice and this permission notice shall be included in
13b843c749SSergey Zigachev  * all copies or substantial portions of the Software.
14b843c749SSergey Zigachev  *
15b843c749SSergey Zigachev  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b843c749SSergey Zigachev  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b843c749SSergey Zigachev  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18b843c749SSergey Zigachev  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19b843c749SSergey Zigachev  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20b843c749SSergey Zigachev  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21b843c749SSergey Zigachev  * OTHER DEALINGS IN THE SOFTWARE.
22b843c749SSergey Zigachev  *
23b843c749SSergey Zigachev  * Authors: Dave Airlie
24b843c749SSergey Zigachev  *          Alex Deucher
25b843c749SSergey Zigachev  */
26b843c749SSergey Zigachev #include <drm/drmP.h>
27b843c749SSergey Zigachev #include <drm/drm_edid.h>
28b843c749SSergey Zigachev #include <drm/drm_crtc_helper.h>
29b843c749SSergey Zigachev #include <drm/drm_fb_helper.h>
30b843c749SSergey Zigachev #include <drm/amdgpu_drm.h>
31b843c749SSergey Zigachev #include "amdgpu.h"
32b843c749SSergey Zigachev #include "atom.h"
33b843c749SSergey Zigachev #include "atombios_encoders.h"
34b843c749SSergey Zigachev #include "atombios_dp.h"
35b843c749SSergey Zigachev #include "amdgpu_connectors.h"
36b843c749SSergey Zigachev #include "amdgpu_i2c.h"
37b843c749SSergey Zigachev 
38b843c749SSergey Zigachev #include <linux/pm_runtime.h>
39b843c749SSergey Zigachev 
amdgpu_connector_hotplug(struct drm_connector * connector)40b843c749SSergey Zigachev void amdgpu_connector_hotplug(struct drm_connector *connector)
41b843c749SSergey Zigachev {
42b843c749SSergey Zigachev 	struct drm_device *dev = connector->dev;
43b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev->dev_private;
44b843c749SSergey Zigachev 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
45b843c749SSergey Zigachev 
46b843c749SSergey Zigachev 	/* bail if the connector does not have hpd pin, e.g.,
47b843c749SSergey Zigachev 	 * VGA, TV, etc.
48b843c749SSergey Zigachev 	 */
49b843c749SSergey Zigachev 	if (amdgpu_connector->hpd.hpd == AMDGPU_HPD_NONE)
50b843c749SSergey Zigachev 		return;
51b843c749SSergey Zigachev 
52b843c749SSergey Zigachev 	amdgpu_display_hpd_set_polarity(adev, amdgpu_connector->hpd.hpd);
53b843c749SSergey Zigachev 
54b843c749SSergey Zigachev 	/* if the connector is already off, don't turn it back on */
55b843c749SSergey Zigachev 	if (connector->dpms != DRM_MODE_DPMS_ON)
56b843c749SSergey Zigachev 		return;
57b843c749SSergey Zigachev 
58b843c749SSergey Zigachev 	/* just deal with DP (not eDP) here. */
59b843c749SSergey Zigachev 	if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
60b843c749SSergey Zigachev 		struct amdgpu_connector_atom_dig *dig_connector =
61b843c749SSergey Zigachev 			amdgpu_connector->con_priv;
62b843c749SSergey Zigachev 
63b843c749SSergey Zigachev 		/* if existing sink type was not DP no need to retrain */
64b843c749SSergey Zigachev 		if (dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_DISPLAYPORT)
65b843c749SSergey Zigachev 			return;
66b843c749SSergey Zigachev 
67b843c749SSergey Zigachev 		/* first get sink type as it may be reset after (un)plug */
68b843c749SSergey Zigachev 		dig_connector->dp_sink_type = amdgpu_atombios_dp_get_sinktype(amdgpu_connector);
69b843c749SSergey Zigachev 		/* don't do anything if sink is not display port, i.e.,
70b843c749SSergey Zigachev 		 * passive dp->(dvi|hdmi) adaptor
71b843c749SSergey Zigachev 		 */
72b843c749SSergey Zigachev 		if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT &&
73b843c749SSergey Zigachev 		    amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd) &&
74b843c749SSergey Zigachev 		    amdgpu_atombios_dp_needs_link_train(amdgpu_connector)) {
75b843c749SSergey Zigachev 			/* Don't start link training before we have the DPCD */
76b843c749SSergey Zigachev 			if (amdgpu_atombios_dp_get_dpcd(amdgpu_connector))
77b843c749SSergey Zigachev 				return;
78b843c749SSergey Zigachev 
79b843c749SSergey Zigachev 			/* Turn the connector off and back on immediately, which
80b843c749SSergey Zigachev 			 * will trigger link training
81b843c749SSergey Zigachev 			 */
82b843c749SSergey Zigachev 			drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
83b843c749SSergey Zigachev 			drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
84b843c749SSergey Zigachev 		}
85b843c749SSergey Zigachev 	}
86b843c749SSergey Zigachev }
87b843c749SSergey Zigachev 
amdgpu_connector_property_change_mode(struct drm_encoder * encoder)88b843c749SSergey Zigachev static void amdgpu_connector_property_change_mode(struct drm_encoder *encoder)
89b843c749SSergey Zigachev {
90b843c749SSergey Zigachev 	struct drm_crtc *crtc = encoder->crtc;
91b843c749SSergey Zigachev 
92b843c749SSergey Zigachev 	if (crtc && crtc->enabled) {
93b843c749SSergey Zigachev 		drm_crtc_helper_set_mode(crtc, &crtc->mode,
94b843c749SSergey Zigachev 					 crtc->x, crtc->y, crtc->primary->fb);
95b843c749SSergey Zigachev 	}
96b843c749SSergey Zigachev }
97b843c749SSergey Zigachev 
amdgpu_connector_get_monitor_bpc(struct drm_connector * connector)98b843c749SSergey Zigachev int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector)
99b843c749SSergey Zigachev {
100b843c749SSergey Zigachev 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
101b843c749SSergey Zigachev 	struct amdgpu_connector_atom_dig *dig_connector;
102b843c749SSergey Zigachev 	int bpc = 8;
103b843c749SSergey Zigachev 	unsigned mode_clock, max_tmds_clock;
104b843c749SSergey Zigachev 
105b843c749SSergey Zigachev 	switch (connector->connector_type) {
106b843c749SSergey Zigachev 	case DRM_MODE_CONNECTOR_DVII:
107b843c749SSergey Zigachev 	case DRM_MODE_CONNECTOR_HDMIB:
108b843c749SSergey Zigachev 		if (amdgpu_connector->use_digital) {
109b843c749SSergey Zigachev 			if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
110b843c749SSergey Zigachev 				if (connector->display_info.bpc)
111b843c749SSergey Zigachev 					bpc = connector->display_info.bpc;
112b843c749SSergey Zigachev 			}
113b843c749SSergey Zigachev 		}
114b843c749SSergey Zigachev 		break;
115b843c749SSergey Zigachev 	case DRM_MODE_CONNECTOR_DVID:
116b843c749SSergey Zigachev 	case DRM_MODE_CONNECTOR_HDMIA:
117b843c749SSergey Zigachev 		if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
118b843c749SSergey Zigachev 			if (connector->display_info.bpc)
119b843c749SSergey Zigachev 				bpc = connector->display_info.bpc;
120b843c749SSergey Zigachev 		}
121b843c749SSergey Zigachev 		break;
122b843c749SSergey Zigachev 	case DRM_MODE_CONNECTOR_DisplayPort:
123b843c749SSergey Zigachev 		dig_connector = amdgpu_connector->con_priv;
124b843c749SSergey Zigachev 		if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
125b843c749SSergey Zigachev 		    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) ||
126b843c749SSergey Zigachev 		    drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
127b843c749SSergey Zigachev 			if (connector->display_info.bpc)
128b843c749SSergey Zigachev 				bpc = connector->display_info.bpc;
129b843c749SSergey Zigachev 		}
130b843c749SSergey Zigachev 		break;
131b843c749SSergey Zigachev 	case DRM_MODE_CONNECTOR_eDP:
132b843c749SSergey Zigachev 	case DRM_MODE_CONNECTOR_LVDS:
133b843c749SSergey Zigachev 		if (connector->display_info.bpc)
134b843c749SSergey Zigachev 			bpc = connector->display_info.bpc;
135b843c749SSergey Zigachev 		else {
136b843c749SSergey Zigachev 			const struct drm_connector_helper_funcs *connector_funcs =
137b843c749SSergey Zigachev 				connector->helper_private;
138b843c749SSergey Zigachev 			struct drm_encoder *encoder = connector_funcs->best_encoder(connector);
139b843c749SSergey Zigachev 			struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
140b843c749SSergey Zigachev 			struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
141b843c749SSergey Zigachev 
142b843c749SSergey Zigachev 			if (dig->lcd_misc & ATOM_PANEL_MISC_V13_6BIT_PER_COLOR)
143b843c749SSergey Zigachev 				bpc = 6;
144b843c749SSergey Zigachev 			else if (dig->lcd_misc & ATOM_PANEL_MISC_V13_8BIT_PER_COLOR)
145b843c749SSergey Zigachev 				bpc = 8;
146b843c749SSergey Zigachev 		}
147b843c749SSergey Zigachev 		break;
148b843c749SSergey Zigachev 	}
149b843c749SSergey Zigachev 
150b843c749SSergey Zigachev 	if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
151b843c749SSergey Zigachev 		/*
152b843c749SSergey Zigachev 		 * Pre DCE-8 hw can't handle > 12 bpc, and more than 12 bpc doesn't make
153b843c749SSergey Zigachev 		 * much sense without support for > 12 bpc framebuffers. RGB 4:4:4 at
154b843c749SSergey Zigachev 		 * 12 bpc is always supported on hdmi deep color sinks, as this is
155b843c749SSergey Zigachev 		 * required by the HDMI-1.3 spec. Clamp to a safe 12 bpc maximum.
156b843c749SSergey Zigachev 		 */
157b843c749SSergey Zigachev 		if (bpc > 12) {
158b843c749SSergey Zigachev 			DRM_DEBUG("%s: HDMI deep color %d bpc unsupported. Using 12 bpc.\n",
159b843c749SSergey Zigachev 				  connector->name, bpc);
160b843c749SSergey Zigachev 			bpc = 12;
161b843c749SSergey Zigachev 		}
162b843c749SSergey Zigachev 
163b843c749SSergey Zigachev 		/* Any defined maximum tmds clock limit we must not exceed? */
164b843c749SSergey Zigachev 		if (connector->display_info.max_tmds_clock > 0) {
165b843c749SSergey Zigachev 			/* mode_clock is clock in kHz for mode to be modeset on this connector */
166b843c749SSergey Zigachev 			mode_clock = amdgpu_connector->pixelclock_for_modeset;
167b843c749SSergey Zigachev 
168b843c749SSergey Zigachev 			/* Maximum allowable input clock in kHz */
169b843c749SSergey Zigachev 			max_tmds_clock = connector->display_info.max_tmds_clock;
170b843c749SSergey Zigachev 
171b843c749SSergey Zigachev 			DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n",
172b843c749SSergey Zigachev 				  connector->name, mode_clock, max_tmds_clock);
173b843c749SSergey Zigachev 
174b843c749SSergey Zigachev 			/* Check if bpc is within clock limit. Try to degrade gracefully otherwise */
175b843c749SSergey Zigachev 			if ((bpc == 12) && (mode_clock * 3/2 > max_tmds_clock)) {
176b843c749SSergey Zigachev 				if ((connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) &&
177b843c749SSergey Zigachev 				    (mode_clock * 5/4 <= max_tmds_clock))
178b843c749SSergey Zigachev 					bpc = 10;
179b843c749SSergey Zigachev 				else
180b843c749SSergey Zigachev 					bpc = 8;
181b843c749SSergey Zigachev 
182b843c749SSergey Zigachev 				DRM_DEBUG("%s: HDMI deep color 12 bpc exceeds max tmds clock. Using %d bpc.\n",
183b843c749SSergey Zigachev 					  connector->name, bpc);
184b843c749SSergey Zigachev 			}
185b843c749SSergey Zigachev 
186b843c749SSergey Zigachev 			if ((bpc == 10) && (mode_clock * 5/4 > max_tmds_clock)) {
187b843c749SSergey Zigachev 				bpc = 8;
188b843c749SSergey Zigachev 				DRM_DEBUG("%s: HDMI deep color 10 bpc exceeds max tmds clock. Using %d bpc.\n",
189b843c749SSergey Zigachev 					  connector->name, bpc);
190b843c749SSergey Zigachev 			}
191b843c749SSergey Zigachev 		} else if (bpc > 8) {
192b843c749SSergey Zigachev 			/* max_tmds_clock missing, but hdmi spec mandates it for deep color. */
193b843c749SSergey Zigachev 			DRM_DEBUG("%s: Required max tmds clock for HDMI deep color missing. Using 8 bpc.\n",
194b843c749SSergey Zigachev 				  connector->name);
195b843c749SSergey Zigachev 			bpc = 8;
196b843c749SSergey Zigachev 		}
197b843c749SSergey Zigachev 	}
198b843c749SSergey Zigachev 
199b843c749SSergey Zigachev 	if ((amdgpu_deep_color == 0) && (bpc > 8)) {
200b843c749SSergey Zigachev 		DRM_DEBUG("%s: Deep color disabled. Set amdgpu module param deep_color=1 to enable.\n",
201b843c749SSergey Zigachev 			  connector->name);
202b843c749SSergey Zigachev 		bpc = 8;
203b843c749SSergey Zigachev 	}
204b843c749SSergey Zigachev 
205b843c749SSergey Zigachev 	DRM_DEBUG("%s: Display bpc=%d, returned bpc=%d\n",
206b843c749SSergey Zigachev 		  connector->name, connector->display_info.bpc, bpc);
207b843c749SSergey Zigachev 
208b843c749SSergey Zigachev 	return bpc;
209b843c749SSergey Zigachev }
210b843c749SSergey Zigachev 
211b843c749SSergey Zigachev static void
amdgpu_connector_update_scratch_regs(struct drm_connector * connector,enum drm_connector_status status)212b843c749SSergey Zigachev amdgpu_connector_update_scratch_regs(struct drm_connector *connector,
213b843c749SSergey Zigachev 				      enum drm_connector_status status)
214b843c749SSergey Zigachev {
215b843c749SSergey Zigachev 	struct drm_encoder *best_encoder;
216b843c749SSergey Zigachev 	struct drm_encoder *encoder;
217b843c749SSergey Zigachev 	const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
218b843c749SSergey Zigachev 	bool connected;
219b843c749SSergey Zigachev 	int i;
220b843c749SSergey Zigachev 
221b843c749SSergey Zigachev 	best_encoder = connector_funcs->best_encoder(connector);
222b843c749SSergey Zigachev 
223b843c749SSergey Zigachev 	drm_connector_for_each_possible_encoder(connector, encoder, i) {
224b843c749SSergey Zigachev 		if ((encoder == best_encoder) && (status == connector_status_connected))
225b843c749SSergey Zigachev 			connected = true;
226b843c749SSergey Zigachev 		else
227b843c749SSergey Zigachev 			connected = false;
228b843c749SSergey Zigachev 
229b843c749SSergey Zigachev 		amdgpu_atombios_encoder_set_bios_scratch_regs(connector, encoder, connected);
230b843c749SSergey Zigachev 	}
231b843c749SSergey Zigachev }
232b843c749SSergey Zigachev 
233b843c749SSergey Zigachev static struct drm_encoder *
amdgpu_connector_find_encoder(struct drm_connector * connector,int encoder_type)234b843c749SSergey Zigachev amdgpu_connector_find_encoder(struct drm_connector *connector,
235b843c749SSergey Zigachev 			       int encoder_type)
236b843c749SSergey Zigachev {
237b843c749SSergey Zigachev 	struct drm_encoder *encoder;
238b843c749SSergey Zigachev 	int i;
239b843c749SSergey Zigachev 
240b843c749SSergey Zigachev 	drm_connector_for_each_possible_encoder(connector, encoder, i) {
241b843c749SSergey Zigachev 		if (encoder->encoder_type == encoder_type)
242b843c749SSergey Zigachev 			return encoder;
243b843c749SSergey Zigachev 	}
244b843c749SSergey Zigachev 
245b843c749SSergey Zigachev 	return NULL;
246b843c749SSergey Zigachev }
247b843c749SSergey Zigachev 
amdgpu_connector_edid(struct drm_connector * connector)248b843c749SSergey Zigachev struct edid *amdgpu_connector_edid(struct drm_connector *connector)
249b843c749SSergey Zigachev {
250b843c749SSergey Zigachev 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
251b843c749SSergey Zigachev 	struct drm_property_blob *edid_blob = connector->edid_blob_ptr;
252b843c749SSergey Zigachev 
253b843c749SSergey Zigachev 	if (amdgpu_connector->edid) {
254b843c749SSergey Zigachev 		return amdgpu_connector->edid;
255b843c749SSergey Zigachev 	} else if (edid_blob) {
256b843c749SSergey Zigachev 		struct edid *edid = kmemdup(edid_blob->data, edid_blob->length, GFP_KERNEL);
257b843c749SSergey Zigachev 		if (edid)
258b843c749SSergey Zigachev 			amdgpu_connector->edid = edid;
259b843c749SSergey Zigachev 	}
260b843c749SSergey Zigachev 	return amdgpu_connector->edid;
261b843c749SSergey Zigachev }
262b843c749SSergey Zigachev 
263b843c749SSergey Zigachev static struct edid *
amdgpu_connector_get_hardcoded_edid(struct amdgpu_device * adev)264b843c749SSergey Zigachev amdgpu_connector_get_hardcoded_edid(struct amdgpu_device *adev)
265b843c749SSergey Zigachev {
266b843c749SSergey Zigachev 	struct edid *edid;
267b843c749SSergey Zigachev 
268b843c749SSergey Zigachev 	if (adev->mode_info.bios_hardcoded_edid) {
269*78973132SSergey Zigachev 		edid = kmalloc(adev->mode_info.bios_hardcoded_edid_size, M_DRM, GFP_KERNEL);
270b843c749SSergey Zigachev 		if (edid) {
271b843c749SSergey Zigachev 			memcpy((unsigned char *)edid,
272b843c749SSergey Zigachev 			       (unsigned char *)adev->mode_info.bios_hardcoded_edid,
273b843c749SSergey Zigachev 			       adev->mode_info.bios_hardcoded_edid_size);
274b843c749SSergey Zigachev 			return edid;
275b843c749SSergey Zigachev 		}
276b843c749SSergey Zigachev 	}
277b843c749SSergey Zigachev 	return NULL;
278b843c749SSergey Zigachev }
279b843c749SSergey Zigachev 
amdgpu_connector_get_edid(struct drm_connector * connector)280b843c749SSergey Zigachev static void amdgpu_connector_get_edid(struct drm_connector *connector)
281b843c749SSergey Zigachev {
282b843c749SSergey Zigachev 	struct drm_device *dev = connector->dev;
283b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev->dev_private;
284b843c749SSergey Zigachev 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
285b843c749SSergey Zigachev 
286b843c749SSergey Zigachev 	if (amdgpu_connector->edid)
287b843c749SSergey Zigachev 		return;
288b843c749SSergey Zigachev 
289b843c749SSergey Zigachev 	/* on hw with routers, select right port */
290b843c749SSergey Zigachev 	if (amdgpu_connector->router.ddc_valid)
291b843c749SSergey Zigachev 		amdgpu_i2c_router_select_ddc_port(amdgpu_connector);
292b843c749SSergey Zigachev 
293b843c749SSergey Zigachev 	if ((amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) !=
294b843c749SSergey Zigachev 	     ENCODER_OBJECT_ID_NONE) &&
295b843c749SSergey Zigachev 	    amdgpu_connector->ddc_bus->has_aux) {
296b843c749SSergey Zigachev 		amdgpu_connector->edid = drm_get_edid(connector,
297b843c749SSergey Zigachev 						      &amdgpu_connector->ddc_bus->aux.ddc);
298b843c749SSergey Zigachev 	} else if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
299b843c749SSergey Zigachev 		   (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
300b843c749SSergey Zigachev 		struct amdgpu_connector_atom_dig *dig = amdgpu_connector->con_priv;
301b843c749SSergey Zigachev 
302b843c749SSergey Zigachev 		if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT ||
303b843c749SSergey Zigachev 		     dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) &&
304b843c749SSergey Zigachev 		    amdgpu_connector->ddc_bus->has_aux)
305b843c749SSergey Zigachev 			amdgpu_connector->edid = drm_get_edid(connector,
306b843c749SSergey Zigachev 							      &amdgpu_connector->ddc_bus->aux.ddc);
307b843c749SSergey Zigachev 		else if (amdgpu_connector->ddc_bus)
308b843c749SSergey Zigachev 			amdgpu_connector->edid = drm_get_edid(connector,
309b843c749SSergey Zigachev 							      &amdgpu_connector->ddc_bus->adapter);
310b843c749SSergey Zigachev 	} else if (amdgpu_connector->ddc_bus) {
311b843c749SSergey Zigachev 		amdgpu_connector->edid = drm_get_edid(connector,
312b843c749SSergey Zigachev 						      &amdgpu_connector->ddc_bus->adapter);
313b843c749SSergey Zigachev 	}
314b843c749SSergey Zigachev 
315b843c749SSergey Zigachev 	if (!amdgpu_connector->edid) {
316b843c749SSergey Zigachev 		/* some laptops provide a hardcoded edid in rom for LCDs */
317b843c749SSergey Zigachev 		if (((connector->connector_type == DRM_MODE_CONNECTOR_LVDS) ||
318b843c749SSergey Zigachev 		     (connector->connector_type == DRM_MODE_CONNECTOR_eDP)))
319b843c749SSergey Zigachev 			amdgpu_connector->edid = amdgpu_connector_get_hardcoded_edid(adev);
320b843c749SSergey Zigachev 	}
321b843c749SSergey Zigachev }
322b843c749SSergey Zigachev 
amdgpu_connector_free_edid(struct drm_connector * connector)323b843c749SSergey Zigachev static void amdgpu_connector_free_edid(struct drm_connector *connector)
324b843c749SSergey Zigachev {
325b843c749SSergey Zigachev 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
326b843c749SSergey Zigachev 
327b843c749SSergey Zigachev 	kfree(amdgpu_connector->edid);
328b843c749SSergey Zigachev 	amdgpu_connector->edid = NULL;
329b843c749SSergey Zigachev }
330b843c749SSergey Zigachev 
amdgpu_connector_ddc_get_modes(struct drm_connector * connector)331b843c749SSergey Zigachev static int amdgpu_connector_ddc_get_modes(struct drm_connector *connector)
332b843c749SSergey Zigachev {
333b843c749SSergey Zigachev 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
334b843c749SSergey Zigachev 	int ret;
335b843c749SSergey Zigachev 
336b843c749SSergey Zigachev 	if (amdgpu_connector->edid) {
337b843c749SSergey Zigachev 		drm_connector_update_edid_property(connector, amdgpu_connector->edid);
338b843c749SSergey Zigachev 		ret = drm_add_edid_modes(connector, amdgpu_connector->edid);
339b843c749SSergey Zigachev 		return ret;
340b843c749SSergey Zigachev 	}
341b843c749SSergey Zigachev 	drm_connector_update_edid_property(connector, NULL);
342b843c749SSergey Zigachev 	return 0;
343b843c749SSergey Zigachev }
344b843c749SSergey Zigachev 
345b843c749SSergey Zigachev static struct drm_encoder *
amdgpu_connector_best_single_encoder(struct drm_connector * connector)346b843c749SSergey Zigachev amdgpu_connector_best_single_encoder(struct drm_connector *connector)
347b843c749SSergey Zigachev {
348b843c749SSergey Zigachev 	struct drm_encoder *encoder;
349b843c749SSergey Zigachev 	int i;
350b843c749SSergey Zigachev 
351b843c749SSergey Zigachev 	/* pick the first one */
352b843c749SSergey Zigachev 	drm_connector_for_each_possible_encoder(connector, encoder, i)
353b843c749SSergey Zigachev 		return encoder;
354b843c749SSergey Zigachev 
355b843c749SSergey Zigachev 	return NULL;
356b843c749SSergey Zigachev }
357b843c749SSergey Zigachev 
amdgpu_get_native_mode(struct drm_connector * connector)358b843c749SSergey Zigachev static void amdgpu_get_native_mode(struct drm_connector *connector)
359b843c749SSergey Zigachev {
360b843c749SSergey Zigachev 	struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector);
361b843c749SSergey Zigachev 	struct amdgpu_encoder *amdgpu_encoder;
362b843c749SSergey Zigachev 
363b843c749SSergey Zigachev 	if (encoder == NULL)
364b843c749SSergey Zigachev 		return;
365b843c749SSergey Zigachev 
366b843c749SSergey Zigachev 	amdgpu_encoder = to_amdgpu_encoder(encoder);
367b843c749SSergey Zigachev 
368b843c749SSergey Zigachev 	if (!list_empty(&connector->probed_modes)) {
369b843c749SSergey Zigachev 		struct drm_display_mode *preferred_mode =
370b843c749SSergey Zigachev 			list_first_entry(&connector->probed_modes,
371b843c749SSergey Zigachev 					 struct drm_display_mode, head);
372b843c749SSergey Zigachev 
373b843c749SSergey Zigachev 		amdgpu_encoder->native_mode = *preferred_mode;
374b843c749SSergey Zigachev 	} else {
375b843c749SSergey Zigachev 		amdgpu_encoder->native_mode.clock = 0;
376b843c749SSergey Zigachev 	}
377b843c749SSergey Zigachev }
378b843c749SSergey Zigachev 
379b843c749SSergey Zigachev static struct drm_display_mode *
amdgpu_connector_lcd_native_mode(struct drm_encoder * encoder)380b843c749SSergey Zigachev amdgpu_connector_lcd_native_mode(struct drm_encoder *encoder)
381b843c749SSergey Zigachev {
382b843c749SSergey Zigachev 	struct drm_device *dev = encoder->dev;
383b843c749SSergey Zigachev 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
384b843c749SSergey Zigachev 	struct drm_display_mode *mode = NULL;
385b843c749SSergey Zigachev 	struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
386b843c749SSergey Zigachev 
387b843c749SSergey Zigachev 	if (native_mode->hdisplay != 0 &&
388b843c749SSergey Zigachev 	    native_mode->vdisplay != 0 &&
389b843c749SSergey Zigachev 	    native_mode->clock != 0) {
390b843c749SSergey Zigachev 		mode = drm_mode_duplicate(dev, native_mode);
391b843c749SSergey Zigachev 		mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
392b843c749SSergey Zigachev 		drm_mode_set_name(mode);
393b843c749SSergey Zigachev 
394b843c749SSergey Zigachev 		DRM_DEBUG_KMS("Adding native panel mode %s\n", mode->name);
395b843c749SSergey Zigachev 	} else if (native_mode->hdisplay != 0 &&
396b843c749SSergey Zigachev 		   native_mode->vdisplay != 0) {
397b843c749SSergey Zigachev 		/* mac laptops without an edid */
398b843c749SSergey Zigachev 		/* Note that this is not necessarily the exact panel mode,
399b843c749SSergey Zigachev 		 * but an approximation based on the cvt formula.  For these
400b843c749SSergey Zigachev 		 * systems we should ideally read the mode info out of the
401b843c749SSergey Zigachev 		 * registers or add a mode table, but this works and is much
402b843c749SSergey Zigachev 		 * simpler.
403b843c749SSergey Zigachev 		 */
404b843c749SSergey Zigachev 		mode = drm_cvt_mode(dev, native_mode->hdisplay, native_mode->vdisplay, 60, true, false, false);
405b843c749SSergey Zigachev 		mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
406b843c749SSergey Zigachev 		DRM_DEBUG_KMS("Adding cvt approximation of native panel mode %s\n", mode->name);
407b843c749SSergey Zigachev 	}
408b843c749SSergey Zigachev 	return mode;
409b843c749SSergey Zigachev }
410b843c749SSergey Zigachev 
amdgpu_connector_add_common_modes(struct drm_encoder * encoder,struct drm_connector * connector)411b843c749SSergey Zigachev static void amdgpu_connector_add_common_modes(struct drm_encoder *encoder,
412b843c749SSergey Zigachev 					       struct drm_connector *connector)
413b843c749SSergey Zigachev {
414b843c749SSergey Zigachev 	struct drm_device *dev = encoder->dev;
415b843c749SSergey Zigachev 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
416b843c749SSergey Zigachev 	struct drm_display_mode *mode = NULL;
417b843c749SSergey Zigachev 	struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
418b843c749SSergey Zigachev 	int i;
419b843c749SSergey Zigachev 	static const struct mode_size {
420b843c749SSergey Zigachev 		int w;
421b843c749SSergey Zigachev 		int h;
422b843c749SSergey Zigachev 	} common_modes[17] = {
423b843c749SSergey Zigachev 		{ 640,  480},
424b843c749SSergey Zigachev 		{ 720,  480},
425b843c749SSergey Zigachev 		{ 800,  600},
426b843c749SSergey Zigachev 		{ 848,  480},
427b843c749SSergey Zigachev 		{1024,  768},
428b843c749SSergey Zigachev 		{1152,  768},
429b843c749SSergey Zigachev 		{1280,  720},
430b843c749SSergey Zigachev 		{1280,  800},
431b843c749SSergey Zigachev 		{1280,  854},
432b843c749SSergey Zigachev 		{1280,  960},
433b843c749SSergey Zigachev 		{1280, 1024},
434b843c749SSergey Zigachev 		{1440,  900},
435b843c749SSergey Zigachev 		{1400, 1050},
436b843c749SSergey Zigachev 		{1680, 1050},
437b843c749SSergey Zigachev 		{1600, 1200},
438b843c749SSergey Zigachev 		{1920, 1080},
439b843c749SSergey Zigachev 		{1920, 1200}
440b843c749SSergey Zigachev 	};
441b843c749SSergey Zigachev 
442b843c749SSergey Zigachev 	for (i = 0; i < 17; i++) {
443b843c749SSergey Zigachev 		if (amdgpu_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) {
444b843c749SSergey Zigachev 			if (common_modes[i].w > 1024 ||
445b843c749SSergey Zigachev 			    common_modes[i].h > 768)
446b843c749SSergey Zigachev 				continue;
447b843c749SSergey Zigachev 		}
448b843c749SSergey Zigachev 		if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
449b843c749SSergey Zigachev 			if (common_modes[i].w > native_mode->hdisplay ||
450b843c749SSergey Zigachev 			    common_modes[i].h > native_mode->vdisplay ||
451b843c749SSergey Zigachev 			    (common_modes[i].w == native_mode->hdisplay &&
452b843c749SSergey Zigachev 			     common_modes[i].h == native_mode->vdisplay))
453b843c749SSergey Zigachev 				continue;
454b843c749SSergey Zigachev 		}
455b843c749SSergey Zigachev 		if (common_modes[i].w < 320 || common_modes[i].h < 200)
456b843c749SSergey Zigachev 			continue;
457b843c749SSergey Zigachev 
458b843c749SSergey Zigachev 		mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false);
459b843c749SSergey Zigachev 		drm_mode_probed_add(connector, mode);
460b843c749SSergey Zigachev 	}
461b843c749SSergey Zigachev }
462b843c749SSergey Zigachev 
amdgpu_connector_set_property(struct drm_connector * connector,struct drm_property * property,uint64_t val)463b843c749SSergey Zigachev static int amdgpu_connector_set_property(struct drm_connector *connector,
464b843c749SSergey Zigachev 					  struct drm_property *property,
465b843c749SSergey Zigachev 					  uint64_t val)
466b843c749SSergey Zigachev {
467b843c749SSergey Zigachev 	struct drm_device *dev = connector->dev;
468b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev->dev_private;
469b843c749SSergey Zigachev 	struct drm_encoder *encoder;
470b843c749SSergey Zigachev 	struct amdgpu_encoder *amdgpu_encoder;
471b843c749SSergey Zigachev 
472b843c749SSergey Zigachev 	if (property == adev->mode_info.coherent_mode_property) {
473b843c749SSergey Zigachev 		struct amdgpu_encoder_atom_dig *dig;
474b843c749SSergey Zigachev 		bool new_coherent_mode;
475b843c749SSergey Zigachev 
476b843c749SSergey Zigachev 		/* need to find digital encoder on connector */
477b843c749SSergey Zigachev 		encoder = amdgpu_connector_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
478b843c749SSergey Zigachev 		if (!encoder)
479b843c749SSergey Zigachev 			return 0;
480b843c749SSergey Zigachev 
481b843c749SSergey Zigachev 		amdgpu_encoder = to_amdgpu_encoder(encoder);
482b843c749SSergey Zigachev 
483b843c749SSergey Zigachev 		if (!amdgpu_encoder->enc_priv)
484b843c749SSergey Zigachev 			return 0;
485b843c749SSergey Zigachev 
486b843c749SSergey Zigachev 		dig = amdgpu_encoder->enc_priv;
487b843c749SSergey Zigachev 		new_coherent_mode = val ? true : false;
488b843c749SSergey Zigachev 		if (dig->coherent_mode != new_coherent_mode) {
489b843c749SSergey Zigachev 			dig->coherent_mode = new_coherent_mode;
490b843c749SSergey Zigachev 			amdgpu_connector_property_change_mode(&amdgpu_encoder->base);
491b843c749SSergey Zigachev 		}
492b843c749SSergey Zigachev 	}
493b843c749SSergey Zigachev 
494b843c749SSergey Zigachev 	if (property == adev->mode_info.audio_property) {
495b843c749SSergey Zigachev 		struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
496b843c749SSergey Zigachev 		/* need to find digital encoder on connector */
497b843c749SSergey Zigachev 		encoder = amdgpu_connector_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
498b843c749SSergey Zigachev 		if (!encoder)
499b843c749SSergey Zigachev 			return 0;
500b843c749SSergey Zigachev 
501b843c749SSergey Zigachev 		amdgpu_encoder = to_amdgpu_encoder(encoder);
502b843c749SSergey Zigachev 
503b843c749SSergey Zigachev 		if (amdgpu_connector->audio != val) {
504b843c749SSergey Zigachev 			amdgpu_connector->audio = val;
505b843c749SSergey Zigachev 			amdgpu_connector_property_change_mode(&amdgpu_encoder->base);
506b843c749SSergey Zigachev 		}
507b843c749SSergey Zigachev 	}
508b843c749SSergey Zigachev 
509b843c749SSergey Zigachev 	if (property == adev->mode_info.dither_property) {
510b843c749SSergey Zigachev 		struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
511b843c749SSergey Zigachev 		/* need to find digital encoder on connector */
512b843c749SSergey Zigachev 		encoder = amdgpu_connector_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
513b843c749SSergey Zigachev 		if (!encoder)
514b843c749SSergey Zigachev 			return 0;
515b843c749SSergey Zigachev 
516b843c749SSergey Zigachev 		amdgpu_encoder = to_amdgpu_encoder(encoder);
517b843c749SSergey Zigachev 
518b843c749SSergey Zigachev 		if (amdgpu_connector->dither != val) {
519b843c749SSergey Zigachev 			amdgpu_connector->dither = val;
520b843c749SSergey Zigachev 			amdgpu_connector_property_change_mode(&amdgpu_encoder->base);
521b843c749SSergey Zigachev 		}
522b843c749SSergey Zigachev 	}
523b843c749SSergey Zigachev 
524b843c749SSergey Zigachev 	if (property == adev->mode_info.underscan_property) {
525b843c749SSergey Zigachev 		/* need to find digital encoder on connector */
526b843c749SSergey Zigachev 		encoder = amdgpu_connector_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
527b843c749SSergey Zigachev 		if (!encoder)
528b843c749SSergey Zigachev 			return 0;
529b843c749SSergey Zigachev 
530b843c749SSergey Zigachev 		amdgpu_encoder = to_amdgpu_encoder(encoder);
531b843c749SSergey Zigachev 
532b843c749SSergey Zigachev 		if (amdgpu_encoder->underscan_type != val) {
533b843c749SSergey Zigachev 			amdgpu_encoder->underscan_type = val;
534b843c749SSergey Zigachev 			amdgpu_connector_property_change_mode(&amdgpu_encoder->base);
535b843c749SSergey Zigachev 		}
536b843c749SSergey Zigachev 	}
537b843c749SSergey Zigachev 
538b843c749SSergey Zigachev 	if (property == adev->mode_info.underscan_hborder_property) {
539b843c749SSergey Zigachev 		/* need to find digital encoder on connector */
540b843c749SSergey Zigachev 		encoder = amdgpu_connector_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
541b843c749SSergey Zigachev 		if (!encoder)
542b843c749SSergey Zigachev 			return 0;
543b843c749SSergey Zigachev 
544b843c749SSergey Zigachev 		amdgpu_encoder = to_amdgpu_encoder(encoder);
545b843c749SSergey Zigachev 
546b843c749SSergey Zigachev 		if (amdgpu_encoder->underscan_hborder != val) {
547b843c749SSergey Zigachev 			amdgpu_encoder->underscan_hborder = val;
548b843c749SSergey Zigachev 			amdgpu_connector_property_change_mode(&amdgpu_encoder->base);
549b843c749SSergey Zigachev 		}
550b843c749SSergey Zigachev 	}
551b843c749SSergey Zigachev 
552b843c749SSergey Zigachev 	if (property == adev->mode_info.underscan_vborder_property) {
553b843c749SSergey Zigachev 		/* need to find digital encoder on connector */
554b843c749SSergey Zigachev 		encoder = amdgpu_connector_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
555b843c749SSergey Zigachev 		if (!encoder)
556b843c749SSergey Zigachev 			return 0;
557b843c749SSergey Zigachev 
558b843c749SSergey Zigachev 		amdgpu_encoder = to_amdgpu_encoder(encoder);
559b843c749SSergey Zigachev 
560b843c749SSergey Zigachev 		if (amdgpu_encoder->underscan_vborder != val) {
561b843c749SSergey Zigachev 			amdgpu_encoder->underscan_vborder = val;
562b843c749SSergey Zigachev 			amdgpu_connector_property_change_mode(&amdgpu_encoder->base);
563b843c749SSergey Zigachev 		}
564b843c749SSergey Zigachev 	}
565b843c749SSergey Zigachev 
566b843c749SSergey Zigachev 	if (property == adev->mode_info.load_detect_property) {
567b843c749SSergey Zigachev 		struct amdgpu_connector *amdgpu_connector =
568b843c749SSergey Zigachev 			to_amdgpu_connector(connector);
569b843c749SSergey Zigachev 
570b843c749SSergey Zigachev 		if (val == 0)
571b843c749SSergey Zigachev 			amdgpu_connector->dac_load_detect = false;
572b843c749SSergey Zigachev 		else
573b843c749SSergey Zigachev 			amdgpu_connector->dac_load_detect = true;
574b843c749SSergey Zigachev 	}
575b843c749SSergey Zigachev 
576b843c749SSergey Zigachev 	if (property == dev->mode_config.scaling_mode_property) {
577b843c749SSergey Zigachev 		enum amdgpu_rmx_type rmx_type;
578b843c749SSergey Zigachev 
579b843c749SSergey Zigachev 		if (connector->encoder) {
580b843c749SSergey Zigachev 			amdgpu_encoder = to_amdgpu_encoder(connector->encoder);
581b843c749SSergey Zigachev 		} else {
582b843c749SSergey Zigachev 			const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
583b843c749SSergey Zigachev 			amdgpu_encoder = to_amdgpu_encoder(connector_funcs->best_encoder(connector));
584b843c749SSergey Zigachev 		}
585b843c749SSergey Zigachev 
586b843c749SSergey Zigachev 		switch (val) {
587b843c749SSergey Zigachev 		default:
588b843c749SSergey Zigachev 		case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break;
589b843c749SSergey Zigachev 		case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break;
590b843c749SSergey Zigachev 		case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break;
591b843c749SSergey Zigachev 		case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break;
592b843c749SSergey Zigachev 		}
593b843c749SSergey Zigachev 		if (amdgpu_encoder->rmx_type == rmx_type)
594b843c749SSergey Zigachev 			return 0;
595b843c749SSergey Zigachev 
596b843c749SSergey Zigachev 		if ((rmx_type != DRM_MODE_SCALE_NONE) &&
597b843c749SSergey Zigachev 		    (amdgpu_encoder->native_mode.clock == 0))
598b843c749SSergey Zigachev 			return 0;
599b843c749SSergey Zigachev 
600b843c749SSergey Zigachev 		amdgpu_encoder->rmx_type = rmx_type;
601b843c749SSergey Zigachev 
602b843c749SSergey Zigachev 		amdgpu_connector_property_change_mode(&amdgpu_encoder->base);
603b843c749SSergey Zigachev 	}
604b843c749SSergey Zigachev 
605b843c749SSergey Zigachev 	return 0;
606b843c749SSergey Zigachev }
607b843c749SSergey Zigachev 
608b843c749SSergey Zigachev static void
amdgpu_connector_fixup_lcd_native_mode(struct drm_encoder * encoder,struct drm_connector * connector)609b843c749SSergey Zigachev amdgpu_connector_fixup_lcd_native_mode(struct drm_encoder *encoder,
610b843c749SSergey Zigachev 					struct drm_connector *connector)
611b843c749SSergey Zigachev {
612b843c749SSergey Zigachev 	struct amdgpu_encoder *amdgpu_encoder =	to_amdgpu_encoder(encoder);
613b843c749SSergey Zigachev 	struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
614b843c749SSergey Zigachev 	struct drm_display_mode *t, *mode;
615b843c749SSergey Zigachev 
616b843c749SSergey Zigachev 	/* If the EDID preferred mode doesn't match the native mode, use it */
617b843c749SSergey Zigachev 	list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
618b843c749SSergey Zigachev 		if (mode->type & DRM_MODE_TYPE_PREFERRED) {
619b843c749SSergey Zigachev 			if (mode->hdisplay != native_mode->hdisplay ||
620b843c749SSergey Zigachev 			    mode->vdisplay != native_mode->vdisplay)
621b843c749SSergey Zigachev 				memcpy(native_mode, mode, sizeof(*mode));
622b843c749SSergey Zigachev 		}
623b843c749SSergey Zigachev 	}
624b843c749SSergey Zigachev 
625b843c749SSergey Zigachev 	/* Try to get native mode details from EDID if necessary */
626b843c749SSergey Zigachev 	if (!native_mode->clock) {
627b843c749SSergey Zigachev 		list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
628b843c749SSergey Zigachev 			if (mode->hdisplay == native_mode->hdisplay &&
629b843c749SSergey Zigachev 			    mode->vdisplay == native_mode->vdisplay) {
630b843c749SSergey Zigachev 				*native_mode = *mode;
631b843c749SSergey Zigachev 				drm_mode_set_crtcinfo(native_mode, CRTC_INTERLACE_HALVE_V);
632b843c749SSergey Zigachev 				DRM_DEBUG_KMS("Determined LVDS native mode details from EDID\n");
633b843c749SSergey Zigachev 				break;
634b843c749SSergey Zigachev 			}
635b843c749SSergey Zigachev 		}
636b843c749SSergey Zigachev 	}
637b843c749SSergey Zigachev 
638b843c749SSergey Zigachev 	if (!native_mode->clock) {
639b843c749SSergey Zigachev 		DRM_DEBUG_KMS("No LVDS native mode details, disabling RMX\n");
640b843c749SSergey Zigachev 		amdgpu_encoder->rmx_type = RMX_OFF;
641b843c749SSergey Zigachev 	}
642b843c749SSergey Zigachev }
643b843c749SSergey Zigachev 
amdgpu_connector_lvds_get_modes(struct drm_connector * connector)644b843c749SSergey Zigachev static int amdgpu_connector_lvds_get_modes(struct drm_connector *connector)
645b843c749SSergey Zigachev {
646b843c749SSergey Zigachev 	struct drm_encoder *encoder;
647b843c749SSergey Zigachev 	int ret = 0;
648b843c749SSergey Zigachev 	struct drm_display_mode *mode;
649b843c749SSergey Zigachev 
650b843c749SSergey Zigachev 	amdgpu_connector_get_edid(connector);
651b843c749SSergey Zigachev 	ret = amdgpu_connector_ddc_get_modes(connector);
652b843c749SSergey Zigachev 	if (ret > 0) {
653b843c749SSergey Zigachev 		encoder = amdgpu_connector_best_single_encoder(connector);
654b843c749SSergey Zigachev 		if (encoder) {
655b843c749SSergey Zigachev 			amdgpu_connector_fixup_lcd_native_mode(encoder, connector);
656b843c749SSergey Zigachev 			/* add scaled modes */
657b843c749SSergey Zigachev 			amdgpu_connector_add_common_modes(encoder, connector);
658b843c749SSergey Zigachev 		}
659b843c749SSergey Zigachev 		return ret;
660b843c749SSergey Zigachev 	}
661b843c749SSergey Zigachev 
662b843c749SSergey Zigachev 	encoder = amdgpu_connector_best_single_encoder(connector);
663b843c749SSergey Zigachev 	if (!encoder)
664b843c749SSergey Zigachev 		return 0;
665b843c749SSergey Zigachev 
666b843c749SSergey Zigachev 	/* we have no EDID modes */
667b843c749SSergey Zigachev 	mode = amdgpu_connector_lcd_native_mode(encoder);
668b843c749SSergey Zigachev 	if (mode) {
669b843c749SSergey Zigachev 		ret = 1;
670b843c749SSergey Zigachev 		drm_mode_probed_add(connector, mode);
671b843c749SSergey Zigachev 		/* add the width/height from vbios tables if available */
672b843c749SSergey Zigachev 		connector->display_info.width_mm = mode->width_mm;
673b843c749SSergey Zigachev 		connector->display_info.height_mm = mode->height_mm;
674b843c749SSergey Zigachev 		/* add scaled modes */
675b843c749SSergey Zigachev 		amdgpu_connector_add_common_modes(encoder, connector);
676b843c749SSergey Zigachev 	}
677b843c749SSergey Zigachev 
678b843c749SSergey Zigachev 	return ret;
679b843c749SSergey Zigachev }
680b843c749SSergey Zigachev 
amdgpu_connector_lvds_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)681b843c749SSergey Zigachev static enum drm_mode_status amdgpu_connector_lvds_mode_valid(struct drm_connector *connector,
682b843c749SSergey Zigachev 					     struct drm_display_mode *mode)
683b843c749SSergey Zigachev {
684b843c749SSergey Zigachev 	struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector);
685b843c749SSergey Zigachev 
686b843c749SSergey Zigachev 	if ((mode->hdisplay < 320) || (mode->vdisplay < 240))
687b843c749SSergey Zigachev 		return MODE_PANEL;
688b843c749SSergey Zigachev 
689b843c749SSergey Zigachev 	if (encoder) {
690b843c749SSergey Zigachev 		struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
691b843c749SSergey Zigachev 		struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
692b843c749SSergey Zigachev 
693b843c749SSergey Zigachev 		/* AVIVO hardware supports downscaling modes larger than the panel
694b843c749SSergey Zigachev 		 * to the panel size, but I'm not sure this is desirable.
695b843c749SSergey Zigachev 		 */
696b843c749SSergey Zigachev 		if ((mode->hdisplay > native_mode->hdisplay) ||
697b843c749SSergey Zigachev 		    (mode->vdisplay > native_mode->vdisplay))
698b843c749SSergey Zigachev 			return MODE_PANEL;
699b843c749SSergey Zigachev 
700b843c749SSergey Zigachev 		/* if scaling is disabled, block non-native modes */
701b843c749SSergey Zigachev 		if (amdgpu_encoder->rmx_type == RMX_OFF) {
702b843c749SSergey Zigachev 			if ((mode->hdisplay != native_mode->hdisplay) ||
703b843c749SSergey Zigachev 			    (mode->vdisplay != native_mode->vdisplay))
704b843c749SSergey Zigachev 				return MODE_PANEL;
705b843c749SSergey Zigachev 		}
706b843c749SSergey Zigachev 	}
707b843c749SSergey Zigachev 
708b843c749SSergey Zigachev 	return MODE_OK;
709b843c749SSergey Zigachev }
710b843c749SSergey Zigachev 
711b843c749SSergey Zigachev static enum drm_connector_status
amdgpu_connector_lvds_detect(struct drm_connector * connector,bool force)712b843c749SSergey Zigachev amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force)
713b843c749SSergey Zigachev {
714b843c749SSergey Zigachev 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
715b843c749SSergey Zigachev 	struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector);
716b843c749SSergey Zigachev 	enum drm_connector_status ret = connector_status_disconnected;
717*78973132SSergey Zigachev #if 0
718b843c749SSergey Zigachev 	int r;
719b843c749SSergey Zigachev 
720b843c749SSergey Zigachev 	if (!drm_kms_helper_is_poll_worker()) {
721b843c749SSergey Zigachev 		r = pm_runtime_get_sync(connector->dev->dev);
722b843c749SSergey Zigachev 		if (r < 0) {
723b843c749SSergey Zigachev 			pm_runtime_put_autosuspend(connector->dev->dev);
724b843c749SSergey Zigachev 			return connector_status_disconnected;
725b843c749SSergey Zigachev 		}
726b843c749SSergey Zigachev 	}
727*78973132SSergey Zigachev #endif
728b843c749SSergey Zigachev 
729b843c749SSergey Zigachev 	if (encoder) {
730b843c749SSergey Zigachev 		struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
731b843c749SSergey Zigachev 		struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
732b843c749SSergey Zigachev 
733b843c749SSergey Zigachev 		/* check if panel is valid */
734b843c749SSergey Zigachev 		if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
735b843c749SSergey Zigachev 			ret = connector_status_connected;
736b843c749SSergey Zigachev 
737b843c749SSergey Zigachev 	}
738b843c749SSergey Zigachev 
739b843c749SSergey Zigachev 	/* check for edid as well */
740b843c749SSergey Zigachev 	amdgpu_connector_get_edid(connector);
741b843c749SSergey Zigachev 	if (amdgpu_connector->edid)
742b843c749SSergey Zigachev 		ret = connector_status_connected;
743b843c749SSergey Zigachev 	/* check acpi lid status ??? */
744b843c749SSergey Zigachev 
745b843c749SSergey Zigachev 	amdgpu_connector_update_scratch_regs(connector, ret);
746b843c749SSergey Zigachev 
747b843c749SSergey Zigachev 	if (!drm_kms_helper_is_poll_worker()) {
748b843c749SSergey Zigachev 		pm_runtime_mark_last_busy(connector->dev->dev);
749*78973132SSergey Zigachev #if 0
750b843c749SSergey Zigachev 		pm_runtime_put_autosuspend(connector->dev->dev);
751*78973132SSergey Zigachev #endif
752b843c749SSergey Zigachev 	}
753b843c749SSergey Zigachev 
754b843c749SSergey Zigachev 	return ret;
755b843c749SSergey Zigachev }
756b843c749SSergey Zigachev 
amdgpu_connector_unregister(struct drm_connector * connector)757b843c749SSergey Zigachev static void amdgpu_connector_unregister(struct drm_connector *connector)
758b843c749SSergey Zigachev {
759b843c749SSergey Zigachev 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
760b843c749SSergey Zigachev 
761b843c749SSergey Zigachev 	if (amdgpu_connector->ddc_bus && amdgpu_connector->ddc_bus->has_aux) {
762b843c749SSergey Zigachev 		drm_dp_aux_unregister(&amdgpu_connector->ddc_bus->aux);
763b843c749SSergey Zigachev 		amdgpu_connector->ddc_bus->has_aux = false;
764b843c749SSergey Zigachev 	}
765b843c749SSergey Zigachev }
766b843c749SSergey Zigachev 
amdgpu_connector_destroy(struct drm_connector * connector)767b843c749SSergey Zigachev static void amdgpu_connector_destroy(struct drm_connector *connector)
768b843c749SSergey Zigachev {
769b843c749SSergey Zigachev 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
770b843c749SSergey Zigachev 
771b843c749SSergey Zigachev 	amdgpu_connector_free_edid(connector);
772b843c749SSergey Zigachev 	kfree(amdgpu_connector->con_priv);
773b843c749SSergey Zigachev 	drm_connector_unregister(connector);
774b843c749SSergey Zigachev 	drm_connector_cleanup(connector);
775b843c749SSergey Zigachev 	kfree(connector);
776b843c749SSergey Zigachev }
777b843c749SSergey Zigachev 
amdgpu_connector_set_lcd_property(struct drm_connector * connector,struct drm_property * property,uint64_t value)778b843c749SSergey Zigachev static int amdgpu_connector_set_lcd_property(struct drm_connector *connector,
779b843c749SSergey Zigachev 					      struct drm_property *property,
780b843c749SSergey Zigachev 					      uint64_t value)
781b843c749SSergey Zigachev {
782b843c749SSergey Zigachev 	struct drm_device *dev = connector->dev;
783b843c749SSergey Zigachev 	struct amdgpu_encoder *amdgpu_encoder;
784b843c749SSergey Zigachev 	enum amdgpu_rmx_type rmx_type;
785b843c749SSergey Zigachev 
786b843c749SSergey Zigachev 	DRM_DEBUG_KMS("\n");
787b843c749SSergey Zigachev 	if (property != dev->mode_config.scaling_mode_property)
788b843c749SSergey Zigachev 		return 0;
789b843c749SSergey Zigachev 
790b843c749SSergey Zigachev 	if (connector->encoder)
791b843c749SSergey Zigachev 		amdgpu_encoder = to_amdgpu_encoder(connector->encoder);
792b843c749SSergey Zigachev 	else {
793b843c749SSergey Zigachev 		const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
794b843c749SSergey Zigachev 		amdgpu_encoder = to_amdgpu_encoder(connector_funcs->best_encoder(connector));
795b843c749SSergey Zigachev 	}
796b843c749SSergey Zigachev 
797b843c749SSergey Zigachev 	switch (value) {
798b843c749SSergey Zigachev 	case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break;
799b843c749SSergey Zigachev 	case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break;
800b843c749SSergey Zigachev 	case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break;
801b843c749SSergey Zigachev 	default:
802b843c749SSergey Zigachev 	case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break;
803b843c749SSergey Zigachev 	}
804b843c749SSergey Zigachev 	if (amdgpu_encoder->rmx_type == rmx_type)
805b843c749SSergey Zigachev 		return 0;
806b843c749SSergey Zigachev 
807b843c749SSergey Zigachev 	amdgpu_encoder->rmx_type = rmx_type;
808b843c749SSergey Zigachev 
809b843c749SSergey Zigachev 	amdgpu_connector_property_change_mode(&amdgpu_encoder->base);
810b843c749SSergey Zigachev 	return 0;
811b843c749SSergey Zigachev }
812b843c749SSergey Zigachev 
813b843c749SSergey Zigachev 
814b843c749SSergey Zigachev static const struct drm_connector_helper_funcs amdgpu_connector_lvds_helper_funcs = {
815b843c749SSergey Zigachev 	.get_modes = amdgpu_connector_lvds_get_modes,
816b843c749SSergey Zigachev 	.mode_valid = amdgpu_connector_lvds_mode_valid,
817b843c749SSergey Zigachev 	.best_encoder = amdgpu_connector_best_single_encoder,
818b843c749SSergey Zigachev };
819b843c749SSergey Zigachev 
820b843c749SSergey Zigachev static const struct drm_connector_funcs amdgpu_connector_lvds_funcs = {
821b843c749SSergey Zigachev 	.dpms = drm_helper_connector_dpms,
822b843c749SSergey Zigachev 	.detect = amdgpu_connector_lvds_detect,
823b843c749SSergey Zigachev 	.fill_modes = drm_helper_probe_single_connector_modes,
824b843c749SSergey Zigachev 	.early_unregister = amdgpu_connector_unregister,
825b843c749SSergey Zigachev 	.destroy = amdgpu_connector_destroy,
826b843c749SSergey Zigachev 	.set_property = amdgpu_connector_set_lcd_property,
827b843c749SSergey Zigachev };
828b843c749SSergey Zigachev 
amdgpu_connector_vga_get_modes(struct drm_connector * connector)829b843c749SSergey Zigachev static int amdgpu_connector_vga_get_modes(struct drm_connector *connector)
830b843c749SSergey Zigachev {
831b843c749SSergey Zigachev 	int ret;
832b843c749SSergey Zigachev 
833b843c749SSergey Zigachev 	amdgpu_connector_get_edid(connector);
834b843c749SSergey Zigachev 	ret = amdgpu_connector_ddc_get_modes(connector);
835b843c749SSergey Zigachev 
836b843c749SSergey Zigachev 	return ret;
837b843c749SSergey Zigachev }
838b843c749SSergey Zigachev 
amdgpu_connector_vga_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)839b843c749SSergey Zigachev static enum drm_mode_status amdgpu_connector_vga_mode_valid(struct drm_connector *connector,
840b843c749SSergey Zigachev 					    struct drm_display_mode *mode)
841b843c749SSergey Zigachev {
842b843c749SSergey Zigachev 	struct drm_device *dev = connector->dev;
843b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev->dev_private;
844b843c749SSergey Zigachev 
845b843c749SSergey Zigachev 	/* XXX check mode bandwidth */
846b843c749SSergey Zigachev 
847b843c749SSergey Zigachev 	if ((mode->clock / 10) > adev->clock.max_pixel_clock)
848b843c749SSergey Zigachev 		return MODE_CLOCK_HIGH;
849b843c749SSergey Zigachev 
850b843c749SSergey Zigachev 	return MODE_OK;
851b843c749SSergey Zigachev }
852b843c749SSergey Zigachev 
853b843c749SSergey Zigachev static enum drm_connector_status
amdgpu_connector_vga_detect(struct drm_connector * connector,bool force)854b843c749SSergey Zigachev amdgpu_connector_vga_detect(struct drm_connector *connector, bool force)
855b843c749SSergey Zigachev {
856b843c749SSergey Zigachev 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
857b843c749SSergey Zigachev 	struct drm_encoder *encoder;
858b843c749SSergey Zigachev 	const struct drm_encoder_helper_funcs *encoder_funcs;
859b843c749SSergey Zigachev 	bool dret = false;
860b843c749SSergey Zigachev 	enum drm_connector_status ret = connector_status_disconnected;
861*78973132SSergey Zigachev #if 0
862b843c749SSergey Zigachev 	int r;
863b843c749SSergey Zigachev 
864b843c749SSergey Zigachev 	if (!drm_kms_helper_is_poll_worker()) {
865b843c749SSergey Zigachev 		r = pm_runtime_get_sync(connector->dev->dev);
866b843c749SSergey Zigachev 		if (r < 0) {
867b843c749SSergey Zigachev 			pm_runtime_put_autosuspend(connector->dev->dev);
868b843c749SSergey Zigachev 			return connector_status_disconnected;
869b843c749SSergey Zigachev 		}
870b843c749SSergey Zigachev 	}
871*78973132SSergey Zigachev #endif
872b843c749SSergey Zigachev 
873b843c749SSergey Zigachev 	encoder = amdgpu_connector_best_single_encoder(connector);
874b843c749SSergey Zigachev 	if (!encoder)
875b843c749SSergey Zigachev 		ret = connector_status_disconnected;
876b843c749SSergey Zigachev 
877b843c749SSergey Zigachev 	if (amdgpu_connector->ddc_bus)
878b843c749SSergey Zigachev 		dret = amdgpu_display_ddc_probe(amdgpu_connector, false);
879b843c749SSergey Zigachev 	if (dret) {
880b843c749SSergey Zigachev 		amdgpu_connector->detected_by_load = false;
881b843c749SSergey Zigachev 		amdgpu_connector_free_edid(connector);
882b843c749SSergey Zigachev 		amdgpu_connector_get_edid(connector);
883b843c749SSergey Zigachev 
884b843c749SSergey Zigachev 		if (!amdgpu_connector->edid) {
885b843c749SSergey Zigachev 			DRM_ERROR("%s: probed a monitor but no|invalid EDID\n",
886b843c749SSergey Zigachev 					connector->name);
887b843c749SSergey Zigachev 			ret = connector_status_connected;
888b843c749SSergey Zigachev 		} else {
889b843c749SSergey Zigachev 			amdgpu_connector->use_digital =
890b843c749SSergey Zigachev 				!!(amdgpu_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
891b843c749SSergey Zigachev 
892b843c749SSergey Zigachev 			/* some oems have boards with separate digital and analog connectors
893b843c749SSergey Zigachev 			 * with a shared ddc line (often vga + hdmi)
894b843c749SSergey Zigachev 			 */
895b843c749SSergey Zigachev 			if (amdgpu_connector->use_digital && amdgpu_connector->shared_ddc) {
896b843c749SSergey Zigachev 				amdgpu_connector_free_edid(connector);
897b843c749SSergey Zigachev 				ret = connector_status_disconnected;
898b843c749SSergey Zigachev 			} else {
899b843c749SSergey Zigachev 				ret = connector_status_connected;
900b843c749SSergey Zigachev 			}
901b843c749SSergey Zigachev 		}
902b843c749SSergey Zigachev 	} else {
903b843c749SSergey Zigachev 
904b843c749SSergey Zigachev 		/* if we aren't forcing don't do destructive polling */
905b843c749SSergey Zigachev 		if (!force) {
906b843c749SSergey Zigachev 			/* only return the previous status if we last
907b843c749SSergey Zigachev 			 * detected a monitor via load.
908b843c749SSergey Zigachev 			 */
909b843c749SSergey Zigachev 			if (amdgpu_connector->detected_by_load)
910b843c749SSergey Zigachev 				ret = connector->status;
911b843c749SSergey Zigachev 			goto out;
912b843c749SSergey Zigachev 		}
913b843c749SSergey Zigachev 
914b843c749SSergey Zigachev 		if (amdgpu_connector->dac_load_detect && encoder) {
915b843c749SSergey Zigachev 			encoder_funcs = encoder->helper_private;
916b843c749SSergey Zigachev 			ret = encoder_funcs->detect(encoder, connector);
917b843c749SSergey Zigachev 			if (ret != connector_status_disconnected)
918b843c749SSergey Zigachev 				amdgpu_connector->detected_by_load = true;
919b843c749SSergey Zigachev 		}
920b843c749SSergey Zigachev 	}
921b843c749SSergey Zigachev 
922b843c749SSergey Zigachev 	amdgpu_connector_update_scratch_regs(connector, ret);
923b843c749SSergey Zigachev 
924b843c749SSergey Zigachev out:
925b843c749SSergey Zigachev 	if (!drm_kms_helper_is_poll_worker()) {
926b843c749SSergey Zigachev 		pm_runtime_mark_last_busy(connector->dev->dev);
927b843c749SSergey Zigachev 		pm_runtime_put_autosuspend(connector->dev->dev);
928b843c749SSergey Zigachev 	}
929b843c749SSergey Zigachev 
930b843c749SSergey Zigachev 	return ret;
931b843c749SSergey Zigachev }
932b843c749SSergey Zigachev 
933b843c749SSergey Zigachev static const struct drm_connector_helper_funcs amdgpu_connector_vga_helper_funcs = {
934b843c749SSergey Zigachev 	.get_modes = amdgpu_connector_vga_get_modes,
935b843c749SSergey Zigachev 	.mode_valid = amdgpu_connector_vga_mode_valid,
936b843c749SSergey Zigachev 	.best_encoder = amdgpu_connector_best_single_encoder,
937b843c749SSergey Zigachev };
938b843c749SSergey Zigachev 
939b843c749SSergey Zigachev static const struct drm_connector_funcs amdgpu_connector_vga_funcs = {
940b843c749SSergey Zigachev 	.dpms = drm_helper_connector_dpms,
941b843c749SSergey Zigachev 	.detect = amdgpu_connector_vga_detect,
942b843c749SSergey Zigachev 	.fill_modes = drm_helper_probe_single_connector_modes,
943b843c749SSergey Zigachev 	.early_unregister = amdgpu_connector_unregister,
944b843c749SSergey Zigachev 	.destroy = amdgpu_connector_destroy,
945b843c749SSergey Zigachev 	.set_property = amdgpu_connector_set_property,
946b843c749SSergey Zigachev };
947b843c749SSergey Zigachev 
948b843c749SSergey Zigachev static bool
amdgpu_connector_check_hpd_status_unchanged(struct drm_connector * connector)949b843c749SSergey Zigachev amdgpu_connector_check_hpd_status_unchanged(struct drm_connector *connector)
950b843c749SSergey Zigachev {
951b843c749SSergey Zigachev 	struct drm_device *dev = connector->dev;
952b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev->dev_private;
953b843c749SSergey Zigachev 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
954b843c749SSergey Zigachev 	enum drm_connector_status status;
955b843c749SSergey Zigachev 
956b843c749SSergey Zigachev 	if (amdgpu_connector->hpd.hpd != AMDGPU_HPD_NONE) {
957b843c749SSergey Zigachev 		if (amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd))
958b843c749SSergey Zigachev 			status = connector_status_connected;
959b843c749SSergey Zigachev 		else
960b843c749SSergey Zigachev 			status = connector_status_disconnected;
961b843c749SSergey Zigachev 		if (connector->status == status)
962b843c749SSergey Zigachev 			return true;
963b843c749SSergey Zigachev 	}
964b843c749SSergey Zigachev 
965b843c749SSergey Zigachev 	return false;
966b843c749SSergey Zigachev }
967b843c749SSergey Zigachev 
968b843c749SSergey Zigachev /*
969b843c749SSergey Zigachev  * DVI is complicated
970b843c749SSergey Zigachev  * Do a DDC probe, if DDC probe passes, get the full EDID so
971b843c749SSergey Zigachev  * we can do analog/digital monitor detection at this point.
972b843c749SSergey Zigachev  * If the monitor is an analog monitor or we got no DDC,
973b843c749SSergey Zigachev  * we need to find the DAC encoder object for this connector.
974b843c749SSergey Zigachev  * If we got no DDC, we do load detection on the DAC encoder object.
975b843c749SSergey Zigachev  * If we got analog DDC or load detection passes on the DAC encoder
976b843c749SSergey Zigachev  * we have to check if this analog encoder is shared with anyone else (TV)
977b843c749SSergey Zigachev  * if its shared we have to set the other connector to disconnected.
978b843c749SSergey Zigachev  */
979b843c749SSergey Zigachev static enum drm_connector_status
amdgpu_connector_dvi_detect(struct drm_connector * connector,bool force)980b843c749SSergey Zigachev amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force)
981b843c749SSergey Zigachev {
982b843c749SSergey Zigachev 	struct drm_device *dev = connector->dev;
983b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev->dev_private;
984b843c749SSergey Zigachev 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
985b843c749SSergey Zigachev 	const struct drm_encoder_helper_funcs *encoder_funcs;
986b843c749SSergey Zigachev 	enum drm_connector_status ret = connector_status_disconnected;
987b843c749SSergey Zigachev 	bool dret = false, broken_edid = false;
988b843c749SSergey Zigachev 
989*78973132SSergey Zigachev #if 0
990b843c749SSergey Zigachev 	if (!drm_kms_helper_is_poll_worker()) {
991b843c749SSergey Zigachev 		r = pm_runtime_get_sync(connector->dev->dev);
992b843c749SSergey Zigachev 		if (r < 0) {
993b843c749SSergey Zigachev 			pm_runtime_put_autosuspend(connector->dev->dev);
994b843c749SSergey Zigachev 			return connector_status_disconnected;
995b843c749SSergey Zigachev 		}
996b843c749SSergey Zigachev 	}
997*78973132SSergey Zigachev #endif
998b843c749SSergey Zigachev 
999b843c749SSergey Zigachev 	if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
1000b843c749SSergey Zigachev 		ret = connector->status;
1001b843c749SSergey Zigachev 		goto exit;
1002b843c749SSergey Zigachev 	}
1003b843c749SSergey Zigachev 
1004b843c749SSergey Zigachev 	if (amdgpu_connector->ddc_bus)
1005b843c749SSergey Zigachev 		dret = amdgpu_display_ddc_probe(amdgpu_connector, false);
1006b843c749SSergey Zigachev 	if (dret) {
1007b843c749SSergey Zigachev 		amdgpu_connector->detected_by_load = false;
1008b843c749SSergey Zigachev 		amdgpu_connector_free_edid(connector);
1009b843c749SSergey Zigachev 		amdgpu_connector_get_edid(connector);
1010b843c749SSergey Zigachev 
1011b843c749SSergey Zigachev 		if (!amdgpu_connector->edid) {
1012b843c749SSergey Zigachev 			DRM_ERROR("%s: probed a monitor but no|invalid EDID\n",
1013b843c749SSergey Zigachev 					connector->name);
1014b843c749SSergey Zigachev 			ret = connector_status_connected;
1015b843c749SSergey Zigachev 			broken_edid = true; /* defer use_digital to later */
1016b843c749SSergey Zigachev 		} else {
1017b843c749SSergey Zigachev 			amdgpu_connector->use_digital =
1018b843c749SSergey Zigachev 				!!(amdgpu_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
1019b843c749SSergey Zigachev 
1020b843c749SSergey Zigachev 			/* some oems have boards with separate digital and analog connectors
1021b843c749SSergey Zigachev 			 * with a shared ddc line (often vga + hdmi)
1022b843c749SSergey Zigachev 			 */
1023b843c749SSergey Zigachev 			if ((!amdgpu_connector->use_digital) && amdgpu_connector->shared_ddc) {
1024b843c749SSergey Zigachev 				amdgpu_connector_free_edid(connector);
1025b843c749SSergey Zigachev 				ret = connector_status_disconnected;
1026b843c749SSergey Zigachev 			} else {
1027b843c749SSergey Zigachev 				ret = connector_status_connected;
1028b843c749SSergey Zigachev 			}
1029b843c749SSergey Zigachev 
1030b843c749SSergey Zigachev 			/* This gets complicated.  We have boards with VGA + HDMI with a
1031b843c749SSergey Zigachev 			 * shared DDC line and we have boards with DVI-D + HDMI with a shared
1032b843c749SSergey Zigachev 			 * DDC line.  The latter is more complex because with DVI<->HDMI adapters
1033b843c749SSergey Zigachev 			 * you don't really know what's connected to which port as both are digital.
1034b843c749SSergey Zigachev 			 */
1035b843c749SSergey Zigachev 			if (amdgpu_connector->shared_ddc && (ret == connector_status_connected)) {
1036b843c749SSergey Zigachev 				struct drm_connector *list_connector;
1037b843c749SSergey Zigachev 				struct amdgpu_connector *list_amdgpu_connector;
1038b843c749SSergey Zigachev 				list_for_each_entry(list_connector, &dev->mode_config.connector_list, head) {
1039b843c749SSergey Zigachev 					if (connector == list_connector)
1040b843c749SSergey Zigachev 						continue;
1041b843c749SSergey Zigachev 					list_amdgpu_connector = to_amdgpu_connector(list_connector);
1042b843c749SSergey Zigachev 					if (list_amdgpu_connector->shared_ddc &&
1043b843c749SSergey Zigachev 					    (list_amdgpu_connector->ddc_bus->rec.i2c_id ==
1044b843c749SSergey Zigachev 					     amdgpu_connector->ddc_bus->rec.i2c_id)) {
1045b843c749SSergey Zigachev 						/* cases where both connectors are digital */
1046b843c749SSergey Zigachev 						if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) {
1047b843c749SSergey Zigachev 							/* hpd is our only option in this case */
1048b843c749SSergey Zigachev 							if (!amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd)) {
1049b843c749SSergey Zigachev 								amdgpu_connector_free_edid(connector);
1050b843c749SSergey Zigachev 								ret = connector_status_disconnected;
1051b843c749SSergey Zigachev 							}
1052b843c749SSergey Zigachev 						}
1053b843c749SSergey Zigachev 					}
1054b843c749SSergey Zigachev 				}
1055b843c749SSergey Zigachev 			}
1056b843c749SSergey Zigachev 		}
1057b843c749SSergey Zigachev 	}
1058b843c749SSergey Zigachev 
1059b843c749SSergey Zigachev 	if ((ret == connector_status_connected) && (amdgpu_connector->use_digital == true))
1060b843c749SSergey Zigachev 		goto out;
1061b843c749SSergey Zigachev 
1062b843c749SSergey Zigachev 	/* DVI-D and HDMI-A are digital only */
1063b843c749SSergey Zigachev 	if ((connector->connector_type == DRM_MODE_CONNECTOR_DVID) ||
1064b843c749SSergey Zigachev 	    (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA))
1065b843c749SSergey Zigachev 		goto out;
1066b843c749SSergey Zigachev 
1067b843c749SSergey Zigachev 	/* if we aren't forcing don't do destructive polling */
1068b843c749SSergey Zigachev 	if (!force) {
1069b843c749SSergey Zigachev 		/* only return the previous status if we last
1070b843c749SSergey Zigachev 		 * detected a monitor via load.
1071b843c749SSergey Zigachev 		 */
1072b843c749SSergey Zigachev 		if (amdgpu_connector->detected_by_load)
1073b843c749SSergey Zigachev 			ret = connector->status;
1074b843c749SSergey Zigachev 		goto out;
1075b843c749SSergey Zigachev 	}
1076b843c749SSergey Zigachev 
1077b843c749SSergey Zigachev 	/* find analog encoder */
1078b843c749SSergey Zigachev 	if (amdgpu_connector->dac_load_detect) {
1079b843c749SSergey Zigachev 		struct drm_encoder *encoder;
1080b843c749SSergey Zigachev 		int i;
1081b843c749SSergey Zigachev 
1082b843c749SSergey Zigachev 		drm_connector_for_each_possible_encoder(connector, encoder, i) {
1083b843c749SSergey Zigachev 			if (encoder->encoder_type != DRM_MODE_ENCODER_DAC &&
1084b843c749SSergey Zigachev 			    encoder->encoder_type != DRM_MODE_ENCODER_TVDAC)
1085b843c749SSergey Zigachev 				continue;
1086b843c749SSergey Zigachev 
1087b843c749SSergey Zigachev 			encoder_funcs = encoder->helper_private;
1088b843c749SSergey Zigachev 			if (encoder_funcs->detect) {
1089b843c749SSergey Zigachev 				if (!broken_edid) {
1090b843c749SSergey Zigachev 					if (ret != connector_status_connected) {
1091b843c749SSergey Zigachev 						/* deal with analog monitors without DDC */
1092b843c749SSergey Zigachev 						ret = encoder_funcs->detect(encoder, connector);
1093b843c749SSergey Zigachev 						if (ret == connector_status_connected) {
1094b843c749SSergey Zigachev 							amdgpu_connector->use_digital = false;
1095b843c749SSergey Zigachev 						}
1096b843c749SSergey Zigachev 						if (ret != connector_status_disconnected)
1097b843c749SSergey Zigachev 							amdgpu_connector->detected_by_load = true;
1098b843c749SSergey Zigachev 					}
1099b843c749SSergey Zigachev 				} else {
1100b843c749SSergey Zigachev 					enum drm_connector_status lret;
1101b843c749SSergey Zigachev 					/* assume digital unless load detected otherwise */
1102b843c749SSergey Zigachev 					amdgpu_connector->use_digital = true;
1103b843c749SSergey Zigachev 					lret = encoder_funcs->detect(encoder, connector);
1104b843c749SSergey Zigachev 					DRM_DEBUG_KMS("load_detect %x returned: %x\n",encoder->encoder_type,lret);
1105b843c749SSergey Zigachev 					if (lret == connector_status_connected)
1106b843c749SSergey Zigachev 						amdgpu_connector->use_digital = false;
1107b843c749SSergey Zigachev 				}
1108b843c749SSergey Zigachev 				break;
1109b843c749SSergey Zigachev 			}
1110b843c749SSergey Zigachev 		}
1111b843c749SSergey Zigachev 	}
1112b843c749SSergey Zigachev 
1113b843c749SSergey Zigachev out:
1114b843c749SSergey Zigachev 	/* updated in get modes as well since we need to know if it's analog or digital */
1115b843c749SSergey Zigachev 	amdgpu_connector_update_scratch_regs(connector, ret);
1116b843c749SSergey Zigachev 
1117b843c749SSergey Zigachev exit:
1118b843c749SSergey Zigachev 	if (!drm_kms_helper_is_poll_worker()) {
1119b843c749SSergey Zigachev 		pm_runtime_mark_last_busy(connector->dev->dev);
1120b843c749SSergey Zigachev 		pm_runtime_put_autosuspend(connector->dev->dev);
1121b843c749SSergey Zigachev 	}
1122b843c749SSergey Zigachev 
1123b843c749SSergey Zigachev 	return ret;
1124b843c749SSergey Zigachev }
1125b843c749SSergey Zigachev 
1126b843c749SSergey Zigachev /* okay need to be smart in here about which encoder to pick */
1127b843c749SSergey Zigachev static struct drm_encoder *
amdgpu_connector_dvi_encoder(struct drm_connector * connector)1128b843c749SSergey Zigachev amdgpu_connector_dvi_encoder(struct drm_connector *connector)
1129b843c749SSergey Zigachev {
1130b843c749SSergey Zigachev 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
1131b843c749SSergey Zigachev 	struct drm_encoder *encoder;
1132b843c749SSergey Zigachev 	int i;
1133b843c749SSergey Zigachev 
1134b843c749SSergey Zigachev 	drm_connector_for_each_possible_encoder(connector, encoder, i) {
1135b843c749SSergey Zigachev 		if (amdgpu_connector->use_digital == true) {
1136b843c749SSergey Zigachev 			if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
1137b843c749SSergey Zigachev 				return encoder;
1138b843c749SSergey Zigachev 		} else {
1139b843c749SSergey Zigachev 			if (encoder->encoder_type == DRM_MODE_ENCODER_DAC ||
1140b843c749SSergey Zigachev 			    encoder->encoder_type == DRM_MODE_ENCODER_TVDAC)
1141b843c749SSergey Zigachev 				return encoder;
1142b843c749SSergey Zigachev 		}
1143b843c749SSergey Zigachev 	}
1144b843c749SSergey Zigachev 
1145b843c749SSergey Zigachev 	/* see if we have a default encoder  TODO */
1146b843c749SSergey Zigachev 
1147b843c749SSergey Zigachev 	/* then check use digitial */
1148b843c749SSergey Zigachev 	/* pick the first one */
1149b843c749SSergey Zigachev 	drm_connector_for_each_possible_encoder(connector, encoder, i)
1150b843c749SSergey Zigachev 		return encoder;
1151b843c749SSergey Zigachev 
1152b843c749SSergey Zigachev 	return NULL;
1153b843c749SSergey Zigachev }
1154b843c749SSergey Zigachev 
amdgpu_connector_dvi_force(struct drm_connector * connector)1155b843c749SSergey Zigachev static void amdgpu_connector_dvi_force(struct drm_connector *connector)
1156b843c749SSergey Zigachev {
1157b843c749SSergey Zigachev 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
1158b843c749SSergey Zigachev 	if (connector->force == DRM_FORCE_ON)
1159b843c749SSergey Zigachev 		amdgpu_connector->use_digital = false;
1160b843c749SSergey Zigachev 	if (connector->force == DRM_FORCE_ON_DIGITAL)
1161b843c749SSergey Zigachev 		amdgpu_connector->use_digital = true;
1162b843c749SSergey Zigachev }
1163b843c749SSergey Zigachev 
amdgpu_connector_dvi_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)1164b843c749SSergey Zigachev static enum drm_mode_status amdgpu_connector_dvi_mode_valid(struct drm_connector *connector,
1165b843c749SSergey Zigachev 					    struct drm_display_mode *mode)
1166b843c749SSergey Zigachev {
1167b843c749SSergey Zigachev 	struct drm_device *dev = connector->dev;
1168b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev->dev_private;
1169b843c749SSergey Zigachev 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
1170b843c749SSergey Zigachev 
1171b843c749SSergey Zigachev 	/* XXX check mode bandwidth */
1172b843c749SSergey Zigachev 
1173b843c749SSergey Zigachev 	if (amdgpu_connector->use_digital && (mode->clock > 165000)) {
1174b843c749SSergey Zigachev 		if ((amdgpu_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I) ||
1175b843c749SSergey Zigachev 		    (amdgpu_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D) ||
1176b843c749SSergey Zigachev 		    (amdgpu_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_B)) {
1177b843c749SSergey Zigachev 			return MODE_OK;
1178b843c749SSergey Zigachev 		} else if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
1179b843c749SSergey Zigachev 			/* HDMI 1.3+ supports max clock of 340 Mhz */
1180b843c749SSergey Zigachev 			if (mode->clock > 340000)
1181b843c749SSergey Zigachev 				return MODE_CLOCK_HIGH;
1182b843c749SSergey Zigachev 			else
1183b843c749SSergey Zigachev 				return MODE_OK;
1184b843c749SSergey Zigachev 		} else {
1185b843c749SSergey Zigachev 			return MODE_CLOCK_HIGH;
1186b843c749SSergey Zigachev 		}
1187b843c749SSergey Zigachev 	}
1188b843c749SSergey Zigachev 
1189b843c749SSergey Zigachev 	/* check against the max pixel clock */
1190b843c749SSergey Zigachev 	if ((mode->clock / 10) > adev->clock.max_pixel_clock)
1191b843c749SSergey Zigachev 		return MODE_CLOCK_HIGH;
1192b843c749SSergey Zigachev 
1193b843c749SSergey Zigachev 	return MODE_OK;
1194b843c749SSergey Zigachev }
1195b843c749SSergey Zigachev 
1196b843c749SSergey Zigachev static const struct drm_connector_helper_funcs amdgpu_connector_dvi_helper_funcs = {
1197b843c749SSergey Zigachev 	.get_modes = amdgpu_connector_vga_get_modes,
1198b843c749SSergey Zigachev 	.mode_valid = amdgpu_connector_dvi_mode_valid,
1199b843c749SSergey Zigachev 	.best_encoder = amdgpu_connector_dvi_encoder,
1200b843c749SSergey Zigachev };
1201b843c749SSergey Zigachev 
1202b843c749SSergey Zigachev static const struct drm_connector_funcs amdgpu_connector_dvi_funcs = {
1203b843c749SSergey Zigachev 	.dpms = drm_helper_connector_dpms,
1204b843c749SSergey Zigachev 	.detect = amdgpu_connector_dvi_detect,
1205b843c749SSergey Zigachev 	.fill_modes = drm_helper_probe_single_connector_modes,
1206b843c749SSergey Zigachev 	.set_property = amdgpu_connector_set_property,
1207b843c749SSergey Zigachev 	.early_unregister = amdgpu_connector_unregister,
1208b843c749SSergey Zigachev 	.destroy = amdgpu_connector_destroy,
1209b843c749SSergey Zigachev 	.force = amdgpu_connector_dvi_force,
1210b843c749SSergey Zigachev };
1211b843c749SSergey Zigachev 
amdgpu_connector_dp_get_modes(struct drm_connector * connector)1212b843c749SSergey Zigachev static int amdgpu_connector_dp_get_modes(struct drm_connector *connector)
1213b843c749SSergey Zigachev {
1214b843c749SSergey Zigachev 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
1215b843c749SSergey Zigachev 	struct amdgpu_connector_atom_dig *amdgpu_dig_connector = amdgpu_connector->con_priv;
1216b843c749SSergey Zigachev 	struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector);
1217b843c749SSergey Zigachev 	int ret;
1218b843c749SSergey Zigachev 
1219b843c749SSergey Zigachev 	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
1220b843c749SSergey Zigachev 	    (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
1221b843c749SSergey Zigachev 		struct drm_display_mode *mode;
1222b843c749SSergey Zigachev 
1223b843c749SSergey Zigachev 		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
1224b843c749SSergey Zigachev 			if (!amdgpu_dig_connector->edp_on)
1225b843c749SSergey Zigachev 				amdgpu_atombios_encoder_set_edp_panel_power(connector,
1226b843c749SSergey Zigachev 								     ATOM_TRANSMITTER_ACTION_POWER_ON);
1227b843c749SSergey Zigachev 			amdgpu_connector_get_edid(connector);
1228b843c749SSergey Zigachev 			ret = amdgpu_connector_ddc_get_modes(connector);
1229b843c749SSergey Zigachev 			if (!amdgpu_dig_connector->edp_on)
1230b843c749SSergey Zigachev 				amdgpu_atombios_encoder_set_edp_panel_power(connector,
1231b843c749SSergey Zigachev 								     ATOM_TRANSMITTER_ACTION_POWER_OFF);
1232b843c749SSergey Zigachev 		} else {
1233b843c749SSergey Zigachev 			/* need to setup ddc on the bridge */
1234b843c749SSergey Zigachev 			if (amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) !=
1235b843c749SSergey Zigachev 			    ENCODER_OBJECT_ID_NONE) {
1236b843c749SSergey Zigachev 				if (encoder)
1237b843c749SSergey Zigachev 					amdgpu_atombios_encoder_setup_ext_encoder_ddc(encoder);
1238b843c749SSergey Zigachev 			}
1239b843c749SSergey Zigachev 			amdgpu_connector_get_edid(connector);
1240b843c749SSergey Zigachev 			ret = amdgpu_connector_ddc_get_modes(connector);
1241b843c749SSergey Zigachev 		}
1242b843c749SSergey Zigachev 
1243b843c749SSergey Zigachev 		if (ret > 0) {
1244b843c749SSergey Zigachev 			if (encoder) {
1245b843c749SSergey Zigachev 				amdgpu_connector_fixup_lcd_native_mode(encoder, connector);
1246b843c749SSergey Zigachev 				/* add scaled modes */
1247b843c749SSergey Zigachev 				amdgpu_connector_add_common_modes(encoder, connector);
1248b843c749SSergey Zigachev 			}
1249b843c749SSergey Zigachev 			return ret;
1250b843c749SSergey Zigachev 		}
1251b843c749SSergey Zigachev 
1252b843c749SSergey Zigachev 		if (!encoder)
1253b843c749SSergey Zigachev 			return 0;
1254b843c749SSergey Zigachev 
1255b843c749SSergey Zigachev 		/* we have no EDID modes */
1256b843c749SSergey Zigachev 		mode = amdgpu_connector_lcd_native_mode(encoder);
1257b843c749SSergey Zigachev 		if (mode) {
1258b843c749SSergey Zigachev 			ret = 1;
1259b843c749SSergey Zigachev 			drm_mode_probed_add(connector, mode);
1260b843c749SSergey Zigachev 			/* add the width/height from vbios tables if available */
1261b843c749SSergey Zigachev 			connector->display_info.width_mm = mode->width_mm;
1262b843c749SSergey Zigachev 			connector->display_info.height_mm = mode->height_mm;
1263b843c749SSergey Zigachev 			/* add scaled modes */
1264b843c749SSergey Zigachev 			amdgpu_connector_add_common_modes(encoder, connector);
1265b843c749SSergey Zigachev 		}
1266b843c749SSergey Zigachev 	} else {
1267b843c749SSergey Zigachev 		/* need to setup ddc on the bridge */
1268b843c749SSergey Zigachev 		if (amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) !=
1269b843c749SSergey Zigachev 			ENCODER_OBJECT_ID_NONE) {
1270b843c749SSergey Zigachev 			if (encoder)
1271b843c749SSergey Zigachev 				amdgpu_atombios_encoder_setup_ext_encoder_ddc(encoder);
1272b843c749SSergey Zigachev 		}
1273b843c749SSergey Zigachev 		amdgpu_connector_get_edid(connector);
1274b843c749SSergey Zigachev 		ret = amdgpu_connector_ddc_get_modes(connector);
1275b843c749SSergey Zigachev 
1276b843c749SSergey Zigachev 		amdgpu_get_native_mode(connector);
1277b843c749SSergey Zigachev 	}
1278b843c749SSergey Zigachev 
1279b843c749SSergey Zigachev 	return ret;
1280b843c749SSergey Zigachev }
1281b843c749SSergey Zigachev 
amdgpu_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector * connector)1282b843c749SSergey Zigachev u16 amdgpu_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector)
1283b843c749SSergey Zigachev {
1284b843c749SSergey Zigachev 	struct drm_encoder *encoder;
1285b843c749SSergey Zigachev 	struct amdgpu_encoder *amdgpu_encoder;
1286b843c749SSergey Zigachev 	int i;
1287b843c749SSergey Zigachev 
1288b843c749SSergey Zigachev 	drm_connector_for_each_possible_encoder(connector, encoder, i) {
1289b843c749SSergey Zigachev 		amdgpu_encoder = to_amdgpu_encoder(encoder);
1290b843c749SSergey Zigachev 
1291b843c749SSergey Zigachev 		switch (amdgpu_encoder->encoder_id) {
1292b843c749SSergey Zigachev 		case ENCODER_OBJECT_ID_TRAVIS:
1293b843c749SSergey Zigachev 		case ENCODER_OBJECT_ID_NUTMEG:
1294b843c749SSergey Zigachev 			return amdgpu_encoder->encoder_id;
1295b843c749SSergey Zigachev 		default:
1296b843c749SSergey Zigachev 			break;
1297b843c749SSergey Zigachev 		}
1298b843c749SSergey Zigachev 	}
1299b843c749SSergey Zigachev 
1300b843c749SSergey Zigachev 	return ENCODER_OBJECT_ID_NONE;
1301b843c749SSergey Zigachev }
1302b843c749SSergey Zigachev 
amdgpu_connector_encoder_is_hbr2(struct drm_connector * connector)1303b843c749SSergey Zigachev static bool amdgpu_connector_encoder_is_hbr2(struct drm_connector *connector)
1304b843c749SSergey Zigachev {
1305b843c749SSergey Zigachev 	struct drm_encoder *encoder;
1306b843c749SSergey Zigachev 	struct amdgpu_encoder *amdgpu_encoder;
1307b843c749SSergey Zigachev 	int i;
1308b843c749SSergey Zigachev 	bool found = false;
1309b843c749SSergey Zigachev 
1310b843c749SSergey Zigachev 	drm_connector_for_each_possible_encoder(connector, encoder, i) {
1311b843c749SSergey Zigachev 		amdgpu_encoder = to_amdgpu_encoder(encoder);
1312b843c749SSergey Zigachev 		if (amdgpu_encoder->caps & ATOM_ENCODER_CAP_RECORD_HBR2)
1313b843c749SSergey Zigachev 			found = true;
1314b843c749SSergey Zigachev 	}
1315b843c749SSergey Zigachev 
1316b843c749SSergey Zigachev 	return found;
1317b843c749SSergey Zigachev }
1318b843c749SSergey Zigachev 
amdgpu_connector_is_dp12_capable(struct drm_connector * connector)1319b843c749SSergey Zigachev bool amdgpu_connector_is_dp12_capable(struct drm_connector *connector)
1320b843c749SSergey Zigachev {
1321b843c749SSergey Zigachev 	struct drm_device *dev = connector->dev;
1322b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev->dev_private;
1323b843c749SSergey Zigachev 
1324b843c749SSergey Zigachev 	if ((adev->clock.default_dispclk >= 53900) &&
1325b843c749SSergey Zigachev 	    amdgpu_connector_encoder_is_hbr2(connector)) {
1326b843c749SSergey Zigachev 		return true;
1327b843c749SSergey Zigachev 	}
1328b843c749SSergey Zigachev 
1329b843c749SSergey Zigachev 	return false;
1330b843c749SSergey Zigachev }
1331b843c749SSergey Zigachev 
1332b843c749SSergey Zigachev static enum drm_connector_status
amdgpu_connector_dp_detect(struct drm_connector * connector,bool force)1333b843c749SSergey Zigachev amdgpu_connector_dp_detect(struct drm_connector *connector, bool force)
1334b843c749SSergey Zigachev {
1335b843c749SSergey Zigachev 	struct drm_device *dev = connector->dev;
1336b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev->dev_private;
1337b843c749SSergey Zigachev 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
1338b843c749SSergey Zigachev 	enum drm_connector_status ret = connector_status_disconnected;
1339b843c749SSergey Zigachev 	struct amdgpu_connector_atom_dig *amdgpu_dig_connector = amdgpu_connector->con_priv;
1340b843c749SSergey Zigachev 	struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector);
1341b843c749SSergey Zigachev 	int r;
1342b843c749SSergey Zigachev 
1343b843c749SSergey Zigachev 	if (!drm_kms_helper_is_poll_worker()) {
1344b843c749SSergey Zigachev 		r = pm_runtime_get_sync(connector->dev->dev);
1345b843c749SSergey Zigachev 		if (r < 0) {
1346b843c749SSergey Zigachev 			pm_runtime_put_autosuspend(connector->dev->dev);
1347b843c749SSergey Zigachev 			return connector_status_disconnected;
1348b843c749SSergey Zigachev 		}
1349b843c749SSergey Zigachev 	}
1350b843c749SSergey Zigachev 
1351b843c749SSergey Zigachev 	if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
1352b843c749SSergey Zigachev 		ret = connector->status;
1353b843c749SSergey Zigachev 		goto out;
1354b843c749SSergey Zigachev 	}
1355b843c749SSergey Zigachev 
1356b843c749SSergey Zigachev 	amdgpu_connector_free_edid(connector);
1357b843c749SSergey Zigachev 
1358b843c749SSergey Zigachev 	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
1359b843c749SSergey Zigachev 	    (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
1360b843c749SSergey Zigachev 		if (encoder) {
1361b843c749SSergey Zigachev 			struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
1362b843c749SSergey Zigachev 			struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
1363b843c749SSergey Zigachev 
1364b843c749SSergey Zigachev 			/* check if panel is valid */
1365b843c749SSergey Zigachev 			if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
1366b843c749SSergey Zigachev 				ret = connector_status_connected;
1367b843c749SSergey Zigachev 		}
1368b843c749SSergey Zigachev 		/* eDP is always DP */
1369b843c749SSergey Zigachev 		amdgpu_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
1370b843c749SSergey Zigachev 		if (!amdgpu_dig_connector->edp_on)
1371b843c749SSergey Zigachev 			amdgpu_atombios_encoder_set_edp_panel_power(connector,
1372b843c749SSergey Zigachev 							     ATOM_TRANSMITTER_ACTION_POWER_ON);
1373b843c749SSergey Zigachev 		if (!amdgpu_atombios_dp_get_dpcd(amdgpu_connector))
1374b843c749SSergey Zigachev 			ret = connector_status_connected;
1375b843c749SSergey Zigachev 		if (!amdgpu_dig_connector->edp_on)
1376b843c749SSergey Zigachev 			amdgpu_atombios_encoder_set_edp_panel_power(connector,
1377b843c749SSergey Zigachev 							     ATOM_TRANSMITTER_ACTION_POWER_OFF);
1378b843c749SSergey Zigachev 	} else if (amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) !=
1379b843c749SSergey Zigachev 		   ENCODER_OBJECT_ID_NONE) {
1380b843c749SSergey Zigachev 		/* DP bridges are always DP */
1381b843c749SSergey Zigachev 		amdgpu_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
1382b843c749SSergey Zigachev 		/* get the DPCD from the bridge */
1383b843c749SSergey Zigachev 		amdgpu_atombios_dp_get_dpcd(amdgpu_connector);
1384b843c749SSergey Zigachev 
1385b843c749SSergey Zigachev 		if (encoder) {
1386b843c749SSergey Zigachev 			/* setup ddc on the bridge */
1387b843c749SSergey Zigachev 			amdgpu_atombios_encoder_setup_ext_encoder_ddc(encoder);
1388b843c749SSergey Zigachev 			/* bridge chips are always aux */
1389b843c749SSergey Zigachev 			/* try DDC */
1390b843c749SSergey Zigachev 			if (amdgpu_display_ddc_probe(amdgpu_connector, true))
1391b843c749SSergey Zigachev 				ret = connector_status_connected;
1392b843c749SSergey Zigachev 			else if (amdgpu_connector->dac_load_detect) { /* try load detection */
1393b843c749SSergey Zigachev 				const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
1394b843c749SSergey Zigachev 				ret = encoder_funcs->detect(encoder, connector);
1395b843c749SSergey Zigachev 			}
1396b843c749SSergey Zigachev 		}
1397b843c749SSergey Zigachev 	} else {
1398b843c749SSergey Zigachev 		amdgpu_dig_connector->dp_sink_type =
1399b843c749SSergey Zigachev 			amdgpu_atombios_dp_get_sinktype(amdgpu_connector);
1400b843c749SSergey Zigachev 		if (amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd)) {
1401b843c749SSergey Zigachev 			ret = connector_status_connected;
1402b843c749SSergey Zigachev 			if (amdgpu_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT)
1403b843c749SSergey Zigachev 				amdgpu_atombios_dp_get_dpcd(amdgpu_connector);
1404b843c749SSergey Zigachev 		} else {
1405b843c749SSergey Zigachev 			if (amdgpu_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
1406b843c749SSergey Zigachev 				if (!amdgpu_atombios_dp_get_dpcd(amdgpu_connector))
1407b843c749SSergey Zigachev 					ret = connector_status_connected;
1408b843c749SSergey Zigachev 			} else {
1409b843c749SSergey Zigachev 				/* try non-aux ddc (DP to DVI/HDMI/etc. adapter) */
1410b843c749SSergey Zigachev 				if (amdgpu_display_ddc_probe(amdgpu_connector,
1411b843c749SSergey Zigachev 							     false))
1412b843c749SSergey Zigachev 					ret = connector_status_connected;
1413b843c749SSergey Zigachev 			}
1414b843c749SSergey Zigachev 		}
1415b843c749SSergey Zigachev 	}
1416b843c749SSergey Zigachev 
1417b843c749SSergey Zigachev 	amdgpu_connector_update_scratch_regs(connector, ret);
1418b843c749SSergey Zigachev out:
1419b843c749SSergey Zigachev 	if (!drm_kms_helper_is_poll_worker()) {
1420b843c749SSergey Zigachev 		pm_runtime_mark_last_busy(connector->dev->dev);
1421b843c749SSergey Zigachev 		pm_runtime_put_autosuspend(connector->dev->dev);
1422b843c749SSergey Zigachev 	}
1423b843c749SSergey Zigachev 
1424b843c749SSergey Zigachev 	return ret;
1425b843c749SSergey Zigachev }
1426b843c749SSergey Zigachev 
amdgpu_connector_dp_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)1427b843c749SSergey Zigachev static enum drm_mode_status amdgpu_connector_dp_mode_valid(struct drm_connector *connector,
1428b843c749SSergey Zigachev 					   struct drm_display_mode *mode)
1429b843c749SSergey Zigachev {
1430b843c749SSergey Zigachev 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
1431b843c749SSergey Zigachev 	struct amdgpu_connector_atom_dig *amdgpu_dig_connector = amdgpu_connector->con_priv;
1432b843c749SSergey Zigachev 
1433b843c749SSergey Zigachev 	/* XXX check mode bandwidth */
1434b843c749SSergey Zigachev 
1435b843c749SSergey Zigachev 	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
1436b843c749SSergey Zigachev 	    (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
1437b843c749SSergey Zigachev 		struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector);
1438b843c749SSergey Zigachev 
1439b843c749SSergey Zigachev 		if ((mode->hdisplay < 320) || (mode->vdisplay < 240))
1440b843c749SSergey Zigachev 			return MODE_PANEL;
1441b843c749SSergey Zigachev 
1442b843c749SSergey Zigachev 		if (encoder) {
1443b843c749SSergey Zigachev 			struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
1444b843c749SSergey Zigachev 			struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
1445b843c749SSergey Zigachev 
1446b843c749SSergey Zigachev 			/* AVIVO hardware supports downscaling modes larger than the panel
1447b843c749SSergey Zigachev 			 * to the panel size, but I'm not sure this is desirable.
1448b843c749SSergey Zigachev 			 */
1449b843c749SSergey Zigachev 			if ((mode->hdisplay > native_mode->hdisplay) ||
1450b843c749SSergey Zigachev 			    (mode->vdisplay > native_mode->vdisplay))
1451b843c749SSergey Zigachev 				return MODE_PANEL;
1452b843c749SSergey Zigachev 
1453b843c749SSergey Zigachev 			/* if scaling is disabled, block non-native modes */
1454b843c749SSergey Zigachev 			if (amdgpu_encoder->rmx_type == RMX_OFF) {
1455b843c749SSergey Zigachev 				if ((mode->hdisplay != native_mode->hdisplay) ||
1456b843c749SSergey Zigachev 				    (mode->vdisplay != native_mode->vdisplay))
1457b843c749SSergey Zigachev 					return MODE_PANEL;
1458b843c749SSergey Zigachev 			}
1459b843c749SSergey Zigachev 		}
1460b843c749SSergey Zigachev 		return MODE_OK;
1461b843c749SSergey Zigachev 	} else {
1462b843c749SSergey Zigachev 		if ((amdgpu_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
1463b843c749SSergey Zigachev 		    (amdgpu_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
1464b843c749SSergey Zigachev 			return amdgpu_atombios_dp_mode_valid_helper(connector, mode);
1465b843c749SSergey Zigachev 		} else {
1466b843c749SSergey Zigachev 			if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
1467b843c749SSergey Zigachev 				/* HDMI 1.3+ supports max clock of 340 Mhz */
1468b843c749SSergey Zigachev 				if (mode->clock > 340000)
1469b843c749SSergey Zigachev 					return MODE_CLOCK_HIGH;
1470b843c749SSergey Zigachev 			} else {
1471b843c749SSergey Zigachev 				if (mode->clock > 165000)
1472b843c749SSergey Zigachev 					return MODE_CLOCK_HIGH;
1473b843c749SSergey Zigachev 			}
1474b843c749SSergey Zigachev 		}
1475b843c749SSergey Zigachev 	}
1476b843c749SSergey Zigachev 
1477b843c749SSergey Zigachev 	return MODE_OK;
1478b843c749SSergey Zigachev }
1479b843c749SSergey Zigachev 
1480b843c749SSergey Zigachev static const struct drm_connector_helper_funcs amdgpu_connector_dp_helper_funcs = {
1481b843c749SSergey Zigachev 	.get_modes = amdgpu_connector_dp_get_modes,
1482b843c749SSergey Zigachev 	.mode_valid = amdgpu_connector_dp_mode_valid,
1483b843c749SSergey Zigachev 	.best_encoder = amdgpu_connector_dvi_encoder,
1484b843c749SSergey Zigachev };
1485b843c749SSergey Zigachev 
1486b843c749SSergey Zigachev static const struct drm_connector_funcs amdgpu_connector_dp_funcs = {
1487b843c749SSergey Zigachev 	.dpms = drm_helper_connector_dpms,
1488b843c749SSergey Zigachev 	.detect = amdgpu_connector_dp_detect,
1489b843c749SSergey Zigachev 	.fill_modes = drm_helper_probe_single_connector_modes,
1490b843c749SSergey Zigachev 	.set_property = amdgpu_connector_set_property,
1491b843c749SSergey Zigachev 	.early_unregister = amdgpu_connector_unregister,
1492b843c749SSergey Zigachev 	.destroy = amdgpu_connector_destroy,
1493b843c749SSergey Zigachev 	.force = amdgpu_connector_dvi_force,
1494b843c749SSergey Zigachev };
1495b843c749SSergey Zigachev 
1496b843c749SSergey Zigachev static const struct drm_connector_funcs amdgpu_connector_edp_funcs = {
1497b843c749SSergey Zigachev 	.dpms = drm_helper_connector_dpms,
1498b843c749SSergey Zigachev 	.detect = amdgpu_connector_dp_detect,
1499b843c749SSergey Zigachev 	.fill_modes = drm_helper_probe_single_connector_modes,
1500b843c749SSergey Zigachev 	.set_property = amdgpu_connector_set_lcd_property,
1501b843c749SSergey Zigachev 	.early_unregister = amdgpu_connector_unregister,
1502b843c749SSergey Zigachev 	.destroy = amdgpu_connector_destroy,
1503b843c749SSergey Zigachev 	.force = amdgpu_connector_dvi_force,
1504b843c749SSergey Zigachev };
1505b843c749SSergey Zigachev 
1506b843c749SSergey Zigachev void
amdgpu_connector_add(struct amdgpu_device * adev,uint32_t connector_id,uint32_t supported_device,int connector_type,struct amdgpu_i2c_bus_rec * i2c_bus,uint16_t connector_object_id,struct amdgpu_hpd * hpd,struct amdgpu_router * router)1507b843c749SSergey Zigachev amdgpu_connector_add(struct amdgpu_device *adev,
1508b843c749SSergey Zigachev 		      uint32_t connector_id,
1509b843c749SSergey Zigachev 		      uint32_t supported_device,
1510b843c749SSergey Zigachev 		      int connector_type,
1511b843c749SSergey Zigachev 		      struct amdgpu_i2c_bus_rec *i2c_bus,
1512b843c749SSergey Zigachev 		      uint16_t connector_object_id,
1513b843c749SSergey Zigachev 		      struct amdgpu_hpd *hpd,
1514b843c749SSergey Zigachev 		      struct amdgpu_router *router)
1515b843c749SSergey Zigachev {
1516b843c749SSergey Zigachev 	struct drm_device *dev = adev->ddev;
1517b843c749SSergey Zigachev 	struct drm_connector *connector;
1518b843c749SSergey Zigachev 	struct amdgpu_connector *amdgpu_connector;
1519b843c749SSergey Zigachev 	struct amdgpu_connector_atom_dig *amdgpu_dig_connector;
1520b843c749SSergey Zigachev 	struct drm_encoder *encoder;
1521b843c749SSergey Zigachev 	struct amdgpu_encoder *amdgpu_encoder;
1522b843c749SSergey Zigachev 	uint32_t subpixel_order = SubPixelNone;
1523b843c749SSergey Zigachev 	bool shared_ddc = false;
1524b843c749SSergey Zigachev 	bool is_dp_bridge = false;
1525b843c749SSergey Zigachev 	bool has_aux = false;
1526b843c749SSergey Zigachev 
1527b843c749SSergey Zigachev 	if (connector_type == DRM_MODE_CONNECTOR_Unknown)
1528b843c749SSergey Zigachev 		return;
1529b843c749SSergey Zigachev 
1530b843c749SSergey Zigachev 	/* see if we already added it */
1531b843c749SSergey Zigachev 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1532b843c749SSergey Zigachev 		amdgpu_connector = to_amdgpu_connector(connector);
1533b843c749SSergey Zigachev 		if (amdgpu_connector->connector_id == connector_id) {
1534b843c749SSergey Zigachev 			amdgpu_connector->devices |= supported_device;
1535b843c749SSergey Zigachev 			return;
1536b843c749SSergey Zigachev 		}
1537b843c749SSergey Zigachev 		if (amdgpu_connector->ddc_bus && i2c_bus->valid) {
1538b843c749SSergey Zigachev 			if (amdgpu_connector->ddc_bus->rec.i2c_id == i2c_bus->i2c_id) {
1539b843c749SSergey Zigachev 				amdgpu_connector->shared_ddc = true;
1540b843c749SSergey Zigachev 				shared_ddc = true;
1541b843c749SSergey Zigachev 			}
1542b843c749SSergey Zigachev 			if (amdgpu_connector->router_bus && router->ddc_valid &&
1543b843c749SSergey Zigachev 			    (amdgpu_connector->router.router_id == router->router_id)) {
1544b843c749SSergey Zigachev 				amdgpu_connector->shared_ddc = false;
1545b843c749SSergey Zigachev 				shared_ddc = false;
1546b843c749SSergey Zigachev 			}
1547b843c749SSergey Zigachev 		}
1548b843c749SSergey Zigachev 	}
1549b843c749SSergey Zigachev 
1550b843c749SSergey Zigachev 	/* check if it's a dp bridge */
1551b843c749SSergey Zigachev 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
1552b843c749SSergey Zigachev 		amdgpu_encoder = to_amdgpu_encoder(encoder);
1553b843c749SSergey Zigachev 		if (amdgpu_encoder->devices & supported_device) {
1554b843c749SSergey Zigachev 			switch (amdgpu_encoder->encoder_id) {
1555b843c749SSergey Zigachev 			case ENCODER_OBJECT_ID_TRAVIS:
1556b843c749SSergey Zigachev 			case ENCODER_OBJECT_ID_NUTMEG:
1557b843c749SSergey Zigachev 				is_dp_bridge = true;
1558b843c749SSergey Zigachev 				break;
1559b843c749SSergey Zigachev 			default:
1560b843c749SSergey Zigachev 				break;
1561b843c749SSergey Zigachev 			}
1562b843c749SSergey Zigachev 		}
1563b843c749SSergey Zigachev 	}
1564b843c749SSergey Zigachev 
1565b843c749SSergey Zigachev 	amdgpu_connector = kzalloc(sizeof(struct amdgpu_connector), GFP_KERNEL);
1566b843c749SSergey Zigachev 	if (!amdgpu_connector)
1567b843c749SSergey Zigachev 		return;
1568b843c749SSergey Zigachev 
1569b843c749SSergey Zigachev 	connector = &amdgpu_connector->base;
1570b843c749SSergey Zigachev 
1571b843c749SSergey Zigachev 	amdgpu_connector->connector_id = connector_id;
1572b843c749SSergey Zigachev 	amdgpu_connector->devices = supported_device;
1573b843c749SSergey Zigachev 	amdgpu_connector->shared_ddc = shared_ddc;
1574b843c749SSergey Zigachev 	amdgpu_connector->connector_object_id = connector_object_id;
1575b843c749SSergey Zigachev 	amdgpu_connector->hpd = *hpd;
1576b843c749SSergey Zigachev 
1577b843c749SSergey Zigachev 	amdgpu_connector->router = *router;
1578b843c749SSergey Zigachev 	if (router->ddc_valid || router->cd_valid) {
1579b843c749SSergey Zigachev 		amdgpu_connector->router_bus = amdgpu_i2c_lookup(adev, &router->i2c_info);
1580b843c749SSergey Zigachev 		if (!amdgpu_connector->router_bus)
1581b843c749SSergey Zigachev 			DRM_ERROR("Failed to assign router i2c bus! Check dmesg for i2c errors.\n");
1582b843c749SSergey Zigachev 	}
1583b843c749SSergey Zigachev 
1584b843c749SSergey Zigachev 	if (is_dp_bridge) {
1585b843c749SSergey Zigachev 		amdgpu_dig_connector = kzalloc(sizeof(struct amdgpu_connector_atom_dig), GFP_KERNEL);
1586b843c749SSergey Zigachev 		if (!amdgpu_dig_connector)
1587b843c749SSergey Zigachev 			goto failed;
1588b843c749SSergey Zigachev 		amdgpu_connector->con_priv = amdgpu_dig_connector;
1589b843c749SSergey Zigachev 		if (i2c_bus->valid) {
1590b843c749SSergey Zigachev 			amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
1591b843c749SSergey Zigachev 			if (amdgpu_connector->ddc_bus)
1592b843c749SSergey Zigachev 				has_aux = true;
1593b843c749SSergey Zigachev 			else
1594b843c749SSergey Zigachev 				DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
1595b843c749SSergey Zigachev 		}
1596b843c749SSergey Zigachev 		switch (connector_type) {
1597b843c749SSergey Zigachev 		case DRM_MODE_CONNECTOR_VGA:
1598b843c749SSergey Zigachev 		case DRM_MODE_CONNECTOR_DVIA:
1599b843c749SSergey Zigachev 		default:
1600b843c749SSergey Zigachev 			drm_connector_init(dev, &amdgpu_connector->base,
1601b843c749SSergey Zigachev 					   &amdgpu_connector_dp_funcs, connector_type);
1602b843c749SSergey Zigachev 			drm_connector_helper_add(&amdgpu_connector->base,
1603b843c749SSergey Zigachev 						 &amdgpu_connector_dp_helper_funcs);
1604b843c749SSergey Zigachev 			connector->interlace_allowed = true;
1605b843c749SSergey Zigachev 			connector->doublescan_allowed = true;
1606b843c749SSergey Zigachev 			amdgpu_connector->dac_load_detect = true;
1607b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1608b843c749SSergey Zigachev 						      adev->mode_info.load_detect_property,
1609b843c749SSergey Zigachev 						      1);
1610b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1611b843c749SSergey Zigachev 						   dev->mode_config.scaling_mode_property,
1612b843c749SSergey Zigachev 						   DRM_MODE_SCALE_NONE);
1613b843c749SSergey Zigachev 			break;
1614b843c749SSergey Zigachev 		case DRM_MODE_CONNECTOR_DVII:
1615b843c749SSergey Zigachev 		case DRM_MODE_CONNECTOR_DVID:
1616b843c749SSergey Zigachev 		case DRM_MODE_CONNECTOR_HDMIA:
1617b843c749SSergey Zigachev 		case DRM_MODE_CONNECTOR_HDMIB:
1618b843c749SSergey Zigachev 		case DRM_MODE_CONNECTOR_DisplayPort:
1619b843c749SSergey Zigachev 			drm_connector_init(dev, &amdgpu_connector->base,
1620b843c749SSergey Zigachev 					   &amdgpu_connector_dp_funcs, connector_type);
1621b843c749SSergey Zigachev 			drm_connector_helper_add(&amdgpu_connector->base,
1622b843c749SSergey Zigachev 						 &amdgpu_connector_dp_helper_funcs);
1623b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1624b843c749SSergey Zigachev 						      adev->mode_info.underscan_property,
1625b843c749SSergey Zigachev 						      UNDERSCAN_OFF);
1626b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1627b843c749SSergey Zigachev 						      adev->mode_info.underscan_hborder_property,
1628b843c749SSergey Zigachev 						      0);
1629b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1630b843c749SSergey Zigachev 						      adev->mode_info.underscan_vborder_property,
1631b843c749SSergey Zigachev 						      0);
1632b843c749SSergey Zigachev 
1633b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1634b843c749SSergey Zigachev 						   dev->mode_config.scaling_mode_property,
1635b843c749SSergey Zigachev 						   DRM_MODE_SCALE_NONE);
1636b843c749SSergey Zigachev 
1637b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1638b843c749SSergey Zigachev 						   adev->mode_info.dither_property,
1639b843c749SSergey Zigachev 						   AMDGPU_FMT_DITHER_DISABLE);
1640b843c749SSergey Zigachev 
1641b843c749SSergey Zigachev 			if (amdgpu_audio != 0)
1642b843c749SSergey Zigachev 				drm_object_attach_property(&amdgpu_connector->base.base,
1643b843c749SSergey Zigachev 							   adev->mode_info.audio_property,
1644b843c749SSergey Zigachev 							   AMDGPU_AUDIO_AUTO);
1645b843c749SSergey Zigachev 
1646b843c749SSergey Zigachev 			subpixel_order = SubPixelHorizontalRGB;
1647b843c749SSergey Zigachev 			connector->interlace_allowed = true;
1648b843c749SSergey Zigachev 			if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
1649b843c749SSergey Zigachev 				connector->doublescan_allowed = true;
1650b843c749SSergey Zigachev 			else
1651b843c749SSergey Zigachev 				connector->doublescan_allowed = false;
1652b843c749SSergey Zigachev 			if (connector_type == DRM_MODE_CONNECTOR_DVII) {
1653b843c749SSergey Zigachev 				amdgpu_connector->dac_load_detect = true;
1654b843c749SSergey Zigachev 				drm_object_attach_property(&amdgpu_connector->base.base,
1655b843c749SSergey Zigachev 							      adev->mode_info.load_detect_property,
1656b843c749SSergey Zigachev 							      1);
1657b843c749SSergey Zigachev 			}
1658b843c749SSergey Zigachev 			break;
1659b843c749SSergey Zigachev 		case DRM_MODE_CONNECTOR_LVDS:
1660b843c749SSergey Zigachev 		case DRM_MODE_CONNECTOR_eDP:
1661b843c749SSergey Zigachev 			drm_connector_init(dev, &amdgpu_connector->base,
1662b843c749SSergey Zigachev 					   &amdgpu_connector_edp_funcs, connector_type);
1663b843c749SSergey Zigachev 			drm_connector_helper_add(&amdgpu_connector->base,
1664b843c749SSergey Zigachev 						 &amdgpu_connector_dp_helper_funcs);
1665b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1666b843c749SSergey Zigachev 						      dev->mode_config.scaling_mode_property,
1667b843c749SSergey Zigachev 						      DRM_MODE_SCALE_FULLSCREEN);
1668b843c749SSergey Zigachev 			subpixel_order = SubPixelHorizontalRGB;
1669b843c749SSergey Zigachev 			connector->interlace_allowed = false;
1670b843c749SSergey Zigachev 			connector->doublescan_allowed = false;
1671b843c749SSergey Zigachev 			break;
1672b843c749SSergey Zigachev 		}
1673b843c749SSergey Zigachev 	} else {
1674b843c749SSergey Zigachev 		switch (connector_type) {
1675b843c749SSergey Zigachev 		case DRM_MODE_CONNECTOR_VGA:
1676b843c749SSergey Zigachev 			drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_vga_funcs, connector_type);
1677b843c749SSergey Zigachev 			drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_vga_helper_funcs);
1678b843c749SSergey Zigachev 			if (i2c_bus->valid) {
1679b843c749SSergey Zigachev 				amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
1680b843c749SSergey Zigachev 				if (!amdgpu_connector->ddc_bus)
1681b843c749SSergey Zigachev 					DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
1682b843c749SSergey Zigachev 			}
1683b843c749SSergey Zigachev 			amdgpu_connector->dac_load_detect = true;
1684b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1685b843c749SSergey Zigachev 						      adev->mode_info.load_detect_property,
1686b843c749SSergey Zigachev 						      1);
1687b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1688b843c749SSergey Zigachev 						   dev->mode_config.scaling_mode_property,
1689b843c749SSergey Zigachev 						   DRM_MODE_SCALE_NONE);
1690b843c749SSergey Zigachev 			/* no HPD on analog connectors */
1691b843c749SSergey Zigachev 			amdgpu_connector->hpd.hpd = AMDGPU_HPD_NONE;
1692b843c749SSergey Zigachev 			connector->interlace_allowed = true;
1693b843c749SSergey Zigachev 			connector->doublescan_allowed = true;
1694b843c749SSergey Zigachev 			break;
1695b843c749SSergey Zigachev 		case DRM_MODE_CONNECTOR_DVIA:
1696b843c749SSergey Zigachev 			drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_vga_funcs, connector_type);
1697b843c749SSergey Zigachev 			drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_vga_helper_funcs);
1698b843c749SSergey Zigachev 			if (i2c_bus->valid) {
1699b843c749SSergey Zigachev 				amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
1700b843c749SSergey Zigachev 				if (!amdgpu_connector->ddc_bus)
1701b843c749SSergey Zigachev 					DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
1702b843c749SSergey Zigachev 			}
1703b843c749SSergey Zigachev 			amdgpu_connector->dac_load_detect = true;
1704b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1705b843c749SSergey Zigachev 						      adev->mode_info.load_detect_property,
1706b843c749SSergey Zigachev 						      1);
1707b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1708b843c749SSergey Zigachev 						   dev->mode_config.scaling_mode_property,
1709b843c749SSergey Zigachev 						   DRM_MODE_SCALE_NONE);
1710b843c749SSergey Zigachev 			/* no HPD on analog connectors */
1711b843c749SSergey Zigachev 			amdgpu_connector->hpd.hpd = AMDGPU_HPD_NONE;
1712b843c749SSergey Zigachev 			connector->interlace_allowed = true;
1713b843c749SSergey Zigachev 			connector->doublescan_allowed = true;
1714b843c749SSergey Zigachev 			break;
1715b843c749SSergey Zigachev 		case DRM_MODE_CONNECTOR_DVII:
1716b843c749SSergey Zigachev 		case DRM_MODE_CONNECTOR_DVID:
1717b843c749SSergey Zigachev 			amdgpu_dig_connector = kzalloc(sizeof(struct amdgpu_connector_atom_dig), GFP_KERNEL);
1718b843c749SSergey Zigachev 			if (!amdgpu_dig_connector)
1719b843c749SSergey Zigachev 				goto failed;
1720b843c749SSergey Zigachev 			amdgpu_connector->con_priv = amdgpu_dig_connector;
1721b843c749SSergey Zigachev 			drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_dvi_funcs, connector_type);
1722b843c749SSergey Zigachev 			drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_dvi_helper_funcs);
1723b843c749SSergey Zigachev 			if (i2c_bus->valid) {
1724b843c749SSergey Zigachev 				amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
1725b843c749SSergey Zigachev 				if (!amdgpu_connector->ddc_bus)
1726b843c749SSergey Zigachev 					DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
1727b843c749SSergey Zigachev 			}
1728b843c749SSergey Zigachev 			subpixel_order = SubPixelHorizontalRGB;
1729b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1730b843c749SSergey Zigachev 						      adev->mode_info.coherent_mode_property,
1731b843c749SSergey Zigachev 						      1);
1732b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1733b843c749SSergey Zigachev 						   adev->mode_info.underscan_property,
1734b843c749SSergey Zigachev 						   UNDERSCAN_OFF);
1735b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1736b843c749SSergey Zigachev 						   adev->mode_info.underscan_hborder_property,
1737b843c749SSergey Zigachev 						   0);
1738b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1739b843c749SSergey Zigachev 						   adev->mode_info.underscan_vborder_property,
1740b843c749SSergey Zigachev 						   0);
1741b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1742b843c749SSergey Zigachev 						   dev->mode_config.scaling_mode_property,
1743b843c749SSergey Zigachev 						   DRM_MODE_SCALE_NONE);
1744b843c749SSergey Zigachev 
1745b843c749SSergey Zigachev 			if (amdgpu_audio != 0) {
1746b843c749SSergey Zigachev 				drm_object_attach_property(&amdgpu_connector->base.base,
1747b843c749SSergey Zigachev 							   adev->mode_info.audio_property,
1748b843c749SSergey Zigachev 							   AMDGPU_AUDIO_AUTO);
1749b843c749SSergey Zigachev 			}
1750b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1751b843c749SSergey Zigachev 						   adev->mode_info.dither_property,
1752b843c749SSergey Zigachev 						   AMDGPU_FMT_DITHER_DISABLE);
1753b843c749SSergey Zigachev 			if (connector_type == DRM_MODE_CONNECTOR_DVII) {
1754b843c749SSergey Zigachev 				amdgpu_connector->dac_load_detect = true;
1755b843c749SSergey Zigachev 				drm_object_attach_property(&amdgpu_connector->base.base,
1756b843c749SSergey Zigachev 							   adev->mode_info.load_detect_property,
1757b843c749SSergey Zigachev 							   1);
1758b843c749SSergey Zigachev 			}
1759b843c749SSergey Zigachev 			connector->interlace_allowed = true;
1760b843c749SSergey Zigachev 			if (connector_type == DRM_MODE_CONNECTOR_DVII)
1761b843c749SSergey Zigachev 				connector->doublescan_allowed = true;
1762b843c749SSergey Zigachev 			else
1763b843c749SSergey Zigachev 				connector->doublescan_allowed = false;
1764b843c749SSergey Zigachev 			break;
1765b843c749SSergey Zigachev 		case DRM_MODE_CONNECTOR_HDMIA:
1766b843c749SSergey Zigachev 		case DRM_MODE_CONNECTOR_HDMIB:
1767b843c749SSergey Zigachev 			amdgpu_dig_connector = kzalloc(sizeof(struct amdgpu_connector_atom_dig), GFP_KERNEL);
1768b843c749SSergey Zigachev 			if (!amdgpu_dig_connector)
1769b843c749SSergey Zigachev 				goto failed;
1770b843c749SSergey Zigachev 			amdgpu_connector->con_priv = amdgpu_dig_connector;
1771b843c749SSergey Zigachev 			drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_dvi_funcs, connector_type);
1772b843c749SSergey Zigachev 			drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_dvi_helper_funcs);
1773b843c749SSergey Zigachev 			if (i2c_bus->valid) {
1774b843c749SSergey Zigachev 				amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
1775b843c749SSergey Zigachev 				if (!amdgpu_connector->ddc_bus)
1776b843c749SSergey Zigachev 					DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
1777b843c749SSergey Zigachev 			}
1778b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1779b843c749SSergey Zigachev 						      adev->mode_info.coherent_mode_property,
1780b843c749SSergey Zigachev 						      1);
1781b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1782b843c749SSergey Zigachev 						   adev->mode_info.underscan_property,
1783b843c749SSergey Zigachev 						   UNDERSCAN_OFF);
1784b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1785b843c749SSergey Zigachev 						   adev->mode_info.underscan_hborder_property,
1786b843c749SSergey Zigachev 						   0);
1787b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1788b843c749SSergey Zigachev 						   adev->mode_info.underscan_vborder_property,
1789b843c749SSergey Zigachev 						   0);
1790b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1791b843c749SSergey Zigachev 						   dev->mode_config.scaling_mode_property,
1792b843c749SSergey Zigachev 						   DRM_MODE_SCALE_NONE);
1793b843c749SSergey Zigachev 			if (amdgpu_audio != 0) {
1794b843c749SSergey Zigachev 				drm_object_attach_property(&amdgpu_connector->base.base,
1795b843c749SSergey Zigachev 							   adev->mode_info.audio_property,
1796b843c749SSergey Zigachev 							   AMDGPU_AUDIO_AUTO);
1797b843c749SSergey Zigachev 			}
1798b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1799b843c749SSergey Zigachev 						   adev->mode_info.dither_property,
1800b843c749SSergey Zigachev 						   AMDGPU_FMT_DITHER_DISABLE);
1801b843c749SSergey Zigachev 			subpixel_order = SubPixelHorizontalRGB;
1802b843c749SSergey Zigachev 			connector->interlace_allowed = true;
1803b843c749SSergey Zigachev 			if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
1804b843c749SSergey Zigachev 				connector->doublescan_allowed = true;
1805b843c749SSergey Zigachev 			else
1806b843c749SSergey Zigachev 				connector->doublescan_allowed = false;
1807b843c749SSergey Zigachev 			break;
1808b843c749SSergey Zigachev 		case DRM_MODE_CONNECTOR_DisplayPort:
1809b843c749SSergey Zigachev 			amdgpu_dig_connector = kzalloc(sizeof(struct amdgpu_connector_atom_dig), GFP_KERNEL);
1810b843c749SSergey Zigachev 			if (!amdgpu_dig_connector)
1811b843c749SSergey Zigachev 				goto failed;
1812b843c749SSergey Zigachev 			amdgpu_connector->con_priv = amdgpu_dig_connector;
1813b843c749SSergey Zigachev 			drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_dp_funcs, connector_type);
1814b843c749SSergey Zigachev 			drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_dp_helper_funcs);
1815b843c749SSergey Zigachev 			if (i2c_bus->valid) {
1816b843c749SSergey Zigachev 				amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
1817b843c749SSergey Zigachev 				if (amdgpu_connector->ddc_bus)
1818b843c749SSergey Zigachev 					has_aux = true;
1819b843c749SSergey Zigachev 				else
1820b843c749SSergey Zigachev 					DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
1821b843c749SSergey Zigachev 			}
1822b843c749SSergey Zigachev 			subpixel_order = SubPixelHorizontalRGB;
1823b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1824b843c749SSergey Zigachev 						      adev->mode_info.coherent_mode_property,
1825b843c749SSergey Zigachev 						      1);
1826b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1827b843c749SSergey Zigachev 						   adev->mode_info.underscan_property,
1828b843c749SSergey Zigachev 						   UNDERSCAN_OFF);
1829b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1830b843c749SSergey Zigachev 						   adev->mode_info.underscan_hborder_property,
1831b843c749SSergey Zigachev 						   0);
1832b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1833b843c749SSergey Zigachev 						   adev->mode_info.underscan_vborder_property,
1834b843c749SSergey Zigachev 						   0);
1835b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1836b843c749SSergey Zigachev 						   dev->mode_config.scaling_mode_property,
1837b843c749SSergey Zigachev 						   DRM_MODE_SCALE_NONE);
1838b843c749SSergey Zigachev 			if (amdgpu_audio != 0) {
1839b843c749SSergey Zigachev 				drm_object_attach_property(&amdgpu_connector->base.base,
1840b843c749SSergey Zigachev 							   adev->mode_info.audio_property,
1841b843c749SSergey Zigachev 							   AMDGPU_AUDIO_AUTO);
1842b843c749SSergey Zigachev 			}
1843b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1844b843c749SSergey Zigachev 						   adev->mode_info.dither_property,
1845b843c749SSergey Zigachev 						   AMDGPU_FMT_DITHER_DISABLE);
1846b843c749SSergey Zigachev 			connector->interlace_allowed = true;
1847b843c749SSergey Zigachev 			/* in theory with a DP to VGA converter... */
1848b843c749SSergey Zigachev 			connector->doublescan_allowed = false;
1849b843c749SSergey Zigachev 			break;
1850b843c749SSergey Zigachev 		case DRM_MODE_CONNECTOR_eDP:
1851b843c749SSergey Zigachev 			amdgpu_dig_connector = kzalloc(sizeof(struct amdgpu_connector_atom_dig), GFP_KERNEL);
1852b843c749SSergey Zigachev 			if (!amdgpu_dig_connector)
1853b843c749SSergey Zigachev 				goto failed;
1854b843c749SSergey Zigachev 			amdgpu_connector->con_priv = amdgpu_dig_connector;
1855b843c749SSergey Zigachev 			drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_edp_funcs, connector_type);
1856b843c749SSergey Zigachev 			drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_dp_helper_funcs);
1857b843c749SSergey Zigachev 			if (i2c_bus->valid) {
1858b843c749SSergey Zigachev 				amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
1859b843c749SSergey Zigachev 				if (amdgpu_connector->ddc_bus)
1860b843c749SSergey Zigachev 					has_aux = true;
1861b843c749SSergey Zigachev 				else
1862b843c749SSergey Zigachev 					DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
1863b843c749SSergey Zigachev 			}
1864b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1865b843c749SSergey Zigachev 						      dev->mode_config.scaling_mode_property,
1866b843c749SSergey Zigachev 						      DRM_MODE_SCALE_FULLSCREEN);
1867b843c749SSergey Zigachev 			subpixel_order = SubPixelHorizontalRGB;
1868b843c749SSergey Zigachev 			connector->interlace_allowed = false;
1869b843c749SSergey Zigachev 			connector->doublescan_allowed = false;
1870b843c749SSergey Zigachev 			break;
1871b843c749SSergey Zigachev 		case DRM_MODE_CONNECTOR_LVDS:
1872b843c749SSergey Zigachev 			amdgpu_dig_connector = kzalloc(sizeof(struct amdgpu_connector_atom_dig), GFP_KERNEL);
1873b843c749SSergey Zigachev 			if (!amdgpu_dig_connector)
1874b843c749SSergey Zigachev 				goto failed;
1875b843c749SSergey Zigachev 			amdgpu_connector->con_priv = amdgpu_dig_connector;
1876b843c749SSergey Zigachev 			drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_lvds_funcs, connector_type);
1877b843c749SSergey Zigachev 			drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_lvds_helper_funcs);
1878b843c749SSergey Zigachev 			if (i2c_bus->valid) {
1879b843c749SSergey Zigachev 				amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus);
1880b843c749SSergey Zigachev 				if (!amdgpu_connector->ddc_bus)
1881b843c749SSergey Zigachev 					DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
1882b843c749SSergey Zigachev 			}
1883b843c749SSergey Zigachev 			drm_object_attach_property(&amdgpu_connector->base.base,
1884b843c749SSergey Zigachev 						      dev->mode_config.scaling_mode_property,
1885b843c749SSergey Zigachev 						      DRM_MODE_SCALE_FULLSCREEN);
1886b843c749SSergey Zigachev 			subpixel_order = SubPixelHorizontalRGB;
1887b843c749SSergey Zigachev 			connector->interlace_allowed = false;
1888b843c749SSergey Zigachev 			connector->doublescan_allowed = false;
1889b843c749SSergey Zigachev 			break;
1890b843c749SSergey Zigachev 		}
1891b843c749SSergey Zigachev 	}
1892b843c749SSergey Zigachev 
1893b843c749SSergey Zigachev 	if (amdgpu_connector->hpd.hpd == AMDGPU_HPD_NONE) {
1894b843c749SSergey Zigachev 		if (i2c_bus->valid) {
1895b843c749SSergey Zigachev 			connector->polled = DRM_CONNECTOR_POLL_CONNECT |
1896b843c749SSergey Zigachev 			                    DRM_CONNECTOR_POLL_DISCONNECT;
1897b843c749SSergey Zigachev 		}
1898b843c749SSergey Zigachev 	} else
1899b843c749SSergey Zigachev 		connector->polled = DRM_CONNECTOR_POLL_HPD;
1900b843c749SSergey Zigachev 
1901b843c749SSergey Zigachev 	connector->display_info.subpixel_order = subpixel_order;
1902b843c749SSergey Zigachev 	drm_connector_register(connector);
1903b843c749SSergey Zigachev 
1904b843c749SSergey Zigachev 	if (has_aux)
1905b843c749SSergey Zigachev 		amdgpu_atombios_dp_aux_init(amdgpu_connector);
1906b843c749SSergey Zigachev 
1907b843c749SSergey Zigachev 	return;
1908b843c749SSergey Zigachev 
1909b843c749SSergey Zigachev failed:
1910b843c749SSergey Zigachev 	drm_connector_cleanup(connector);
1911b843c749SSergey Zigachev 	kfree(connector);
1912b843c749SSergey Zigachev }
1913