1*b843c749SSergey Zigachev /* 2*b843c749SSergey Zigachev * Copyright 2007-8 Advanced Micro Devices, Inc. 3*b843c749SSergey Zigachev * Copyright 2008 Red Hat Inc. 4*b843c749SSergey Zigachev * 5*b843c749SSergey Zigachev * Permission is hereby granted, free of charge, to any person obtaining a 6*b843c749SSergey Zigachev * copy of this software and associated documentation files (the "Software"), 7*b843c749SSergey Zigachev * to deal in the Software without restriction, including without limitation 8*b843c749SSergey Zigachev * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9*b843c749SSergey Zigachev * and/or sell copies of the Software, and to permit persons to whom the 10*b843c749SSergey Zigachev * Software is furnished to do so, subject to the following conditions: 11*b843c749SSergey Zigachev * 12*b843c749SSergey Zigachev * The above copyright notice and this permission notice shall be included in 13*b843c749SSergey Zigachev * all copies or substantial portions of the Software. 14*b843c749SSergey Zigachev * 15*b843c749SSergey Zigachev * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16*b843c749SSergey Zigachev * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17*b843c749SSergey Zigachev * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18*b843c749SSergey Zigachev * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19*b843c749SSergey Zigachev * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20*b843c749SSergey Zigachev * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21*b843c749SSergey Zigachev * OTHER DEALINGS IN THE SOFTWARE. 22*b843c749SSergey Zigachev * 23*b843c749SSergey Zigachev * Authors: Dave Airlie 24*b843c749SSergey Zigachev * Alex Deucher 25*b843c749SSergey Zigachev */ 26*b843c749SSergey Zigachev #include <drm/drmP.h> 27*b843c749SSergey Zigachev #include <drm/drm_edid.h> 28*b843c749SSergey Zigachev #include <drm/drm_crtc_helper.h> 29*b843c749SSergey Zigachev #include <drm/drm_fb_helper.h> 30*b843c749SSergey Zigachev #include <drm/amdgpu_drm.h> 31*b843c749SSergey Zigachev #include "amdgpu.h" 32*b843c749SSergey Zigachev #include "atom.h" 33*b843c749SSergey Zigachev #include "atombios_encoders.h" 34*b843c749SSergey Zigachev #include "atombios_dp.h" 35*b843c749SSergey Zigachev #include "amdgpu_connectors.h" 36*b843c749SSergey Zigachev #include "amdgpu_i2c.h" 37*b843c749SSergey Zigachev 38*b843c749SSergey Zigachev #include <linux/pm_runtime.h> 39*b843c749SSergey Zigachev 40*b843c749SSergey Zigachev void amdgpu_connector_hotplug(struct drm_connector *connector) 41*b843c749SSergey Zigachev { 42*b843c749SSergey Zigachev struct drm_device *dev = connector->dev; 43*b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private; 44*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 45*b843c749SSergey Zigachev 46*b843c749SSergey Zigachev /* bail if the connector does not have hpd pin, e.g., 47*b843c749SSergey Zigachev * VGA, TV, etc. 48*b843c749SSergey Zigachev */ 49*b843c749SSergey Zigachev if (amdgpu_connector->hpd.hpd == AMDGPU_HPD_NONE) 50*b843c749SSergey Zigachev return; 51*b843c749SSergey Zigachev 52*b843c749SSergey Zigachev amdgpu_display_hpd_set_polarity(adev, amdgpu_connector->hpd.hpd); 53*b843c749SSergey Zigachev 54*b843c749SSergey Zigachev /* if the connector is already off, don't turn it back on */ 55*b843c749SSergey Zigachev if (connector->dpms != DRM_MODE_DPMS_ON) 56*b843c749SSergey Zigachev return; 57*b843c749SSergey Zigachev 58*b843c749SSergey Zigachev /* just deal with DP (not eDP) here. */ 59*b843c749SSergey Zigachev if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { 60*b843c749SSergey Zigachev struct amdgpu_connector_atom_dig *dig_connector = 61*b843c749SSergey Zigachev amdgpu_connector->con_priv; 62*b843c749SSergey Zigachev 63*b843c749SSergey Zigachev /* if existing sink type was not DP no need to retrain */ 64*b843c749SSergey Zigachev if (dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_DISPLAYPORT) 65*b843c749SSergey Zigachev return; 66*b843c749SSergey Zigachev 67*b843c749SSergey Zigachev /* first get sink type as it may be reset after (un)plug */ 68*b843c749SSergey Zigachev dig_connector->dp_sink_type = amdgpu_atombios_dp_get_sinktype(amdgpu_connector); 69*b843c749SSergey Zigachev /* don't do anything if sink is not display port, i.e., 70*b843c749SSergey Zigachev * passive dp->(dvi|hdmi) adaptor 71*b843c749SSergey Zigachev */ 72*b843c749SSergey Zigachev if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT && 73*b843c749SSergey Zigachev amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd) && 74*b843c749SSergey Zigachev amdgpu_atombios_dp_needs_link_train(amdgpu_connector)) { 75*b843c749SSergey Zigachev /* Don't start link training before we have the DPCD */ 76*b843c749SSergey Zigachev if (amdgpu_atombios_dp_get_dpcd(amdgpu_connector)) 77*b843c749SSergey Zigachev return; 78*b843c749SSergey Zigachev 79*b843c749SSergey Zigachev /* Turn the connector off and back on immediately, which 80*b843c749SSergey Zigachev * will trigger link training 81*b843c749SSergey Zigachev */ 82*b843c749SSergey Zigachev drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); 83*b843c749SSergey Zigachev drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); 84*b843c749SSergey Zigachev } 85*b843c749SSergey Zigachev } 86*b843c749SSergey Zigachev } 87*b843c749SSergey Zigachev 88*b843c749SSergey Zigachev static void amdgpu_connector_property_change_mode(struct drm_encoder *encoder) 89*b843c749SSergey Zigachev { 90*b843c749SSergey Zigachev struct drm_crtc *crtc = encoder->crtc; 91*b843c749SSergey Zigachev 92*b843c749SSergey Zigachev if (crtc && crtc->enabled) { 93*b843c749SSergey Zigachev drm_crtc_helper_set_mode(crtc, &crtc->mode, 94*b843c749SSergey Zigachev crtc->x, crtc->y, crtc->primary->fb); 95*b843c749SSergey Zigachev } 96*b843c749SSergey Zigachev } 97*b843c749SSergey Zigachev 98*b843c749SSergey Zigachev int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector) 99*b843c749SSergey Zigachev { 100*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 101*b843c749SSergey Zigachev struct amdgpu_connector_atom_dig *dig_connector; 102*b843c749SSergey Zigachev int bpc = 8; 103*b843c749SSergey Zigachev unsigned mode_clock, max_tmds_clock; 104*b843c749SSergey Zigachev 105*b843c749SSergey Zigachev switch (connector->connector_type) { 106*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_DVII: 107*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_HDMIB: 108*b843c749SSergey Zigachev if (amdgpu_connector->use_digital) { 109*b843c749SSergey Zigachev if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) { 110*b843c749SSergey Zigachev if (connector->display_info.bpc) 111*b843c749SSergey Zigachev bpc = connector->display_info.bpc; 112*b843c749SSergey Zigachev } 113*b843c749SSergey Zigachev } 114*b843c749SSergey Zigachev break; 115*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_DVID: 116*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_HDMIA: 117*b843c749SSergey Zigachev if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) { 118*b843c749SSergey Zigachev if (connector->display_info.bpc) 119*b843c749SSergey Zigachev bpc = connector->display_info.bpc; 120*b843c749SSergey Zigachev } 121*b843c749SSergey Zigachev break; 122*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_DisplayPort: 123*b843c749SSergey Zigachev dig_connector = amdgpu_connector->con_priv; 124*b843c749SSergey Zigachev if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || 125*b843c749SSergey Zigachev (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) || 126*b843c749SSergey Zigachev drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) { 127*b843c749SSergey Zigachev if (connector->display_info.bpc) 128*b843c749SSergey Zigachev bpc = connector->display_info.bpc; 129*b843c749SSergey Zigachev } 130*b843c749SSergey Zigachev break; 131*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_eDP: 132*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_LVDS: 133*b843c749SSergey Zigachev if (connector->display_info.bpc) 134*b843c749SSergey Zigachev bpc = connector->display_info.bpc; 135*b843c749SSergey Zigachev else { 136*b843c749SSergey Zigachev const struct drm_connector_helper_funcs *connector_funcs = 137*b843c749SSergey Zigachev connector->helper_private; 138*b843c749SSergey Zigachev struct drm_encoder *encoder = connector_funcs->best_encoder(connector); 139*b843c749SSergey Zigachev struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); 140*b843c749SSergey Zigachev struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; 141*b843c749SSergey Zigachev 142*b843c749SSergey Zigachev if (dig->lcd_misc & ATOM_PANEL_MISC_V13_6BIT_PER_COLOR) 143*b843c749SSergey Zigachev bpc = 6; 144*b843c749SSergey Zigachev else if (dig->lcd_misc & ATOM_PANEL_MISC_V13_8BIT_PER_COLOR) 145*b843c749SSergey Zigachev bpc = 8; 146*b843c749SSergey Zigachev } 147*b843c749SSergey Zigachev break; 148*b843c749SSergey Zigachev } 149*b843c749SSergey Zigachev 150*b843c749SSergey Zigachev if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) { 151*b843c749SSergey Zigachev /* 152*b843c749SSergey Zigachev * Pre DCE-8 hw can't handle > 12 bpc, and more than 12 bpc doesn't make 153*b843c749SSergey Zigachev * much sense without support for > 12 bpc framebuffers. RGB 4:4:4 at 154*b843c749SSergey Zigachev * 12 bpc is always supported on hdmi deep color sinks, as this is 155*b843c749SSergey Zigachev * required by the HDMI-1.3 spec. Clamp to a safe 12 bpc maximum. 156*b843c749SSergey Zigachev */ 157*b843c749SSergey Zigachev if (bpc > 12) { 158*b843c749SSergey Zigachev DRM_DEBUG("%s: HDMI deep color %d bpc unsupported. Using 12 bpc.\n", 159*b843c749SSergey Zigachev connector->name, bpc); 160*b843c749SSergey Zigachev bpc = 12; 161*b843c749SSergey Zigachev } 162*b843c749SSergey Zigachev 163*b843c749SSergey Zigachev /* Any defined maximum tmds clock limit we must not exceed? */ 164*b843c749SSergey Zigachev if (connector->display_info.max_tmds_clock > 0) { 165*b843c749SSergey Zigachev /* mode_clock is clock in kHz for mode to be modeset on this connector */ 166*b843c749SSergey Zigachev mode_clock = amdgpu_connector->pixelclock_for_modeset; 167*b843c749SSergey Zigachev 168*b843c749SSergey Zigachev /* Maximum allowable input clock in kHz */ 169*b843c749SSergey Zigachev max_tmds_clock = connector->display_info.max_tmds_clock; 170*b843c749SSergey Zigachev 171*b843c749SSergey Zigachev DRM_DEBUG("%s: hdmi mode dotclock %d kHz, max tmds input clock %d kHz.\n", 172*b843c749SSergey Zigachev connector->name, mode_clock, max_tmds_clock); 173*b843c749SSergey Zigachev 174*b843c749SSergey Zigachev /* Check if bpc is within clock limit. Try to degrade gracefully otherwise */ 175*b843c749SSergey Zigachev if ((bpc == 12) && (mode_clock * 3/2 > max_tmds_clock)) { 176*b843c749SSergey Zigachev if ((connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) && 177*b843c749SSergey Zigachev (mode_clock * 5/4 <= max_tmds_clock)) 178*b843c749SSergey Zigachev bpc = 10; 179*b843c749SSergey Zigachev else 180*b843c749SSergey Zigachev bpc = 8; 181*b843c749SSergey Zigachev 182*b843c749SSergey Zigachev DRM_DEBUG("%s: HDMI deep color 12 bpc exceeds max tmds clock. Using %d bpc.\n", 183*b843c749SSergey Zigachev connector->name, bpc); 184*b843c749SSergey Zigachev } 185*b843c749SSergey Zigachev 186*b843c749SSergey Zigachev if ((bpc == 10) && (mode_clock * 5/4 > max_tmds_clock)) { 187*b843c749SSergey Zigachev bpc = 8; 188*b843c749SSergey Zigachev DRM_DEBUG("%s: HDMI deep color 10 bpc exceeds max tmds clock. Using %d bpc.\n", 189*b843c749SSergey Zigachev connector->name, bpc); 190*b843c749SSergey Zigachev } 191*b843c749SSergey Zigachev } else if (bpc > 8) { 192*b843c749SSergey Zigachev /* max_tmds_clock missing, but hdmi spec mandates it for deep color. */ 193*b843c749SSergey Zigachev DRM_DEBUG("%s: Required max tmds clock for HDMI deep color missing. Using 8 bpc.\n", 194*b843c749SSergey Zigachev connector->name); 195*b843c749SSergey Zigachev bpc = 8; 196*b843c749SSergey Zigachev } 197*b843c749SSergey Zigachev } 198*b843c749SSergey Zigachev 199*b843c749SSergey Zigachev if ((amdgpu_deep_color == 0) && (bpc > 8)) { 200*b843c749SSergey Zigachev DRM_DEBUG("%s: Deep color disabled. Set amdgpu module param deep_color=1 to enable.\n", 201*b843c749SSergey Zigachev connector->name); 202*b843c749SSergey Zigachev bpc = 8; 203*b843c749SSergey Zigachev } 204*b843c749SSergey Zigachev 205*b843c749SSergey Zigachev DRM_DEBUG("%s: Display bpc=%d, returned bpc=%d\n", 206*b843c749SSergey Zigachev connector->name, connector->display_info.bpc, bpc); 207*b843c749SSergey Zigachev 208*b843c749SSergey Zigachev return bpc; 209*b843c749SSergey Zigachev } 210*b843c749SSergey Zigachev 211*b843c749SSergey Zigachev static void 212*b843c749SSergey Zigachev amdgpu_connector_update_scratch_regs(struct drm_connector *connector, 213*b843c749SSergey Zigachev enum drm_connector_status status) 214*b843c749SSergey Zigachev { 215*b843c749SSergey Zigachev struct drm_encoder *best_encoder; 216*b843c749SSergey Zigachev struct drm_encoder *encoder; 217*b843c749SSergey Zigachev const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; 218*b843c749SSergey Zigachev bool connected; 219*b843c749SSergey Zigachev int i; 220*b843c749SSergey Zigachev 221*b843c749SSergey Zigachev best_encoder = connector_funcs->best_encoder(connector); 222*b843c749SSergey Zigachev 223*b843c749SSergey Zigachev drm_connector_for_each_possible_encoder(connector, encoder, i) { 224*b843c749SSergey Zigachev if ((encoder == best_encoder) && (status == connector_status_connected)) 225*b843c749SSergey Zigachev connected = true; 226*b843c749SSergey Zigachev else 227*b843c749SSergey Zigachev connected = false; 228*b843c749SSergey Zigachev 229*b843c749SSergey Zigachev amdgpu_atombios_encoder_set_bios_scratch_regs(connector, encoder, connected); 230*b843c749SSergey Zigachev } 231*b843c749SSergey Zigachev } 232*b843c749SSergey Zigachev 233*b843c749SSergey Zigachev static struct drm_encoder * 234*b843c749SSergey Zigachev amdgpu_connector_find_encoder(struct drm_connector *connector, 235*b843c749SSergey Zigachev int encoder_type) 236*b843c749SSergey Zigachev { 237*b843c749SSergey Zigachev struct drm_encoder *encoder; 238*b843c749SSergey Zigachev int i; 239*b843c749SSergey Zigachev 240*b843c749SSergey Zigachev drm_connector_for_each_possible_encoder(connector, encoder, i) { 241*b843c749SSergey Zigachev if (encoder->encoder_type == encoder_type) 242*b843c749SSergey Zigachev return encoder; 243*b843c749SSergey Zigachev } 244*b843c749SSergey Zigachev 245*b843c749SSergey Zigachev return NULL; 246*b843c749SSergey Zigachev } 247*b843c749SSergey Zigachev 248*b843c749SSergey Zigachev struct edid *amdgpu_connector_edid(struct drm_connector *connector) 249*b843c749SSergey Zigachev { 250*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 251*b843c749SSergey Zigachev struct drm_property_blob *edid_blob = connector->edid_blob_ptr; 252*b843c749SSergey Zigachev 253*b843c749SSergey Zigachev if (amdgpu_connector->edid) { 254*b843c749SSergey Zigachev return amdgpu_connector->edid; 255*b843c749SSergey Zigachev } else if (edid_blob) { 256*b843c749SSergey Zigachev struct edid *edid = kmemdup(edid_blob->data, edid_blob->length, GFP_KERNEL); 257*b843c749SSergey Zigachev if (edid) 258*b843c749SSergey Zigachev amdgpu_connector->edid = edid; 259*b843c749SSergey Zigachev } 260*b843c749SSergey Zigachev return amdgpu_connector->edid; 261*b843c749SSergey Zigachev } 262*b843c749SSergey Zigachev 263*b843c749SSergey Zigachev static struct edid * 264*b843c749SSergey Zigachev amdgpu_connector_get_hardcoded_edid(struct amdgpu_device *adev) 265*b843c749SSergey Zigachev { 266*b843c749SSergey Zigachev struct edid *edid; 267*b843c749SSergey Zigachev 268*b843c749SSergey Zigachev if (adev->mode_info.bios_hardcoded_edid) { 269*b843c749SSergey Zigachev edid = kmalloc(adev->mode_info.bios_hardcoded_edid_size, GFP_KERNEL); 270*b843c749SSergey Zigachev if (edid) { 271*b843c749SSergey Zigachev memcpy((unsigned char *)edid, 272*b843c749SSergey Zigachev (unsigned char *)adev->mode_info.bios_hardcoded_edid, 273*b843c749SSergey Zigachev adev->mode_info.bios_hardcoded_edid_size); 274*b843c749SSergey Zigachev return edid; 275*b843c749SSergey Zigachev } 276*b843c749SSergey Zigachev } 277*b843c749SSergey Zigachev return NULL; 278*b843c749SSergey Zigachev } 279*b843c749SSergey Zigachev 280*b843c749SSergey Zigachev static void amdgpu_connector_get_edid(struct drm_connector *connector) 281*b843c749SSergey Zigachev { 282*b843c749SSergey Zigachev struct drm_device *dev = connector->dev; 283*b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private; 284*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 285*b843c749SSergey Zigachev 286*b843c749SSergey Zigachev if (amdgpu_connector->edid) 287*b843c749SSergey Zigachev return; 288*b843c749SSergey Zigachev 289*b843c749SSergey Zigachev /* on hw with routers, select right port */ 290*b843c749SSergey Zigachev if (amdgpu_connector->router.ddc_valid) 291*b843c749SSergey Zigachev amdgpu_i2c_router_select_ddc_port(amdgpu_connector); 292*b843c749SSergey Zigachev 293*b843c749SSergey Zigachev if ((amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) != 294*b843c749SSergey Zigachev ENCODER_OBJECT_ID_NONE) && 295*b843c749SSergey Zigachev amdgpu_connector->ddc_bus->has_aux) { 296*b843c749SSergey Zigachev amdgpu_connector->edid = drm_get_edid(connector, 297*b843c749SSergey Zigachev &amdgpu_connector->ddc_bus->aux.ddc); 298*b843c749SSergey Zigachev } else if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) || 299*b843c749SSergey Zigachev (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) { 300*b843c749SSergey Zigachev struct amdgpu_connector_atom_dig *dig = amdgpu_connector->con_priv; 301*b843c749SSergey Zigachev 302*b843c749SSergey Zigachev if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT || 303*b843c749SSergey Zigachev dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && 304*b843c749SSergey Zigachev amdgpu_connector->ddc_bus->has_aux) 305*b843c749SSergey Zigachev amdgpu_connector->edid = drm_get_edid(connector, 306*b843c749SSergey Zigachev &amdgpu_connector->ddc_bus->aux.ddc); 307*b843c749SSergey Zigachev else if (amdgpu_connector->ddc_bus) 308*b843c749SSergey Zigachev amdgpu_connector->edid = drm_get_edid(connector, 309*b843c749SSergey Zigachev &amdgpu_connector->ddc_bus->adapter); 310*b843c749SSergey Zigachev } else if (amdgpu_connector->ddc_bus) { 311*b843c749SSergey Zigachev amdgpu_connector->edid = drm_get_edid(connector, 312*b843c749SSergey Zigachev &amdgpu_connector->ddc_bus->adapter); 313*b843c749SSergey Zigachev } 314*b843c749SSergey Zigachev 315*b843c749SSergey Zigachev if (!amdgpu_connector->edid) { 316*b843c749SSergey Zigachev /* some laptops provide a hardcoded edid in rom for LCDs */ 317*b843c749SSergey Zigachev if (((connector->connector_type == DRM_MODE_CONNECTOR_LVDS) || 318*b843c749SSergey Zigachev (connector->connector_type == DRM_MODE_CONNECTOR_eDP))) 319*b843c749SSergey Zigachev amdgpu_connector->edid = amdgpu_connector_get_hardcoded_edid(adev); 320*b843c749SSergey Zigachev } 321*b843c749SSergey Zigachev } 322*b843c749SSergey Zigachev 323*b843c749SSergey Zigachev static void amdgpu_connector_free_edid(struct drm_connector *connector) 324*b843c749SSergey Zigachev { 325*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 326*b843c749SSergey Zigachev 327*b843c749SSergey Zigachev kfree(amdgpu_connector->edid); 328*b843c749SSergey Zigachev amdgpu_connector->edid = NULL; 329*b843c749SSergey Zigachev } 330*b843c749SSergey Zigachev 331*b843c749SSergey Zigachev static int amdgpu_connector_ddc_get_modes(struct drm_connector *connector) 332*b843c749SSergey Zigachev { 333*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 334*b843c749SSergey Zigachev int ret; 335*b843c749SSergey Zigachev 336*b843c749SSergey Zigachev if (amdgpu_connector->edid) { 337*b843c749SSergey Zigachev drm_connector_update_edid_property(connector, amdgpu_connector->edid); 338*b843c749SSergey Zigachev ret = drm_add_edid_modes(connector, amdgpu_connector->edid); 339*b843c749SSergey Zigachev return ret; 340*b843c749SSergey Zigachev } 341*b843c749SSergey Zigachev drm_connector_update_edid_property(connector, NULL); 342*b843c749SSergey Zigachev return 0; 343*b843c749SSergey Zigachev } 344*b843c749SSergey Zigachev 345*b843c749SSergey Zigachev static struct drm_encoder * 346*b843c749SSergey Zigachev amdgpu_connector_best_single_encoder(struct drm_connector *connector) 347*b843c749SSergey Zigachev { 348*b843c749SSergey Zigachev struct drm_encoder *encoder; 349*b843c749SSergey Zigachev int i; 350*b843c749SSergey Zigachev 351*b843c749SSergey Zigachev /* pick the first one */ 352*b843c749SSergey Zigachev drm_connector_for_each_possible_encoder(connector, encoder, i) 353*b843c749SSergey Zigachev return encoder; 354*b843c749SSergey Zigachev 355*b843c749SSergey Zigachev return NULL; 356*b843c749SSergey Zigachev } 357*b843c749SSergey Zigachev 358*b843c749SSergey Zigachev static void amdgpu_get_native_mode(struct drm_connector *connector) 359*b843c749SSergey Zigachev { 360*b843c749SSergey Zigachev struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector); 361*b843c749SSergey Zigachev struct amdgpu_encoder *amdgpu_encoder; 362*b843c749SSergey Zigachev 363*b843c749SSergey Zigachev if (encoder == NULL) 364*b843c749SSergey Zigachev return; 365*b843c749SSergey Zigachev 366*b843c749SSergey Zigachev amdgpu_encoder = to_amdgpu_encoder(encoder); 367*b843c749SSergey Zigachev 368*b843c749SSergey Zigachev if (!list_empty(&connector->probed_modes)) { 369*b843c749SSergey Zigachev struct drm_display_mode *preferred_mode = 370*b843c749SSergey Zigachev list_first_entry(&connector->probed_modes, 371*b843c749SSergey Zigachev struct drm_display_mode, head); 372*b843c749SSergey Zigachev 373*b843c749SSergey Zigachev amdgpu_encoder->native_mode = *preferred_mode; 374*b843c749SSergey Zigachev } else { 375*b843c749SSergey Zigachev amdgpu_encoder->native_mode.clock = 0; 376*b843c749SSergey Zigachev } 377*b843c749SSergey Zigachev } 378*b843c749SSergey Zigachev 379*b843c749SSergey Zigachev static struct drm_display_mode * 380*b843c749SSergey Zigachev amdgpu_connector_lcd_native_mode(struct drm_encoder *encoder) 381*b843c749SSergey Zigachev { 382*b843c749SSergey Zigachev struct drm_device *dev = encoder->dev; 383*b843c749SSergey Zigachev struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); 384*b843c749SSergey Zigachev struct drm_display_mode *mode = NULL; 385*b843c749SSergey Zigachev struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode; 386*b843c749SSergey Zigachev 387*b843c749SSergey Zigachev if (native_mode->hdisplay != 0 && 388*b843c749SSergey Zigachev native_mode->vdisplay != 0 && 389*b843c749SSergey Zigachev native_mode->clock != 0) { 390*b843c749SSergey Zigachev mode = drm_mode_duplicate(dev, native_mode); 391*b843c749SSergey Zigachev mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; 392*b843c749SSergey Zigachev drm_mode_set_name(mode); 393*b843c749SSergey Zigachev 394*b843c749SSergey Zigachev DRM_DEBUG_KMS("Adding native panel mode %s\n", mode->name); 395*b843c749SSergey Zigachev } else if (native_mode->hdisplay != 0 && 396*b843c749SSergey Zigachev native_mode->vdisplay != 0) { 397*b843c749SSergey Zigachev /* mac laptops without an edid */ 398*b843c749SSergey Zigachev /* Note that this is not necessarily the exact panel mode, 399*b843c749SSergey Zigachev * but an approximation based on the cvt formula. For these 400*b843c749SSergey Zigachev * systems we should ideally read the mode info out of the 401*b843c749SSergey Zigachev * registers or add a mode table, but this works and is much 402*b843c749SSergey Zigachev * simpler. 403*b843c749SSergey Zigachev */ 404*b843c749SSergey Zigachev mode = drm_cvt_mode(dev, native_mode->hdisplay, native_mode->vdisplay, 60, true, false, false); 405*b843c749SSergey Zigachev mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; 406*b843c749SSergey Zigachev DRM_DEBUG_KMS("Adding cvt approximation of native panel mode %s\n", mode->name); 407*b843c749SSergey Zigachev } 408*b843c749SSergey Zigachev return mode; 409*b843c749SSergey Zigachev } 410*b843c749SSergey Zigachev 411*b843c749SSergey Zigachev static void amdgpu_connector_add_common_modes(struct drm_encoder *encoder, 412*b843c749SSergey Zigachev struct drm_connector *connector) 413*b843c749SSergey Zigachev { 414*b843c749SSergey Zigachev struct drm_device *dev = encoder->dev; 415*b843c749SSergey Zigachev struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); 416*b843c749SSergey Zigachev struct drm_display_mode *mode = NULL; 417*b843c749SSergey Zigachev struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode; 418*b843c749SSergey Zigachev int i; 419*b843c749SSergey Zigachev static const struct mode_size { 420*b843c749SSergey Zigachev int w; 421*b843c749SSergey Zigachev int h; 422*b843c749SSergey Zigachev } common_modes[17] = { 423*b843c749SSergey Zigachev { 640, 480}, 424*b843c749SSergey Zigachev { 720, 480}, 425*b843c749SSergey Zigachev { 800, 600}, 426*b843c749SSergey Zigachev { 848, 480}, 427*b843c749SSergey Zigachev {1024, 768}, 428*b843c749SSergey Zigachev {1152, 768}, 429*b843c749SSergey Zigachev {1280, 720}, 430*b843c749SSergey Zigachev {1280, 800}, 431*b843c749SSergey Zigachev {1280, 854}, 432*b843c749SSergey Zigachev {1280, 960}, 433*b843c749SSergey Zigachev {1280, 1024}, 434*b843c749SSergey Zigachev {1440, 900}, 435*b843c749SSergey Zigachev {1400, 1050}, 436*b843c749SSergey Zigachev {1680, 1050}, 437*b843c749SSergey Zigachev {1600, 1200}, 438*b843c749SSergey Zigachev {1920, 1080}, 439*b843c749SSergey Zigachev {1920, 1200} 440*b843c749SSergey Zigachev }; 441*b843c749SSergey Zigachev 442*b843c749SSergey Zigachev for (i = 0; i < 17; i++) { 443*b843c749SSergey Zigachev if (amdgpu_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) { 444*b843c749SSergey Zigachev if (common_modes[i].w > 1024 || 445*b843c749SSergey Zigachev common_modes[i].h > 768) 446*b843c749SSergey Zigachev continue; 447*b843c749SSergey Zigachev } 448*b843c749SSergey Zigachev if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 449*b843c749SSergey Zigachev if (common_modes[i].w > native_mode->hdisplay || 450*b843c749SSergey Zigachev common_modes[i].h > native_mode->vdisplay || 451*b843c749SSergey Zigachev (common_modes[i].w == native_mode->hdisplay && 452*b843c749SSergey Zigachev common_modes[i].h == native_mode->vdisplay)) 453*b843c749SSergey Zigachev continue; 454*b843c749SSergey Zigachev } 455*b843c749SSergey Zigachev if (common_modes[i].w < 320 || common_modes[i].h < 200) 456*b843c749SSergey Zigachev continue; 457*b843c749SSergey Zigachev 458*b843c749SSergey Zigachev mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false); 459*b843c749SSergey Zigachev drm_mode_probed_add(connector, mode); 460*b843c749SSergey Zigachev } 461*b843c749SSergey Zigachev } 462*b843c749SSergey Zigachev 463*b843c749SSergey Zigachev static int amdgpu_connector_set_property(struct drm_connector *connector, 464*b843c749SSergey Zigachev struct drm_property *property, 465*b843c749SSergey Zigachev uint64_t val) 466*b843c749SSergey Zigachev { 467*b843c749SSergey Zigachev struct drm_device *dev = connector->dev; 468*b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private; 469*b843c749SSergey Zigachev struct drm_encoder *encoder; 470*b843c749SSergey Zigachev struct amdgpu_encoder *amdgpu_encoder; 471*b843c749SSergey Zigachev 472*b843c749SSergey Zigachev if (property == adev->mode_info.coherent_mode_property) { 473*b843c749SSergey Zigachev struct amdgpu_encoder_atom_dig *dig; 474*b843c749SSergey Zigachev bool new_coherent_mode; 475*b843c749SSergey Zigachev 476*b843c749SSergey Zigachev /* need to find digital encoder on connector */ 477*b843c749SSergey Zigachev encoder = amdgpu_connector_find_encoder(connector, DRM_MODE_ENCODER_TMDS); 478*b843c749SSergey Zigachev if (!encoder) 479*b843c749SSergey Zigachev return 0; 480*b843c749SSergey Zigachev 481*b843c749SSergey Zigachev amdgpu_encoder = to_amdgpu_encoder(encoder); 482*b843c749SSergey Zigachev 483*b843c749SSergey Zigachev if (!amdgpu_encoder->enc_priv) 484*b843c749SSergey Zigachev return 0; 485*b843c749SSergey Zigachev 486*b843c749SSergey Zigachev dig = amdgpu_encoder->enc_priv; 487*b843c749SSergey Zigachev new_coherent_mode = val ? true : false; 488*b843c749SSergey Zigachev if (dig->coherent_mode != new_coherent_mode) { 489*b843c749SSergey Zigachev dig->coherent_mode = new_coherent_mode; 490*b843c749SSergey Zigachev amdgpu_connector_property_change_mode(&amdgpu_encoder->base); 491*b843c749SSergey Zigachev } 492*b843c749SSergey Zigachev } 493*b843c749SSergey Zigachev 494*b843c749SSergey Zigachev if (property == adev->mode_info.audio_property) { 495*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 496*b843c749SSergey Zigachev /* need to find digital encoder on connector */ 497*b843c749SSergey Zigachev encoder = amdgpu_connector_find_encoder(connector, DRM_MODE_ENCODER_TMDS); 498*b843c749SSergey Zigachev if (!encoder) 499*b843c749SSergey Zigachev return 0; 500*b843c749SSergey Zigachev 501*b843c749SSergey Zigachev amdgpu_encoder = to_amdgpu_encoder(encoder); 502*b843c749SSergey Zigachev 503*b843c749SSergey Zigachev if (amdgpu_connector->audio != val) { 504*b843c749SSergey Zigachev amdgpu_connector->audio = val; 505*b843c749SSergey Zigachev amdgpu_connector_property_change_mode(&amdgpu_encoder->base); 506*b843c749SSergey Zigachev } 507*b843c749SSergey Zigachev } 508*b843c749SSergey Zigachev 509*b843c749SSergey Zigachev if (property == adev->mode_info.dither_property) { 510*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 511*b843c749SSergey Zigachev /* need to find digital encoder on connector */ 512*b843c749SSergey Zigachev encoder = amdgpu_connector_find_encoder(connector, DRM_MODE_ENCODER_TMDS); 513*b843c749SSergey Zigachev if (!encoder) 514*b843c749SSergey Zigachev return 0; 515*b843c749SSergey Zigachev 516*b843c749SSergey Zigachev amdgpu_encoder = to_amdgpu_encoder(encoder); 517*b843c749SSergey Zigachev 518*b843c749SSergey Zigachev if (amdgpu_connector->dither != val) { 519*b843c749SSergey Zigachev amdgpu_connector->dither = val; 520*b843c749SSergey Zigachev amdgpu_connector_property_change_mode(&amdgpu_encoder->base); 521*b843c749SSergey Zigachev } 522*b843c749SSergey Zigachev } 523*b843c749SSergey Zigachev 524*b843c749SSergey Zigachev if (property == adev->mode_info.underscan_property) { 525*b843c749SSergey Zigachev /* need to find digital encoder on connector */ 526*b843c749SSergey Zigachev encoder = amdgpu_connector_find_encoder(connector, DRM_MODE_ENCODER_TMDS); 527*b843c749SSergey Zigachev if (!encoder) 528*b843c749SSergey Zigachev return 0; 529*b843c749SSergey Zigachev 530*b843c749SSergey Zigachev amdgpu_encoder = to_amdgpu_encoder(encoder); 531*b843c749SSergey Zigachev 532*b843c749SSergey Zigachev if (amdgpu_encoder->underscan_type != val) { 533*b843c749SSergey Zigachev amdgpu_encoder->underscan_type = val; 534*b843c749SSergey Zigachev amdgpu_connector_property_change_mode(&amdgpu_encoder->base); 535*b843c749SSergey Zigachev } 536*b843c749SSergey Zigachev } 537*b843c749SSergey Zigachev 538*b843c749SSergey Zigachev if (property == adev->mode_info.underscan_hborder_property) { 539*b843c749SSergey Zigachev /* need to find digital encoder on connector */ 540*b843c749SSergey Zigachev encoder = amdgpu_connector_find_encoder(connector, DRM_MODE_ENCODER_TMDS); 541*b843c749SSergey Zigachev if (!encoder) 542*b843c749SSergey Zigachev return 0; 543*b843c749SSergey Zigachev 544*b843c749SSergey Zigachev amdgpu_encoder = to_amdgpu_encoder(encoder); 545*b843c749SSergey Zigachev 546*b843c749SSergey Zigachev if (amdgpu_encoder->underscan_hborder != val) { 547*b843c749SSergey Zigachev amdgpu_encoder->underscan_hborder = val; 548*b843c749SSergey Zigachev amdgpu_connector_property_change_mode(&amdgpu_encoder->base); 549*b843c749SSergey Zigachev } 550*b843c749SSergey Zigachev } 551*b843c749SSergey Zigachev 552*b843c749SSergey Zigachev if (property == adev->mode_info.underscan_vborder_property) { 553*b843c749SSergey Zigachev /* need to find digital encoder on connector */ 554*b843c749SSergey Zigachev encoder = amdgpu_connector_find_encoder(connector, DRM_MODE_ENCODER_TMDS); 555*b843c749SSergey Zigachev if (!encoder) 556*b843c749SSergey Zigachev return 0; 557*b843c749SSergey Zigachev 558*b843c749SSergey Zigachev amdgpu_encoder = to_amdgpu_encoder(encoder); 559*b843c749SSergey Zigachev 560*b843c749SSergey Zigachev if (amdgpu_encoder->underscan_vborder != val) { 561*b843c749SSergey Zigachev amdgpu_encoder->underscan_vborder = val; 562*b843c749SSergey Zigachev amdgpu_connector_property_change_mode(&amdgpu_encoder->base); 563*b843c749SSergey Zigachev } 564*b843c749SSergey Zigachev } 565*b843c749SSergey Zigachev 566*b843c749SSergey Zigachev if (property == adev->mode_info.load_detect_property) { 567*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = 568*b843c749SSergey Zigachev to_amdgpu_connector(connector); 569*b843c749SSergey Zigachev 570*b843c749SSergey Zigachev if (val == 0) 571*b843c749SSergey Zigachev amdgpu_connector->dac_load_detect = false; 572*b843c749SSergey Zigachev else 573*b843c749SSergey Zigachev amdgpu_connector->dac_load_detect = true; 574*b843c749SSergey Zigachev } 575*b843c749SSergey Zigachev 576*b843c749SSergey Zigachev if (property == dev->mode_config.scaling_mode_property) { 577*b843c749SSergey Zigachev enum amdgpu_rmx_type rmx_type; 578*b843c749SSergey Zigachev 579*b843c749SSergey Zigachev if (connector->encoder) { 580*b843c749SSergey Zigachev amdgpu_encoder = to_amdgpu_encoder(connector->encoder); 581*b843c749SSergey Zigachev } else { 582*b843c749SSergey Zigachev const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; 583*b843c749SSergey Zigachev amdgpu_encoder = to_amdgpu_encoder(connector_funcs->best_encoder(connector)); 584*b843c749SSergey Zigachev } 585*b843c749SSergey Zigachev 586*b843c749SSergey Zigachev switch (val) { 587*b843c749SSergey Zigachev default: 588*b843c749SSergey Zigachev case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break; 589*b843c749SSergey Zigachev case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break; 590*b843c749SSergey Zigachev case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break; 591*b843c749SSergey Zigachev case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break; 592*b843c749SSergey Zigachev } 593*b843c749SSergey Zigachev if (amdgpu_encoder->rmx_type == rmx_type) 594*b843c749SSergey Zigachev return 0; 595*b843c749SSergey Zigachev 596*b843c749SSergey Zigachev if ((rmx_type != DRM_MODE_SCALE_NONE) && 597*b843c749SSergey Zigachev (amdgpu_encoder->native_mode.clock == 0)) 598*b843c749SSergey Zigachev return 0; 599*b843c749SSergey Zigachev 600*b843c749SSergey Zigachev amdgpu_encoder->rmx_type = rmx_type; 601*b843c749SSergey Zigachev 602*b843c749SSergey Zigachev amdgpu_connector_property_change_mode(&amdgpu_encoder->base); 603*b843c749SSergey Zigachev } 604*b843c749SSergey Zigachev 605*b843c749SSergey Zigachev return 0; 606*b843c749SSergey Zigachev } 607*b843c749SSergey Zigachev 608*b843c749SSergey Zigachev static void 609*b843c749SSergey Zigachev amdgpu_connector_fixup_lcd_native_mode(struct drm_encoder *encoder, 610*b843c749SSergey Zigachev struct drm_connector *connector) 611*b843c749SSergey Zigachev { 612*b843c749SSergey Zigachev struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); 613*b843c749SSergey Zigachev struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode; 614*b843c749SSergey Zigachev struct drm_display_mode *t, *mode; 615*b843c749SSergey Zigachev 616*b843c749SSergey Zigachev /* If the EDID preferred mode doesn't match the native mode, use it */ 617*b843c749SSergey Zigachev list_for_each_entry_safe(mode, t, &connector->probed_modes, head) { 618*b843c749SSergey Zigachev if (mode->type & DRM_MODE_TYPE_PREFERRED) { 619*b843c749SSergey Zigachev if (mode->hdisplay != native_mode->hdisplay || 620*b843c749SSergey Zigachev mode->vdisplay != native_mode->vdisplay) 621*b843c749SSergey Zigachev memcpy(native_mode, mode, sizeof(*mode)); 622*b843c749SSergey Zigachev } 623*b843c749SSergey Zigachev } 624*b843c749SSergey Zigachev 625*b843c749SSergey Zigachev /* Try to get native mode details from EDID if necessary */ 626*b843c749SSergey Zigachev if (!native_mode->clock) { 627*b843c749SSergey Zigachev list_for_each_entry_safe(mode, t, &connector->probed_modes, head) { 628*b843c749SSergey Zigachev if (mode->hdisplay == native_mode->hdisplay && 629*b843c749SSergey Zigachev mode->vdisplay == native_mode->vdisplay) { 630*b843c749SSergey Zigachev *native_mode = *mode; 631*b843c749SSergey Zigachev drm_mode_set_crtcinfo(native_mode, CRTC_INTERLACE_HALVE_V); 632*b843c749SSergey Zigachev DRM_DEBUG_KMS("Determined LVDS native mode details from EDID\n"); 633*b843c749SSergey Zigachev break; 634*b843c749SSergey Zigachev } 635*b843c749SSergey Zigachev } 636*b843c749SSergey Zigachev } 637*b843c749SSergey Zigachev 638*b843c749SSergey Zigachev if (!native_mode->clock) { 639*b843c749SSergey Zigachev DRM_DEBUG_KMS("No LVDS native mode details, disabling RMX\n"); 640*b843c749SSergey Zigachev amdgpu_encoder->rmx_type = RMX_OFF; 641*b843c749SSergey Zigachev } 642*b843c749SSergey Zigachev } 643*b843c749SSergey Zigachev 644*b843c749SSergey Zigachev static int amdgpu_connector_lvds_get_modes(struct drm_connector *connector) 645*b843c749SSergey Zigachev { 646*b843c749SSergey Zigachev struct drm_encoder *encoder; 647*b843c749SSergey Zigachev int ret = 0; 648*b843c749SSergey Zigachev struct drm_display_mode *mode; 649*b843c749SSergey Zigachev 650*b843c749SSergey Zigachev amdgpu_connector_get_edid(connector); 651*b843c749SSergey Zigachev ret = amdgpu_connector_ddc_get_modes(connector); 652*b843c749SSergey Zigachev if (ret > 0) { 653*b843c749SSergey Zigachev encoder = amdgpu_connector_best_single_encoder(connector); 654*b843c749SSergey Zigachev if (encoder) { 655*b843c749SSergey Zigachev amdgpu_connector_fixup_lcd_native_mode(encoder, connector); 656*b843c749SSergey Zigachev /* add scaled modes */ 657*b843c749SSergey Zigachev amdgpu_connector_add_common_modes(encoder, connector); 658*b843c749SSergey Zigachev } 659*b843c749SSergey Zigachev return ret; 660*b843c749SSergey Zigachev } 661*b843c749SSergey Zigachev 662*b843c749SSergey Zigachev encoder = amdgpu_connector_best_single_encoder(connector); 663*b843c749SSergey Zigachev if (!encoder) 664*b843c749SSergey Zigachev return 0; 665*b843c749SSergey Zigachev 666*b843c749SSergey Zigachev /* we have no EDID modes */ 667*b843c749SSergey Zigachev mode = amdgpu_connector_lcd_native_mode(encoder); 668*b843c749SSergey Zigachev if (mode) { 669*b843c749SSergey Zigachev ret = 1; 670*b843c749SSergey Zigachev drm_mode_probed_add(connector, mode); 671*b843c749SSergey Zigachev /* add the width/height from vbios tables if available */ 672*b843c749SSergey Zigachev connector->display_info.width_mm = mode->width_mm; 673*b843c749SSergey Zigachev connector->display_info.height_mm = mode->height_mm; 674*b843c749SSergey Zigachev /* add scaled modes */ 675*b843c749SSergey Zigachev amdgpu_connector_add_common_modes(encoder, connector); 676*b843c749SSergey Zigachev } 677*b843c749SSergey Zigachev 678*b843c749SSergey Zigachev return ret; 679*b843c749SSergey Zigachev } 680*b843c749SSergey Zigachev 681*b843c749SSergey Zigachev static enum drm_mode_status amdgpu_connector_lvds_mode_valid(struct drm_connector *connector, 682*b843c749SSergey Zigachev struct drm_display_mode *mode) 683*b843c749SSergey Zigachev { 684*b843c749SSergey Zigachev struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector); 685*b843c749SSergey Zigachev 686*b843c749SSergey Zigachev if ((mode->hdisplay < 320) || (mode->vdisplay < 240)) 687*b843c749SSergey Zigachev return MODE_PANEL; 688*b843c749SSergey Zigachev 689*b843c749SSergey Zigachev if (encoder) { 690*b843c749SSergey Zigachev struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); 691*b843c749SSergey Zigachev struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode; 692*b843c749SSergey Zigachev 693*b843c749SSergey Zigachev /* AVIVO hardware supports downscaling modes larger than the panel 694*b843c749SSergey Zigachev * to the panel size, but I'm not sure this is desirable. 695*b843c749SSergey Zigachev */ 696*b843c749SSergey Zigachev if ((mode->hdisplay > native_mode->hdisplay) || 697*b843c749SSergey Zigachev (mode->vdisplay > native_mode->vdisplay)) 698*b843c749SSergey Zigachev return MODE_PANEL; 699*b843c749SSergey Zigachev 700*b843c749SSergey Zigachev /* if scaling is disabled, block non-native modes */ 701*b843c749SSergey Zigachev if (amdgpu_encoder->rmx_type == RMX_OFF) { 702*b843c749SSergey Zigachev if ((mode->hdisplay != native_mode->hdisplay) || 703*b843c749SSergey Zigachev (mode->vdisplay != native_mode->vdisplay)) 704*b843c749SSergey Zigachev return MODE_PANEL; 705*b843c749SSergey Zigachev } 706*b843c749SSergey Zigachev } 707*b843c749SSergey Zigachev 708*b843c749SSergey Zigachev return MODE_OK; 709*b843c749SSergey Zigachev } 710*b843c749SSergey Zigachev 711*b843c749SSergey Zigachev static enum drm_connector_status 712*b843c749SSergey Zigachev amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force) 713*b843c749SSergey Zigachev { 714*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 715*b843c749SSergey Zigachev struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector); 716*b843c749SSergey Zigachev enum drm_connector_status ret = connector_status_disconnected; 717*b843c749SSergey Zigachev int r; 718*b843c749SSergey Zigachev 719*b843c749SSergey Zigachev if (!drm_kms_helper_is_poll_worker()) { 720*b843c749SSergey Zigachev r = pm_runtime_get_sync(connector->dev->dev); 721*b843c749SSergey Zigachev if (r < 0) { 722*b843c749SSergey Zigachev pm_runtime_put_autosuspend(connector->dev->dev); 723*b843c749SSergey Zigachev return connector_status_disconnected; 724*b843c749SSergey Zigachev } 725*b843c749SSergey Zigachev } 726*b843c749SSergey Zigachev 727*b843c749SSergey Zigachev if (encoder) { 728*b843c749SSergey Zigachev struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); 729*b843c749SSergey Zigachev struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode; 730*b843c749SSergey Zigachev 731*b843c749SSergey Zigachev /* check if panel is valid */ 732*b843c749SSergey Zigachev if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240) 733*b843c749SSergey Zigachev ret = connector_status_connected; 734*b843c749SSergey Zigachev 735*b843c749SSergey Zigachev } 736*b843c749SSergey Zigachev 737*b843c749SSergey Zigachev /* check for edid as well */ 738*b843c749SSergey Zigachev amdgpu_connector_get_edid(connector); 739*b843c749SSergey Zigachev if (amdgpu_connector->edid) 740*b843c749SSergey Zigachev ret = connector_status_connected; 741*b843c749SSergey Zigachev /* check acpi lid status ??? */ 742*b843c749SSergey Zigachev 743*b843c749SSergey Zigachev amdgpu_connector_update_scratch_regs(connector, ret); 744*b843c749SSergey Zigachev 745*b843c749SSergey Zigachev if (!drm_kms_helper_is_poll_worker()) { 746*b843c749SSergey Zigachev pm_runtime_mark_last_busy(connector->dev->dev); 747*b843c749SSergey Zigachev pm_runtime_put_autosuspend(connector->dev->dev); 748*b843c749SSergey Zigachev } 749*b843c749SSergey Zigachev 750*b843c749SSergey Zigachev return ret; 751*b843c749SSergey Zigachev } 752*b843c749SSergey Zigachev 753*b843c749SSergey Zigachev static void amdgpu_connector_unregister(struct drm_connector *connector) 754*b843c749SSergey Zigachev { 755*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 756*b843c749SSergey Zigachev 757*b843c749SSergey Zigachev if (amdgpu_connector->ddc_bus && amdgpu_connector->ddc_bus->has_aux) { 758*b843c749SSergey Zigachev drm_dp_aux_unregister(&amdgpu_connector->ddc_bus->aux); 759*b843c749SSergey Zigachev amdgpu_connector->ddc_bus->has_aux = false; 760*b843c749SSergey Zigachev } 761*b843c749SSergey Zigachev } 762*b843c749SSergey Zigachev 763*b843c749SSergey Zigachev static void amdgpu_connector_destroy(struct drm_connector *connector) 764*b843c749SSergey Zigachev { 765*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 766*b843c749SSergey Zigachev 767*b843c749SSergey Zigachev amdgpu_connector_free_edid(connector); 768*b843c749SSergey Zigachev kfree(amdgpu_connector->con_priv); 769*b843c749SSergey Zigachev drm_connector_unregister(connector); 770*b843c749SSergey Zigachev drm_connector_cleanup(connector); 771*b843c749SSergey Zigachev kfree(connector); 772*b843c749SSergey Zigachev } 773*b843c749SSergey Zigachev 774*b843c749SSergey Zigachev static int amdgpu_connector_set_lcd_property(struct drm_connector *connector, 775*b843c749SSergey Zigachev struct drm_property *property, 776*b843c749SSergey Zigachev uint64_t value) 777*b843c749SSergey Zigachev { 778*b843c749SSergey Zigachev struct drm_device *dev = connector->dev; 779*b843c749SSergey Zigachev struct amdgpu_encoder *amdgpu_encoder; 780*b843c749SSergey Zigachev enum amdgpu_rmx_type rmx_type; 781*b843c749SSergey Zigachev 782*b843c749SSergey Zigachev DRM_DEBUG_KMS("\n"); 783*b843c749SSergey Zigachev if (property != dev->mode_config.scaling_mode_property) 784*b843c749SSergey Zigachev return 0; 785*b843c749SSergey Zigachev 786*b843c749SSergey Zigachev if (connector->encoder) 787*b843c749SSergey Zigachev amdgpu_encoder = to_amdgpu_encoder(connector->encoder); 788*b843c749SSergey Zigachev else { 789*b843c749SSergey Zigachev const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; 790*b843c749SSergey Zigachev amdgpu_encoder = to_amdgpu_encoder(connector_funcs->best_encoder(connector)); 791*b843c749SSergey Zigachev } 792*b843c749SSergey Zigachev 793*b843c749SSergey Zigachev switch (value) { 794*b843c749SSergey Zigachev case DRM_MODE_SCALE_NONE: rmx_type = RMX_OFF; break; 795*b843c749SSergey Zigachev case DRM_MODE_SCALE_CENTER: rmx_type = RMX_CENTER; break; 796*b843c749SSergey Zigachev case DRM_MODE_SCALE_ASPECT: rmx_type = RMX_ASPECT; break; 797*b843c749SSergey Zigachev default: 798*b843c749SSergey Zigachev case DRM_MODE_SCALE_FULLSCREEN: rmx_type = RMX_FULL; break; 799*b843c749SSergey Zigachev } 800*b843c749SSergey Zigachev if (amdgpu_encoder->rmx_type == rmx_type) 801*b843c749SSergey Zigachev return 0; 802*b843c749SSergey Zigachev 803*b843c749SSergey Zigachev amdgpu_encoder->rmx_type = rmx_type; 804*b843c749SSergey Zigachev 805*b843c749SSergey Zigachev amdgpu_connector_property_change_mode(&amdgpu_encoder->base); 806*b843c749SSergey Zigachev return 0; 807*b843c749SSergey Zigachev } 808*b843c749SSergey Zigachev 809*b843c749SSergey Zigachev 810*b843c749SSergey Zigachev static const struct drm_connector_helper_funcs amdgpu_connector_lvds_helper_funcs = { 811*b843c749SSergey Zigachev .get_modes = amdgpu_connector_lvds_get_modes, 812*b843c749SSergey Zigachev .mode_valid = amdgpu_connector_lvds_mode_valid, 813*b843c749SSergey Zigachev .best_encoder = amdgpu_connector_best_single_encoder, 814*b843c749SSergey Zigachev }; 815*b843c749SSergey Zigachev 816*b843c749SSergey Zigachev static const struct drm_connector_funcs amdgpu_connector_lvds_funcs = { 817*b843c749SSergey Zigachev .dpms = drm_helper_connector_dpms, 818*b843c749SSergey Zigachev .detect = amdgpu_connector_lvds_detect, 819*b843c749SSergey Zigachev .fill_modes = drm_helper_probe_single_connector_modes, 820*b843c749SSergey Zigachev .early_unregister = amdgpu_connector_unregister, 821*b843c749SSergey Zigachev .destroy = amdgpu_connector_destroy, 822*b843c749SSergey Zigachev .set_property = amdgpu_connector_set_lcd_property, 823*b843c749SSergey Zigachev }; 824*b843c749SSergey Zigachev 825*b843c749SSergey Zigachev static int amdgpu_connector_vga_get_modes(struct drm_connector *connector) 826*b843c749SSergey Zigachev { 827*b843c749SSergey Zigachev int ret; 828*b843c749SSergey Zigachev 829*b843c749SSergey Zigachev amdgpu_connector_get_edid(connector); 830*b843c749SSergey Zigachev ret = amdgpu_connector_ddc_get_modes(connector); 831*b843c749SSergey Zigachev 832*b843c749SSergey Zigachev return ret; 833*b843c749SSergey Zigachev } 834*b843c749SSergey Zigachev 835*b843c749SSergey Zigachev static enum drm_mode_status amdgpu_connector_vga_mode_valid(struct drm_connector *connector, 836*b843c749SSergey Zigachev struct drm_display_mode *mode) 837*b843c749SSergey Zigachev { 838*b843c749SSergey Zigachev struct drm_device *dev = connector->dev; 839*b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private; 840*b843c749SSergey Zigachev 841*b843c749SSergey Zigachev /* XXX check mode bandwidth */ 842*b843c749SSergey Zigachev 843*b843c749SSergey Zigachev if ((mode->clock / 10) > adev->clock.max_pixel_clock) 844*b843c749SSergey Zigachev return MODE_CLOCK_HIGH; 845*b843c749SSergey Zigachev 846*b843c749SSergey Zigachev return MODE_OK; 847*b843c749SSergey Zigachev } 848*b843c749SSergey Zigachev 849*b843c749SSergey Zigachev static enum drm_connector_status 850*b843c749SSergey Zigachev amdgpu_connector_vga_detect(struct drm_connector *connector, bool force) 851*b843c749SSergey Zigachev { 852*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 853*b843c749SSergey Zigachev struct drm_encoder *encoder; 854*b843c749SSergey Zigachev const struct drm_encoder_helper_funcs *encoder_funcs; 855*b843c749SSergey Zigachev bool dret = false; 856*b843c749SSergey Zigachev enum drm_connector_status ret = connector_status_disconnected; 857*b843c749SSergey Zigachev int r; 858*b843c749SSergey Zigachev 859*b843c749SSergey Zigachev if (!drm_kms_helper_is_poll_worker()) { 860*b843c749SSergey Zigachev r = pm_runtime_get_sync(connector->dev->dev); 861*b843c749SSergey Zigachev if (r < 0) { 862*b843c749SSergey Zigachev pm_runtime_put_autosuspend(connector->dev->dev); 863*b843c749SSergey Zigachev return connector_status_disconnected; 864*b843c749SSergey Zigachev } 865*b843c749SSergey Zigachev } 866*b843c749SSergey Zigachev 867*b843c749SSergey Zigachev encoder = amdgpu_connector_best_single_encoder(connector); 868*b843c749SSergey Zigachev if (!encoder) 869*b843c749SSergey Zigachev ret = connector_status_disconnected; 870*b843c749SSergey Zigachev 871*b843c749SSergey Zigachev if (amdgpu_connector->ddc_bus) 872*b843c749SSergey Zigachev dret = amdgpu_display_ddc_probe(amdgpu_connector, false); 873*b843c749SSergey Zigachev if (dret) { 874*b843c749SSergey Zigachev amdgpu_connector->detected_by_load = false; 875*b843c749SSergey Zigachev amdgpu_connector_free_edid(connector); 876*b843c749SSergey Zigachev amdgpu_connector_get_edid(connector); 877*b843c749SSergey Zigachev 878*b843c749SSergey Zigachev if (!amdgpu_connector->edid) { 879*b843c749SSergey Zigachev DRM_ERROR("%s: probed a monitor but no|invalid EDID\n", 880*b843c749SSergey Zigachev connector->name); 881*b843c749SSergey Zigachev ret = connector_status_connected; 882*b843c749SSergey Zigachev } else { 883*b843c749SSergey Zigachev amdgpu_connector->use_digital = 884*b843c749SSergey Zigachev !!(amdgpu_connector->edid->input & DRM_EDID_INPUT_DIGITAL); 885*b843c749SSergey Zigachev 886*b843c749SSergey Zigachev /* some oems have boards with separate digital and analog connectors 887*b843c749SSergey Zigachev * with a shared ddc line (often vga + hdmi) 888*b843c749SSergey Zigachev */ 889*b843c749SSergey Zigachev if (amdgpu_connector->use_digital && amdgpu_connector->shared_ddc) { 890*b843c749SSergey Zigachev amdgpu_connector_free_edid(connector); 891*b843c749SSergey Zigachev ret = connector_status_disconnected; 892*b843c749SSergey Zigachev } else { 893*b843c749SSergey Zigachev ret = connector_status_connected; 894*b843c749SSergey Zigachev } 895*b843c749SSergey Zigachev } 896*b843c749SSergey Zigachev } else { 897*b843c749SSergey Zigachev 898*b843c749SSergey Zigachev /* if we aren't forcing don't do destructive polling */ 899*b843c749SSergey Zigachev if (!force) { 900*b843c749SSergey Zigachev /* only return the previous status if we last 901*b843c749SSergey Zigachev * detected a monitor via load. 902*b843c749SSergey Zigachev */ 903*b843c749SSergey Zigachev if (amdgpu_connector->detected_by_load) 904*b843c749SSergey Zigachev ret = connector->status; 905*b843c749SSergey Zigachev goto out; 906*b843c749SSergey Zigachev } 907*b843c749SSergey Zigachev 908*b843c749SSergey Zigachev if (amdgpu_connector->dac_load_detect && encoder) { 909*b843c749SSergey Zigachev encoder_funcs = encoder->helper_private; 910*b843c749SSergey Zigachev ret = encoder_funcs->detect(encoder, connector); 911*b843c749SSergey Zigachev if (ret != connector_status_disconnected) 912*b843c749SSergey Zigachev amdgpu_connector->detected_by_load = true; 913*b843c749SSergey Zigachev } 914*b843c749SSergey Zigachev } 915*b843c749SSergey Zigachev 916*b843c749SSergey Zigachev amdgpu_connector_update_scratch_regs(connector, ret); 917*b843c749SSergey Zigachev 918*b843c749SSergey Zigachev out: 919*b843c749SSergey Zigachev if (!drm_kms_helper_is_poll_worker()) { 920*b843c749SSergey Zigachev pm_runtime_mark_last_busy(connector->dev->dev); 921*b843c749SSergey Zigachev pm_runtime_put_autosuspend(connector->dev->dev); 922*b843c749SSergey Zigachev } 923*b843c749SSergey Zigachev 924*b843c749SSergey Zigachev return ret; 925*b843c749SSergey Zigachev } 926*b843c749SSergey Zigachev 927*b843c749SSergey Zigachev static const struct drm_connector_helper_funcs amdgpu_connector_vga_helper_funcs = { 928*b843c749SSergey Zigachev .get_modes = amdgpu_connector_vga_get_modes, 929*b843c749SSergey Zigachev .mode_valid = amdgpu_connector_vga_mode_valid, 930*b843c749SSergey Zigachev .best_encoder = amdgpu_connector_best_single_encoder, 931*b843c749SSergey Zigachev }; 932*b843c749SSergey Zigachev 933*b843c749SSergey Zigachev static const struct drm_connector_funcs amdgpu_connector_vga_funcs = { 934*b843c749SSergey Zigachev .dpms = drm_helper_connector_dpms, 935*b843c749SSergey Zigachev .detect = amdgpu_connector_vga_detect, 936*b843c749SSergey Zigachev .fill_modes = drm_helper_probe_single_connector_modes, 937*b843c749SSergey Zigachev .early_unregister = amdgpu_connector_unregister, 938*b843c749SSergey Zigachev .destroy = amdgpu_connector_destroy, 939*b843c749SSergey Zigachev .set_property = amdgpu_connector_set_property, 940*b843c749SSergey Zigachev }; 941*b843c749SSergey Zigachev 942*b843c749SSergey Zigachev static bool 943*b843c749SSergey Zigachev amdgpu_connector_check_hpd_status_unchanged(struct drm_connector *connector) 944*b843c749SSergey Zigachev { 945*b843c749SSergey Zigachev struct drm_device *dev = connector->dev; 946*b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private; 947*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 948*b843c749SSergey Zigachev enum drm_connector_status status; 949*b843c749SSergey Zigachev 950*b843c749SSergey Zigachev if (amdgpu_connector->hpd.hpd != AMDGPU_HPD_NONE) { 951*b843c749SSergey Zigachev if (amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd)) 952*b843c749SSergey Zigachev status = connector_status_connected; 953*b843c749SSergey Zigachev else 954*b843c749SSergey Zigachev status = connector_status_disconnected; 955*b843c749SSergey Zigachev if (connector->status == status) 956*b843c749SSergey Zigachev return true; 957*b843c749SSergey Zigachev } 958*b843c749SSergey Zigachev 959*b843c749SSergey Zigachev return false; 960*b843c749SSergey Zigachev } 961*b843c749SSergey Zigachev 962*b843c749SSergey Zigachev /* 963*b843c749SSergey Zigachev * DVI is complicated 964*b843c749SSergey Zigachev * Do a DDC probe, if DDC probe passes, get the full EDID so 965*b843c749SSergey Zigachev * we can do analog/digital monitor detection at this point. 966*b843c749SSergey Zigachev * If the monitor is an analog monitor or we got no DDC, 967*b843c749SSergey Zigachev * we need to find the DAC encoder object for this connector. 968*b843c749SSergey Zigachev * If we got no DDC, we do load detection on the DAC encoder object. 969*b843c749SSergey Zigachev * If we got analog DDC or load detection passes on the DAC encoder 970*b843c749SSergey Zigachev * we have to check if this analog encoder is shared with anyone else (TV) 971*b843c749SSergey Zigachev * if its shared we have to set the other connector to disconnected. 972*b843c749SSergey Zigachev */ 973*b843c749SSergey Zigachev static enum drm_connector_status 974*b843c749SSergey Zigachev amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force) 975*b843c749SSergey Zigachev { 976*b843c749SSergey Zigachev struct drm_device *dev = connector->dev; 977*b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private; 978*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 979*b843c749SSergey Zigachev const struct drm_encoder_helper_funcs *encoder_funcs; 980*b843c749SSergey Zigachev int r; 981*b843c749SSergey Zigachev enum drm_connector_status ret = connector_status_disconnected; 982*b843c749SSergey Zigachev bool dret = false, broken_edid = false; 983*b843c749SSergey Zigachev 984*b843c749SSergey Zigachev if (!drm_kms_helper_is_poll_worker()) { 985*b843c749SSergey Zigachev r = pm_runtime_get_sync(connector->dev->dev); 986*b843c749SSergey Zigachev if (r < 0) { 987*b843c749SSergey Zigachev pm_runtime_put_autosuspend(connector->dev->dev); 988*b843c749SSergey Zigachev return connector_status_disconnected; 989*b843c749SSergey Zigachev } 990*b843c749SSergey Zigachev } 991*b843c749SSergey Zigachev 992*b843c749SSergey Zigachev if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) { 993*b843c749SSergey Zigachev ret = connector->status; 994*b843c749SSergey Zigachev goto exit; 995*b843c749SSergey Zigachev } 996*b843c749SSergey Zigachev 997*b843c749SSergey Zigachev if (amdgpu_connector->ddc_bus) 998*b843c749SSergey Zigachev dret = amdgpu_display_ddc_probe(amdgpu_connector, false); 999*b843c749SSergey Zigachev if (dret) { 1000*b843c749SSergey Zigachev amdgpu_connector->detected_by_load = false; 1001*b843c749SSergey Zigachev amdgpu_connector_free_edid(connector); 1002*b843c749SSergey Zigachev amdgpu_connector_get_edid(connector); 1003*b843c749SSergey Zigachev 1004*b843c749SSergey Zigachev if (!amdgpu_connector->edid) { 1005*b843c749SSergey Zigachev DRM_ERROR("%s: probed a monitor but no|invalid EDID\n", 1006*b843c749SSergey Zigachev connector->name); 1007*b843c749SSergey Zigachev ret = connector_status_connected; 1008*b843c749SSergey Zigachev broken_edid = true; /* defer use_digital to later */ 1009*b843c749SSergey Zigachev } else { 1010*b843c749SSergey Zigachev amdgpu_connector->use_digital = 1011*b843c749SSergey Zigachev !!(amdgpu_connector->edid->input & DRM_EDID_INPUT_DIGITAL); 1012*b843c749SSergey Zigachev 1013*b843c749SSergey Zigachev /* some oems have boards with separate digital and analog connectors 1014*b843c749SSergey Zigachev * with a shared ddc line (often vga + hdmi) 1015*b843c749SSergey Zigachev */ 1016*b843c749SSergey Zigachev if ((!amdgpu_connector->use_digital) && amdgpu_connector->shared_ddc) { 1017*b843c749SSergey Zigachev amdgpu_connector_free_edid(connector); 1018*b843c749SSergey Zigachev ret = connector_status_disconnected; 1019*b843c749SSergey Zigachev } else { 1020*b843c749SSergey Zigachev ret = connector_status_connected; 1021*b843c749SSergey Zigachev } 1022*b843c749SSergey Zigachev 1023*b843c749SSergey Zigachev /* This gets complicated. We have boards with VGA + HDMI with a 1024*b843c749SSergey Zigachev * shared DDC line and we have boards with DVI-D + HDMI with a shared 1025*b843c749SSergey Zigachev * DDC line. The latter is more complex because with DVI<->HDMI adapters 1026*b843c749SSergey Zigachev * you don't really know what's connected to which port as both are digital. 1027*b843c749SSergey Zigachev */ 1028*b843c749SSergey Zigachev if (amdgpu_connector->shared_ddc && (ret == connector_status_connected)) { 1029*b843c749SSergey Zigachev struct drm_connector *list_connector; 1030*b843c749SSergey Zigachev struct amdgpu_connector *list_amdgpu_connector; 1031*b843c749SSergey Zigachev list_for_each_entry(list_connector, &dev->mode_config.connector_list, head) { 1032*b843c749SSergey Zigachev if (connector == list_connector) 1033*b843c749SSergey Zigachev continue; 1034*b843c749SSergey Zigachev list_amdgpu_connector = to_amdgpu_connector(list_connector); 1035*b843c749SSergey Zigachev if (list_amdgpu_connector->shared_ddc && 1036*b843c749SSergey Zigachev (list_amdgpu_connector->ddc_bus->rec.i2c_id == 1037*b843c749SSergey Zigachev amdgpu_connector->ddc_bus->rec.i2c_id)) { 1038*b843c749SSergey Zigachev /* cases where both connectors are digital */ 1039*b843c749SSergey Zigachev if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) { 1040*b843c749SSergey Zigachev /* hpd is our only option in this case */ 1041*b843c749SSergey Zigachev if (!amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd)) { 1042*b843c749SSergey Zigachev amdgpu_connector_free_edid(connector); 1043*b843c749SSergey Zigachev ret = connector_status_disconnected; 1044*b843c749SSergey Zigachev } 1045*b843c749SSergey Zigachev } 1046*b843c749SSergey Zigachev } 1047*b843c749SSergey Zigachev } 1048*b843c749SSergey Zigachev } 1049*b843c749SSergey Zigachev } 1050*b843c749SSergey Zigachev } 1051*b843c749SSergey Zigachev 1052*b843c749SSergey Zigachev if ((ret == connector_status_connected) && (amdgpu_connector->use_digital == true)) 1053*b843c749SSergey Zigachev goto out; 1054*b843c749SSergey Zigachev 1055*b843c749SSergey Zigachev /* DVI-D and HDMI-A are digital only */ 1056*b843c749SSergey Zigachev if ((connector->connector_type == DRM_MODE_CONNECTOR_DVID) || 1057*b843c749SSergey Zigachev (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)) 1058*b843c749SSergey Zigachev goto out; 1059*b843c749SSergey Zigachev 1060*b843c749SSergey Zigachev /* if we aren't forcing don't do destructive polling */ 1061*b843c749SSergey Zigachev if (!force) { 1062*b843c749SSergey Zigachev /* only return the previous status if we last 1063*b843c749SSergey Zigachev * detected a monitor via load. 1064*b843c749SSergey Zigachev */ 1065*b843c749SSergey Zigachev if (amdgpu_connector->detected_by_load) 1066*b843c749SSergey Zigachev ret = connector->status; 1067*b843c749SSergey Zigachev goto out; 1068*b843c749SSergey Zigachev } 1069*b843c749SSergey Zigachev 1070*b843c749SSergey Zigachev /* find analog encoder */ 1071*b843c749SSergey Zigachev if (amdgpu_connector->dac_load_detect) { 1072*b843c749SSergey Zigachev struct drm_encoder *encoder; 1073*b843c749SSergey Zigachev int i; 1074*b843c749SSergey Zigachev 1075*b843c749SSergey Zigachev drm_connector_for_each_possible_encoder(connector, encoder, i) { 1076*b843c749SSergey Zigachev if (encoder->encoder_type != DRM_MODE_ENCODER_DAC && 1077*b843c749SSergey Zigachev encoder->encoder_type != DRM_MODE_ENCODER_TVDAC) 1078*b843c749SSergey Zigachev continue; 1079*b843c749SSergey Zigachev 1080*b843c749SSergey Zigachev encoder_funcs = encoder->helper_private; 1081*b843c749SSergey Zigachev if (encoder_funcs->detect) { 1082*b843c749SSergey Zigachev if (!broken_edid) { 1083*b843c749SSergey Zigachev if (ret != connector_status_connected) { 1084*b843c749SSergey Zigachev /* deal with analog monitors without DDC */ 1085*b843c749SSergey Zigachev ret = encoder_funcs->detect(encoder, connector); 1086*b843c749SSergey Zigachev if (ret == connector_status_connected) { 1087*b843c749SSergey Zigachev amdgpu_connector->use_digital = false; 1088*b843c749SSergey Zigachev } 1089*b843c749SSergey Zigachev if (ret != connector_status_disconnected) 1090*b843c749SSergey Zigachev amdgpu_connector->detected_by_load = true; 1091*b843c749SSergey Zigachev } 1092*b843c749SSergey Zigachev } else { 1093*b843c749SSergey Zigachev enum drm_connector_status lret; 1094*b843c749SSergey Zigachev /* assume digital unless load detected otherwise */ 1095*b843c749SSergey Zigachev amdgpu_connector->use_digital = true; 1096*b843c749SSergey Zigachev lret = encoder_funcs->detect(encoder, connector); 1097*b843c749SSergey Zigachev DRM_DEBUG_KMS("load_detect %x returned: %x\n",encoder->encoder_type,lret); 1098*b843c749SSergey Zigachev if (lret == connector_status_connected) 1099*b843c749SSergey Zigachev amdgpu_connector->use_digital = false; 1100*b843c749SSergey Zigachev } 1101*b843c749SSergey Zigachev break; 1102*b843c749SSergey Zigachev } 1103*b843c749SSergey Zigachev } 1104*b843c749SSergey Zigachev } 1105*b843c749SSergey Zigachev 1106*b843c749SSergey Zigachev out: 1107*b843c749SSergey Zigachev /* updated in get modes as well since we need to know if it's analog or digital */ 1108*b843c749SSergey Zigachev amdgpu_connector_update_scratch_regs(connector, ret); 1109*b843c749SSergey Zigachev 1110*b843c749SSergey Zigachev exit: 1111*b843c749SSergey Zigachev if (!drm_kms_helper_is_poll_worker()) { 1112*b843c749SSergey Zigachev pm_runtime_mark_last_busy(connector->dev->dev); 1113*b843c749SSergey Zigachev pm_runtime_put_autosuspend(connector->dev->dev); 1114*b843c749SSergey Zigachev } 1115*b843c749SSergey Zigachev 1116*b843c749SSergey Zigachev return ret; 1117*b843c749SSergey Zigachev } 1118*b843c749SSergey Zigachev 1119*b843c749SSergey Zigachev /* okay need to be smart in here about which encoder to pick */ 1120*b843c749SSergey Zigachev static struct drm_encoder * 1121*b843c749SSergey Zigachev amdgpu_connector_dvi_encoder(struct drm_connector *connector) 1122*b843c749SSergey Zigachev { 1123*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 1124*b843c749SSergey Zigachev struct drm_encoder *encoder; 1125*b843c749SSergey Zigachev int i; 1126*b843c749SSergey Zigachev 1127*b843c749SSergey Zigachev drm_connector_for_each_possible_encoder(connector, encoder, i) { 1128*b843c749SSergey Zigachev if (amdgpu_connector->use_digital == true) { 1129*b843c749SSergey Zigachev if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS) 1130*b843c749SSergey Zigachev return encoder; 1131*b843c749SSergey Zigachev } else { 1132*b843c749SSergey Zigachev if (encoder->encoder_type == DRM_MODE_ENCODER_DAC || 1133*b843c749SSergey Zigachev encoder->encoder_type == DRM_MODE_ENCODER_TVDAC) 1134*b843c749SSergey Zigachev return encoder; 1135*b843c749SSergey Zigachev } 1136*b843c749SSergey Zigachev } 1137*b843c749SSergey Zigachev 1138*b843c749SSergey Zigachev /* see if we have a default encoder TODO */ 1139*b843c749SSergey Zigachev 1140*b843c749SSergey Zigachev /* then check use digitial */ 1141*b843c749SSergey Zigachev /* pick the first one */ 1142*b843c749SSergey Zigachev drm_connector_for_each_possible_encoder(connector, encoder, i) 1143*b843c749SSergey Zigachev return encoder; 1144*b843c749SSergey Zigachev 1145*b843c749SSergey Zigachev return NULL; 1146*b843c749SSergey Zigachev } 1147*b843c749SSergey Zigachev 1148*b843c749SSergey Zigachev static void amdgpu_connector_dvi_force(struct drm_connector *connector) 1149*b843c749SSergey Zigachev { 1150*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 1151*b843c749SSergey Zigachev if (connector->force == DRM_FORCE_ON) 1152*b843c749SSergey Zigachev amdgpu_connector->use_digital = false; 1153*b843c749SSergey Zigachev if (connector->force == DRM_FORCE_ON_DIGITAL) 1154*b843c749SSergey Zigachev amdgpu_connector->use_digital = true; 1155*b843c749SSergey Zigachev } 1156*b843c749SSergey Zigachev 1157*b843c749SSergey Zigachev static enum drm_mode_status amdgpu_connector_dvi_mode_valid(struct drm_connector *connector, 1158*b843c749SSergey Zigachev struct drm_display_mode *mode) 1159*b843c749SSergey Zigachev { 1160*b843c749SSergey Zigachev struct drm_device *dev = connector->dev; 1161*b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private; 1162*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 1163*b843c749SSergey Zigachev 1164*b843c749SSergey Zigachev /* XXX check mode bandwidth */ 1165*b843c749SSergey Zigachev 1166*b843c749SSergey Zigachev if (amdgpu_connector->use_digital && (mode->clock > 165000)) { 1167*b843c749SSergey Zigachev if ((amdgpu_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I) || 1168*b843c749SSergey Zigachev (amdgpu_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D) || 1169*b843c749SSergey Zigachev (amdgpu_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_B)) { 1170*b843c749SSergey Zigachev return MODE_OK; 1171*b843c749SSergey Zigachev } else if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) { 1172*b843c749SSergey Zigachev /* HDMI 1.3+ supports max clock of 340 Mhz */ 1173*b843c749SSergey Zigachev if (mode->clock > 340000) 1174*b843c749SSergey Zigachev return MODE_CLOCK_HIGH; 1175*b843c749SSergey Zigachev else 1176*b843c749SSergey Zigachev return MODE_OK; 1177*b843c749SSergey Zigachev } else { 1178*b843c749SSergey Zigachev return MODE_CLOCK_HIGH; 1179*b843c749SSergey Zigachev } 1180*b843c749SSergey Zigachev } 1181*b843c749SSergey Zigachev 1182*b843c749SSergey Zigachev /* check against the max pixel clock */ 1183*b843c749SSergey Zigachev if ((mode->clock / 10) > adev->clock.max_pixel_clock) 1184*b843c749SSergey Zigachev return MODE_CLOCK_HIGH; 1185*b843c749SSergey Zigachev 1186*b843c749SSergey Zigachev return MODE_OK; 1187*b843c749SSergey Zigachev } 1188*b843c749SSergey Zigachev 1189*b843c749SSergey Zigachev static const struct drm_connector_helper_funcs amdgpu_connector_dvi_helper_funcs = { 1190*b843c749SSergey Zigachev .get_modes = amdgpu_connector_vga_get_modes, 1191*b843c749SSergey Zigachev .mode_valid = amdgpu_connector_dvi_mode_valid, 1192*b843c749SSergey Zigachev .best_encoder = amdgpu_connector_dvi_encoder, 1193*b843c749SSergey Zigachev }; 1194*b843c749SSergey Zigachev 1195*b843c749SSergey Zigachev static const struct drm_connector_funcs amdgpu_connector_dvi_funcs = { 1196*b843c749SSergey Zigachev .dpms = drm_helper_connector_dpms, 1197*b843c749SSergey Zigachev .detect = amdgpu_connector_dvi_detect, 1198*b843c749SSergey Zigachev .fill_modes = drm_helper_probe_single_connector_modes, 1199*b843c749SSergey Zigachev .set_property = amdgpu_connector_set_property, 1200*b843c749SSergey Zigachev .early_unregister = amdgpu_connector_unregister, 1201*b843c749SSergey Zigachev .destroy = amdgpu_connector_destroy, 1202*b843c749SSergey Zigachev .force = amdgpu_connector_dvi_force, 1203*b843c749SSergey Zigachev }; 1204*b843c749SSergey Zigachev 1205*b843c749SSergey Zigachev static int amdgpu_connector_dp_get_modes(struct drm_connector *connector) 1206*b843c749SSergey Zigachev { 1207*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 1208*b843c749SSergey Zigachev struct amdgpu_connector_atom_dig *amdgpu_dig_connector = amdgpu_connector->con_priv; 1209*b843c749SSergey Zigachev struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector); 1210*b843c749SSergey Zigachev int ret; 1211*b843c749SSergey Zigachev 1212*b843c749SSergey Zigachev if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) || 1213*b843c749SSergey Zigachev (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) { 1214*b843c749SSergey Zigachev struct drm_display_mode *mode; 1215*b843c749SSergey Zigachev 1216*b843c749SSergey Zigachev if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { 1217*b843c749SSergey Zigachev if (!amdgpu_dig_connector->edp_on) 1218*b843c749SSergey Zigachev amdgpu_atombios_encoder_set_edp_panel_power(connector, 1219*b843c749SSergey Zigachev ATOM_TRANSMITTER_ACTION_POWER_ON); 1220*b843c749SSergey Zigachev amdgpu_connector_get_edid(connector); 1221*b843c749SSergey Zigachev ret = amdgpu_connector_ddc_get_modes(connector); 1222*b843c749SSergey Zigachev if (!amdgpu_dig_connector->edp_on) 1223*b843c749SSergey Zigachev amdgpu_atombios_encoder_set_edp_panel_power(connector, 1224*b843c749SSergey Zigachev ATOM_TRANSMITTER_ACTION_POWER_OFF); 1225*b843c749SSergey Zigachev } else { 1226*b843c749SSergey Zigachev /* need to setup ddc on the bridge */ 1227*b843c749SSergey Zigachev if (amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) != 1228*b843c749SSergey Zigachev ENCODER_OBJECT_ID_NONE) { 1229*b843c749SSergey Zigachev if (encoder) 1230*b843c749SSergey Zigachev amdgpu_atombios_encoder_setup_ext_encoder_ddc(encoder); 1231*b843c749SSergey Zigachev } 1232*b843c749SSergey Zigachev amdgpu_connector_get_edid(connector); 1233*b843c749SSergey Zigachev ret = amdgpu_connector_ddc_get_modes(connector); 1234*b843c749SSergey Zigachev } 1235*b843c749SSergey Zigachev 1236*b843c749SSergey Zigachev if (ret > 0) { 1237*b843c749SSergey Zigachev if (encoder) { 1238*b843c749SSergey Zigachev amdgpu_connector_fixup_lcd_native_mode(encoder, connector); 1239*b843c749SSergey Zigachev /* add scaled modes */ 1240*b843c749SSergey Zigachev amdgpu_connector_add_common_modes(encoder, connector); 1241*b843c749SSergey Zigachev } 1242*b843c749SSergey Zigachev return ret; 1243*b843c749SSergey Zigachev } 1244*b843c749SSergey Zigachev 1245*b843c749SSergey Zigachev if (!encoder) 1246*b843c749SSergey Zigachev return 0; 1247*b843c749SSergey Zigachev 1248*b843c749SSergey Zigachev /* we have no EDID modes */ 1249*b843c749SSergey Zigachev mode = amdgpu_connector_lcd_native_mode(encoder); 1250*b843c749SSergey Zigachev if (mode) { 1251*b843c749SSergey Zigachev ret = 1; 1252*b843c749SSergey Zigachev drm_mode_probed_add(connector, mode); 1253*b843c749SSergey Zigachev /* add the width/height from vbios tables if available */ 1254*b843c749SSergey Zigachev connector->display_info.width_mm = mode->width_mm; 1255*b843c749SSergey Zigachev connector->display_info.height_mm = mode->height_mm; 1256*b843c749SSergey Zigachev /* add scaled modes */ 1257*b843c749SSergey Zigachev amdgpu_connector_add_common_modes(encoder, connector); 1258*b843c749SSergey Zigachev } 1259*b843c749SSergey Zigachev } else { 1260*b843c749SSergey Zigachev /* need to setup ddc on the bridge */ 1261*b843c749SSergey Zigachev if (amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) != 1262*b843c749SSergey Zigachev ENCODER_OBJECT_ID_NONE) { 1263*b843c749SSergey Zigachev if (encoder) 1264*b843c749SSergey Zigachev amdgpu_atombios_encoder_setup_ext_encoder_ddc(encoder); 1265*b843c749SSergey Zigachev } 1266*b843c749SSergey Zigachev amdgpu_connector_get_edid(connector); 1267*b843c749SSergey Zigachev ret = amdgpu_connector_ddc_get_modes(connector); 1268*b843c749SSergey Zigachev 1269*b843c749SSergey Zigachev amdgpu_get_native_mode(connector); 1270*b843c749SSergey Zigachev } 1271*b843c749SSergey Zigachev 1272*b843c749SSergey Zigachev return ret; 1273*b843c749SSergey Zigachev } 1274*b843c749SSergey Zigachev 1275*b843c749SSergey Zigachev u16 amdgpu_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector) 1276*b843c749SSergey Zigachev { 1277*b843c749SSergey Zigachev struct drm_encoder *encoder; 1278*b843c749SSergey Zigachev struct amdgpu_encoder *amdgpu_encoder; 1279*b843c749SSergey Zigachev int i; 1280*b843c749SSergey Zigachev 1281*b843c749SSergey Zigachev drm_connector_for_each_possible_encoder(connector, encoder, i) { 1282*b843c749SSergey Zigachev amdgpu_encoder = to_amdgpu_encoder(encoder); 1283*b843c749SSergey Zigachev 1284*b843c749SSergey Zigachev switch (amdgpu_encoder->encoder_id) { 1285*b843c749SSergey Zigachev case ENCODER_OBJECT_ID_TRAVIS: 1286*b843c749SSergey Zigachev case ENCODER_OBJECT_ID_NUTMEG: 1287*b843c749SSergey Zigachev return amdgpu_encoder->encoder_id; 1288*b843c749SSergey Zigachev default: 1289*b843c749SSergey Zigachev break; 1290*b843c749SSergey Zigachev } 1291*b843c749SSergey Zigachev } 1292*b843c749SSergey Zigachev 1293*b843c749SSergey Zigachev return ENCODER_OBJECT_ID_NONE; 1294*b843c749SSergey Zigachev } 1295*b843c749SSergey Zigachev 1296*b843c749SSergey Zigachev static bool amdgpu_connector_encoder_is_hbr2(struct drm_connector *connector) 1297*b843c749SSergey Zigachev { 1298*b843c749SSergey Zigachev struct drm_encoder *encoder; 1299*b843c749SSergey Zigachev struct amdgpu_encoder *amdgpu_encoder; 1300*b843c749SSergey Zigachev int i; 1301*b843c749SSergey Zigachev bool found = false; 1302*b843c749SSergey Zigachev 1303*b843c749SSergey Zigachev drm_connector_for_each_possible_encoder(connector, encoder, i) { 1304*b843c749SSergey Zigachev amdgpu_encoder = to_amdgpu_encoder(encoder); 1305*b843c749SSergey Zigachev if (amdgpu_encoder->caps & ATOM_ENCODER_CAP_RECORD_HBR2) 1306*b843c749SSergey Zigachev found = true; 1307*b843c749SSergey Zigachev } 1308*b843c749SSergey Zigachev 1309*b843c749SSergey Zigachev return found; 1310*b843c749SSergey Zigachev } 1311*b843c749SSergey Zigachev 1312*b843c749SSergey Zigachev bool amdgpu_connector_is_dp12_capable(struct drm_connector *connector) 1313*b843c749SSergey Zigachev { 1314*b843c749SSergey Zigachev struct drm_device *dev = connector->dev; 1315*b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private; 1316*b843c749SSergey Zigachev 1317*b843c749SSergey Zigachev if ((adev->clock.default_dispclk >= 53900) && 1318*b843c749SSergey Zigachev amdgpu_connector_encoder_is_hbr2(connector)) { 1319*b843c749SSergey Zigachev return true; 1320*b843c749SSergey Zigachev } 1321*b843c749SSergey Zigachev 1322*b843c749SSergey Zigachev return false; 1323*b843c749SSergey Zigachev } 1324*b843c749SSergey Zigachev 1325*b843c749SSergey Zigachev static enum drm_connector_status 1326*b843c749SSergey Zigachev amdgpu_connector_dp_detect(struct drm_connector *connector, bool force) 1327*b843c749SSergey Zigachev { 1328*b843c749SSergey Zigachev struct drm_device *dev = connector->dev; 1329*b843c749SSergey Zigachev struct amdgpu_device *adev = dev->dev_private; 1330*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 1331*b843c749SSergey Zigachev enum drm_connector_status ret = connector_status_disconnected; 1332*b843c749SSergey Zigachev struct amdgpu_connector_atom_dig *amdgpu_dig_connector = amdgpu_connector->con_priv; 1333*b843c749SSergey Zigachev struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector); 1334*b843c749SSergey Zigachev int r; 1335*b843c749SSergey Zigachev 1336*b843c749SSergey Zigachev if (!drm_kms_helper_is_poll_worker()) { 1337*b843c749SSergey Zigachev r = pm_runtime_get_sync(connector->dev->dev); 1338*b843c749SSergey Zigachev if (r < 0) { 1339*b843c749SSergey Zigachev pm_runtime_put_autosuspend(connector->dev->dev); 1340*b843c749SSergey Zigachev return connector_status_disconnected; 1341*b843c749SSergey Zigachev } 1342*b843c749SSergey Zigachev } 1343*b843c749SSergey Zigachev 1344*b843c749SSergey Zigachev if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) { 1345*b843c749SSergey Zigachev ret = connector->status; 1346*b843c749SSergey Zigachev goto out; 1347*b843c749SSergey Zigachev } 1348*b843c749SSergey Zigachev 1349*b843c749SSergey Zigachev amdgpu_connector_free_edid(connector); 1350*b843c749SSergey Zigachev 1351*b843c749SSergey Zigachev if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) || 1352*b843c749SSergey Zigachev (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) { 1353*b843c749SSergey Zigachev if (encoder) { 1354*b843c749SSergey Zigachev struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); 1355*b843c749SSergey Zigachev struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode; 1356*b843c749SSergey Zigachev 1357*b843c749SSergey Zigachev /* check if panel is valid */ 1358*b843c749SSergey Zigachev if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240) 1359*b843c749SSergey Zigachev ret = connector_status_connected; 1360*b843c749SSergey Zigachev } 1361*b843c749SSergey Zigachev /* eDP is always DP */ 1362*b843c749SSergey Zigachev amdgpu_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT; 1363*b843c749SSergey Zigachev if (!amdgpu_dig_connector->edp_on) 1364*b843c749SSergey Zigachev amdgpu_atombios_encoder_set_edp_panel_power(connector, 1365*b843c749SSergey Zigachev ATOM_TRANSMITTER_ACTION_POWER_ON); 1366*b843c749SSergey Zigachev if (!amdgpu_atombios_dp_get_dpcd(amdgpu_connector)) 1367*b843c749SSergey Zigachev ret = connector_status_connected; 1368*b843c749SSergey Zigachev if (!amdgpu_dig_connector->edp_on) 1369*b843c749SSergey Zigachev amdgpu_atombios_encoder_set_edp_panel_power(connector, 1370*b843c749SSergey Zigachev ATOM_TRANSMITTER_ACTION_POWER_OFF); 1371*b843c749SSergey Zigachev } else if (amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) != 1372*b843c749SSergey Zigachev ENCODER_OBJECT_ID_NONE) { 1373*b843c749SSergey Zigachev /* DP bridges are always DP */ 1374*b843c749SSergey Zigachev amdgpu_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT; 1375*b843c749SSergey Zigachev /* get the DPCD from the bridge */ 1376*b843c749SSergey Zigachev amdgpu_atombios_dp_get_dpcd(amdgpu_connector); 1377*b843c749SSergey Zigachev 1378*b843c749SSergey Zigachev if (encoder) { 1379*b843c749SSergey Zigachev /* setup ddc on the bridge */ 1380*b843c749SSergey Zigachev amdgpu_atombios_encoder_setup_ext_encoder_ddc(encoder); 1381*b843c749SSergey Zigachev /* bridge chips are always aux */ 1382*b843c749SSergey Zigachev /* try DDC */ 1383*b843c749SSergey Zigachev if (amdgpu_display_ddc_probe(amdgpu_connector, true)) 1384*b843c749SSergey Zigachev ret = connector_status_connected; 1385*b843c749SSergey Zigachev else if (amdgpu_connector->dac_load_detect) { /* try load detection */ 1386*b843c749SSergey Zigachev const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; 1387*b843c749SSergey Zigachev ret = encoder_funcs->detect(encoder, connector); 1388*b843c749SSergey Zigachev } 1389*b843c749SSergey Zigachev } 1390*b843c749SSergey Zigachev } else { 1391*b843c749SSergey Zigachev amdgpu_dig_connector->dp_sink_type = 1392*b843c749SSergey Zigachev amdgpu_atombios_dp_get_sinktype(amdgpu_connector); 1393*b843c749SSergey Zigachev if (amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd)) { 1394*b843c749SSergey Zigachev ret = connector_status_connected; 1395*b843c749SSergey Zigachev if (amdgpu_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) 1396*b843c749SSergey Zigachev amdgpu_atombios_dp_get_dpcd(amdgpu_connector); 1397*b843c749SSergey Zigachev } else { 1398*b843c749SSergey Zigachev if (amdgpu_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { 1399*b843c749SSergey Zigachev if (!amdgpu_atombios_dp_get_dpcd(amdgpu_connector)) 1400*b843c749SSergey Zigachev ret = connector_status_connected; 1401*b843c749SSergey Zigachev } else { 1402*b843c749SSergey Zigachev /* try non-aux ddc (DP to DVI/HDMI/etc. adapter) */ 1403*b843c749SSergey Zigachev if (amdgpu_display_ddc_probe(amdgpu_connector, 1404*b843c749SSergey Zigachev false)) 1405*b843c749SSergey Zigachev ret = connector_status_connected; 1406*b843c749SSergey Zigachev } 1407*b843c749SSergey Zigachev } 1408*b843c749SSergey Zigachev } 1409*b843c749SSergey Zigachev 1410*b843c749SSergey Zigachev amdgpu_connector_update_scratch_regs(connector, ret); 1411*b843c749SSergey Zigachev out: 1412*b843c749SSergey Zigachev if (!drm_kms_helper_is_poll_worker()) { 1413*b843c749SSergey Zigachev pm_runtime_mark_last_busy(connector->dev->dev); 1414*b843c749SSergey Zigachev pm_runtime_put_autosuspend(connector->dev->dev); 1415*b843c749SSergey Zigachev } 1416*b843c749SSergey Zigachev 1417*b843c749SSergey Zigachev return ret; 1418*b843c749SSergey Zigachev } 1419*b843c749SSergey Zigachev 1420*b843c749SSergey Zigachev static enum drm_mode_status amdgpu_connector_dp_mode_valid(struct drm_connector *connector, 1421*b843c749SSergey Zigachev struct drm_display_mode *mode) 1422*b843c749SSergey Zigachev { 1423*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); 1424*b843c749SSergey Zigachev struct amdgpu_connector_atom_dig *amdgpu_dig_connector = amdgpu_connector->con_priv; 1425*b843c749SSergey Zigachev 1426*b843c749SSergey Zigachev /* XXX check mode bandwidth */ 1427*b843c749SSergey Zigachev 1428*b843c749SSergey Zigachev if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) || 1429*b843c749SSergey Zigachev (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) { 1430*b843c749SSergey Zigachev struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector); 1431*b843c749SSergey Zigachev 1432*b843c749SSergey Zigachev if ((mode->hdisplay < 320) || (mode->vdisplay < 240)) 1433*b843c749SSergey Zigachev return MODE_PANEL; 1434*b843c749SSergey Zigachev 1435*b843c749SSergey Zigachev if (encoder) { 1436*b843c749SSergey Zigachev struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); 1437*b843c749SSergey Zigachev struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode; 1438*b843c749SSergey Zigachev 1439*b843c749SSergey Zigachev /* AVIVO hardware supports downscaling modes larger than the panel 1440*b843c749SSergey Zigachev * to the panel size, but I'm not sure this is desirable. 1441*b843c749SSergey Zigachev */ 1442*b843c749SSergey Zigachev if ((mode->hdisplay > native_mode->hdisplay) || 1443*b843c749SSergey Zigachev (mode->vdisplay > native_mode->vdisplay)) 1444*b843c749SSergey Zigachev return MODE_PANEL; 1445*b843c749SSergey Zigachev 1446*b843c749SSergey Zigachev /* if scaling is disabled, block non-native modes */ 1447*b843c749SSergey Zigachev if (amdgpu_encoder->rmx_type == RMX_OFF) { 1448*b843c749SSergey Zigachev if ((mode->hdisplay != native_mode->hdisplay) || 1449*b843c749SSergey Zigachev (mode->vdisplay != native_mode->vdisplay)) 1450*b843c749SSergey Zigachev return MODE_PANEL; 1451*b843c749SSergey Zigachev } 1452*b843c749SSergey Zigachev } 1453*b843c749SSergey Zigachev return MODE_OK; 1454*b843c749SSergey Zigachev } else { 1455*b843c749SSergey Zigachev if ((amdgpu_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || 1456*b843c749SSergey Zigachev (amdgpu_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) { 1457*b843c749SSergey Zigachev return amdgpu_atombios_dp_mode_valid_helper(connector, mode); 1458*b843c749SSergey Zigachev } else { 1459*b843c749SSergey Zigachev if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) { 1460*b843c749SSergey Zigachev /* HDMI 1.3+ supports max clock of 340 Mhz */ 1461*b843c749SSergey Zigachev if (mode->clock > 340000) 1462*b843c749SSergey Zigachev return MODE_CLOCK_HIGH; 1463*b843c749SSergey Zigachev } else { 1464*b843c749SSergey Zigachev if (mode->clock > 165000) 1465*b843c749SSergey Zigachev return MODE_CLOCK_HIGH; 1466*b843c749SSergey Zigachev } 1467*b843c749SSergey Zigachev } 1468*b843c749SSergey Zigachev } 1469*b843c749SSergey Zigachev 1470*b843c749SSergey Zigachev return MODE_OK; 1471*b843c749SSergey Zigachev } 1472*b843c749SSergey Zigachev 1473*b843c749SSergey Zigachev static const struct drm_connector_helper_funcs amdgpu_connector_dp_helper_funcs = { 1474*b843c749SSergey Zigachev .get_modes = amdgpu_connector_dp_get_modes, 1475*b843c749SSergey Zigachev .mode_valid = amdgpu_connector_dp_mode_valid, 1476*b843c749SSergey Zigachev .best_encoder = amdgpu_connector_dvi_encoder, 1477*b843c749SSergey Zigachev }; 1478*b843c749SSergey Zigachev 1479*b843c749SSergey Zigachev static const struct drm_connector_funcs amdgpu_connector_dp_funcs = { 1480*b843c749SSergey Zigachev .dpms = drm_helper_connector_dpms, 1481*b843c749SSergey Zigachev .detect = amdgpu_connector_dp_detect, 1482*b843c749SSergey Zigachev .fill_modes = drm_helper_probe_single_connector_modes, 1483*b843c749SSergey Zigachev .set_property = amdgpu_connector_set_property, 1484*b843c749SSergey Zigachev .early_unregister = amdgpu_connector_unregister, 1485*b843c749SSergey Zigachev .destroy = amdgpu_connector_destroy, 1486*b843c749SSergey Zigachev .force = amdgpu_connector_dvi_force, 1487*b843c749SSergey Zigachev }; 1488*b843c749SSergey Zigachev 1489*b843c749SSergey Zigachev static const struct drm_connector_funcs amdgpu_connector_edp_funcs = { 1490*b843c749SSergey Zigachev .dpms = drm_helper_connector_dpms, 1491*b843c749SSergey Zigachev .detect = amdgpu_connector_dp_detect, 1492*b843c749SSergey Zigachev .fill_modes = drm_helper_probe_single_connector_modes, 1493*b843c749SSergey Zigachev .set_property = amdgpu_connector_set_lcd_property, 1494*b843c749SSergey Zigachev .early_unregister = amdgpu_connector_unregister, 1495*b843c749SSergey Zigachev .destroy = amdgpu_connector_destroy, 1496*b843c749SSergey Zigachev .force = amdgpu_connector_dvi_force, 1497*b843c749SSergey Zigachev }; 1498*b843c749SSergey Zigachev 1499*b843c749SSergey Zigachev void 1500*b843c749SSergey Zigachev amdgpu_connector_add(struct amdgpu_device *adev, 1501*b843c749SSergey Zigachev uint32_t connector_id, 1502*b843c749SSergey Zigachev uint32_t supported_device, 1503*b843c749SSergey Zigachev int connector_type, 1504*b843c749SSergey Zigachev struct amdgpu_i2c_bus_rec *i2c_bus, 1505*b843c749SSergey Zigachev uint16_t connector_object_id, 1506*b843c749SSergey Zigachev struct amdgpu_hpd *hpd, 1507*b843c749SSergey Zigachev struct amdgpu_router *router) 1508*b843c749SSergey Zigachev { 1509*b843c749SSergey Zigachev struct drm_device *dev = adev->ddev; 1510*b843c749SSergey Zigachev struct drm_connector *connector; 1511*b843c749SSergey Zigachev struct amdgpu_connector *amdgpu_connector; 1512*b843c749SSergey Zigachev struct amdgpu_connector_atom_dig *amdgpu_dig_connector; 1513*b843c749SSergey Zigachev struct drm_encoder *encoder; 1514*b843c749SSergey Zigachev struct amdgpu_encoder *amdgpu_encoder; 1515*b843c749SSergey Zigachev uint32_t subpixel_order = SubPixelNone; 1516*b843c749SSergey Zigachev bool shared_ddc = false; 1517*b843c749SSergey Zigachev bool is_dp_bridge = false; 1518*b843c749SSergey Zigachev bool has_aux = false; 1519*b843c749SSergey Zigachev 1520*b843c749SSergey Zigachev if (connector_type == DRM_MODE_CONNECTOR_Unknown) 1521*b843c749SSergey Zigachev return; 1522*b843c749SSergey Zigachev 1523*b843c749SSergey Zigachev /* see if we already added it */ 1524*b843c749SSergey Zigachev list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 1525*b843c749SSergey Zigachev amdgpu_connector = to_amdgpu_connector(connector); 1526*b843c749SSergey Zigachev if (amdgpu_connector->connector_id == connector_id) { 1527*b843c749SSergey Zigachev amdgpu_connector->devices |= supported_device; 1528*b843c749SSergey Zigachev return; 1529*b843c749SSergey Zigachev } 1530*b843c749SSergey Zigachev if (amdgpu_connector->ddc_bus && i2c_bus->valid) { 1531*b843c749SSergey Zigachev if (amdgpu_connector->ddc_bus->rec.i2c_id == i2c_bus->i2c_id) { 1532*b843c749SSergey Zigachev amdgpu_connector->shared_ddc = true; 1533*b843c749SSergey Zigachev shared_ddc = true; 1534*b843c749SSergey Zigachev } 1535*b843c749SSergey Zigachev if (amdgpu_connector->router_bus && router->ddc_valid && 1536*b843c749SSergey Zigachev (amdgpu_connector->router.router_id == router->router_id)) { 1537*b843c749SSergey Zigachev amdgpu_connector->shared_ddc = false; 1538*b843c749SSergey Zigachev shared_ddc = false; 1539*b843c749SSergey Zigachev } 1540*b843c749SSergey Zigachev } 1541*b843c749SSergey Zigachev } 1542*b843c749SSergey Zigachev 1543*b843c749SSergey Zigachev /* check if it's a dp bridge */ 1544*b843c749SSergey Zigachev list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 1545*b843c749SSergey Zigachev amdgpu_encoder = to_amdgpu_encoder(encoder); 1546*b843c749SSergey Zigachev if (amdgpu_encoder->devices & supported_device) { 1547*b843c749SSergey Zigachev switch (amdgpu_encoder->encoder_id) { 1548*b843c749SSergey Zigachev case ENCODER_OBJECT_ID_TRAVIS: 1549*b843c749SSergey Zigachev case ENCODER_OBJECT_ID_NUTMEG: 1550*b843c749SSergey Zigachev is_dp_bridge = true; 1551*b843c749SSergey Zigachev break; 1552*b843c749SSergey Zigachev default: 1553*b843c749SSergey Zigachev break; 1554*b843c749SSergey Zigachev } 1555*b843c749SSergey Zigachev } 1556*b843c749SSergey Zigachev } 1557*b843c749SSergey Zigachev 1558*b843c749SSergey Zigachev amdgpu_connector = kzalloc(sizeof(struct amdgpu_connector), GFP_KERNEL); 1559*b843c749SSergey Zigachev if (!amdgpu_connector) 1560*b843c749SSergey Zigachev return; 1561*b843c749SSergey Zigachev 1562*b843c749SSergey Zigachev connector = &amdgpu_connector->base; 1563*b843c749SSergey Zigachev 1564*b843c749SSergey Zigachev amdgpu_connector->connector_id = connector_id; 1565*b843c749SSergey Zigachev amdgpu_connector->devices = supported_device; 1566*b843c749SSergey Zigachev amdgpu_connector->shared_ddc = shared_ddc; 1567*b843c749SSergey Zigachev amdgpu_connector->connector_object_id = connector_object_id; 1568*b843c749SSergey Zigachev amdgpu_connector->hpd = *hpd; 1569*b843c749SSergey Zigachev 1570*b843c749SSergey Zigachev amdgpu_connector->router = *router; 1571*b843c749SSergey Zigachev if (router->ddc_valid || router->cd_valid) { 1572*b843c749SSergey Zigachev amdgpu_connector->router_bus = amdgpu_i2c_lookup(adev, &router->i2c_info); 1573*b843c749SSergey Zigachev if (!amdgpu_connector->router_bus) 1574*b843c749SSergey Zigachev DRM_ERROR("Failed to assign router i2c bus! Check dmesg for i2c errors.\n"); 1575*b843c749SSergey Zigachev } 1576*b843c749SSergey Zigachev 1577*b843c749SSergey Zigachev if (is_dp_bridge) { 1578*b843c749SSergey Zigachev amdgpu_dig_connector = kzalloc(sizeof(struct amdgpu_connector_atom_dig), GFP_KERNEL); 1579*b843c749SSergey Zigachev if (!amdgpu_dig_connector) 1580*b843c749SSergey Zigachev goto failed; 1581*b843c749SSergey Zigachev amdgpu_connector->con_priv = amdgpu_dig_connector; 1582*b843c749SSergey Zigachev if (i2c_bus->valid) { 1583*b843c749SSergey Zigachev amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus); 1584*b843c749SSergey Zigachev if (amdgpu_connector->ddc_bus) 1585*b843c749SSergey Zigachev has_aux = true; 1586*b843c749SSergey Zigachev else 1587*b843c749SSergey Zigachev DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 1588*b843c749SSergey Zigachev } 1589*b843c749SSergey Zigachev switch (connector_type) { 1590*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_VGA: 1591*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_DVIA: 1592*b843c749SSergey Zigachev default: 1593*b843c749SSergey Zigachev drm_connector_init(dev, &amdgpu_connector->base, 1594*b843c749SSergey Zigachev &amdgpu_connector_dp_funcs, connector_type); 1595*b843c749SSergey Zigachev drm_connector_helper_add(&amdgpu_connector->base, 1596*b843c749SSergey Zigachev &amdgpu_connector_dp_helper_funcs); 1597*b843c749SSergey Zigachev connector->interlace_allowed = true; 1598*b843c749SSergey Zigachev connector->doublescan_allowed = true; 1599*b843c749SSergey Zigachev amdgpu_connector->dac_load_detect = true; 1600*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1601*b843c749SSergey Zigachev adev->mode_info.load_detect_property, 1602*b843c749SSergey Zigachev 1); 1603*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1604*b843c749SSergey Zigachev dev->mode_config.scaling_mode_property, 1605*b843c749SSergey Zigachev DRM_MODE_SCALE_NONE); 1606*b843c749SSergey Zigachev break; 1607*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_DVII: 1608*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_DVID: 1609*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_HDMIA: 1610*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_HDMIB: 1611*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_DisplayPort: 1612*b843c749SSergey Zigachev drm_connector_init(dev, &amdgpu_connector->base, 1613*b843c749SSergey Zigachev &amdgpu_connector_dp_funcs, connector_type); 1614*b843c749SSergey Zigachev drm_connector_helper_add(&amdgpu_connector->base, 1615*b843c749SSergey Zigachev &amdgpu_connector_dp_helper_funcs); 1616*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1617*b843c749SSergey Zigachev adev->mode_info.underscan_property, 1618*b843c749SSergey Zigachev UNDERSCAN_OFF); 1619*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1620*b843c749SSergey Zigachev adev->mode_info.underscan_hborder_property, 1621*b843c749SSergey Zigachev 0); 1622*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1623*b843c749SSergey Zigachev adev->mode_info.underscan_vborder_property, 1624*b843c749SSergey Zigachev 0); 1625*b843c749SSergey Zigachev 1626*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1627*b843c749SSergey Zigachev dev->mode_config.scaling_mode_property, 1628*b843c749SSergey Zigachev DRM_MODE_SCALE_NONE); 1629*b843c749SSergey Zigachev 1630*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1631*b843c749SSergey Zigachev adev->mode_info.dither_property, 1632*b843c749SSergey Zigachev AMDGPU_FMT_DITHER_DISABLE); 1633*b843c749SSergey Zigachev 1634*b843c749SSergey Zigachev if (amdgpu_audio != 0) 1635*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1636*b843c749SSergey Zigachev adev->mode_info.audio_property, 1637*b843c749SSergey Zigachev AMDGPU_AUDIO_AUTO); 1638*b843c749SSergey Zigachev 1639*b843c749SSergey Zigachev subpixel_order = SubPixelHorizontalRGB; 1640*b843c749SSergey Zigachev connector->interlace_allowed = true; 1641*b843c749SSergey Zigachev if (connector_type == DRM_MODE_CONNECTOR_HDMIB) 1642*b843c749SSergey Zigachev connector->doublescan_allowed = true; 1643*b843c749SSergey Zigachev else 1644*b843c749SSergey Zigachev connector->doublescan_allowed = false; 1645*b843c749SSergey Zigachev if (connector_type == DRM_MODE_CONNECTOR_DVII) { 1646*b843c749SSergey Zigachev amdgpu_connector->dac_load_detect = true; 1647*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1648*b843c749SSergey Zigachev adev->mode_info.load_detect_property, 1649*b843c749SSergey Zigachev 1); 1650*b843c749SSergey Zigachev } 1651*b843c749SSergey Zigachev break; 1652*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_LVDS: 1653*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_eDP: 1654*b843c749SSergey Zigachev drm_connector_init(dev, &amdgpu_connector->base, 1655*b843c749SSergey Zigachev &amdgpu_connector_edp_funcs, connector_type); 1656*b843c749SSergey Zigachev drm_connector_helper_add(&amdgpu_connector->base, 1657*b843c749SSergey Zigachev &amdgpu_connector_dp_helper_funcs); 1658*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1659*b843c749SSergey Zigachev dev->mode_config.scaling_mode_property, 1660*b843c749SSergey Zigachev DRM_MODE_SCALE_FULLSCREEN); 1661*b843c749SSergey Zigachev subpixel_order = SubPixelHorizontalRGB; 1662*b843c749SSergey Zigachev connector->interlace_allowed = false; 1663*b843c749SSergey Zigachev connector->doublescan_allowed = false; 1664*b843c749SSergey Zigachev break; 1665*b843c749SSergey Zigachev } 1666*b843c749SSergey Zigachev } else { 1667*b843c749SSergey Zigachev switch (connector_type) { 1668*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_VGA: 1669*b843c749SSergey Zigachev drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_vga_funcs, connector_type); 1670*b843c749SSergey Zigachev drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_vga_helper_funcs); 1671*b843c749SSergey Zigachev if (i2c_bus->valid) { 1672*b843c749SSergey Zigachev amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus); 1673*b843c749SSergey Zigachev if (!amdgpu_connector->ddc_bus) 1674*b843c749SSergey Zigachev DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 1675*b843c749SSergey Zigachev } 1676*b843c749SSergey Zigachev amdgpu_connector->dac_load_detect = true; 1677*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1678*b843c749SSergey Zigachev adev->mode_info.load_detect_property, 1679*b843c749SSergey Zigachev 1); 1680*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1681*b843c749SSergey Zigachev dev->mode_config.scaling_mode_property, 1682*b843c749SSergey Zigachev DRM_MODE_SCALE_NONE); 1683*b843c749SSergey Zigachev /* no HPD on analog connectors */ 1684*b843c749SSergey Zigachev amdgpu_connector->hpd.hpd = AMDGPU_HPD_NONE; 1685*b843c749SSergey Zigachev connector->interlace_allowed = true; 1686*b843c749SSergey Zigachev connector->doublescan_allowed = true; 1687*b843c749SSergey Zigachev break; 1688*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_DVIA: 1689*b843c749SSergey Zigachev drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_vga_funcs, connector_type); 1690*b843c749SSergey Zigachev drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_vga_helper_funcs); 1691*b843c749SSergey Zigachev if (i2c_bus->valid) { 1692*b843c749SSergey Zigachev amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus); 1693*b843c749SSergey Zigachev if (!amdgpu_connector->ddc_bus) 1694*b843c749SSergey Zigachev DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 1695*b843c749SSergey Zigachev } 1696*b843c749SSergey Zigachev amdgpu_connector->dac_load_detect = true; 1697*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1698*b843c749SSergey Zigachev adev->mode_info.load_detect_property, 1699*b843c749SSergey Zigachev 1); 1700*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1701*b843c749SSergey Zigachev dev->mode_config.scaling_mode_property, 1702*b843c749SSergey Zigachev DRM_MODE_SCALE_NONE); 1703*b843c749SSergey Zigachev /* no HPD on analog connectors */ 1704*b843c749SSergey Zigachev amdgpu_connector->hpd.hpd = AMDGPU_HPD_NONE; 1705*b843c749SSergey Zigachev connector->interlace_allowed = true; 1706*b843c749SSergey Zigachev connector->doublescan_allowed = true; 1707*b843c749SSergey Zigachev break; 1708*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_DVII: 1709*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_DVID: 1710*b843c749SSergey Zigachev amdgpu_dig_connector = kzalloc(sizeof(struct amdgpu_connector_atom_dig), GFP_KERNEL); 1711*b843c749SSergey Zigachev if (!amdgpu_dig_connector) 1712*b843c749SSergey Zigachev goto failed; 1713*b843c749SSergey Zigachev amdgpu_connector->con_priv = amdgpu_dig_connector; 1714*b843c749SSergey Zigachev drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_dvi_funcs, connector_type); 1715*b843c749SSergey Zigachev drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_dvi_helper_funcs); 1716*b843c749SSergey Zigachev if (i2c_bus->valid) { 1717*b843c749SSergey Zigachev amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus); 1718*b843c749SSergey Zigachev if (!amdgpu_connector->ddc_bus) 1719*b843c749SSergey Zigachev DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 1720*b843c749SSergey Zigachev } 1721*b843c749SSergey Zigachev subpixel_order = SubPixelHorizontalRGB; 1722*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1723*b843c749SSergey Zigachev adev->mode_info.coherent_mode_property, 1724*b843c749SSergey Zigachev 1); 1725*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1726*b843c749SSergey Zigachev adev->mode_info.underscan_property, 1727*b843c749SSergey Zigachev UNDERSCAN_OFF); 1728*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1729*b843c749SSergey Zigachev adev->mode_info.underscan_hborder_property, 1730*b843c749SSergey Zigachev 0); 1731*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1732*b843c749SSergey Zigachev adev->mode_info.underscan_vborder_property, 1733*b843c749SSergey Zigachev 0); 1734*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1735*b843c749SSergey Zigachev dev->mode_config.scaling_mode_property, 1736*b843c749SSergey Zigachev DRM_MODE_SCALE_NONE); 1737*b843c749SSergey Zigachev 1738*b843c749SSergey Zigachev if (amdgpu_audio != 0) { 1739*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1740*b843c749SSergey Zigachev adev->mode_info.audio_property, 1741*b843c749SSergey Zigachev AMDGPU_AUDIO_AUTO); 1742*b843c749SSergey Zigachev } 1743*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1744*b843c749SSergey Zigachev adev->mode_info.dither_property, 1745*b843c749SSergey Zigachev AMDGPU_FMT_DITHER_DISABLE); 1746*b843c749SSergey Zigachev if (connector_type == DRM_MODE_CONNECTOR_DVII) { 1747*b843c749SSergey Zigachev amdgpu_connector->dac_load_detect = true; 1748*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1749*b843c749SSergey Zigachev adev->mode_info.load_detect_property, 1750*b843c749SSergey Zigachev 1); 1751*b843c749SSergey Zigachev } 1752*b843c749SSergey Zigachev connector->interlace_allowed = true; 1753*b843c749SSergey Zigachev if (connector_type == DRM_MODE_CONNECTOR_DVII) 1754*b843c749SSergey Zigachev connector->doublescan_allowed = true; 1755*b843c749SSergey Zigachev else 1756*b843c749SSergey Zigachev connector->doublescan_allowed = false; 1757*b843c749SSergey Zigachev break; 1758*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_HDMIA: 1759*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_HDMIB: 1760*b843c749SSergey Zigachev amdgpu_dig_connector = kzalloc(sizeof(struct amdgpu_connector_atom_dig), GFP_KERNEL); 1761*b843c749SSergey Zigachev if (!amdgpu_dig_connector) 1762*b843c749SSergey Zigachev goto failed; 1763*b843c749SSergey Zigachev amdgpu_connector->con_priv = amdgpu_dig_connector; 1764*b843c749SSergey Zigachev drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_dvi_funcs, connector_type); 1765*b843c749SSergey Zigachev drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_dvi_helper_funcs); 1766*b843c749SSergey Zigachev if (i2c_bus->valid) { 1767*b843c749SSergey Zigachev amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus); 1768*b843c749SSergey Zigachev if (!amdgpu_connector->ddc_bus) 1769*b843c749SSergey Zigachev DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 1770*b843c749SSergey Zigachev } 1771*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1772*b843c749SSergey Zigachev adev->mode_info.coherent_mode_property, 1773*b843c749SSergey Zigachev 1); 1774*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1775*b843c749SSergey Zigachev adev->mode_info.underscan_property, 1776*b843c749SSergey Zigachev UNDERSCAN_OFF); 1777*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1778*b843c749SSergey Zigachev adev->mode_info.underscan_hborder_property, 1779*b843c749SSergey Zigachev 0); 1780*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1781*b843c749SSergey Zigachev adev->mode_info.underscan_vborder_property, 1782*b843c749SSergey Zigachev 0); 1783*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1784*b843c749SSergey Zigachev dev->mode_config.scaling_mode_property, 1785*b843c749SSergey Zigachev DRM_MODE_SCALE_NONE); 1786*b843c749SSergey Zigachev if (amdgpu_audio != 0) { 1787*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1788*b843c749SSergey Zigachev adev->mode_info.audio_property, 1789*b843c749SSergey Zigachev AMDGPU_AUDIO_AUTO); 1790*b843c749SSergey Zigachev } 1791*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1792*b843c749SSergey Zigachev adev->mode_info.dither_property, 1793*b843c749SSergey Zigachev AMDGPU_FMT_DITHER_DISABLE); 1794*b843c749SSergey Zigachev subpixel_order = SubPixelHorizontalRGB; 1795*b843c749SSergey Zigachev connector->interlace_allowed = true; 1796*b843c749SSergey Zigachev if (connector_type == DRM_MODE_CONNECTOR_HDMIB) 1797*b843c749SSergey Zigachev connector->doublescan_allowed = true; 1798*b843c749SSergey Zigachev else 1799*b843c749SSergey Zigachev connector->doublescan_allowed = false; 1800*b843c749SSergey Zigachev break; 1801*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_DisplayPort: 1802*b843c749SSergey Zigachev amdgpu_dig_connector = kzalloc(sizeof(struct amdgpu_connector_atom_dig), GFP_KERNEL); 1803*b843c749SSergey Zigachev if (!amdgpu_dig_connector) 1804*b843c749SSergey Zigachev goto failed; 1805*b843c749SSergey Zigachev amdgpu_connector->con_priv = amdgpu_dig_connector; 1806*b843c749SSergey Zigachev drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_dp_funcs, connector_type); 1807*b843c749SSergey Zigachev drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_dp_helper_funcs); 1808*b843c749SSergey Zigachev if (i2c_bus->valid) { 1809*b843c749SSergey Zigachev amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus); 1810*b843c749SSergey Zigachev if (amdgpu_connector->ddc_bus) 1811*b843c749SSergey Zigachev has_aux = true; 1812*b843c749SSergey Zigachev else 1813*b843c749SSergey Zigachev DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 1814*b843c749SSergey Zigachev } 1815*b843c749SSergey Zigachev subpixel_order = SubPixelHorizontalRGB; 1816*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1817*b843c749SSergey Zigachev adev->mode_info.coherent_mode_property, 1818*b843c749SSergey Zigachev 1); 1819*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1820*b843c749SSergey Zigachev adev->mode_info.underscan_property, 1821*b843c749SSergey Zigachev UNDERSCAN_OFF); 1822*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1823*b843c749SSergey Zigachev adev->mode_info.underscan_hborder_property, 1824*b843c749SSergey Zigachev 0); 1825*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1826*b843c749SSergey Zigachev adev->mode_info.underscan_vborder_property, 1827*b843c749SSergey Zigachev 0); 1828*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1829*b843c749SSergey Zigachev dev->mode_config.scaling_mode_property, 1830*b843c749SSergey Zigachev DRM_MODE_SCALE_NONE); 1831*b843c749SSergey Zigachev if (amdgpu_audio != 0) { 1832*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1833*b843c749SSergey Zigachev adev->mode_info.audio_property, 1834*b843c749SSergey Zigachev AMDGPU_AUDIO_AUTO); 1835*b843c749SSergey Zigachev } 1836*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1837*b843c749SSergey Zigachev adev->mode_info.dither_property, 1838*b843c749SSergey Zigachev AMDGPU_FMT_DITHER_DISABLE); 1839*b843c749SSergey Zigachev connector->interlace_allowed = true; 1840*b843c749SSergey Zigachev /* in theory with a DP to VGA converter... */ 1841*b843c749SSergey Zigachev connector->doublescan_allowed = false; 1842*b843c749SSergey Zigachev break; 1843*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_eDP: 1844*b843c749SSergey Zigachev amdgpu_dig_connector = kzalloc(sizeof(struct amdgpu_connector_atom_dig), GFP_KERNEL); 1845*b843c749SSergey Zigachev if (!amdgpu_dig_connector) 1846*b843c749SSergey Zigachev goto failed; 1847*b843c749SSergey Zigachev amdgpu_connector->con_priv = amdgpu_dig_connector; 1848*b843c749SSergey Zigachev drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_edp_funcs, connector_type); 1849*b843c749SSergey Zigachev drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_dp_helper_funcs); 1850*b843c749SSergey Zigachev if (i2c_bus->valid) { 1851*b843c749SSergey Zigachev amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus); 1852*b843c749SSergey Zigachev if (amdgpu_connector->ddc_bus) 1853*b843c749SSergey Zigachev has_aux = true; 1854*b843c749SSergey Zigachev else 1855*b843c749SSergey Zigachev DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 1856*b843c749SSergey Zigachev } 1857*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1858*b843c749SSergey Zigachev dev->mode_config.scaling_mode_property, 1859*b843c749SSergey Zigachev DRM_MODE_SCALE_FULLSCREEN); 1860*b843c749SSergey Zigachev subpixel_order = SubPixelHorizontalRGB; 1861*b843c749SSergey Zigachev connector->interlace_allowed = false; 1862*b843c749SSergey Zigachev connector->doublescan_allowed = false; 1863*b843c749SSergey Zigachev break; 1864*b843c749SSergey Zigachev case DRM_MODE_CONNECTOR_LVDS: 1865*b843c749SSergey Zigachev amdgpu_dig_connector = kzalloc(sizeof(struct amdgpu_connector_atom_dig), GFP_KERNEL); 1866*b843c749SSergey Zigachev if (!amdgpu_dig_connector) 1867*b843c749SSergey Zigachev goto failed; 1868*b843c749SSergey Zigachev amdgpu_connector->con_priv = amdgpu_dig_connector; 1869*b843c749SSergey Zigachev drm_connector_init(dev, &amdgpu_connector->base, &amdgpu_connector_lvds_funcs, connector_type); 1870*b843c749SSergey Zigachev drm_connector_helper_add(&amdgpu_connector->base, &amdgpu_connector_lvds_helper_funcs); 1871*b843c749SSergey Zigachev if (i2c_bus->valid) { 1872*b843c749SSergey Zigachev amdgpu_connector->ddc_bus = amdgpu_i2c_lookup(adev, i2c_bus); 1873*b843c749SSergey Zigachev if (!amdgpu_connector->ddc_bus) 1874*b843c749SSergey Zigachev DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); 1875*b843c749SSergey Zigachev } 1876*b843c749SSergey Zigachev drm_object_attach_property(&amdgpu_connector->base.base, 1877*b843c749SSergey Zigachev dev->mode_config.scaling_mode_property, 1878*b843c749SSergey Zigachev DRM_MODE_SCALE_FULLSCREEN); 1879*b843c749SSergey Zigachev subpixel_order = SubPixelHorizontalRGB; 1880*b843c749SSergey Zigachev connector->interlace_allowed = false; 1881*b843c749SSergey Zigachev connector->doublescan_allowed = false; 1882*b843c749SSergey Zigachev break; 1883*b843c749SSergey Zigachev } 1884*b843c749SSergey Zigachev } 1885*b843c749SSergey Zigachev 1886*b843c749SSergey Zigachev if (amdgpu_connector->hpd.hpd == AMDGPU_HPD_NONE) { 1887*b843c749SSergey Zigachev if (i2c_bus->valid) { 1888*b843c749SSergey Zigachev connector->polled = DRM_CONNECTOR_POLL_CONNECT | 1889*b843c749SSergey Zigachev DRM_CONNECTOR_POLL_DISCONNECT; 1890*b843c749SSergey Zigachev } 1891*b843c749SSergey Zigachev } else 1892*b843c749SSergey Zigachev connector->polled = DRM_CONNECTOR_POLL_HPD; 1893*b843c749SSergey Zigachev 1894*b843c749SSergey Zigachev connector->display_info.subpixel_order = subpixel_order; 1895*b843c749SSergey Zigachev drm_connector_register(connector); 1896*b843c749SSergey Zigachev 1897*b843c749SSergey Zigachev if (has_aux) 1898*b843c749SSergey Zigachev amdgpu_atombios_dp_aux_init(amdgpu_connector); 1899*b843c749SSergey Zigachev 1900*b843c749SSergey Zigachev return; 1901*b843c749SSergey Zigachev 1902*b843c749SSergey Zigachev failed: 1903*b843c749SSergey Zigachev drm_connector_cleanup(connector); 1904*b843c749SSergey Zigachev kfree(connector); 1905*b843c749SSergey Zigachev } 1906