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