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