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> 3083b4b9b9SFrançois Tigeot #include <drm/radeon_drm.h> 31926deccbSFrançois Tigeot #include "radeon.h" 32926deccbSFrançois Tigeot #include "atom.h" 33926deccbSFrançois Tigeot 34c6f73aabSFrançois Tigeot #include <linux/string.h> 35c6f73aabSFrançois Tigeot 36c6f73aabSFrançois Tigeot #ifdef PM_TODO 37c6f73aabSFrançois Tigeot #include <linux/pm_runtime.h> 38c6f73aabSFrançois Tigeot #endif 39c6f73aabSFrançois Tigeot 40926deccbSFrançois Tigeot void radeon_connector_hotplug(struct drm_connector *connector) 41926deccbSFrançois Tigeot { 42926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 43926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 44926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 45926deccbSFrançois Tigeot 46926deccbSFrançois Tigeot /* bail if the connector does not have hpd pin, e.g., 47926deccbSFrançois Tigeot * VGA, TV, etc. 48926deccbSFrançois Tigeot */ 49926deccbSFrançois Tigeot if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) 50926deccbSFrançois Tigeot return; 51926deccbSFrançois Tigeot 52926deccbSFrançois Tigeot radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); 53926deccbSFrançois Tigeot 54926deccbSFrançois Tigeot /* if the connector is already off, don't turn it back on */ 55c6f73aabSFrançois Tigeot /* FIXME: This access isn't protected by any locks. */ 56926deccbSFrançois Tigeot if (connector->dpms != DRM_MODE_DPMS_ON) 57926deccbSFrançois Tigeot return; 58926deccbSFrançois Tigeot 59926deccbSFrançois Tigeot /* just deal with DP (not eDP) here. */ 60926deccbSFrançois Tigeot if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { 61926deccbSFrançois Tigeot struct radeon_connector_atom_dig *dig_connector = 62926deccbSFrançois Tigeot radeon_connector->con_priv; 63926deccbSFrançois Tigeot 64926deccbSFrançois Tigeot /* if existing sink type was not DP no need to retrain */ 65926deccbSFrançois Tigeot if (dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_DISPLAYPORT) 66926deccbSFrançois Tigeot return; 67926deccbSFrançois Tigeot 68926deccbSFrançois Tigeot /* first get sink type as it may be reset after (un)plug */ 69926deccbSFrançois Tigeot dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector); 70926deccbSFrançois Tigeot /* don't do anything if sink is not display port, i.e., 71926deccbSFrançois Tigeot * passive dp->(dvi|hdmi) adaptor 72926deccbSFrançois Tigeot */ 73926deccbSFrançois Tigeot if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { 74926deccbSFrançois Tigeot int saved_dpms = connector->dpms; 75926deccbSFrançois Tigeot /* Only turn off the display if it's physically disconnected */ 76926deccbSFrançois Tigeot if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) { 77926deccbSFrançois Tigeot drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); 78926deccbSFrançois Tigeot } else if (radeon_dp_needs_link_train(radeon_connector)) { 79926deccbSFrançois Tigeot /* set it to OFF so that drm_helper_connector_dpms() 80926deccbSFrançois Tigeot * won't return immediately since the current state 81926deccbSFrançois Tigeot * is ON at this point. 82926deccbSFrançois Tigeot */ 83926deccbSFrançois Tigeot connector->dpms = DRM_MODE_DPMS_OFF; 84926deccbSFrançois Tigeot drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); 85926deccbSFrançois Tigeot } 86926deccbSFrançois Tigeot connector->dpms = saved_dpms; 87926deccbSFrançois Tigeot } 88926deccbSFrançois Tigeot } 89926deccbSFrançois Tigeot } 90926deccbSFrançois Tigeot 91926deccbSFrançois Tigeot static void radeon_property_change_mode(struct drm_encoder *encoder) 92926deccbSFrançois Tigeot { 93926deccbSFrançois Tigeot struct drm_crtc *crtc = encoder->crtc; 94926deccbSFrançois Tigeot 95926deccbSFrançois Tigeot if (crtc && crtc->enabled) { 96926deccbSFrançois Tigeot drm_crtc_helper_set_mode(crtc, &crtc->mode, 97ba55f2f5SFrançois Tigeot crtc->x, crtc->y, crtc->primary->fb); 98926deccbSFrançois Tigeot } 99926deccbSFrançois Tigeot } 100926deccbSFrançois Tigeot 101926deccbSFrançois Tigeot int radeon_get_monitor_bpc(struct drm_connector *connector) 102926deccbSFrançois Tigeot { 103926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 104926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 105926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 106926deccbSFrançois Tigeot struct radeon_connector_atom_dig *dig_connector; 107926deccbSFrançois Tigeot int bpc = 8; 108c6f73aabSFrançois Tigeot int mode_clock, max_tmds_clock; 109926deccbSFrançois Tigeot 110926deccbSFrançois Tigeot switch (connector->connector_type) { 111926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVII: 112926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_HDMIB: 113926deccbSFrançois Tigeot if (radeon_connector->use_digital) { 114c6f73aabSFrançois Tigeot if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { 115926deccbSFrançois Tigeot if (connector->display_info.bpc) 116926deccbSFrançois Tigeot bpc = connector->display_info.bpc; 117926deccbSFrançois Tigeot } 118926deccbSFrançois Tigeot } 119926deccbSFrançois Tigeot break; 120926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVID: 121926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_HDMIA: 122c6f73aabSFrançois Tigeot if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { 123926deccbSFrançois Tigeot if (connector->display_info.bpc) 124926deccbSFrançois Tigeot bpc = connector->display_info.bpc; 125926deccbSFrançois Tigeot } 126926deccbSFrançois Tigeot break; 127926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DisplayPort: 128926deccbSFrançois Tigeot dig_connector = radeon_connector->con_priv; 129926deccbSFrançois Tigeot if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || 130926deccbSFrançois Tigeot (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) || 131c6f73aabSFrançois Tigeot drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { 132926deccbSFrançois Tigeot if (connector->display_info.bpc) 133926deccbSFrançois Tigeot bpc = connector->display_info.bpc; 134926deccbSFrançois Tigeot } 135926deccbSFrançois Tigeot break; 136926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_eDP: 137926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_LVDS: 138926deccbSFrançois Tigeot if (connector->display_info.bpc) 139926deccbSFrançois Tigeot bpc = connector->display_info.bpc; 140926deccbSFrançois Tigeot else if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) { 141c0e85e96SFrançois Tigeot const struct drm_connector_helper_funcs *connector_funcs = 142926deccbSFrançois Tigeot connector->helper_private; 143926deccbSFrançois Tigeot struct drm_encoder *encoder = connector_funcs->best_encoder(connector); 144926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 145926deccbSFrançois Tigeot struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; 146926deccbSFrançois Tigeot 147926deccbSFrançois Tigeot if (dig->lcd_misc & ATOM_PANEL_MISC_V13_6BIT_PER_COLOR) 148926deccbSFrançois Tigeot bpc = 6; 149926deccbSFrançois Tigeot else if (dig->lcd_misc & ATOM_PANEL_MISC_V13_8BIT_PER_COLOR) 150926deccbSFrançois Tigeot bpc = 8; 151926deccbSFrançois Tigeot } 152926deccbSFrançois Tigeot break; 153926deccbSFrançois Tigeot } 154c6f73aabSFrançois Tigeot 155c6f73aabSFrançois Tigeot if (drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { 156c6f73aabSFrançois Tigeot /* hdmi deep color only implemented on DCE4+ */ 157c6f73aabSFrançois Tigeot if ((bpc > 8) && !ASIC_IS_DCE4(rdev)) { 158c6f73aabSFrançois Tigeot DRM_DEBUG("%s: HDMI deep color %d bpc unsupported. Using 8 bpc.\n", 159c6f73aabSFrançois Tigeot connector->name, bpc); 160c6f73aabSFrançois Tigeot bpc = 8; 161c6f73aabSFrançois Tigeot } 162c6f73aabSFrançois Tigeot 163c6f73aabSFrançois Tigeot /* 164c6f73aabSFrançois Tigeot * Pre DCE-8 hw can't handle > 12 bpc, and more than 12 bpc doesn't make 165c6f73aabSFrançois Tigeot * much sense without support for > 12 bpc framebuffers. RGB 4:4:4 at 166c6f73aabSFrançois Tigeot * 12 bpc is always supported on hdmi deep color sinks, as this is 167c6f73aabSFrançois Tigeot * required by the HDMI-1.3 spec. Clamp to a safe 12 bpc maximum. 168c6f73aabSFrançois Tigeot */ 169c6f73aabSFrançois Tigeot if (bpc > 12) { 170c6f73aabSFrançois Tigeot DRM_DEBUG("%s: HDMI deep color %d bpc unsupported. Using 12 bpc.\n", 171c6f73aabSFrançois Tigeot connector->name, bpc); 172c6f73aabSFrançois Tigeot bpc = 12; 173c6f73aabSFrançois Tigeot } 174c6f73aabSFrançois Tigeot 175c6f73aabSFrançois Tigeot /* Any defined maximum tmds clock limit we must not exceed? */ 176c6f73aabSFrançois Tigeot if (connector->max_tmds_clock > 0) { 177c6f73aabSFrançois Tigeot /* mode_clock is clock in kHz for mode to be modeset on this connector */ 178c6f73aabSFrançois Tigeot mode_clock = radeon_connector->pixelclock_for_modeset; 179c6f73aabSFrançois Tigeot 180c6f73aabSFrançois Tigeot /* Maximum allowable input clock in kHz */ 181c6f73aabSFrançois Tigeot max_tmds_clock = connector->max_tmds_clock * 1000; 182c6f73aabSFrançois Tigeot 183c6f73aabSFrançois Tigeot DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n", 184c6f73aabSFrançois Tigeot connector->name, mode_clock, max_tmds_clock); 185c6f73aabSFrançois Tigeot 186c6f73aabSFrançois Tigeot /* Check if bpc is within clock limit. Try to degrade gracefully otherwise */ 187c6f73aabSFrançois Tigeot if ((bpc == 12) && (mode_clock * 3/2 > max_tmds_clock)) { 188c6f73aabSFrançois Tigeot if ((connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) && 189c6f73aabSFrançois Tigeot (mode_clock * 5/4 <= max_tmds_clock)) 190c6f73aabSFrançois Tigeot bpc = 10; 191c6f73aabSFrançois Tigeot else 192c6f73aabSFrançois Tigeot bpc = 8; 193c6f73aabSFrançois Tigeot 194c6f73aabSFrançois Tigeot DRM_DEBUG("%s: HDMI deep color 12 bpc exceeds max tmds clock. Using %d bpc.\n", 195c6f73aabSFrançois Tigeot connector->name, bpc); 196c6f73aabSFrançois Tigeot } 197c6f73aabSFrançois Tigeot 198c6f73aabSFrançois Tigeot if ((bpc == 10) && (mode_clock * 5/4 > max_tmds_clock)) { 199c6f73aabSFrançois Tigeot bpc = 8; 200c6f73aabSFrançois Tigeot DRM_DEBUG("%s: HDMI deep color 10 bpc exceeds max tmds clock. Using %d bpc.\n", 201c6f73aabSFrançois Tigeot connector->name, bpc); 202c6f73aabSFrançois Tigeot } 203c6f73aabSFrançois Tigeot } 204c6f73aabSFrançois Tigeot else if (bpc > 8) { 205c6f73aabSFrançois Tigeot /* max_tmds_clock missing, but hdmi spec mandates it for deep color. */ 206c6f73aabSFrançois Tigeot DRM_DEBUG("%s: Required max tmds clock for HDMI deep color missing. Using 8 bpc.\n", 207c6f73aabSFrançois Tigeot connector->name); 208c6f73aabSFrançois Tigeot bpc = 8; 209c6f73aabSFrançois Tigeot } 210c6f73aabSFrançois Tigeot } 211c6f73aabSFrançois Tigeot 212c6f73aabSFrançois Tigeot if ((radeon_deep_color == 0) && (bpc > 8)) { 213c6f73aabSFrançois Tigeot DRM_DEBUG("%s: Deep color disabled. Set radeon module param deep_color=1 to enable.\n", 214c6f73aabSFrançois Tigeot connector->name); 215c6f73aabSFrançois Tigeot bpc = 8; 216c6f73aabSFrançois Tigeot } 217c6f73aabSFrançois Tigeot 218c6f73aabSFrançois Tigeot DRM_DEBUG("%s: Display bpc=%d, returned bpc=%d\n", 219c6f73aabSFrançois Tigeot connector->name, connector->display_info.bpc, bpc); 220c6f73aabSFrançois Tigeot 221926deccbSFrançois Tigeot return bpc; 222926deccbSFrançois Tigeot } 223926deccbSFrançois Tigeot 224926deccbSFrançois Tigeot static void 225926deccbSFrançois Tigeot radeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_connector_status status) 226926deccbSFrançois Tigeot { 227926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 228926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 229926deccbSFrançois Tigeot struct drm_encoder *best_encoder = NULL; 230926deccbSFrançois Tigeot struct drm_encoder *encoder = NULL; 231c0e85e96SFrançois Tigeot const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; 232926deccbSFrançois Tigeot bool connected; 233926deccbSFrançois Tigeot int i; 234926deccbSFrançois Tigeot 235926deccbSFrançois Tigeot best_encoder = connector_funcs->best_encoder(connector); 236926deccbSFrançois Tigeot 237926deccbSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 238926deccbSFrançois Tigeot if (connector->encoder_ids[i] == 0) 239926deccbSFrançois Tigeot break; 240926deccbSFrançois Tigeot 241c6f73aabSFrançois Tigeot encoder = drm_encoder_find(connector->dev, 242c6f73aabSFrançois Tigeot connector->encoder_ids[i]); 243c6f73aabSFrançois Tigeot if (!encoder) 244926deccbSFrançois Tigeot continue; 245926deccbSFrançois Tigeot 246926deccbSFrançois Tigeot if ((encoder == best_encoder) && (status == connector_status_connected)) 247926deccbSFrançois Tigeot connected = true; 248926deccbSFrançois Tigeot else 249926deccbSFrançois Tigeot connected = false; 250926deccbSFrançois Tigeot 251926deccbSFrançois Tigeot if (rdev->is_atom_bios) 252926deccbSFrançois Tigeot radeon_atombios_connected_scratch_regs(connector, encoder, connected); 253926deccbSFrançois Tigeot else 254926deccbSFrançois Tigeot radeon_combios_connected_scratch_regs(connector, encoder, connected); 255926deccbSFrançois Tigeot 256926deccbSFrançois Tigeot } 257926deccbSFrançois Tigeot } 258926deccbSFrançois Tigeot 259926deccbSFrançois Tigeot static struct drm_encoder *radeon_find_encoder(struct drm_connector *connector, int encoder_type) 260926deccbSFrançois Tigeot { 261926deccbSFrançois Tigeot struct drm_encoder *encoder; 262926deccbSFrançois Tigeot int i; 263926deccbSFrançois Tigeot 264926deccbSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 265926deccbSFrançois Tigeot if (connector->encoder_ids[i] == 0) 266926deccbSFrançois Tigeot break; 267926deccbSFrançois Tigeot 268c6f73aabSFrançois Tigeot encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); 269c6f73aabSFrançois Tigeot if (!encoder) 270926deccbSFrançois Tigeot continue; 271926deccbSFrançois Tigeot 272926deccbSFrançois Tigeot if (encoder->encoder_type == encoder_type) 273926deccbSFrançois Tigeot return encoder; 274926deccbSFrançois Tigeot } 275926deccbSFrançois Tigeot return NULL; 276926deccbSFrançois Tigeot } 277926deccbSFrançois Tigeot 278c6f73aabSFrançois Tigeot struct edid *radeon_connector_edid(struct drm_connector *connector) 279c6f73aabSFrançois Tigeot { 280c6f73aabSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 281c6f73aabSFrançois Tigeot struct drm_property_blob *edid_blob = connector->edid_blob_ptr; 282c6f73aabSFrançois Tigeot 283c6f73aabSFrançois Tigeot if (radeon_connector->edid) { 284c6f73aabSFrançois Tigeot return radeon_connector->edid; 285c6f73aabSFrançois Tigeot } else if (edid_blob) { 286c6f73aabSFrançois Tigeot struct edid *edid = kmemdup(edid_blob->data, edid_blob->length, GFP_KERNEL); 287c6f73aabSFrançois Tigeot if (edid) 288c6f73aabSFrançois Tigeot radeon_connector->edid = edid; 289c6f73aabSFrançois Tigeot } 290c6f73aabSFrançois Tigeot return radeon_connector->edid; 291c6f73aabSFrançois Tigeot } 292c6f73aabSFrançois Tigeot 293ee479021SImre Vadász static void radeon_connector_get_edid(struct radeon_connector *radeon_connector) 2947191d616Szrj { 295ee479021SImre Vadász struct drm_device *dev = radeon_connector->base.dev; 2967191d616Szrj struct radeon_device *rdev = dev->dev_private; 2977191d616Szrj 2987191d616Szrj if (radeon_connector->edid) 2997191d616Szrj return; 3007191d616Szrj 3017191d616Szrj /* on hw with routers, select right port */ 3027191d616Szrj if (radeon_connector->router.ddc_valid) 3037191d616Szrj radeon_router_select_ddc_port(radeon_connector); 3047191d616Szrj 305ee479021SImre Vadász if (radeon_connector_encoder_get_dp_bridge_encoder_id(&radeon_connector->base) != 306ee479021SImre Vadász ENCODER_OBJECT_ID_NONE) { 307ee479021SImre Vadász struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; 308ee479021SImre Vadász 309ee479021SImre Vadász if (dig->dp_i2c_bus) 310ee479021SImre Vadász radeon_connector->edid = drm_get_edid_iic(&radeon_connector->base, 311ee479021SImre Vadász dig->dp_i2c_bus->adapter); 312ee479021SImre Vadász } else if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || 313ee479021SImre Vadász (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) { 3147191d616Szrj struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; 3157191d616Szrj 3167191d616Szrj if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT || 317ee479021SImre Vadász dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && dig->dp_i2c_bus) 3189f4ca867SFrançois Tigeot radeon_connector->edid = drm_get_edid_iic(&radeon_connector->base, 319ee479021SImre Vadász dig->dp_i2c_bus->adapter); 320ee479021SImre Vadász else if (radeon_connector->ddc_bus && !radeon_connector->edid) 3219f4ca867SFrançois Tigeot radeon_connector->edid = drm_get_edid_iic(&radeon_connector->base, 322ee479021SImre Vadász radeon_connector->ddc_bus->adapter); 3237191d616Szrj } else if (radeon_connector->ddc_bus) { 3249f4ca867SFrançois Tigeot radeon_connector->edid = drm_get_edid_iic(&radeon_connector->base, 325ee479021SImre Vadász radeon_connector->ddc_bus->adapter); 3267191d616Szrj } 3277191d616Szrj 3287191d616Szrj if (!radeon_connector->edid) { 329*1cfef1a5SFrançois Tigeot /* don't fetch the edid from the vbios if ddc fails and runpm is 330*1cfef1a5SFrançois Tigeot * enabled so we report disconnected. 331*1cfef1a5SFrançois Tigeot */ 332*1cfef1a5SFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0)) 333*1cfef1a5SFrançois Tigeot return; 334*1cfef1a5SFrançois Tigeot 3357191d616Szrj if (rdev->is_atom_bios) { 3367191d616Szrj /* some laptops provide a hardcoded edid in rom for LCDs */ 337ee479021SImre Vadász if (((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_LVDS) || 338ee479021SImre Vadász (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP))) 3397191d616Szrj radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev); 3407191d616Szrj } else { 3417191d616Szrj /* some servers provide a hardcoded edid in rom for KVMs */ 3427191d616Szrj radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev); 3437191d616Szrj } 3447191d616Szrj } 3457191d616Szrj } 3467191d616Szrj 347ee479021SImre Vadász static void radeon_connector_free_edid(struct radeon_connector *radeon_connector) 3487191d616Szrj { 3497191d616Szrj if (radeon_connector->edid) { 3507191d616Szrj kfree(radeon_connector->edid); 3517191d616Szrj radeon_connector->edid = NULL; 3527191d616Szrj } 3537191d616Szrj } 3547191d616Szrj 355ee479021SImre Vadász static int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) 3567191d616Szrj { 3577191d616Szrj int ret; 3587191d616Szrj 3597191d616Szrj if (radeon_connector->edid) { 360ee479021SImre Vadász drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); 361ee479021SImre Vadász ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); 362ee479021SImre Vadász drm_edid_to_eld(&radeon_connector->base, radeon_connector->edid); 3637191d616Szrj return ret; 3647191d616Szrj } 365ee479021SImre Vadász drm_mode_connector_update_edid_property(&radeon_connector->base, NULL); 3667191d616Szrj return 0; 3677191d616Szrj } 3687191d616Szrj 369926deccbSFrançois Tigeot static struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector) 370926deccbSFrançois Tigeot { 371926deccbSFrançois Tigeot int enc_id = connector->encoder_ids[0]; 372926deccbSFrançois Tigeot /* pick the encoder ids */ 373c6f73aabSFrançois Tigeot if (enc_id) 374c6f73aabSFrançois Tigeot return drm_encoder_find(connector->dev, enc_id); 375926deccbSFrançois Tigeot return NULL; 376926deccbSFrançois Tigeot } 377c6f73aabSFrançois Tigeot 378c6f73aabSFrançois Tigeot static void radeon_get_native_mode(struct drm_connector *connector) 379c6f73aabSFrançois Tigeot { 380c6f73aabSFrançois Tigeot struct drm_encoder *encoder = radeon_best_single_encoder(connector); 381c6f73aabSFrançois Tigeot struct radeon_encoder *radeon_encoder; 382c6f73aabSFrançois Tigeot 383c6f73aabSFrançois Tigeot if (encoder == NULL) 384c6f73aabSFrançois Tigeot return; 385c6f73aabSFrançois Tigeot 386c6f73aabSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 387c6f73aabSFrançois Tigeot 388c6f73aabSFrançois Tigeot if (!list_empty(&connector->probed_modes)) { 389c6f73aabSFrançois Tigeot struct drm_display_mode *preferred_mode = 390c6f73aabSFrançois Tigeot list_first_entry(&connector->probed_modes, 391c6f73aabSFrançois Tigeot struct drm_display_mode, head); 392c6f73aabSFrançois Tigeot 393c6f73aabSFrançois Tigeot radeon_encoder->native_mode = *preferred_mode; 394c6f73aabSFrançois Tigeot } else { 395c6f73aabSFrançois Tigeot radeon_encoder->native_mode.clock = 0; 396c6f73aabSFrançois Tigeot } 397926deccbSFrançois Tigeot } 398926deccbSFrançois Tigeot 399926deccbSFrançois Tigeot /* 400926deccbSFrançois Tigeot * radeon_connector_analog_encoder_conflict_solve 401926deccbSFrançois Tigeot * - search for other connectors sharing this encoder 402926deccbSFrançois Tigeot * if priority is true, then set them disconnected if this is connected 403926deccbSFrançois Tigeot * if priority is false, set us disconnected if they are connected 404926deccbSFrançois Tigeot */ 405926deccbSFrançois Tigeot static enum drm_connector_status 406926deccbSFrançois Tigeot radeon_connector_analog_encoder_conflict_solve(struct drm_connector *connector, 407926deccbSFrançois Tigeot struct drm_encoder *encoder, 408926deccbSFrançois Tigeot enum drm_connector_status current_status, 409926deccbSFrançois Tigeot bool priority) 410926deccbSFrançois Tigeot { 411926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 412926deccbSFrançois Tigeot struct drm_connector *conflict; 413926deccbSFrançois Tigeot struct radeon_connector *radeon_conflict; 414926deccbSFrançois Tigeot int i; 415926deccbSFrançois Tigeot 416926deccbSFrançois Tigeot list_for_each_entry(conflict, &dev->mode_config.connector_list, head) { 417926deccbSFrançois Tigeot if (conflict == connector) 418926deccbSFrançois Tigeot continue; 419926deccbSFrançois Tigeot 420926deccbSFrançois Tigeot radeon_conflict = to_radeon_connector(conflict); 421926deccbSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 422926deccbSFrançois Tigeot if (conflict->encoder_ids[i] == 0) 423926deccbSFrançois Tigeot break; 424926deccbSFrançois Tigeot 425926deccbSFrançois Tigeot /* if the IDs match */ 426926deccbSFrançois Tigeot if (conflict->encoder_ids[i] == encoder->base.id) { 427926deccbSFrançois Tigeot if (conflict->status != connector_status_connected) 428926deccbSFrançois Tigeot continue; 429926deccbSFrançois Tigeot 430926deccbSFrançois Tigeot if (radeon_conflict->use_digital) 431926deccbSFrançois Tigeot continue; 432926deccbSFrançois Tigeot 433926deccbSFrançois Tigeot if (priority == true) { 434ba55f2f5SFrançois Tigeot DRM_DEBUG_KMS("1: conflicting encoders switching off %s\n", 435ba55f2f5SFrançois Tigeot conflict->name); 436ba55f2f5SFrançois Tigeot DRM_DEBUG_KMS("in favor of %s\n", 437ba55f2f5SFrançois Tigeot connector->name); 438926deccbSFrançois Tigeot conflict->status = connector_status_disconnected; 439926deccbSFrançois Tigeot radeon_connector_update_scratch_regs(conflict, connector_status_disconnected); 440926deccbSFrançois Tigeot } else { 441ba55f2f5SFrançois Tigeot DRM_DEBUG_KMS("2: conflicting encoders switching off %s\n", 442ba55f2f5SFrançois Tigeot connector->name); 443ba55f2f5SFrançois Tigeot DRM_DEBUG_KMS("in favor of %s\n", 444ba55f2f5SFrançois Tigeot conflict->name); 445926deccbSFrançois Tigeot current_status = connector_status_disconnected; 446926deccbSFrançois Tigeot } 447926deccbSFrançois Tigeot break; 448926deccbSFrançois Tigeot } 449926deccbSFrançois Tigeot } 450926deccbSFrançois Tigeot } 451926deccbSFrançois Tigeot return current_status; 452926deccbSFrançois Tigeot 453926deccbSFrançois Tigeot } 454926deccbSFrançois Tigeot 455926deccbSFrançois Tigeot static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encoder) 456926deccbSFrançois Tigeot { 457926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 458926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 459926deccbSFrançois Tigeot struct drm_display_mode *mode = NULL; 460926deccbSFrançois Tigeot struct drm_display_mode *native_mode = &radeon_encoder->native_mode; 461926deccbSFrançois Tigeot 462926deccbSFrançois Tigeot if (native_mode->hdisplay != 0 && 463926deccbSFrançois Tigeot native_mode->vdisplay != 0 && 464926deccbSFrançois Tigeot native_mode->clock != 0) { 465926deccbSFrançois Tigeot mode = drm_mode_duplicate(dev, native_mode); 466926deccbSFrançois Tigeot mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; 467926deccbSFrançois Tigeot drm_mode_set_name(mode); 468926deccbSFrançois Tigeot 469926deccbSFrançois Tigeot DRM_DEBUG_KMS("Adding native panel mode %s\n", mode->name); 470926deccbSFrançois Tigeot } else if (native_mode->hdisplay != 0 && 471926deccbSFrançois Tigeot native_mode->vdisplay != 0) { 472926deccbSFrançois Tigeot /* mac laptops without an edid */ 473926deccbSFrançois Tigeot /* Note that this is not necessarily the exact panel mode, 474926deccbSFrançois Tigeot * but an approximation based on the cvt formula. For these 475926deccbSFrançois Tigeot * systems we should ideally read the mode info out of the 476926deccbSFrançois Tigeot * registers or add a mode table, but this works and is much 477926deccbSFrançois Tigeot * simpler. 478926deccbSFrançois Tigeot */ 479926deccbSFrançois Tigeot mode = drm_cvt_mode(dev, native_mode->hdisplay, native_mode->vdisplay, 60, true, false, false); 480926deccbSFrançois Tigeot mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; 481926deccbSFrançois Tigeot DRM_DEBUG_KMS("Adding cvt approximation of native panel mode %s\n", mode->name); 482926deccbSFrançois Tigeot } 483926deccbSFrançois Tigeot return mode; 484926deccbSFrançois Tigeot } 485926deccbSFrançois Tigeot 486926deccbSFrançois Tigeot static void radeon_add_common_modes(struct drm_encoder *encoder, struct drm_connector *connector) 487926deccbSFrançois Tigeot { 488926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 489926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 490926deccbSFrançois Tigeot struct drm_display_mode *mode = NULL; 491926deccbSFrançois Tigeot struct drm_display_mode *native_mode = &radeon_encoder->native_mode; 492926deccbSFrançois Tigeot int i; 493926deccbSFrançois Tigeot struct mode_size { 494926deccbSFrançois Tigeot int w; 495926deccbSFrançois Tigeot int h; 496926deccbSFrançois Tigeot } common_modes[17] = { 497926deccbSFrançois Tigeot { 640, 480}, 498926deccbSFrançois Tigeot { 720, 480}, 499926deccbSFrançois Tigeot { 800, 600}, 500926deccbSFrançois Tigeot { 848, 480}, 501926deccbSFrançois Tigeot {1024, 768}, 502926deccbSFrançois Tigeot {1152, 768}, 503926deccbSFrançois Tigeot {1280, 720}, 504926deccbSFrançois Tigeot {1280, 800}, 505926deccbSFrançois Tigeot {1280, 854}, 506926deccbSFrançois Tigeot {1280, 960}, 507926deccbSFrançois Tigeot {1280, 1024}, 508926deccbSFrançois Tigeot {1440, 900}, 509926deccbSFrançois Tigeot {1400, 1050}, 510926deccbSFrançois Tigeot {1680, 1050}, 511926deccbSFrançois Tigeot {1600, 1200}, 512926deccbSFrançois Tigeot {1920, 1080}, 513926deccbSFrançois Tigeot {1920, 1200} 514926deccbSFrançois Tigeot }; 515926deccbSFrançois Tigeot 516926deccbSFrançois Tigeot for (i = 0; i < 17; i++) { 517926deccbSFrançois Tigeot if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) { 518926deccbSFrançois Tigeot if (common_modes[i].w > 1024 || 519926deccbSFrançois Tigeot common_modes[i].h > 768) 520926deccbSFrançois Tigeot continue; 521926deccbSFrançois Tigeot } 522926deccbSFrançois Tigeot if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 523926deccbSFrançois Tigeot if (common_modes[i].w > native_mode->hdisplay || 524926deccbSFrançois Tigeot common_modes[i].h > native_mode->vdisplay || 525926deccbSFrançois Tigeot (common_modes[i].w == native_mode->hdisplay && 526926deccbSFrançois Tigeot common_modes[i].h == native_mode->vdisplay)) 527926deccbSFrançois Tigeot continue; 528926deccbSFrançois Tigeot } 529926deccbSFrançois Tigeot if (common_modes[i].w < 320 || common_modes[i].h < 200) 530926deccbSFrançois Tigeot continue; 531926deccbSFrançois Tigeot 532926deccbSFrançois Tigeot mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false); 533926deccbSFrançois Tigeot drm_mode_probed_add(connector, mode); 534926deccbSFrançois Tigeot } 535926deccbSFrançois Tigeot } 536926deccbSFrançois Tigeot 537926deccbSFrançois Tigeot static int radeon_connector_set_property(struct drm_connector *connector, struct drm_property *property, 538926deccbSFrançois Tigeot uint64_t val) 539926deccbSFrançois Tigeot { 540926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 541926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 542926deccbSFrançois Tigeot struct drm_encoder *encoder; 543926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder; 544926deccbSFrançois Tigeot 545926deccbSFrançois Tigeot if (property == rdev->mode_info.coherent_mode_property) { 546926deccbSFrançois Tigeot struct radeon_encoder_atom_dig *dig; 547926deccbSFrançois Tigeot bool new_coherent_mode; 548926deccbSFrançois Tigeot 549926deccbSFrançois Tigeot /* need to find digital encoder on connector */ 550926deccbSFrançois Tigeot encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS); 551926deccbSFrançois Tigeot if (!encoder) 552926deccbSFrançois Tigeot return 0; 553926deccbSFrançois Tigeot 554926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 555926deccbSFrançois Tigeot 556926deccbSFrançois Tigeot if (!radeon_encoder->enc_priv) 557926deccbSFrançois Tigeot return 0; 558926deccbSFrançois Tigeot 559926deccbSFrançois Tigeot dig = radeon_encoder->enc_priv; 560926deccbSFrançois Tigeot new_coherent_mode = val ? true : false; 561926deccbSFrançois Tigeot if (dig->coherent_mode != new_coherent_mode) { 562926deccbSFrançois Tigeot dig->coherent_mode = new_coherent_mode; 563926deccbSFrançois Tigeot radeon_property_change_mode(&radeon_encoder->base); 564926deccbSFrançois Tigeot } 565926deccbSFrançois Tigeot } 566926deccbSFrançois Tigeot 5674cd92098Szrj if (property == rdev->mode_info.audio_property) { 5684cd92098Szrj struct radeon_connector *radeon_connector = to_radeon_connector(connector); 5694cd92098Szrj /* need to find digital encoder on connector */ 5704cd92098Szrj encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS); 5714cd92098Szrj if (!encoder) 5724cd92098Szrj return 0; 5734cd92098Szrj 5744cd92098Szrj radeon_encoder = to_radeon_encoder(encoder); 5754cd92098Szrj 5764cd92098Szrj if (radeon_connector->audio != val) { 5774cd92098Szrj radeon_connector->audio = val; 5784cd92098Szrj radeon_property_change_mode(&radeon_encoder->base); 5794cd92098Szrj } 5804cd92098Szrj } 5814cd92098Szrj 582c6f73aabSFrançois Tigeot if (property == rdev->mode_info.dither_property) { 583c6f73aabSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 584c6f73aabSFrançois Tigeot /* need to find digital encoder on connector */ 585c6f73aabSFrançois Tigeot encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS); 586c6f73aabSFrançois Tigeot if (!encoder) 587c6f73aabSFrançois Tigeot return 0; 588c6f73aabSFrançois Tigeot 589c6f73aabSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 590c6f73aabSFrançois Tigeot 591c6f73aabSFrançois Tigeot if (radeon_connector->dither != val) { 592c6f73aabSFrançois Tigeot radeon_connector->dither = val; 593c6f73aabSFrançois Tigeot radeon_property_change_mode(&radeon_encoder->base); 594c6f73aabSFrançois Tigeot } 595c6f73aabSFrançois Tigeot } 596c6f73aabSFrançois Tigeot 597926deccbSFrançois Tigeot if (property == rdev->mode_info.underscan_property) { 598926deccbSFrançois Tigeot /* need to find digital encoder on connector */ 599926deccbSFrançois Tigeot encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS); 600926deccbSFrançois Tigeot if (!encoder) 601926deccbSFrançois Tigeot return 0; 602926deccbSFrançois Tigeot 603926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 604926deccbSFrançois Tigeot 605926deccbSFrançois Tigeot if (radeon_encoder->underscan_type != val) { 606926deccbSFrançois Tigeot radeon_encoder->underscan_type = val; 607926deccbSFrançois Tigeot radeon_property_change_mode(&radeon_encoder->base); 608926deccbSFrançois Tigeot } 609926deccbSFrançois Tigeot } 610926deccbSFrançois Tigeot 611926deccbSFrançois Tigeot if (property == rdev->mode_info.underscan_hborder_property) { 612926deccbSFrançois Tigeot /* need to find digital encoder on connector */ 613926deccbSFrançois Tigeot encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS); 614926deccbSFrançois Tigeot if (!encoder) 615926deccbSFrançois Tigeot return 0; 616926deccbSFrançois Tigeot 617926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 618926deccbSFrançois Tigeot 619926deccbSFrançois Tigeot if (radeon_encoder->underscan_hborder != val) { 620926deccbSFrançois Tigeot radeon_encoder->underscan_hborder = val; 621926deccbSFrançois Tigeot radeon_property_change_mode(&radeon_encoder->base); 622926deccbSFrançois Tigeot } 623926deccbSFrançois Tigeot } 624926deccbSFrançois Tigeot 625926deccbSFrançois Tigeot if (property == rdev->mode_info.underscan_vborder_property) { 626926deccbSFrançois Tigeot /* need to find digital encoder on connector */ 627926deccbSFrançois Tigeot encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS); 628926deccbSFrançois Tigeot if (!encoder) 629926deccbSFrançois Tigeot return 0; 630926deccbSFrançois Tigeot 631926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 632926deccbSFrançois Tigeot 633926deccbSFrançois Tigeot if (radeon_encoder->underscan_vborder != val) { 634926deccbSFrançois Tigeot radeon_encoder->underscan_vborder = val; 635926deccbSFrançois Tigeot radeon_property_change_mode(&radeon_encoder->base); 636926deccbSFrançois Tigeot } 637926deccbSFrançois Tigeot } 638926deccbSFrançois Tigeot 639926deccbSFrançois Tigeot if (property == rdev->mode_info.tv_std_property) { 640926deccbSFrançois Tigeot encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TVDAC); 641926deccbSFrançois Tigeot if (!encoder) { 642926deccbSFrançois Tigeot encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_DAC); 643926deccbSFrançois Tigeot } 644926deccbSFrançois Tigeot 645926deccbSFrançois Tigeot if (!encoder) 646926deccbSFrançois Tigeot return 0; 647926deccbSFrançois Tigeot 648926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 649926deccbSFrançois Tigeot if (!radeon_encoder->enc_priv) 650926deccbSFrançois Tigeot return 0; 651926deccbSFrançois Tigeot if (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom) { 652926deccbSFrançois Tigeot struct radeon_encoder_atom_dac *dac_int; 653926deccbSFrançois Tigeot dac_int = radeon_encoder->enc_priv; 654926deccbSFrançois Tigeot dac_int->tv_std = val; 655926deccbSFrançois Tigeot } else { 656926deccbSFrançois Tigeot struct radeon_encoder_tv_dac *dac_int; 657926deccbSFrançois Tigeot dac_int = radeon_encoder->enc_priv; 658926deccbSFrançois Tigeot dac_int->tv_std = val; 659926deccbSFrançois Tigeot } 660926deccbSFrançois Tigeot radeon_property_change_mode(&radeon_encoder->base); 661926deccbSFrançois Tigeot } 662926deccbSFrançois Tigeot 663926deccbSFrançois Tigeot if (property == rdev->mode_info.load_detect_property) { 664926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = 665926deccbSFrançois Tigeot to_radeon_connector(connector); 666926deccbSFrançois Tigeot 667926deccbSFrançois Tigeot if (val == 0) 668926deccbSFrançois Tigeot radeon_connector->dac_load_detect = false; 669926deccbSFrançois Tigeot else 670926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 671926deccbSFrançois Tigeot } 672926deccbSFrançois Tigeot 673926deccbSFrançois Tigeot if (property == rdev->mode_info.tmds_pll_property) { 674926deccbSFrançois Tigeot struct radeon_encoder_int_tmds *tmds = NULL; 675926deccbSFrançois Tigeot bool ret = false; 676926deccbSFrançois Tigeot /* need to find digital encoder on connector */ 677926deccbSFrançois Tigeot encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS); 678926deccbSFrançois Tigeot if (!encoder) 679926deccbSFrançois Tigeot return 0; 680926deccbSFrançois Tigeot 681926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 682926deccbSFrançois Tigeot 683926deccbSFrançois Tigeot tmds = radeon_encoder->enc_priv; 684926deccbSFrançois Tigeot if (!tmds) 685926deccbSFrançois Tigeot return 0; 686926deccbSFrançois Tigeot 687926deccbSFrançois Tigeot if (val == 0) { 688926deccbSFrançois Tigeot if (rdev->is_atom_bios) 689926deccbSFrançois Tigeot ret = radeon_atombios_get_tmds_info(radeon_encoder, tmds); 690926deccbSFrançois Tigeot else 691926deccbSFrançois Tigeot ret = radeon_legacy_get_tmds_info_from_combios(radeon_encoder, tmds); 692926deccbSFrançois Tigeot } 693926deccbSFrançois Tigeot if (val == 1 || ret == false) { 694926deccbSFrançois Tigeot radeon_legacy_get_tmds_info_from_table(radeon_encoder, tmds); 695926deccbSFrançois Tigeot } 696926deccbSFrançois Tigeot radeon_property_change_mode(&radeon_encoder->base); 697926deccbSFrançois Tigeot } 698926deccbSFrançois Tigeot 699c6f73aabSFrançois Tigeot if (property == dev->mode_config.scaling_mode_property) { 700c6f73aabSFrançois Tigeot enum radeon_rmx_type rmx_type; 701c6f73aabSFrançois Tigeot 702c6f73aabSFrançois Tigeot if (connector->encoder) 703c6f73aabSFrançois Tigeot radeon_encoder = to_radeon_encoder(connector->encoder); 704c6f73aabSFrançois Tigeot else { 705c0e85e96SFrançois Tigeot const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; 706c6f73aabSFrançois Tigeot radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector)); 707c6f73aabSFrançois Tigeot } 708c6f73aabSFrançois Tigeot 709c6f73aabSFrançois Tigeot switch (val) { 710c6f73aabSFrançois Tigeot default: 711c6f73aabSFrançois Tigeot case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break; 712c6f73aabSFrançois Tigeot case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break; 713c6f73aabSFrançois Tigeot case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break; 714c6f73aabSFrançois Tigeot case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break; 715c6f73aabSFrançois Tigeot } 716c6f73aabSFrançois Tigeot if (radeon_encoder->rmx_type == rmx_type) 717c6f73aabSFrançois Tigeot return 0; 718c6f73aabSFrançois Tigeot 719c6f73aabSFrançois Tigeot if ((rmx_type != DRM_MODE_SCALE_NONE) && 720c6f73aabSFrançois Tigeot (radeon_encoder->native_mode.clock == 0)) 721c6f73aabSFrançois Tigeot return 0; 722c6f73aabSFrançois Tigeot 723c6f73aabSFrançois Tigeot radeon_encoder->rmx_type = rmx_type; 724c6f73aabSFrançois Tigeot 725c6f73aabSFrançois Tigeot radeon_property_change_mode(&radeon_encoder->base); 726c6f73aabSFrançois Tigeot } 727c6f73aabSFrançois Tigeot 728926deccbSFrançois Tigeot return 0; 729926deccbSFrançois Tigeot } 730926deccbSFrançois Tigeot 731926deccbSFrançois Tigeot static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder, 732926deccbSFrançois Tigeot struct drm_connector *connector) 733926deccbSFrançois Tigeot { 734926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 735926deccbSFrançois Tigeot struct drm_display_mode *native_mode = &radeon_encoder->native_mode; 736926deccbSFrançois Tigeot struct drm_display_mode *t, *mode; 737926deccbSFrançois Tigeot 738926deccbSFrançois Tigeot /* If the EDID preferred mode doesn't match the native mode, use it */ 739926deccbSFrançois Tigeot list_for_each_entry_safe(mode, t, &connector->probed_modes, head) { 740926deccbSFrançois Tigeot if (mode->type & DRM_MODE_TYPE_PREFERRED) { 741926deccbSFrançois Tigeot if (mode->hdisplay != native_mode->hdisplay || 742926deccbSFrançois Tigeot mode->vdisplay != native_mode->vdisplay) 743926deccbSFrançois Tigeot memcpy(native_mode, mode, sizeof(*mode)); 744926deccbSFrançois Tigeot } 745926deccbSFrançois Tigeot } 746926deccbSFrançois Tigeot 747926deccbSFrançois Tigeot /* Try to get native mode details from EDID if necessary */ 748926deccbSFrançois Tigeot if (!native_mode->clock) { 749926deccbSFrançois Tigeot list_for_each_entry_safe(mode, t, &connector->probed_modes, head) { 750926deccbSFrançois Tigeot if (mode->hdisplay == native_mode->hdisplay && 751926deccbSFrançois Tigeot mode->vdisplay == native_mode->vdisplay) { 752926deccbSFrançois Tigeot *native_mode = *mode; 753926deccbSFrançois Tigeot drm_mode_set_crtcinfo(native_mode, CRTC_INTERLACE_HALVE_V); 754926deccbSFrançois Tigeot DRM_DEBUG_KMS("Determined LVDS native mode details from EDID\n"); 755926deccbSFrançois Tigeot break; 756926deccbSFrançois Tigeot } 757926deccbSFrançois Tigeot } 758926deccbSFrançois Tigeot } 759926deccbSFrançois Tigeot 760926deccbSFrançois Tigeot if (!native_mode->clock) { 761926deccbSFrançois Tigeot DRM_DEBUG_KMS("No LVDS native mode details, disabling RMX\n"); 762926deccbSFrançois Tigeot radeon_encoder->rmx_type = RMX_OFF; 763926deccbSFrançois Tigeot } 764926deccbSFrançois Tigeot } 765926deccbSFrançois Tigeot 766926deccbSFrançois Tigeot static int radeon_lvds_get_modes(struct drm_connector *connector) 767926deccbSFrançois Tigeot { 768ee479021SImre Vadász struct radeon_connector *radeon_connector = to_radeon_connector(connector); 769926deccbSFrançois Tigeot struct drm_encoder *encoder; 770926deccbSFrançois Tigeot int ret = 0; 771926deccbSFrançois Tigeot struct drm_display_mode *mode; 772926deccbSFrançois Tigeot 773ee479021SImre Vadász if (radeon_connector->ddc_bus) { 774ee479021SImre Vadász radeon_connector_get_edid(radeon_connector); 775ee479021SImre Vadász ret = radeon_ddc_get_modes(radeon_connector); 776926deccbSFrançois Tigeot if (ret > 0) { 777926deccbSFrançois Tigeot encoder = radeon_best_single_encoder(connector); 778926deccbSFrançois Tigeot if (encoder) { 779926deccbSFrançois Tigeot radeon_fixup_lvds_native_mode(encoder, connector); 780926deccbSFrançois Tigeot /* add scaled modes */ 781926deccbSFrançois Tigeot radeon_add_common_modes(encoder, connector); 782926deccbSFrançois Tigeot } 783926deccbSFrançois Tigeot return ret; 784926deccbSFrançois Tigeot } 785ee479021SImre Vadász } 786926deccbSFrançois Tigeot 787926deccbSFrançois Tigeot encoder = radeon_best_single_encoder(connector); 788926deccbSFrançois Tigeot if (!encoder) 789926deccbSFrançois Tigeot return 0; 790926deccbSFrançois Tigeot 791926deccbSFrançois Tigeot /* we have no EDID modes */ 792926deccbSFrançois Tigeot mode = radeon_fp_native_mode(encoder); 793926deccbSFrançois Tigeot if (mode) { 794926deccbSFrançois Tigeot ret = 1; 795926deccbSFrançois Tigeot drm_mode_probed_add(connector, mode); 796926deccbSFrançois Tigeot /* add the width/height from vbios tables if available */ 797926deccbSFrançois Tigeot connector->display_info.width_mm = mode->width_mm; 798926deccbSFrançois Tigeot connector->display_info.height_mm = mode->height_mm; 799926deccbSFrançois Tigeot /* add scaled modes */ 800926deccbSFrançois Tigeot radeon_add_common_modes(encoder, connector); 801926deccbSFrançois Tigeot } 802926deccbSFrançois Tigeot 803926deccbSFrançois Tigeot return ret; 804926deccbSFrançois Tigeot } 805926deccbSFrançois Tigeot 806926deccbSFrançois Tigeot static int radeon_lvds_mode_valid(struct drm_connector *connector, 807926deccbSFrançois Tigeot struct drm_display_mode *mode) 808926deccbSFrançois Tigeot { 809926deccbSFrançois Tigeot struct drm_encoder *encoder = radeon_best_single_encoder(connector); 810926deccbSFrançois Tigeot 811926deccbSFrançois Tigeot if ((mode->hdisplay < 320) || (mode->vdisplay < 240)) 812926deccbSFrançois Tigeot return MODE_PANEL; 813926deccbSFrançois Tigeot 814926deccbSFrançois Tigeot if (encoder) { 815926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 816926deccbSFrançois Tigeot struct drm_display_mode *native_mode = &radeon_encoder->native_mode; 817926deccbSFrançois Tigeot 818926deccbSFrançois Tigeot /* AVIVO hardware supports downscaling modes larger than the panel 819926deccbSFrançois Tigeot * to the panel size, but I'm not sure this is desirable. 820926deccbSFrançois Tigeot */ 821926deccbSFrançois Tigeot if ((mode->hdisplay > native_mode->hdisplay) || 822926deccbSFrançois Tigeot (mode->vdisplay > native_mode->vdisplay)) 823926deccbSFrançois Tigeot return MODE_PANEL; 824926deccbSFrançois Tigeot 825926deccbSFrançois Tigeot /* if scaling is disabled, block non-native modes */ 826926deccbSFrançois Tigeot if (radeon_encoder->rmx_type == RMX_OFF) { 827926deccbSFrançois Tigeot if ((mode->hdisplay != native_mode->hdisplay) || 828926deccbSFrançois Tigeot (mode->vdisplay != native_mode->vdisplay)) 829926deccbSFrançois Tigeot return MODE_PANEL; 830926deccbSFrançois Tigeot } 831926deccbSFrançois Tigeot } 832926deccbSFrançois Tigeot 833926deccbSFrançois Tigeot return MODE_OK; 834926deccbSFrançois Tigeot } 835926deccbSFrançois Tigeot 836926deccbSFrançois Tigeot static enum drm_connector_status 837926deccbSFrançois Tigeot radeon_lvds_detect(struct drm_connector *connector, bool force) 838926deccbSFrançois Tigeot { 839*1cfef1a5SFrançois Tigeot struct drm_device *dev = connector->dev; 840*1cfef1a5SFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 841926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 842926deccbSFrançois Tigeot struct drm_encoder *encoder = radeon_best_single_encoder(connector); 843926deccbSFrançois Tigeot enum drm_connector_status ret = connector_status_disconnected; 844c6f73aabSFrançois Tigeot #ifdef PM_TODO 845c6f73aabSFrançois Tigeot int r; 846c6f73aabSFrançois Tigeot 847c6f73aabSFrançois Tigeot r = pm_runtime_get_sync(connector->dev->dev); 848c6f73aabSFrançois Tigeot if (r < 0) 849c6f73aabSFrançois Tigeot return connector_status_disconnected; 850c6f73aabSFrançois Tigeot #endif 851926deccbSFrançois Tigeot 852926deccbSFrançois Tigeot if (encoder) { 853926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 854926deccbSFrançois Tigeot struct drm_display_mode *native_mode = &radeon_encoder->native_mode; 855926deccbSFrançois Tigeot 856926deccbSFrançois Tigeot /* check if panel is valid */ 857926deccbSFrançois Tigeot if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240) 858926deccbSFrançois Tigeot ret = connector_status_connected; 859*1cfef1a5SFrançois Tigeot /* don't fetch the edid from the vbios if ddc fails and runpm is 860*1cfef1a5SFrançois Tigeot * enabled so we report disconnected. 861*1cfef1a5SFrançois Tigeot */ 862*1cfef1a5SFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0)) 863*1cfef1a5SFrançois Tigeot ret = connector_status_disconnected; 864926deccbSFrançois Tigeot } 865926deccbSFrançois Tigeot 866926deccbSFrançois Tigeot /* check for edid as well */ 867ee479021SImre Vadász radeon_connector_get_edid(radeon_connector); 868926deccbSFrançois Tigeot if (radeon_connector->edid) 869926deccbSFrançois Tigeot ret = connector_status_connected; 870926deccbSFrançois Tigeot else { 871926deccbSFrançois Tigeot if (radeon_connector->ddc_bus) { 8729f4ca867SFrançois Tigeot radeon_connector->edid = drm_get_edid_iic(&radeon_connector->base, 873ee479021SImre Vadász radeon_connector->ddc_bus->adapter); 874926deccbSFrançois Tigeot if (radeon_connector->edid) 875926deccbSFrançois Tigeot ret = connector_status_connected; 876926deccbSFrançois Tigeot } 877926deccbSFrançois Tigeot } 878926deccbSFrançois Tigeot /* check acpi lid status ??? */ 879926deccbSFrançois Tigeot 880926deccbSFrançois Tigeot radeon_connector_update_scratch_regs(connector, ret); 881c6f73aabSFrançois Tigeot #ifdef PM_TODO 882c6f73aabSFrançois Tigeot pm_runtime_mark_last_busy(connector->dev->dev); 883c6f73aabSFrançois Tigeot pm_runtime_put_autosuspend(connector->dev->dev); 884c6f73aabSFrançois Tigeot #endif 885926deccbSFrançois Tigeot return ret; 886926deccbSFrançois Tigeot } 887926deccbSFrançois Tigeot 888926deccbSFrançois Tigeot static void radeon_connector_destroy(struct drm_connector *connector) 889926deccbSFrançois Tigeot { 890926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 891926deccbSFrançois Tigeot 892ee479021SImre Vadász radeon_connector_free_edid(radeon_connector); 893c4ef309bSzrj kfree(radeon_connector->con_priv); 894c6f73aabSFrançois Tigeot drm_connector_unregister(connector); 895926deccbSFrançois Tigeot drm_connector_cleanup(connector); 896c4ef309bSzrj kfree(connector); 897926deccbSFrançois Tigeot } 898926deccbSFrançois Tigeot 899926deccbSFrançois Tigeot static int radeon_lvds_set_property(struct drm_connector *connector, 900926deccbSFrançois Tigeot struct drm_property *property, 901926deccbSFrançois Tigeot uint64_t value) 902926deccbSFrançois Tigeot { 903926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 904926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder; 905926deccbSFrançois Tigeot enum radeon_rmx_type rmx_type; 906926deccbSFrançois Tigeot 907926deccbSFrançois Tigeot DRM_DEBUG_KMS("\n"); 908926deccbSFrançois Tigeot if (property != dev->mode_config.scaling_mode_property) 909926deccbSFrançois Tigeot return 0; 910926deccbSFrançois Tigeot 911926deccbSFrançois Tigeot if (connector->encoder) 912926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(connector->encoder); 913926deccbSFrançois Tigeot else { 914c0e85e96SFrançois Tigeot const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; 915926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector)); 916926deccbSFrançois Tigeot } 917926deccbSFrançois Tigeot 918926deccbSFrançois Tigeot switch (value) { 919926deccbSFrançois Tigeot case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break; 920926deccbSFrançois Tigeot case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break; 921926deccbSFrançois Tigeot case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break; 922926deccbSFrançois Tigeot default: 923926deccbSFrançois Tigeot case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break; 924926deccbSFrançois Tigeot } 925926deccbSFrançois Tigeot if (radeon_encoder->rmx_type == rmx_type) 926926deccbSFrançois Tigeot return 0; 927926deccbSFrançois Tigeot 928926deccbSFrançois Tigeot radeon_encoder->rmx_type = rmx_type; 929926deccbSFrançois Tigeot 930926deccbSFrançois Tigeot radeon_property_change_mode(&radeon_encoder->base); 931926deccbSFrançois Tigeot return 0; 932926deccbSFrançois Tigeot } 933926deccbSFrançois Tigeot 934926deccbSFrançois Tigeot 935926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_lvds_connector_helper_funcs = { 936926deccbSFrançois Tigeot .get_modes = radeon_lvds_get_modes, 937926deccbSFrançois Tigeot .mode_valid = radeon_lvds_mode_valid, 938926deccbSFrançois Tigeot .best_encoder = radeon_best_single_encoder, 939926deccbSFrançois Tigeot }; 940926deccbSFrançois Tigeot 941926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_lvds_connector_funcs = { 942926deccbSFrançois Tigeot .dpms = drm_helper_connector_dpms, 943926deccbSFrançois Tigeot .detect = radeon_lvds_detect, 944926deccbSFrançois Tigeot .fill_modes = drm_helper_probe_single_connector_modes, 945926deccbSFrançois Tigeot .destroy = radeon_connector_destroy, 946926deccbSFrançois Tigeot .set_property = radeon_lvds_set_property, 947926deccbSFrançois Tigeot }; 948926deccbSFrançois Tigeot 949926deccbSFrançois Tigeot static int radeon_vga_get_modes(struct drm_connector *connector) 950926deccbSFrançois Tigeot { 951ee479021SImre Vadász struct radeon_connector *radeon_connector = to_radeon_connector(connector); 952926deccbSFrançois Tigeot int ret; 953926deccbSFrançois Tigeot 954ee479021SImre Vadász radeon_connector_get_edid(radeon_connector); 955ee479021SImre Vadász ret = radeon_ddc_get_modes(radeon_connector); 956926deccbSFrançois Tigeot 957c6f73aabSFrançois Tigeot radeon_get_native_mode(connector); 958c6f73aabSFrançois Tigeot 959926deccbSFrançois Tigeot return ret; 960926deccbSFrançois Tigeot } 961926deccbSFrançois Tigeot 962926deccbSFrançois Tigeot static int radeon_vga_mode_valid(struct drm_connector *connector, 963926deccbSFrançois Tigeot struct drm_display_mode *mode) 964926deccbSFrançois Tigeot { 965926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 966926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 967926deccbSFrançois Tigeot 968926deccbSFrançois Tigeot /* XXX check mode bandwidth */ 969926deccbSFrançois Tigeot 970926deccbSFrançois Tigeot if ((mode->clock / 10) > rdev->clock.max_pixel_clock) 971926deccbSFrançois Tigeot return MODE_CLOCK_HIGH; 972926deccbSFrançois Tigeot 973926deccbSFrançois Tigeot return MODE_OK; 974926deccbSFrançois Tigeot } 975926deccbSFrançois Tigeot 976926deccbSFrançois Tigeot static enum drm_connector_status 977926deccbSFrançois Tigeot radeon_vga_detect(struct drm_connector *connector, bool force) 978926deccbSFrançois Tigeot { 979926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 980926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 981926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 982926deccbSFrançois Tigeot struct drm_encoder *encoder; 983c0e85e96SFrançois Tigeot const struct drm_encoder_helper_funcs *encoder_funcs; 984926deccbSFrançois Tigeot bool dret = false; 985926deccbSFrançois Tigeot enum drm_connector_status ret = connector_status_disconnected; 986c6f73aabSFrançois Tigeot #ifdef PM_TODO 987c6f73aabSFrançois Tigeot int r; 988c6f73aabSFrançois Tigeot 989c6f73aabSFrançois Tigeot r = pm_runtime_get_sync(connector->dev->dev); 990c6f73aabSFrançois Tigeot if (r < 0) 991c6f73aabSFrançois Tigeot return connector_status_disconnected; 992c6f73aabSFrançois Tigeot #endif 993926deccbSFrançois Tigeot 994926deccbSFrançois Tigeot encoder = radeon_best_single_encoder(connector); 995926deccbSFrançois Tigeot if (!encoder) 996926deccbSFrançois Tigeot ret = connector_status_disconnected; 997926deccbSFrançois Tigeot 998926deccbSFrançois Tigeot if (radeon_connector->ddc_bus) 999926deccbSFrançois Tigeot dret = radeon_ddc_probe(radeon_connector, false); 1000926deccbSFrançois Tigeot if (dret) { 1001926deccbSFrançois Tigeot radeon_connector->detected_by_load = false; 1002ee479021SImre Vadász radeon_connector_free_edid(radeon_connector); 1003ee479021SImre Vadász radeon_connector_get_edid(radeon_connector); 1004926deccbSFrançois Tigeot 1005926deccbSFrançois Tigeot if (!radeon_connector->edid) { 1006926deccbSFrançois Tigeot DRM_ERROR("%s: probed a monitor but no|invalid EDID\n", 1007ba55f2f5SFrançois Tigeot connector->name); 1008926deccbSFrançois Tigeot ret = connector_status_connected; 1009926deccbSFrançois Tigeot } else { 10107191d616Szrj radeon_connector->use_digital = 10117191d616Szrj !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); 1012926deccbSFrançois Tigeot 1013926deccbSFrançois Tigeot /* some oems have boards with separate digital and analog connectors 1014926deccbSFrançois Tigeot * with a shared ddc line (often vga + hdmi) 1015926deccbSFrançois Tigeot */ 1016926deccbSFrançois Tigeot if (radeon_connector->use_digital && radeon_connector->shared_ddc) { 1017ee479021SImre Vadász radeon_connector_free_edid(radeon_connector); 1018926deccbSFrançois Tigeot ret = connector_status_disconnected; 10197191d616Szrj } else { 1020926deccbSFrançois Tigeot ret = connector_status_connected; 1021926deccbSFrançois Tigeot } 10227191d616Szrj } 1023926deccbSFrançois Tigeot } else { 1024926deccbSFrançois Tigeot 1025926deccbSFrançois Tigeot /* if we aren't forcing don't do destructive polling */ 1026926deccbSFrançois Tigeot if (!force) { 1027926deccbSFrançois Tigeot /* only return the previous status if we last 1028926deccbSFrançois Tigeot * detected a monitor via load. 1029926deccbSFrançois Tigeot */ 1030926deccbSFrançois Tigeot if (radeon_connector->detected_by_load) 1031c6f73aabSFrançois Tigeot ret = connector->status; 1032c6f73aabSFrançois Tigeot goto out; 1033926deccbSFrançois Tigeot } 1034926deccbSFrançois Tigeot 1035926deccbSFrançois Tigeot if (radeon_connector->dac_load_detect && encoder) { 1036926deccbSFrançois Tigeot encoder_funcs = encoder->helper_private; 1037926deccbSFrançois Tigeot ret = encoder_funcs->detect(encoder, connector); 1038926deccbSFrançois Tigeot if (ret != connector_status_disconnected) 1039926deccbSFrançois Tigeot radeon_connector->detected_by_load = true; 1040926deccbSFrançois Tigeot } 1041926deccbSFrançois Tigeot } 1042926deccbSFrançois Tigeot 1043926deccbSFrançois Tigeot if (ret == connector_status_connected) 1044926deccbSFrançois Tigeot ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true); 1045926deccbSFrançois Tigeot 1046926deccbSFrançois Tigeot /* RN50 and some RV100 asics in servers often have a hardcoded EDID in the 1047926deccbSFrançois Tigeot * vbios to deal with KVMs. If we have one and are not able to detect a monitor 1048926deccbSFrançois Tigeot * by other means, assume the CRT is connected and use that EDID. 1049926deccbSFrançois Tigeot */ 1050926deccbSFrançois Tigeot if ((!rdev->is_atom_bios) && 1051926deccbSFrançois Tigeot (ret == connector_status_disconnected) && 1052926deccbSFrançois Tigeot rdev->mode_info.bios_hardcoded_edid_size) { 1053926deccbSFrançois Tigeot ret = connector_status_connected; 1054926deccbSFrançois Tigeot } 1055926deccbSFrançois Tigeot 1056926deccbSFrançois Tigeot radeon_connector_update_scratch_regs(connector, ret); 1057c6f73aabSFrançois Tigeot 1058c6f73aabSFrançois Tigeot out: 1059c6f73aabSFrançois Tigeot #ifdef PM_TODO 1060c6f73aabSFrançois Tigeot pm_runtime_mark_last_busy(connector->dev->dev); 1061c6f73aabSFrançois Tigeot pm_runtime_put_autosuspend(connector->dev->dev); 1062c6f73aabSFrançois Tigeot #endif 1063c6f73aabSFrançois Tigeot 1064926deccbSFrançois Tigeot return ret; 1065926deccbSFrançois Tigeot } 1066926deccbSFrançois Tigeot 1067926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_vga_connector_helper_funcs = { 1068926deccbSFrançois Tigeot .get_modes = radeon_vga_get_modes, 1069926deccbSFrançois Tigeot .mode_valid = radeon_vga_mode_valid, 1070926deccbSFrançois Tigeot .best_encoder = radeon_best_single_encoder, 1071926deccbSFrançois Tigeot }; 1072926deccbSFrançois Tigeot 1073926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_vga_connector_funcs = { 1074926deccbSFrançois Tigeot .dpms = drm_helper_connector_dpms, 1075926deccbSFrançois Tigeot .detect = radeon_vga_detect, 1076926deccbSFrançois Tigeot .fill_modes = drm_helper_probe_single_connector_modes, 1077926deccbSFrançois Tigeot .destroy = radeon_connector_destroy, 1078926deccbSFrançois Tigeot .set_property = radeon_connector_set_property, 1079926deccbSFrançois Tigeot }; 1080926deccbSFrançois Tigeot 1081926deccbSFrançois Tigeot static int radeon_tv_get_modes(struct drm_connector *connector) 1082926deccbSFrançois Tigeot { 1083926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 1084926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1085926deccbSFrançois Tigeot struct drm_display_mode *tv_mode; 1086926deccbSFrançois Tigeot struct drm_encoder *encoder; 1087926deccbSFrançois Tigeot 1088926deccbSFrançois Tigeot encoder = radeon_best_single_encoder(connector); 1089926deccbSFrançois Tigeot if (!encoder) 1090926deccbSFrançois Tigeot return 0; 1091926deccbSFrançois Tigeot 1092926deccbSFrançois Tigeot /* avivo chips can scale any mode */ 1093926deccbSFrançois Tigeot if (rdev->family >= CHIP_RS600) 1094926deccbSFrançois Tigeot /* add scaled modes */ 1095926deccbSFrançois Tigeot radeon_add_common_modes(encoder, connector); 1096926deccbSFrançois Tigeot else { 1097926deccbSFrançois Tigeot /* only 800x600 is supported right now on pre-avivo chips */ 1098926deccbSFrançois Tigeot tv_mode = drm_cvt_mode(dev, 800, 600, 60, false, false, false); 1099926deccbSFrançois Tigeot tv_mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 1100926deccbSFrançois Tigeot drm_mode_probed_add(connector, tv_mode); 1101926deccbSFrançois Tigeot } 1102926deccbSFrançois Tigeot return 1; 1103926deccbSFrançois Tigeot } 1104926deccbSFrançois Tigeot 1105926deccbSFrançois Tigeot static int radeon_tv_mode_valid(struct drm_connector *connector, 1106926deccbSFrançois Tigeot struct drm_display_mode *mode) 1107926deccbSFrançois Tigeot { 1108926deccbSFrançois Tigeot if ((mode->hdisplay > 1024) || (mode->vdisplay > 768)) 1109926deccbSFrançois Tigeot return MODE_CLOCK_RANGE; 1110926deccbSFrançois Tigeot return MODE_OK; 1111926deccbSFrançois Tigeot } 1112926deccbSFrançois Tigeot 1113926deccbSFrançois Tigeot static enum drm_connector_status 1114926deccbSFrançois Tigeot radeon_tv_detect(struct drm_connector *connector, bool force) 1115926deccbSFrançois Tigeot { 1116926deccbSFrançois Tigeot struct drm_encoder *encoder; 1117c0e85e96SFrançois Tigeot const struct drm_encoder_helper_funcs *encoder_funcs; 1118926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1119926deccbSFrançois Tigeot enum drm_connector_status ret = connector_status_disconnected; 1120c6f73aabSFrançois Tigeot #ifdef PM_TODO 1121c6f73aabSFrançois Tigeot int r; 1122c6f73aabSFrançois Tigeot #endif 1123926deccbSFrançois Tigeot 1124926deccbSFrançois Tigeot if (!radeon_connector->dac_load_detect) 1125926deccbSFrançois Tigeot return ret; 1126926deccbSFrançois Tigeot 1127c6f73aabSFrançois Tigeot #ifdef PM_TODO 1128c6f73aabSFrançois Tigeot r = pm_runtime_get_sync(connector->dev->dev); 1129c6f73aabSFrançois Tigeot if (r < 0) 1130c6f73aabSFrançois Tigeot return connector_status_disconnected; 1131c6f73aabSFrançois Tigeot #endif 1132c6f73aabSFrançois Tigeot 1133926deccbSFrançois Tigeot encoder = radeon_best_single_encoder(connector); 1134926deccbSFrançois Tigeot if (!encoder) 1135926deccbSFrançois Tigeot ret = connector_status_disconnected; 1136926deccbSFrançois Tigeot else { 1137926deccbSFrançois Tigeot encoder_funcs = encoder->helper_private; 1138926deccbSFrançois Tigeot ret = encoder_funcs->detect(encoder, connector); 1139926deccbSFrançois Tigeot } 1140926deccbSFrançois Tigeot if (ret == connector_status_connected) 1141926deccbSFrançois Tigeot ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false); 1142926deccbSFrançois Tigeot radeon_connector_update_scratch_regs(connector, ret); 1143c6f73aabSFrançois Tigeot #ifdef PM_TODO 1144c6f73aabSFrançois Tigeot pm_runtime_mark_last_busy(connector->dev->dev); 1145c6f73aabSFrançois Tigeot pm_runtime_put_autosuspend(connector->dev->dev); 1146c6f73aabSFrançois Tigeot #endif 1147926deccbSFrançois Tigeot return ret; 1148926deccbSFrançois Tigeot } 1149926deccbSFrançois Tigeot 1150926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_tv_connector_helper_funcs = { 1151926deccbSFrançois Tigeot .get_modes = radeon_tv_get_modes, 1152926deccbSFrançois Tigeot .mode_valid = radeon_tv_mode_valid, 1153926deccbSFrançois Tigeot .best_encoder = radeon_best_single_encoder, 1154926deccbSFrançois Tigeot }; 1155926deccbSFrançois Tigeot 1156926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_tv_connector_funcs = { 1157926deccbSFrançois Tigeot .dpms = drm_helper_connector_dpms, 1158926deccbSFrançois Tigeot .detect = radeon_tv_detect, 1159926deccbSFrançois Tigeot .fill_modes = drm_helper_probe_single_connector_modes, 1160926deccbSFrançois Tigeot .destroy = radeon_connector_destroy, 1161926deccbSFrançois Tigeot .set_property = radeon_connector_set_property, 1162926deccbSFrançois Tigeot }; 1163926deccbSFrançois Tigeot 1164926deccbSFrançois Tigeot static bool radeon_check_hpd_status_unchanged(struct drm_connector *connector) 1165926deccbSFrançois Tigeot { 1166926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 1167926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1168926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1169926deccbSFrançois Tigeot enum drm_connector_status status; 1170926deccbSFrançois Tigeot 1171926deccbSFrançois Tigeot /* We only trust HPD on R600 and newer ASICS. */ 1172926deccbSFrançois Tigeot if (rdev->family >= CHIP_R600 1173926deccbSFrançois Tigeot && radeon_connector->hpd.hpd != RADEON_HPD_NONE) { 1174926deccbSFrançois Tigeot if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) 1175926deccbSFrançois Tigeot status = connector_status_connected; 1176926deccbSFrançois Tigeot else 1177926deccbSFrançois Tigeot status = connector_status_disconnected; 1178926deccbSFrançois Tigeot if (connector->status == status) 1179926deccbSFrançois Tigeot return true; 1180926deccbSFrançois Tigeot } 1181926deccbSFrançois Tigeot 1182926deccbSFrançois Tigeot return false; 1183926deccbSFrançois Tigeot } 1184926deccbSFrançois Tigeot 1185926deccbSFrançois Tigeot /* 1186926deccbSFrançois Tigeot * DVI is complicated 1187926deccbSFrançois Tigeot * Do a DDC probe, if DDC probe passes, get the full EDID so 1188926deccbSFrançois Tigeot * we can do analog/digital monitor detection at this point. 1189926deccbSFrançois Tigeot * If the monitor is an analog monitor or we got no DDC, 1190926deccbSFrançois Tigeot * we need to find the DAC encoder object for this connector. 1191926deccbSFrançois Tigeot * If we got no DDC, we do load detection on the DAC encoder object. 1192926deccbSFrançois Tigeot * If we got analog DDC or load detection passes on the DAC encoder 1193926deccbSFrançois Tigeot * we have to check if this analog encoder is shared with anyone else (TV) 1194926deccbSFrançois Tigeot * if its shared we have to set the other connector to disconnected. 1195926deccbSFrançois Tigeot */ 1196926deccbSFrançois Tigeot static enum drm_connector_status 1197926deccbSFrançois Tigeot radeon_dvi_detect(struct drm_connector *connector, bool force) 1198926deccbSFrançois Tigeot { 1199926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 1200926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1201926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1202926deccbSFrançois Tigeot struct drm_encoder *encoder = NULL; 1203c0e85e96SFrançois Tigeot const struct drm_encoder_helper_funcs *encoder_funcs; 1204926deccbSFrançois Tigeot int i; 1205926deccbSFrançois Tigeot enum drm_connector_status ret = connector_status_disconnected; 1206926deccbSFrançois Tigeot bool dret = false, broken_edid = false; 1207926deccbSFrançois Tigeot 1208c6f73aabSFrançois Tigeot #ifdef PM_TODO 1209c6f73aabSFrançois Tigeot r = pm_runtime_get_sync(connector->dev->dev); 1210c6f73aabSFrançois Tigeot if (r < 0) 1211c6f73aabSFrançois Tigeot return connector_status_disconnected; 1212c6f73aabSFrançois Tigeot #endif 1213c6f73aabSFrançois Tigeot 1214c6f73aabSFrançois Tigeot if (!force && radeon_check_hpd_status_unchanged(connector)) { 1215c6f73aabSFrançois Tigeot ret = connector->status; 1216c6f73aabSFrançois Tigeot goto exit; 1217c6f73aabSFrançois Tigeot } 1218926deccbSFrançois Tigeot 1219926deccbSFrançois Tigeot if (radeon_connector->ddc_bus) 1220926deccbSFrançois Tigeot dret = radeon_ddc_probe(radeon_connector, false); 1221926deccbSFrançois Tigeot if (dret) { 1222926deccbSFrançois Tigeot radeon_connector->detected_by_load = false; 1223ee479021SImre Vadász radeon_connector_free_edid(radeon_connector); 1224ee479021SImre Vadász radeon_connector_get_edid(radeon_connector); 1225926deccbSFrançois Tigeot 1226926deccbSFrançois Tigeot if (!radeon_connector->edid) { 1227926deccbSFrançois Tigeot DRM_ERROR("%s: probed a monitor but no|invalid EDID\n", 1228ba55f2f5SFrançois Tigeot connector->name); 1229926deccbSFrançois Tigeot /* rs690 seems to have a problem with connectors not existing and always 1230926deccbSFrançois Tigeot * return a block of 0's. If we see this just stop polling on this output */ 12317191d616Szrj if ((rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) && 12327191d616Szrj radeon_connector->base.null_edid_counter) { 1233926deccbSFrançois Tigeot ret = connector_status_disconnected; 1234ba55f2f5SFrançois Tigeot DRM_ERROR("%s: detected RS690 floating bus bug, stopping ddc detect\n", 1235ba55f2f5SFrançois Tigeot connector->name); 1236926deccbSFrançois Tigeot radeon_connector->ddc_bus = NULL; 1237926deccbSFrançois Tigeot } else { 1238926deccbSFrançois Tigeot ret = connector_status_connected; 1239926deccbSFrançois Tigeot broken_edid = true; /* defer use_digital to later */ 1240926deccbSFrançois Tigeot } 1241926deccbSFrançois Tigeot } else { 12427191d616Szrj radeon_connector->use_digital = 12437191d616Szrj !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); 1244926deccbSFrançois Tigeot 1245926deccbSFrançois Tigeot /* some oems have boards with separate digital and analog connectors 1246926deccbSFrançois Tigeot * with a shared ddc line (often vga + hdmi) 1247926deccbSFrançois Tigeot */ 1248926deccbSFrançois Tigeot if ((!radeon_connector->use_digital) && radeon_connector->shared_ddc) { 1249ee479021SImre Vadász radeon_connector_free_edid(radeon_connector); 1250926deccbSFrançois Tigeot ret = connector_status_disconnected; 12517191d616Szrj } else { 1252926deccbSFrançois Tigeot ret = connector_status_connected; 12537191d616Szrj } 1254926deccbSFrançois Tigeot /* This gets complicated. We have boards with VGA + HDMI with a 1255926deccbSFrançois Tigeot * shared DDC line and we have boards with DVI-D + HDMI with a shared 1256926deccbSFrançois Tigeot * DDC line. The latter is more complex because with DVI<->HDMI adapters 1257926deccbSFrançois Tigeot * you don't really know what's connected to which port as both are digital. 1258926deccbSFrançois Tigeot */ 1259926deccbSFrançois Tigeot if (radeon_connector->shared_ddc && (ret == connector_status_connected)) { 1260926deccbSFrançois Tigeot struct drm_connector *list_connector; 1261926deccbSFrançois Tigeot struct radeon_connector *list_radeon_connector; 1262926deccbSFrançois Tigeot list_for_each_entry(list_connector, &dev->mode_config.connector_list, head) { 1263926deccbSFrançois Tigeot if (connector == list_connector) 1264926deccbSFrançois Tigeot continue; 1265926deccbSFrançois Tigeot list_radeon_connector = to_radeon_connector(list_connector); 1266926deccbSFrançois Tigeot if (list_radeon_connector->shared_ddc && 1267926deccbSFrançois Tigeot (list_radeon_connector->ddc_bus->rec.i2c_id == 1268926deccbSFrançois Tigeot radeon_connector->ddc_bus->rec.i2c_id)) { 1269926deccbSFrançois Tigeot /* cases where both connectors are digital */ 1270926deccbSFrançois Tigeot if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) { 1271926deccbSFrançois Tigeot /* hpd is our only option in this case */ 1272926deccbSFrançois Tigeot if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) { 1273ee479021SImre Vadász radeon_connector_free_edid(radeon_connector); 1274926deccbSFrançois Tigeot ret = connector_status_disconnected; 1275926deccbSFrançois Tigeot } 1276926deccbSFrançois Tigeot } 1277926deccbSFrançois Tigeot } 1278926deccbSFrançois Tigeot } 1279926deccbSFrançois Tigeot } 1280926deccbSFrançois Tigeot } 1281926deccbSFrançois Tigeot } 1282926deccbSFrançois Tigeot 1283926deccbSFrançois Tigeot if ((ret == connector_status_connected) && (radeon_connector->use_digital == true)) 1284926deccbSFrançois Tigeot goto out; 1285926deccbSFrançois Tigeot 1286926deccbSFrançois Tigeot /* DVI-D and HDMI-A are digital only */ 1287926deccbSFrançois Tigeot if ((connector->connector_type == DRM_MODE_CONNECTOR_DVID) || 1288926deccbSFrançois Tigeot (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)) 1289926deccbSFrançois Tigeot goto out; 1290926deccbSFrançois Tigeot 1291926deccbSFrançois Tigeot /* if we aren't forcing don't do destructive polling */ 1292926deccbSFrançois Tigeot if (!force) { 1293926deccbSFrançois Tigeot /* only return the previous status if we last 1294926deccbSFrançois Tigeot * detected a monitor via load. 1295926deccbSFrançois Tigeot */ 1296926deccbSFrançois Tigeot if (radeon_connector->detected_by_load) 1297926deccbSFrançois Tigeot ret = connector->status; 1298926deccbSFrançois Tigeot goto out; 1299926deccbSFrançois Tigeot } 1300926deccbSFrançois Tigeot 1301926deccbSFrançois Tigeot /* find analog encoder */ 1302926deccbSFrançois Tigeot if (radeon_connector->dac_load_detect) { 1303926deccbSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 1304926deccbSFrançois Tigeot if (connector->encoder_ids[i] == 0) 1305926deccbSFrançois Tigeot break; 1306926deccbSFrançois Tigeot 1307c6f73aabSFrançois Tigeot encoder = drm_encoder_find(connector->dev, 1308c6f73aabSFrançois Tigeot connector->encoder_ids[i]); 1309c6f73aabSFrançois Tigeot if (!encoder) 1310926deccbSFrançois Tigeot continue; 1311926deccbSFrançois Tigeot 1312926deccbSFrançois Tigeot if (encoder->encoder_type != DRM_MODE_ENCODER_DAC && 1313926deccbSFrançois Tigeot encoder->encoder_type != DRM_MODE_ENCODER_TVDAC) 1314926deccbSFrançois Tigeot continue; 1315926deccbSFrançois Tigeot 1316926deccbSFrançois Tigeot encoder_funcs = encoder->helper_private; 1317926deccbSFrançois Tigeot if (encoder_funcs->detect) { 1318926deccbSFrançois Tigeot if (!broken_edid) { 1319926deccbSFrançois Tigeot if (ret != connector_status_connected) { 1320926deccbSFrançois Tigeot /* deal with analog monitors without DDC */ 1321926deccbSFrançois Tigeot ret = encoder_funcs->detect(encoder, connector); 1322926deccbSFrançois Tigeot if (ret == connector_status_connected) { 1323926deccbSFrançois Tigeot radeon_connector->use_digital = false; 1324926deccbSFrançois Tigeot } 1325926deccbSFrançois Tigeot if (ret != connector_status_disconnected) 1326926deccbSFrançois Tigeot radeon_connector->detected_by_load = true; 1327926deccbSFrançois Tigeot } 1328926deccbSFrançois Tigeot } else { 1329926deccbSFrançois Tigeot enum drm_connector_status lret; 1330926deccbSFrançois Tigeot /* assume digital unless load detected otherwise */ 1331926deccbSFrançois Tigeot radeon_connector->use_digital = true; 1332926deccbSFrançois Tigeot lret = encoder_funcs->detect(encoder, connector); 1333926deccbSFrançois Tigeot DRM_DEBUG_KMS("load_detect %x returned: %x\n",encoder->encoder_type,lret); 1334926deccbSFrançois Tigeot if (lret == connector_status_connected) 1335926deccbSFrançois Tigeot radeon_connector->use_digital = false; 1336926deccbSFrançois Tigeot } 1337926deccbSFrançois Tigeot break; 1338926deccbSFrançois Tigeot } 1339926deccbSFrançois Tigeot } 1340926deccbSFrançois Tigeot } 1341926deccbSFrançois Tigeot 1342926deccbSFrançois Tigeot if ((ret == connector_status_connected) && (radeon_connector->use_digital == false) && 1343926deccbSFrançois Tigeot encoder) { 1344926deccbSFrançois Tigeot ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true); 1345926deccbSFrançois Tigeot } 1346926deccbSFrançois Tigeot 1347926deccbSFrançois Tigeot /* RN50 and some RV100 asics in servers often have a hardcoded EDID in the 1348926deccbSFrançois Tigeot * vbios to deal with KVMs. If we have one and are not able to detect a monitor 1349926deccbSFrançois Tigeot * by other means, assume the DFP is connected and use that EDID. In most 1350926deccbSFrançois Tigeot * cases the DVI port is actually a virtual KVM port connected to the service 1351926deccbSFrançois Tigeot * processor. 1352926deccbSFrançois Tigeot */ 1353926deccbSFrançois Tigeot out: 1354926deccbSFrançois Tigeot if ((!rdev->is_atom_bios) && 1355926deccbSFrançois Tigeot (ret == connector_status_disconnected) && 1356926deccbSFrançois Tigeot rdev->mode_info.bios_hardcoded_edid_size) { 1357926deccbSFrançois Tigeot radeon_connector->use_digital = true; 1358926deccbSFrançois Tigeot ret = connector_status_connected; 1359926deccbSFrançois Tigeot } 1360926deccbSFrançois Tigeot 1361926deccbSFrançois Tigeot /* updated in get modes as well since we need to know if it's analog or digital */ 1362926deccbSFrançois Tigeot radeon_connector_update_scratch_regs(connector, ret); 1363c6f73aabSFrançois Tigeot 1364c6f73aabSFrançois Tigeot exit: 1365c6f73aabSFrançois Tigeot #ifdef PM_TODO 1366c6f73aabSFrançois Tigeot pm_runtime_mark_last_busy(connector->dev->dev); 1367c6f73aabSFrançois Tigeot pm_runtime_put_autosuspend(connector->dev->dev); 1368c6f73aabSFrançois Tigeot #endif 1369c6f73aabSFrançois Tigeot 1370926deccbSFrançois Tigeot return ret; 1371926deccbSFrançois Tigeot } 1372926deccbSFrançois Tigeot 1373926deccbSFrançois Tigeot /* okay need to be smart in here about which encoder to pick */ 1374926deccbSFrançois Tigeot static struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector) 1375926deccbSFrançois Tigeot { 1376926deccbSFrançois Tigeot int enc_id = connector->encoder_ids[0]; 1377926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1378926deccbSFrançois Tigeot struct drm_encoder *encoder; 1379926deccbSFrançois Tigeot int i; 1380926deccbSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 1381926deccbSFrançois Tigeot if (connector->encoder_ids[i] == 0) 1382926deccbSFrançois Tigeot break; 1383926deccbSFrançois Tigeot 1384c6f73aabSFrançois Tigeot encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); 1385c6f73aabSFrançois Tigeot if (!encoder) 1386926deccbSFrançois Tigeot continue; 1387926deccbSFrançois Tigeot 1388926deccbSFrançois Tigeot if (radeon_connector->use_digital == true) { 1389926deccbSFrançois Tigeot if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS) 1390926deccbSFrançois Tigeot return encoder; 1391926deccbSFrançois Tigeot } else { 1392926deccbSFrançois Tigeot if (encoder->encoder_type == DRM_MODE_ENCODER_DAC || 1393926deccbSFrançois Tigeot encoder->encoder_type == DRM_MODE_ENCODER_TVDAC) 1394926deccbSFrançois Tigeot return encoder; 1395926deccbSFrançois Tigeot } 1396926deccbSFrançois Tigeot } 1397926deccbSFrançois Tigeot 1398926deccbSFrançois Tigeot /* see if we have a default encoder TODO */ 1399926deccbSFrançois Tigeot 1400926deccbSFrançois Tigeot /* then check use digitial */ 1401926deccbSFrançois Tigeot /* pick the first one */ 1402c6f73aabSFrançois Tigeot if (enc_id) 1403c6f73aabSFrançois Tigeot return drm_encoder_find(connector->dev, enc_id); 1404926deccbSFrançois Tigeot return NULL; 1405926deccbSFrançois Tigeot } 1406926deccbSFrançois Tigeot 1407926deccbSFrançois Tigeot static void radeon_dvi_force(struct drm_connector *connector) 1408926deccbSFrançois Tigeot { 1409926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1410926deccbSFrançois Tigeot if (connector->force == DRM_FORCE_ON) 1411926deccbSFrançois Tigeot radeon_connector->use_digital = false; 1412926deccbSFrançois Tigeot if (connector->force == DRM_FORCE_ON_DIGITAL) 1413926deccbSFrançois Tigeot radeon_connector->use_digital = true; 1414926deccbSFrançois Tigeot } 1415926deccbSFrançois Tigeot 1416926deccbSFrançois Tigeot static int radeon_dvi_mode_valid(struct drm_connector *connector, 1417926deccbSFrançois Tigeot struct drm_display_mode *mode) 1418926deccbSFrançois Tigeot { 1419926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 1420926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1421926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1422926deccbSFrançois Tigeot 1423926deccbSFrançois Tigeot /* XXX check mode bandwidth */ 1424926deccbSFrançois Tigeot 1425926deccbSFrançois Tigeot /* clocks over 135 MHz have heat issues with DVI on RV100 */ 1426926deccbSFrançois Tigeot if (radeon_connector->use_digital && 1427926deccbSFrançois Tigeot (rdev->family == CHIP_RV100) && 1428926deccbSFrançois Tigeot (mode->clock > 135000)) 1429926deccbSFrançois Tigeot return MODE_CLOCK_HIGH; 1430926deccbSFrançois Tigeot 1431926deccbSFrançois Tigeot if (radeon_connector->use_digital && (mode->clock > 165000)) { 1432926deccbSFrançois Tigeot if ((radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I) || 1433926deccbSFrançois Tigeot (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D) || 1434926deccbSFrançois Tigeot (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_B)) 1435926deccbSFrançois Tigeot return MODE_OK; 1436c6f73aabSFrançois Tigeot else if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { 1437926deccbSFrançois Tigeot /* HDMI 1.3+ supports max clock of 340 Mhz */ 1438926deccbSFrançois Tigeot if (mode->clock > 340000) 1439926deccbSFrançois Tigeot return MODE_CLOCK_HIGH; 1440926deccbSFrançois Tigeot else 1441926deccbSFrançois Tigeot return MODE_OK; 1442c6f73aabSFrançois Tigeot } else { 1443926deccbSFrançois Tigeot return MODE_CLOCK_HIGH; 1444c6f73aabSFrançois Tigeot } 1445926deccbSFrançois Tigeot } 1446926deccbSFrançois Tigeot 1447926deccbSFrançois Tigeot /* check against the max pixel clock */ 1448926deccbSFrançois Tigeot if ((mode->clock / 10) > rdev->clock.max_pixel_clock) 1449926deccbSFrançois Tigeot return MODE_CLOCK_HIGH; 1450926deccbSFrançois Tigeot 1451926deccbSFrançois Tigeot return MODE_OK; 1452926deccbSFrançois Tigeot } 1453926deccbSFrançois Tigeot 1454926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = { 1455c6f73aabSFrançois Tigeot .get_modes = radeon_vga_get_modes, 1456926deccbSFrançois Tigeot .mode_valid = radeon_dvi_mode_valid, 1457926deccbSFrançois Tigeot .best_encoder = radeon_dvi_encoder, 1458926deccbSFrançois Tigeot }; 1459926deccbSFrançois Tigeot 1460926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_dvi_connector_funcs = { 1461926deccbSFrançois Tigeot .dpms = drm_helper_connector_dpms, 1462926deccbSFrançois Tigeot .detect = radeon_dvi_detect, 1463926deccbSFrançois Tigeot .fill_modes = drm_helper_probe_single_connector_modes, 1464926deccbSFrançois Tigeot .set_property = radeon_connector_set_property, 1465926deccbSFrançois Tigeot .destroy = radeon_connector_destroy, 1466926deccbSFrançois Tigeot .force = radeon_dvi_force, 1467926deccbSFrançois Tigeot }; 1468926deccbSFrançois Tigeot 1469ee479021SImre Vadász static void radeon_dp_connector_destroy(struct drm_connector *connector) 1470ee479021SImre Vadász { 1471ee479021SImre Vadász struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1472ee479021SImre Vadász struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; 1473ee479021SImre Vadász 1474ee479021SImre Vadász radeon_connector_free_edid(radeon_connector); 1475ee479021SImre Vadász if (radeon_dig_connector->dp_i2c_bus) 1476ee479021SImre Vadász radeon_i2c_destroy(radeon_dig_connector->dp_i2c_bus); 1477ee479021SImre Vadász kfree(radeon_connector->con_priv); 1478ee479021SImre Vadász drm_connector_unregister(connector); 1479ee479021SImre Vadász drm_connector_cleanup(connector); 1480ee479021SImre Vadász kfree(connector); 1481ee479021SImre Vadász } 1482ee479021SImre Vadász 1483926deccbSFrançois Tigeot static int radeon_dp_get_modes(struct drm_connector *connector) 1484926deccbSFrançois Tigeot { 1485926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1486926deccbSFrançois Tigeot struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; 1487926deccbSFrançois Tigeot struct drm_encoder *encoder = radeon_best_single_encoder(connector); 1488926deccbSFrançois Tigeot int ret; 1489926deccbSFrançois Tigeot 1490926deccbSFrançois Tigeot if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) || 1491926deccbSFrançois Tigeot (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) { 1492926deccbSFrançois Tigeot struct drm_display_mode *mode; 1493926deccbSFrançois Tigeot 1494926deccbSFrançois Tigeot if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { 1495926deccbSFrançois Tigeot if (!radeon_dig_connector->edp_on) 1496926deccbSFrançois Tigeot atombios_set_edp_panel_power(connector, 1497926deccbSFrançois Tigeot ATOM_TRANSMITTER_ACTION_POWER_ON); 1498ee479021SImre Vadász radeon_connector_get_edid(radeon_connector); 1499ee479021SImre Vadász ret = radeon_ddc_get_modes(radeon_connector); 1500926deccbSFrançois Tigeot if (!radeon_dig_connector->edp_on) 1501926deccbSFrançois Tigeot atombios_set_edp_panel_power(connector, 1502926deccbSFrançois Tigeot ATOM_TRANSMITTER_ACTION_POWER_OFF); 1503926deccbSFrançois Tigeot } else { 1504926deccbSFrançois Tigeot /* need to setup ddc on the bridge */ 1505926deccbSFrançois Tigeot if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) != 1506926deccbSFrançois Tigeot ENCODER_OBJECT_ID_NONE) { 1507926deccbSFrançois Tigeot if (encoder) 1508926deccbSFrançois Tigeot radeon_atom_ext_encoder_setup_ddc(encoder); 1509926deccbSFrançois Tigeot } 1510ee479021SImre Vadász radeon_connector_get_edid(radeon_connector); 1511ee479021SImre Vadász ret = radeon_ddc_get_modes(radeon_connector); 1512926deccbSFrançois Tigeot } 1513926deccbSFrançois Tigeot 1514926deccbSFrançois Tigeot if (ret > 0) { 1515926deccbSFrançois Tigeot if (encoder) { 1516926deccbSFrançois Tigeot radeon_fixup_lvds_native_mode(encoder, connector); 1517926deccbSFrançois Tigeot /* add scaled modes */ 1518926deccbSFrançois Tigeot radeon_add_common_modes(encoder, connector); 1519926deccbSFrançois Tigeot } 1520926deccbSFrançois Tigeot return ret; 1521926deccbSFrançois Tigeot } 1522926deccbSFrançois Tigeot 1523926deccbSFrançois Tigeot if (!encoder) 1524926deccbSFrançois Tigeot return 0; 1525926deccbSFrançois Tigeot 1526926deccbSFrançois Tigeot /* we have no EDID modes */ 1527926deccbSFrançois Tigeot mode = radeon_fp_native_mode(encoder); 1528926deccbSFrançois Tigeot if (mode) { 1529926deccbSFrançois Tigeot ret = 1; 1530926deccbSFrançois Tigeot drm_mode_probed_add(connector, mode); 1531926deccbSFrançois Tigeot /* add the width/height from vbios tables if available */ 1532926deccbSFrançois Tigeot connector->display_info.width_mm = mode->width_mm; 1533926deccbSFrançois Tigeot connector->display_info.height_mm = mode->height_mm; 1534926deccbSFrançois Tigeot /* add scaled modes */ 1535926deccbSFrançois Tigeot radeon_add_common_modes(encoder, connector); 1536926deccbSFrançois Tigeot } 1537926deccbSFrançois Tigeot } else { 1538926deccbSFrançois Tigeot /* need to setup ddc on the bridge */ 1539926deccbSFrançois Tigeot if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) != 1540926deccbSFrançois Tigeot ENCODER_OBJECT_ID_NONE) { 1541926deccbSFrançois Tigeot if (encoder) 1542926deccbSFrançois Tigeot radeon_atom_ext_encoder_setup_ddc(encoder); 1543926deccbSFrançois Tigeot } 1544ee479021SImre Vadász radeon_connector_get_edid(radeon_connector); 1545ee479021SImre Vadász ret = radeon_ddc_get_modes(radeon_connector); 1546c6f73aabSFrançois Tigeot 1547c6f73aabSFrançois Tigeot radeon_get_native_mode(connector); 1548926deccbSFrançois Tigeot } 1549926deccbSFrançois Tigeot 1550926deccbSFrançois Tigeot return ret; 1551926deccbSFrançois Tigeot } 1552926deccbSFrançois Tigeot 1553926deccbSFrançois Tigeot u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector) 1554926deccbSFrançois Tigeot { 1555926deccbSFrançois Tigeot struct drm_encoder *encoder; 1556926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder; 1557926deccbSFrançois Tigeot int i; 1558926deccbSFrançois Tigeot 1559926deccbSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 1560926deccbSFrançois Tigeot if (connector->encoder_ids[i] == 0) 1561926deccbSFrançois Tigeot break; 1562926deccbSFrançois Tigeot 1563c6f73aabSFrançois Tigeot encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); 1564c6f73aabSFrançois Tigeot if (!encoder) 1565926deccbSFrançois Tigeot continue; 1566926deccbSFrançois Tigeot 1567926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 1568926deccbSFrançois Tigeot 1569926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 1570926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_TRAVIS: 1571926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_NUTMEG: 1572926deccbSFrançois Tigeot return radeon_encoder->encoder_id; 1573926deccbSFrançois Tigeot default: 1574926deccbSFrançois Tigeot break; 1575926deccbSFrançois Tigeot } 1576926deccbSFrançois Tigeot } 1577926deccbSFrançois Tigeot 1578926deccbSFrançois Tigeot return ENCODER_OBJECT_ID_NONE; 1579926deccbSFrançois Tigeot } 1580926deccbSFrançois Tigeot 1581c6f73aabSFrançois Tigeot static bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector) 1582926deccbSFrançois Tigeot { 1583926deccbSFrançois Tigeot struct drm_encoder *encoder; 1584926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder; 1585926deccbSFrançois Tigeot int i; 1586926deccbSFrançois Tigeot bool found = false; 1587926deccbSFrançois Tigeot 1588926deccbSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 1589926deccbSFrançois Tigeot if (connector->encoder_ids[i] == 0) 1590926deccbSFrançois Tigeot break; 1591926deccbSFrançois Tigeot 1592c6f73aabSFrançois Tigeot encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); 1593c6f73aabSFrançois Tigeot if (!encoder) 1594926deccbSFrançois Tigeot continue; 1595926deccbSFrançois Tigeot 1596926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 1597926deccbSFrançois Tigeot if (radeon_encoder->caps & ATOM_ENCODER_CAP_RECORD_HBR2) 1598926deccbSFrançois Tigeot found = true; 1599926deccbSFrançois Tigeot } 1600926deccbSFrançois Tigeot 1601926deccbSFrançois Tigeot return found; 1602926deccbSFrançois Tigeot } 1603926deccbSFrançois Tigeot 1604926deccbSFrançois Tigeot bool radeon_connector_is_dp12_capable(struct drm_connector *connector) 1605926deccbSFrançois Tigeot { 1606926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 1607926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1608926deccbSFrançois Tigeot 1609926deccbSFrançois Tigeot if (ASIC_IS_DCE5(rdev) && 1610c6f73aabSFrançois Tigeot (rdev->clock.default_dispclk >= 53900) && 1611926deccbSFrançois Tigeot radeon_connector_encoder_is_hbr2(connector)) { 1612926deccbSFrançois Tigeot return true; 1613926deccbSFrançois Tigeot } 1614926deccbSFrançois Tigeot 1615926deccbSFrançois Tigeot return false; 1616926deccbSFrançois Tigeot } 1617926deccbSFrançois Tigeot 1618926deccbSFrançois Tigeot static enum drm_connector_status 1619926deccbSFrançois Tigeot radeon_dp_detect(struct drm_connector *connector, bool force) 1620926deccbSFrançois Tigeot { 1621926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 1622926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1623926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1624926deccbSFrançois Tigeot enum drm_connector_status ret = connector_status_disconnected; 1625926deccbSFrançois Tigeot struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; 1626926deccbSFrançois Tigeot struct drm_encoder *encoder = radeon_best_single_encoder(connector); 1627c6f73aabSFrançois Tigeot #ifdef PM_TODO 1628c6f73aabSFrançois Tigeot int r; 1629926deccbSFrançois Tigeot 1630c6f73aabSFrançois Tigeot r = pm_runtime_get_sync(connector->dev->dev); 1631c6f73aabSFrançois Tigeot if (r < 0) 1632c6f73aabSFrançois Tigeot return connector_status_disconnected; 1633c6f73aabSFrançois Tigeot #endif 1634c6f73aabSFrançois Tigeot 1635c6f73aabSFrançois Tigeot if (!force && radeon_check_hpd_status_unchanged(connector)) { 1636c6f73aabSFrançois Tigeot ret = connector->status; 1637c6f73aabSFrançois Tigeot goto out; 1638c6f73aabSFrançois Tigeot } 1639926deccbSFrançois Tigeot 1640ee479021SImre Vadász radeon_connector_free_edid(radeon_connector); 1641926deccbSFrançois Tigeot 1642926deccbSFrançois Tigeot if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) || 1643926deccbSFrançois Tigeot (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) { 1644926deccbSFrançois Tigeot if (encoder) { 1645926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 1646926deccbSFrançois Tigeot struct drm_display_mode *native_mode = &radeon_encoder->native_mode; 1647926deccbSFrançois Tigeot 1648926deccbSFrançois Tigeot /* check if panel is valid */ 1649926deccbSFrançois Tigeot if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240) 1650926deccbSFrançois Tigeot ret = connector_status_connected; 1651*1cfef1a5SFrançois Tigeot /* don't fetch the edid from the vbios if ddc fails and runpm is 1652*1cfef1a5SFrançois Tigeot * enabled so we report disconnected. 1653*1cfef1a5SFrançois Tigeot */ 1654*1cfef1a5SFrançois Tigeot if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0)) 1655*1cfef1a5SFrançois Tigeot ret = connector_status_disconnected; 1656926deccbSFrançois Tigeot } 1657926deccbSFrançois Tigeot /* eDP is always DP */ 1658926deccbSFrançois Tigeot radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT; 1659926deccbSFrançois Tigeot if (!radeon_dig_connector->edp_on) 1660926deccbSFrançois Tigeot atombios_set_edp_panel_power(connector, 1661926deccbSFrançois Tigeot ATOM_TRANSMITTER_ACTION_POWER_ON); 1662926deccbSFrançois Tigeot if (radeon_dp_getdpcd(radeon_connector)) 1663926deccbSFrançois Tigeot ret = connector_status_connected; 1664926deccbSFrançois Tigeot if (!radeon_dig_connector->edp_on) 1665926deccbSFrançois Tigeot atombios_set_edp_panel_power(connector, 1666926deccbSFrançois Tigeot ATOM_TRANSMITTER_ACTION_POWER_OFF); 1667926deccbSFrançois Tigeot } else if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) != 1668926deccbSFrançois Tigeot ENCODER_OBJECT_ID_NONE) { 1669926deccbSFrançois Tigeot /* DP bridges are always DP */ 1670926deccbSFrançois Tigeot radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT; 1671926deccbSFrançois Tigeot /* get the DPCD from the bridge */ 1672926deccbSFrançois Tigeot radeon_dp_getdpcd(radeon_connector); 1673926deccbSFrançois Tigeot 1674926deccbSFrançois Tigeot if (encoder) { 1675926deccbSFrançois Tigeot /* setup ddc on the bridge */ 1676926deccbSFrançois Tigeot radeon_atom_ext_encoder_setup_ddc(encoder); 1677926deccbSFrançois Tigeot /* bridge chips are always aux */ 1678926deccbSFrançois Tigeot if (radeon_ddc_probe(radeon_connector, true)) /* try DDC */ 1679926deccbSFrançois Tigeot ret = connector_status_connected; 1680926deccbSFrançois Tigeot else if (radeon_connector->dac_load_detect) { /* try load detection */ 1681c0e85e96SFrançois Tigeot const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; 1682926deccbSFrançois Tigeot ret = encoder_funcs->detect(encoder, connector); 1683926deccbSFrançois Tigeot } 1684926deccbSFrançois Tigeot } 1685926deccbSFrançois Tigeot } else { 1686926deccbSFrançois Tigeot radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector); 1687926deccbSFrançois Tigeot if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) { 1688926deccbSFrançois Tigeot ret = connector_status_connected; 1689926deccbSFrançois Tigeot if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) 1690926deccbSFrançois Tigeot radeon_dp_getdpcd(radeon_connector); 1691926deccbSFrançois Tigeot } else { 1692926deccbSFrançois Tigeot if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { 1693926deccbSFrançois Tigeot if (radeon_dp_getdpcd(radeon_connector)) 1694926deccbSFrançois Tigeot ret = connector_status_connected; 1695926deccbSFrançois Tigeot } else { 16964cd92098Szrj /* try non-aux ddc (DP to DVI/HDMI/etc. adapter) */ 1697926deccbSFrançois Tigeot if (radeon_ddc_probe(radeon_connector, false)) 1698926deccbSFrançois Tigeot ret = connector_status_connected; 1699926deccbSFrançois Tigeot } 1700926deccbSFrançois Tigeot } 1701926deccbSFrançois Tigeot } 1702926deccbSFrançois Tigeot 1703926deccbSFrançois Tigeot radeon_connector_update_scratch_regs(connector, ret); 1704c6f73aabSFrançois Tigeot out: 1705c6f73aabSFrançois Tigeot #ifdef PM_TODO 1706c6f73aabSFrançois Tigeot pm_runtime_mark_last_busy(connector->dev->dev); 1707c6f73aabSFrançois Tigeot pm_runtime_put_autosuspend(connector->dev->dev); 1708c6f73aabSFrançois Tigeot #endif 1709c6f73aabSFrançois Tigeot 1710926deccbSFrançois Tigeot return ret; 1711926deccbSFrançois Tigeot } 1712926deccbSFrançois Tigeot 1713926deccbSFrançois Tigeot static int radeon_dp_mode_valid(struct drm_connector *connector, 1714926deccbSFrançois Tigeot struct drm_display_mode *mode) 1715926deccbSFrançois Tigeot { 1716c6f73aabSFrançois Tigeot struct drm_device *dev = connector->dev; 1717c6f73aabSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1718926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1719926deccbSFrançois Tigeot struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; 1720926deccbSFrançois Tigeot 1721926deccbSFrançois Tigeot /* XXX check mode bandwidth */ 1722926deccbSFrançois Tigeot 1723926deccbSFrançois Tigeot if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) || 1724926deccbSFrançois Tigeot (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) { 1725926deccbSFrançois Tigeot struct drm_encoder *encoder = radeon_best_single_encoder(connector); 1726926deccbSFrançois Tigeot 1727926deccbSFrançois Tigeot if ((mode->hdisplay < 320) || (mode->vdisplay < 240)) 1728926deccbSFrançois Tigeot return MODE_PANEL; 1729926deccbSFrançois Tigeot 1730926deccbSFrançois Tigeot if (encoder) { 1731926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 1732926deccbSFrançois Tigeot struct drm_display_mode *native_mode = &radeon_encoder->native_mode; 1733926deccbSFrançois Tigeot 1734926deccbSFrançois Tigeot /* AVIVO hardware supports downscaling modes larger than the panel 1735926deccbSFrançois Tigeot * to the panel size, but I'm not sure this is desirable. 1736926deccbSFrançois Tigeot */ 1737926deccbSFrançois Tigeot if ((mode->hdisplay > native_mode->hdisplay) || 1738926deccbSFrançois Tigeot (mode->vdisplay > native_mode->vdisplay)) 1739926deccbSFrançois Tigeot return MODE_PANEL; 1740926deccbSFrançois Tigeot 1741926deccbSFrançois Tigeot /* if scaling is disabled, block non-native modes */ 1742926deccbSFrançois Tigeot if (radeon_encoder->rmx_type == RMX_OFF) { 1743926deccbSFrançois Tigeot if ((mode->hdisplay != native_mode->hdisplay) || 1744926deccbSFrançois Tigeot (mode->vdisplay != native_mode->vdisplay)) 1745926deccbSFrançois Tigeot return MODE_PANEL; 1746926deccbSFrançois Tigeot } 1747926deccbSFrançois Tigeot } 1748926deccbSFrançois Tigeot } else { 1749926deccbSFrançois Tigeot if ((radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || 1750c6f73aabSFrançois Tigeot (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) { 1751926deccbSFrançois Tigeot return radeon_dp_mode_valid_helper(connector, mode); 1752c6f73aabSFrançois Tigeot } else { 1753c6f73aabSFrançois Tigeot if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { 1754c6f73aabSFrançois Tigeot /* HDMI 1.3+ supports max clock of 340 Mhz */ 1755c6f73aabSFrançois Tigeot if (mode->clock > 340000) 1756c6f73aabSFrançois Tigeot return MODE_CLOCK_HIGH; 1757c6f73aabSFrançois Tigeot } else { 1758c6f73aabSFrançois Tigeot if (mode->clock > 165000) 1759c6f73aabSFrançois Tigeot return MODE_CLOCK_HIGH; 1760926deccbSFrançois Tigeot } 1761926deccbSFrançois Tigeot } 1762c6f73aabSFrançois Tigeot } 1763c6f73aabSFrançois Tigeot 1764c6f73aabSFrançois Tigeot return MODE_OK; 1765c6f73aabSFrançois Tigeot } 1766926deccbSFrançois Tigeot 1767926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_dp_connector_helper_funcs = { 1768926deccbSFrançois Tigeot .get_modes = radeon_dp_get_modes, 1769926deccbSFrançois Tigeot .mode_valid = radeon_dp_mode_valid, 1770926deccbSFrançois Tigeot .best_encoder = radeon_dvi_encoder, 1771926deccbSFrançois Tigeot }; 1772926deccbSFrançois Tigeot 1773926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_dp_connector_funcs = { 1774926deccbSFrançois Tigeot .dpms = drm_helper_connector_dpms, 1775926deccbSFrançois Tigeot .detect = radeon_dp_detect, 1776926deccbSFrançois Tigeot .fill_modes = drm_helper_probe_single_connector_modes, 1777926deccbSFrançois Tigeot .set_property = radeon_connector_set_property, 1778ee479021SImre Vadász .destroy = radeon_dp_connector_destroy, 1779926deccbSFrançois Tigeot .force = radeon_dvi_force, 1780926deccbSFrançois Tigeot }; 1781926deccbSFrançois Tigeot 17824cd92098Szrj static const struct drm_connector_funcs radeon_edp_connector_funcs = { 17834cd92098Szrj .dpms = drm_helper_connector_dpms, 17844cd92098Szrj .detect = radeon_dp_detect, 17854cd92098Szrj .fill_modes = drm_helper_probe_single_connector_modes, 17864cd92098Szrj .set_property = radeon_lvds_set_property, 1787ee479021SImre Vadász .destroy = radeon_dp_connector_destroy, 17884cd92098Szrj .force = radeon_dvi_force, 17894cd92098Szrj }; 17904cd92098Szrj 17914cd92098Szrj static const struct drm_connector_funcs radeon_lvds_bridge_connector_funcs = { 17924cd92098Szrj .dpms = drm_helper_connector_dpms, 17934cd92098Szrj .detect = radeon_dp_detect, 17944cd92098Szrj .fill_modes = drm_helper_probe_single_connector_modes, 17954cd92098Szrj .set_property = radeon_lvds_set_property, 1796ee479021SImre Vadász .destroy = radeon_dp_connector_destroy, 17974cd92098Szrj .force = radeon_dvi_force, 17984cd92098Szrj }; 17994cd92098Szrj 1800926deccbSFrançois Tigeot void 1801926deccbSFrançois Tigeot radeon_add_atom_connector(struct drm_device *dev, 1802926deccbSFrançois Tigeot uint32_t connector_id, 1803926deccbSFrançois Tigeot uint32_t supported_device, 1804926deccbSFrançois Tigeot int connector_type, 1805926deccbSFrançois Tigeot struct radeon_i2c_bus_rec *i2c_bus, 1806926deccbSFrançois Tigeot uint32_t igp_lane_info, 1807926deccbSFrançois Tigeot uint16_t connector_object_id, 1808926deccbSFrançois Tigeot struct radeon_hpd *hpd, 1809926deccbSFrançois Tigeot struct radeon_router *router) 1810926deccbSFrançois Tigeot { 1811926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1812926deccbSFrançois Tigeot struct drm_connector *connector; 1813926deccbSFrançois Tigeot struct radeon_connector *radeon_connector; 1814926deccbSFrançois Tigeot struct radeon_connector_atom_dig *radeon_dig_connector; 1815926deccbSFrançois Tigeot struct drm_encoder *encoder; 1816926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder; 1817926deccbSFrançois Tigeot uint32_t subpixel_order = SubPixelNone; 1818926deccbSFrançois Tigeot bool shared_ddc = false; 1819926deccbSFrançois Tigeot bool is_dp_bridge = false; 18207191d616Szrj bool has_aux = false; 1821926deccbSFrançois Tigeot 1822926deccbSFrançois Tigeot if (connector_type == DRM_MODE_CONNECTOR_Unknown) 1823926deccbSFrançois Tigeot return; 1824926deccbSFrançois Tigeot 1825926deccbSFrançois Tigeot /* if the user selected tv=0 don't try and add the connector */ 1826926deccbSFrançois Tigeot if (((connector_type == DRM_MODE_CONNECTOR_SVIDEO) || 1827926deccbSFrançois Tigeot (connector_type == DRM_MODE_CONNECTOR_Composite) || 1828926deccbSFrançois Tigeot (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) && 1829926deccbSFrançois Tigeot (radeon_tv == 0)) 1830926deccbSFrançois Tigeot return; 1831926deccbSFrançois Tigeot 1832926deccbSFrançois Tigeot /* see if we already added it */ 1833926deccbSFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 1834926deccbSFrançois Tigeot radeon_connector = to_radeon_connector(connector); 1835926deccbSFrançois Tigeot if (radeon_connector->connector_id == connector_id) { 1836926deccbSFrançois Tigeot radeon_connector->devices |= supported_device; 1837926deccbSFrançois Tigeot return; 1838926deccbSFrançois Tigeot } 1839926deccbSFrançois Tigeot if (radeon_connector->ddc_bus && i2c_bus->valid) { 1840926deccbSFrançois Tigeot if (radeon_connector->ddc_bus->rec.i2c_id == i2c_bus->i2c_id) { 1841926deccbSFrançois Tigeot radeon_connector->shared_ddc = true; 1842926deccbSFrançois Tigeot shared_ddc = true; 1843926deccbSFrançois Tigeot } 1844926deccbSFrançois Tigeot if (radeon_connector->router_bus && router->ddc_valid && 1845926deccbSFrançois Tigeot (radeon_connector->router.router_id == router->router_id)) { 1846926deccbSFrançois Tigeot radeon_connector->shared_ddc = false; 1847926deccbSFrançois Tigeot shared_ddc = false; 1848926deccbSFrançois Tigeot } 1849926deccbSFrançois Tigeot } 1850926deccbSFrançois Tigeot } 1851926deccbSFrançois Tigeot 1852926deccbSFrançois Tigeot /* check if it's a dp bridge */ 1853926deccbSFrançois Tigeot list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 1854926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 1855926deccbSFrançois Tigeot if (radeon_encoder->devices & supported_device) { 1856926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 1857926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_TRAVIS: 1858926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_NUTMEG: 1859926deccbSFrançois Tigeot is_dp_bridge = true; 1860926deccbSFrançois Tigeot break; 1861926deccbSFrançois Tigeot default: 1862926deccbSFrançois Tigeot break; 1863926deccbSFrançois Tigeot } 1864926deccbSFrançois Tigeot } 1865926deccbSFrançois Tigeot } 1866926deccbSFrançois Tigeot 1867c4ef309bSzrj radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL); 1868926deccbSFrançois Tigeot if (!radeon_connector) 1869926deccbSFrançois Tigeot return; 1870926deccbSFrançois Tigeot 1871926deccbSFrançois Tigeot connector = &radeon_connector->base; 1872926deccbSFrançois Tigeot 1873926deccbSFrançois Tigeot radeon_connector->connector_id = connector_id; 1874926deccbSFrançois Tigeot radeon_connector->devices = supported_device; 1875926deccbSFrançois Tigeot radeon_connector->shared_ddc = shared_ddc; 1876926deccbSFrançois Tigeot radeon_connector->connector_object_id = connector_object_id; 1877926deccbSFrançois Tigeot radeon_connector->hpd = *hpd; 1878926deccbSFrançois Tigeot 1879926deccbSFrançois Tigeot radeon_connector->router = *router; 1880926deccbSFrançois Tigeot if (router->ddc_valid || router->cd_valid) { 1881926deccbSFrançois Tigeot radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info); 1882926deccbSFrançois Tigeot if (!radeon_connector->router_bus) 1883926deccbSFrançois Tigeot DRM_ERROR("Failed to assign router i2c bus! Check dmesg for i2c errors.\n"); 1884926deccbSFrançois Tigeot } 1885926deccbSFrançois Tigeot 1886926deccbSFrançois Tigeot if (is_dp_bridge) { 1887c4ef309bSzrj radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); 1888926deccbSFrançois Tigeot if (!radeon_dig_connector) 1889926deccbSFrançois Tigeot goto failed; 1890926deccbSFrançois Tigeot radeon_dig_connector->igp_lane_info = igp_lane_info; 1891926deccbSFrançois Tigeot radeon_connector->con_priv = radeon_dig_connector; 1892926deccbSFrançois Tigeot if (i2c_bus->valid) { 1893ee479021SImre Vadász /* add DP i2c bus */ 1894ee479021SImre Vadász if (connector_type == DRM_MODE_CONNECTOR_eDP) 1895ee479021SImre Vadász radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch"); 1896ee479021SImre Vadász else 1897ee479021SImre Vadász radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch"); 1898ee479021SImre Vadász if (radeon_dig_connector->dp_i2c_bus) 18997191d616Szrj has_aux = true; 19007191d616Szrj else 1901ee479021SImre Vadász DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); 1902ee479021SImre Vadász radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 1903ee479021SImre Vadász if (!radeon_connector->ddc_bus) 1904926deccbSFrançois Tigeot DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 1905926deccbSFrançois Tigeot } 1906926deccbSFrançois Tigeot switch (connector_type) { 1907926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_VGA: 1908926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVIA: 1909926deccbSFrançois Tigeot default: 19104cd92098Szrj drm_connector_init(dev, &radeon_connector->base, 19114cd92098Szrj &radeon_dp_connector_funcs, connector_type); 19124cd92098Szrj drm_connector_helper_add(&radeon_connector->base, 19134cd92098Szrj &radeon_dp_connector_helper_funcs); 1914926deccbSFrançois Tigeot connector->interlace_allowed = true; 1915926deccbSFrançois Tigeot connector->doublescan_allowed = true; 1916926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 1917b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1918926deccbSFrançois Tigeot rdev->mode_info.load_detect_property, 1919926deccbSFrançois Tigeot 1); 1920c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1921c6f73aabSFrançois Tigeot dev->mode_config.scaling_mode_property, 1922c6f73aabSFrançois Tigeot DRM_MODE_SCALE_NONE); 1923926deccbSFrançois Tigeot break; 1924926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVII: 1925926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVID: 1926926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_HDMIA: 1927926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_HDMIB: 1928926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DisplayPort: 19294cd92098Szrj drm_connector_init(dev, &radeon_connector->base, 19304cd92098Szrj &radeon_dp_connector_funcs, connector_type); 19314cd92098Szrj drm_connector_helper_add(&radeon_connector->base, 19324cd92098Szrj &radeon_dp_connector_helper_funcs); 1933b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1934926deccbSFrançois Tigeot rdev->mode_info.underscan_property, 1935926deccbSFrançois Tigeot UNDERSCAN_OFF); 1936b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1937926deccbSFrançois Tigeot rdev->mode_info.underscan_hborder_property, 1938926deccbSFrançois Tigeot 0); 1939b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1940926deccbSFrançois Tigeot rdev->mode_info.underscan_vborder_property, 1941926deccbSFrançois Tigeot 0); 1942c6f73aabSFrançois Tigeot 1943c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1944c6f73aabSFrançois Tigeot dev->mode_config.scaling_mode_property, 1945c6f73aabSFrançois Tigeot DRM_MODE_SCALE_NONE); 1946c6f73aabSFrançois Tigeot 1947c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1948c6f73aabSFrançois Tigeot rdev->mode_info.dither_property, 1949c6f73aabSFrançois Tigeot RADEON_FMT_DITHER_DISABLE); 1950c6f73aabSFrançois Tigeot 1951ee479021SImre Vadász if (radeon_audio != 0) 19524cd92098Szrj drm_object_attach_property(&radeon_connector->base.base, 19534cd92098Szrj rdev->mode_info.audio_property, 1954c6f73aabSFrançois Tigeot RADEON_AUDIO_AUTO); 1955c6f73aabSFrançois Tigeot 1956926deccbSFrançois Tigeot subpixel_order = SubPixelHorizontalRGB; 1957926deccbSFrançois Tigeot connector->interlace_allowed = true; 1958926deccbSFrançois Tigeot if (connector_type == DRM_MODE_CONNECTOR_HDMIB) 1959926deccbSFrançois Tigeot connector->doublescan_allowed = true; 1960926deccbSFrançois Tigeot else 1961926deccbSFrançois Tigeot connector->doublescan_allowed = false; 1962926deccbSFrançois Tigeot if (connector_type == DRM_MODE_CONNECTOR_DVII) { 1963926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 1964b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1965926deccbSFrançois Tigeot rdev->mode_info.load_detect_property, 1966926deccbSFrançois Tigeot 1); 1967926deccbSFrançois Tigeot } 1968926deccbSFrançois Tigeot break; 1969926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_LVDS: 1970926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_eDP: 19714cd92098Szrj drm_connector_init(dev, &radeon_connector->base, 19724cd92098Szrj &radeon_lvds_bridge_connector_funcs, connector_type); 19734cd92098Szrj drm_connector_helper_add(&radeon_connector->base, 19744cd92098Szrj &radeon_dp_connector_helper_funcs); 1975b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1976926deccbSFrançois Tigeot dev->mode_config.scaling_mode_property, 1977926deccbSFrançois Tigeot DRM_MODE_SCALE_FULLSCREEN); 1978926deccbSFrançois Tigeot subpixel_order = SubPixelHorizontalRGB; 1979926deccbSFrançois Tigeot connector->interlace_allowed = false; 1980926deccbSFrançois Tigeot connector->doublescan_allowed = false; 1981926deccbSFrançois Tigeot break; 1982926deccbSFrançois Tigeot } 1983926deccbSFrançois Tigeot } else { 1984926deccbSFrançois Tigeot switch (connector_type) { 1985926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_VGA: 1986926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); 1987926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); 1988926deccbSFrançois Tigeot if (i2c_bus->valid) { 1989926deccbSFrançois Tigeot radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 1990926deccbSFrançois Tigeot if (!radeon_connector->ddc_bus) 1991926deccbSFrançois Tigeot DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 1992926deccbSFrançois Tigeot } 1993926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 1994b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1995926deccbSFrançois Tigeot rdev->mode_info.load_detect_property, 1996926deccbSFrançois Tigeot 1); 1997c6f73aabSFrançois Tigeot if (ASIC_IS_AVIVO(rdev)) 1998c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1999c6f73aabSFrançois Tigeot dev->mode_config.scaling_mode_property, 2000c6f73aabSFrançois Tigeot DRM_MODE_SCALE_NONE); 2001926deccbSFrançois Tigeot /* no HPD on analog connectors */ 2002926deccbSFrançois Tigeot radeon_connector->hpd.hpd = RADEON_HPD_NONE; 2003ee479021SImre Vadász connector->polled = DRM_CONNECTOR_POLL_CONNECT; 2004926deccbSFrançois Tigeot connector->interlace_allowed = true; 2005926deccbSFrançois Tigeot connector->doublescan_allowed = true; 2006926deccbSFrançois Tigeot break; 2007926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVIA: 2008926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); 2009926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); 2010926deccbSFrançois Tigeot if (i2c_bus->valid) { 2011926deccbSFrançois Tigeot radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 2012926deccbSFrançois Tigeot if (!radeon_connector->ddc_bus) 2013926deccbSFrançois Tigeot DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 2014926deccbSFrançois Tigeot } 2015926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 2016b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2017926deccbSFrançois Tigeot rdev->mode_info.load_detect_property, 2018926deccbSFrançois Tigeot 1); 2019c6f73aabSFrançois Tigeot if (ASIC_IS_AVIVO(rdev)) 2020c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2021c6f73aabSFrançois Tigeot dev->mode_config.scaling_mode_property, 2022c6f73aabSFrançois Tigeot DRM_MODE_SCALE_NONE); 2023926deccbSFrançois Tigeot /* no HPD on analog connectors */ 2024926deccbSFrançois Tigeot radeon_connector->hpd.hpd = RADEON_HPD_NONE; 2025926deccbSFrançois Tigeot connector->interlace_allowed = true; 2026926deccbSFrançois Tigeot connector->doublescan_allowed = true; 2027926deccbSFrançois Tigeot break; 2028926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVII: 2029926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVID: 2030c4ef309bSzrj radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); 2031926deccbSFrançois Tigeot if (!radeon_dig_connector) 2032926deccbSFrançois Tigeot goto failed; 2033926deccbSFrançois Tigeot radeon_dig_connector->igp_lane_info = igp_lane_info; 2034926deccbSFrançois Tigeot radeon_connector->con_priv = radeon_dig_connector; 2035926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); 2036926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); 2037926deccbSFrançois Tigeot if (i2c_bus->valid) { 2038926deccbSFrançois Tigeot radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 2039926deccbSFrançois Tigeot if (!radeon_connector->ddc_bus) 2040926deccbSFrançois Tigeot DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 2041926deccbSFrançois Tigeot } 2042926deccbSFrançois Tigeot subpixel_order = SubPixelHorizontalRGB; 2043b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2044926deccbSFrançois Tigeot rdev->mode_info.coherent_mode_property, 2045926deccbSFrançois Tigeot 1); 2046926deccbSFrançois Tigeot if (ASIC_IS_AVIVO(rdev)) { 2047b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2048926deccbSFrançois Tigeot rdev->mode_info.underscan_property, 2049926deccbSFrançois Tigeot UNDERSCAN_OFF); 2050b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2051926deccbSFrançois Tigeot rdev->mode_info.underscan_hborder_property, 2052926deccbSFrançois Tigeot 0); 2053b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2054926deccbSFrançois Tigeot rdev->mode_info.underscan_vborder_property, 2055926deccbSFrançois Tigeot 0); 2056c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2057c6f73aabSFrançois Tigeot rdev->mode_info.dither_property, 2058c6f73aabSFrançois Tigeot RADEON_FMT_DITHER_DISABLE); 2059c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2060c6f73aabSFrançois Tigeot dev->mode_config.scaling_mode_property, 2061c6f73aabSFrançois Tigeot DRM_MODE_SCALE_NONE); 2062926deccbSFrançois Tigeot } 20634cd92098Szrj if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) { 20644cd92098Szrj drm_object_attach_property(&radeon_connector->base.base, 20654cd92098Szrj rdev->mode_info.audio_property, 2066c6f73aabSFrançois Tigeot RADEON_AUDIO_AUTO); 20674cd92098Szrj } 2068926deccbSFrançois Tigeot if (connector_type == DRM_MODE_CONNECTOR_DVII) { 2069926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 2070b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2071926deccbSFrançois Tigeot rdev->mode_info.load_detect_property, 2072926deccbSFrançois Tigeot 1); 2073926deccbSFrançois Tigeot } 2074926deccbSFrançois Tigeot connector->interlace_allowed = true; 2075926deccbSFrançois Tigeot if (connector_type == DRM_MODE_CONNECTOR_DVII) 2076926deccbSFrançois Tigeot connector->doublescan_allowed = true; 2077926deccbSFrançois Tigeot else 2078926deccbSFrançois Tigeot connector->doublescan_allowed = false; 2079926deccbSFrançois Tigeot break; 2080926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_HDMIA: 2081926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_HDMIB: 2082c4ef309bSzrj radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); 2083926deccbSFrançois Tigeot if (!radeon_dig_connector) 2084926deccbSFrançois Tigeot goto failed; 2085926deccbSFrançois Tigeot radeon_dig_connector->igp_lane_info = igp_lane_info; 2086926deccbSFrançois Tigeot radeon_connector->con_priv = radeon_dig_connector; 2087926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); 2088926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); 2089926deccbSFrançois Tigeot if (i2c_bus->valid) { 2090926deccbSFrançois Tigeot radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 2091926deccbSFrançois Tigeot if (!radeon_connector->ddc_bus) 2092926deccbSFrançois Tigeot DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 2093926deccbSFrançois Tigeot } 2094b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2095926deccbSFrançois Tigeot rdev->mode_info.coherent_mode_property, 2096926deccbSFrançois Tigeot 1); 2097926deccbSFrançois Tigeot if (ASIC_IS_AVIVO(rdev)) { 2098b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2099926deccbSFrançois Tigeot rdev->mode_info.underscan_property, 2100926deccbSFrançois Tigeot UNDERSCAN_OFF); 2101b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2102926deccbSFrançois Tigeot rdev->mode_info.underscan_hborder_property, 2103926deccbSFrançois Tigeot 0); 2104b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2105926deccbSFrançois Tigeot rdev->mode_info.underscan_vborder_property, 2106926deccbSFrançois Tigeot 0); 2107c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2108c6f73aabSFrançois Tigeot rdev->mode_info.dither_property, 2109c6f73aabSFrançois Tigeot RADEON_FMT_DITHER_DISABLE); 2110c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2111c6f73aabSFrançois Tigeot dev->mode_config.scaling_mode_property, 2112c6f73aabSFrançois Tigeot DRM_MODE_SCALE_NONE); 2113926deccbSFrançois Tigeot } 21144cd92098Szrj if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) { 21154cd92098Szrj drm_object_attach_property(&radeon_connector->base.base, 21164cd92098Szrj rdev->mode_info.audio_property, 2117c6f73aabSFrançois Tigeot RADEON_AUDIO_AUTO); 21184cd92098Szrj } 2119926deccbSFrançois Tigeot subpixel_order = SubPixelHorizontalRGB; 2120926deccbSFrançois Tigeot connector->interlace_allowed = true; 2121926deccbSFrançois Tigeot if (connector_type == DRM_MODE_CONNECTOR_HDMIB) 2122926deccbSFrançois Tigeot connector->doublescan_allowed = true; 2123926deccbSFrançois Tigeot else 2124926deccbSFrançois Tigeot connector->doublescan_allowed = false; 2125926deccbSFrançois Tigeot break; 2126926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DisplayPort: 2127c4ef309bSzrj radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); 2128926deccbSFrançois Tigeot if (!radeon_dig_connector) 2129926deccbSFrançois Tigeot goto failed; 2130926deccbSFrançois Tigeot radeon_dig_connector->igp_lane_info = igp_lane_info; 2131926deccbSFrançois Tigeot radeon_connector->con_priv = radeon_dig_connector; 2132926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type); 2133926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs); 2134926deccbSFrançois Tigeot if (i2c_bus->valid) { 2135ee479021SImre Vadász /* add DP i2c bus */ 2136ee479021SImre Vadász radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch"); 2137ee479021SImre Vadász if (!radeon_dig_connector->dp_i2c_bus) 2138ee479021SImre Vadász DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); 2139926deccbSFrançois Tigeot radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 21407191d616Szrj if (radeon_connector->ddc_bus) 21417191d616Szrj has_aux = true; 21427191d616Szrj else 2143926deccbSFrançois Tigeot DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 2144926deccbSFrançois Tigeot } 2145926deccbSFrançois Tigeot subpixel_order = SubPixelHorizontalRGB; 2146b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2147926deccbSFrançois Tigeot rdev->mode_info.coherent_mode_property, 2148926deccbSFrançois Tigeot 1); 2149926deccbSFrançois Tigeot if (ASIC_IS_AVIVO(rdev)) { 2150b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2151926deccbSFrançois Tigeot rdev->mode_info.underscan_property, 2152926deccbSFrançois Tigeot UNDERSCAN_OFF); 2153b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2154926deccbSFrançois Tigeot rdev->mode_info.underscan_hborder_property, 2155926deccbSFrançois Tigeot 0); 2156b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2157926deccbSFrançois Tigeot rdev->mode_info.underscan_vborder_property, 2158926deccbSFrançois Tigeot 0); 2159c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2160c6f73aabSFrançois Tigeot rdev->mode_info.dither_property, 2161c6f73aabSFrançois Tigeot RADEON_FMT_DITHER_DISABLE); 2162c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2163c6f73aabSFrançois Tigeot dev->mode_config.scaling_mode_property, 2164c6f73aabSFrançois Tigeot DRM_MODE_SCALE_NONE); 2165926deccbSFrançois Tigeot } 21664cd92098Szrj if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) { 21674cd92098Szrj drm_object_attach_property(&radeon_connector->base.base, 21684cd92098Szrj rdev->mode_info.audio_property, 2169c6f73aabSFrançois Tigeot RADEON_AUDIO_AUTO); 21704cd92098Szrj } 2171926deccbSFrançois Tigeot connector->interlace_allowed = true; 2172926deccbSFrançois Tigeot /* in theory with a DP to VGA converter... */ 2173926deccbSFrançois Tigeot connector->doublescan_allowed = false; 2174926deccbSFrançois Tigeot break; 2175926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_eDP: 2176c4ef309bSzrj radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); 2177926deccbSFrançois Tigeot if (!radeon_dig_connector) 2178926deccbSFrançois Tigeot goto failed; 2179926deccbSFrançois Tigeot radeon_dig_connector->igp_lane_info = igp_lane_info; 2180926deccbSFrançois Tigeot radeon_connector->con_priv = radeon_dig_connector; 21814cd92098Szrj drm_connector_init(dev, &radeon_connector->base, &radeon_edp_connector_funcs, connector_type); 2182926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs); 2183926deccbSFrançois Tigeot if (i2c_bus->valid) { 2184ee479021SImre Vadász /* add DP i2c bus */ 2185ee479021SImre Vadász radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch"); 2186ee479021SImre Vadász if (radeon_dig_connector->dp_i2c_bus) 21877191d616Szrj has_aux = true; 21887191d616Szrj else 2189ee479021SImre Vadász DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); 2190ee479021SImre Vadász radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 2191ee479021SImre Vadász if (!radeon_connector->ddc_bus) 2192926deccbSFrançois Tigeot DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 2193926deccbSFrançois Tigeot } 2194b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2195926deccbSFrançois Tigeot dev->mode_config.scaling_mode_property, 2196926deccbSFrançois Tigeot DRM_MODE_SCALE_FULLSCREEN); 2197926deccbSFrançois Tigeot subpixel_order = SubPixelHorizontalRGB; 2198926deccbSFrançois Tigeot connector->interlace_allowed = false; 2199926deccbSFrançois Tigeot connector->doublescan_allowed = false; 2200926deccbSFrançois Tigeot break; 2201926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_SVIDEO: 2202926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_Composite: 2203926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_9PinDIN: 2204926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type); 2205926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); 2206926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 2207b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2208926deccbSFrançois Tigeot rdev->mode_info.load_detect_property, 2209926deccbSFrançois Tigeot 1); 2210b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2211926deccbSFrançois Tigeot rdev->mode_info.tv_std_property, 2212926deccbSFrançois Tigeot radeon_atombios_get_tv_info(rdev)); 2213926deccbSFrançois Tigeot /* no HPD on analog connectors */ 2214926deccbSFrançois Tigeot radeon_connector->hpd.hpd = RADEON_HPD_NONE; 2215926deccbSFrançois Tigeot connector->interlace_allowed = false; 2216926deccbSFrançois Tigeot connector->doublescan_allowed = false; 2217926deccbSFrançois Tigeot break; 2218926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_LVDS: 2219c4ef309bSzrj radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); 2220926deccbSFrançois Tigeot if (!radeon_dig_connector) 2221926deccbSFrançois Tigeot goto failed; 2222926deccbSFrançois Tigeot radeon_dig_connector->igp_lane_info = igp_lane_info; 2223926deccbSFrançois Tigeot radeon_connector->con_priv = radeon_dig_connector; 2224926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); 2225926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs); 2226926deccbSFrançois Tigeot if (i2c_bus->valid) { 2227926deccbSFrançois Tigeot radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 2228926deccbSFrançois Tigeot if (!radeon_connector->ddc_bus) 2229926deccbSFrançois Tigeot DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 2230926deccbSFrançois Tigeot } 2231b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2232926deccbSFrançois Tigeot dev->mode_config.scaling_mode_property, 2233926deccbSFrançois Tigeot DRM_MODE_SCALE_FULLSCREEN); 2234926deccbSFrançois Tigeot subpixel_order = SubPixelHorizontalRGB; 2235926deccbSFrançois Tigeot connector->interlace_allowed = false; 2236926deccbSFrançois Tigeot connector->doublescan_allowed = false; 2237926deccbSFrançois Tigeot break; 2238926deccbSFrançois Tigeot } 2239926deccbSFrançois Tigeot } 2240926deccbSFrançois Tigeot 2241926deccbSFrançois Tigeot if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) { 2242ee479021SImre Vadász if (i2c_bus->valid) 2243ee479021SImre Vadász connector->polled = DRM_CONNECTOR_POLL_CONNECT; 2244926deccbSFrançois Tigeot } else 2245926deccbSFrançois Tigeot connector->polled = DRM_CONNECTOR_POLL_HPD; 2246926deccbSFrançois Tigeot 2247926deccbSFrançois Tigeot connector->display_info.subpixel_order = subpixel_order; 2248c6f73aabSFrançois Tigeot drm_connector_register(connector); 22497191d616Szrj 22507191d616Szrj if (has_aux) 22517191d616Szrj radeon_dp_aux_init(radeon_connector); 22527191d616Szrj 2253926deccbSFrançois Tigeot return; 2254926deccbSFrançois Tigeot 2255926deccbSFrançois Tigeot failed: 2256926deccbSFrançois Tigeot drm_connector_cleanup(connector); 2257158486a6SFrançois Tigeot kfree(connector); 2258926deccbSFrançois Tigeot } 2259926deccbSFrançois Tigeot 2260926deccbSFrançois Tigeot void 2261926deccbSFrançois Tigeot radeon_add_legacy_connector(struct drm_device *dev, 2262926deccbSFrançois Tigeot uint32_t connector_id, 2263926deccbSFrançois Tigeot uint32_t supported_device, 2264926deccbSFrançois Tigeot int connector_type, 2265926deccbSFrançois Tigeot struct radeon_i2c_bus_rec *i2c_bus, 2266926deccbSFrançois Tigeot uint16_t connector_object_id, 2267926deccbSFrançois Tigeot struct radeon_hpd *hpd) 2268926deccbSFrançois Tigeot { 2269926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 2270926deccbSFrançois Tigeot struct drm_connector *connector; 2271926deccbSFrançois Tigeot struct radeon_connector *radeon_connector; 2272926deccbSFrançois Tigeot uint32_t subpixel_order = SubPixelNone; 2273926deccbSFrançois Tigeot 2274926deccbSFrançois Tigeot if (connector_type == DRM_MODE_CONNECTOR_Unknown) 2275926deccbSFrançois Tigeot return; 2276926deccbSFrançois Tigeot 2277926deccbSFrançois Tigeot /* if the user selected tv=0 don't try and add the connector */ 2278926deccbSFrançois Tigeot if (((connector_type == DRM_MODE_CONNECTOR_SVIDEO) || 2279926deccbSFrançois Tigeot (connector_type == DRM_MODE_CONNECTOR_Composite) || 2280926deccbSFrançois Tigeot (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) && 2281926deccbSFrançois Tigeot (radeon_tv == 0)) 2282926deccbSFrançois Tigeot return; 2283926deccbSFrançois Tigeot 2284926deccbSFrançois Tigeot /* see if we already added it */ 2285926deccbSFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 2286926deccbSFrançois Tigeot radeon_connector = to_radeon_connector(connector); 2287926deccbSFrançois Tigeot if (radeon_connector->connector_id == connector_id) { 2288926deccbSFrançois Tigeot radeon_connector->devices |= supported_device; 2289926deccbSFrançois Tigeot return; 2290926deccbSFrançois Tigeot } 2291926deccbSFrançois Tigeot } 2292926deccbSFrançois Tigeot 2293c4ef309bSzrj radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL); 2294926deccbSFrançois Tigeot if (!radeon_connector) 2295926deccbSFrançois Tigeot return; 2296926deccbSFrançois Tigeot 2297926deccbSFrançois Tigeot connector = &radeon_connector->base; 2298926deccbSFrançois Tigeot 2299926deccbSFrançois Tigeot radeon_connector->connector_id = connector_id; 2300926deccbSFrançois Tigeot radeon_connector->devices = supported_device; 2301926deccbSFrançois Tigeot radeon_connector->connector_object_id = connector_object_id; 2302926deccbSFrançois Tigeot radeon_connector->hpd = *hpd; 2303926deccbSFrançois Tigeot 2304926deccbSFrançois Tigeot switch (connector_type) { 2305926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_VGA: 2306926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); 2307926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); 2308926deccbSFrançois Tigeot if (i2c_bus->valid) { 2309926deccbSFrançois Tigeot radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 2310926deccbSFrançois Tigeot if (!radeon_connector->ddc_bus) 2311926deccbSFrançois Tigeot DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 2312926deccbSFrançois Tigeot } 2313926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 2314b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2315926deccbSFrançois Tigeot rdev->mode_info.load_detect_property, 2316926deccbSFrançois Tigeot 1); 2317926deccbSFrançois Tigeot /* no HPD on analog connectors */ 2318926deccbSFrançois Tigeot radeon_connector->hpd.hpd = RADEON_HPD_NONE; 2319ee479021SImre Vadász connector->polled = DRM_CONNECTOR_POLL_CONNECT; 2320926deccbSFrançois Tigeot connector->interlace_allowed = true; 2321926deccbSFrançois Tigeot connector->doublescan_allowed = true; 2322926deccbSFrançois Tigeot break; 2323926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVIA: 2324926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); 2325926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); 2326926deccbSFrançois Tigeot if (i2c_bus->valid) { 2327926deccbSFrançois Tigeot radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 2328926deccbSFrançois Tigeot if (!radeon_connector->ddc_bus) 2329926deccbSFrançois Tigeot DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 2330926deccbSFrançois Tigeot } 2331926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 2332b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2333926deccbSFrançois Tigeot rdev->mode_info.load_detect_property, 2334926deccbSFrançois Tigeot 1); 2335926deccbSFrançois Tigeot /* no HPD on analog connectors */ 2336926deccbSFrançois Tigeot radeon_connector->hpd.hpd = RADEON_HPD_NONE; 2337926deccbSFrançois Tigeot connector->interlace_allowed = true; 2338926deccbSFrançois Tigeot connector->doublescan_allowed = true; 2339926deccbSFrançois Tigeot break; 2340926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVII: 2341926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVID: 2342926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); 2343926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); 2344926deccbSFrançois Tigeot if (i2c_bus->valid) { 2345926deccbSFrançois Tigeot radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 2346926deccbSFrançois Tigeot if (!radeon_connector->ddc_bus) 2347926deccbSFrançois Tigeot DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 2348926deccbSFrançois Tigeot } 2349926deccbSFrançois Tigeot if (connector_type == DRM_MODE_CONNECTOR_DVII) { 2350926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 2351b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2352926deccbSFrançois Tigeot rdev->mode_info.load_detect_property, 2353926deccbSFrançois Tigeot 1); 2354926deccbSFrançois Tigeot } 2355926deccbSFrançois Tigeot subpixel_order = SubPixelHorizontalRGB; 2356926deccbSFrançois Tigeot connector->interlace_allowed = true; 2357926deccbSFrançois Tigeot if (connector_type == DRM_MODE_CONNECTOR_DVII) 2358926deccbSFrançois Tigeot connector->doublescan_allowed = true; 2359926deccbSFrançois Tigeot else 2360926deccbSFrançois Tigeot connector->doublescan_allowed = false; 2361926deccbSFrançois Tigeot break; 2362926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_SVIDEO: 2363926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_Composite: 2364926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_9PinDIN: 2365926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type); 2366926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); 2367926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 2368926deccbSFrançois Tigeot /* RS400,RC410,RS480 chipset seems to report a lot 2369926deccbSFrançois Tigeot * of false positive on load detect, we haven't yet 2370926deccbSFrançois Tigeot * found a way to make load detect reliable on those 2371926deccbSFrançois Tigeot * chipset, thus just disable it for TV. 2372926deccbSFrançois Tigeot */ 2373926deccbSFrançois Tigeot if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480) 2374926deccbSFrançois Tigeot radeon_connector->dac_load_detect = false; 2375b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2376926deccbSFrançois Tigeot rdev->mode_info.load_detect_property, 2377926deccbSFrançois Tigeot radeon_connector->dac_load_detect); 2378b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2379926deccbSFrançois Tigeot rdev->mode_info.tv_std_property, 2380926deccbSFrançois Tigeot radeon_combios_get_tv_info(rdev)); 2381926deccbSFrançois Tigeot /* no HPD on analog connectors */ 2382926deccbSFrançois Tigeot radeon_connector->hpd.hpd = RADEON_HPD_NONE; 2383926deccbSFrançois Tigeot connector->interlace_allowed = false; 2384926deccbSFrançois Tigeot connector->doublescan_allowed = false; 2385926deccbSFrançois Tigeot break; 2386926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_LVDS: 2387926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); 2388926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs); 2389926deccbSFrançois Tigeot if (i2c_bus->valid) { 2390926deccbSFrançois Tigeot radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 2391926deccbSFrançois Tigeot if (!radeon_connector->ddc_bus) 2392926deccbSFrançois Tigeot DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 2393926deccbSFrançois Tigeot } 2394b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2395926deccbSFrançois Tigeot dev->mode_config.scaling_mode_property, 2396926deccbSFrançois Tigeot DRM_MODE_SCALE_FULLSCREEN); 2397926deccbSFrançois Tigeot subpixel_order = SubPixelHorizontalRGB; 2398926deccbSFrançois Tigeot connector->interlace_allowed = false; 2399926deccbSFrançois Tigeot connector->doublescan_allowed = false; 2400926deccbSFrançois Tigeot break; 2401926deccbSFrançois Tigeot } 2402926deccbSFrançois Tigeot 2403926deccbSFrançois Tigeot if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) { 2404ee479021SImre Vadász if (i2c_bus->valid) 2405ee479021SImre Vadász connector->polled = DRM_CONNECTOR_POLL_CONNECT; 2406926deccbSFrançois Tigeot } else 2407926deccbSFrançois Tigeot connector->polled = DRM_CONNECTOR_POLL_HPD; 2408926deccbSFrançois Tigeot connector->display_info.subpixel_order = subpixel_order; 2409c6f73aabSFrançois Tigeot drm_connector_register(connector); 2410926deccbSFrançois Tigeot } 2411