263 lines · c
1/*2 * Copyright 2007-8 Advanced Micro Devices, Inc.3 * Copyright 2008 Red Hat Inc.4 *5 * Permission is hereby granted, free of charge, to any person obtaining a6 * copy of this software and associated documentation files (the "Software"),7 * to deal in the Software without restriction, including without limitation8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,9 * and/or sell copies of the Software, and to permit persons to whom the10 * Software is furnished to do so, subject to the following conditions:11 *12 * The above copyright notice and this permission notice shall be included in13 * all copies or substantial portions of the Software.14 *15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR21 * OTHER DEALINGS IN THE SOFTWARE.22 *23 * Authors: Dave Airlie24 * Alex Deucher25 */26 27#include <drm/amdgpu_drm.h>28#include "amdgpu.h"29#include "amdgpu_connectors.h"30#include "amdgpu_display.h"31#include "atom.h"32#include "atombios_encoders.h"33 34void35amdgpu_link_encoder_connector(struct drm_device *dev)36{37 struct amdgpu_device *adev = drm_to_adev(dev);38 struct drm_connector *connector;39 struct drm_connector_list_iter iter;40 struct amdgpu_connector *amdgpu_connector;41 struct drm_encoder *encoder;42 struct amdgpu_encoder *amdgpu_encoder;43 44 drm_connector_list_iter_begin(dev, &iter);45 /* walk the list and link encoders to connectors */46 drm_for_each_connector_iter(connector, &iter) {47 amdgpu_connector = to_amdgpu_connector(connector);48 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {49 amdgpu_encoder = to_amdgpu_encoder(encoder);50 if (amdgpu_encoder->devices & amdgpu_connector->devices) {51 drm_connector_attach_encoder(connector, encoder);52 if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {53 amdgpu_atombios_encoder_init_backlight(amdgpu_encoder, connector);54 adev->mode_info.bl_encoder = amdgpu_encoder;55 }56 }57 }58 }59 drm_connector_list_iter_end(&iter);60}61 62void amdgpu_encoder_set_active_device(struct drm_encoder *encoder)63{64 struct drm_device *dev = encoder->dev;65 struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);66 struct drm_connector *connector;67 struct drm_connector_list_iter iter;68 69 drm_connector_list_iter_begin(dev, &iter);70 drm_for_each_connector_iter(connector, &iter) {71 if (connector->encoder == encoder) {72 struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);73 74 amdgpu_encoder->active_device = amdgpu_encoder->devices & amdgpu_connector->devices;75 DRM_DEBUG_KMS("setting active device to %08x from %08x %08x for encoder %d\n",76 amdgpu_encoder->active_device, amdgpu_encoder->devices,77 amdgpu_connector->devices, encoder->encoder_type);78 }79 }80 drm_connector_list_iter_end(&iter);81}82 83struct drm_connector *84amdgpu_get_connector_for_encoder(struct drm_encoder *encoder)85{86 struct drm_device *dev = encoder->dev;87 struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);88 struct drm_connector *connector, *found = NULL;89 struct drm_connector_list_iter iter;90 struct amdgpu_connector *amdgpu_connector;91 92 drm_connector_list_iter_begin(dev, &iter);93 drm_for_each_connector_iter(connector, &iter) {94 amdgpu_connector = to_amdgpu_connector(connector);95 if (amdgpu_encoder->active_device & amdgpu_connector->devices) {96 found = connector;97 break;98 }99 }100 drm_connector_list_iter_end(&iter);101 return found;102}103 104struct drm_connector *105amdgpu_get_connector_for_encoder_init(struct drm_encoder *encoder)106{107 struct drm_device *dev = encoder->dev;108 struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);109 struct drm_connector *connector, *found = NULL;110 struct drm_connector_list_iter iter;111 struct amdgpu_connector *amdgpu_connector;112 113 drm_connector_list_iter_begin(dev, &iter);114 drm_for_each_connector_iter(connector, &iter) {115 amdgpu_connector = to_amdgpu_connector(connector);116 if (amdgpu_encoder->devices & amdgpu_connector->devices) {117 found = connector;118 break;119 }120 }121 drm_connector_list_iter_end(&iter);122 return found;123}124 125struct drm_encoder *amdgpu_get_external_encoder(struct drm_encoder *encoder)126{127 struct drm_device *dev = encoder->dev;128 struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);129 struct drm_encoder *other_encoder;130 struct amdgpu_encoder *other_amdgpu_encoder;131 132 if (amdgpu_encoder->is_ext_encoder)133 return NULL;134 135 list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) {136 if (other_encoder == encoder)137 continue;138 other_amdgpu_encoder = to_amdgpu_encoder(other_encoder);139 if (other_amdgpu_encoder->is_ext_encoder &&140 (amdgpu_encoder->devices & other_amdgpu_encoder->devices))141 return other_encoder;142 }143 return NULL;144}145 146u16 amdgpu_encoder_get_dp_bridge_encoder_id(struct drm_encoder *encoder)147{148 struct drm_encoder *other_encoder = amdgpu_get_external_encoder(encoder);149 150 if (other_encoder) {151 struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(other_encoder);152 153 switch (amdgpu_encoder->encoder_id) {154 case ENCODER_OBJECT_ID_TRAVIS:155 case ENCODER_OBJECT_ID_NUTMEG:156 return amdgpu_encoder->encoder_id;157 default:158 return ENCODER_OBJECT_ID_NONE;159 }160 }161 return ENCODER_OBJECT_ID_NONE;162}163 164void amdgpu_panel_mode_fixup(struct drm_encoder *encoder,165 struct drm_display_mode *adjusted_mode)166{167 struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);168 struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;169 unsigned int hblank = native_mode->htotal - native_mode->hdisplay;170 unsigned int vblank = native_mode->vtotal - native_mode->vdisplay;171 unsigned int hover = native_mode->hsync_start - native_mode->hdisplay;172 unsigned int vover = native_mode->vsync_start - native_mode->vdisplay;173 unsigned int hsync_width = native_mode->hsync_end - native_mode->hsync_start;174 unsigned int vsync_width = native_mode->vsync_end - native_mode->vsync_start;175 176 adjusted_mode->clock = native_mode->clock;177 adjusted_mode->flags = native_mode->flags;178 179 adjusted_mode->hdisplay = native_mode->hdisplay;180 adjusted_mode->vdisplay = native_mode->vdisplay;181 182 adjusted_mode->htotal = native_mode->hdisplay + hblank;183 adjusted_mode->hsync_start = native_mode->hdisplay + hover;184 adjusted_mode->hsync_end = adjusted_mode->hsync_start + hsync_width;185 186 adjusted_mode->vtotal = native_mode->vdisplay + vblank;187 adjusted_mode->vsync_start = native_mode->vdisplay + vover;188 adjusted_mode->vsync_end = adjusted_mode->vsync_start + vsync_width;189 190 drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);191 192 adjusted_mode->crtc_hdisplay = native_mode->hdisplay;193 adjusted_mode->crtc_vdisplay = native_mode->vdisplay;194 195 adjusted_mode->crtc_htotal = adjusted_mode->crtc_hdisplay + hblank;196 adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hdisplay + hover;197 adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + hsync_width;198 199 adjusted_mode->crtc_vtotal = adjusted_mode->crtc_vdisplay + vblank;200 adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + vover;201 adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + vsync_width;202 203}204 205bool amdgpu_dig_monitor_is_duallink(struct drm_encoder *encoder,206 u32 pixel_clock)207{208 struct drm_connector *connector;209 struct amdgpu_connector *amdgpu_connector;210 struct amdgpu_connector_atom_dig *dig_connector;211 212 connector = amdgpu_get_connector_for_encoder(encoder);213 /* if we don't have an active device yet, just use one of214 * the connectors tied to the encoder.215 */216 if (!connector)217 connector = amdgpu_get_connector_for_encoder_init(encoder);218 amdgpu_connector = to_amdgpu_connector(connector);219 220 switch (connector->connector_type) {221 case DRM_MODE_CONNECTOR_DVII:222 case DRM_MODE_CONNECTOR_HDMIB:223 if (amdgpu_connector->use_digital) {224 /* HDMI 1.3 supports up to 340 Mhz over single link */225 if (connector->display_info.is_hdmi) {226 if (pixel_clock > 340000)227 return true;228 else229 return false;230 } else {231 if (pixel_clock > 165000)232 return true;233 else234 return false;235 }236 } else237 return false;238 case DRM_MODE_CONNECTOR_DVID:239 case DRM_MODE_CONNECTOR_HDMIA:240 case DRM_MODE_CONNECTOR_DisplayPort:241 dig_connector = amdgpu_connector->con_priv;242 if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||243 (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))244 return false;245 else {246 /* HDMI 1.3 supports up to 340 Mhz over single link */247 if (connector->display_info.is_hdmi) {248 if (pixel_clock > 340000)249 return true;250 else251 return false;252 } else {253 if (pixel_clock > 165000)254 return true;255 else256 return false;257 }258 }259 default:260 return false;261 }262}263