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