18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2007-8 Advanced Micro Devices, Inc.
38c2ecf20Sopenharmony_ci * Copyright 2008 Red Hat Inc.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
68c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
78c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
88c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
98c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
108c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
138c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
168c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
188c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
198c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
208c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
218c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * Authors: Dave Airlie
248c2ecf20Sopenharmony_ci *          Alex Deucher
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include <drm/drm_edid.h>
288c2ecf20Sopenharmony_ci#include <drm/drm_crtc_helper.h>
298c2ecf20Sopenharmony_ci#include <drm/drm_fb_helper.h>
308c2ecf20Sopenharmony_ci#include <drm/drm_dp_mst_helper.h>
318c2ecf20Sopenharmony_ci#include <drm/drm_probe_helper.h>
328c2ecf20Sopenharmony_ci#include <drm/radeon_drm.h>
338c2ecf20Sopenharmony_ci#include "radeon.h"
348c2ecf20Sopenharmony_ci#include "radeon_audio.h"
358c2ecf20Sopenharmony_ci#include "atom.h"
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
388c2ecf20Sopenharmony_ci#include <linux/vga_switcheroo.h>
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic int radeon_dp_handle_hpd(struct drm_connector *connector)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
438c2ecf20Sopenharmony_ci	int ret;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	ret = radeon_dp_mst_check_status(radeon_connector);
468c2ecf20Sopenharmony_ci	if (ret == -EINVAL)
478c2ecf20Sopenharmony_ci		return 1;
488c2ecf20Sopenharmony_ci	return 0;
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_civoid radeon_connector_hotplug(struct drm_connector *connector)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	struct drm_device *dev = connector->dev;
538c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
548c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
578c2ecf20Sopenharmony_ci		struct radeon_connector_atom_dig *dig_connector =
588c2ecf20Sopenharmony_ci			radeon_connector->con_priv;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci		if (radeon_connector->is_mst_connector)
618c2ecf20Sopenharmony_ci			return;
628c2ecf20Sopenharmony_ci		if (dig_connector->is_mst) {
638c2ecf20Sopenharmony_ci			radeon_dp_handle_hpd(connector);
648c2ecf20Sopenharmony_ci			return;
658c2ecf20Sopenharmony_ci		}
668c2ecf20Sopenharmony_ci	}
678c2ecf20Sopenharmony_ci	/* bail if the connector does not have hpd pin, e.g.,
688c2ecf20Sopenharmony_ci	 * VGA, TV, etc.
698c2ecf20Sopenharmony_ci	 */
708c2ecf20Sopenharmony_ci	if (radeon_connector->hpd.hpd == RADEON_HPD_NONE)
718c2ecf20Sopenharmony_ci		return;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	/* if the connector is already off, don't turn it back on */
768c2ecf20Sopenharmony_ci	/* FIXME: This access isn't protected by any locks. */
778c2ecf20Sopenharmony_ci	if (connector->dpms != DRM_MODE_DPMS_ON)
788c2ecf20Sopenharmony_ci		return;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	/* just deal with DP (not eDP) here. */
818c2ecf20Sopenharmony_ci	if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
828c2ecf20Sopenharmony_ci		struct radeon_connector_atom_dig *dig_connector =
838c2ecf20Sopenharmony_ci			radeon_connector->con_priv;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci		/* if existing sink type was not DP no need to retrain */
868c2ecf20Sopenharmony_ci		if (dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_DISPLAYPORT)
878c2ecf20Sopenharmony_ci			return;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci		/* first get sink type as it may be reset after (un)plug */
908c2ecf20Sopenharmony_ci		dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
918c2ecf20Sopenharmony_ci		/* don't do anything if sink is not display port, i.e.,
928c2ecf20Sopenharmony_ci		 * passive dp->(dvi|hdmi) adaptor
938c2ecf20Sopenharmony_ci		 */
948c2ecf20Sopenharmony_ci		if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT &&
958c2ecf20Sopenharmony_ci		    radeon_hpd_sense(rdev, radeon_connector->hpd.hpd) &&
968c2ecf20Sopenharmony_ci		    radeon_dp_needs_link_train(radeon_connector)) {
978c2ecf20Sopenharmony_ci			/* Don't start link training before we have the DPCD */
988c2ecf20Sopenharmony_ci			if (!radeon_dp_getdpcd(radeon_connector))
998c2ecf20Sopenharmony_ci				return;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci			/* Turn the connector off and back on immediately, which
1028c2ecf20Sopenharmony_ci			 * will trigger link training
1038c2ecf20Sopenharmony_ci			 */
1048c2ecf20Sopenharmony_ci			drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
1058c2ecf20Sopenharmony_ci			drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
1068c2ecf20Sopenharmony_ci		}
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic void radeon_property_change_mode(struct drm_encoder *encoder)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	struct drm_crtc *crtc = encoder->crtc;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	if (crtc && crtc->enabled) {
1158c2ecf20Sopenharmony_ci		drm_crtc_helper_set_mode(crtc, &crtc->mode,
1168c2ecf20Sopenharmony_ci					 crtc->x, crtc->y, crtc->primary->fb);
1178c2ecf20Sopenharmony_ci	}
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ciint radeon_get_monitor_bpc(struct drm_connector *connector)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	struct drm_device *dev = connector->dev;
1238c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
1248c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
1258c2ecf20Sopenharmony_ci	struct radeon_connector_atom_dig *dig_connector;
1268c2ecf20Sopenharmony_ci	int bpc = 8;
1278c2ecf20Sopenharmony_ci	int mode_clock, max_tmds_clock;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	switch (connector->connector_type) {
1308c2ecf20Sopenharmony_ci	case DRM_MODE_CONNECTOR_DVII:
1318c2ecf20Sopenharmony_ci	case DRM_MODE_CONNECTOR_HDMIB:
1328c2ecf20Sopenharmony_ci		if (radeon_connector->use_digital) {
1338c2ecf20Sopenharmony_ci			if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
1348c2ecf20Sopenharmony_ci				if (connector->display_info.bpc)
1358c2ecf20Sopenharmony_ci					bpc = connector->display_info.bpc;
1368c2ecf20Sopenharmony_ci			}
1378c2ecf20Sopenharmony_ci		}
1388c2ecf20Sopenharmony_ci		break;
1398c2ecf20Sopenharmony_ci	case DRM_MODE_CONNECTOR_DVID:
1408c2ecf20Sopenharmony_ci	case DRM_MODE_CONNECTOR_HDMIA:
1418c2ecf20Sopenharmony_ci		if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
1428c2ecf20Sopenharmony_ci			if (connector->display_info.bpc)
1438c2ecf20Sopenharmony_ci				bpc = connector->display_info.bpc;
1448c2ecf20Sopenharmony_ci		}
1458c2ecf20Sopenharmony_ci		break;
1468c2ecf20Sopenharmony_ci	case DRM_MODE_CONNECTOR_DisplayPort:
1478c2ecf20Sopenharmony_ci		dig_connector = radeon_connector->con_priv;
1488c2ecf20Sopenharmony_ci		if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
1498c2ecf20Sopenharmony_ci		    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) ||
1508c2ecf20Sopenharmony_ci		    drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
1518c2ecf20Sopenharmony_ci			if (connector->display_info.bpc)
1528c2ecf20Sopenharmony_ci				bpc = connector->display_info.bpc;
1538c2ecf20Sopenharmony_ci		}
1548c2ecf20Sopenharmony_ci		break;
1558c2ecf20Sopenharmony_ci	case DRM_MODE_CONNECTOR_eDP:
1568c2ecf20Sopenharmony_ci	case DRM_MODE_CONNECTOR_LVDS:
1578c2ecf20Sopenharmony_ci		if (connector->display_info.bpc)
1588c2ecf20Sopenharmony_ci			bpc = connector->display_info.bpc;
1598c2ecf20Sopenharmony_ci		else if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) {
1608c2ecf20Sopenharmony_ci			const struct drm_connector_helper_funcs *connector_funcs =
1618c2ecf20Sopenharmony_ci				connector->helper_private;
1628c2ecf20Sopenharmony_ci			struct drm_encoder *encoder = connector_funcs->best_encoder(connector);
1638c2ecf20Sopenharmony_ci			struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
1648c2ecf20Sopenharmony_ci			struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci			if (dig->lcd_misc & ATOM_PANEL_MISC_V13_6BIT_PER_COLOR)
1678c2ecf20Sopenharmony_ci				bpc = 6;
1688c2ecf20Sopenharmony_ci			else if (dig->lcd_misc & ATOM_PANEL_MISC_V13_8BIT_PER_COLOR)
1698c2ecf20Sopenharmony_ci				bpc = 8;
1708c2ecf20Sopenharmony_ci		}
1718c2ecf20Sopenharmony_ci		break;
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
1758c2ecf20Sopenharmony_ci		/* hdmi deep color only implemented on DCE4+ */
1768c2ecf20Sopenharmony_ci		if ((bpc > 8) && !ASIC_IS_DCE4(rdev)) {
1778c2ecf20Sopenharmony_ci			DRM_DEBUG("%s: HDMI deep color %d bpc unsupported. Using 8 bpc.\n",
1788c2ecf20Sopenharmony_ci					  connector->name, bpc);
1798c2ecf20Sopenharmony_ci			bpc = 8;
1808c2ecf20Sopenharmony_ci		}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci		/*
1838c2ecf20Sopenharmony_ci		 * Pre DCE-8 hw can't handle > 12 bpc, and more than 12 bpc doesn't make
1848c2ecf20Sopenharmony_ci		 * much sense without support for > 12 bpc framebuffers. RGB 4:4:4 at
1858c2ecf20Sopenharmony_ci		 * 12 bpc is always supported on hdmi deep color sinks, as this is
1868c2ecf20Sopenharmony_ci		 * required by the HDMI-1.3 spec. Clamp to a safe 12 bpc maximum.
1878c2ecf20Sopenharmony_ci		 */
1888c2ecf20Sopenharmony_ci		if (bpc > 12) {
1898c2ecf20Sopenharmony_ci			DRM_DEBUG("%s: HDMI deep color %d bpc unsupported. Using 12 bpc.\n",
1908c2ecf20Sopenharmony_ci					  connector->name, bpc);
1918c2ecf20Sopenharmony_ci			bpc = 12;
1928c2ecf20Sopenharmony_ci		}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci		/* Any defined maximum tmds clock limit we must not exceed? */
1958c2ecf20Sopenharmony_ci		if (connector->display_info.max_tmds_clock > 0) {
1968c2ecf20Sopenharmony_ci			/* mode_clock is clock in kHz for mode to be modeset on this connector */
1978c2ecf20Sopenharmony_ci			mode_clock = radeon_connector->pixelclock_for_modeset;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci			/* Maximum allowable input clock in kHz */
2008c2ecf20Sopenharmony_ci			max_tmds_clock = connector->display_info.max_tmds_clock;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci			DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n",
2038c2ecf20Sopenharmony_ci					  connector->name, mode_clock, max_tmds_clock);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci			/* Check if bpc is within clock limit. Try to degrade gracefully otherwise */
2068c2ecf20Sopenharmony_ci			if ((bpc == 12) && (mode_clock * 3/2 > max_tmds_clock)) {
2078c2ecf20Sopenharmony_ci				if ((connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) &&
2088c2ecf20Sopenharmony_ci					(mode_clock * 5/4 <= max_tmds_clock))
2098c2ecf20Sopenharmony_ci					bpc = 10;
2108c2ecf20Sopenharmony_ci				else
2118c2ecf20Sopenharmony_ci					bpc = 8;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci				DRM_DEBUG("%s: HDMI deep color 12 bpc exceeds max tmds clock. Using %d bpc.\n",
2148c2ecf20Sopenharmony_ci						  connector->name, bpc);
2158c2ecf20Sopenharmony_ci			}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci			if ((bpc == 10) && (mode_clock * 5/4 > max_tmds_clock)) {
2188c2ecf20Sopenharmony_ci				bpc = 8;
2198c2ecf20Sopenharmony_ci				DRM_DEBUG("%s: HDMI deep color 10 bpc exceeds max tmds clock. Using %d bpc.\n",
2208c2ecf20Sopenharmony_ci						  connector->name, bpc);
2218c2ecf20Sopenharmony_ci			}
2228c2ecf20Sopenharmony_ci		}
2238c2ecf20Sopenharmony_ci		else if (bpc > 8) {
2248c2ecf20Sopenharmony_ci			/* max_tmds_clock missing, but hdmi spec mandates it for deep color. */
2258c2ecf20Sopenharmony_ci			DRM_DEBUG("%s: Required max tmds clock for HDMI deep color missing. Using 8 bpc.\n",
2268c2ecf20Sopenharmony_ci					  connector->name);
2278c2ecf20Sopenharmony_ci			bpc = 8;
2288c2ecf20Sopenharmony_ci		}
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	if ((radeon_deep_color == 0) && (bpc > 8)) {
2328c2ecf20Sopenharmony_ci		DRM_DEBUG("%s: Deep color disabled. Set radeon module param deep_color=1 to enable.\n",
2338c2ecf20Sopenharmony_ci				  connector->name);
2348c2ecf20Sopenharmony_ci		bpc = 8;
2358c2ecf20Sopenharmony_ci	}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	DRM_DEBUG("%s: Display bpc=%d, returned bpc=%d\n",
2388c2ecf20Sopenharmony_ci			  connector->name, connector->display_info.bpc, bpc);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	return bpc;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic void
2448c2ecf20Sopenharmony_ciradeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_connector_status status)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	struct drm_device *dev = connector->dev;
2478c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
2488c2ecf20Sopenharmony_ci	struct drm_encoder *best_encoder;
2498c2ecf20Sopenharmony_ci	struct drm_encoder *encoder;
2508c2ecf20Sopenharmony_ci	const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
2518c2ecf20Sopenharmony_ci	bool connected;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	best_encoder = connector_funcs->best_encoder(connector);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	drm_connector_for_each_possible_encoder(connector, encoder) {
2568c2ecf20Sopenharmony_ci		if ((encoder == best_encoder) && (status == connector_status_connected))
2578c2ecf20Sopenharmony_ci			connected = true;
2588c2ecf20Sopenharmony_ci		else
2598c2ecf20Sopenharmony_ci			connected = false;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci		if (rdev->is_atom_bios)
2628c2ecf20Sopenharmony_ci			radeon_atombios_connected_scratch_regs(connector, encoder, connected);
2638c2ecf20Sopenharmony_ci		else
2648c2ecf20Sopenharmony_ci			radeon_combios_connected_scratch_regs(connector, encoder, connected);
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic struct drm_encoder *radeon_find_encoder(struct drm_connector *connector, int encoder_type)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	struct drm_encoder *encoder;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	drm_connector_for_each_possible_encoder(connector, encoder) {
2738c2ecf20Sopenharmony_ci		if (encoder->encoder_type == encoder_type)
2748c2ecf20Sopenharmony_ci			return encoder;
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	return NULL;
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_cistruct edid *radeon_connector_edid(struct drm_connector *connector)
2818c2ecf20Sopenharmony_ci{
2828c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
2838c2ecf20Sopenharmony_ci	struct drm_property_blob *edid_blob = connector->edid_blob_ptr;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	if (radeon_connector->edid) {
2868c2ecf20Sopenharmony_ci		return radeon_connector->edid;
2878c2ecf20Sopenharmony_ci	} else if (edid_blob) {
2888c2ecf20Sopenharmony_ci		struct edid *edid = kmemdup(edid_blob->data, edid_blob->length, GFP_KERNEL);
2898c2ecf20Sopenharmony_ci		if (edid)
2908c2ecf20Sopenharmony_ci			radeon_connector->edid = edid;
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci	return radeon_connector->edid;
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic void radeon_connector_get_edid(struct drm_connector *connector)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	struct drm_device *dev = connector->dev;
2988c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
2998c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	if (radeon_connector->edid)
3028c2ecf20Sopenharmony_ci		return;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	/* on hw with routers, select right port */
3058c2ecf20Sopenharmony_ci	if (radeon_connector->router.ddc_valid)
3068c2ecf20Sopenharmony_ci		radeon_router_select_ddc_port(radeon_connector);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	if ((radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
3098c2ecf20Sopenharmony_ci	     ENCODER_OBJECT_ID_NONE) &&
3108c2ecf20Sopenharmony_ci	    radeon_connector->ddc_bus->has_aux) {
3118c2ecf20Sopenharmony_ci		radeon_connector->edid = drm_get_edid(connector,
3128c2ecf20Sopenharmony_ci						      &radeon_connector->ddc_bus->aux.ddc);
3138c2ecf20Sopenharmony_ci	} else if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
3148c2ecf20Sopenharmony_ci		   (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
3158c2ecf20Sopenharmony_ci		struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci		if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT ||
3188c2ecf20Sopenharmony_ci		     dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) &&
3198c2ecf20Sopenharmony_ci		    radeon_connector->ddc_bus->has_aux)
3208c2ecf20Sopenharmony_ci			radeon_connector->edid = drm_get_edid(&radeon_connector->base,
3218c2ecf20Sopenharmony_ci							      &radeon_connector->ddc_bus->aux.ddc);
3228c2ecf20Sopenharmony_ci		else if (radeon_connector->ddc_bus)
3238c2ecf20Sopenharmony_ci			radeon_connector->edid = drm_get_edid(&radeon_connector->base,
3248c2ecf20Sopenharmony_ci							      &radeon_connector->ddc_bus->adapter);
3258c2ecf20Sopenharmony_ci	} else if (vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC &&
3268c2ecf20Sopenharmony_ci		   connector->connector_type == DRM_MODE_CONNECTOR_LVDS &&
3278c2ecf20Sopenharmony_ci		   radeon_connector->ddc_bus) {
3288c2ecf20Sopenharmony_ci		radeon_connector->edid = drm_get_edid_switcheroo(&radeon_connector->base,
3298c2ecf20Sopenharmony_ci								 &radeon_connector->ddc_bus->adapter);
3308c2ecf20Sopenharmony_ci	} else if (radeon_connector->ddc_bus) {
3318c2ecf20Sopenharmony_ci		radeon_connector->edid = drm_get_edid(&radeon_connector->base,
3328c2ecf20Sopenharmony_ci						      &radeon_connector->ddc_bus->adapter);
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	if (!radeon_connector->edid) {
3368c2ecf20Sopenharmony_ci		/* don't fetch the edid from the vbios if ddc fails and runpm is
3378c2ecf20Sopenharmony_ci		 * enabled so we report disconnected.
3388c2ecf20Sopenharmony_ci		 */
3398c2ecf20Sopenharmony_ci		if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0))
3408c2ecf20Sopenharmony_ci			return;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci		if (rdev->is_atom_bios) {
3438c2ecf20Sopenharmony_ci			/* some laptops provide a hardcoded edid in rom for LCDs */
3448c2ecf20Sopenharmony_ci			if (((connector->connector_type == DRM_MODE_CONNECTOR_LVDS) ||
3458c2ecf20Sopenharmony_ci			     (connector->connector_type == DRM_MODE_CONNECTOR_eDP)))
3468c2ecf20Sopenharmony_ci				radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev);
3478c2ecf20Sopenharmony_ci		} else {
3488c2ecf20Sopenharmony_ci			/* some servers provide a hardcoded edid in rom for KVMs */
3498c2ecf20Sopenharmony_ci			radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev);
3508c2ecf20Sopenharmony_ci		}
3518c2ecf20Sopenharmony_ci	}
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cistatic void radeon_connector_free_edid(struct drm_connector *connector)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	if (radeon_connector->edid) {
3598c2ecf20Sopenharmony_ci		kfree(radeon_connector->edid);
3608c2ecf20Sopenharmony_ci		radeon_connector->edid = NULL;
3618c2ecf20Sopenharmony_ci	}
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_cistatic int radeon_ddc_get_modes(struct drm_connector *connector)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
3678c2ecf20Sopenharmony_ci	int ret;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	if (radeon_connector->edid) {
3708c2ecf20Sopenharmony_ci		drm_connector_update_edid_property(connector, radeon_connector->edid);
3718c2ecf20Sopenharmony_ci		ret = drm_add_edid_modes(connector, radeon_connector->edid);
3728c2ecf20Sopenharmony_ci		return ret;
3738c2ecf20Sopenharmony_ci	}
3748c2ecf20Sopenharmony_ci	drm_connector_update_edid_property(connector, NULL);
3758c2ecf20Sopenharmony_ci	return 0;
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	struct drm_encoder *encoder;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	/* pick the first one */
3838c2ecf20Sopenharmony_ci	drm_connector_for_each_possible_encoder(connector, encoder)
3848c2ecf20Sopenharmony_ci		return encoder;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	return NULL;
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic void radeon_get_native_mode(struct drm_connector *connector)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
3928c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	if (encoder == NULL)
3958c2ecf20Sopenharmony_ci		return;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	radeon_encoder = to_radeon_encoder(encoder);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	if (!list_empty(&connector->probed_modes)) {
4008c2ecf20Sopenharmony_ci		struct drm_display_mode *preferred_mode =
4018c2ecf20Sopenharmony_ci			list_first_entry(&connector->probed_modes,
4028c2ecf20Sopenharmony_ci					 struct drm_display_mode, head);
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci		radeon_encoder->native_mode = *preferred_mode;
4058c2ecf20Sopenharmony_ci	} else {
4068c2ecf20Sopenharmony_ci		radeon_encoder->native_mode.clock = 0;
4078c2ecf20Sopenharmony_ci	}
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci/*
4118c2ecf20Sopenharmony_ci * radeon_connector_analog_encoder_conflict_solve
4128c2ecf20Sopenharmony_ci * - search for other connectors sharing this encoder
4138c2ecf20Sopenharmony_ci *   if priority is true, then set them disconnected if this is connected
4148c2ecf20Sopenharmony_ci *   if priority is false, set us disconnected if they are connected
4158c2ecf20Sopenharmony_ci */
4168c2ecf20Sopenharmony_cistatic enum drm_connector_status
4178c2ecf20Sopenharmony_ciradeon_connector_analog_encoder_conflict_solve(struct drm_connector *connector,
4188c2ecf20Sopenharmony_ci					       struct drm_encoder *encoder,
4198c2ecf20Sopenharmony_ci					       enum drm_connector_status current_status,
4208c2ecf20Sopenharmony_ci					       bool priority)
4218c2ecf20Sopenharmony_ci{
4228c2ecf20Sopenharmony_ci	struct drm_device *dev = connector->dev;
4238c2ecf20Sopenharmony_ci	struct drm_connector *conflict;
4248c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_conflict;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	list_for_each_entry(conflict, &dev->mode_config.connector_list, head) {
4278c2ecf20Sopenharmony_ci		struct drm_encoder *enc;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci		if (conflict == connector)
4308c2ecf20Sopenharmony_ci			continue;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci		radeon_conflict = to_radeon_connector(conflict);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci		drm_connector_for_each_possible_encoder(conflict, enc) {
4358c2ecf20Sopenharmony_ci			/* if the IDs match */
4368c2ecf20Sopenharmony_ci			if (enc == encoder) {
4378c2ecf20Sopenharmony_ci				if (conflict->status != connector_status_connected)
4388c2ecf20Sopenharmony_ci					continue;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci				if (radeon_conflict->use_digital)
4418c2ecf20Sopenharmony_ci					continue;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci				if (priority) {
4448c2ecf20Sopenharmony_ci					DRM_DEBUG_KMS("1: conflicting encoders switching off %s\n",
4458c2ecf20Sopenharmony_ci						      conflict->name);
4468c2ecf20Sopenharmony_ci					DRM_DEBUG_KMS("in favor of %s\n",
4478c2ecf20Sopenharmony_ci						      connector->name);
4488c2ecf20Sopenharmony_ci					conflict->status = connector_status_disconnected;
4498c2ecf20Sopenharmony_ci					radeon_connector_update_scratch_regs(conflict, connector_status_disconnected);
4508c2ecf20Sopenharmony_ci				} else {
4518c2ecf20Sopenharmony_ci					DRM_DEBUG_KMS("2: conflicting encoders switching off %s\n",
4528c2ecf20Sopenharmony_ci						      connector->name);
4538c2ecf20Sopenharmony_ci					DRM_DEBUG_KMS("in favor of %s\n",
4548c2ecf20Sopenharmony_ci						      conflict->name);
4558c2ecf20Sopenharmony_ci					current_status = connector_status_disconnected;
4568c2ecf20Sopenharmony_ci				}
4578c2ecf20Sopenharmony_ci				break;
4588c2ecf20Sopenharmony_ci			}
4598c2ecf20Sopenharmony_ci		}
4608c2ecf20Sopenharmony_ci	}
4618c2ecf20Sopenharmony_ci	return current_status;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_cistatic struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encoder)
4668c2ecf20Sopenharmony_ci{
4678c2ecf20Sopenharmony_ci	struct drm_device *dev = encoder->dev;
4688c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
4698c2ecf20Sopenharmony_ci	struct drm_display_mode *mode = NULL;
4708c2ecf20Sopenharmony_ci	struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	if (native_mode->hdisplay != 0 &&
4738c2ecf20Sopenharmony_ci	    native_mode->vdisplay != 0 &&
4748c2ecf20Sopenharmony_ci	    native_mode->clock != 0) {
4758c2ecf20Sopenharmony_ci		mode = drm_mode_duplicate(dev, native_mode);
4768c2ecf20Sopenharmony_ci		if (!mode)
4778c2ecf20Sopenharmony_ci			return NULL;
4788c2ecf20Sopenharmony_ci		mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
4798c2ecf20Sopenharmony_ci		drm_mode_set_name(mode);
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci		DRM_DEBUG_KMS("Adding native panel mode %s\n", mode->name);
4828c2ecf20Sopenharmony_ci	} else if (native_mode->hdisplay != 0 &&
4838c2ecf20Sopenharmony_ci		   native_mode->vdisplay != 0) {
4848c2ecf20Sopenharmony_ci		/* mac laptops without an edid */
4858c2ecf20Sopenharmony_ci		/* Note that this is not necessarily the exact panel mode,
4868c2ecf20Sopenharmony_ci		 * but an approximation based on the cvt formula.  For these
4878c2ecf20Sopenharmony_ci		 * systems we should ideally read the mode info out of the
4888c2ecf20Sopenharmony_ci		 * registers or add a mode table, but this works and is much
4898c2ecf20Sopenharmony_ci		 * simpler.
4908c2ecf20Sopenharmony_ci		 */
4918c2ecf20Sopenharmony_ci		mode = drm_cvt_mode(dev, native_mode->hdisplay, native_mode->vdisplay, 60, true, false, false);
4928c2ecf20Sopenharmony_ci		if (!mode)
4938c2ecf20Sopenharmony_ci			return NULL;
4948c2ecf20Sopenharmony_ci		mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
4958c2ecf20Sopenharmony_ci		DRM_DEBUG_KMS("Adding cvt approximation of native panel mode %s\n", mode->name);
4968c2ecf20Sopenharmony_ci	}
4978c2ecf20Sopenharmony_ci	return mode;
4988c2ecf20Sopenharmony_ci}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_cistatic void radeon_add_common_modes(struct drm_encoder *encoder, struct drm_connector *connector)
5018c2ecf20Sopenharmony_ci{
5028c2ecf20Sopenharmony_ci	struct drm_device *dev = encoder->dev;
5038c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
5048c2ecf20Sopenharmony_ci	struct drm_display_mode *mode = NULL;
5058c2ecf20Sopenharmony_ci	struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
5068c2ecf20Sopenharmony_ci	int i;
5078c2ecf20Sopenharmony_ci	struct mode_size {
5088c2ecf20Sopenharmony_ci		int w;
5098c2ecf20Sopenharmony_ci		int h;
5108c2ecf20Sopenharmony_ci	} common_modes[17] = {
5118c2ecf20Sopenharmony_ci		{ 640,  480},
5128c2ecf20Sopenharmony_ci		{ 720,  480},
5138c2ecf20Sopenharmony_ci		{ 800,  600},
5148c2ecf20Sopenharmony_ci		{ 848,  480},
5158c2ecf20Sopenharmony_ci		{1024,  768},
5168c2ecf20Sopenharmony_ci		{1152,  768},
5178c2ecf20Sopenharmony_ci		{1280,  720},
5188c2ecf20Sopenharmony_ci		{1280,  800},
5198c2ecf20Sopenharmony_ci		{1280,  854},
5208c2ecf20Sopenharmony_ci		{1280,  960},
5218c2ecf20Sopenharmony_ci		{1280, 1024},
5228c2ecf20Sopenharmony_ci		{1440,  900},
5238c2ecf20Sopenharmony_ci		{1400, 1050},
5248c2ecf20Sopenharmony_ci		{1680, 1050},
5258c2ecf20Sopenharmony_ci		{1600, 1200},
5268c2ecf20Sopenharmony_ci		{1920, 1080},
5278c2ecf20Sopenharmony_ci		{1920, 1200}
5288c2ecf20Sopenharmony_ci	};
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	for (i = 0; i < 17; i++) {
5318c2ecf20Sopenharmony_ci		if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) {
5328c2ecf20Sopenharmony_ci			if (common_modes[i].w > 1024 ||
5338c2ecf20Sopenharmony_ci			    common_modes[i].h > 768)
5348c2ecf20Sopenharmony_ci				continue;
5358c2ecf20Sopenharmony_ci		}
5368c2ecf20Sopenharmony_ci		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
5378c2ecf20Sopenharmony_ci			if (common_modes[i].w > native_mode->hdisplay ||
5388c2ecf20Sopenharmony_ci			    common_modes[i].h > native_mode->vdisplay ||
5398c2ecf20Sopenharmony_ci			    (common_modes[i].w == native_mode->hdisplay &&
5408c2ecf20Sopenharmony_ci			     common_modes[i].h == native_mode->vdisplay))
5418c2ecf20Sopenharmony_ci				continue;
5428c2ecf20Sopenharmony_ci		}
5438c2ecf20Sopenharmony_ci		if (common_modes[i].w < 320 || common_modes[i].h < 200)
5448c2ecf20Sopenharmony_ci			continue;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci		mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false);
5478c2ecf20Sopenharmony_ci		drm_mode_probed_add(connector, mode);
5488c2ecf20Sopenharmony_ci	}
5498c2ecf20Sopenharmony_ci}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_cistatic int radeon_connector_set_property(struct drm_connector *connector, struct drm_property *property,
5528c2ecf20Sopenharmony_ci				  uint64_t val)
5538c2ecf20Sopenharmony_ci{
5548c2ecf20Sopenharmony_ci	struct drm_device *dev = connector->dev;
5558c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
5568c2ecf20Sopenharmony_ci	struct drm_encoder *encoder;
5578c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	if (property == rdev->mode_info.coherent_mode_property) {
5608c2ecf20Sopenharmony_ci		struct radeon_encoder_atom_dig *dig;
5618c2ecf20Sopenharmony_ci		bool new_coherent_mode;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci		/* need to find digital encoder on connector */
5648c2ecf20Sopenharmony_ci		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
5658c2ecf20Sopenharmony_ci		if (!encoder)
5668c2ecf20Sopenharmony_ci			return 0;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci		radeon_encoder = to_radeon_encoder(encoder);
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci		if (!radeon_encoder->enc_priv)
5718c2ecf20Sopenharmony_ci			return 0;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci		dig = radeon_encoder->enc_priv;
5748c2ecf20Sopenharmony_ci		new_coherent_mode = val ? true : false;
5758c2ecf20Sopenharmony_ci		if (dig->coherent_mode != new_coherent_mode) {
5768c2ecf20Sopenharmony_ci			dig->coherent_mode = new_coherent_mode;
5778c2ecf20Sopenharmony_ci			radeon_property_change_mode(&radeon_encoder->base);
5788c2ecf20Sopenharmony_ci		}
5798c2ecf20Sopenharmony_ci	}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	if (property == rdev->mode_info.audio_property) {
5828c2ecf20Sopenharmony_ci		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
5838c2ecf20Sopenharmony_ci		/* need to find digital encoder on connector */
5848c2ecf20Sopenharmony_ci		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
5858c2ecf20Sopenharmony_ci		if (!encoder)
5868c2ecf20Sopenharmony_ci			return 0;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci		radeon_encoder = to_radeon_encoder(encoder);
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci		if (radeon_connector->audio != val) {
5918c2ecf20Sopenharmony_ci			radeon_connector->audio = val;
5928c2ecf20Sopenharmony_ci			radeon_property_change_mode(&radeon_encoder->base);
5938c2ecf20Sopenharmony_ci		}
5948c2ecf20Sopenharmony_ci	}
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	if (property == rdev->mode_info.dither_property) {
5978c2ecf20Sopenharmony_ci		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
5988c2ecf20Sopenharmony_ci		/* need to find digital encoder on connector */
5998c2ecf20Sopenharmony_ci		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
6008c2ecf20Sopenharmony_ci		if (!encoder)
6018c2ecf20Sopenharmony_ci			return 0;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci		radeon_encoder = to_radeon_encoder(encoder);
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci		if (radeon_connector->dither != val) {
6068c2ecf20Sopenharmony_ci			radeon_connector->dither = val;
6078c2ecf20Sopenharmony_ci			radeon_property_change_mode(&radeon_encoder->base);
6088c2ecf20Sopenharmony_ci		}
6098c2ecf20Sopenharmony_ci	}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	if (property == rdev->mode_info.underscan_property) {
6128c2ecf20Sopenharmony_ci		/* need to find digital encoder on connector */
6138c2ecf20Sopenharmony_ci		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
6148c2ecf20Sopenharmony_ci		if (!encoder)
6158c2ecf20Sopenharmony_ci			return 0;
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci		radeon_encoder = to_radeon_encoder(encoder);
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci		if (radeon_encoder->underscan_type != val) {
6208c2ecf20Sopenharmony_ci			radeon_encoder->underscan_type = val;
6218c2ecf20Sopenharmony_ci			radeon_property_change_mode(&radeon_encoder->base);
6228c2ecf20Sopenharmony_ci		}
6238c2ecf20Sopenharmony_ci	}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	if (property == rdev->mode_info.underscan_hborder_property) {
6268c2ecf20Sopenharmony_ci		/* need to find digital encoder on connector */
6278c2ecf20Sopenharmony_ci		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
6288c2ecf20Sopenharmony_ci		if (!encoder)
6298c2ecf20Sopenharmony_ci			return 0;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci		radeon_encoder = to_radeon_encoder(encoder);
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci		if (radeon_encoder->underscan_hborder != val) {
6348c2ecf20Sopenharmony_ci			radeon_encoder->underscan_hborder = val;
6358c2ecf20Sopenharmony_ci			radeon_property_change_mode(&radeon_encoder->base);
6368c2ecf20Sopenharmony_ci		}
6378c2ecf20Sopenharmony_ci	}
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	if (property == rdev->mode_info.underscan_vborder_property) {
6408c2ecf20Sopenharmony_ci		/* need to find digital encoder on connector */
6418c2ecf20Sopenharmony_ci		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
6428c2ecf20Sopenharmony_ci		if (!encoder)
6438c2ecf20Sopenharmony_ci			return 0;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci		radeon_encoder = to_radeon_encoder(encoder);
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci		if (radeon_encoder->underscan_vborder != val) {
6488c2ecf20Sopenharmony_ci			radeon_encoder->underscan_vborder = val;
6498c2ecf20Sopenharmony_ci			radeon_property_change_mode(&radeon_encoder->base);
6508c2ecf20Sopenharmony_ci		}
6518c2ecf20Sopenharmony_ci	}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	if (property == rdev->mode_info.tv_std_property) {
6548c2ecf20Sopenharmony_ci		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TVDAC);
6558c2ecf20Sopenharmony_ci		if (!encoder) {
6568c2ecf20Sopenharmony_ci			encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_DAC);
6578c2ecf20Sopenharmony_ci		}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci		if (!encoder)
6608c2ecf20Sopenharmony_ci			return 0;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci		radeon_encoder = to_radeon_encoder(encoder);
6638c2ecf20Sopenharmony_ci		if (!radeon_encoder->enc_priv)
6648c2ecf20Sopenharmony_ci			return 0;
6658c2ecf20Sopenharmony_ci		if (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom) {
6668c2ecf20Sopenharmony_ci			struct radeon_encoder_atom_dac *dac_int;
6678c2ecf20Sopenharmony_ci			dac_int = radeon_encoder->enc_priv;
6688c2ecf20Sopenharmony_ci			dac_int->tv_std = val;
6698c2ecf20Sopenharmony_ci		} else {
6708c2ecf20Sopenharmony_ci			struct radeon_encoder_tv_dac *dac_int;
6718c2ecf20Sopenharmony_ci			dac_int = radeon_encoder->enc_priv;
6728c2ecf20Sopenharmony_ci			dac_int->tv_std = val;
6738c2ecf20Sopenharmony_ci		}
6748c2ecf20Sopenharmony_ci		radeon_property_change_mode(&radeon_encoder->base);
6758c2ecf20Sopenharmony_ci	}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	if (property == rdev->mode_info.load_detect_property) {
6788c2ecf20Sopenharmony_ci		struct radeon_connector *radeon_connector =
6798c2ecf20Sopenharmony_ci			to_radeon_connector(connector);
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci		if (val == 0)
6828c2ecf20Sopenharmony_ci			radeon_connector->dac_load_detect = false;
6838c2ecf20Sopenharmony_ci		else
6848c2ecf20Sopenharmony_ci			radeon_connector->dac_load_detect = true;
6858c2ecf20Sopenharmony_ci	}
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	if (property == rdev->mode_info.tmds_pll_property) {
6888c2ecf20Sopenharmony_ci		struct radeon_encoder_int_tmds *tmds = NULL;
6898c2ecf20Sopenharmony_ci		bool ret = false;
6908c2ecf20Sopenharmony_ci		/* need to find digital encoder on connector */
6918c2ecf20Sopenharmony_ci		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
6928c2ecf20Sopenharmony_ci		if (!encoder)
6938c2ecf20Sopenharmony_ci			return 0;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci		radeon_encoder = to_radeon_encoder(encoder);
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci		tmds = radeon_encoder->enc_priv;
6988c2ecf20Sopenharmony_ci		if (!tmds)
6998c2ecf20Sopenharmony_ci			return 0;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci		if (val == 0) {
7028c2ecf20Sopenharmony_ci			if (rdev->is_atom_bios)
7038c2ecf20Sopenharmony_ci				ret = radeon_atombios_get_tmds_info(radeon_encoder, tmds);
7048c2ecf20Sopenharmony_ci			else
7058c2ecf20Sopenharmony_ci				ret = radeon_legacy_get_tmds_info_from_combios(radeon_encoder, tmds);
7068c2ecf20Sopenharmony_ci		}
7078c2ecf20Sopenharmony_ci		if (val == 1 || !ret)
7088c2ecf20Sopenharmony_ci			radeon_legacy_get_tmds_info_from_table(radeon_encoder, tmds);
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci		radeon_property_change_mode(&radeon_encoder->base);
7118c2ecf20Sopenharmony_ci	}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	if (property == dev->mode_config.scaling_mode_property) {
7148c2ecf20Sopenharmony_ci		enum radeon_rmx_type rmx_type;
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci		if (connector->encoder)
7178c2ecf20Sopenharmony_ci			radeon_encoder = to_radeon_encoder(connector->encoder);
7188c2ecf20Sopenharmony_ci		else {
7198c2ecf20Sopenharmony_ci			const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
7208c2ecf20Sopenharmony_ci			radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector));
7218c2ecf20Sopenharmony_ci		}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci		switch (val) {
7248c2ecf20Sopenharmony_ci		default:
7258c2ecf20Sopenharmony_ci		case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break;
7268c2ecf20Sopenharmony_ci		case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break;
7278c2ecf20Sopenharmony_ci		case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break;
7288c2ecf20Sopenharmony_ci		case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break;
7298c2ecf20Sopenharmony_ci		}
7308c2ecf20Sopenharmony_ci		if (radeon_encoder->rmx_type == rmx_type)
7318c2ecf20Sopenharmony_ci			return 0;
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci		if ((rmx_type != DRM_MODE_SCALE_NONE) &&
7348c2ecf20Sopenharmony_ci		    (radeon_encoder->native_mode.clock == 0))
7358c2ecf20Sopenharmony_ci			return 0;
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci		radeon_encoder->rmx_type = rmx_type;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci		radeon_property_change_mode(&radeon_encoder->base);
7408c2ecf20Sopenharmony_ci	}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	if (property == rdev->mode_info.output_csc_property) {
7438c2ecf20Sopenharmony_ci		if (connector->encoder)
7448c2ecf20Sopenharmony_ci			radeon_encoder = to_radeon_encoder(connector->encoder);
7458c2ecf20Sopenharmony_ci		else {
7468c2ecf20Sopenharmony_ci			const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
7478c2ecf20Sopenharmony_ci			radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector));
7488c2ecf20Sopenharmony_ci		}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci		if (radeon_encoder->output_csc == val)
7518c2ecf20Sopenharmony_ci			return 0;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci		radeon_encoder->output_csc = val;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci		if (connector->encoder && connector->encoder->crtc) {
7568c2ecf20Sopenharmony_ci			struct drm_crtc *crtc  = connector->encoder->crtc;
7578c2ecf20Sopenharmony_ci			struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci			radeon_crtc->output_csc = radeon_encoder->output_csc;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci			/*
7628c2ecf20Sopenharmony_ci			 * Our .gamma_set assumes the .gamma_store has been
7638c2ecf20Sopenharmony_ci			 * prefilled and don't care about its arguments.
7648c2ecf20Sopenharmony_ci			 */
7658c2ecf20Sopenharmony_ci			crtc->funcs->gamma_set(crtc, NULL, NULL, NULL, 0, NULL);
7668c2ecf20Sopenharmony_ci		}
7678c2ecf20Sopenharmony_ci	}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	return 0;
7708c2ecf20Sopenharmony_ci}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_cistatic void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder,
7738c2ecf20Sopenharmony_ci					  struct drm_connector *connector)
7748c2ecf20Sopenharmony_ci{
7758c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder =	to_radeon_encoder(encoder);
7768c2ecf20Sopenharmony_ci	struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
7778c2ecf20Sopenharmony_ci	struct drm_display_mode *t, *mode;
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	/* If the EDID preferred mode doesn't match the native mode, use it */
7808c2ecf20Sopenharmony_ci	list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
7818c2ecf20Sopenharmony_ci		if (mode->type & DRM_MODE_TYPE_PREFERRED) {
7828c2ecf20Sopenharmony_ci			if (mode->hdisplay != native_mode->hdisplay ||
7838c2ecf20Sopenharmony_ci			    mode->vdisplay != native_mode->vdisplay)
7848c2ecf20Sopenharmony_ci				memcpy(native_mode, mode, sizeof(*mode));
7858c2ecf20Sopenharmony_ci		}
7868c2ecf20Sopenharmony_ci	}
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	/* Try to get native mode details from EDID if necessary */
7898c2ecf20Sopenharmony_ci	if (!native_mode->clock) {
7908c2ecf20Sopenharmony_ci		list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
7918c2ecf20Sopenharmony_ci			if (mode->hdisplay == native_mode->hdisplay &&
7928c2ecf20Sopenharmony_ci			    mode->vdisplay == native_mode->vdisplay) {
7938c2ecf20Sopenharmony_ci				*native_mode = *mode;
7948c2ecf20Sopenharmony_ci				drm_mode_set_crtcinfo(native_mode, CRTC_INTERLACE_HALVE_V);
7958c2ecf20Sopenharmony_ci				DRM_DEBUG_KMS("Determined LVDS native mode details from EDID\n");
7968c2ecf20Sopenharmony_ci				break;
7978c2ecf20Sopenharmony_ci			}
7988c2ecf20Sopenharmony_ci		}
7998c2ecf20Sopenharmony_ci	}
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	if (!native_mode->clock) {
8028c2ecf20Sopenharmony_ci		DRM_DEBUG_KMS("No LVDS native mode details, disabling RMX\n");
8038c2ecf20Sopenharmony_ci		radeon_encoder->rmx_type = RMX_OFF;
8048c2ecf20Sopenharmony_ci	}
8058c2ecf20Sopenharmony_ci}
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_cistatic int radeon_lvds_get_modes(struct drm_connector *connector)
8088c2ecf20Sopenharmony_ci{
8098c2ecf20Sopenharmony_ci	struct drm_encoder *encoder;
8108c2ecf20Sopenharmony_ci	int ret = 0;
8118c2ecf20Sopenharmony_ci	struct drm_display_mode *mode;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	radeon_connector_get_edid(connector);
8148c2ecf20Sopenharmony_ci	ret = radeon_ddc_get_modes(connector);
8158c2ecf20Sopenharmony_ci	if (ret > 0) {
8168c2ecf20Sopenharmony_ci		encoder = radeon_best_single_encoder(connector);
8178c2ecf20Sopenharmony_ci		if (encoder) {
8188c2ecf20Sopenharmony_ci			radeon_fixup_lvds_native_mode(encoder, connector);
8198c2ecf20Sopenharmony_ci			/* add scaled modes */
8208c2ecf20Sopenharmony_ci			radeon_add_common_modes(encoder, connector);
8218c2ecf20Sopenharmony_ci		}
8228c2ecf20Sopenharmony_ci		return ret;
8238c2ecf20Sopenharmony_ci	}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	encoder = radeon_best_single_encoder(connector);
8268c2ecf20Sopenharmony_ci	if (!encoder)
8278c2ecf20Sopenharmony_ci		return 0;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	/* we have no EDID modes */
8308c2ecf20Sopenharmony_ci	mode = radeon_fp_native_mode(encoder);
8318c2ecf20Sopenharmony_ci	if (mode) {
8328c2ecf20Sopenharmony_ci		ret = 1;
8338c2ecf20Sopenharmony_ci		drm_mode_probed_add(connector, mode);
8348c2ecf20Sopenharmony_ci		/* add the width/height from vbios tables if available */
8358c2ecf20Sopenharmony_ci		connector->display_info.width_mm = mode->width_mm;
8368c2ecf20Sopenharmony_ci		connector->display_info.height_mm = mode->height_mm;
8378c2ecf20Sopenharmony_ci		/* add scaled modes */
8388c2ecf20Sopenharmony_ci		radeon_add_common_modes(encoder, connector);
8398c2ecf20Sopenharmony_ci	}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	return ret;
8428c2ecf20Sopenharmony_ci}
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_cistatic enum drm_mode_status radeon_lvds_mode_valid(struct drm_connector *connector,
8458c2ecf20Sopenharmony_ci				  struct drm_display_mode *mode)
8468c2ecf20Sopenharmony_ci{
8478c2ecf20Sopenharmony_ci	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	if ((mode->hdisplay < 320) || (mode->vdisplay < 240))
8508c2ecf20Sopenharmony_ci		return MODE_PANEL;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	if (encoder) {
8538c2ecf20Sopenharmony_ci		struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
8548c2ecf20Sopenharmony_ci		struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci		/* AVIVO hardware supports downscaling modes larger than the panel
8578c2ecf20Sopenharmony_ci		 * to the panel size, but I'm not sure this is desirable.
8588c2ecf20Sopenharmony_ci		 */
8598c2ecf20Sopenharmony_ci		if ((mode->hdisplay > native_mode->hdisplay) ||
8608c2ecf20Sopenharmony_ci		    (mode->vdisplay > native_mode->vdisplay))
8618c2ecf20Sopenharmony_ci			return MODE_PANEL;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci		/* if scaling is disabled, block non-native modes */
8648c2ecf20Sopenharmony_ci		if (radeon_encoder->rmx_type == RMX_OFF) {
8658c2ecf20Sopenharmony_ci			if ((mode->hdisplay != native_mode->hdisplay) ||
8668c2ecf20Sopenharmony_ci			    (mode->vdisplay != native_mode->vdisplay))
8678c2ecf20Sopenharmony_ci				return MODE_PANEL;
8688c2ecf20Sopenharmony_ci		}
8698c2ecf20Sopenharmony_ci	}
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	return MODE_OK;
8728c2ecf20Sopenharmony_ci}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_cistatic enum drm_connector_status
8758c2ecf20Sopenharmony_ciradeon_lvds_detect(struct drm_connector *connector, bool force)
8768c2ecf20Sopenharmony_ci{
8778c2ecf20Sopenharmony_ci	struct drm_device *dev = connector->dev;
8788c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
8798c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
8808c2ecf20Sopenharmony_ci	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
8818c2ecf20Sopenharmony_ci	enum drm_connector_status ret = connector_status_disconnected;
8828c2ecf20Sopenharmony_ci	int r;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	if (!drm_kms_helper_is_poll_worker()) {
8858c2ecf20Sopenharmony_ci		r = pm_runtime_get_sync(connector->dev->dev);
8868c2ecf20Sopenharmony_ci		if (r < 0) {
8878c2ecf20Sopenharmony_ci			pm_runtime_put_autosuspend(connector->dev->dev);
8888c2ecf20Sopenharmony_ci			return connector_status_disconnected;
8898c2ecf20Sopenharmony_ci		}
8908c2ecf20Sopenharmony_ci	}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	if (encoder) {
8938c2ecf20Sopenharmony_ci		struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
8948c2ecf20Sopenharmony_ci		struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci		/* check if panel is valid */
8978c2ecf20Sopenharmony_ci		if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
8988c2ecf20Sopenharmony_ci			ret = connector_status_connected;
8998c2ecf20Sopenharmony_ci		/* don't fetch the edid from the vbios if ddc fails and runpm is
9008c2ecf20Sopenharmony_ci		 * enabled so we report disconnected.
9018c2ecf20Sopenharmony_ci		 */
9028c2ecf20Sopenharmony_ci		if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0))
9038c2ecf20Sopenharmony_ci			ret = connector_status_disconnected;
9048c2ecf20Sopenharmony_ci	}
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	/* check for edid as well */
9078c2ecf20Sopenharmony_ci	radeon_connector_get_edid(connector);
9088c2ecf20Sopenharmony_ci	if (radeon_connector->edid)
9098c2ecf20Sopenharmony_ci		ret = connector_status_connected;
9108c2ecf20Sopenharmony_ci	/* check acpi lid status ??? */
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	radeon_connector_update_scratch_regs(connector, ret);
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	if (!drm_kms_helper_is_poll_worker()) {
9158c2ecf20Sopenharmony_ci		pm_runtime_mark_last_busy(connector->dev->dev);
9168c2ecf20Sopenharmony_ci		pm_runtime_put_autosuspend(connector->dev->dev);
9178c2ecf20Sopenharmony_ci	}
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	return ret;
9208c2ecf20Sopenharmony_ci}
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_cistatic void radeon_connector_unregister(struct drm_connector *connector)
9238c2ecf20Sopenharmony_ci{
9248c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	if (radeon_connector->ddc_bus && radeon_connector->ddc_bus->has_aux) {
9278c2ecf20Sopenharmony_ci		drm_dp_aux_unregister(&radeon_connector->ddc_bus->aux);
9288c2ecf20Sopenharmony_ci		radeon_connector->ddc_bus->has_aux = false;
9298c2ecf20Sopenharmony_ci	}
9308c2ecf20Sopenharmony_ci}
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_cistatic void radeon_connector_destroy(struct drm_connector *connector)
9338c2ecf20Sopenharmony_ci{
9348c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	radeon_connector_free_edid(connector);
9378c2ecf20Sopenharmony_ci	kfree(radeon_connector->con_priv);
9388c2ecf20Sopenharmony_ci	drm_connector_unregister(connector);
9398c2ecf20Sopenharmony_ci	drm_connector_cleanup(connector);
9408c2ecf20Sopenharmony_ci	kfree(connector);
9418c2ecf20Sopenharmony_ci}
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_cistatic int radeon_lvds_set_property(struct drm_connector *connector,
9448c2ecf20Sopenharmony_ci				    struct drm_property *property,
9458c2ecf20Sopenharmony_ci				    uint64_t value)
9468c2ecf20Sopenharmony_ci{
9478c2ecf20Sopenharmony_ci	struct drm_device *dev = connector->dev;
9488c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder;
9498c2ecf20Sopenharmony_ci	enum radeon_rmx_type rmx_type;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	DRM_DEBUG_KMS("\n");
9528c2ecf20Sopenharmony_ci	if (property != dev->mode_config.scaling_mode_property)
9538c2ecf20Sopenharmony_ci		return 0;
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	if (connector->encoder)
9568c2ecf20Sopenharmony_ci		radeon_encoder = to_radeon_encoder(connector->encoder);
9578c2ecf20Sopenharmony_ci	else {
9588c2ecf20Sopenharmony_ci		const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
9598c2ecf20Sopenharmony_ci		radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector));
9608c2ecf20Sopenharmony_ci	}
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	switch (value) {
9638c2ecf20Sopenharmony_ci	case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break;
9648c2ecf20Sopenharmony_ci	case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break;
9658c2ecf20Sopenharmony_ci	case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break;
9668c2ecf20Sopenharmony_ci	default:
9678c2ecf20Sopenharmony_ci	case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break;
9688c2ecf20Sopenharmony_ci	}
9698c2ecf20Sopenharmony_ci	if (radeon_encoder->rmx_type == rmx_type)
9708c2ecf20Sopenharmony_ci		return 0;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	radeon_encoder->rmx_type = rmx_type;
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	radeon_property_change_mode(&radeon_encoder->base);
9758c2ecf20Sopenharmony_ci	return 0;
9768c2ecf20Sopenharmony_ci}
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_cistatic const struct drm_connector_helper_funcs radeon_lvds_connector_helper_funcs = {
9808c2ecf20Sopenharmony_ci	.get_modes = radeon_lvds_get_modes,
9818c2ecf20Sopenharmony_ci	.mode_valid = radeon_lvds_mode_valid,
9828c2ecf20Sopenharmony_ci	.best_encoder = radeon_best_single_encoder,
9838c2ecf20Sopenharmony_ci};
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs radeon_lvds_connector_funcs = {
9868c2ecf20Sopenharmony_ci	.dpms = drm_helper_connector_dpms,
9878c2ecf20Sopenharmony_ci	.detect = radeon_lvds_detect,
9888c2ecf20Sopenharmony_ci	.fill_modes = drm_helper_probe_single_connector_modes,
9898c2ecf20Sopenharmony_ci	.early_unregister = radeon_connector_unregister,
9908c2ecf20Sopenharmony_ci	.destroy = radeon_connector_destroy,
9918c2ecf20Sopenharmony_ci	.set_property = radeon_lvds_set_property,
9928c2ecf20Sopenharmony_ci};
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_cistatic int radeon_vga_get_modes(struct drm_connector *connector)
9958c2ecf20Sopenharmony_ci{
9968c2ecf20Sopenharmony_ci	int ret;
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	radeon_connector_get_edid(connector);
9998c2ecf20Sopenharmony_ci	ret = radeon_ddc_get_modes(connector);
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	radeon_get_native_mode(connector);
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	return ret;
10048c2ecf20Sopenharmony_ci}
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_cistatic enum drm_mode_status radeon_vga_mode_valid(struct drm_connector *connector,
10078c2ecf20Sopenharmony_ci				  struct drm_display_mode *mode)
10088c2ecf20Sopenharmony_ci{
10098c2ecf20Sopenharmony_ci	struct drm_device *dev = connector->dev;
10108c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	/* XXX check mode bandwidth */
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	if ((mode->clock / 10) > rdev->clock.max_pixel_clock)
10158c2ecf20Sopenharmony_ci		return MODE_CLOCK_HIGH;
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	return MODE_OK;
10188c2ecf20Sopenharmony_ci}
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_cistatic enum drm_connector_status
10218c2ecf20Sopenharmony_ciradeon_vga_detect(struct drm_connector *connector, bool force)
10228c2ecf20Sopenharmony_ci{
10238c2ecf20Sopenharmony_ci	struct drm_device *dev = connector->dev;
10248c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
10258c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
10268c2ecf20Sopenharmony_ci	struct drm_encoder *encoder;
10278c2ecf20Sopenharmony_ci	const struct drm_encoder_helper_funcs *encoder_funcs;
10288c2ecf20Sopenharmony_ci	bool dret = false;
10298c2ecf20Sopenharmony_ci	enum drm_connector_status ret = connector_status_disconnected;
10308c2ecf20Sopenharmony_ci	int r;
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	if (!drm_kms_helper_is_poll_worker()) {
10338c2ecf20Sopenharmony_ci		r = pm_runtime_get_sync(connector->dev->dev);
10348c2ecf20Sopenharmony_ci		if (r < 0) {
10358c2ecf20Sopenharmony_ci			pm_runtime_put_autosuspend(connector->dev->dev);
10368c2ecf20Sopenharmony_ci			return connector_status_disconnected;
10378c2ecf20Sopenharmony_ci		}
10388c2ecf20Sopenharmony_ci	}
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	encoder = radeon_best_single_encoder(connector);
10418c2ecf20Sopenharmony_ci	if (!encoder)
10428c2ecf20Sopenharmony_ci		ret = connector_status_disconnected;
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	if (radeon_connector->ddc_bus)
10458c2ecf20Sopenharmony_ci		dret = radeon_ddc_probe(radeon_connector, false);
10468c2ecf20Sopenharmony_ci	if (dret) {
10478c2ecf20Sopenharmony_ci		radeon_connector->detected_by_load = false;
10488c2ecf20Sopenharmony_ci		radeon_connector_free_edid(connector);
10498c2ecf20Sopenharmony_ci		radeon_connector_get_edid(connector);
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci		if (!radeon_connector->edid) {
10528c2ecf20Sopenharmony_ci			DRM_ERROR("%s: probed a monitor but no|invalid EDID\n",
10538c2ecf20Sopenharmony_ci					connector->name);
10548c2ecf20Sopenharmony_ci			ret = connector_status_connected;
10558c2ecf20Sopenharmony_ci		} else {
10568c2ecf20Sopenharmony_ci			radeon_connector->use_digital =
10578c2ecf20Sopenharmony_ci				!!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci			/* some oems have boards with separate digital and analog connectors
10608c2ecf20Sopenharmony_ci			 * with a shared ddc line (often vga + hdmi)
10618c2ecf20Sopenharmony_ci			 */
10628c2ecf20Sopenharmony_ci			if (radeon_connector->use_digital && radeon_connector->shared_ddc) {
10638c2ecf20Sopenharmony_ci				radeon_connector_free_edid(connector);
10648c2ecf20Sopenharmony_ci				ret = connector_status_disconnected;
10658c2ecf20Sopenharmony_ci			} else {
10668c2ecf20Sopenharmony_ci				ret = connector_status_connected;
10678c2ecf20Sopenharmony_ci			}
10688c2ecf20Sopenharmony_ci		}
10698c2ecf20Sopenharmony_ci	} else {
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci		/* if we aren't forcing don't do destructive polling */
10728c2ecf20Sopenharmony_ci		if (!force) {
10738c2ecf20Sopenharmony_ci			/* only return the previous status if we last
10748c2ecf20Sopenharmony_ci			 * detected a monitor via load.
10758c2ecf20Sopenharmony_ci			 */
10768c2ecf20Sopenharmony_ci			if (radeon_connector->detected_by_load)
10778c2ecf20Sopenharmony_ci				ret = connector->status;
10788c2ecf20Sopenharmony_ci			goto out;
10798c2ecf20Sopenharmony_ci		}
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci		if (radeon_connector->dac_load_detect && encoder) {
10828c2ecf20Sopenharmony_ci			encoder_funcs = encoder->helper_private;
10838c2ecf20Sopenharmony_ci			ret = encoder_funcs->detect(encoder, connector);
10848c2ecf20Sopenharmony_ci			if (ret != connector_status_disconnected)
10858c2ecf20Sopenharmony_ci				radeon_connector->detected_by_load = true;
10868c2ecf20Sopenharmony_ci		}
10878c2ecf20Sopenharmony_ci	}
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	if (ret == connector_status_connected)
10908c2ecf20Sopenharmony_ci		ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true);
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	/* RN50 and some RV100 asics in servers often have a hardcoded EDID in the
10938c2ecf20Sopenharmony_ci	 * vbios to deal with KVMs. If we have one and are not able to detect a monitor
10948c2ecf20Sopenharmony_ci	 * by other means, assume the CRT is connected and use that EDID.
10958c2ecf20Sopenharmony_ci	 */
10968c2ecf20Sopenharmony_ci	if ((!rdev->is_atom_bios) &&
10978c2ecf20Sopenharmony_ci	    (ret == connector_status_disconnected) &&
10988c2ecf20Sopenharmony_ci	    rdev->mode_info.bios_hardcoded_edid_size) {
10998c2ecf20Sopenharmony_ci		ret = connector_status_connected;
11008c2ecf20Sopenharmony_ci	}
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	radeon_connector_update_scratch_regs(connector, ret);
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ciout:
11058c2ecf20Sopenharmony_ci	if (!drm_kms_helper_is_poll_worker()) {
11068c2ecf20Sopenharmony_ci		pm_runtime_mark_last_busy(connector->dev->dev);
11078c2ecf20Sopenharmony_ci		pm_runtime_put_autosuspend(connector->dev->dev);
11088c2ecf20Sopenharmony_ci	}
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	return ret;
11118c2ecf20Sopenharmony_ci}
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_cistatic const struct drm_connector_helper_funcs radeon_vga_connector_helper_funcs = {
11148c2ecf20Sopenharmony_ci	.get_modes = radeon_vga_get_modes,
11158c2ecf20Sopenharmony_ci	.mode_valid = radeon_vga_mode_valid,
11168c2ecf20Sopenharmony_ci	.best_encoder = radeon_best_single_encoder,
11178c2ecf20Sopenharmony_ci};
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs radeon_vga_connector_funcs = {
11208c2ecf20Sopenharmony_ci	.dpms = drm_helper_connector_dpms,
11218c2ecf20Sopenharmony_ci	.detect = radeon_vga_detect,
11228c2ecf20Sopenharmony_ci	.fill_modes = drm_helper_probe_single_connector_modes,
11238c2ecf20Sopenharmony_ci	.early_unregister = radeon_connector_unregister,
11248c2ecf20Sopenharmony_ci	.destroy = radeon_connector_destroy,
11258c2ecf20Sopenharmony_ci	.set_property = radeon_connector_set_property,
11268c2ecf20Sopenharmony_ci};
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_cistatic int radeon_tv_get_modes(struct drm_connector *connector)
11298c2ecf20Sopenharmony_ci{
11308c2ecf20Sopenharmony_ci	struct drm_device *dev = connector->dev;
11318c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
11328c2ecf20Sopenharmony_ci	struct drm_display_mode *tv_mode;
11338c2ecf20Sopenharmony_ci	struct drm_encoder *encoder;
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	encoder = radeon_best_single_encoder(connector);
11368c2ecf20Sopenharmony_ci	if (!encoder)
11378c2ecf20Sopenharmony_ci		return 0;
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	/* avivo chips can scale any mode */
11408c2ecf20Sopenharmony_ci	if (rdev->family >= CHIP_RS600)
11418c2ecf20Sopenharmony_ci		/* add scaled modes */
11428c2ecf20Sopenharmony_ci		radeon_add_common_modes(encoder, connector);
11438c2ecf20Sopenharmony_ci	else {
11448c2ecf20Sopenharmony_ci		/* only 800x600 is supported right now on pre-avivo chips */
11458c2ecf20Sopenharmony_ci		tv_mode = drm_cvt_mode(dev, 800, 600, 60, false, false, false);
11468c2ecf20Sopenharmony_ci		tv_mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
11478c2ecf20Sopenharmony_ci		drm_mode_probed_add(connector, tv_mode);
11488c2ecf20Sopenharmony_ci	}
11498c2ecf20Sopenharmony_ci	return 1;
11508c2ecf20Sopenharmony_ci}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_cistatic enum drm_mode_status radeon_tv_mode_valid(struct drm_connector *connector,
11538c2ecf20Sopenharmony_ci				struct drm_display_mode *mode)
11548c2ecf20Sopenharmony_ci{
11558c2ecf20Sopenharmony_ci	if ((mode->hdisplay > 1024) || (mode->vdisplay > 768))
11568c2ecf20Sopenharmony_ci		return MODE_CLOCK_RANGE;
11578c2ecf20Sopenharmony_ci	return MODE_OK;
11588c2ecf20Sopenharmony_ci}
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_cistatic enum drm_connector_status
11618c2ecf20Sopenharmony_ciradeon_tv_detect(struct drm_connector *connector, bool force)
11628c2ecf20Sopenharmony_ci{
11638c2ecf20Sopenharmony_ci	struct drm_encoder *encoder;
11648c2ecf20Sopenharmony_ci	const struct drm_encoder_helper_funcs *encoder_funcs;
11658c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
11668c2ecf20Sopenharmony_ci	enum drm_connector_status ret = connector_status_disconnected;
11678c2ecf20Sopenharmony_ci	int r;
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	if (!radeon_connector->dac_load_detect)
11708c2ecf20Sopenharmony_ci		return ret;
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci	if (!drm_kms_helper_is_poll_worker()) {
11738c2ecf20Sopenharmony_ci		r = pm_runtime_get_sync(connector->dev->dev);
11748c2ecf20Sopenharmony_ci		if (r < 0) {
11758c2ecf20Sopenharmony_ci			pm_runtime_put_autosuspend(connector->dev->dev);
11768c2ecf20Sopenharmony_ci			return connector_status_disconnected;
11778c2ecf20Sopenharmony_ci		}
11788c2ecf20Sopenharmony_ci	}
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	encoder = radeon_best_single_encoder(connector);
11818c2ecf20Sopenharmony_ci	if (!encoder)
11828c2ecf20Sopenharmony_ci		ret = connector_status_disconnected;
11838c2ecf20Sopenharmony_ci	else {
11848c2ecf20Sopenharmony_ci		encoder_funcs = encoder->helper_private;
11858c2ecf20Sopenharmony_ci		ret = encoder_funcs->detect(encoder, connector);
11868c2ecf20Sopenharmony_ci	}
11878c2ecf20Sopenharmony_ci	if (ret == connector_status_connected)
11888c2ecf20Sopenharmony_ci		ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false);
11898c2ecf20Sopenharmony_ci	radeon_connector_update_scratch_regs(connector, ret);
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	if (!drm_kms_helper_is_poll_worker()) {
11928c2ecf20Sopenharmony_ci		pm_runtime_mark_last_busy(connector->dev->dev);
11938c2ecf20Sopenharmony_ci		pm_runtime_put_autosuspend(connector->dev->dev);
11948c2ecf20Sopenharmony_ci	}
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	return ret;
11978c2ecf20Sopenharmony_ci}
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_cistatic const struct drm_connector_helper_funcs radeon_tv_connector_helper_funcs = {
12008c2ecf20Sopenharmony_ci	.get_modes = radeon_tv_get_modes,
12018c2ecf20Sopenharmony_ci	.mode_valid = radeon_tv_mode_valid,
12028c2ecf20Sopenharmony_ci	.best_encoder = radeon_best_single_encoder,
12038c2ecf20Sopenharmony_ci};
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs radeon_tv_connector_funcs = {
12068c2ecf20Sopenharmony_ci	.dpms = drm_helper_connector_dpms,
12078c2ecf20Sopenharmony_ci	.detect = radeon_tv_detect,
12088c2ecf20Sopenharmony_ci	.fill_modes = drm_helper_probe_single_connector_modes,
12098c2ecf20Sopenharmony_ci	.early_unregister = radeon_connector_unregister,
12108c2ecf20Sopenharmony_ci	.destroy = radeon_connector_destroy,
12118c2ecf20Sopenharmony_ci	.set_property = radeon_connector_set_property,
12128c2ecf20Sopenharmony_ci};
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_cistatic bool radeon_check_hpd_status_unchanged(struct drm_connector *connector)
12158c2ecf20Sopenharmony_ci{
12168c2ecf20Sopenharmony_ci	struct drm_device *dev = connector->dev;
12178c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
12188c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
12198c2ecf20Sopenharmony_ci	enum drm_connector_status status;
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	/* We only trust HPD on R600 and newer ASICS. */
12228c2ecf20Sopenharmony_ci	if (rdev->family >= CHIP_R600
12238c2ecf20Sopenharmony_ci	  && radeon_connector->hpd.hpd != RADEON_HPD_NONE) {
12248c2ecf20Sopenharmony_ci		if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
12258c2ecf20Sopenharmony_ci			status = connector_status_connected;
12268c2ecf20Sopenharmony_ci		else
12278c2ecf20Sopenharmony_ci			status = connector_status_disconnected;
12288c2ecf20Sopenharmony_ci		if (connector->status == status)
12298c2ecf20Sopenharmony_ci			return true;
12308c2ecf20Sopenharmony_ci	}
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci	return false;
12338c2ecf20Sopenharmony_ci}
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci/*
12368c2ecf20Sopenharmony_ci * DVI is complicated
12378c2ecf20Sopenharmony_ci * Do a DDC probe, if DDC probe passes, get the full EDID so
12388c2ecf20Sopenharmony_ci * we can do analog/digital monitor detection at this point.
12398c2ecf20Sopenharmony_ci * If the monitor is an analog monitor or we got no DDC,
12408c2ecf20Sopenharmony_ci * we need to find the DAC encoder object for this connector.
12418c2ecf20Sopenharmony_ci * If we got no DDC, we do load detection on the DAC encoder object.
12428c2ecf20Sopenharmony_ci * If we got analog DDC or load detection passes on the DAC encoder
12438c2ecf20Sopenharmony_ci * we have to check if this analog encoder is shared with anyone else (TV)
12448c2ecf20Sopenharmony_ci * if its shared we have to set the other connector to disconnected.
12458c2ecf20Sopenharmony_ci */
12468c2ecf20Sopenharmony_cistatic enum drm_connector_status
12478c2ecf20Sopenharmony_ciradeon_dvi_detect(struct drm_connector *connector, bool force)
12488c2ecf20Sopenharmony_ci{
12498c2ecf20Sopenharmony_ci	struct drm_device *dev = connector->dev;
12508c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
12518c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
12528c2ecf20Sopenharmony_ci	struct drm_encoder *encoder = NULL;
12538c2ecf20Sopenharmony_ci	const struct drm_encoder_helper_funcs *encoder_funcs;
12548c2ecf20Sopenharmony_ci	int r;
12558c2ecf20Sopenharmony_ci	enum drm_connector_status ret = connector_status_disconnected;
12568c2ecf20Sopenharmony_ci	bool dret = false, broken_edid = false;
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	if (!drm_kms_helper_is_poll_worker()) {
12598c2ecf20Sopenharmony_ci		r = pm_runtime_get_sync(connector->dev->dev);
12608c2ecf20Sopenharmony_ci		if (r < 0) {
12618c2ecf20Sopenharmony_ci			pm_runtime_put_autosuspend(connector->dev->dev);
12628c2ecf20Sopenharmony_ci			return connector_status_disconnected;
12638c2ecf20Sopenharmony_ci		}
12648c2ecf20Sopenharmony_ci	}
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	if (radeon_connector->detected_hpd_without_ddc) {
12678c2ecf20Sopenharmony_ci		force = true;
12688c2ecf20Sopenharmony_ci		radeon_connector->detected_hpd_without_ddc = false;
12698c2ecf20Sopenharmony_ci	}
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	if (!force && radeon_check_hpd_status_unchanged(connector)) {
12728c2ecf20Sopenharmony_ci		ret = connector->status;
12738c2ecf20Sopenharmony_ci		goto exit;
12748c2ecf20Sopenharmony_ci	}
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	if (radeon_connector->ddc_bus) {
12778c2ecf20Sopenharmony_ci		dret = radeon_ddc_probe(radeon_connector, false);
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci		/* Sometimes the pins required for the DDC probe on DVI
12808c2ecf20Sopenharmony_ci		 * connectors don't make contact at the same time that the ones
12818c2ecf20Sopenharmony_ci		 * for HPD do. If the DDC probe fails even though we had an HPD
12828c2ecf20Sopenharmony_ci		 * signal, try again later */
12838c2ecf20Sopenharmony_ci		if (!dret && !force &&
12848c2ecf20Sopenharmony_ci		    connector->status != connector_status_connected) {
12858c2ecf20Sopenharmony_ci			DRM_DEBUG_KMS("hpd detected without ddc, retrying in 1 second\n");
12868c2ecf20Sopenharmony_ci			radeon_connector->detected_hpd_without_ddc = true;
12878c2ecf20Sopenharmony_ci			schedule_delayed_work(&rdev->hotplug_work,
12888c2ecf20Sopenharmony_ci					      msecs_to_jiffies(1000));
12898c2ecf20Sopenharmony_ci			goto exit;
12908c2ecf20Sopenharmony_ci		}
12918c2ecf20Sopenharmony_ci	}
12928c2ecf20Sopenharmony_ci	if (dret) {
12938c2ecf20Sopenharmony_ci		radeon_connector->detected_by_load = false;
12948c2ecf20Sopenharmony_ci		radeon_connector_free_edid(connector);
12958c2ecf20Sopenharmony_ci		radeon_connector_get_edid(connector);
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci		if (!radeon_connector->edid) {
12988c2ecf20Sopenharmony_ci			DRM_ERROR("%s: probed a monitor but no|invalid EDID\n",
12998c2ecf20Sopenharmony_ci					connector->name);
13008c2ecf20Sopenharmony_ci			/* rs690 seems to have a problem with connectors not existing and always
13018c2ecf20Sopenharmony_ci			 * return a block of 0's. If we see this just stop polling on this output */
13028c2ecf20Sopenharmony_ci			if ((rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) &&
13038c2ecf20Sopenharmony_ci			    radeon_connector->base.null_edid_counter) {
13048c2ecf20Sopenharmony_ci				ret = connector_status_disconnected;
13058c2ecf20Sopenharmony_ci				DRM_ERROR("%s: detected RS690 floating bus bug, stopping ddc detect\n",
13068c2ecf20Sopenharmony_ci					  connector->name);
13078c2ecf20Sopenharmony_ci				radeon_connector->ddc_bus = NULL;
13088c2ecf20Sopenharmony_ci			} else {
13098c2ecf20Sopenharmony_ci				ret = connector_status_connected;
13108c2ecf20Sopenharmony_ci				broken_edid = true; /* defer use_digital to later */
13118c2ecf20Sopenharmony_ci			}
13128c2ecf20Sopenharmony_ci		} else {
13138c2ecf20Sopenharmony_ci			radeon_connector->use_digital =
13148c2ecf20Sopenharmony_ci				!!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci			/* some oems have boards with separate digital and analog connectors
13178c2ecf20Sopenharmony_ci			 * with a shared ddc line (often vga + hdmi)
13188c2ecf20Sopenharmony_ci			 */
13198c2ecf20Sopenharmony_ci			if ((!radeon_connector->use_digital) && radeon_connector->shared_ddc) {
13208c2ecf20Sopenharmony_ci				radeon_connector_free_edid(connector);
13218c2ecf20Sopenharmony_ci				ret = connector_status_disconnected;
13228c2ecf20Sopenharmony_ci			} else {
13238c2ecf20Sopenharmony_ci				ret = connector_status_connected;
13248c2ecf20Sopenharmony_ci			}
13258c2ecf20Sopenharmony_ci			/* This gets complicated.  We have boards with VGA + HDMI with a
13268c2ecf20Sopenharmony_ci			 * shared DDC line and we have boards with DVI-D + HDMI with a shared
13278c2ecf20Sopenharmony_ci			 * DDC line.  The latter is more complex because with DVI<->HDMI adapters
13288c2ecf20Sopenharmony_ci			 * you don't really know what's connected to which port as both are digital.
13298c2ecf20Sopenharmony_ci			 */
13308c2ecf20Sopenharmony_ci			if (radeon_connector->shared_ddc && (ret == connector_status_connected)) {
13318c2ecf20Sopenharmony_ci				struct drm_connector *list_connector;
13328c2ecf20Sopenharmony_ci				struct radeon_connector *list_radeon_connector;
13338c2ecf20Sopenharmony_ci				list_for_each_entry(list_connector, &dev->mode_config.connector_list, head) {
13348c2ecf20Sopenharmony_ci					if (connector == list_connector)
13358c2ecf20Sopenharmony_ci						continue;
13368c2ecf20Sopenharmony_ci					list_radeon_connector = to_radeon_connector(list_connector);
13378c2ecf20Sopenharmony_ci					if (list_radeon_connector->shared_ddc &&
13388c2ecf20Sopenharmony_ci					    (list_radeon_connector->ddc_bus->rec.i2c_id ==
13398c2ecf20Sopenharmony_ci					     radeon_connector->ddc_bus->rec.i2c_id)) {
13408c2ecf20Sopenharmony_ci						/* cases where both connectors are digital */
13418c2ecf20Sopenharmony_ci						if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) {
13428c2ecf20Sopenharmony_ci							/* hpd is our only option in this case */
13438c2ecf20Sopenharmony_ci							if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
13448c2ecf20Sopenharmony_ci								radeon_connector_free_edid(connector);
13458c2ecf20Sopenharmony_ci								ret = connector_status_disconnected;
13468c2ecf20Sopenharmony_ci							}
13478c2ecf20Sopenharmony_ci						}
13488c2ecf20Sopenharmony_ci					}
13498c2ecf20Sopenharmony_ci				}
13508c2ecf20Sopenharmony_ci			}
13518c2ecf20Sopenharmony_ci		}
13528c2ecf20Sopenharmony_ci	}
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	if ((ret == connector_status_connected) && (radeon_connector->use_digital == true))
13558c2ecf20Sopenharmony_ci		goto out;
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci	/* DVI-D and HDMI-A are digital only */
13588c2ecf20Sopenharmony_ci	if ((connector->connector_type == DRM_MODE_CONNECTOR_DVID) ||
13598c2ecf20Sopenharmony_ci	    (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA))
13608c2ecf20Sopenharmony_ci		goto out;
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci	/* if we aren't forcing don't do destructive polling */
13638c2ecf20Sopenharmony_ci	if (!force) {
13648c2ecf20Sopenharmony_ci		/* only return the previous status if we last
13658c2ecf20Sopenharmony_ci		 * detected a monitor via load.
13668c2ecf20Sopenharmony_ci		 */
13678c2ecf20Sopenharmony_ci		if (radeon_connector->detected_by_load)
13688c2ecf20Sopenharmony_ci			ret = connector->status;
13698c2ecf20Sopenharmony_ci		goto out;
13708c2ecf20Sopenharmony_ci	}
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ci	/* find analog encoder */
13738c2ecf20Sopenharmony_ci	if (radeon_connector->dac_load_detect) {
13748c2ecf20Sopenharmony_ci		drm_connector_for_each_possible_encoder(connector, encoder) {
13758c2ecf20Sopenharmony_ci			if (encoder->encoder_type != DRM_MODE_ENCODER_DAC &&
13768c2ecf20Sopenharmony_ci			    encoder->encoder_type != DRM_MODE_ENCODER_TVDAC)
13778c2ecf20Sopenharmony_ci				continue;
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci			encoder_funcs = encoder->helper_private;
13808c2ecf20Sopenharmony_ci			if (encoder_funcs->detect) {
13818c2ecf20Sopenharmony_ci				if (!broken_edid) {
13828c2ecf20Sopenharmony_ci					if (ret != connector_status_connected) {
13838c2ecf20Sopenharmony_ci						/* deal with analog monitors without DDC */
13848c2ecf20Sopenharmony_ci						ret = encoder_funcs->detect(encoder, connector);
13858c2ecf20Sopenharmony_ci						if (ret == connector_status_connected) {
13868c2ecf20Sopenharmony_ci							radeon_connector->use_digital = false;
13878c2ecf20Sopenharmony_ci						}
13888c2ecf20Sopenharmony_ci						if (ret != connector_status_disconnected)
13898c2ecf20Sopenharmony_ci							radeon_connector->detected_by_load = true;
13908c2ecf20Sopenharmony_ci					}
13918c2ecf20Sopenharmony_ci				} else {
13928c2ecf20Sopenharmony_ci					enum drm_connector_status lret;
13938c2ecf20Sopenharmony_ci					/* assume digital unless load detected otherwise */
13948c2ecf20Sopenharmony_ci					radeon_connector->use_digital = true;
13958c2ecf20Sopenharmony_ci					lret = encoder_funcs->detect(encoder, connector);
13968c2ecf20Sopenharmony_ci					DRM_DEBUG_KMS("load_detect %x returned: %x\n",encoder->encoder_type,lret);
13978c2ecf20Sopenharmony_ci					if (lret == connector_status_connected)
13988c2ecf20Sopenharmony_ci						radeon_connector->use_digital = false;
13998c2ecf20Sopenharmony_ci				}
14008c2ecf20Sopenharmony_ci				break;
14018c2ecf20Sopenharmony_ci			}
14028c2ecf20Sopenharmony_ci		}
14038c2ecf20Sopenharmony_ci	}
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	if ((ret == connector_status_connected) && (radeon_connector->use_digital == false) &&
14068c2ecf20Sopenharmony_ci	    encoder) {
14078c2ecf20Sopenharmony_ci		ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true);
14088c2ecf20Sopenharmony_ci	}
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	/* RN50 and some RV100 asics in servers often have a hardcoded EDID in the
14118c2ecf20Sopenharmony_ci	 * vbios to deal with KVMs. If we have one and are not able to detect a monitor
14128c2ecf20Sopenharmony_ci	 * by other means, assume the DFP is connected and use that EDID.  In most
14138c2ecf20Sopenharmony_ci	 * cases the DVI port is actually a virtual KVM port connected to the service
14148c2ecf20Sopenharmony_ci	 * processor.
14158c2ecf20Sopenharmony_ci	 */
14168c2ecf20Sopenharmony_ciout:
14178c2ecf20Sopenharmony_ci	if ((!rdev->is_atom_bios) &&
14188c2ecf20Sopenharmony_ci	    (ret == connector_status_disconnected) &&
14198c2ecf20Sopenharmony_ci	    rdev->mode_info.bios_hardcoded_edid_size) {
14208c2ecf20Sopenharmony_ci		radeon_connector->use_digital = true;
14218c2ecf20Sopenharmony_ci		ret = connector_status_connected;
14228c2ecf20Sopenharmony_ci	}
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci	/* updated in get modes as well since we need to know if it's analog or digital */
14258c2ecf20Sopenharmony_ci	radeon_connector_update_scratch_regs(connector, ret);
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci	if ((radeon_audio != 0) && radeon_connector->use_digital) {
14288c2ecf20Sopenharmony_ci		const struct drm_connector_helper_funcs *connector_funcs =
14298c2ecf20Sopenharmony_ci			connector->helper_private;
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci		encoder = connector_funcs->best_encoder(connector);
14328c2ecf20Sopenharmony_ci		if (encoder && (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)) {
14338c2ecf20Sopenharmony_ci			radeon_connector_get_edid(connector);
14348c2ecf20Sopenharmony_ci			radeon_audio_detect(connector, encoder, ret);
14358c2ecf20Sopenharmony_ci		}
14368c2ecf20Sopenharmony_ci	}
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ciexit:
14398c2ecf20Sopenharmony_ci	if (!drm_kms_helper_is_poll_worker()) {
14408c2ecf20Sopenharmony_ci		pm_runtime_mark_last_busy(connector->dev->dev);
14418c2ecf20Sopenharmony_ci		pm_runtime_put_autosuspend(connector->dev->dev);
14428c2ecf20Sopenharmony_ci	}
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	return ret;
14458c2ecf20Sopenharmony_ci}
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci/* okay need to be smart in here about which encoder to pick */
14488c2ecf20Sopenharmony_cistatic struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector)
14498c2ecf20Sopenharmony_ci{
14508c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
14518c2ecf20Sopenharmony_ci	struct drm_encoder *encoder;
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	drm_connector_for_each_possible_encoder(connector, encoder) {
14548c2ecf20Sopenharmony_ci		if (radeon_connector->use_digital == true) {
14558c2ecf20Sopenharmony_ci			if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
14568c2ecf20Sopenharmony_ci				return encoder;
14578c2ecf20Sopenharmony_ci		} else {
14588c2ecf20Sopenharmony_ci			if (encoder->encoder_type == DRM_MODE_ENCODER_DAC ||
14598c2ecf20Sopenharmony_ci			    encoder->encoder_type == DRM_MODE_ENCODER_TVDAC)
14608c2ecf20Sopenharmony_ci				return encoder;
14618c2ecf20Sopenharmony_ci		}
14628c2ecf20Sopenharmony_ci	}
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_ci	/* see if we have a default encoder  TODO */
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_ci	/* then check use digitial */
14678c2ecf20Sopenharmony_ci	/* pick the first one */
14688c2ecf20Sopenharmony_ci	drm_connector_for_each_possible_encoder(connector, encoder)
14698c2ecf20Sopenharmony_ci		return encoder;
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci	return NULL;
14728c2ecf20Sopenharmony_ci}
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_cistatic void radeon_dvi_force(struct drm_connector *connector)
14758c2ecf20Sopenharmony_ci{
14768c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
14778c2ecf20Sopenharmony_ci	if (connector->force == DRM_FORCE_ON)
14788c2ecf20Sopenharmony_ci		radeon_connector->use_digital = false;
14798c2ecf20Sopenharmony_ci	if (connector->force == DRM_FORCE_ON_DIGITAL)
14808c2ecf20Sopenharmony_ci		radeon_connector->use_digital = true;
14818c2ecf20Sopenharmony_ci}
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_cistatic enum drm_mode_status radeon_dvi_mode_valid(struct drm_connector *connector,
14848c2ecf20Sopenharmony_ci				  struct drm_display_mode *mode)
14858c2ecf20Sopenharmony_ci{
14868c2ecf20Sopenharmony_ci	struct drm_device *dev = connector->dev;
14878c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
14888c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	/* XXX check mode bandwidth */
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	/* clocks over 135 MHz have heat issues with DVI on RV100 */
14938c2ecf20Sopenharmony_ci	if (radeon_connector->use_digital &&
14948c2ecf20Sopenharmony_ci	    (rdev->family == CHIP_RV100) &&
14958c2ecf20Sopenharmony_ci	    (mode->clock > 135000))
14968c2ecf20Sopenharmony_ci		return MODE_CLOCK_HIGH;
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	if (radeon_connector->use_digital && (mode->clock > 165000)) {
14998c2ecf20Sopenharmony_ci		if ((radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I) ||
15008c2ecf20Sopenharmony_ci		    (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D) ||
15018c2ecf20Sopenharmony_ci		    (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_B))
15028c2ecf20Sopenharmony_ci			return MODE_OK;
15038c2ecf20Sopenharmony_ci		else if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
15048c2ecf20Sopenharmony_ci			/* HDMI 1.3+ supports max clock of 340 Mhz */
15058c2ecf20Sopenharmony_ci			if (mode->clock > 340000)
15068c2ecf20Sopenharmony_ci				return MODE_CLOCK_HIGH;
15078c2ecf20Sopenharmony_ci			else
15088c2ecf20Sopenharmony_ci				return MODE_OK;
15098c2ecf20Sopenharmony_ci		} else {
15108c2ecf20Sopenharmony_ci			return MODE_CLOCK_HIGH;
15118c2ecf20Sopenharmony_ci		}
15128c2ecf20Sopenharmony_ci	}
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci	/* check against the max pixel clock */
15158c2ecf20Sopenharmony_ci	if ((mode->clock / 10) > rdev->clock.max_pixel_clock)
15168c2ecf20Sopenharmony_ci		return MODE_CLOCK_HIGH;
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	return MODE_OK;
15198c2ecf20Sopenharmony_ci}
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_cistatic const struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = {
15228c2ecf20Sopenharmony_ci	.get_modes = radeon_vga_get_modes,
15238c2ecf20Sopenharmony_ci	.mode_valid = radeon_dvi_mode_valid,
15248c2ecf20Sopenharmony_ci	.best_encoder = radeon_dvi_encoder,
15258c2ecf20Sopenharmony_ci};
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs radeon_dvi_connector_funcs = {
15288c2ecf20Sopenharmony_ci	.dpms = drm_helper_connector_dpms,
15298c2ecf20Sopenharmony_ci	.detect = radeon_dvi_detect,
15308c2ecf20Sopenharmony_ci	.fill_modes = drm_helper_probe_single_connector_modes,
15318c2ecf20Sopenharmony_ci	.set_property = radeon_connector_set_property,
15328c2ecf20Sopenharmony_ci	.early_unregister = radeon_connector_unregister,
15338c2ecf20Sopenharmony_ci	.destroy = radeon_connector_destroy,
15348c2ecf20Sopenharmony_ci	.force = radeon_dvi_force,
15358c2ecf20Sopenharmony_ci};
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_cistatic int radeon_dp_get_modes(struct drm_connector *connector)
15388c2ecf20Sopenharmony_ci{
15398c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
15408c2ecf20Sopenharmony_ci	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
15418c2ecf20Sopenharmony_ci	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
15428c2ecf20Sopenharmony_ci	int ret;
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
15458c2ecf20Sopenharmony_ci	    (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
15468c2ecf20Sopenharmony_ci		struct drm_display_mode *mode;
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
15498c2ecf20Sopenharmony_ci			if (!radeon_dig_connector->edp_on)
15508c2ecf20Sopenharmony_ci				atombios_set_edp_panel_power(connector,
15518c2ecf20Sopenharmony_ci							     ATOM_TRANSMITTER_ACTION_POWER_ON);
15528c2ecf20Sopenharmony_ci			radeon_connector_get_edid(connector);
15538c2ecf20Sopenharmony_ci			ret = radeon_ddc_get_modes(connector);
15548c2ecf20Sopenharmony_ci			if (!radeon_dig_connector->edp_on)
15558c2ecf20Sopenharmony_ci				atombios_set_edp_panel_power(connector,
15568c2ecf20Sopenharmony_ci							     ATOM_TRANSMITTER_ACTION_POWER_OFF);
15578c2ecf20Sopenharmony_ci		} else {
15588c2ecf20Sopenharmony_ci			/* need to setup ddc on the bridge */
15598c2ecf20Sopenharmony_ci			if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
15608c2ecf20Sopenharmony_ci			    ENCODER_OBJECT_ID_NONE) {
15618c2ecf20Sopenharmony_ci				if (encoder)
15628c2ecf20Sopenharmony_ci					radeon_atom_ext_encoder_setup_ddc(encoder);
15638c2ecf20Sopenharmony_ci			}
15648c2ecf20Sopenharmony_ci			radeon_connector_get_edid(connector);
15658c2ecf20Sopenharmony_ci			ret = radeon_ddc_get_modes(connector);
15668c2ecf20Sopenharmony_ci		}
15678c2ecf20Sopenharmony_ci
15688c2ecf20Sopenharmony_ci		if (ret > 0) {
15698c2ecf20Sopenharmony_ci			if (encoder) {
15708c2ecf20Sopenharmony_ci				radeon_fixup_lvds_native_mode(encoder, connector);
15718c2ecf20Sopenharmony_ci				/* add scaled modes */
15728c2ecf20Sopenharmony_ci				radeon_add_common_modes(encoder, connector);
15738c2ecf20Sopenharmony_ci			}
15748c2ecf20Sopenharmony_ci			return ret;
15758c2ecf20Sopenharmony_ci		}
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_ci		if (!encoder)
15788c2ecf20Sopenharmony_ci			return 0;
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci		/* we have no EDID modes */
15818c2ecf20Sopenharmony_ci		mode = radeon_fp_native_mode(encoder);
15828c2ecf20Sopenharmony_ci		if (mode) {
15838c2ecf20Sopenharmony_ci			ret = 1;
15848c2ecf20Sopenharmony_ci			drm_mode_probed_add(connector, mode);
15858c2ecf20Sopenharmony_ci			/* add the width/height from vbios tables if available */
15868c2ecf20Sopenharmony_ci			connector->display_info.width_mm = mode->width_mm;
15878c2ecf20Sopenharmony_ci			connector->display_info.height_mm = mode->height_mm;
15888c2ecf20Sopenharmony_ci			/* add scaled modes */
15898c2ecf20Sopenharmony_ci			radeon_add_common_modes(encoder, connector);
15908c2ecf20Sopenharmony_ci		}
15918c2ecf20Sopenharmony_ci	} else {
15928c2ecf20Sopenharmony_ci		/* need to setup ddc on the bridge */
15938c2ecf20Sopenharmony_ci		if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
15948c2ecf20Sopenharmony_ci			ENCODER_OBJECT_ID_NONE) {
15958c2ecf20Sopenharmony_ci			if (encoder)
15968c2ecf20Sopenharmony_ci				radeon_atom_ext_encoder_setup_ddc(encoder);
15978c2ecf20Sopenharmony_ci		}
15988c2ecf20Sopenharmony_ci		radeon_connector_get_edid(connector);
15998c2ecf20Sopenharmony_ci		ret = radeon_ddc_get_modes(connector);
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci		radeon_get_native_mode(connector);
16028c2ecf20Sopenharmony_ci	}
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci	return ret;
16058c2ecf20Sopenharmony_ci}
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ciu16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector)
16088c2ecf20Sopenharmony_ci{
16098c2ecf20Sopenharmony_ci	struct drm_encoder *encoder;
16108c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder;
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	drm_connector_for_each_possible_encoder(connector, encoder) {
16138c2ecf20Sopenharmony_ci		radeon_encoder = to_radeon_encoder(encoder);
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci		switch (radeon_encoder->encoder_id) {
16168c2ecf20Sopenharmony_ci		case ENCODER_OBJECT_ID_TRAVIS:
16178c2ecf20Sopenharmony_ci		case ENCODER_OBJECT_ID_NUTMEG:
16188c2ecf20Sopenharmony_ci			return radeon_encoder->encoder_id;
16198c2ecf20Sopenharmony_ci		default:
16208c2ecf20Sopenharmony_ci			break;
16218c2ecf20Sopenharmony_ci		}
16228c2ecf20Sopenharmony_ci	}
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci	return ENCODER_OBJECT_ID_NONE;
16258c2ecf20Sopenharmony_ci}
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_cistatic bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector)
16288c2ecf20Sopenharmony_ci{
16298c2ecf20Sopenharmony_ci	struct drm_encoder *encoder;
16308c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder;
16318c2ecf20Sopenharmony_ci	bool found = false;
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci	drm_connector_for_each_possible_encoder(connector, encoder) {
16348c2ecf20Sopenharmony_ci		radeon_encoder = to_radeon_encoder(encoder);
16358c2ecf20Sopenharmony_ci		if (radeon_encoder->caps & ATOM_ENCODER_CAP_RECORD_HBR2)
16368c2ecf20Sopenharmony_ci			found = true;
16378c2ecf20Sopenharmony_ci	}
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci	return found;
16408c2ecf20Sopenharmony_ci}
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_cibool radeon_connector_is_dp12_capable(struct drm_connector *connector)
16438c2ecf20Sopenharmony_ci{
16448c2ecf20Sopenharmony_ci	struct drm_device *dev = connector->dev;
16458c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci	if (ASIC_IS_DCE5(rdev) &&
16488c2ecf20Sopenharmony_ci	    (rdev->clock.default_dispclk >= 53900) &&
16498c2ecf20Sopenharmony_ci	    radeon_connector_encoder_is_hbr2(connector)) {
16508c2ecf20Sopenharmony_ci		return true;
16518c2ecf20Sopenharmony_ci	}
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci	return false;
16548c2ecf20Sopenharmony_ci}
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_cistatic enum drm_connector_status
16578c2ecf20Sopenharmony_ciradeon_dp_detect(struct drm_connector *connector, bool force)
16588c2ecf20Sopenharmony_ci{
16598c2ecf20Sopenharmony_ci	struct drm_device *dev = connector->dev;
16608c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
16618c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
16628c2ecf20Sopenharmony_ci	enum drm_connector_status ret = connector_status_disconnected;
16638c2ecf20Sopenharmony_ci	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
16648c2ecf20Sopenharmony_ci	struct drm_encoder *encoder = radeon_best_single_encoder(connector);
16658c2ecf20Sopenharmony_ci	int r;
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci	if (radeon_dig_connector->is_mst)
16688c2ecf20Sopenharmony_ci		return connector_status_disconnected;
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci	if (!drm_kms_helper_is_poll_worker()) {
16718c2ecf20Sopenharmony_ci		r = pm_runtime_get_sync(connector->dev->dev);
16728c2ecf20Sopenharmony_ci		if (r < 0) {
16738c2ecf20Sopenharmony_ci			pm_runtime_put_autosuspend(connector->dev->dev);
16748c2ecf20Sopenharmony_ci			return connector_status_disconnected;
16758c2ecf20Sopenharmony_ci		}
16768c2ecf20Sopenharmony_ci	}
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	if (!force && radeon_check_hpd_status_unchanged(connector)) {
16798c2ecf20Sopenharmony_ci		ret = connector->status;
16808c2ecf20Sopenharmony_ci		goto out;
16818c2ecf20Sopenharmony_ci	}
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci	radeon_connector_free_edid(connector);
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
16868c2ecf20Sopenharmony_ci	    (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
16878c2ecf20Sopenharmony_ci		if (encoder) {
16888c2ecf20Sopenharmony_ci			struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
16898c2ecf20Sopenharmony_ci			struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_ci			/* check if panel is valid */
16928c2ecf20Sopenharmony_ci			if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
16938c2ecf20Sopenharmony_ci				ret = connector_status_connected;
16948c2ecf20Sopenharmony_ci			/* don't fetch the edid from the vbios if ddc fails and runpm is
16958c2ecf20Sopenharmony_ci			 * enabled so we report disconnected.
16968c2ecf20Sopenharmony_ci			 */
16978c2ecf20Sopenharmony_ci			if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0))
16988c2ecf20Sopenharmony_ci				ret = connector_status_disconnected;
16998c2ecf20Sopenharmony_ci		}
17008c2ecf20Sopenharmony_ci		/* eDP is always DP */
17018c2ecf20Sopenharmony_ci		radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
17028c2ecf20Sopenharmony_ci		if (!radeon_dig_connector->edp_on)
17038c2ecf20Sopenharmony_ci			atombios_set_edp_panel_power(connector,
17048c2ecf20Sopenharmony_ci						     ATOM_TRANSMITTER_ACTION_POWER_ON);
17058c2ecf20Sopenharmony_ci		if (radeon_dp_getdpcd(radeon_connector))
17068c2ecf20Sopenharmony_ci			ret = connector_status_connected;
17078c2ecf20Sopenharmony_ci		if (!radeon_dig_connector->edp_on)
17088c2ecf20Sopenharmony_ci			atombios_set_edp_panel_power(connector,
17098c2ecf20Sopenharmony_ci						     ATOM_TRANSMITTER_ACTION_POWER_OFF);
17108c2ecf20Sopenharmony_ci	} else if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
17118c2ecf20Sopenharmony_ci		   ENCODER_OBJECT_ID_NONE) {
17128c2ecf20Sopenharmony_ci		/* DP bridges are always DP */
17138c2ecf20Sopenharmony_ci		radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
17148c2ecf20Sopenharmony_ci		/* get the DPCD from the bridge */
17158c2ecf20Sopenharmony_ci		radeon_dp_getdpcd(radeon_connector);
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci		if (encoder) {
17188c2ecf20Sopenharmony_ci			/* setup ddc on the bridge */
17198c2ecf20Sopenharmony_ci			radeon_atom_ext_encoder_setup_ddc(encoder);
17208c2ecf20Sopenharmony_ci			/* bridge chips are always aux */
17218c2ecf20Sopenharmony_ci			if (radeon_ddc_probe(radeon_connector, true)) /* try DDC */
17228c2ecf20Sopenharmony_ci				ret = connector_status_connected;
17238c2ecf20Sopenharmony_ci			else if (radeon_connector->dac_load_detect) { /* try load detection */
17248c2ecf20Sopenharmony_ci				const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
17258c2ecf20Sopenharmony_ci				ret = encoder_funcs->detect(encoder, connector);
17268c2ecf20Sopenharmony_ci			}
17278c2ecf20Sopenharmony_ci		}
17288c2ecf20Sopenharmony_ci	} else {
17298c2ecf20Sopenharmony_ci		radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
17308c2ecf20Sopenharmony_ci		if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
17318c2ecf20Sopenharmony_ci			ret = connector_status_connected;
17328c2ecf20Sopenharmony_ci			if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
17338c2ecf20Sopenharmony_ci				radeon_dp_getdpcd(radeon_connector);
17348c2ecf20Sopenharmony_ci				r = radeon_dp_mst_probe(radeon_connector);
17358c2ecf20Sopenharmony_ci				if (r == 1)
17368c2ecf20Sopenharmony_ci					ret = connector_status_disconnected;
17378c2ecf20Sopenharmony_ci			}
17388c2ecf20Sopenharmony_ci		} else {
17398c2ecf20Sopenharmony_ci			if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
17408c2ecf20Sopenharmony_ci				if (radeon_dp_getdpcd(radeon_connector)) {
17418c2ecf20Sopenharmony_ci					r = radeon_dp_mst_probe(radeon_connector);
17428c2ecf20Sopenharmony_ci					if (r == 1)
17438c2ecf20Sopenharmony_ci						ret = connector_status_disconnected;
17448c2ecf20Sopenharmony_ci					else
17458c2ecf20Sopenharmony_ci						ret = connector_status_connected;
17468c2ecf20Sopenharmony_ci				}
17478c2ecf20Sopenharmony_ci			} else {
17488c2ecf20Sopenharmony_ci				/* try non-aux ddc (DP to DVI/HDMI/etc. adapter) */
17498c2ecf20Sopenharmony_ci				if (radeon_ddc_probe(radeon_connector, false))
17508c2ecf20Sopenharmony_ci					ret = connector_status_connected;
17518c2ecf20Sopenharmony_ci			}
17528c2ecf20Sopenharmony_ci		}
17538c2ecf20Sopenharmony_ci	}
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci	radeon_connector_update_scratch_regs(connector, ret);
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	if ((radeon_audio != 0) && encoder) {
17588c2ecf20Sopenharmony_ci		radeon_connector_get_edid(connector);
17598c2ecf20Sopenharmony_ci		radeon_audio_detect(connector, encoder, ret);
17608c2ecf20Sopenharmony_ci	}
17618c2ecf20Sopenharmony_ci
17628c2ecf20Sopenharmony_ciout:
17638c2ecf20Sopenharmony_ci	if (!drm_kms_helper_is_poll_worker()) {
17648c2ecf20Sopenharmony_ci		pm_runtime_mark_last_busy(connector->dev->dev);
17658c2ecf20Sopenharmony_ci		pm_runtime_put_autosuspend(connector->dev->dev);
17668c2ecf20Sopenharmony_ci	}
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci	return ret;
17698c2ecf20Sopenharmony_ci}
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_cistatic enum drm_mode_status radeon_dp_mode_valid(struct drm_connector *connector,
17728c2ecf20Sopenharmony_ci				  struct drm_display_mode *mode)
17738c2ecf20Sopenharmony_ci{
17748c2ecf20Sopenharmony_ci	struct drm_device *dev = connector->dev;
17758c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
17768c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
17778c2ecf20Sopenharmony_ci	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_ci	/* XXX check mode bandwidth */
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
17828c2ecf20Sopenharmony_ci	    (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
17838c2ecf20Sopenharmony_ci		struct drm_encoder *encoder = radeon_best_single_encoder(connector);
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ci		if ((mode->hdisplay < 320) || (mode->vdisplay < 240))
17868c2ecf20Sopenharmony_ci			return MODE_PANEL;
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ci		if (encoder) {
17898c2ecf20Sopenharmony_ci			struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
17908c2ecf20Sopenharmony_ci			struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci			/* AVIVO hardware supports downscaling modes larger than the panel
17938c2ecf20Sopenharmony_ci			 * to the panel size, but I'm not sure this is desirable.
17948c2ecf20Sopenharmony_ci			 */
17958c2ecf20Sopenharmony_ci			if ((mode->hdisplay > native_mode->hdisplay) ||
17968c2ecf20Sopenharmony_ci			    (mode->vdisplay > native_mode->vdisplay))
17978c2ecf20Sopenharmony_ci				return MODE_PANEL;
17988c2ecf20Sopenharmony_ci
17998c2ecf20Sopenharmony_ci			/* if scaling is disabled, block non-native modes */
18008c2ecf20Sopenharmony_ci			if (radeon_encoder->rmx_type == RMX_OFF) {
18018c2ecf20Sopenharmony_ci				if ((mode->hdisplay != native_mode->hdisplay) ||
18028c2ecf20Sopenharmony_ci				    (mode->vdisplay != native_mode->vdisplay))
18038c2ecf20Sopenharmony_ci					return MODE_PANEL;
18048c2ecf20Sopenharmony_ci			}
18058c2ecf20Sopenharmony_ci		}
18068c2ecf20Sopenharmony_ci	} else {
18078c2ecf20Sopenharmony_ci		if ((radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
18088c2ecf20Sopenharmony_ci		    (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
18098c2ecf20Sopenharmony_ci			return radeon_dp_mode_valid_helper(connector, mode);
18108c2ecf20Sopenharmony_ci		} else {
18118c2ecf20Sopenharmony_ci			if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) {
18128c2ecf20Sopenharmony_ci				/* HDMI 1.3+ supports max clock of 340 Mhz */
18138c2ecf20Sopenharmony_ci				if (mode->clock > 340000)
18148c2ecf20Sopenharmony_ci					return MODE_CLOCK_HIGH;
18158c2ecf20Sopenharmony_ci			} else {
18168c2ecf20Sopenharmony_ci				if (mode->clock > 165000)
18178c2ecf20Sopenharmony_ci					return MODE_CLOCK_HIGH;
18188c2ecf20Sopenharmony_ci			}
18198c2ecf20Sopenharmony_ci		}
18208c2ecf20Sopenharmony_ci	}
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci	return MODE_OK;
18238c2ecf20Sopenharmony_ci}
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_cistatic const struct drm_connector_helper_funcs radeon_dp_connector_helper_funcs = {
18268c2ecf20Sopenharmony_ci	.get_modes = radeon_dp_get_modes,
18278c2ecf20Sopenharmony_ci	.mode_valid = radeon_dp_mode_valid,
18288c2ecf20Sopenharmony_ci	.best_encoder = radeon_dvi_encoder,
18298c2ecf20Sopenharmony_ci};
18308c2ecf20Sopenharmony_ci
18318c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs radeon_dp_connector_funcs = {
18328c2ecf20Sopenharmony_ci	.dpms = drm_helper_connector_dpms,
18338c2ecf20Sopenharmony_ci	.detect = radeon_dp_detect,
18348c2ecf20Sopenharmony_ci	.fill_modes = drm_helper_probe_single_connector_modes,
18358c2ecf20Sopenharmony_ci	.set_property = radeon_connector_set_property,
18368c2ecf20Sopenharmony_ci	.early_unregister = radeon_connector_unregister,
18378c2ecf20Sopenharmony_ci	.destroy = radeon_connector_destroy,
18388c2ecf20Sopenharmony_ci	.force = radeon_dvi_force,
18398c2ecf20Sopenharmony_ci};
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs radeon_edp_connector_funcs = {
18428c2ecf20Sopenharmony_ci	.dpms = drm_helper_connector_dpms,
18438c2ecf20Sopenharmony_ci	.detect = radeon_dp_detect,
18448c2ecf20Sopenharmony_ci	.fill_modes = drm_helper_probe_single_connector_modes,
18458c2ecf20Sopenharmony_ci	.set_property = radeon_lvds_set_property,
18468c2ecf20Sopenharmony_ci	.early_unregister = radeon_connector_unregister,
18478c2ecf20Sopenharmony_ci	.destroy = radeon_connector_destroy,
18488c2ecf20Sopenharmony_ci	.force = radeon_dvi_force,
18498c2ecf20Sopenharmony_ci};
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs radeon_lvds_bridge_connector_funcs = {
18528c2ecf20Sopenharmony_ci	.dpms = drm_helper_connector_dpms,
18538c2ecf20Sopenharmony_ci	.detect = radeon_dp_detect,
18548c2ecf20Sopenharmony_ci	.fill_modes = drm_helper_probe_single_connector_modes,
18558c2ecf20Sopenharmony_ci	.set_property = radeon_lvds_set_property,
18568c2ecf20Sopenharmony_ci	.early_unregister = radeon_connector_unregister,
18578c2ecf20Sopenharmony_ci	.destroy = radeon_connector_destroy,
18588c2ecf20Sopenharmony_ci	.force = radeon_dvi_force,
18598c2ecf20Sopenharmony_ci};
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_civoid
18628c2ecf20Sopenharmony_ciradeon_add_atom_connector(struct drm_device *dev,
18638c2ecf20Sopenharmony_ci			  uint32_t connector_id,
18648c2ecf20Sopenharmony_ci			  uint32_t supported_device,
18658c2ecf20Sopenharmony_ci			  int connector_type,
18668c2ecf20Sopenharmony_ci			  struct radeon_i2c_bus_rec *i2c_bus,
18678c2ecf20Sopenharmony_ci			  uint32_t igp_lane_info,
18688c2ecf20Sopenharmony_ci			  uint16_t connector_object_id,
18698c2ecf20Sopenharmony_ci			  struct radeon_hpd *hpd,
18708c2ecf20Sopenharmony_ci			  struct radeon_router *router)
18718c2ecf20Sopenharmony_ci{
18728c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
18738c2ecf20Sopenharmony_ci	struct drm_connector *connector;
18748c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector;
18758c2ecf20Sopenharmony_ci	struct radeon_connector_atom_dig *radeon_dig_connector;
18768c2ecf20Sopenharmony_ci	struct drm_encoder *encoder;
18778c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder;
18788c2ecf20Sopenharmony_ci	struct i2c_adapter *ddc = NULL;
18798c2ecf20Sopenharmony_ci	uint32_t subpixel_order = SubPixelNone;
18808c2ecf20Sopenharmony_ci	bool shared_ddc = false;
18818c2ecf20Sopenharmony_ci	bool is_dp_bridge = false;
18828c2ecf20Sopenharmony_ci	bool has_aux = false;
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_ci	if (connector_type == DRM_MODE_CONNECTOR_Unknown)
18858c2ecf20Sopenharmony_ci		return;
18868c2ecf20Sopenharmony_ci
18878c2ecf20Sopenharmony_ci	/* if the user selected tv=0 don't try and add the connector */
18888c2ecf20Sopenharmony_ci	if (((connector_type == DRM_MODE_CONNECTOR_SVIDEO) ||
18898c2ecf20Sopenharmony_ci	     (connector_type == DRM_MODE_CONNECTOR_Composite) ||
18908c2ecf20Sopenharmony_ci	     (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) &&
18918c2ecf20Sopenharmony_ci	    (radeon_tv == 0))
18928c2ecf20Sopenharmony_ci		return;
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci	/* see if we already added it */
18958c2ecf20Sopenharmony_ci	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
18968c2ecf20Sopenharmony_ci		radeon_connector = to_radeon_connector(connector);
18978c2ecf20Sopenharmony_ci		if (radeon_connector->connector_id == connector_id) {
18988c2ecf20Sopenharmony_ci			radeon_connector->devices |= supported_device;
18998c2ecf20Sopenharmony_ci			return;
19008c2ecf20Sopenharmony_ci		}
19018c2ecf20Sopenharmony_ci		if (radeon_connector->ddc_bus && i2c_bus->valid) {
19028c2ecf20Sopenharmony_ci			if (radeon_connector->ddc_bus->rec.i2c_id == i2c_bus->i2c_id) {
19038c2ecf20Sopenharmony_ci				radeon_connector->shared_ddc = true;
19048c2ecf20Sopenharmony_ci				shared_ddc = true;
19058c2ecf20Sopenharmony_ci			}
19068c2ecf20Sopenharmony_ci			if (radeon_connector->router_bus && router->ddc_valid &&
19078c2ecf20Sopenharmony_ci			    (radeon_connector->router.router_id == router->router_id)) {
19088c2ecf20Sopenharmony_ci				radeon_connector->shared_ddc = false;
19098c2ecf20Sopenharmony_ci				shared_ddc = false;
19108c2ecf20Sopenharmony_ci			}
19118c2ecf20Sopenharmony_ci		}
19128c2ecf20Sopenharmony_ci	}
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci	/* check if it's a dp bridge */
19158c2ecf20Sopenharmony_ci	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
19168c2ecf20Sopenharmony_ci		radeon_encoder = to_radeon_encoder(encoder);
19178c2ecf20Sopenharmony_ci		if (radeon_encoder->devices & supported_device) {
19188c2ecf20Sopenharmony_ci			switch (radeon_encoder->encoder_id) {
19198c2ecf20Sopenharmony_ci			case ENCODER_OBJECT_ID_TRAVIS:
19208c2ecf20Sopenharmony_ci			case ENCODER_OBJECT_ID_NUTMEG:
19218c2ecf20Sopenharmony_ci				is_dp_bridge = true;
19228c2ecf20Sopenharmony_ci				break;
19238c2ecf20Sopenharmony_ci			default:
19248c2ecf20Sopenharmony_ci				break;
19258c2ecf20Sopenharmony_ci			}
19268c2ecf20Sopenharmony_ci		}
19278c2ecf20Sopenharmony_ci	}
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_ci	radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL);
19308c2ecf20Sopenharmony_ci	if (!radeon_connector)
19318c2ecf20Sopenharmony_ci		return;
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci	connector = &radeon_connector->base;
19348c2ecf20Sopenharmony_ci
19358c2ecf20Sopenharmony_ci	radeon_connector->connector_id = connector_id;
19368c2ecf20Sopenharmony_ci	radeon_connector->devices = supported_device;
19378c2ecf20Sopenharmony_ci	radeon_connector->shared_ddc = shared_ddc;
19388c2ecf20Sopenharmony_ci	radeon_connector->connector_object_id = connector_object_id;
19398c2ecf20Sopenharmony_ci	radeon_connector->hpd = *hpd;
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_ci	radeon_connector->router = *router;
19428c2ecf20Sopenharmony_ci	if (router->ddc_valid || router->cd_valid) {
19438c2ecf20Sopenharmony_ci		radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info);
19448c2ecf20Sopenharmony_ci		if (!radeon_connector->router_bus)
19458c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to assign router i2c bus! Check dmesg for i2c errors.\n");
19468c2ecf20Sopenharmony_ci	}
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci	if (is_dp_bridge) {
19498c2ecf20Sopenharmony_ci		radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
19508c2ecf20Sopenharmony_ci		if (!radeon_dig_connector)
19518c2ecf20Sopenharmony_ci			goto failed;
19528c2ecf20Sopenharmony_ci		radeon_dig_connector->igp_lane_info = igp_lane_info;
19538c2ecf20Sopenharmony_ci		radeon_connector->con_priv = radeon_dig_connector;
19548c2ecf20Sopenharmony_ci		if (i2c_bus->valid) {
19558c2ecf20Sopenharmony_ci			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
19568c2ecf20Sopenharmony_ci			if (radeon_connector->ddc_bus) {
19578c2ecf20Sopenharmony_ci				has_aux = true;
19588c2ecf20Sopenharmony_ci				ddc = &radeon_connector->ddc_bus->adapter;
19598c2ecf20Sopenharmony_ci			} else {
19608c2ecf20Sopenharmony_ci				DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
19618c2ecf20Sopenharmony_ci			}
19628c2ecf20Sopenharmony_ci		}
19638c2ecf20Sopenharmony_ci		switch (connector_type) {
19648c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_VGA:
19658c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_DVIA:
19668c2ecf20Sopenharmony_ci		default:
19678c2ecf20Sopenharmony_ci			drm_connector_init_with_ddc(dev, &radeon_connector->base,
19688c2ecf20Sopenharmony_ci						    &radeon_dp_connector_funcs,
19698c2ecf20Sopenharmony_ci						    connector_type,
19708c2ecf20Sopenharmony_ci						    ddc);
19718c2ecf20Sopenharmony_ci			drm_connector_helper_add(&radeon_connector->base,
19728c2ecf20Sopenharmony_ci						 &radeon_dp_connector_helper_funcs);
19738c2ecf20Sopenharmony_ci			connector->interlace_allowed = true;
19748c2ecf20Sopenharmony_ci			connector->doublescan_allowed = true;
19758c2ecf20Sopenharmony_ci			radeon_connector->dac_load_detect = true;
19768c2ecf20Sopenharmony_ci			drm_object_attach_property(&radeon_connector->base.base,
19778c2ecf20Sopenharmony_ci						      rdev->mode_info.load_detect_property,
19788c2ecf20Sopenharmony_ci						      1);
19798c2ecf20Sopenharmony_ci			drm_object_attach_property(&radeon_connector->base.base,
19808c2ecf20Sopenharmony_ci						   dev->mode_config.scaling_mode_property,
19818c2ecf20Sopenharmony_ci						   DRM_MODE_SCALE_NONE);
19828c2ecf20Sopenharmony_ci			if (ASIC_IS_DCE5(rdev))
19838c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
19848c2ecf20Sopenharmony_ci							   rdev->mode_info.output_csc_property,
19858c2ecf20Sopenharmony_ci							   RADEON_OUTPUT_CSC_BYPASS);
19868c2ecf20Sopenharmony_ci			break;
19878c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_DVII:
19888c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_DVID:
19898c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_HDMIA:
19908c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_HDMIB:
19918c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_DisplayPort:
19928c2ecf20Sopenharmony_ci			drm_connector_init_with_ddc(dev, &radeon_connector->base,
19938c2ecf20Sopenharmony_ci						    &radeon_dp_connector_funcs,
19948c2ecf20Sopenharmony_ci						    connector_type,
19958c2ecf20Sopenharmony_ci						    ddc);
19968c2ecf20Sopenharmony_ci			drm_connector_helper_add(&radeon_connector->base,
19978c2ecf20Sopenharmony_ci						 &radeon_dp_connector_helper_funcs);
19988c2ecf20Sopenharmony_ci			drm_object_attach_property(&radeon_connector->base.base,
19998c2ecf20Sopenharmony_ci						      rdev->mode_info.underscan_property,
20008c2ecf20Sopenharmony_ci						      UNDERSCAN_OFF);
20018c2ecf20Sopenharmony_ci			drm_object_attach_property(&radeon_connector->base.base,
20028c2ecf20Sopenharmony_ci						      rdev->mode_info.underscan_hborder_property,
20038c2ecf20Sopenharmony_ci						      0);
20048c2ecf20Sopenharmony_ci			drm_object_attach_property(&radeon_connector->base.base,
20058c2ecf20Sopenharmony_ci						      rdev->mode_info.underscan_vborder_property,
20068c2ecf20Sopenharmony_ci						      0);
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci			drm_object_attach_property(&radeon_connector->base.base,
20098c2ecf20Sopenharmony_ci						      dev->mode_config.scaling_mode_property,
20108c2ecf20Sopenharmony_ci						      DRM_MODE_SCALE_NONE);
20118c2ecf20Sopenharmony_ci
20128c2ecf20Sopenharmony_ci			drm_object_attach_property(&radeon_connector->base.base,
20138c2ecf20Sopenharmony_ci						   rdev->mode_info.dither_property,
20148c2ecf20Sopenharmony_ci						   RADEON_FMT_DITHER_DISABLE);
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci			if (radeon_audio != 0) {
20178c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
20188c2ecf20Sopenharmony_ci							   rdev->mode_info.audio_property,
20198c2ecf20Sopenharmony_ci							   RADEON_AUDIO_AUTO);
20208c2ecf20Sopenharmony_ci				radeon_connector->audio = RADEON_AUDIO_AUTO;
20218c2ecf20Sopenharmony_ci			}
20228c2ecf20Sopenharmony_ci			if (ASIC_IS_DCE5(rdev))
20238c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
20248c2ecf20Sopenharmony_ci							   rdev->mode_info.output_csc_property,
20258c2ecf20Sopenharmony_ci							   RADEON_OUTPUT_CSC_BYPASS);
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_ci			subpixel_order = SubPixelHorizontalRGB;
20288c2ecf20Sopenharmony_ci			connector->interlace_allowed = true;
20298c2ecf20Sopenharmony_ci			if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
20308c2ecf20Sopenharmony_ci				connector->doublescan_allowed = true;
20318c2ecf20Sopenharmony_ci			else
20328c2ecf20Sopenharmony_ci				connector->doublescan_allowed = false;
20338c2ecf20Sopenharmony_ci			if (connector_type == DRM_MODE_CONNECTOR_DVII) {
20348c2ecf20Sopenharmony_ci				radeon_connector->dac_load_detect = true;
20358c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
20368c2ecf20Sopenharmony_ci							      rdev->mode_info.load_detect_property,
20378c2ecf20Sopenharmony_ci							      1);
20388c2ecf20Sopenharmony_ci			}
20398c2ecf20Sopenharmony_ci			break;
20408c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_LVDS:
20418c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_eDP:
20428c2ecf20Sopenharmony_ci			drm_connector_init_with_ddc(dev, &radeon_connector->base,
20438c2ecf20Sopenharmony_ci						    &radeon_lvds_bridge_connector_funcs,
20448c2ecf20Sopenharmony_ci						    connector_type,
20458c2ecf20Sopenharmony_ci						    ddc);
20468c2ecf20Sopenharmony_ci			drm_connector_helper_add(&radeon_connector->base,
20478c2ecf20Sopenharmony_ci						 &radeon_dp_connector_helper_funcs);
20488c2ecf20Sopenharmony_ci			drm_object_attach_property(&radeon_connector->base.base,
20498c2ecf20Sopenharmony_ci						      dev->mode_config.scaling_mode_property,
20508c2ecf20Sopenharmony_ci						      DRM_MODE_SCALE_FULLSCREEN);
20518c2ecf20Sopenharmony_ci			subpixel_order = SubPixelHorizontalRGB;
20528c2ecf20Sopenharmony_ci			connector->interlace_allowed = false;
20538c2ecf20Sopenharmony_ci			connector->doublescan_allowed = false;
20548c2ecf20Sopenharmony_ci			break;
20558c2ecf20Sopenharmony_ci		}
20568c2ecf20Sopenharmony_ci	} else {
20578c2ecf20Sopenharmony_ci		switch (connector_type) {
20588c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_VGA:
20598c2ecf20Sopenharmony_ci			if (i2c_bus->valid) {
20608c2ecf20Sopenharmony_ci				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
20618c2ecf20Sopenharmony_ci				if (!radeon_connector->ddc_bus)
20628c2ecf20Sopenharmony_ci					DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
20638c2ecf20Sopenharmony_ci				else
20648c2ecf20Sopenharmony_ci					ddc = &radeon_connector->ddc_bus->adapter;
20658c2ecf20Sopenharmony_ci			}
20668c2ecf20Sopenharmony_ci			drm_connector_init_with_ddc(dev, &radeon_connector->base,
20678c2ecf20Sopenharmony_ci						    &radeon_vga_connector_funcs,
20688c2ecf20Sopenharmony_ci						    connector_type,
20698c2ecf20Sopenharmony_ci						    ddc);
20708c2ecf20Sopenharmony_ci			drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
20718c2ecf20Sopenharmony_ci			radeon_connector->dac_load_detect = true;
20728c2ecf20Sopenharmony_ci			drm_object_attach_property(&radeon_connector->base.base,
20738c2ecf20Sopenharmony_ci						      rdev->mode_info.load_detect_property,
20748c2ecf20Sopenharmony_ci						      1);
20758c2ecf20Sopenharmony_ci			if (ASIC_IS_AVIVO(rdev))
20768c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
20778c2ecf20Sopenharmony_ci							   dev->mode_config.scaling_mode_property,
20788c2ecf20Sopenharmony_ci							   DRM_MODE_SCALE_NONE);
20798c2ecf20Sopenharmony_ci			if (ASIC_IS_DCE5(rdev))
20808c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
20818c2ecf20Sopenharmony_ci							   rdev->mode_info.output_csc_property,
20828c2ecf20Sopenharmony_ci							   RADEON_OUTPUT_CSC_BYPASS);
20838c2ecf20Sopenharmony_ci			/* no HPD on analog connectors */
20848c2ecf20Sopenharmony_ci			radeon_connector->hpd.hpd = RADEON_HPD_NONE;
20858c2ecf20Sopenharmony_ci			connector->interlace_allowed = true;
20868c2ecf20Sopenharmony_ci			connector->doublescan_allowed = true;
20878c2ecf20Sopenharmony_ci			break;
20888c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_DVIA:
20898c2ecf20Sopenharmony_ci			if (i2c_bus->valid) {
20908c2ecf20Sopenharmony_ci				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
20918c2ecf20Sopenharmony_ci				if (!radeon_connector->ddc_bus)
20928c2ecf20Sopenharmony_ci					DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
20938c2ecf20Sopenharmony_ci				else
20948c2ecf20Sopenharmony_ci					ddc = &radeon_connector->ddc_bus->adapter;
20958c2ecf20Sopenharmony_ci			}
20968c2ecf20Sopenharmony_ci			drm_connector_init_with_ddc(dev, &radeon_connector->base,
20978c2ecf20Sopenharmony_ci						    &radeon_vga_connector_funcs,
20988c2ecf20Sopenharmony_ci						    connector_type,
20998c2ecf20Sopenharmony_ci						    ddc);
21008c2ecf20Sopenharmony_ci			drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
21018c2ecf20Sopenharmony_ci			radeon_connector->dac_load_detect = true;
21028c2ecf20Sopenharmony_ci			drm_object_attach_property(&radeon_connector->base.base,
21038c2ecf20Sopenharmony_ci						      rdev->mode_info.load_detect_property,
21048c2ecf20Sopenharmony_ci						      1);
21058c2ecf20Sopenharmony_ci			if (ASIC_IS_AVIVO(rdev))
21068c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
21078c2ecf20Sopenharmony_ci							   dev->mode_config.scaling_mode_property,
21088c2ecf20Sopenharmony_ci							   DRM_MODE_SCALE_NONE);
21098c2ecf20Sopenharmony_ci			if (ASIC_IS_DCE5(rdev))
21108c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
21118c2ecf20Sopenharmony_ci							   rdev->mode_info.output_csc_property,
21128c2ecf20Sopenharmony_ci							   RADEON_OUTPUT_CSC_BYPASS);
21138c2ecf20Sopenharmony_ci			/* no HPD on analog connectors */
21148c2ecf20Sopenharmony_ci			radeon_connector->hpd.hpd = RADEON_HPD_NONE;
21158c2ecf20Sopenharmony_ci			connector->interlace_allowed = true;
21168c2ecf20Sopenharmony_ci			connector->doublescan_allowed = true;
21178c2ecf20Sopenharmony_ci			break;
21188c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_DVII:
21198c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_DVID:
21208c2ecf20Sopenharmony_ci			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
21218c2ecf20Sopenharmony_ci			if (!radeon_dig_connector)
21228c2ecf20Sopenharmony_ci				goto failed;
21238c2ecf20Sopenharmony_ci			radeon_dig_connector->igp_lane_info = igp_lane_info;
21248c2ecf20Sopenharmony_ci			radeon_connector->con_priv = radeon_dig_connector;
21258c2ecf20Sopenharmony_ci			if (i2c_bus->valid) {
21268c2ecf20Sopenharmony_ci				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
21278c2ecf20Sopenharmony_ci				if (!radeon_connector->ddc_bus)
21288c2ecf20Sopenharmony_ci					DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
21298c2ecf20Sopenharmony_ci				else
21308c2ecf20Sopenharmony_ci					ddc = &radeon_connector->ddc_bus->adapter;
21318c2ecf20Sopenharmony_ci			}
21328c2ecf20Sopenharmony_ci			drm_connector_init_with_ddc(dev, &radeon_connector->base,
21338c2ecf20Sopenharmony_ci						    &radeon_dvi_connector_funcs,
21348c2ecf20Sopenharmony_ci						    connector_type,
21358c2ecf20Sopenharmony_ci						    ddc);
21368c2ecf20Sopenharmony_ci			drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
21378c2ecf20Sopenharmony_ci			subpixel_order = SubPixelHorizontalRGB;
21388c2ecf20Sopenharmony_ci			drm_object_attach_property(&radeon_connector->base.base,
21398c2ecf20Sopenharmony_ci						      rdev->mode_info.coherent_mode_property,
21408c2ecf20Sopenharmony_ci						      1);
21418c2ecf20Sopenharmony_ci			if (ASIC_IS_AVIVO(rdev)) {
21428c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
21438c2ecf20Sopenharmony_ci							      rdev->mode_info.underscan_property,
21448c2ecf20Sopenharmony_ci							      UNDERSCAN_OFF);
21458c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
21468c2ecf20Sopenharmony_ci							      rdev->mode_info.underscan_hborder_property,
21478c2ecf20Sopenharmony_ci							      0);
21488c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
21498c2ecf20Sopenharmony_ci							      rdev->mode_info.underscan_vborder_property,
21508c2ecf20Sopenharmony_ci							      0);
21518c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
21528c2ecf20Sopenharmony_ci							   rdev->mode_info.dither_property,
21538c2ecf20Sopenharmony_ci							   RADEON_FMT_DITHER_DISABLE);
21548c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
21558c2ecf20Sopenharmony_ci							   dev->mode_config.scaling_mode_property,
21568c2ecf20Sopenharmony_ci							   DRM_MODE_SCALE_NONE);
21578c2ecf20Sopenharmony_ci			}
21588c2ecf20Sopenharmony_ci			if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
21598c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
21608c2ecf20Sopenharmony_ci							   rdev->mode_info.audio_property,
21618c2ecf20Sopenharmony_ci							   RADEON_AUDIO_AUTO);
21628c2ecf20Sopenharmony_ci				radeon_connector->audio = RADEON_AUDIO_AUTO;
21638c2ecf20Sopenharmony_ci			}
21648c2ecf20Sopenharmony_ci			if (connector_type == DRM_MODE_CONNECTOR_DVII) {
21658c2ecf20Sopenharmony_ci				radeon_connector->dac_load_detect = true;
21668c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
21678c2ecf20Sopenharmony_ci							      rdev->mode_info.load_detect_property,
21688c2ecf20Sopenharmony_ci							      1);
21698c2ecf20Sopenharmony_ci			}
21708c2ecf20Sopenharmony_ci			if (ASIC_IS_DCE5(rdev))
21718c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
21728c2ecf20Sopenharmony_ci							   rdev->mode_info.output_csc_property,
21738c2ecf20Sopenharmony_ci							   RADEON_OUTPUT_CSC_BYPASS);
21748c2ecf20Sopenharmony_ci			connector->interlace_allowed = true;
21758c2ecf20Sopenharmony_ci			if (connector_type == DRM_MODE_CONNECTOR_DVII)
21768c2ecf20Sopenharmony_ci				connector->doublescan_allowed = true;
21778c2ecf20Sopenharmony_ci			else
21788c2ecf20Sopenharmony_ci				connector->doublescan_allowed = false;
21798c2ecf20Sopenharmony_ci			break;
21808c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_HDMIA:
21818c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_HDMIB:
21828c2ecf20Sopenharmony_ci			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
21838c2ecf20Sopenharmony_ci			if (!radeon_dig_connector)
21848c2ecf20Sopenharmony_ci				goto failed;
21858c2ecf20Sopenharmony_ci			radeon_dig_connector->igp_lane_info = igp_lane_info;
21868c2ecf20Sopenharmony_ci			radeon_connector->con_priv = radeon_dig_connector;
21878c2ecf20Sopenharmony_ci			if (i2c_bus->valid) {
21888c2ecf20Sopenharmony_ci				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
21898c2ecf20Sopenharmony_ci				if (!radeon_connector->ddc_bus)
21908c2ecf20Sopenharmony_ci					DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
21918c2ecf20Sopenharmony_ci				else
21928c2ecf20Sopenharmony_ci					ddc = &radeon_connector->ddc_bus->adapter;
21938c2ecf20Sopenharmony_ci			}
21948c2ecf20Sopenharmony_ci			drm_connector_init_with_ddc(dev, &radeon_connector->base,
21958c2ecf20Sopenharmony_ci						    &radeon_dvi_connector_funcs,
21968c2ecf20Sopenharmony_ci						    connector_type,
21978c2ecf20Sopenharmony_ci						    ddc);
21988c2ecf20Sopenharmony_ci			drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
21998c2ecf20Sopenharmony_ci			drm_object_attach_property(&radeon_connector->base.base,
22008c2ecf20Sopenharmony_ci						      rdev->mode_info.coherent_mode_property,
22018c2ecf20Sopenharmony_ci						      1);
22028c2ecf20Sopenharmony_ci			if (ASIC_IS_AVIVO(rdev)) {
22038c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
22048c2ecf20Sopenharmony_ci							      rdev->mode_info.underscan_property,
22058c2ecf20Sopenharmony_ci							      UNDERSCAN_OFF);
22068c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
22078c2ecf20Sopenharmony_ci							      rdev->mode_info.underscan_hborder_property,
22088c2ecf20Sopenharmony_ci							      0);
22098c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
22108c2ecf20Sopenharmony_ci							      rdev->mode_info.underscan_vborder_property,
22118c2ecf20Sopenharmony_ci							      0);
22128c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
22138c2ecf20Sopenharmony_ci							   rdev->mode_info.dither_property,
22148c2ecf20Sopenharmony_ci							   RADEON_FMT_DITHER_DISABLE);
22158c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
22168c2ecf20Sopenharmony_ci							   dev->mode_config.scaling_mode_property,
22178c2ecf20Sopenharmony_ci							   DRM_MODE_SCALE_NONE);
22188c2ecf20Sopenharmony_ci			}
22198c2ecf20Sopenharmony_ci			if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
22208c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
22218c2ecf20Sopenharmony_ci							   rdev->mode_info.audio_property,
22228c2ecf20Sopenharmony_ci							   RADEON_AUDIO_AUTO);
22238c2ecf20Sopenharmony_ci				radeon_connector->audio = RADEON_AUDIO_AUTO;
22248c2ecf20Sopenharmony_ci			}
22258c2ecf20Sopenharmony_ci			if (ASIC_IS_DCE5(rdev))
22268c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
22278c2ecf20Sopenharmony_ci							   rdev->mode_info.output_csc_property,
22288c2ecf20Sopenharmony_ci							   RADEON_OUTPUT_CSC_BYPASS);
22298c2ecf20Sopenharmony_ci			subpixel_order = SubPixelHorizontalRGB;
22308c2ecf20Sopenharmony_ci			connector->interlace_allowed = true;
22318c2ecf20Sopenharmony_ci			if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
22328c2ecf20Sopenharmony_ci				connector->doublescan_allowed = true;
22338c2ecf20Sopenharmony_ci			else
22348c2ecf20Sopenharmony_ci				connector->doublescan_allowed = false;
22358c2ecf20Sopenharmony_ci			break;
22368c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_DisplayPort:
22378c2ecf20Sopenharmony_ci			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
22388c2ecf20Sopenharmony_ci			if (!radeon_dig_connector)
22398c2ecf20Sopenharmony_ci				goto failed;
22408c2ecf20Sopenharmony_ci			radeon_dig_connector->igp_lane_info = igp_lane_info;
22418c2ecf20Sopenharmony_ci			radeon_connector->con_priv = radeon_dig_connector;
22428c2ecf20Sopenharmony_ci			if (i2c_bus->valid) {
22438c2ecf20Sopenharmony_ci				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
22448c2ecf20Sopenharmony_ci				if (radeon_connector->ddc_bus) {
22458c2ecf20Sopenharmony_ci					has_aux = true;
22468c2ecf20Sopenharmony_ci					ddc = &radeon_connector->ddc_bus->adapter;
22478c2ecf20Sopenharmony_ci				} else {
22488c2ecf20Sopenharmony_ci					DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
22498c2ecf20Sopenharmony_ci				}
22508c2ecf20Sopenharmony_ci			}
22518c2ecf20Sopenharmony_ci			drm_connector_init_with_ddc(dev, &radeon_connector->base,
22528c2ecf20Sopenharmony_ci						    &radeon_dp_connector_funcs,
22538c2ecf20Sopenharmony_ci						    connector_type,
22548c2ecf20Sopenharmony_ci						    ddc);
22558c2ecf20Sopenharmony_ci			drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
22568c2ecf20Sopenharmony_ci			subpixel_order = SubPixelHorizontalRGB;
22578c2ecf20Sopenharmony_ci			drm_object_attach_property(&radeon_connector->base.base,
22588c2ecf20Sopenharmony_ci						      rdev->mode_info.coherent_mode_property,
22598c2ecf20Sopenharmony_ci						      1);
22608c2ecf20Sopenharmony_ci			if (ASIC_IS_AVIVO(rdev)) {
22618c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
22628c2ecf20Sopenharmony_ci							      rdev->mode_info.underscan_property,
22638c2ecf20Sopenharmony_ci							      UNDERSCAN_OFF);
22648c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
22658c2ecf20Sopenharmony_ci							      rdev->mode_info.underscan_hborder_property,
22668c2ecf20Sopenharmony_ci							      0);
22678c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
22688c2ecf20Sopenharmony_ci							      rdev->mode_info.underscan_vborder_property,
22698c2ecf20Sopenharmony_ci							      0);
22708c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
22718c2ecf20Sopenharmony_ci							   rdev->mode_info.dither_property,
22728c2ecf20Sopenharmony_ci							   RADEON_FMT_DITHER_DISABLE);
22738c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
22748c2ecf20Sopenharmony_ci							   dev->mode_config.scaling_mode_property,
22758c2ecf20Sopenharmony_ci							   DRM_MODE_SCALE_NONE);
22768c2ecf20Sopenharmony_ci			}
22778c2ecf20Sopenharmony_ci			if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) {
22788c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
22798c2ecf20Sopenharmony_ci							   rdev->mode_info.audio_property,
22808c2ecf20Sopenharmony_ci							   RADEON_AUDIO_AUTO);
22818c2ecf20Sopenharmony_ci				radeon_connector->audio = RADEON_AUDIO_AUTO;
22828c2ecf20Sopenharmony_ci			}
22838c2ecf20Sopenharmony_ci			if (ASIC_IS_DCE5(rdev))
22848c2ecf20Sopenharmony_ci				drm_object_attach_property(&radeon_connector->base.base,
22858c2ecf20Sopenharmony_ci							   rdev->mode_info.output_csc_property,
22868c2ecf20Sopenharmony_ci							   RADEON_OUTPUT_CSC_BYPASS);
22878c2ecf20Sopenharmony_ci			connector->interlace_allowed = true;
22888c2ecf20Sopenharmony_ci			/* in theory with a DP to VGA converter... */
22898c2ecf20Sopenharmony_ci			connector->doublescan_allowed = false;
22908c2ecf20Sopenharmony_ci			break;
22918c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_eDP:
22928c2ecf20Sopenharmony_ci			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
22938c2ecf20Sopenharmony_ci			if (!radeon_dig_connector)
22948c2ecf20Sopenharmony_ci				goto failed;
22958c2ecf20Sopenharmony_ci			radeon_dig_connector->igp_lane_info = igp_lane_info;
22968c2ecf20Sopenharmony_ci			radeon_connector->con_priv = radeon_dig_connector;
22978c2ecf20Sopenharmony_ci			if (i2c_bus->valid) {
22988c2ecf20Sopenharmony_ci				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
22998c2ecf20Sopenharmony_ci				if (radeon_connector->ddc_bus) {
23008c2ecf20Sopenharmony_ci					has_aux = true;
23018c2ecf20Sopenharmony_ci					ddc = &radeon_connector->ddc_bus->adapter;
23028c2ecf20Sopenharmony_ci				} else {
23038c2ecf20Sopenharmony_ci					DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
23048c2ecf20Sopenharmony_ci				}
23058c2ecf20Sopenharmony_ci			}
23068c2ecf20Sopenharmony_ci			drm_connector_init_with_ddc(dev, &radeon_connector->base,
23078c2ecf20Sopenharmony_ci						    &radeon_edp_connector_funcs,
23088c2ecf20Sopenharmony_ci						    connector_type,
23098c2ecf20Sopenharmony_ci						    ddc);
23108c2ecf20Sopenharmony_ci			drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
23118c2ecf20Sopenharmony_ci			drm_object_attach_property(&radeon_connector->base.base,
23128c2ecf20Sopenharmony_ci						      dev->mode_config.scaling_mode_property,
23138c2ecf20Sopenharmony_ci						      DRM_MODE_SCALE_FULLSCREEN);
23148c2ecf20Sopenharmony_ci			subpixel_order = SubPixelHorizontalRGB;
23158c2ecf20Sopenharmony_ci			connector->interlace_allowed = false;
23168c2ecf20Sopenharmony_ci			connector->doublescan_allowed = false;
23178c2ecf20Sopenharmony_ci			break;
23188c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_SVIDEO:
23198c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_Composite:
23208c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_9PinDIN:
23218c2ecf20Sopenharmony_ci			drm_connector_init_with_ddc(dev, &radeon_connector->base,
23228c2ecf20Sopenharmony_ci						    &radeon_tv_connector_funcs,
23238c2ecf20Sopenharmony_ci						    connector_type,
23248c2ecf20Sopenharmony_ci						    ddc);
23258c2ecf20Sopenharmony_ci			drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
23268c2ecf20Sopenharmony_ci			radeon_connector->dac_load_detect = true;
23278c2ecf20Sopenharmony_ci			drm_object_attach_property(&radeon_connector->base.base,
23288c2ecf20Sopenharmony_ci						      rdev->mode_info.load_detect_property,
23298c2ecf20Sopenharmony_ci						      1);
23308c2ecf20Sopenharmony_ci			drm_object_attach_property(&radeon_connector->base.base,
23318c2ecf20Sopenharmony_ci						      rdev->mode_info.tv_std_property,
23328c2ecf20Sopenharmony_ci						      radeon_atombios_get_tv_info(rdev));
23338c2ecf20Sopenharmony_ci			/* no HPD on analog connectors */
23348c2ecf20Sopenharmony_ci			radeon_connector->hpd.hpd = RADEON_HPD_NONE;
23358c2ecf20Sopenharmony_ci			connector->interlace_allowed = false;
23368c2ecf20Sopenharmony_ci			connector->doublescan_allowed = false;
23378c2ecf20Sopenharmony_ci			break;
23388c2ecf20Sopenharmony_ci		case DRM_MODE_CONNECTOR_LVDS:
23398c2ecf20Sopenharmony_ci			radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
23408c2ecf20Sopenharmony_ci			if (!radeon_dig_connector)
23418c2ecf20Sopenharmony_ci				goto failed;
23428c2ecf20Sopenharmony_ci			radeon_dig_connector->igp_lane_info = igp_lane_info;
23438c2ecf20Sopenharmony_ci			radeon_connector->con_priv = radeon_dig_connector;
23448c2ecf20Sopenharmony_ci			if (i2c_bus->valid) {
23458c2ecf20Sopenharmony_ci				radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
23468c2ecf20Sopenharmony_ci				if (!radeon_connector->ddc_bus)
23478c2ecf20Sopenharmony_ci					DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
23488c2ecf20Sopenharmony_ci				else
23498c2ecf20Sopenharmony_ci					ddc = &radeon_connector->ddc_bus->adapter;
23508c2ecf20Sopenharmony_ci			}
23518c2ecf20Sopenharmony_ci			drm_connector_init_with_ddc(dev, &radeon_connector->base,
23528c2ecf20Sopenharmony_ci						    &radeon_lvds_connector_funcs,
23538c2ecf20Sopenharmony_ci						    connector_type,
23548c2ecf20Sopenharmony_ci						    ddc);
23558c2ecf20Sopenharmony_ci			drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
23568c2ecf20Sopenharmony_ci			drm_object_attach_property(&radeon_connector->base.base,
23578c2ecf20Sopenharmony_ci						      dev->mode_config.scaling_mode_property,
23588c2ecf20Sopenharmony_ci						      DRM_MODE_SCALE_FULLSCREEN);
23598c2ecf20Sopenharmony_ci			subpixel_order = SubPixelHorizontalRGB;
23608c2ecf20Sopenharmony_ci			connector->interlace_allowed = false;
23618c2ecf20Sopenharmony_ci			connector->doublescan_allowed = false;
23628c2ecf20Sopenharmony_ci			break;
23638c2ecf20Sopenharmony_ci		}
23648c2ecf20Sopenharmony_ci	}
23658c2ecf20Sopenharmony_ci
23668c2ecf20Sopenharmony_ci	if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
23678c2ecf20Sopenharmony_ci		if (i2c_bus->valid) {
23688c2ecf20Sopenharmony_ci			connector->polled = DRM_CONNECTOR_POLL_CONNECT |
23698c2ecf20Sopenharmony_ci			                    DRM_CONNECTOR_POLL_DISCONNECT;
23708c2ecf20Sopenharmony_ci		}
23718c2ecf20Sopenharmony_ci	} else
23728c2ecf20Sopenharmony_ci		connector->polled = DRM_CONNECTOR_POLL_HPD;
23738c2ecf20Sopenharmony_ci
23748c2ecf20Sopenharmony_ci	connector->display_info.subpixel_order = subpixel_order;
23758c2ecf20Sopenharmony_ci	drm_connector_register(connector);
23768c2ecf20Sopenharmony_ci
23778c2ecf20Sopenharmony_ci	if (has_aux)
23788c2ecf20Sopenharmony_ci		radeon_dp_aux_init(radeon_connector);
23798c2ecf20Sopenharmony_ci
23808c2ecf20Sopenharmony_ci	return;
23818c2ecf20Sopenharmony_ci
23828c2ecf20Sopenharmony_cifailed:
23838c2ecf20Sopenharmony_ci	drm_connector_cleanup(connector);
23848c2ecf20Sopenharmony_ci	kfree(connector);
23858c2ecf20Sopenharmony_ci}
23868c2ecf20Sopenharmony_ci
23878c2ecf20Sopenharmony_civoid
23888c2ecf20Sopenharmony_ciradeon_add_legacy_connector(struct drm_device *dev,
23898c2ecf20Sopenharmony_ci			    uint32_t connector_id,
23908c2ecf20Sopenharmony_ci			    uint32_t supported_device,
23918c2ecf20Sopenharmony_ci			    int connector_type,
23928c2ecf20Sopenharmony_ci			    struct radeon_i2c_bus_rec *i2c_bus,
23938c2ecf20Sopenharmony_ci			    uint16_t connector_object_id,
23948c2ecf20Sopenharmony_ci			    struct radeon_hpd *hpd)
23958c2ecf20Sopenharmony_ci{
23968c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
23978c2ecf20Sopenharmony_ci	struct drm_connector *connector;
23988c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector;
23998c2ecf20Sopenharmony_ci	struct i2c_adapter *ddc = NULL;
24008c2ecf20Sopenharmony_ci	uint32_t subpixel_order = SubPixelNone;
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_ci	if (connector_type == DRM_MODE_CONNECTOR_Unknown)
24038c2ecf20Sopenharmony_ci		return;
24048c2ecf20Sopenharmony_ci
24058c2ecf20Sopenharmony_ci	/* if the user selected tv=0 don't try and add the connector */
24068c2ecf20Sopenharmony_ci	if (((connector_type == DRM_MODE_CONNECTOR_SVIDEO) ||
24078c2ecf20Sopenharmony_ci	     (connector_type == DRM_MODE_CONNECTOR_Composite) ||
24088c2ecf20Sopenharmony_ci	     (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) &&
24098c2ecf20Sopenharmony_ci	    (radeon_tv == 0))
24108c2ecf20Sopenharmony_ci		return;
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_ci	/* see if we already added it */
24138c2ecf20Sopenharmony_ci	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
24148c2ecf20Sopenharmony_ci		radeon_connector = to_radeon_connector(connector);
24158c2ecf20Sopenharmony_ci		if (radeon_connector->connector_id == connector_id) {
24168c2ecf20Sopenharmony_ci			radeon_connector->devices |= supported_device;
24178c2ecf20Sopenharmony_ci			return;
24188c2ecf20Sopenharmony_ci		}
24198c2ecf20Sopenharmony_ci	}
24208c2ecf20Sopenharmony_ci
24218c2ecf20Sopenharmony_ci	radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL);
24228c2ecf20Sopenharmony_ci	if (!radeon_connector)
24238c2ecf20Sopenharmony_ci		return;
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ci	connector = &radeon_connector->base;
24268c2ecf20Sopenharmony_ci
24278c2ecf20Sopenharmony_ci	radeon_connector->connector_id = connector_id;
24288c2ecf20Sopenharmony_ci	radeon_connector->devices = supported_device;
24298c2ecf20Sopenharmony_ci	radeon_connector->connector_object_id = connector_object_id;
24308c2ecf20Sopenharmony_ci	radeon_connector->hpd = *hpd;
24318c2ecf20Sopenharmony_ci
24328c2ecf20Sopenharmony_ci	switch (connector_type) {
24338c2ecf20Sopenharmony_ci	case DRM_MODE_CONNECTOR_VGA:
24348c2ecf20Sopenharmony_ci		if (i2c_bus->valid) {
24358c2ecf20Sopenharmony_ci			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
24368c2ecf20Sopenharmony_ci			if (!radeon_connector->ddc_bus)
24378c2ecf20Sopenharmony_ci				DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
24388c2ecf20Sopenharmony_ci			else
24398c2ecf20Sopenharmony_ci				ddc = &radeon_connector->ddc_bus->adapter;
24408c2ecf20Sopenharmony_ci		}
24418c2ecf20Sopenharmony_ci		drm_connector_init_with_ddc(dev, &radeon_connector->base,
24428c2ecf20Sopenharmony_ci					    &radeon_vga_connector_funcs,
24438c2ecf20Sopenharmony_ci					    connector_type,
24448c2ecf20Sopenharmony_ci					    ddc);
24458c2ecf20Sopenharmony_ci		drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
24468c2ecf20Sopenharmony_ci		radeon_connector->dac_load_detect = true;
24478c2ecf20Sopenharmony_ci		drm_object_attach_property(&radeon_connector->base.base,
24488c2ecf20Sopenharmony_ci					      rdev->mode_info.load_detect_property,
24498c2ecf20Sopenharmony_ci					      1);
24508c2ecf20Sopenharmony_ci		/* no HPD on analog connectors */
24518c2ecf20Sopenharmony_ci		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
24528c2ecf20Sopenharmony_ci		connector->interlace_allowed = true;
24538c2ecf20Sopenharmony_ci		connector->doublescan_allowed = true;
24548c2ecf20Sopenharmony_ci		break;
24558c2ecf20Sopenharmony_ci	case DRM_MODE_CONNECTOR_DVIA:
24568c2ecf20Sopenharmony_ci		if (i2c_bus->valid) {
24578c2ecf20Sopenharmony_ci			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
24588c2ecf20Sopenharmony_ci			if (!radeon_connector->ddc_bus)
24598c2ecf20Sopenharmony_ci				DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
24608c2ecf20Sopenharmony_ci			else
24618c2ecf20Sopenharmony_ci				ddc = &radeon_connector->ddc_bus->adapter;
24628c2ecf20Sopenharmony_ci		}
24638c2ecf20Sopenharmony_ci		drm_connector_init_with_ddc(dev, &radeon_connector->base,
24648c2ecf20Sopenharmony_ci					    &radeon_vga_connector_funcs,
24658c2ecf20Sopenharmony_ci					    connector_type,
24668c2ecf20Sopenharmony_ci					    ddc);
24678c2ecf20Sopenharmony_ci		drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
24688c2ecf20Sopenharmony_ci		radeon_connector->dac_load_detect = true;
24698c2ecf20Sopenharmony_ci		drm_object_attach_property(&radeon_connector->base.base,
24708c2ecf20Sopenharmony_ci					      rdev->mode_info.load_detect_property,
24718c2ecf20Sopenharmony_ci					      1);
24728c2ecf20Sopenharmony_ci		/* no HPD on analog connectors */
24738c2ecf20Sopenharmony_ci		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
24748c2ecf20Sopenharmony_ci		connector->interlace_allowed = true;
24758c2ecf20Sopenharmony_ci		connector->doublescan_allowed = true;
24768c2ecf20Sopenharmony_ci		break;
24778c2ecf20Sopenharmony_ci	case DRM_MODE_CONNECTOR_DVII:
24788c2ecf20Sopenharmony_ci	case DRM_MODE_CONNECTOR_DVID:
24798c2ecf20Sopenharmony_ci		if (i2c_bus->valid) {
24808c2ecf20Sopenharmony_ci			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
24818c2ecf20Sopenharmony_ci			if (!radeon_connector->ddc_bus)
24828c2ecf20Sopenharmony_ci				DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
24838c2ecf20Sopenharmony_ci			else
24848c2ecf20Sopenharmony_ci				ddc = &radeon_connector->ddc_bus->adapter;
24858c2ecf20Sopenharmony_ci		}
24868c2ecf20Sopenharmony_ci		drm_connector_init_with_ddc(dev, &radeon_connector->base,
24878c2ecf20Sopenharmony_ci					    &radeon_dvi_connector_funcs,
24888c2ecf20Sopenharmony_ci					    connector_type,
24898c2ecf20Sopenharmony_ci					    ddc);
24908c2ecf20Sopenharmony_ci		drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
24918c2ecf20Sopenharmony_ci		if (connector_type == DRM_MODE_CONNECTOR_DVII) {
24928c2ecf20Sopenharmony_ci			radeon_connector->dac_load_detect = true;
24938c2ecf20Sopenharmony_ci			drm_object_attach_property(&radeon_connector->base.base,
24948c2ecf20Sopenharmony_ci						      rdev->mode_info.load_detect_property,
24958c2ecf20Sopenharmony_ci						      1);
24968c2ecf20Sopenharmony_ci		}
24978c2ecf20Sopenharmony_ci		subpixel_order = SubPixelHorizontalRGB;
24988c2ecf20Sopenharmony_ci		connector->interlace_allowed = true;
24998c2ecf20Sopenharmony_ci		if (connector_type == DRM_MODE_CONNECTOR_DVII)
25008c2ecf20Sopenharmony_ci			connector->doublescan_allowed = true;
25018c2ecf20Sopenharmony_ci		else
25028c2ecf20Sopenharmony_ci			connector->doublescan_allowed = false;
25038c2ecf20Sopenharmony_ci		break;
25048c2ecf20Sopenharmony_ci	case DRM_MODE_CONNECTOR_SVIDEO:
25058c2ecf20Sopenharmony_ci	case DRM_MODE_CONNECTOR_Composite:
25068c2ecf20Sopenharmony_ci	case DRM_MODE_CONNECTOR_9PinDIN:
25078c2ecf20Sopenharmony_ci		drm_connector_init_with_ddc(dev, &radeon_connector->base,
25088c2ecf20Sopenharmony_ci					    &radeon_tv_connector_funcs,
25098c2ecf20Sopenharmony_ci					    connector_type,
25108c2ecf20Sopenharmony_ci					    ddc);
25118c2ecf20Sopenharmony_ci		drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
25128c2ecf20Sopenharmony_ci		radeon_connector->dac_load_detect = true;
25138c2ecf20Sopenharmony_ci		/* RS400,RC410,RS480 chipset seems to report a lot
25148c2ecf20Sopenharmony_ci		 * of false positive on load detect, we haven't yet
25158c2ecf20Sopenharmony_ci		 * found a way to make load detect reliable on those
25168c2ecf20Sopenharmony_ci		 * chipset, thus just disable it for TV.
25178c2ecf20Sopenharmony_ci		 */
25188c2ecf20Sopenharmony_ci		if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480)
25198c2ecf20Sopenharmony_ci			radeon_connector->dac_load_detect = false;
25208c2ecf20Sopenharmony_ci		drm_object_attach_property(&radeon_connector->base.base,
25218c2ecf20Sopenharmony_ci					      rdev->mode_info.load_detect_property,
25228c2ecf20Sopenharmony_ci					      radeon_connector->dac_load_detect);
25238c2ecf20Sopenharmony_ci		drm_object_attach_property(&radeon_connector->base.base,
25248c2ecf20Sopenharmony_ci					      rdev->mode_info.tv_std_property,
25258c2ecf20Sopenharmony_ci					      radeon_combios_get_tv_info(rdev));
25268c2ecf20Sopenharmony_ci		/* no HPD on analog connectors */
25278c2ecf20Sopenharmony_ci		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
25288c2ecf20Sopenharmony_ci		connector->interlace_allowed = false;
25298c2ecf20Sopenharmony_ci		connector->doublescan_allowed = false;
25308c2ecf20Sopenharmony_ci		break;
25318c2ecf20Sopenharmony_ci	case DRM_MODE_CONNECTOR_LVDS:
25328c2ecf20Sopenharmony_ci		if (i2c_bus->valid) {
25338c2ecf20Sopenharmony_ci			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
25348c2ecf20Sopenharmony_ci			if (!radeon_connector->ddc_bus)
25358c2ecf20Sopenharmony_ci				DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
25368c2ecf20Sopenharmony_ci			else
25378c2ecf20Sopenharmony_ci				ddc = &radeon_connector->ddc_bus->adapter;
25388c2ecf20Sopenharmony_ci		}
25398c2ecf20Sopenharmony_ci		drm_connector_init_with_ddc(dev, &radeon_connector->base,
25408c2ecf20Sopenharmony_ci					    &radeon_lvds_connector_funcs,
25418c2ecf20Sopenharmony_ci					    connector_type,
25428c2ecf20Sopenharmony_ci					    ddc);
25438c2ecf20Sopenharmony_ci		drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
25448c2ecf20Sopenharmony_ci		drm_object_attach_property(&radeon_connector->base.base,
25458c2ecf20Sopenharmony_ci					      dev->mode_config.scaling_mode_property,
25468c2ecf20Sopenharmony_ci					      DRM_MODE_SCALE_FULLSCREEN);
25478c2ecf20Sopenharmony_ci		subpixel_order = SubPixelHorizontalRGB;
25488c2ecf20Sopenharmony_ci		connector->interlace_allowed = false;
25498c2ecf20Sopenharmony_ci		connector->doublescan_allowed = false;
25508c2ecf20Sopenharmony_ci		break;
25518c2ecf20Sopenharmony_ci	}
25528c2ecf20Sopenharmony_ci
25538c2ecf20Sopenharmony_ci	if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
25548c2ecf20Sopenharmony_ci		if (i2c_bus->valid) {
25558c2ecf20Sopenharmony_ci			connector->polled = DRM_CONNECTOR_POLL_CONNECT |
25568c2ecf20Sopenharmony_ci			                    DRM_CONNECTOR_POLL_DISCONNECT;
25578c2ecf20Sopenharmony_ci		}
25588c2ecf20Sopenharmony_ci	} else
25598c2ecf20Sopenharmony_ci		connector->polled = DRM_CONNECTOR_POLL_HPD;
25608c2ecf20Sopenharmony_ci
25618c2ecf20Sopenharmony_ci	connector->display_info.subpixel_order = subpixel_order;
25628c2ecf20Sopenharmony_ci	drm_connector_register(connector);
25638c2ecf20Sopenharmony_ci}
25648c2ecf20Sopenharmony_ci
25658c2ecf20Sopenharmony_civoid radeon_setup_mst_connector(struct drm_device *dev)
25668c2ecf20Sopenharmony_ci{
25678c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
25688c2ecf20Sopenharmony_ci	struct drm_connector *connector;
25698c2ecf20Sopenharmony_ci	struct radeon_connector *radeon_connector;
25708c2ecf20Sopenharmony_ci
25718c2ecf20Sopenharmony_ci	if (!ASIC_IS_DCE5(rdev))
25728c2ecf20Sopenharmony_ci		return;
25738c2ecf20Sopenharmony_ci
25748c2ecf20Sopenharmony_ci	if (radeon_mst == 0)
25758c2ecf20Sopenharmony_ci		return;
25768c2ecf20Sopenharmony_ci
25778c2ecf20Sopenharmony_ci	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
25788c2ecf20Sopenharmony_ci		int ret;
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_ci		radeon_connector = to_radeon_connector(connector);
25818c2ecf20Sopenharmony_ci
25828c2ecf20Sopenharmony_ci		if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
25838c2ecf20Sopenharmony_ci			continue;
25848c2ecf20Sopenharmony_ci
25858c2ecf20Sopenharmony_ci		ret = radeon_dp_mst_init(radeon_connector);
25868c2ecf20Sopenharmony_ci	}
25878c2ecf20Sopenharmony_ci}
2588