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