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