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> 30*83b4b9b9SFranç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) { 3297191d616Szrj if (rdev->is_atom_bios) { 3307191d616Szrj /* some laptops provide a hardcoded edid in rom for LCDs */ 331ee479021SImre Vadász if (((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_LVDS) || 332ee479021SImre Vadász (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP))) 3337191d616Szrj radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev); 3347191d616Szrj } else { 3357191d616Szrj /* some servers provide a hardcoded edid in rom for KVMs */ 3367191d616Szrj radeon_connector->edid = radeon_bios_get_hardcoded_edid(rdev); 3377191d616Szrj } 3387191d616Szrj } 3397191d616Szrj } 3407191d616Szrj 341ee479021SImre Vadász static void radeon_connector_free_edid(struct radeon_connector *radeon_connector) 3427191d616Szrj { 3437191d616Szrj if (radeon_connector->edid) { 3447191d616Szrj kfree(radeon_connector->edid); 3457191d616Szrj radeon_connector->edid = NULL; 3467191d616Szrj } 3477191d616Szrj } 3487191d616Szrj 349ee479021SImre Vadász static int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) 3507191d616Szrj { 3517191d616Szrj int ret; 3527191d616Szrj 3537191d616Szrj if (radeon_connector->edid) { 354ee479021SImre Vadász drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); 355ee479021SImre Vadász ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); 356ee479021SImre Vadász drm_edid_to_eld(&radeon_connector->base, radeon_connector->edid); 3577191d616Szrj return ret; 3587191d616Szrj } 359ee479021SImre Vadász drm_mode_connector_update_edid_property(&radeon_connector->base, NULL); 3607191d616Szrj return 0; 3617191d616Szrj } 3627191d616Szrj 363926deccbSFrançois Tigeot static struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector) 364926deccbSFrançois Tigeot { 365926deccbSFrançois Tigeot int enc_id = connector->encoder_ids[0]; 366926deccbSFrançois Tigeot /* pick the encoder ids */ 367c6f73aabSFrançois Tigeot if (enc_id) 368c6f73aabSFrançois Tigeot return drm_encoder_find(connector->dev, enc_id); 369926deccbSFrançois Tigeot return NULL; 370926deccbSFrançois Tigeot } 371c6f73aabSFrançois Tigeot 372c6f73aabSFrançois Tigeot static void radeon_get_native_mode(struct drm_connector *connector) 373c6f73aabSFrançois Tigeot { 374c6f73aabSFrançois Tigeot struct drm_encoder *encoder = radeon_best_single_encoder(connector); 375c6f73aabSFrançois Tigeot struct radeon_encoder *radeon_encoder; 376c6f73aabSFrançois Tigeot 377c6f73aabSFrançois Tigeot if (encoder == NULL) 378c6f73aabSFrançois Tigeot return; 379c6f73aabSFrançois Tigeot 380c6f73aabSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 381c6f73aabSFrançois Tigeot 382c6f73aabSFrançois Tigeot if (!list_empty(&connector->probed_modes)) { 383c6f73aabSFrançois Tigeot struct drm_display_mode *preferred_mode = 384c6f73aabSFrançois Tigeot list_first_entry(&connector->probed_modes, 385c6f73aabSFrançois Tigeot struct drm_display_mode, head); 386c6f73aabSFrançois Tigeot 387c6f73aabSFrançois Tigeot radeon_encoder->native_mode = *preferred_mode; 388c6f73aabSFrançois Tigeot } else { 389c6f73aabSFrançois Tigeot radeon_encoder->native_mode.clock = 0; 390c6f73aabSFrançois Tigeot } 391926deccbSFrançois Tigeot } 392926deccbSFrançois Tigeot 393926deccbSFrançois Tigeot /* 394926deccbSFrançois Tigeot * radeon_connector_analog_encoder_conflict_solve 395926deccbSFrançois Tigeot * - search for other connectors sharing this encoder 396926deccbSFrançois Tigeot * if priority is true, then set them disconnected if this is connected 397926deccbSFrançois Tigeot * if priority is false, set us disconnected if they are connected 398926deccbSFrançois Tigeot */ 399926deccbSFrançois Tigeot static enum drm_connector_status 400926deccbSFrançois Tigeot radeon_connector_analog_encoder_conflict_solve(struct drm_connector *connector, 401926deccbSFrançois Tigeot struct drm_encoder *encoder, 402926deccbSFrançois Tigeot enum drm_connector_status current_status, 403926deccbSFrançois Tigeot bool priority) 404926deccbSFrançois Tigeot { 405926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 406926deccbSFrançois Tigeot struct drm_connector *conflict; 407926deccbSFrançois Tigeot struct radeon_connector *radeon_conflict; 408926deccbSFrançois Tigeot int i; 409926deccbSFrançois Tigeot 410926deccbSFrançois Tigeot list_for_each_entry(conflict, &dev->mode_config.connector_list, head) { 411926deccbSFrançois Tigeot if (conflict == connector) 412926deccbSFrançois Tigeot continue; 413926deccbSFrançois Tigeot 414926deccbSFrançois Tigeot radeon_conflict = to_radeon_connector(conflict); 415926deccbSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 416926deccbSFrançois Tigeot if (conflict->encoder_ids[i] == 0) 417926deccbSFrançois Tigeot break; 418926deccbSFrançois Tigeot 419926deccbSFrançois Tigeot /* if the IDs match */ 420926deccbSFrançois Tigeot if (conflict->encoder_ids[i] == encoder->base.id) { 421926deccbSFrançois Tigeot if (conflict->status != connector_status_connected) 422926deccbSFrançois Tigeot continue; 423926deccbSFrançois Tigeot 424926deccbSFrançois Tigeot if (radeon_conflict->use_digital) 425926deccbSFrançois Tigeot continue; 426926deccbSFrançois Tigeot 427926deccbSFrançois Tigeot if (priority == true) { 428ba55f2f5SFrançois Tigeot DRM_DEBUG_KMS("1: conflicting encoders switching off %s\n", 429ba55f2f5SFrançois Tigeot conflict->name); 430ba55f2f5SFrançois Tigeot DRM_DEBUG_KMS("in favor of %s\n", 431ba55f2f5SFrançois Tigeot connector->name); 432926deccbSFrançois Tigeot conflict->status = connector_status_disconnected; 433926deccbSFrançois Tigeot radeon_connector_update_scratch_regs(conflict, connector_status_disconnected); 434926deccbSFrançois Tigeot } else { 435ba55f2f5SFrançois Tigeot DRM_DEBUG_KMS("2: conflicting encoders switching off %s\n", 436ba55f2f5SFrançois Tigeot connector->name); 437ba55f2f5SFrançois Tigeot DRM_DEBUG_KMS("in favor of %s\n", 438ba55f2f5SFrançois Tigeot conflict->name); 439926deccbSFrançois Tigeot current_status = connector_status_disconnected; 440926deccbSFrançois Tigeot } 441926deccbSFrançois Tigeot break; 442926deccbSFrançois Tigeot } 443926deccbSFrançois Tigeot } 444926deccbSFrançois Tigeot } 445926deccbSFrançois Tigeot return current_status; 446926deccbSFrançois Tigeot 447926deccbSFrançois Tigeot } 448926deccbSFrançois Tigeot 449926deccbSFrançois Tigeot static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encoder) 450926deccbSFrançois Tigeot { 451926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 452926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 453926deccbSFrançois Tigeot struct drm_display_mode *mode = NULL; 454926deccbSFrançois Tigeot struct drm_display_mode *native_mode = &radeon_encoder->native_mode; 455926deccbSFrançois Tigeot 456926deccbSFrançois Tigeot if (native_mode->hdisplay != 0 && 457926deccbSFrançois Tigeot native_mode->vdisplay != 0 && 458926deccbSFrançois Tigeot native_mode->clock != 0) { 459926deccbSFrançois Tigeot mode = drm_mode_duplicate(dev, native_mode); 460926deccbSFrançois Tigeot mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; 461926deccbSFrançois Tigeot drm_mode_set_name(mode); 462926deccbSFrançois Tigeot 463926deccbSFrançois Tigeot DRM_DEBUG_KMS("Adding native panel mode %s\n", mode->name); 464926deccbSFrançois Tigeot } else if (native_mode->hdisplay != 0 && 465926deccbSFrançois Tigeot native_mode->vdisplay != 0) { 466926deccbSFrançois Tigeot /* mac laptops without an edid */ 467926deccbSFrançois Tigeot /* Note that this is not necessarily the exact panel mode, 468926deccbSFrançois Tigeot * but an approximation based on the cvt formula. For these 469926deccbSFrançois Tigeot * systems we should ideally read the mode info out of the 470926deccbSFrançois Tigeot * registers or add a mode table, but this works and is much 471926deccbSFrançois Tigeot * simpler. 472926deccbSFrançois Tigeot */ 473926deccbSFrançois Tigeot mode = drm_cvt_mode(dev, native_mode->hdisplay, native_mode->vdisplay, 60, true, false, false); 474926deccbSFrançois Tigeot mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; 475926deccbSFrançois Tigeot DRM_DEBUG_KMS("Adding cvt approximation of native panel mode %s\n", mode->name); 476926deccbSFrançois Tigeot } 477926deccbSFrançois Tigeot return mode; 478926deccbSFrançois Tigeot } 479926deccbSFrançois Tigeot 480926deccbSFrançois Tigeot static void radeon_add_common_modes(struct drm_encoder *encoder, struct drm_connector *connector) 481926deccbSFrançois Tigeot { 482926deccbSFrançois Tigeot struct drm_device *dev = encoder->dev; 483926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 484926deccbSFrançois Tigeot struct drm_display_mode *mode = NULL; 485926deccbSFrançois Tigeot struct drm_display_mode *native_mode = &radeon_encoder->native_mode; 486926deccbSFrançois Tigeot int i; 487926deccbSFrançois Tigeot struct mode_size { 488926deccbSFrançois Tigeot int w; 489926deccbSFrançois Tigeot int h; 490926deccbSFrançois Tigeot } common_modes[17] = { 491926deccbSFrançois Tigeot { 640, 480}, 492926deccbSFrançois Tigeot { 720, 480}, 493926deccbSFrançois Tigeot { 800, 600}, 494926deccbSFrançois Tigeot { 848, 480}, 495926deccbSFrançois Tigeot {1024, 768}, 496926deccbSFrançois Tigeot {1152, 768}, 497926deccbSFrançois Tigeot {1280, 720}, 498926deccbSFrançois Tigeot {1280, 800}, 499926deccbSFrançois Tigeot {1280, 854}, 500926deccbSFrançois Tigeot {1280, 960}, 501926deccbSFrançois Tigeot {1280, 1024}, 502926deccbSFrançois Tigeot {1440, 900}, 503926deccbSFrançois Tigeot {1400, 1050}, 504926deccbSFrançois Tigeot {1680, 1050}, 505926deccbSFrançois Tigeot {1600, 1200}, 506926deccbSFrançois Tigeot {1920, 1080}, 507926deccbSFrançois Tigeot {1920, 1200} 508926deccbSFrançois Tigeot }; 509926deccbSFrançois Tigeot 510926deccbSFrançois Tigeot for (i = 0; i < 17; i++) { 511926deccbSFrançois Tigeot if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) { 512926deccbSFrançois Tigeot if (common_modes[i].w > 1024 || 513926deccbSFrançois Tigeot common_modes[i].h > 768) 514926deccbSFrançois Tigeot continue; 515926deccbSFrançois Tigeot } 516926deccbSFrançois Tigeot if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 517926deccbSFrançois Tigeot if (common_modes[i].w > native_mode->hdisplay || 518926deccbSFrançois Tigeot common_modes[i].h > native_mode->vdisplay || 519926deccbSFrançois Tigeot (common_modes[i].w == native_mode->hdisplay && 520926deccbSFrançois Tigeot common_modes[i].h == native_mode->vdisplay)) 521926deccbSFrançois Tigeot continue; 522926deccbSFrançois Tigeot } 523926deccbSFrançois Tigeot if (common_modes[i].w < 320 || common_modes[i].h < 200) 524926deccbSFrançois Tigeot continue; 525926deccbSFrançois Tigeot 526926deccbSFrançois Tigeot mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false); 527926deccbSFrançois Tigeot drm_mode_probed_add(connector, mode); 528926deccbSFrançois Tigeot } 529926deccbSFrançois Tigeot } 530926deccbSFrançois Tigeot 531926deccbSFrançois Tigeot static int radeon_connector_set_property(struct drm_connector *connector, struct drm_property *property, 532926deccbSFrançois Tigeot uint64_t val) 533926deccbSFrançois Tigeot { 534926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 535926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 536926deccbSFrançois Tigeot struct drm_encoder *encoder; 537926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder; 538926deccbSFrançois Tigeot 539926deccbSFrançois Tigeot if (property == rdev->mode_info.coherent_mode_property) { 540926deccbSFrançois Tigeot struct radeon_encoder_atom_dig *dig; 541926deccbSFrançois Tigeot bool new_coherent_mode; 542926deccbSFrançois Tigeot 543926deccbSFrançois Tigeot /* need to find digital encoder on connector */ 544926deccbSFrançois Tigeot encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS); 545926deccbSFrançois Tigeot if (!encoder) 546926deccbSFrançois Tigeot return 0; 547926deccbSFrançois Tigeot 548926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 549926deccbSFrançois Tigeot 550926deccbSFrançois Tigeot if (!radeon_encoder->enc_priv) 551926deccbSFrançois Tigeot return 0; 552926deccbSFrançois Tigeot 553926deccbSFrançois Tigeot dig = radeon_encoder->enc_priv; 554926deccbSFrançois Tigeot new_coherent_mode = val ? true : false; 555926deccbSFrançois Tigeot if (dig->coherent_mode != new_coherent_mode) { 556926deccbSFrançois Tigeot dig->coherent_mode = new_coherent_mode; 557926deccbSFrançois Tigeot radeon_property_change_mode(&radeon_encoder->base); 558926deccbSFrançois Tigeot } 559926deccbSFrançois Tigeot } 560926deccbSFrançois Tigeot 5614cd92098Szrj if (property == rdev->mode_info.audio_property) { 5624cd92098Szrj struct radeon_connector *radeon_connector = to_radeon_connector(connector); 5634cd92098Szrj /* need to find digital encoder on connector */ 5644cd92098Szrj encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS); 5654cd92098Szrj if (!encoder) 5664cd92098Szrj return 0; 5674cd92098Szrj 5684cd92098Szrj radeon_encoder = to_radeon_encoder(encoder); 5694cd92098Szrj 5704cd92098Szrj if (radeon_connector->audio != val) { 5714cd92098Szrj radeon_connector->audio = val; 5724cd92098Szrj radeon_property_change_mode(&radeon_encoder->base); 5734cd92098Szrj } 5744cd92098Szrj } 5754cd92098Szrj 576c6f73aabSFrançois Tigeot if (property == rdev->mode_info.dither_property) { 577c6f73aabSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 578c6f73aabSFrançois Tigeot /* need to find digital encoder on connector */ 579c6f73aabSFrançois Tigeot encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS); 580c6f73aabSFrançois Tigeot if (!encoder) 581c6f73aabSFrançois Tigeot return 0; 582c6f73aabSFrançois Tigeot 583c6f73aabSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 584c6f73aabSFrançois Tigeot 585c6f73aabSFrançois Tigeot if (radeon_connector->dither != val) { 586c6f73aabSFrançois Tigeot radeon_connector->dither = val; 587c6f73aabSFrançois Tigeot radeon_property_change_mode(&radeon_encoder->base); 588c6f73aabSFrançois Tigeot } 589c6f73aabSFrançois Tigeot } 590c6f73aabSFrançois Tigeot 591926deccbSFrançois Tigeot if (property == rdev->mode_info.underscan_property) { 592926deccbSFrançois Tigeot /* need to find digital encoder on connector */ 593926deccbSFrançois Tigeot encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS); 594926deccbSFrançois Tigeot if (!encoder) 595926deccbSFrançois Tigeot return 0; 596926deccbSFrançois Tigeot 597926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 598926deccbSFrançois Tigeot 599926deccbSFrançois Tigeot if (radeon_encoder->underscan_type != val) { 600926deccbSFrançois Tigeot radeon_encoder->underscan_type = val; 601926deccbSFrançois Tigeot radeon_property_change_mode(&radeon_encoder->base); 602926deccbSFrançois Tigeot } 603926deccbSFrançois Tigeot } 604926deccbSFrançois Tigeot 605926deccbSFrançois Tigeot if (property == rdev->mode_info.underscan_hborder_property) { 606926deccbSFrançois Tigeot /* need to find digital encoder on connector */ 607926deccbSFrançois Tigeot encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS); 608926deccbSFrançois Tigeot if (!encoder) 609926deccbSFrançois Tigeot return 0; 610926deccbSFrançois Tigeot 611926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 612926deccbSFrançois Tigeot 613926deccbSFrançois Tigeot if (radeon_encoder->underscan_hborder != val) { 614926deccbSFrançois Tigeot radeon_encoder->underscan_hborder = val; 615926deccbSFrançois Tigeot radeon_property_change_mode(&radeon_encoder->base); 616926deccbSFrançois Tigeot } 617926deccbSFrançois Tigeot } 618926deccbSFrançois Tigeot 619926deccbSFrançois Tigeot if (property == rdev->mode_info.underscan_vborder_property) { 620926deccbSFrançois Tigeot /* need to find digital encoder on connector */ 621926deccbSFrançois Tigeot encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS); 622926deccbSFrançois Tigeot if (!encoder) 623926deccbSFrançois Tigeot return 0; 624926deccbSFrançois Tigeot 625926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 626926deccbSFrançois Tigeot 627926deccbSFrançois Tigeot if (radeon_encoder->underscan_vborder != val) { 628926deccbSFrançois Tigeot radeon_encoder->underscan_vborder = val; 629926deccbSFrançois Tigeot radeon_property_change_mode(&radeon_encoder->base); 630926deccbSFrançois Tigeot } 631926deccbSFrançois Tigeot } 632926deccbSFrançois Tigeot 633926deccbSFrançois Tigeot if (property == rdev->mode_info.tv_std_property) { 634926deccbSFrançois Tigeot encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TVDAC); 635926deccbSFrançois Tigeot if (!encoder) { 636926deccbSFrançois Tigeot encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_DAC); 637926deccbSFrançois Tigeot } 638926deccbSFrançois Tigeot 639926deccbSFrançois Tigeot if (!encoder) 640926deccbSFrançois Tigeot return 0; 641926deccbSFrançois Tigeot 642926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 643926deccbSFrançois Tigeot if (!radeon_encoder->enc_priv) 644926deccbSFrançois Tigeot return 0; 645926deccbSFrançois Tigeot if (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom) { 646926deccbSFrançois Tigeot struct radeon_encoder_atom_dac *dac_int; 647926deccbSFrançois Tigeot dac_int = radeon_encoder->enc_priv; 648926deccbSFrançois Tigeot dac_int->tv_std = val; 649926deccbSFrançois Tigeot } else { 650926deccbSFrançois Tigeot struct radeon_encoder_tv_dac *dac_int; 651926deccbSFrançois Tigeot dac_int = radeon_encoder->enc_priv; 652926deccbSFrançois Tigeot dac_int->tv_std = val; 653926deccbSFrançois Tigeot } 654926deccbSFrançois Tigeot radeon_property_change_mode(&radeon_encoder->base); 655926deccbSFrançois Tigeot } 656926deccbSFrançois Tigeot 657926deccbSFrançois Tigeot if (property == rdev->mode_info.load_detect_property) { 658926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = 659926deccbSFrançois Tigeot to_radeon_connector(connector); 660926deccbSFrançois Tigeot 661926deccbSFrançois Tigeot if (val == 0) 662926deccbSFrançois Tigeot radeon_connector->dac_load_detect = false; 663926deccbSFrançois Tigeot else 664926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 665926deccbSFrançois Tigeot } 666926deccbSFrançois Tigeot 667926deccbSFrançois Tigeot if (property == rdev->mode_info.tmds_pll_property) { 668926deccbSFrançois Tigeot struct radeon_encoder_int_tmds *tmds = NULL; 669926deccbSFrançois Tigeot bool ret = false; 670926deccbSFrançois Tigeot /* need to find digital encoder on connector */ 671926deccbSFrançois Tigeot encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS); 672926deccbSFrançois Tigeot if (!encoder) 673926deccbSFrançois Tigeot return 0; 674926deccbSFrançois Tigeot 675926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 676926deccbSFrançois Tigeot 677926deccbSFrançois Tigeot tmds = radeon_encoder->enc_priv; 678926deccbSFrançois Tigeot if (!tmds) 679926deccbSFrançois Tigeot return 0; 680926deccbSFrançois Tigeot 681926deccbSFrançois Tigeot if (val == 0) { 682926deccbSFrançois Tigeot if (rdev->is_atom_bios) 683926deccbSFrançois Tigeot ret = radeon_atombios_get_tmds_info(radeon_encoder, tmds); 684926deccbSFrançois Tigeot else 685926deccbSFrançois Tigeot ret = radeon_legacy_get_tmds_info_from_combios(radeon_encoder, tmds); 686926deccbSFrançois Tigeot } 687926deccbSFrançois Tigeot if (val == 1 || ret == false) { 688926deccbSFrançois Tigeot radeon_legacy_get_tmds_info_from_table(radeon_encoder, tmds); 689926deccbSFrançois Tigeot } 690926deccbSFrançois Tigeot radeon_property_change_mode(&radeon_encoder->base); 691926deccbSFrançois Tigeot } 692926deccbSFrançois Tigeot 693c6f73aabSFrançois Tigeot if (property == dev->mode_config.scaling_mode_property) { 694c6f73aabSFrançois Tigeot enum radeon_rmx_type rmx_type; 695c6f73aabSFrançois Tigeot 696c6f73aabSFrançois Tigeot if (connector->encoder) 697c6f73aabSFrançois Tigeot radeon_encoder = to_radeon_encoder(connector->encoder); 698c6f73aabSFrançois Tigeot else { 699c0e85e96SFrançois Tigeot const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; 700c6f73aabSFrançois Tigeot radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector)); 701c6f73aabSFrançois Tigeot } 702c6f73aabSFrançois Tigeot 703c6f73aabSFrançois Tigeot switch (val) { 704c6f73aabSFrançois Tigeot default: 705c6f73aabSFrançois Tigeot case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break; 706c6f73aabSFrançois Tigeot case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break; 707c6f73aabSFrançois Tigeot case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break; 708c6f73aabSFrançois Tigeot case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break; 709c6f73aabSFrançois Tigeot } 710c6f73aabSFrançois Tigeot if (radeon_encoder->rmx_type == rmx_type) 711c6f73aabSFrançois Tigeot return 0; 712c6f73aabSFrançois Tigeot 713c6f73aabSFrançois Tigeot if ((rmx_type != DRM_MODE_SCALE_NONE) && 714c6f73aabSFrançois Tigeot (radeon_encoder->native_mode.clock == 0)) 715c6f73aabSFrançois Tigeot return 0; 716c6f73aabSFrançois Tigeot 717c6f73aabSFrançois Tigeot radeon_encoder->rmx_type = rmx_type; 718c6f73aabSFrançois Tigeot 719c6f73aabSFrançois Tigeot radeon_property_change_mode(&radeon_encoder->base); 720c6f73aabSFrançois Tigeot } 721c6f73aabSFrançois Tigeot 722926deccbSFrançois Tigeot return 0; 723926deccbSFrançois Tigeot } 724926deccbSFrançois Tigeot 725926deccbSFrançois Tigeot static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder, 726926deccbSFrançois Tigeot struct drm_connector *connector) 727926deccbSFrançois Tigeot { 728926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 729926deccbSFrançois Tigeot struct drm_display_mode *native_mode = &radeon_encoder->native_mode; 730926deccbSFrançois Tigeot struct drm_display_mode *t, *mode; 731926deccbSFrançois Tigeot 732926deccbSFrançois Tigeot /* If the EDID preferred mode doesn't match the native mode, use it */ 733926deccbSFrançois Tigeot list_for_each_entry_safe(mode, t, &connector->probed_modes, head) { 734926deccbSFrançois Tigeot if (mode->type & DRM_MODE_TYPE_PREFERRED) { 735926deccbSFrançois Tigeot if (mode->hdisplay != native_mode->hdisplay || 736926deccbSFrançois Tigeot mode->vdisplay != native_mode->vdisplay) 737926deccbSFrançois Tigeot memcpy(native_mode, mode, sizeof(*mode)); 738926deccbSFrançois Tigeot } 739926deccbSFrançois Tigeot } 740926deccbSFrançois Tigeot 741926deccbSFrançois Tigeot /* Try to get native mode details from EDID if necessary */ 742926deccbSFrançois Tigeot if (!native_mode->clock) { 743926deccbSFrançois Tigeot list_for_each_entry_safe(mode, t, &connector->probed_modes, head) { 744926deccbSFrançois Tigeot if (mode->hdisplay == native_mode->hdisplay && 745926deccbSFrançois Tigeot mode->vdisplay == native_mode->vdisplay) { 746926deccbSFrançois Tigeot *native_mode = *mode; 747926deccbSFrançois Tigeot drm_mode_set_crtcinfo(native_mode, CRTC_INTERLACE_HALVE_V); 748926deccbSFrançois Tigeot DRM_DEBUG_KMS("Determined LVDS native mode details from EDID\n"); 749926deccbSFrançois Tigeot break; 750926deccbSFrançois Tigeot } 751926deccbSFrançois Tigeot } 752926deccbSFrançois Tigeot } 753926deccbSFrançois Tigeot 754926deccbSFrançois Tigeot if (!native_mode->clock) { 755926deccbSFrançois Tigeot DRM_DEBUG_KMS("No LVDS native mode details, disabling RMX\n"); 756926deccbSFrançois Tigeot radeon_encoder->rmx_type = RMX_OFF; 757926deccbSFrançois Tigeot } 758926deccbSFrançois Tigeot } 759926deccbSFrançois Tigeot 760926deccbSFrançois Tigeot static int radeon_lvds_get_modes(struct drm_connector *connector) 761926deccbSFrançois Tigeot { 762ee479021SImre Vadász struct radeon_connector *radeon_connector = to_radeon_connector(connector); 763926deccbSFrançois Tigeot struct drm_encoder *encoder; 764926deccbSFrançois Tigeot int ret = 0; 765926deccbSFrançois Tigeot struct drm_display_mode *mode; 766926deccbSFrançois Tigeot 767ee479021SImre Vadász if (radeon_connector->ddc_bus) { 768ee479021SImre Vadász radeon_connector_get_edid(radeon_connector); 769ee479021SImre Vadász ret = radeon_ddc_get_modes(radeon_connector); 770926deccbSFrançois Tigeot if (ret > 0) { 771926deccbSFrançois Tigeot encoder = radeon_best_single_encoder(connector); 772926deccbSFrançois Tigeot if (encoder) { 773926deccbSFrançois Tigeot radeon_fixup_lvds_native_mode(encoder, connector); 774926deccbSFrançois Tigeot /* add scaled modes */ 775926deccbSFrançois Tigeot radeon_add_common_modes(encoder, connector); 776926deccbSFrançois Tigeot } 777926deccbSFrançois Tigeot return ret; 778926deccbSFrançois Tigeot } 779ee479021SImre Vadász } 780926deccbSFrançois Tigeot 781926deccbSFrançois Tigeot encoder = radeon_best_single_encoder(connector); 782926deccbSFrançois Tigeot if (!encoder) 783926deccbSFrançois Tigeot return 0; 784926deccbSFrançois Tigeot 785926deccbSFrançois Tigeot /* we have no EDID modes */ 786926deccbSFrançois Tigeot mode = radeon_fp_native_mode(encoder); 787926deccbSFrançois Tigeot if (mode) { 788926deccbSFrançois Tigeot ret = 1; 789926deccbSFrançois Tigeot drm_mode_probed_add(connector, mode); 790926deccbSFrançois Tigeot /* add the width/height from vbios tables if available */ 791926deccbSFrançois Tigeot connector->display_info.width_mm = mode->width_mm; 792926deccbSFrançois Tigeot connector->display_info.height_mm = mode->height_mm; 793926deccbSFrançois Tigeot /* add scaled modes */ 794926deccbSFrançois Tigeot radeon_add_common_modes(encoder, connector); 795926deccbSFrançois Tigeot } 796926deccbSFrançois Tigeot 797926deccbSFrançois Tigeot return ret; 798926deccbSFrançois Tigeot } 799926deccbSFrançois Tigeot 800926deccbSFrançois Tigeot static int radeon_lvds_mode_valid(struct drm_connector *connector, 801926deccbSFrançois Tigeot struct drm_display_mode *mode) 802926deccbSFrançois Tigeot { 803926deccbSFrançois Tigeot struct drm_encoder *encoder = radeon_best_single_encoder(connector); 804926deccbSFrançois Tigeot 805926deccbSFrançois Tigeot if ((mode->hdisplay < 320) || (mode->vdisplay < 240)) 806926deccbSFrançois Tigeot return MODE_PANEL; 807926deccbSFrançois Tigeot 808926deccbSFrançois Tigeot if (encoder) { 809926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 810926deccbSFrançois Tigeot struct drm_display_mode *native_mode = &radeon_encoder->native_mode; 811926deccbSFrançois Tigeot 812926deccbSFrançois Tigeot /* AVIVO hardware supports downscaling modes larger than the panel 813926deccbSFrançois Tigeot * to the panel size, but I'm not sure this is desirable. 814926deccbSFrançois Tigeot */ 815926deccbSFrançois Tigeot if ((mode->hdisplay > native_mode->hdisplay) || 816926deccbSFrançois Tigeot (mode->vdisplay > native_mode->vdisplay)) 817926deccbSFrançois Tigeot return MODE_PANEL; 818926deccbSFrançois Tigeot 819926deccbSFrançois Tigeot /* if scaling is disabled, block non-native modes */ 820926deccbSFrançois Tigeot if (radeon_encoder->rmx_type == RMX_OFF) { 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 } 826926deccbSFrançois Tigeot 827926deccbSFrançois Tigeot return MODE_OK; 828926deccbSFrançois Tigeot } 829926deccbSFrançois Tigeot 830926deccbSFrançois Tigeot static enum drm_connector_status 831926deccbSFrançois Tigeot radeon_lvds_detect(struct drm_connector *connector, bool force) 832926deccbSFrançois Tigeot { 833926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 834926deccbSFrançois Tigeot struct drm_encoder *encoder = radeon_best_single_encoder(connector); 835926deccbSFrançois Tigeot enum drm_connector_status ret = connector_status_disconnected; 836c6f73aabSFrançois Tigeot #ifdef PM_TODO 837c6f73aabSFrançois Tigeot int r; 838c6f73aabSFrançois Tigeot 839c6f73aabSFrançois Tigeot r = pm_runtime_get_sync(connector->dev->dev); 840c6f73aabSFrançois Tigeot if (r < 0) 841c6f73aabSFrançois Tigeot return connector_status_disconnected; 842c6f73aabSFrançois Tigeot #endif 843926deccbSFrançois Tigeot 844926deccbSFrançois Tigeot if (encoder) { 845926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 846926deccbSFrançois Tigeot struct drm_display_mode *native_mode = &radeon_encoder->native_mode; 847926deccbSFrançois Tigeot 848926deccbSFrançois Tigeot /* check if panel is valid */ 849926deccbSFrançois Tigeot if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240) 850926deccbSFrançois Tigeot ret = connector_status_connected; 851ee479021SImre Vadász 852926deccbSFrançois Tigeot } 853926deccbSFrançois Tigeot 854926deccbSFrançois Tigeot /* check for edid as well */ 855ee479021SImre Vadász radeon_connector_get_edid(radeon_connector); 856926deccbSFrançois Tigeot if (radeon_connector->edid) 857926deccbSFrançois Tigeot ret = connector_status_connected; 858926deccbSFrançois Tigeot else { 859926deccbSFrançois Tigeot if (radeon_connector->ddc_bus) { 8609f4ca867SFrançois Tigeot radeon_connector->edid = drm_get_edid_iic(&radeon_connector->base, 861ee479021SImre Vadász radeon_connector->ddc_bus->adapter); 862926deccbSFrançois Tigeot if (radeon_connector->edid) 863926deccbSFrançois Tigeot ret = connector_status_connected; 864926deccbSFrançois Tigeot } 865926deccbSFrançois Tigeot } 866926deccbSFrançois Tigeot /* check acpi lid status ??? */ 867926deccbSFrançois Tigeot 868926deccbSFrançois Tigeot radeon_connector_update_scratch_regs(connector, ret); 869c6f73aabSFrançois Tigeot #ifdef PM_TODO 870c6f73aabSFrançois Tigeot pm_runtime_mark_last_busy(connector->dev->dev); 871c6f73aabSFrançois Tigeot pm_runtime_put_autosuspend(connector->dev->dev); 872c6f73aabSFrançois Tigeot #endif 873926deccbSFrançois Tigeot return ret; 874926deccbSFrançois Tigeot } 875926deccbSFrançois Tigeot 876926deccbSFrançois Tigeot static void radeon_connector_destroy(struct drm_connector *connector) 877926deccbSFrançois Tigeot { 878926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 879926deccbSFrançois Tigeot 880ee479021SImre Vadász radeon_connector_free_edid(radeon_connector); 881c4ef309bSzrj kfree(radeon_connector->con_priv); 882c6f73aabSFrançois Tigeot drm_connector_unregister(connector); 883926deccbSFrançois Tigeot drm_connector_cleanup(connector); 884c4ef309bSzrj kfree(connector); 885926deccbSFrançois Tigeot } 886926deccbSFrançois Tigeot 887926deccbSFrançois Tigeot static int radeon_lvds_set_property(struct drm_connector *connector, 888926deccbSFrançois Tigeot struct drm_property *property, 889926deccbSFrançois Tigeot uint64_t value) 890926deccbSFrançois Tigeot { 891926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 892926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder; 893926deccbSFrançois Tigeot enum radeon_rmx_type rmx_type; 894926deccbSFrançois Tigeot 895926deccbSFrançois Tigeot DRM_DEBUG_KMS("\n"); 896926deccbSFrançois Tigeot if (property != dev->mode_config.scaling_mode_property) 897926deccbSFrançois Tigeot return 0; 898926deccbSFrançois Tigeot 899926deccbSFrançois Tigeot if (connector->encoder) 900926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(connector->encoder); 901926deccbSFrançois Tigeot else { 902c0e85e96SFrançois Tigeot const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; 903926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(connector_funcs->best_encoder(connector)); 904926deccbSFrançois Tigeot } 905926deccbSFrançois Tigeot 906926deccbSFrançois Tigeot switch (value) { 907926deccbSFrançois Tigeot case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break; 908926deccbSFrançois Tigeot case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break; 909926deccbSFrançois Tigeot case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break; 910926deccbSFrançois Tigeot default: 911926deccbSFrançois Tigeot case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break; 912926deccbSFrançois Tigeot } 913926deccbSFrançois Tigeot if (radeon_encoder->rmx_type == rmx_type) 914926deccbSFrançois Tigeot return 0; 915926deccbSFrançois Tigeot 916926deccbSFrançois Tigeot radeon_encoder->rmx_type = rmx_type; 917926deccbSFrançois Tigeot 918926deccbSFrançois Tigeot radeon_property_change_mode(&radeon_encoder->base); 919926deccbSFrançois Tigeot return 0; 920926deccbSFrançois Tigeot } 921926deccbSFrançois Tigeot 922926deccbSFrançois Tigeot 923926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_lvds_connector_helper_funcs = { 924926deccbSFrançois Tigeot .get_modes = radeon_lvds_get_modes, 925926deccbSFrançois Tigeot .mode_valid = radeon_lvds_mode_valid, 926926deccbSFrançois Tigeot .best_encoder = radeon_best_single_encoder, 927926deccbSFrançois Tigeot }; 928926deccbSFrançois Tigeot 929926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_lvds_connector_funcs = { 930926deccbSFrançois Tigeot .dpms = drm_helper_connector_dpms, 931926deccbSFrançois Tigeot .detect = radeon_lvds_detect, 932926deccbSFrançois Tigeot .fill_modes = drm_helper_probe_single_connector_modes, 933926deccbSFrançois Tigeot .destroy = radeon_connector_destroy, 934926deccbSFrançois Tigeot .set_property = radeon_lvds_set_property, 935926deccbSFrançois Tigeot }; 936926deccbSFrançois Tigeot 937926deccbSFrançois Tigeot static int radeon_vga_get_modes(struct drm_connector *connector) 938926deccbSFrançois Tigeot { 939ee479021SImre Vadász struct radeon_connector *radeon_connector = to_radeon_connector(connector); 940926deccbSFrançois Tigeot int ret; 941926deccbSFrançois Tigeot 942ee479021SImre Vadász radeon_connector_get_edid(radeon_connector); 943ee479021SImre Vadász ret = radeon_ddc_get_modes(radeon_connector); 944926deccbSFrançois Tigeot 945c6f73aabSFrançois Tigeot radeon_get_native_mode(connector); 946c6f73aabSFrançois Tigeot 947926deccbSFrançois Tigeot return ret; 948926deccbSFrançois Tigeot } 949926deccbSFrançois Tigeot 950926deccbSFrançois Tigeot static int radeon_vga_mode_valid(struct drm_connector *connector, 951926deccbSFrançois Tigeot struct drm_display_mode *mode) 952926deccbSFrançois Tigeot { 953926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 954926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 955926deccbSFrançois Tigeot 956926deccbSFrançois Tigeot /* XXX check mode bandwidth */ 957926deccbSFrançois Tigeot 958926deccbSFrançois Tigeot if ((mode->clock / 10) > rdev->clock.max_pixel_clock) 959926deccbSFrançois Tigeot return MODE_CLOCK_HIGH; 960926deccbSFrançois Tigeot 961926deccbSFrançois Tigeot return MODE_OK; 962926deccbSFrançois Tigeot } 963926deccbSFrançois Tigeot 964926deccbSFrançois Tigeot static enum drm_connector_status 965926deccbSFrançois Tigeot radeon_vga_detect(struct drm_connector *connector, bool force) 966926deccbSFrançois Tigeot { 967926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 968926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 969926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 970926deccbSFrançois Tigeot struct drm_encoder *encoder; 971c0e85e96SFrançois Tigeot const struct drm_encoder_helper_funcs *encoder_funcs; 972926deccbSFrançois Tigeot bool dret = false; 973926deccbSFrançois Tigeot enum drm_connector_status ret = connector_status_disconnected; 974c6f73aabSFrançois Tigeot #ifdef PM_TODO 975c6f73aabSFrançois Tigeot int r; 976c6f73aabSFrançois Tigeot 977c6f73aabSFrançois Tigeot r = pm_runtime_get_sync(connector->dev->dev); 978c6f73aabSFrançois Tigeot if (r < 0) 979c6f73aabSFrançois Tigeot return connector_status_disconnected; 980c6f73aabSFrançois Tigeot #endif 981926deccbSFrançois Tigeot 982926deccbSFrançois Tigeot encoder = radeon_best_single_encoder(connector); 983926deccbSFrançois Tigeot if (!encoder) 984926deccbSFrançois Tigeot ret = connector_status_disconnected; 985926deccbSFrançois Tigeot 986926deccbSFrançois Tigeot if (radeon_connector->ddc_bus) 987926deccbSFrançois Tigeot dret = radeon_ddc_probe(radeon_connector, false); 988926deccbSFrançois Tigeot if (dret) { 989926deccbSFrançois Tigeot radeon_connector->detected_by_load = false; 990ee479021SImre Vadász radeon_connector_free_edid(radeon_connector); 991ee479021SImre Vadász radeon_connector_get_edid(radeon_connector); 992926deccbSFrançois Tigeot 993926deccbSFrançois Tigeot if (!radeon_connector->edid) { 994926deccbSFrançois Tigeot DRM_ERROR("%s: probed a monitor but no|invalid EDID\n", 995ba55f2f5SFrançois Tigeot connector->name); 996926deccbSFrançois Tigeot ret = connector_status_connected; 997926deccbSFrançois Tigeot } else { 9987191d616Szrj radeon_connector->use_digital = 9997191d616Szrj !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); 1000926deccbSFrançois Tigeot 1001926deccbSFrançois Tigeot /* some oems have boards with separate digital and analog connectors 1002926deccbSFrançois Tigeot * with a shared ddc line (often vga + hdmi) 1003926deccbSFrançois Tigeot */ 1004926deccbSFrançois Tigeot if (radeon_connector->use_digital && radeon_connector->shared_ddc) { 1005ee479021SImre Vadász radeon_connector_free_edid(radeon_connector); 1006926deccbSFrançois Tigeot ret = connector_status_disconnected; 10077191d616Szrj } else { 1008926deccbSFrançois Tigeot ret = connector_status_connected; 1009926deccbSFrançois Tigeot } 10107191d616Szrj } 1011926deccbSFrançois Tigeot } else { 1012926deccbSFrançois Tigeot 1013926deccbSFrançois Tigeot /* if we aren't forcing don't do destructive polling */ 1014926deccbSFrançois Tigeot if (!force) { 1015926deccbSFrançois Tigeot /* only return the previous status if we last 1016926deccbSFrançois Tigeot * detected a monitor via load. 1017926deccbSFrançois Tigeot */ 1018926deccbSFrançois Tigeot if (radeon_connector->detected_by_load) 1019c6f73aabSFrançois Tigeot ret = connector->status; 1020c6f73aabSFrançois Tigeot goto out; 1021926deccbSFrançois Tigeot } 1022926deccbSFrançois Tigeot 1023926deccbSFrançois Tigeot if (radeon_connector->dac_load_detect && encoder) { 1024926deccbSFrançois Tigeot encoder_funcs = encoder->helper_private; 1025926deccbSFrançois Tigeot ret = encoder_funcs->detect(encoder, connector); 1026926deccbSFrançois Tigeot if (ret != connector_status_disconnected) 1027926deccbSFrançois Tigeot radeon_connector->detected_by_load = true; 1028926deccbSFrançois Tigeot } 1029926deccbSFrançois Tigeot } 1030926deccbSFrançois Tigeot 1031926deccbSFrançois Tigeot if (ret == connector_status_connected) 1032926deccbSFrançois Tigeot ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true); 1033926deccbSFrançois Tigeot 1034926deccbSFrançois Tigeot /* RN50 and some RV100 asics in servers often have a hardcoded EDID in the 1035926deccbSFrançois Tigeot * vbios to deal with KVMs. If we have one and are not able to detect a monitor 1036926deccbSFrançois Tigeot * by other means, assume the CRT is connected and use that EDID. 1037926deccbSFrançois Tigeot */ 1038926deccbSFrançois Tigeot if ((!rdev->is_atom_bios) && 1039926deccbSFrançois Tigeot (ret == connector_status_disconnected) && 1040926deccbSFrançois Tigeot rdev->mode_info.bios_hardcoded_edid_size) { 1041926deccbSFrançois Tigeot ret = connector_status_connected; 1042926deccbSFrançois Tigeot } 1043926deccbSFrançois Tigeot 1044926deccbSFrançois Tigeot radeon_connector_update_scratch_regs(connector, ret); 1045c6f73aabSFrançois Tigeot 1046c6f73aabSFrançois Tigeot out: 1047c6f73aabSFrançois Tigeot #ifdef PM_TODO 1048c6f73aabSFrançois Tigeot pm_runtime_mark_last_busy(connector->dev->dev); 1049c6f73aabSFrançois Tigeot pm_runtime_put_autosuspend(connector->dev->dev); 1050c6f73aabSFrançois Tigeot #endif 1051c6f73aabSFrançois Tigeot 1052926deccbSFrançois Tigeot return ret; 1053926deccbSFrançois Tigeot } 1054926deccbSFrançois Tigeot 1055926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_vga_connector_helper_funcs = { 1056926deccbSFrançois Tigeot .get_modes = radeon_vga_get_modes, 1057926deccbSFrançois Tigeot .mode_valid = radeon_vga_mode_valid, 1058926deccbSFrançois Tigeot .best_encoder = radeon_best_single_encoder, 1059926deccbSFrançois Tigeot }; 1060926deccbSFrançois Tigeot 1061926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_vga_connector_funcs = { 1062926deccbSFrançois Tigeot .dpms = drm_helper_connector_dpms, 1063926deccbSFrançois Tigeot .detect = radeon_vga_detect, 1064926deccbSFrançois Tigeot .fill_modes = drm_helper_probe_single_connector_modes, 1065926deccbSFrançois Tigeot .destroy = radeon_connector_destroy, 1066926deccbSFrançois Tigeot .set_property = radeon_connector_set_property, 1067926deccbSFrançois Tigeot }; 1068926deccbSFrançois Tigeot 1069926deccbSFrançois Tigeot static int radeon_tv_get_modes(struct drm_connector *connector) 1070926deccbSFrançois Tigeot { 1071926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 1072926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1073926deccbSFrançois Tigeot struct drm_display_mode *tv_mode; 1074926deccbSFrançois Tigeot struct drm_encoder *encoder; 1075926deccbSFrançois Tigeot 1076926deccbSFrançois Tigeot encoder = radeon_best_single_encoder(connector); 1077926deccbSFrançois Tigeot if (!encoder) 1078926deccbSFrançois Tigeot return 0; 1079926deccbSFrançois Tigeot 1080926deccbSFrançois Tigeot /* avivo chips can scale any mode */ 1081926deccbSFrançois Tigeot if (rdev->family >= CHIP_RS600) 1082926deccbSFrançois Tigeot /* add scaled modes */ 1083926deccbSFrançois Tigeot radeon_add_common_modes(encoder, connector); 1084926deccbSFrançois Tigeot else { 1085926deccbSFrançois Tigeot /* only 800x600 is supported right now on pre-avivo chips */ 1086926deccbSFrançois Tigeot tv_mode = drm_cvt_mode(dev, 800, 600, 60, false, false, false); 1087926deccbSFrançois Tigeot tv_mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 1088926deccbSFrançois Tigeot drm_mode_probed_add(connector, tv_mode); 1089926deccbSFrançois Tigeot } 1090926deccbSFrançois Tigeot return 1; 1091926deccbSFrançois Tigeot } 1092926deccbSFrançois Tigeot 1093926deccbSFrançois Tigeot static int radeon_tv_mode_valid(struct drm_connector *connector, 1094926deccbSFrançois Tigeot struct drm_display_mode *mode) 1095926deccbSFrançois Tigeot { 1096926deccbSFrançois Tigeot if ((mode->hdisplay > 1024) || (mode->vdisplay > 768)) 1097926deccbSFrançois Tigeot return MODE_CLOCK_RANGE; 1098926deccbSFrançois Tigeot return MODE_OK; 1099926deccbSFrançois Tigeot } 1100926deccbSFrançois Tigeot 1101926deccbSFrançois Tigeot static enum drm_connector_status 1102926deccbSFrançois Tigeot radeon_tv_detect(struct drm_connector *connector, bool force) 1103926deccbSFrançois Tigeot { 1104926deccbSFrançois Tigeot struct drm_encoder *encoder; 1105c0e85e96SFrançois Tigeot const struct drm_encoder_helper_funcs *encoder_funcs; 1106926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1107926deccbSFrançois Tigeot enum drm_connector_status ret = connector_status_disconnected; 1108c6f73aabSFrançois Tigeot #ifdef PM_TODO 1109c6f73aabSFrançois Tigeot int r; 1110c6f73aabSFrançois Tigeot #endif 1111926deccbSFrançois Tigeot 1112926deccbSFrançois Tigeot if (!radeon_connector->dac_load_detect) 1113926deccbSFrançois Tigeot return ret; 1114926deccbSFrançois Tigeot 1115c6f73aabSFrançois Tigeot #ifdef PM_TODO 1116c6f73aabSFrançois Tigeot r = pm_runtime_get_sync(connector->dev->dev); 1117c6f73aabSFrançois Tigeot if (r < 0) 1118c6f73aabSFrançois Tigeot return connector_status_disconnected; 1119c6f73aabSFrançois Tigeot #endif 1120c6f73aabSFrançois Tigeot 1121926deccbSFrançois Tigeot encoder = radeon_best_single_encoder(connector); 1122926deccbSFrançois Tigeot if (!encoder) 1123926deccbSFrançois Tigeot ret = connector_status_disconnected; 1124926deccbSFrançois Tigeot else { 1125926deccbSFrançois Tigeot encoder_funcs = encoder->helper_private; 1126926deccbSFrançois Tigeot ret = encoder_funcs->detect(encoder, connector); 1127926deccbSFrançois Tigeot } 1128926deccbSFrançois Tigeot if (ret == connector_status_connected) 1129926deccbSFrançois Tigeot ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false); 1130926deccbSFrançois Tigeot radeon_connector_update_scratch_regs(connector, ret); 1131c6f73aabSFrançois Tigeot #ifdef PM_TODO 1132c6f73aabSFrançois Tigeot pm_runtime_mark_last_busy(connector->dev->dev); 1133c6f73aabSFrançois Tigeot pm_runtime_put_autosuspend(connector->dev->dev); 1134c6f73aabSFrançois Tigeot #endif 1135926deccbSFrançois Tigeot return ret; 1136926deccbSFrançois Tigeot } 1137926deccbSFrançois Tigeot 1138926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_tv_connector_helper_funcs = { 1139926deccbSFrançois Tigeot .get_modes = radeon_tv_get_modes, 1140926deccbSFrançois Tigeot .mode_valid = radeon_tv_mode_valid, 1141926deccbSFrançois Tigeot .best_encoder = radeon_best_single_encoder, 1142926deccbSFrançois Tigeot }; 1143926deccbSFrançois Tigeot 1144926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_tv_connector_funcs = { 1145926deccbSFrançois Tigeot .dpms = drm_helper_connector_dpms, 1146926deccbSFrançois Tigeot .detect = radeon_tv_detect, 1147926deccbSFrançois Tigeot .fill_modes = drm_helper_probe_single_connector_modes, 1148926deccbSFrançois Tigeot .destroy = radeon_connector_destroy, 1149926deccbSFrançois Tigeot .set_property = radeon_connector_set_property, 1150926deccbSFrançois Tigeot }; 1151926deccbSFrançois Tigeot 1152926deccbSFrançois Tigeot static bool radeon_check_hpd_status_unchanged(struct drm_connector *connector) 1153926deccbSFrançois Tigeot { 1154926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 1155926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1156926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1157926deccbSFrançois Tigeot enum drm_connector_status status; 1158926deccbSFrançois Tigeot 1159926deccbSFrançois Tigeot /* We only trust HPD on R600 and newer ASICS. */ 1160926deccbSFrançois Tigeot if (rdev->family >= CHIP_R600 1161926deccbSFrançois Tigeot && radeon_connector->hpd.hpd != RADEON_HPD_NONE) { 1162926deccbSFrançois Tigeot if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) 1163926deccbSFrançois Tigeot status = connector_status_connected; 1164926deccbSFrançois Tigeot else 1165926deccbSFrançois Tigeot status = connector_status_disconnected; 1166926deccbSFrançois Tigeot if (connector->status == status) 1167926deccbSFrançois Tigeot return true; 1168926deccbSFrançois Tigeot } 1169926deccbSFrançois Tigeot 1170926deccbSFrançois Tigeot return false; 1171926deccbSFrançois Tigeot } 1172926deccbSFrançois Tigeot 1173926deccbSFrançois Tigeot /* 1174926deccbSFrançois Tigeot * DVI is complicated 1175926deccbSFrançois Tigeot * Do a DDC probe, if DDC probe passes, get the full EDID so 1176926deccbSFrançois Tigeot * we can do analog/digital monitor detection at this point. 1177926deccbSFrançois Tigeot * If the monitor is an analog monitor or we got no DDC, 1178926deccbSFrançois Tigeot * we need to find the DAC encoder object for this connector. 1179926deccbSFrançois Tigeot * If we got no DDC, we do load detection on the DAC encoder object. 1180926deccbSFrançois Tigeot * If we got analog DDC or load detection passes on the DAC encoder 1181926deccbSFrançois Tigeot * we have to check if this analog encoder is shared with anyone else (TV) 1182926deccbSFrançois Tigeot * if its shared we have to set the other connector to disconnected. 1183926deccbSFrançois Tigeot */ 1184926deccbSFrançois Tigeot static enum drm_connector_status 1185926deccbSFrançois Tigeot radeon_dvi_detect(struct drm_connector *connector, bool force) 1186926deccbSFrançois Tigeot { 1187926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 1188926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1189926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1190926deccbSFrançois Tigeot struct drm_encoder *encoder = NULL; 1191c0e85e96SFrançois Tigeot const struct drm_encoder_helper_funcs *encoder_funcs; 1192926deccbSFrançois Tigeot int i; 1193926deccbSFrançois Tigeot enum drm_connector_status ret = connector_status_disconnected; 1194926deccbSFrançois Tigeot bool dret = false, broken_edid = false; 1195926deccbSFrançois Tigeot 1196c6f73aabSFrançois Tigeot #ifdef PM_TODO 1197c6f73aabSFrançois Tigeot r = pm_runtime_get_sync(connector->dev->dev); 1198c6f73aabSFrançois Tigeot if (r < 0) 1199c6f73aabSFrançois Tigeot return connector_status_disconnected; 1200c6f73aabSFrançois Tigeot #endif 1201c6f73aabSFrançois Tigeot 1202c6f73aabSFrançois Tigeot if (!force && radeon_check_hpd_status_unchanged(connector)) { 1203c6f73aabSFrançois Tigeot ret = connector->status; 1204c6f73aabSFrançois Tigeot goto exit; 1205c6f73aabSFrançois Tigeot } 1206926deccbSFrançois Tigeot 1207926deccbSFrançois Tigeot if (radeon_connector->ddc_bus) 1208926deccbSFrançois Tigeot dret = radeon_ddc_probe(radeon_connector, false); 1209926deccbSFrançois Tigeot if (dret) { 1210926deccbSFrançois Tigeot radeon_connector->detected_by_load = false; 1211ee479021SImre Vadász radeon_connector_free_edid(radeon_connector); 1212ee479021SImre Vadász radeon_connector_get_edid(radeon_connector); 1213926deccbSFrançois Tigeot 1214926deccbSFrançois Tigeot if (!radeon_connector->edid) { 1215926deccbSFrançois Tigeot DRM_ERROR("%s: probed a monitor but no|invalid EDID\n", 1216ba55f2f5SFrançois Tigeot connector->name); 1217926deccbSFrançois Tigeot /* rs690 seems to have a problem with connectors not existing and always 1218926deccbSFrançois Tigeot * return a block of 0's. If we see this just stop polling on this output */ 12197191d616Szrj if ((rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) && 12207191d616Szrj radeon_connector->base.null_edid_counter) { 1221926deccbSFrançois Tigeot ret = connector_status_disconnected; 1222ba55f2f5SFrançois Tigeot DRM_ERROR("%s: detected RS690 floating bus bug, stopping ddc detect\n", 1223ba55f2f5SFrançois Tigeot connector->name); 1224926deccbSFrançois Tigeot radeon_connector->ddc_bus = NULL; 1225926deccbSFrançois Tigeot } else { 1226926deccbSFrançois Tigeot ret = connector_status_connected; 1227926deccbSFrançois Tigeot broken_edid = true; /* defer use_digital to later */ 1228926deccbSFrançois Tigeot } 1229926deccbSFrançois Tigeot } else { 12307191d616Szrj radeon_connector->use_digital = 12317191d616Szrj !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); 1232926deccbSFrançois Tigeot 1233926deccbSFrançois Tigeot /* some oems have boards with separate digital and analog connectors 1234926deccbSFrançois Tigeot * with a shared ddc line (often vga + hdmi) 1235926deccbSFrançois Tigeot */ 1236926deccbSFrançois Tigeot if ((!radeon_connector->use_digital) && radeon_connector->shared_ddc) { 1237ee479021SImre Vadász radeon_connector_free_edid(radeon_connector); 1238926deccbSFrançois Tigeot ret = connector_status_disconnected; 12397191d616Szrj } else { 1240926deccbSFrançois Tigeot ret = connector_status_connected; 12417191d616Szrj } 1242926deccbSFrançois Tigeot /* This gets complicated. We have boards with VGA + HDMI with a 1243926deccbSFrançois Tigeot * shared DDC line and we have boards with DVI-D + HDMI with a shared 1244926deccbSFrançois Tigeot * DDC line. The latter is more complex because with DVI<->HDMI adapters 1245926deccbSFrançois Tigeot * you don't really know what's connected to which port as both are digital. 1246926deccbSFrançois Tigeot */ 1247926deccbSFrançois Tigeot if (radeon_connector->shared_ddc && (ret == connector_status_connected)) { 1248926deccbSFrançois Tigeot struct drm_connector *list_connector; 1249926deccbSFrançois Tigeot struct radeon_connector *list_radeon_connector; 1250926deccbSFrançois Tigeot list_for_each_entry(list_connector, &dev->mode_config.connector_list, head) { 1251926deccbSFrançois Tigeot if (connector == list_connector) 1252926deccbSFrançois Tigeot continue; 1253926deccbSFrançois Tigeot list_radeon_connector = to_radeon_connector(list_connector); 1254926deccbSFrançois Tigeot if (list_radeon_connector->shared_ddc && 1255926deccbSFrançois Tigeot (list_radeon_connector->ddc_bus->rec.i2c_id == 1256926deccbSFrançois Tigeot radeon_connector->ddc_bus->rec.i2c_id)) { 1257926deccbSFrançois Tigeot /* cases where both connectors are digital */ 1258926deccbSFrançois Tigeot if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) { 1259926deccbSFrançois Tigeot /* hpd is our only option in this case */ 1260926deccbSFrançois Tigeot if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) { 1261ee479021SImre Vadász radeon_connector_free_edid(radeon_connector); 1262926deccbSFrançois Tigeot ret = connector_status_disconnected; 1263926deccbSFrançois Tigeot } 1264926deccbSFrançois Tigeot } 1265926deccbSFrançois Tigeot } 1266926deccbSFrançois Tigeot } 1267926deccbSFrançois Tigeot } 1268926deccbSFrançois Tigeot } 1269926deccbSFrançois Tigeot } 1270926deccbSFrançois Tigeot 1271926deccbSFrançois Tigeot if ((ret == connector_status_connected) && (radeon_connector->use_digital == true)) 1272926deccbSFrançois Tigeot goto out; 1273926deccbSFrançois Tigeot 1274926deccbSFrançois Tigeot /* DVI-D and HDMI-A are digital only */ 1275926deccbSFrançois Tigeot if ((connector->connector_type == DRM_MODE_CONNECTOR_DVID) || 1276926deccbSFrançois Tigeot (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)) 1277926deccbSFrançois Tigeot goto out; 1278926deccbSFrançois Tigeot 1279926deccbSFrançois Tigeot /* if we aren't forcing don't do destructive polling */ 1280926deccbSFrançois Tigeot if (!force) { 1281926deccbSFrançois Tigeot /* only return the previous status if we last 1282926deccbSFrançois Tigeot * detected a monitor via load. 1283926deccbSFrançois Tigeot */ 1284926deccbSFrançois Tigeot if (radeon_connector->detected_by_load) 1285926deccbSFrançois Tigeot ret = connector->status; 1286926deccbSFrançois Tigeot goto out; 1287926deccbSFrançois Tigeot } 1288926deccbSFrançois Tigeot 1289926deccbSFrançois Tigeot /* find analog encoder */ 1290926deccbSFrançois Tigeot if (radeon_connector->dac_load_detect) { 1291926deccbSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 1292926deccbSFrançois Tigeot if (connector->encoder_ids[i] == 0) 1293926deccbSFrançois Tigeot break; 1294926deccbSFrançois Tigeot 1295c6f73aabSFrançois Tigeot encoder = drm_encoder_find(connector->dev, 1296c6f73aabSFrançois Tigeot connector->encoder_ids[i]); 1297c6f73aabSFrançois Tigeot if (!encoder) 1298926deccbSFrançois Tigeot continue; 1299926deccbSFrançois Tigeot 1300926deccbSFrançois Tigeot if (encoder->encoder_type != DRM_MODE_ENCODER_DAC && 1301926deccbSFrançois Tigeot encoder->encoder_type != DRM_MODE_ENCODER_TVDAC) 1302926deccbSFrançois Tigeot continue; 1303926deccbSFrançois Tigeot 1304926deccbSFrançois Tigeot encoder_funcs = encoder->helper_private; 1305926deccbSFrançois Tigeot if (encoder_funcs->detect) { 1306926deccbSFrançois Tigeot if (!broken_edid) { 1307926deccbSFrançois Tigeot if (ret != connector_status_connected) { 1308926deccbSFrançois Tigeot /* deal with analog monitors without DDC */ 1309926deccbSFrançois Tigeot ret = encoder_funcs->detect(encoder, connector); 1310926deccbSFrançois Tigeot if (ret == connector_status_connected) { 1311926deccbSFrançois Tigeot radeon_connector->use_digital = false; 1312926deccbSFrançois Tigeot } 1313926deccbSFrançois Tigeot if (ret != connector_status_disconnected) 1314926deccbSFrançois Tigeot radeon_connector->detected_by_load = true; 1315926deccbSFrançois Tigeot } 1316926deccbSFrançois Tigeot } else { 1317926deccbSFrançois Tigeot enum drm_connector_status lret; 1318926deccbSFrançois Tigeot /* assume digital unless load detected otherwise */ 1319926deccbSFrançois Tigeot radeon_connector->use_digital = true; 1320926deccbSFrançois Tigeot lret = encoder_funcs->detect(encoder, connector); 1321926deccbSFrançois Tigeot DRM_DEBUG_KMS("load_detect %x returned: %x\n",encoder->encoder_type,lret); 1322926deccbSFrançois Tigeot if (lret == connector_status_connected) 1323926deccbSFrançois Tigeot radeon_connector->use_digital = false; 1324926deccbSFrançois Tigeot } 1325926deccbSFrançois Tigeot break; 1326926deccbSFrançois Tigeot } 1327926deccbSFrançois Tigeot } 1328926deccbSFrançois Tigeot } 1329926deccbSFrançois Tigeot 1330926deccbSFrançois Tigeot if ((ret == connector_status_connected) && (radeon_connector->use_digital == false) && 1331926deccbSFrançois Tigeot encoder) { 1332926deccbSFrançois Tigeot ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true); 1333926deccbSFrançois Tigeot } 1334926deccbSFrançois Tigeot 1335926deccbSFrançois Tigeot /* RN50 and some RV100 asics in servers often have a hardcoded EDID in the 1336926deccbSFrançois Tigeot * vbios to deal with KVMs. If we have one and are not able to detect a monitor 1337926deccbSFrançois Tigeot * by other means, assume the DFP is connected and use that EDID. In most 1338926deccbSFrançois Tigeot * cases the DVI port is actually a virtual KVM port connected to the service 1339926deccbSFrançois Tigeot * processor. 1340926deccbSFrançois Tigeot */ 1341926deccbSFrançois Tigeot out: 1342926deccbSFrançois Tigeot if ((!rdev->is_atom_bios) && 1343926deccbSFrançois Tigeot (ret == connector_status_disconnected) && 1344926deccbSFrançois Tigeot rdev->mode_info.bios_hardcoded_edid_size) { 1345926deccbSFrançois Tigeot radeon_connector->use_digital = true; 1346926deccbSFrançois Tigeot ret = connector_status_connected; 1347926deccbSFrançois Tigeot } 1348926deccbSFrançois Tigeot 1349926deccbSFrançois Tigeot /* updated in get modes as well since we need to know if it's analog or digital */ 1350926deccbSFrançois Tigeot radeon_connector_update_scratch_regs(connector, ret); 1351c6f73aabSFrançois Tigeot 1352c6f73aabSFrançois Tigeot exit: 1353c6f73aabSFrançois Tigeot #ifdef PM_TODO 1354c6f73aabSFrançois Tigeot pm_runtime_mark_last_busy(connector->dev->dev); 1355c6f73aabSFrançois Tigeot pm_runtime_put_autosuspend(connector->dev->dev); 1356c6f73aabSFrançois Tigeot #endif 1357c6f73aabSFrançois Tigeot 1358926deccbSFrançois Tigeot return ret; 1359926deccbSFrançois Tigeot } 1360926deccbSFrançois Tigeot 1361926deccbSFrançois Tigeot /* okay need to be smart in here about which encoder to pick */ 1362926deccbSFrançois Tigeot static struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector) 1363926deccbSFrançois Tigeot { 1364926deccbSFrançois Tigeot int enc_id = connector->encoder_ids[0]; 1365926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1366926deccbSFrançois Tigeot struct drm_encoder *encoder; 1367926deccbSFrançois Tigeot int i; 1368926deccbSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 1369926deccbSFrançois Tigeot if (connector->encoder_ids[i] == 0) 1370926deccbSFrançois Tigeot break; 1371926deccbSFrançois Tigeot 1372c6f73aabSFrançois Tigeot encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); 1373c6f73aabSFrançois Tigeot if (!encoder) 1374926deccbSFrançois Tigeot continue; 1375926deccbSFrançois Tigeot 1376926deccbSFrançois Tigeot if (radeon_connector->use_digital == true) { 1377926deccbSFrançois Tigeot if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS) 1378926deccbSFrançois Tigeot return encoder; 1379926deccbSFrançois Tigeot } else { 1380926deccbSFrançois Tigeot if (encoder->encoder_type == DRM_MODE_ENCODER_DAC || 1381926deccbSFrançois Tigeot encoder->encoder_type == DRM_MODE_ENCODER_TVDAC) 1382926deccbSFrançois Tigeot return encoder; 1383926deccbSFrançois Tigeot } 1384926deccbSFrançois Tigeot } 1385926deccbSFrançois Tigeot 1386926deccbSFrançois Tigeot /* see if we have a default encoder TODO */ 1387926deccbSFrançois Tigeot 1388926deccbSFrançois Tigeot /* then check use digitial */ 1389926deccbSFrançois Tigeot /* pick the first one */ 1390c6f73aabSFrançois Tigeot if (enc_id) 1391c6f73aabSFrançois Tigeot return drm_encoder_find(connector->dev, enc_id); 1392926deccbSFrançois Tigeot return NULL; 1393926deccbSFrançois Tigeot } 1394926deccbSFrançois Tigeot 1395926deccbSFrançois Tigeot static void radeon_dvi_force(struct drm_connector *connector) 1396926deccbSFrançois Tigeot { 1397926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1398926deccbSFrançois Tigeot if (connector->force == DRM_FORCE_ON) 1399926deccbSFrançois Tigeot radeon_connector->use_digital = false; 1400926deccbSFrançois Tigeot if (connector->force == DRM_FORCE_ON_DIGITAL) 1401926deccbSFrançois Tigeot radeon_connector->use_digital = true; 1402926deccbSFrançois Tigeot } 1403926deccbSFrançois Tigeot 1404926deccbSFrançois Tigeot static int radeon_dvi_mode_valid(struct drm_connector *connector, 1405926deccbSFrançois Tigeot struct drm_display_mode *mode) 1406926deccbSFrançois Tigeot { 1407926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 1408926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1409926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1410926deccbSFrançois Tigeot 1411926deccbSFrançois Tigeot /* XXX check mode bandwidth */ 1412926deccbSFrançois Tigeot 1413926deccbSFrançois Tigeot /* clocks over 135 MHz have heat issues with DVI on RV100 */ 1414926deccbSFrançois Tigeot if (radeon_connector->use_digital && 1415926deccbSFrançois Tigeot (rdev->family == CHIP_RV100) && 1416926deccbSFrançois Tigeot (mode->clock > 135000)) 1417926deccbSFrançois Tigeot return MODE_CLOCK_HIGH; 1418926deccbSFrançois Tigeot 1419926deccbSFrançois Tigeot if (radeon_connector->use_digital && (mode->clock > 165000)) { 1420926deccbSFrançois Tigeot if ((radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I) || 1421926deccbSFrançois Tigeot (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D) || 1422926deccbSFrançois Tigeot (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_B)) 1423926deccbSFrançois Tigeot return MODE_OK; 1424c6f73aabSFrançois Tigeot else if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { 1425926deccbSFrançois Tigeot /* HDMI 1.3+ supports max clock of 340 Mhz */ 1426926deccbSFrançois Tigeot if (mode->clock > 340000) 1427926deccbSFrançois Tigeot return MODE_CLOCK_HIGH; 1428926deccbSFrançois Tigeot else 1429926deccbSFrançois Tigeot return MODE_OK; 1430c6f73aabSFrançois Tigeot } else { 1431926deccbSFrançois Tigeot return MODE_CLOCK_HIGH; 1432c6f73aabSFrançois Tigeot } 1433926deccbSFrançois Tigeot } 1434926deccbSFrançois Tigeot 1435926deccbSFrançois Tigeot /* check against the max pixel clock */ 1436926deccbSFrançois Tigeot if ((mode->clock / 10) > rdev->clock.max_pixel_clock) 1437926deccbSFrançois Tigeot return MODE_CLOCK_HIGH; 1438926deccbSFrançois Tigeot 1439926deccbSFrançois Tigeot return MODE_OK; 1440926deccbSFrançois Tigeot } 1441926deccbSFrançois Tigeot 1442926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = { 1443c6f73aabSFrançois Tigeot .get_modes = radeon_vga_get_modes, 1444926deccbSFrançois Tigeot .mode_valid = radeon_dvi_mode_valid, 1445926deccbSFrançois Tigeot .best_encoder = radeon_dvi_encoder, 1446926deccbSFrançois Tigeot }; 1447926deccbSFrançois Tigeot 1448926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_dvi_connector_funcs = { 1449926deccbSFrançois Tigeot .dpms = drm_helper_connector_dpms, 1450926deccbSFrançois Tigeot .detect = radeon_dvi_detect, 1451926deccbSFrançois Tigeot .fill_modes = drm_helper_probe_single_connector_modes, 1452926deccbSFrançois Tigeot .set_property = radeon_connector_set_property, 1453926deccbSFrançois Tigeot .destroy = radeon_connector_destroy, 1454926deccbSFrançois Tigeot .force = radeon_dvi_force, 1455926deccbSFrançois Tigeot }; 1456926deccbSFrançois Tigeot 1457ee479021SImre Vadász static void radeon_dp_connector_destroy(struct drm_connector *connector) 1458ee479021SImre Vadász { 1459ee479021SImre Vadász struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1460ee479021SImre Vadász struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; 1461ee479021SImre Vadász 1462ee479021SImre Vadász radeon_connector_free_edid(radeon_connector); 1463ee479021SImre Vadász if (radeon_dig_connector->dp_i2c_bus) 1464ee479021SImre Vadász radeon_i2c_destroy(radeon_dig_connector->dp_i2c_bus); 1465ee479021SImre Vadász kfree(radeon_connector->con_priv); 1466ee479021SImre Vadász drm_connector_unregister(connector); 1467ee479021SImre Vadász drm_connector_cleanup(connector); 1468ee479021SImre Vadász kfree(connector); 1469ee479021SImre Vadász } 1470ee479021SImre Vadász 1471926deccbSFrançois Tigeot static int radeon_dp_get_modes(struct drm_connector *connector) 1472926deccbSFrançois Tigeot { 1473926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1474926deccbSFrançois Tigeot struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; 1475926deccbSFrançois Tigeot struct drm_encoder *encoder = radeon_best_single_encoder(connector); 1476926deccbSFrançois Tigeot int ret; 1477926deccbSFrançois Tigeot 1478926deccbSFrançois Tigeot if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) || 1479926deccbSFrançois Tigeot (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) { 1480926deccbSFrançois Tigeot struct drm_display_mode *mode; 1481926deccbSFrançois Tigeot 1482926deccbSFrançois Tigeot if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { 1483926deccbSFrançois Tigeot if (!radeon_dig_connector->edp_on) 1484926deccbSFrançois Tigeot atombios_set_edp_panel_power(connector, 1485926deccbSFrançois Tigeot ATOM_TRANSMITTER_ACTION_POWER_ON); 1486ee479021SImre Vadász radeon_connector_get_edid(radeon_connector); 1487ee479021SImre Vadász ret = radeon_ddc_get_modes(radeon_connector); 1488926deccbSFrançois Tigeot if (!radeon_dig_connector->edp_on) 1489926deccbSFrançois Tigeot atombios_set_edp_panel_power(connector, 1490926deccbSFrançois Tigeot ATOM_TRANSMITTER_ACTION_POWER_OFF); 1491926deccbSFrançois Tigeot } else { 1492926deccbSFrançois Tigeot /* need to setup ddc on the bridge */ 1493926deccbSFrançois Tigeot if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) != 1494926deccbSFrançois Tigeot ENCODER_OBJECT_ID_NONE) { 1495926deccbSFrançois Tigeot if (encoder) 1496926deccbSFrançois Tigeot radeon_atom_ext_encoder_setup_ddc(encoder); 1497926deccbSFrançois Tigeot } 1498ee479021SImre Vadász radeon_connector_get_edid(radeon_connector); 1499ee479021SImre Vadász ret = radeon_ddc_get_modes(radeon_connector); 1500926deccbSFrançois Tigeot } 1501926deccbSFrançois Tigeot 1502926deccbSFrançois Tigeot if (ret > 0) { 1503926deccbSFrançois Tigeot if (encoder) { 1504926deccbSFrançois Tigeot radeon_fixup_lvds_native_mode(encoder, connector); 1505926deccbSFrançois Tigeot /* add scaled modes */ 1506926deccbSFrançois Tigeot radeon_add_common_modes(encoder, connector); 1507926deccbSFrançois Tigeot } 1508926deccbSFrançois Tigeot return ret; 1509926deccbSFrançois Tigeot } 1510926deccbSFrançois Tigeot 1511926deccbSFrançois Tigeot if (!encoder) 1512926deccbSFrançois Tigeot return 0; 1513926deccbSFrançois Tigeot 1514926deccbSFrançois Tigeot /* we have no EDID modes */ 1515926deccbSFrançois Tigeot mode = radeon_fp_native_mode(encoder); 1516926deccbSFrançois Tigeot if (mode) { 1517926deccbSFrançois Tigeot ret = 1; 1518926deccbSFrançois Tigeot drm_mode_probed_add(connector, mode); 1519926deccbSFrançois Tigeot /* add the width/height from vbios tables if available */ 1520926deccbSFrançois Tigeot connector->display_info.width_mm = mode->width_mm; 1521926deccbSFrançois Tigeot connector->display_info.height_mm = mode->height_mm; 1522926deccbSFrançois Tigeot /* add scaled modes */ 1523926deccbSFrançois Tigeot radeon_add_common_modes(encoder, connector); 1524926deccbSFrançois Tigeot } 1525926deccbSFrançois Tigeot } else { 1526926deccbSFrançois Tigeot /* need to setup ddc on the bridge */ 1527926deccbSFrançois Tigeot if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) != 1528926deccbSFrançois Tigeot ENCODER_OBJECT_ID_NONE) { 1529926deccbSFrançois Tigeot if (encoder) 1530926deccbSFrançois Tigeot radeon_atom_ext_encoder_setup_ddc(encoder); 1531926deccbSFrançois Tigeot } 1532ee479021SImre Vadász radeon_connector_get_edid(radeon_connector); 1533ee479021SImre Vadász ret = radeon_ddc_get_modes(radeon_connector); 1534c6f73aabSFrançois Tigeot 1535c6f73aabSFrançois Tigeot radeon_get_native_mode(connector); 1536926deccbSFrançois Tigeot } 1537926deccbSFrançois Tigeot 1538926deccbSFrançois Tigeot return ret; 1539926deccbSFrançois Tigeot } 1540926deccbSFrançois Tigeot 1541926deccbSFrançois Tigeot u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector) 1542926deccbSFrançois Tigeot { 1543926deccbSFrançois Tigeot struct drm_encoder *encoder; 1544926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder; 1545926deccbSFrançois Tigeot int i; 1546926deccbSFrançois Tigeot 1547926deccbSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 1548926deccbSFrançois Tigeot if (connector->encoder_ids[i] == 0) 1549926deccbSFrançois Tigeot break; 1550926deccbSFrançois Tigeot 1551c6f73aabSFrançois Tigeot encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); 1552c6f73aabSFrançois Tigeot if (!encoder) 1553926deccbSFrançois Tigeot continue; 1554926deccbSFrançois Tigeot 1555926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 1556926deccbSFrançois Tigeot 1557926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 1558926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_TRAVIS: 1559926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_NUTMEG: 1560926deccbSFrançois Tigeot return radeon_encoder->encoder_id; 1561926deccbSFrançois Tigeot default: 1562926deccbSFrançois Tigeot break; 1563926deccbSFrançois Tigeot } 1564926deccbSFrançois Tigeot } 1565926deccbSFrançois Tigeot 1566926deccbSFrançois Tigeot return ENCODER_OBJECT_ID_NONE; 1567926deccbSFrançois Tigeot } 1568926deccbSFrançois Tigeot 1569c6f73aabSFrançois Tigeot static bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector) 1570926deccbSFrançois Tigeot { 1571926deccbSFrançois Tigeot struct drm_encoder *encoder; 1572926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder; 1573926deccbSFrançois Tigeot int i; 1574926deccbSFrançois Tigeot bool found = false; 1575926deccbSFrançois Tigeot 1576926deccbSFrançois Tigeot for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 1577926deccbSFrançois Tigeot if (connector->encoder_ids[i] == 0) 1578926deccbSFrançois Tigeot break; 1579926deccbSFrançois Tigeot 1580c6f73aabSFrançois Tigeot encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); 1581c6f73aabSFrançois Tigeot if (!encoder) 1582926deccbSFrançois Tigeot continue; 1583926deccbSFrançois Tigeot 1584926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 1585926deccbSFrançois Tigeot if (radeon_encoder->caps & ATOM_ENCODER_CAP_RECORD_HBR2) 1586926deccbSFrançois Tigeot found = true; 1587926deccbSFrançois Tigeot } 1588926deccbSFrançois Tigeot 1589926deccbSFrançois Tigeot return found; 1590926deccbSFrançois Tigeot } 1591926deccbSFrançois Tigeot 1592926deccbSFrançois Tigeot bool radeon_connector_is_dp12_capable(struct drm_connector *connector) 1593926deccbSFrançois Tigeot { 1594926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 1595926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1596926deccbSFrançois Tigeot 1597926deccbSFrançois Tigeot if (ASIC_IS_DCE5(rdev) && 1598c6f73aabSFrançois Tigeot (rdev->clock.default_dispclk >= 53900) && 1599926deccbSFrançois Tigeot radeon_connector_encoder_is_hbr2(connector)) { 1600926deccbSFrançois Tigeot return true; 1601926deccbSFrançois Tigeot } 1602926deccbSFrançois Tigeot 1603926deccbSFrançois Tigeot return false; 1604926deccbSFrançois Tigeot } 1605926deccbSFrançois Tigeot 1606926deccbSFrançois Tigeot static enum drm_connector_status 1607926deccbSFrançois Tigeot radeon_dp_detect(struct drm_connector *connector, bool force) 1608926deccbSFrançois Tigeot { 1609926deccbSFrançois Tigeot struct drm_device *dev = connector->dev; 1610926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1611926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1612926deccbSFrançois Tigeot enum drm_connector_status ret = connector_status_disconnected; 1613926deccbSFrançois Tigeot struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; 1614926deccbSFrançois Tigeot struct drm_encoder *encoder = radeon_best_single_encoder(connector); 1615c6f73aabSFrançois Tigeot #ifdef PM_TODO 1616c6f73aabSFrançois Tigeot int r; 1617926deccbSFrançois Tigeot 1618c6f73aabSFrançois Tigeot r = pm_runtime_get_sync(connector->dev->dev); 1619c6f73aabSFrançois Tigeot if (r < 0) 1620c6f73aabSFrançois Tigeot return connector_status_disconnected; 1621c6f73aabSFrançois Tigeot #endif 1622c6f73aabSFrançois Tigeot 1623c6f73aabSFrançois Tigeot if (!force && radeon_check_hpd_status_unchanged(connector)) { 1624c6f73aabSFrançois Tigeot ret = connector->status; 1625c6f73aabSFrançois Tigeot goto out; 1626c6f73aabSFrançois Tigeot } 1627926deccbSFrançois Tigeot 1628ee479021SImre Vadász radeon_connector_free_edid(radeon_connector); 1629926deccbSFrançois Tigeot 1630926deccbSFrançois Tigeot if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) || 1631926deccbSFrançois Tigeot (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) { 1632926deccbSFrançois Tigeot if (encoder) { 1633926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 1634926deccbSFrançois Tigeot struct drm_display_mode *native_mode = &radeon_encoder->native_mode; 1635926deccbSFrançois Tigeot 1636926deccbSFrançois Tigeot /* check if panel is valid */ 1637926deccbSFrançois Tigeot if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240) 1638926deccbSFrançois Tigeot ret = connector_status_connected; 1639926deccbSFrançois Tigeot } 1640926deccbSFrançois Tigeot /* eDP is always DP */ 1641926deccbSFrançois Tigeot radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT; 1642926deccbSFrançois Tigeot if (!radeon_dig_connector->edp_on) 1643926deccbSFrançois Tigeot atombios_set_edp_panel_power(connector, 1644926deccbSFrançois Tigeot ATOM_TRANSMITTER_ACTION_POWER_ON); 1645926deccbSFrançois Tigeot if (radeon_dp_getdpcd(radeon_connector)) 1646926deccbSFrançois Tigeot ret = connector_status_connected; 1647926deccbSFrançois Tigeot if (!radeon_dig_connector->edp_on) 1648926deccbSFrançois Tigeot atombios_set_edp_panel_power(connector, 1649926deccbSFrançois Tigeot ATOM_TRANSMITTER_ACTION_POWER_OFF); 1650926deccbSFrançois Tigeot } else if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) != 1651926deccbSFrançois Tigeot ENCODER_OBJECT_ID_NONE) { 1652926deccbSFrançois Tigeot /* DP bridges are always DP */ 1653926deccbSFrançois Tigeot radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT; 1654926deccbSFrançois Tigeot /* get the DPCD from the bridge */ 1655926deccbSFrançois Tigeot radeon_dp_getdpcd(radeon_connector); 1656926deccbSFrançois Tigeot 1657926deccbSFrançois Tigeot if (encoder) { 1658926deccbSFrançois Tigeot /* setup ddc on the bridge */ 1659926deccbSFrançois Tigeot radeon_atom_ext_encoder_setup_ddc(encoder); 1660926deccbSFrançois Tigeot /* bridge chips are always aux */ 1661926deccbSFrançois Tigeot if (radeon_ddc_probe(radeon_connector, true)) /* try DDC */ 1662926deccbSFrançois Tigeot ret = connector_status_connected; 1663926deccbSFrançois Tigeot else if (radeon_connector->dac_load_detect) { /* try load detection */ 1664c0e85e96SFrançois Tigeot const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; 1665926deccbSFrançois Tigeot ret = encoder_funcs->detect(encoder, connector); 1666926deccbSFrançois Tigeot } 1667926deccbSFrançois Tigeot } 1668926deccbSFrançois Tigeot } else { 1669926deccbSFrançois Tigeot radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector); 1670926deccbSFrançois Tigeot if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) { 1671926deccbSFrançois Tigeot ret = connector_status_connected; 1672926deccbSFrançois Tigeot if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) 1673926deccbSFrançois Tigeot radeon_dp_getdpcd(radeon_connector); 1674926deccbSFrançois Tigeot } else { 1675926deccbSFrançois Tigeot if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { 1676926deccbSFrançois Tigeot if (radeon_dp_getdpcd(radeon_connector)) 1677926deccbSFrançois Tigeot ret = connector_status_connected; 1678926deccbSFrançois Tigeot } else { 16794cd92098Szrj /* try non-aux ddc (DP to DVI/HDMI/etc. adapter) */ 1680926deccbSFrançois Tigeot if (radeon_ddc_probe(radeon_connector, false)) 1681926deccbSFrançois Tigeot ret = connector_status_connected; 1682926deccbSFrançois Tigeot } 1683926deccbSFrançois Tigeot } 1684926deccbSFrançois Tigeot } 1685926deccbSFrançois Tigeot 1686926deccbSFrançois Tigeot radeon_connector_update_scratch_regs(connector, ret); 1687c6f73aabSFrançois Tigeot out: 1688c6f73aabSFrançois Tigeot #ifdef PM_TODO 1689c6f73aabSFrançois Tigeot pm_runtime_mark_last_busy(connector->dev->dev); 1690c6f73aabSFrançois Tigeot pm_runtime_put_autosuspend(connector->dev->dev); 1691c6f73aabSFrançois Tigeot #endif 1692c6f73aabSFrançois Tigeot 1693926deccbSFrançois Tigeot return ret; 1694926deccbSFrançois Tigeot } 1695926deccbSFrançois Tigeot 1696926deccbSFrançois Tigeot static int radeon_dp_mode_valid(struct drm_connector *connector, 1697926deccbSFrançois Tigeot struct drm_display_mode *mode) 1698926deccbSFrançois Tigeot { 1699c6f73aabSFrançois Tigeot struct drm_device *dev = connector->dev; 1700c6f73aabSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1701926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector); 1702926deccbSFrançois Tigeot struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; 1703926deccbSFrançois Tigeot 1704926deccbSFrançois Tigeot /* XXX check mode bandwidth */ 1705926deccbSFrançois Tigeot 1706926deccbSFrançois Tigeot if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) || 1707926deccbSFrançois Tigeot (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) { 1708926deccbSFrançois Tigeot struct drm_encoder *encoder = radeon_best_single_encoder(connector); 1709926deccbSFrançois Tigeot 1710926deccbSFrançois Tigeot if ((mode->hdisplay < 320) || (mode->vdisplay < 240)) 1711926deccbSFrançois Tigeot return MODE_PANEL; 1712926deccbSFrançois Tigeot 1713926deccbSFrançois Tigeot if (encoder) { 1714926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 1715926deccbSFrançois Tigeot struct drm_display_mode *native_mode = &radeon_encoder->native_mode; 1716926deccbSFrançois Tigeot 1717926deccbSFrançois Tigeot /* AVIVO hardware supports downscaling modes larger than the panel 1718926deccbSFrançois Tigeot * to the panel size, but I'm not sure this is desirable. 1719926deccbSFrançois Tigeot */ 1720926deccbSFrançois Tigeot if ((mode->hdisplay > native_mode->hdisplay) || 1721926deccbSFrançois Tigeot (mode->vdisplay > native_mode->vdisplay)) 1722926deccbSFrançois Tigeot return MODE_PANEL; 1723926deccbSFrançois Tigeot 1724926deccbSFrançois Tigeot /* if scaling is disabled, block non-native modes */ 1725926deccbSFrançois Tigeot if (radeon_encoder->rmx_type == RMX_OFF) { 1726926deccbSFrançois Tigeot if ((mode->hdisplay != native_mode->hdisplay) || 1727926deccbSFrançois Tigeot (mode->vdisplay != native_mode->vdisplay)) 1728926deccbSFrançois Tigeot return MODE_PANEL; 1729926deccbSFrançois Tigeot } 1730926deccbSFrançois Tigeot } 1731926deccbSFrançois Tigeot } else { 1732926deccbSFrançois Tigeot if ((radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || 1733c6f73aabSFrançois Tigeot (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) { 1734926deccbSFrançois Tigeot return radeon_dp_mode_valid_helper(connector, mode); 1735c6f73aabSFrançois Tigeot } else { 1736c6f73aabSFrançois Tigeot if (ASIC_IS_DCE6(rdev) && drm_detect_hdmi_monitor(radeon_connector_edid(connector))) { 1737c6f73aabSFrançois Tigeot /* HDMI 1.3+ supports max clock of 340 Mhz */ 1738c6f73aabSFrançois Tigeot if (mode->clock > 340000) 1739c6f73aabSFrançois Tigeot return MODE_CLOCK_HIGH; 1740c6f73aabSFrançois Tigeot } else { 1741c6f73aabSFrançois Tigeot if (mode->clock > 165000) 1742c6f73aabSFrançois Tigeot return MODE_CLOCK_HIGH; 1743926deccbSFrançois Tigeot } 1744926deccbSFrançois Tigeot } 1745c6f73aabSFrançois Tigeot } 1746c6f73aabSFrançois Tigeot 1747c6f73aabSFrançois Tigeot return MODE_OK; 1748c6f73aabSFrançois Tigeot } 1749926deccbSFrançois Tigeot 1750926deccbSFrançois Tigeot static const struct drm_connector_helper_funcs radeon_dp_connector_helper_funcs = { 1751926deccbSFrançois Tigeot .get_modes = radeon_dp_get_modes, 1752926deccbSFrançois Tigeot .mode_valid = radeon_dp_mode_valid, 1753926deccbSFrançois Tigeot .best_encoder = radeon_dvi_encoder, 1754926deccbSFrançois Tigeot }; 1755926deccbSFrançois Tigeot 1756926deccbSFrançois Tigeot static const struct drm_connector_funcs radeon_dp_connector_funcs = { 1757926deccbSFrançois Tigeot .dpms = drm_helper_connector_dpms, 1758926deccbSFrançois Tigeot .detect = radeon_dp_detect, 1759926deccbSFrançois Tigeot .fill_modes = drm_helper_probe_single_connector_modes, 1760926deccbSFrançois Tigeot .set_property = radeon_connector_set_property, 1761ee479021SImre Vadász .destroy = radeon_dp_connector_destroy, 1762926deccbSFrançois Tigeot .force = radeon_dvi_force, 1763926deccbSFrançois Tigeot }; 1764926deccbSFrançois Tigeot 17654cd92098Szrj static const struct drm_connector_funcs radeon_edp_connector_funcs = { 17664cd92098Szrj .dpms = drm_helper_connector_dpms, 17674cd92098Szrj .detect = radeon_dp_detect, 17684cd92098Szrj .fill_modes = drm_helper_probe_single_connector_modes, 17694cd92098Szrj .set_property = radeon_lvds_set_property, 1770ee479021SImre Vadász .destroy = radeon_dp_connector_destroy, 17714cd92098Szrj .force = radeon_dvi_force, 17724cd92098Szrj }; 17734cd92098Szrj 17744cd92098Szrj static const struct drm_connector_funcs radeon_lvds_bridge_connector_funcs = { 17754cd92098Szrj .dpms = drm_helper_connector_dpms, 17764cd92098Szrj .detect = radeon_dp_detect, 17774cd92098Szrj .fill_modes = drm_helper_probe_single_connector_modes, 17784cd92098Szrj .set_property = radeon_lvds_set_property, 1779ee479021SImre Vadász .destroy = radeon_dp_connector_destroy, 17804cd92098Szrj .force = radeon_dvi_force, 17814cd92098Szrj }; 17824cd92098Szrj 1783926deccbSFrançois Tigeot void 1784926deccbSFrançois Tigeot radeon_add_atom_connector(struct drm_device *dev, 1785926deccbSFrançois Tigeot uint32_t connector_id, 1786926deccbSFrançois Tigeot uint32_t supported_device, 1787926deccbSFrançois Tigeot int connector_type, 1788926deccbSFrançois Tigeot struct radeon_i2c_bus_rec *i2c_bus, 1789926deccbSFrançois Tigeot uint32_t igp_lane_info, 1790926deccbSFrançois Tigeot uint16_t connector_object_id, 1791926deccbSFrançois Tigeot struct radeon_hpd *hpd, 1792926deccbSFrançois Tigeot struct radeon_router *router) 1793926deccbSFrançois Tigeot { 1794926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 1795926deccbSFrançois Tigeot struct drm_connector *connector; 1796926deccbSFrançois Tigeot struct radeon_connector *radeon_connector; 1797926deccbSFrançois Tigeot struct radeon_connector_atom_dig *radeon_dig_connector; 1798926deccbSFrançois Tigeot struct drm_encoder *encoder; 1799926deccbSFrançois Tigeot struct radeon_encoder *radeon_encoder; 1800926deccbSFrançois Tigeot uint32_t subpixel_order = SubPixelNone; 1801926deccbSFrançois Tigeot bool shared_ddc = false; 1802926deccbSFrançois Tigeot bool is_dp_bridge = false; 18037191d616Szrj bool has_aux = false; 1804926deccbSFrançois Tigeot 1805926deccbSFrançois Tigeot if (connector_type == DRM_MODE_CONNECTOR_Unknown) 1806926deccbSFrançois Tigeot return; 1807926deccbSFrançois Tigeot 1808926deccbSFrançois Tigeot /* if the user selected tv=0 don't try and add the connector */ 1809926deccbSFrançois Tigeot if (((connector_type == DRM_MODE_CONNECTOR_SVIDEO) || 1810926deccbSFrançois Tigeot (connector_type == DRM_MODE_CONNECTOR_Composite) || 1811926deccbSFrançois Tigeot (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) && 1812926deccbSFrançois Tigeot (radeon_tv == 0)) 1813926deccbSFrançois Tigeot return; 1814926deccbSFrançois Tigeot 1815926deccbSFrançois Tigeot /* see if we already added it */ 1816926deccbSFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 1817926deccbSFrançois Tigeot radeon_connector = to_radeon_connector(connector); 1818926deccbSFrançois Tigeot if (radeon_connector->connector_id == connector_id) { 1819926deccbSFrançois Tigeot radeon_connector->devices |= supported_device; 1820926deccbSFrançois Tigeot return; 1821926deccbSFrançois Tigeot } 1822926deccbSFrançois Tigeot if (radeon_connector->ddc_bus && i2c_bus->valid) { 1823926deccbSFrançois Tigeot if (radeon_connector->ddc_bus->rec.i2c_id == i2c_bus->i2c_id) { 1824926deccbSFrançois Tigeot radeon_connector->shared_ddc = true; 1825926deccbSFrançois Tigeot shared_ddc = true; 1826926deccbSFrançois Tigeot } 1827926deccbSFrançois Tigeot if (radeon_connector->router_bus && router->ddc_valid && 1828926deccbSFrançois Tigeot (radeon_connector->router.router_id == router->router_id)) { 1829926deccbSFrançois Tigeot radeon_connector->shared_ddc = false; 1830926deccbSFrançois Tigeot shared_ddc = false; 1831926deccbSFrançois Tigeot } 1832926deccbSFrançois Tigeot } 1833926deccbSFrançois Tigeot } 1834926deccbSFrançois Tigeot 1835926deccbSFrançois Tigeot /* check if it's a dp bridge */ 1836926deccbSFrançois Tigeot list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 1837926deccbSFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder); 1838926deccbSFrançois Tigeot if (radeon_encoder->devices & supported_device) { 1839926deccbSFrançois Tigeot switch (radeon_encoder->encoder_id) { 1840926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_TRAVIS: 1841926deccbSFrançois Tigeot case ENCODER_OBJECT_ID_NUTMEG: 1842926deccbSFrançois Tigeot is_dp_bridge = true; 1843926deccbSFrançois Tigeot break; 1844926deccbSFrançois Tigeot default: 1845926deccbSFrançois Tigeot break; 1846926deccbSFrançois Tigeot } 1847926deccbSFrançois Tigeot } 1848926deccbSFrançois Tigeot } 1849926deccbSFrançois Tigeot 1850c4ef309bSzrj radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL); 1851926deccbSFrançois Tigeot if (!radeon_connector) 1852926deccbSFrançois Tigeot return; 1853926deccbSFrançois Tigeot 1854926deccbSFrançois Tigeot connector = &radeon_connector->base; 1855926deccbSFrançois Tigeot 1856926deccbSFrançois Tigeot radeon_connector->connector_id = connector_id; 1857926deccbSFrançois Tigeot radeon_connector->devices = supported_device; 1858926deccbSFrançois Tigeot radeon_connector->shared_ddc = shared_ddc; 1859926deccbSFrançois Tigeot radeon_connector->connector_object_id = connector_object_id; 1860926deccbSFrançois Tigeot radeon_connector->hpd = *hpd; 1861926deccbSFrançois Tigeot 1862926deccbSFrançois Tigeot radeon_connector->router = *router; 1863926deccbSFrançois Tigeot if (router->ddc_valid || router->cd_valid) { 1864926deccbSFrançois Tigeot radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info); 1865926deccbSFrançois Tigeot if (!radeon_connector->router_bus) 1866926deccbSFrançois Tigeot DRM_ERROR("Failed to assign router i2c bus! Check dmesg for i2c errors.\n"); 1867926deccbSFrançois Tigeot } 1868926deccbSFrançois Tigeot 1869926deccbSFrançois Tigeot if (is_dp_bridge) { 1870c4ef309bSzrj radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); 1871926deccbSFrançois Tigeot if (!radeon_dig_connector) 1872926deccbSFrançois Tigeot goto failed; 1873926deccbSFrançois Tigeot radeon_dig_connector->igp_lane_info = igp_lane_info; 1874926deccbSFrançois Tigeot radeon_connector->con_priv = radeon_dig_connector; 1875926deccbSFrançois Tigeot if (i2c_bus->valid) { 1876ee479021SImre Vadász /* add DP i2c bus */ 1877ee479021SImre Vadász if (connector_type == DRM_MODE_CONNECTOR_eDP) 1878ee479021SImre Vadász radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch"); 1879ee479021SImre Vadász else 1880ee479021SImre Vadász radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch"); 1881ee479021SImre Vadász if (radeon_dig_connector->dp_i2c_bus) 18827191d616Szrj has_aux = true; 18837191d616Szrj else 1884ee479021SImre Vadász DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); 1885ee479021SImre Vadász radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 1886ee479021SImre Vadász if (!radeon_connector->ddc_bus) 1887926deccbSFrançois Tigeot DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 1888926deccbSFrançois Tigeot } 1889926deccbSFrançois Tigeot switch (connector_type) { 1890926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_VGA: 1891926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVIA: 1892926deccbSFrançois Tigeot default: 18934cd92098Szrj drm_connector_init(dev, &radeon_connector->base, 18944cd92098Szrj &radeon_dp_connector_funcs, connector_type); 18954cd92098Szrj drm_connector_helper_add(&radeon_connector->base, 18964cd92098Szrj &radeon_dp_connector_helper_funcs); 1897926deccbSFrançois Tigeot connector->interlace_allowed = true; 1898926deccbSFrançois Tigeot connector->doublescan_allowed = true; 1899926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 1900b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1901926deccbSFrançois Tigeot rdev->mode_info.load_detect_property, 1902926deccbSFrançois Tigeot 1); 1903c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1904c6f73aabSFrançois Tigeot dev->mode_config.scaling_mode_property, 1905c6f73aabSFrançois Tigeot DRM_MODE_SCALE_NONE); 1906926deccbSFrançois Tigeot break; 1907926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVII: 1908926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVID: 1909926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_HDMIA: 1910926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_HDMIB: 1911926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DisplayPort: 19124cd92098Szrj drm_connector_init(dev, &radeon_connector->base, 19134cd92098Szrj &radeon_dp_connector_funcs, connector_type); 19144cd92098Szrj drm_connector_helper_add(&radeon_connector->base, 19154cd92098Szrj &radeon_dp_connector_helper_funcs); 1916b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1917926deccbSFrançois Tigeot rdev->mode_info.underscan_property, 1918926deccbSFrançois Tigeot UNDERSCAN_OFF); 1919b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1920926deccbSFrançois Tigeot rdev->mode_info.underscan_hborder_property, 1921926deccbSFrançois Tigeot 0); 1922b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1923926deccbSFrançois Tigeot rdev->mode_info.underscan_vborder_property, 1924926deccbSFrançois Tigeot 0); 1925c6f73aabSFrançois Tigeot 1926c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1927c6f73aabSFrançois Tigeot dev->mode_config.scaling_mode_property, 1928c6f73aabSFrançois Tigeot DRM_MODE_SCALE_NONE); 1929c6f73aabSFrançois Tigeot 1930c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1931c6f73aabSFrançois Tigeot rdev->mode_info.dither_property, 1932c6f73aabSFrançois Tigeot RADEON_FMT_DITHER_DISABLE); 1933c6f73aabSFrançois Tigeot 1934ee479021SImre Vadász if (radeon_audio != 0) 19354cd92098Szrj drm_object_attach_property(&radeon_connector->base.base, 19364cd92098Szrj rdev->mode_info.audio_property, 1937c6f73aabSFrançois Tigeot RADEON_AUDIO_AUTO); 1938c6f73aabSFrançois Tigeot 1939926deccbSFrançois Tigeot subpixel_order = SubPixelHorizontalRGB; 1940926deccbSFrançois Tigeot connector->interlace_allowed = true; 1941926deccbSFrançois Tigeot if (connector_type == DRM_MODE_CONNECTOR_HDMIB) 1942926deccbSFrançois Tigeot connector->doublescan_allowed = true; 1943926deccbSFrançois Tigeot else 1944926deccbSFrançois Tigeot connector->doublescan_allowed = false; 1945926deccbSFrançois Tigeot if (connector_type == DRM_MODE_CONNECTOR_DVII) { 1946926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 1947b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1948926deccbSFrançois Tigeot rdev->mode_info.load_detect_property, 1949926deccbSFrançois Tigeot 1); 1950926deccbSFrançois Tigeot } 1951926deccbSFrançois Tigeot break; 1952926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_LVDS: 1953926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_eDP: 19544cd92098Szrj drm_connector_init(dev, &radeon_connector->base, 19554cd92098Szrj &radeon_lvds_bridge_connector_funcs, connector_type); 19564cd92098Szrj drm_connector_helper_add(&radeon_connector->base, 19574cd92098Szrj &radeon_dp_connector_helper_funcs); 1958b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1959926deccbSFrançois Tigeot dev->mode_config.scaling_mode_property, 1960926deccbSFrançois Tigeot DRM_MODE_SCALE_FULLSCREEN); 1961926deccbSFrançois Tigeot subpixel_order = SubPixelHorizontalRGB; 1962926deccbSFrançois Tigeot connector->interlace_allowed = false; 1963926deccbSFrançois Tigeot connector->doublescan_allowed = false; 1964926deccbSFrançois Tigeot break; 1965926deccbSFrançois Tigeot } 1966926deccbSFrançois Tigeot } else { 1967926deccbSFrançois Tigeot switch (connector_type) { 1968926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_VGA: 1969926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); 1970926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); 1971926deccbSFrançois Tigeot if (i2c_bus->valid) { 1972926deccbSFrançois Tigeot radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 1973926deccbSFrançois Tigeot if (!radeon_connector->ddc_bus) 1974926deccbSFrançois Tigeot DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 1975926deccbSFrançois Tigeot } 1976926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 1977b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1978926deccbSFrançois Tigeot rdev->mode_info.load_detect_property, 1979926deccbSFrançois Tigeot 1); 1980c6f73aabSFrançois Tigeot if (ASIC_IS_AVIVO(rdev)) 1981c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 1982c6f73aabSFrançois Tigeot dev->mode_config.scaling_mode_property, 1983c6f73aabSFrançois Tigeot DRM_MODE_SCALE_NONE); 1984926deccbSFrançois Tigeot /* no HPD on analog connectors */ 1985926deccbSFrançois Tigeot radeon_connector->hpd.hpd = RADEON_HPD_NONE; 1986ee479021SImre Vadász connector->polled = DRM_CONNECTOR_POLL_CONNECT; 1987926deccbSFrançois Tigeot connector->interlace_allowed = true; 1988926deccbSFrançois Tigeot connector->doublescan_allowed = true; 1989926deccbSFrançois Tigeot break; 1990926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVIA: 1991926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); 1992926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); 1993926deccbSFrançois Tigeot if (i2c_bus->valid) { 1994926deccbSFrançois Tigeot radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 1995926deccbSFrançois Tigeot if (!radeon_connector->ddc_bus) 1996926deccbSFrançois Tigeot DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 1997926deccbSFrançois Tigeot } 1998926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 1999b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2000926deccbSFrançois Tigeot rdev->mode_info.load_detect_property, 2001926deccbSFrançois Tigeot 1); 2002c6f73aabSFrançois Tigeot if (ASIC_IS_AVIVO(rdev)) 2003c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2004c6f73aabSFrançois Tigeot dev->mode_config.scaling_mode_property, 2005c6f73aabSFrançois Tigeot DRM_MODE_SCALE_NONE); 2006926deccbSFrançois Tigeot /* no HPD on analog connectors */ 2007926deccbSFrançois Tigeot radeon_connector->hpd.hpd = RADEON_HPD_NONE; 2008926deccbSFrançois Tigeot connector->interlace_allowed = true; 2009926deccbSFrançois Tigeot connector->doublescan_allowed = true; 2010926deccbSFrançois Tigeot break; 2011926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVII: 2012926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVID: 2013c4ef309bSzrj radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); 2014926deccbSFrançois Tigeot if (!radeon_dig_connector) 2015926deccbSFrançois Tigeot goto failed; 2016926deccbSFrançois Tigeot radeon_dig_connector->igp_lane_info = igp_lane_info; 2017926deccbSFrançois Tigeot radeon_connector->con_priv = radeon_dig_connector; 2018926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); 2019926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); 2020926deccbSFrançois Tigeot if (i2c_bus->valid) { 2021926deccbSFrançois Tigeot radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 2022926deccbSFrançois Tigeot if (!radeon_connector->ddc_bus) 2023926deccbSFrançois Tigeot DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 2024926deccbSFrançois Tigeot } 2025926deccbSFrançois Tigeot subpixel_order = SubPixelHorizontalRGB; 2026b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2027926deccbSFrançois Tigeot rdev->mode_info.coherent_mode_property, 2028926deccbSFrançois Tigeot 1); 2029926deccbSFrançois Tigeot if (ASIC_IS_AVIVO(rdev)) { 2030b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2031926deccbSFrançois Tigeot rdev->mode_info.underscan_property, 2032926deccbSFrançois Tigeot UNDERSCAN_OFF); 2033b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2034926deccbSFrançois Tigeot rdev->mode_info.underscan_hborder_property, 2035926deccbSFrançois Tigeot 0); 2036b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2037926deccbSFrançois Tigeot rdev->mode_info.underscan_vborder_property, 2038926deccbSFrançois Tigeot 0); 2039c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2040c6f73aabSFrançois Tigeot rdev->mode_info.dither_property, 2041c6f73aabSFrançois Tigeot RADEON_FMT_DITHER_DISABLE); 2042c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2043c6f73aabSFrançois Tigeot dev->mode_config.scaling_mode_property, 2044c6f73aabSFrançois Tigeot DRM_MODE_SCALE_NONE); 2045926deccbSFrançois Tigeot } 20464cd92098Szrj if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) { 20474cd92098Szrj drm_object_attach_property(&radeon_connector->base.base, 20484cd92098Szrj rdev->mode_info.audio_property, 2049c6f73aabSFrançois Tigeot RADEON_AUDIO_AUTO); 20504cd92098Szrj } 2051926deccbSFrançois Tigeot if (connector_type == DRM_MODE_CONNECTOR_DVII) { 2052926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 2053b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2054926deccbSFrançois Tigeot rdev->mode_info.load_detect_property, 2055926deccbSFrançois Tigeot 1); 2056926deccbSFrançois Tigeot } 2057926deccbSFrançois Tigeot connector->interlace_allowed = true; 2058926deccbSFrançois Tigeot if (connector_type == DRM_MODE_CONNECTOR_DVII) 2059926deccbSFrançois Tigeot connector->doublescan_allowed = true; 2060926deccbSFrançois Tigeot else 2061926deccbSFrançois Tigeot connector->doublescan_allowed = false; 2062926deccbSFrançois Tigeot break; 2063926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_HDMIA: 2064926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_HDMIB: 2065c4ef309bSzrj radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); 2066926deccbSFrançois Tigeot if (!radeon_dig_connector) 2067926deccbSFrançois Tigeot goto failed; 2068926deccbSFrançois Tigeot radeon_dig_connector->igp_lane_info = igp_lane_info; 2069926deccbSFrançois Tigeot radeon_connector->con_priv = radeon_dig_connector; 2070926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); 2071926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); 2072926deccbSFrançois Tigeot if (i2c_bus->valid) { 2073926deccbSFrançois Tigeot radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 2074926deccbSFrançois Tigeot if (!radeon_connector->ddc_bus) 2075926deccbSFrançois Tigeot DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 2076926deccbSFrançois Tigeot } 2077b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2078926deccbSFrançois Tigeot rdev->mode_info.coherent_mode_property, 2079926deccbSFrançois Tigeot 1); 2080926deccbSFrançois Tigeot if (ASIC_IS_AVIVO(rdev)) { 2081b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2082926deccbSFrançois Tigeot rdev->mode_info.underscan_property, 2083926deccbSFrançois Tigeot UNDERSCAN_OFF); 2084b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2085926deccbSFrançois Tigeot rdev->mode_info.underscan_hborder_property, 2086926deccbSFrançois Tigeot 0); 2087b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2088926deccbSFrançois Tigeot rdev->mode_info.underscan_vborder_property, 2089926deccbSFrançois Tigeot 0); 2090c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2091c6f73aabSFrançois Tigeot rdev->mode_info.dither_property, 2092c6f73aabSFrançois Tigeot RADEON_FMT_DITHER_DISABLE); 2093c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2094c6f73aabSFrançois Tigeot dev->mode_config.scaling_mode_property, 2095c6f73aabSFrançois Tigeot DRM_MODE_SCALE_NONE); 2096926deccbSFrançois Tigeot } 20974cd92098Szrj if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) { 20984cd92098Szrj drm_object_attach_property(&radeon_connector->base.base, 20994cd92098Szrj rdev->mode_info.audio_property, 2100c6f73aabSFrançois Tigeot RADEON_AUDIO_AUTO); 21014cd92098Szrj } 2102926deccbSFrançois Tigeot subpixel_order = SubPixelHorizontalRGB; 2103926deccbSFrançois Tigeot connector->interlace_allowed = true; 2104926deccbSFrançois Tigeot if (connector_type == DRM_MODE_CONNECTOR_HDMIB) 2105926deccbSFrançois Tigeot connector->doublescan_allowed = true; 2106926deccbSFrançois Tigeot else 2107926deccbSFrançois Tigeot connector->doublescan_allowed = false; 2108926deccbSFrançois Tigeot break; 2109926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DisplayPort: 2110c4ef309bSzrj radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); 2111926deccbSFrançois Tigeot if (!radeon_dig_connector) 2112926deccbSFrançois Tigeot goto failed; 2113926deccbSFrançois Tigeot radeon_dig_connector->igp_lane_info = igp_lane_info; 2114926deccbSFrançois Tigeot radeon_connector->con_priv = radeon_dig_connector; 2115926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type); 2116926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs); 2117926deccbSFrançois Tigeot if (i2c_bus->valid) { 2118ee479021SImre Vadász /* add DP i2c bus */ 2119ee479021SImre Vadász radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch"); 2120ee479021SImre Vadász if (!radeon_dig_connector->dp_i2c_bus) 2121ee479021SImre Vadász DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); 2122926deccbSFrançois Tigeot radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 21237191d616Szrj if (radeon_connector->ddc_bus) 21247191d616Szrj has_aux = true; 21257191d616Szrj else 2126926deccbSFrançois Tigeot DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 2127926deccbSFrançois Tigeot } 2128926deccbSFrançois Tigeot subpixel_order = SubPixelHorizontalRGB; 2129b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2130926deccbSFrançois Tigeot rdev->mode_info.coherent_mode_property, 2131926deccbSFrançois Tigeot 1); 2132926deccbSFrançois Tigeot if (ASIC_IS_AVIVO(rdev)) { 2133b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2134926deccbSFrançois Tigeot rdev->mode_info.underscan_property, 2135926deccbSFrançois Tigeot UNDERSCAN_OFF); 2136b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2137926deccbSFrançois Tigeot rdev->mode_info.underscan_hborder_property, 2138926deccbSFrançois Tigeot 0); 2139b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2140926deccbSFrançois Tigeot rdev->mode_info.underscan_vborder_property, 2141926deccbSFrançois Tigeot 0); 2142c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2143c6f73aabSFrançois Tigeot rdev->mode_info.dither_property, 2144c6f73aabSFrançois Tigeot RADEON_FMT_DITHER_DISABLE); 2145c6f73aabSFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2146c6f73aabSFrançois Tigeot dev->mode_config.scaling_mode_property, 2147c6f73aabSFrançois Tigeot DRM_MODE_SCALE_NONE); 2148926deccbSFrançois Tigeot } 21494cd92098Szrj if (ASIC_IS_DCE2(rdev) && (radeon_audio != 0)) { 21504cd92098Szrj drm_object_attach_property(&radeon_connector->base.base, 21514cd92098Szrj rdev->mode_info.audio_property, 2152c6f73aabSFrançois Tigeot RADEON_AUDIO_AUTO); 21534cd92098Szrj } 2154926deccbSFrançois Tigeot connector->interlace_allowed = true; 2155926deccbSFrançois Tigeot /* in theory with a DP to VGA converter... */ 2156926deccbSFrançois Tigeot connector->doublescan_allowed = false; 2157926deccbSFrançois Tigeot break; 2158926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_eDP: 2159c4ef309bSzrj radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); 2160926deccbSFrançois Tigeot if (!radeon_dig_connector) 2161926deccbSFrançois Tigeot goto failed; 2162926deccbSFrançois Tigeot radeon_dig_connector->igp_lane_info = igp_lane_info; 2163926deccbSFrançois Tigeot radeon_connector->con_priv = radeon_dig_connector; 21644cd92098Szrj drm_connector_init(dev, &radeon_connector->base, &radeon_edp_connector_funcs, connector_type); 2165926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs); 2166926deccbSFrançois Tigeot if (i2c_bus->valid) { 2167ee479021SImre Vadász /* add DP i2c bus */ 2168ee479021SImre Vadász radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch"); 2169ee479021SImre Vadász if (radeon_dig_connector->dp_i2c_bus) 21707191d616Szrj has_aux = true; 21717191d616Szrj else 2172ee479021SImre Vadász DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); 2173ee479021SImre Vadász radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 2174ee479021SImre Vadász if (!radeon_connector->ddc_bus) 2175926deccbSFrançois Tigeot DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 2176926deccbSFrançois Tigeot } 2177b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2178926deccbSFrançois Tigeot dev->mode_config.scaling_mode_property, 2179926deccbSFrançois Tigeot DRM_MODE_SCALE_FULLSCREEN); 2180926deccbSFrançois Tigeot subpixel_order = SubPixelHorizontalRGB; 2181926deccbSFrançois Tigeot connector->interlace_allowed = false; 2182926deccbSFrançois Tigeot connector->doublescan_allowed = false; 2183926deccbSFrançois Tigeot break; 2184926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_SVIDEO: 2185926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_Composite: 2186926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_9PinDIN: 2187926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type); 2188926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); 2189926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 2190b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2191926deccbSFrançois Tigeot rdev->mode_info.load_detect_property, 2192926deccbSFrançois Tigeot 1); 2193b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2194926deccbSFrançois Tigeot rdev->mode_info.tv_std_property, 2195926deccbSFrançois Tigeot radeon_atombios_get_tv_info(rdev)); 2196926deccbSFrançois Tigeot /* no HPD on analog connectors */ 2197926deccbSFrançois Tigeot radeon_connector->hpd.hpd = RADEON_HPD_NONE; 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_LVDS: 2202c4ef309bSzrj radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); 2203926deccbSFrançois Tigeot if (!radeon_dig_connector) 2204926deccbSFrançois Tigeot goto failed; 2205926deccbSFrançois Tigeot radeon_dig_connector->igp_lane_info = igp_lane_info; 2206926deccbSFrançois Tigeot radeon_connector->con_priv = radeon_dig_connector; 2207926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); 2208926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs); 2209926deccbSFrançois Tigeot if (i2c_bus->valid) { 2210926deccbSFrançois Tigeot radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 2211926deccbSFrançois Tigeot if (!radeon_connector->ddc_bus) 2212926deccbSFrançois Tigeot DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 2213926deccbSFrançois Tigeot } 2214b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2215926deccbSFrançois Tigeot dev->mode_config.scaling_mode_property, 2216926deccbSFrançois Tigeot DRM_MODE_SCALE_FULLSCREEN); 2217926deccbSFrançois Tigeot subpixel_order = SubPixelHorizontalRGB; 2218926deccbSFrançois Tigeot connector->interlace_allowed = false; 2219926deccbSFrançois Tigeot connector->doublescan_allowed = false; 2220926deccbSFrançois Tigeot break; 2221926deccbSFrançois Tigeot } 2222926deccbSFrançois Tigeot } 2223926deccbSFrançois Tigeot 2224926deccbSFrançois Tigeot if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) { 2225ee479021SImre Vadász if (i2c_bus->valid) 2226ee479021SImre Vadász connector->polled = DRM_CONNECTOR_POLL_CONNECT; 2227926deccbSFrançois Tigeot } else 2228926deccbSFrançois Tigeot connector->polled = DRM_CONNECTOR_POLL_HPD; 2229926deccbSFrançois Tigeot 2230926deccbSFrançois Tigeot connector->display_info.subpixel_order = subpixel_order; 2231c6f73aabSFrançois Tigeot drm_connector_register(connector); 22327191d616Szrj 22337191d616Szrj if (has_aux) 22347191d616Szrj radeon_dp_aux_init(radeon_connector); 22357191d616Szrj 2236926deccbSFrançois Tigeot return; 2237926deccbSFrançois Tigeot 2238926deccbSFrançois Tigeot failed: 2239926deccbSFrançois Tigeot drm_connector_cleanup(connector); 2240158486a6SFrançois Tigeot kfree(connector); 2241926deccbSFrançois Tigeot } 2242926deccbSFrançois Tigeot 2243926deccbSFrançois Tigeot void 2244926deccbSFrançois Tigeot radeon_add_legacy_connector(struct drm_device *dev, 2245926deccbSFrançois Tigeot uint32_t connector_id, 2246926deccbSFrançois Tigeot uint32_t supported_device, 2247926deccbSFrançois Tigeot int connector_type, 2248926deccbSFrançois Tigeot struct radeon_i2c_bus_rec *i2c_bus, 2249926deccbSFrançois Tigeot uint16_t connector_object_id, 2250926deccbSFrançois Tigeot struct radeon_hpd *hpd) 2251926deccbSFrançois Tigeot { 2252926deccbSFrançois Tigeot struct radeon_device *rdev = dev->dev_private; 2253926deccbSFrançois Tigeot struct drm_connector *connector; 2254926deccbSFrançois Tigeot struct radeon_connector *radeon_connector; 2255926deccbSFrançois Tigeot uint32_t subpixel_order = SubPixelNone; 2256926deccbSFrançois Tigeot 2257926deccbSFrançois Tigeot if (connector_type == DRM_MODE_CONNECTOR_Unknown) 2258926deccbSFrançois Tigeot return; 2259926deccbSFrançois Tigeot 2260926deccbSFrançois Tigeot /* if the user selected tv=0 don't try and add the connector */ 2261926deccbSFrançois Tigeot if (((connector_type == DRM_MODE_CONNECTOR_SVIDEO) || 2262926deccbSFrançois Tigeot (connector_type == DRM_MODE_CONNECTOR_Composite) || 2263926deccbSFrançois Tigeot (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) && 2264926deccbSFrançois Tigeot (radeon_tv == 0)) 2265926deccbSFrançois Tigeot return; 2266926deccbSFrançois Tigeot 2267926deccbSFrançois Tigeot /* see if we already added it */ 2268926deccbSFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 2269926deccbSFrançois Tigeot radeon_connector = to_radeon_connector(connector); 2270926deccbSFrançois Tigeot if (radeon_connector->connector_id == connector_id) { 2271926deccbSFrançois Tigeot radeon_connector->devices |= supported_device; 2272926deccbSFrançois Tigeot return; 2273926deccbSFrançois Tigeot } 2274926deccbSFrançois Tigeot } 2275926deccbSFrançois Tigeot 2276c4ef309bSzrj radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL); 2277926deccbSFrançois Tigeot if (!radeon_connector) 2278926deccbSFrançois Tigeot return; 2279926deccbSFrançois Tigeot 2280926deccbSFrançois Tigeot connector = &radeon_connector->base; 2281926deccbSFrançois Tigeot 2282926deccbSFrançois Tigeot radeon_connector->connector_id = connector_id; 2283926deccbSFrançois Tigeot radeon_connector->devices = supported_device; 2284926deccbSFrançois Tigeot radeon_connector->connector_object_id = connector_object_id; 2285926deccbSFrançois Tigeot radeon_connector->hpd = *hpd; 2286926deccbSFrançois Tigeot 2287926deccbSFrançois Tigeot switch (connector_type) { 2288926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_VGA: 2289926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); 2290926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); 2291926deccbSFrançois Tigeot if (i2c_bus->valid) { 2292926deccbSFrançois Tigeot radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 2293926deccbSFrançois Tigeot if (!radeon_connector->ddc_bus) 2294926deccbSFrançois Tigeot DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 2295926deccbSFrançois Tigeot } 2296926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 2297b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2298926deccbSFrançois Tigeot rdev->mode_info.load_detect_property, 2299926deccbSFrançois Tigeot 1); 2300926deccbSFrançois Tigeot /* no HPD on analog connectors */ 2301926deccbSFrançois Tigeot radeon_connector->hpd.hpd = RADEON_HPD_NONE; 2302ee479021SImre Vadász connector->polled = DRM_CONNECTOR_POLL_CONNECT; 2303926deccbSFrançois Tigeot connector->interlace_allowed = true; 2304926deccbSFrançois Tigeot connector->doublescan_allowed = true; 2305926deccbSFrançois Tigeot break; 2306926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVIA: 2307926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); 2308926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); 2309926deccbSFrançois Tigeot if (i2c_bus->valid) { 2310926deccbSFrançois Tigeot radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 2311926deccbSFrançois Tigeot if (!radeon_connector->ddc_bus) 2312926deccbSFrançois Tigeot DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 2313926deccbSFrançois Tigeot } 2314926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 2315b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2316926deccbSFrançois Tigeot rdev->mode_info.load_detect_property, 2317926deccbSFrançois Tigeot 1); 2318926deccbSFrançois Tigeot /* no HPD on analog connectors */ 2319926deccbSFrançois Tigeot radeon_connector->hpd.hpd = RADEON_HPD_NONE; 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_DVII: 2324926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_DVID: 2325926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); 2326926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); 2327926deccbSFrançois Tigeot if (i2c_bus->valid) { 2328926deccbSFrançois Tigeot radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 2329926deccbSFrançois Tigeot if (!radeon_connector->ddc_bus) 2330926deccbSFrançois Tigeot DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 2331926deccbSFrançois Tigeot } 2332926deccbSFrançois Tigeot if (connector_type == DRM_MODE_CONNECTOR_DVII) { 2333926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 2334b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2335926deccbSFrançois Tigeot rdev->mode_info.load_detect_property, 2336926deccbSFrançois Tigeot 1); 2337926deccbSFrançois Tigeot } 2338926deccbSFrançois Tigeot subpixel_order = SubPixelHorizontalRGB; 2339926deccbSFrançois Tigeot connector->interlace_allowed = true; 2340926deccbSFrançois Tigeot if (connector_type == DRM_MODE_CONNECTOR_DVII) 2341926deccbSFrançois Tigeot connector->doublescan_allowed = true; 2342926deccbSFrançois Tigeot else 2343926deccbSFrançois Tigeot connector->doublescan_allowed = false; 2344926deccbSFrançois Tigeot break; 2345926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_SVIDEO: 2346926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_Composite: 2347926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_9PinDIN: 2348926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type); 2349926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); 2350926deccbSFrançois Tigeot radeon_connector->dac_load_detect = true; 2351926deccbSFrançois Tigeot /* RS400,RC410,RS480 chipset seems to report a lot 2352926deccbSFrançois Tigeot * of false positive on load detect, we haven't yet 2353926deccbSFrançois Tigeot * found a way to make load detect reliable on those 2354926deccbSFrançois Tigeot * chipset, thus just disable it for TV. 2355926deccbSFrançois Tigeot */ 2356926deccbSFrançois Tigeot if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480) 2357926deccbSFrançois Tigeot radeon_connector->dac_load_detect = false; 2358b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2359926deccbSFrançois Tigeot rdev->mode_info.load_detect_property, 2360926deccbSFrançois Tigeot radeon_connector->dac_load_detect); 2361b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2362926deccbSFrançois Tigeot rdev->mode_info.tv_std_property, 2363926deccbSFrançois Tigeot radeon_combios_get_tv_info(rdev)); 2364926deccbSFrançois Tigeot /* no HPD on analog connectors */ 2365926deccbSFrançois Tigeot radeon_connector->hpd.hpd = RADEON_HPD_NONE; 2366926deccbSFrançois Tigeot connector->interlace_allowed = false; 2367926deccbSFrançois Tigeot connector->doublescan_allowed = false; 2368926deccbSFrançois Tigeot break; 2369926deccbSFrançois Tigeot case DRM_MODE_CONNECTOR_LVDS: 2370926deccbSFrançois Tigeot drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); 2371926deccbSFrançois Tigeot drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs); 2372926deccbSFrançois Tigeot if (i2c_bus->valid) { 2373926deccbSFrançois Tigeot radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); 2374926deccbSFrançois Tigeot if (!radeon_connector->ddc_bus) 2375926deccbSFrançois Tigeot DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 2376926deccbSFrançois Tigeot } 2377b5162e19SFrançois Tigeot drm_object_attach_property(&radeon_connector->base.base, 2378926deccbSFrançois Tigeot dev->mode_config.scaling_mode_property, 2379926deccbSFrançois Tigeot DRM_MODE_SCALE_FULLSCREEN); 2380926deccbSFrançois Tigeot subpixel_order = SubPixelHorizontalRGB; 2381926deccbSFrançois Tigeot connector->interlace_allowed = false; 2382926deccbSFrançois Tigeot connector->doublescan_allowed = false; 2383926deccbSFrançois Tigeot break; 2384926deccbSFrançois Tigeot } 2385926deccbSFrançois Tigeot 2386926deccbSFrançois Tigeot if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) { 2387ee479021SImre Vadász if (i2c_bus->valid) 2388ee479021SImre Vadász connector->polled = DRM_CONNECTOR_POLL_CONNECT; 2389926deccbSFrançois Tigeot } else 2390926deccbSFrançois Tigeot connector->polled = DRM_CONNECTOR_POLL_HPD; 2391926deccbSFrançois Tigeot connector->display_info.subpixel_order = subpixel_order; 2392c6f73aabSFrançois Tigeot drm_connector_register(connector); 2393926deccbSFrançois Tigeot } 2394