atombios_output.c revision 2f39173d
1209ff23fSmrg/*
2209ff23fSmrg * Copyright © 2007 Red Hat, Inc.
3209ff23fSmrg * Copyright 2007  Advanced Micro Devices, Inc.
4209ff23fSmrg *
5209ff23fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
6209ff23fSmrg * copy of this software and associated documentation files (the "Software"),
7209ff23fSmrg * to deal in the Software without restriction, including without limitation
8209ff23fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9209ff23fSmrg * and/or sell copies of the Software, and to permit persons to whom the
10209ff23fSmrg * Software is furnished to do so, subject to the following conditions:
11209ff23fSmrg *
12209ff23fSmrg * The above copyright notice and this permission notice (including the next
13209ff23fSmrg * paragraph) shall be included in all copies or substantial portions of the
14209ff23fSmrg * Software.
15209ff23fSmrg *
16209ff23fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17209ff23fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18209ff23fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19209ff23fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20209ff23fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21209ff23fSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22209ff23fSmrg * SOFTWARE.
23209ff23fSmrg *
24209ff23fSmrg * Authors:
25209ff23fSmrg *    Dave Airlie <airlied@redhat.com>
26209ff23fSmrg *    Alex Deucher <alexdeucher@gmail.com>
27209ff23fSmrg *
28209ff23fSmrg */
29209ff23fSmrg
30209ff23fSmrg/*
31209ff23fSmrg * avivo output handling functions.
32209ff23fSmrg */
33209ff23fSmrg#ifdef HAVE_CONFIG_H
34209ff23fSmrg#include "config.h"
35209ff23fSmrg#endif
36209ff23fSmrg/* DPMS */
37c503f109Smrg#ifdef HAVE_XEXTPROTO_71
38c503f109Smrg#include <X11/extensions/dpmsconst.h>
39c503f109Smrg#else
40209ff23fSmrg#define DPMS_SERVER
41209ff23fSmrg#include <X11/extensions/dpms.h>
42c503f109Smrg#endif
43c503f109Smrg
44209ff23fSmrg#include <unistd.h>
45209ff23fSmrg
46209ff23fSmrg#include "radeon.h"
47209ff23fSmrg#include "radeon_reg.h"
48209ff23fSmrg#include "radeon_macros.h"
49209ff23fSmrg#include "radeon_atombios.h"
50209ff23fSmrg
51b7e1c893Smrg#include "ati_pciids_gen.h"
52b7e1c893Smrg
53b7e1c893Smrgconst char *device_name[12] = {
54b7e1c893Smrg    "CRT1",
55b7e1c893Smrg    "LCD1",
56b7e1c893Smrg    "TV1",
57b7e1c893Smrg    "DFP1",
58b7e1c893Smrg    "CRT2",
59b7e1c893Smrg    "LCD2",
60b7e1c893Smrg    "TV2",
61b7e1c893Smrg    "DFP2",
62b7e1c893Smrg    "CV",
63b7e1c893Smrg    "DFP3",
64b7e1c893Smrg    "DFP4",
65b7e1c893Smrg    "DFP5",
66b7e1c893Smrg};
67b7e1c893Smrg
68ad43ddacSmrgstatic void do_displayport_link_train(xf86OutputPtr output);
69ad43ddacSmrg
70c503f109Smrgstatic void atombios_set_output_crtc_source(xf86OutputPtr output);
71c503f109Smrg
72209ff23fSmrgstatic int
73b7e1c893Smrgatombios_output_dac_setup(xf86OutputPtr output, int action)
74209ff23fSmrg{
75209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
76209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
77b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
78b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
79209ff23fSmrg    DAC_ENCODER_CONTROL_PS_ALLOCATION disp_data;
80209ff23fSmrg    AtomBiosArgRec data;
81209ff23fSmrg    unsigned char *space;
82b7e1c893Smrg    int index = 0, num = 0;
83b7e1c893Smrg    int clock = radeon_output->pixel_clock;
84b7e1c893Smrg
85b7e1c893Smrg    if (radeon_encoder == NULL)
86b7e1c893Smrg	return ATOM_NOT_IMPLEMENTED;
87b7e1c893Smrg
88b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
89b7e1c893Smrg
90b7e1c893Smrg    switch (radeon_encoder->encoder_id) {
91b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
92b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
93b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl);
94b7e1c893Smrg	num = 1;
95b7e1c893Smrg	break;
96b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
97b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
98b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl);
99b7e1c893Smrg	num = 2;
100b7e1c893Smrg	break;
101b7e1c893Smrg    }
102209ff23fSmrg
103b7e1c893Smrg    disp_data.ucAction =action;
104209ff23fSmrg
105b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_CRT_SUPPORT))
106209ff23fSmrg	disp_data.ucDacStandard = ATOM_DAC1_PS2;
107b7e1c893Smrg    else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
108209ff23fSmrg	disp_data.ucDacStandard = ATOM_DAC1_CV;
109b7e1c893Smrg    else {
110b7e1c893Smrg	switch (tvout->tvStd) {
111209ff23fSmrg	case TV_STD_PAL:
112209ff23fSmrg	case TV_STD_PAL_M:
113209ff23fSmrg	case TV_STD_SCART_PAL:
114209ff23fSmrg	case TV_STD_SECAM:
115209ff23fSmrg	case TV_STD_PAL_CN:
116209ff23fSmrg	    disp_data.ucDacStandard = ATOM_DAC1_PAL;
117209ff23fSmrg	    break;
118209ff23fSmrg	case TV_STD_NTSC:
119209ff23fSmrg	case TV_STD_NTSC_J:
120209ff23fSmrg	case TV_STD_PAL_60:
121209ff23fSmrg	default:
122b7e1c893Smrg	    disp_data.ucDacStandard = ATOM_DAC1_NTSC;
123209ff23fSmrg	    break;
124209ff23fSmrg	}
125209ff23fSmrg    }
126b7e1c893Smrg    disp_data.usPixelClock = cpu_to_le16(clock / 10);
127209ff23fSmrg
128b7e1c893Smrg    data.exec.index = index;
129209ff23fSmrg    data.exec.dataSpace = (void *)&space;
130209ff23fSmrg    data.exec.pspace = &disp_data;
131209ff23fSmrg
132209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
133b7e1c893Smrg	ErrorF("Output DAC%d setup success\n", num);
134209ff23fSmrg	return ATOM_SUCCESS;
135209ff23fSmrg    }
136209ff23fSmrg
137b7e1c893Smrg    ErrorF("Output DAC%d setup failed\n", num);
138209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
139209ff23fSmrg
140209ff23fSmrg}
141209ff23fSmrg
142209ff23fSmrgstatic int
143b7e1c893Smrgatombios_output_tv_setup(xf86OutputPtr output, int action)
144209ff23fSmrg{
145209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
146b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
147209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
148209ff23fSmrg    TV_ENCODER_CONTROL_PS_ALLOCATION disp_data;
149209ff23fSmrg    AtomBiosArgRec data;
150209ff23fSmrg    unsigned char *space;
151b7e1c893Smrg    int clock = radeon_output->pixel_clock;
152b7e1c893Smrg
153b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
154209ff23fSmrg
155b7e1c893Smrg    disp_data.sTVEncoder.ucAction = action;
156209ff23fSmrg
157b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
158209ff23fSmrg	disp_data.sTVEncoder.ucTvStandard = ATOM_TV_CV;
159209ff23fSmrg    else {
160b7e1c893Smrg	switch (tvout->tvStd) {
161209ff23fSmrg	case TV_STD_NTSC:
162209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSC;
163209ff23fSmrg	    break;
164209ff23fSmrg	case TV_STD_PAL:
165209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL;
166209ff23fSmrg	    break;
167209ff23fSmrg	case TV_STD_PAL_M:
168209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PALM;
169209ff23fSmrg	    break;
170209ff23fSmrg	case TV_STD_PAL_60:
171209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL60;
172209ff23fSmrg	    break;
173209ff23fSmrg	case TV_STD_NTSC_J:
174209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSCJ;
175209ff23fSmrg	    break;
176209ff23fSmrg	case TV_STD_SCART_PAL:
177209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL; /* ??? */
178209ff23fSmrg	    break;
179209ff23fSmrg	case TV_STD_SECAM:
180209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_SECAM;
181209ff23fSmrg	    break;
182209ff23fSmrg	case TV_STD_PAL_CN:
183209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PALCN;
184209ff23fSmrg	    break;
185209ff23fSmrg	default:
186209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSC;
187209ff23fSmrg	    break;
188209ff23fSmrg	}
189209ff23fSmrg    }
190209ff23fSmrg
191b7e1c893Smrg    disp_data.sTVEncoder.usPixelClock = cpu_to_le16(clock / 10);
192209ff23fSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl);
193209ff23fSmrg    data.exec.dataSpace = (void *)&space;
194209ff23fSmrg    data.exec.pspace = &disp_data;
195209ff23fSmrg
196209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
197b7e1c893Smrg	ErrorF("Output TV setup success\n");
198209ff23fSmrg	return ATOM_SUCCESS;
199209ff23fSmrg    }
200209ff23fSmrg
201b7e1c893Smrg    ErrorF("Output TV setup failed\n");
202209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
203209ff23fSmrg
204209ff23fSmrg}
205209ff23fSmrg
206209ff23fSmrgint
207b7e1c893Smrgatombios_external_tmds_setup(xf86OutputPtr output, int action)
208209ff23fSmrg{
209b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
210b7e1c893Smrg    ScrnInfoPtr pScrn = output->scrn;
211b7e1c893Smrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
212209ff23fSmrg    ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION disp_data;
213209ff23fSmrg    AtomBiosArgRec data;
214209ff23fSmrg    unsigned char *space;
215b7e1c893Smrg    int clock = radeon_output->pixel_clock;
216209ff23fSmrg
217b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
218209ff23fSmrg
219b7e1c893Smrg    disp_data.sXTmdsEncoder.ucEnable = action;
220b7e1c893Smrg
221b7e1c893Smrg    if (clock > 165000)
222b7e1c893Smrg	disp_data.sXTmdsEncoder.ucMisc = PANEL_ENCODER_MISC_DUAL;
223209ff23fSmrg
224b7e1c893Smrg    if (pScrn->rgbBits == 8)
225209ff23fSmrg	disp_data.sXTmdsEncoder.ucMisc |= (1 << 1);
226209ff23fSmrg
227209ff23fSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
228209ff23fSmrg    data.exec.dataSpace = (void *)&space;
229209ff23fSmrg    data.exec.pspace = &disp_data;
230209ff23fSmrg
231209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
232209ff23fSmrg	ErrorF("External TMDS setup success\n");
233209ff23fSmrg	return ATOM_SUCCESS;
234209ff23fSmrg    }
235209ff23fSmrg
236209ff23fSmrg    ErrorF("External TMDS setup failed\n");
237209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
238209ff23fSmrg}
239209ff23fSmrg
240209ff23fSmrgstatic int
241b7e1c893Smrgatombios_output_ddia_setup(xf86OutputPtr output, int action)
242209ff23fSmrg{
243b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
244209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
245209ff23fSmrg    DVO_ENCODER_CONTROL_PS_ALLOCATION disp_data;
246209ff23fSmrg    AtomBiosArgRec data;
247209ff23fSmrg    unsigned char *space;
248b7e1c893Smrg    int clock = radeon_output->pixel_clock;
249b7e1c893Smrg
250b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
251209ff23fSmrg
252b7e1c893Smrg    disp_data.sDVOEncoder.ucAction = action;
253b7e1c893Smrg    disp_data.sDVOEncoder.usPixelClock = cpu_to_le16(clock / 10);
254209ff23fSmrg
255b7e1c893Smrg    if (clock > 165000)
256209ff23fSmrg	disp_data.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = PANEL_ENCODER_MISC_DUAL;
257209ff23fSmrg
258209ff23fSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
259209ff23fSmrg    data.exec.dataSpace = (void *)&space;
260209ff23fSmrg    data.exec.pspace = &disp_data;
261209ff23fSmrg
262209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
263209ff23fSmrg	ErrorF("DDIA setup success\n");
264209ff23fSmrg	return ATOM_SUCCESS;
265209ff23fSmrg    }
266209ff23fSmrg
267209ff23fSmrg    ErrorF("DDIA setup failed\n");
268209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
269209ff23fSmrg}
270209ff23fSmrg
271209ff23fSmrgstatic int
272b7e1c893Smrgatombios_output_digital_setup(xf86OutputPtr output, int action)
273209ff23fSmrg{
274b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
275b7e1c893Smrg    ScrnInfoPtr pScrn = output->scrn;
276b7e1c893Smrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
277b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
278b7e1c893Smrg    LVDS_ENCODER_CONTROL_PS_ALLOCATION disp_data;
279b7e1c893Smrg    LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 disp_data2;
280209ff23fSmrg    AtomBiosArgRec data;
281209ff23fSmrg    unsigned char *space;
282b7e1c893Smrg    int index = 0;
283b7e1c893Smrg    int major, minor;
284b7e1c893Smrg    int lvds_misc = 0;
285b7e1c893Smrg    int clock = radeon_output->pixel_clock;
286209ff23fSmrg
287b7e1c893Smrg    if (radeon_encoder == NULL)
288b7e1c893Smrg	return ATOM_NOT_IMPLEMENTED;
289b7e1c893Smrg
290b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
291b7e1c893Smrg	radeon_lvds_ptr lvds = (radeon_lvds_ptr)radeon_encoder->dev_priv;
292b7e1c893Smrg	if (lvds == NULL)
293b7e1c893Smrg	    return ATOM_NOT_IMPLEMENTED;
294b7e1c893Smrg	lvds_misc = lvds->lvds_misc;
295b7e1c893Smrg    }
296b7e1c893Smrg
297b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
298b7e1c893Smrg    memset(&disp_data2,0, sizeof(disp_data2));
299b7e1c893Smrg
300b7e1c893Smrg    switch (radeon_encoder->encoder_id) {
301b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
302b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl);
303b7e1c893Smrg	break;
304b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
305b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
306b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl);
307b7e1c893Smrg	break;
308b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
309b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
310b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT))
311b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl);
312b7e1c893Smrg	else
313b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl);
314b7e1c893Smrg	break;
315b7e1c893Smrg    }
316b7e1c893Smrg
317b7e1c893Smrg    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
318b7e1c893Smrg
319b7e1c893Smrg    /*ErrorF("table is %d %d\n", major, minor);*/
320b7e1c893Smrg    switch (major) {
321b7e1c893Smrg    case 0:
322b7e1c893Smrg    case 1:
323b7e1c893Smrg    case 2:
324b7e1c893Smrg	switch (minor) {
325b7e1c893Smrg	case 1:
326b7e1c893Smrg	    disp_data.ucMisc = 0;
327b7e1c893Smrg	    disp_data.ucAction = action;
328b7e1c893Smrg	    if ((radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_A) ||
329b7e1c893Smrg		(radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_B))
330b7e1c893Smrg		disp_data.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
331b7e1c893Smrg	    disp_data.usPixelClock = cpu_to_le16(clock / 10);
332b7e1c893Smrg	    if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
333b7e1c893Smrg		if (lvds_misc & (1 << 0))
334b7e1c893Smrg		    disp_data.ucMisc |= PANEL_ENCODER_MISC_DUAL;
335b7e1c893Smrg		if (lvds_misc & (1 << 1))
336b7e1c893Smrg		    disp_data.ucMisc |= (1 << 1);
337b7e1c893Smrg	    } else {
338b7e1c893Smrg		if (radeon_output->linkb)
339b7e1c893Smrg		    disp_data.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
340b7e1c893Smrg		if (clock > 165000)
341b7e1c893Smrg		    disp_data.ucMisc |= PANEL_ENCODER_MISC_DUAL;
342b7e1c893Smrg		if (pScrn->rgbBits == 8)
343b7e1c893Smrg		    disp_data.ucMisc |= (1 << 1);
344b7e1c893Smrg	    }
345b7e1c893Smrg	    data.exec.pspace = &disp_data;
346b7e1c893Smrg	    break;
347b7e1c893Smrg	case 2:
348b7e1c893Smrg	case 3:
349b7e1c893Smrg	    disp_data2.ucMisc = 0;
350b7e1c893Smrg	    disp_data2.ucAction = action;
351b7e1c893Smrg	    if (minor == 3) {
352b7e1c893Smrg		if (radeon_output->coherent_mode) {
353b7e1c893Smrg		    disp_data2.ucMisc |= PANEL_ENCODER_MISC_COHERENT;
354b7e1c893Smrg		    xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "Coherent Mode enabled\n");
355b7e1c893Smrg		}
356b7e1c893Smrg	    }
357b7e1c893Smrg	    if ((radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_A) ||
358b7e1c893Smrg		(radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_B))
359b7e1c893Smrg		disp_data2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
360b7e1c893Smrg	    disp_data2.usPixelClock = cpu_to_le16(clock / 10);
361b7e1c893Smrg	    disp_data2.ucTruncate = 0;
362b7e1c893Smrg	    disp_data2.ucSpatial = 0;
363b7e1c893Smrg	    disp_data2.ucTemporal = 0;
364b7e1c893Smrg	    disp_data2.ucFRC = 0;
365b7e1c893Smrg	    if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
366b7e1c893Smrg		if (lvds_misc & (1 << 0))
367b7e1c893Smrg		    disp_data2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
368b7e1c893Smrg		if (lvds_misc & (1 << 5)) {
369b7e1c893Smrg		    disp_data2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN;
370b7e1c893Smrg		    if (lvds_misc & (1 << 1))
371b7e1c893Smrg			disp_data2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH;
372b7e1c893Smrg		}
373b7e1c893Smrg		if (lvds_misc & (1 << 6)) {
374b7e1c893Smrg		    disp_data2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN;
375b7e1c893Smrg		    if (lvds_misc & (1 << 1))
376b7e1c893Smrg			disp_data2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH;
377b7e1c893Smrg		    if (((lvds_misc >> 2) & 0x3) == 2)
378b7e1c893Smrg			disp_data2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4;
379b7e1c893Smrg		}
380b7e1c893Smrg	    } else {
381b7e1c893Smrg		if (radeon_output->linkb)
382b7e1c893Smrg		    disp_data2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
383b7e1c893Smrg		if (clock > 165000)
384b7e1c893Smrg		    disp_data2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
385b7e1c893Smrg	    }
386b7e1c893Smrg	    data.exec.pspace = &disp_data2;
387b7e1c893Smrg	    break;
388b7e1c893Smrg	default:
389b7e1c893Smrg	    ErrorF("Unknown table version\n");
390b7e1c893Smrg	    exit(-1);
391b7e1c893Smrg	}
392b7e1c893Smrg	break;
393b7e1c893Smrg    default:
394b7e1c893Smrg	ErrorF("Unknown table version\n");
395b7e1c893Smrg	exit(-1);
396b7e1c893Smrg    }
397b7e1c893Smrg
398b7e1c893Smrg    data.exec.index = index;
399209ff23fSmrg    data.exec.dataSpace = (void *)&space;
400209ff23fSmrg
401209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
402b7e1c893Smrg	ErrorF("Output digital setup success\n");
403209ff23fSmrg	return ATOM_SUCCESS;
404209ff23fSmrg    }
405209ff23fSmrg
406b7e1c893Smrg    ErrorF("Output digital setup failed\n");
407209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
408209ff23fSmrg}
409209ff23fSmrg
410209ff23fSmrgstatic int
411b7e1c893Smrgatombios_maybe_hdmi_mode(xf86OutputPtr output)
412209ff23fSmrg{
413b7e1c893Smrg#ifndef EDID_COMPLETE_RAWDATA
414b7e1c893Smrg    /* there's no getting this right unless we have complete EDID */
415b7e1c893Smrg    return ATOM_ENCODER_MODE_HDMI;
416b7e1c893Smrg#else
417b7e1c893Smrg    if (output && xf86MonitorIsHDMI(output->MonInfo))
418b7e1c893Smrg	return ATOM_ENCODER_MODE_HDMI;
419b7e1c893Smrg
420b7e1c893Smrg    return ATOM_ENCODER_MODE_DVI;
421b7e1c893Smrg#endif
422b7e1c893Smrg}
423209ff23fSmrg
424b7e1c893Smrgint
425b7e1c893Smrgatombios_get_encoder_mode(xf86OutputPtr output)
426b7e1c893Smrg{
427b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
428209ff23fSmrg
429b7e1c893Smrg    /* DVI should really be atombios_maybe_hdmi_mode() as well */
430b7e1c893Smrg    switch (radeon_output->ConnectorType) {
431b7e1c893Smrg    case CONNECTOR_DVI_I:
432b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT))
433b7e1c893Smrg	    return ATOM_ENCODER_MODE_DVI;
434b7e1c893Smrg	else
435b7e1c893Smrg	    return ATOM_ENCODER_MODE_CRT;
436b7e1c893Smrg	break;
437b7e1c893Smrg    case CONNECTOR_DVI_D:
438b7e1c893Smrg    default:
439b7e1c893Smrg	return ATOM_ENCODER_MODE_DVI;
440b7e1c893Smrg	break;
441b7e1c893Smrg    case CONNECTOR_HDMI_TYPE_A:
442b7e1c893Smrg    case CONNECTOR_HDMI_TYPE_B:
443b7e1c893Smrg	return atombios_maybe_hdmi_mode(output);
444b7e1c893Smrg	break;
445b7e1c893Smrg    case CONNECTOR_LVDS:
446b7e1c893Smrg	return ATOM_ENCODER_MODE_LVDS;
447b7e1c893Smrg	break;
448b7e1c893Smrg    case CONNECTOR_DISPLAY_PORT:
449ad43ddacSmrg    case CONNECTOR_EDP:
450b7e1c893Smrg	if (radeon_output->MonType == MT_DP)
451b7e1c893Smrg	    return ATOM_ENCODER_MODE_DP;
452b7e1c893Smrg	else
453b7e1c893Smrg	    return atombios_maybe_hdmi_mode(output);
454b7e1c893Smrg	break;
455b7e1c893Smrg    case CONNECTOR_DVI_A:
456b7e1c893Smrg    case CONNECTOR_VGA:
457b7e1c893Smrg    case CONNECTOR_STV:
458b7e1c893Smrg    case CONNECTOR_CTV:
459b7e1c893Smrg    case CONNECTOR_DIN:
460b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
461b7e1c893Smrg	    return ATOM_ENCODER_MODE_TV;
462b7e1c893Smrg	else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
463b7e1c893Smrg	    return ATOM_ENCODER_MODE_CV;
464b7e1c893Smrg	else
465b7e1c893Smrg	    return ATOM_ENCODER_MODE_CRT;
466b7e1c893Smrg	break;
467209ff23fSmrg    }
468209ff23fSmrg
469209ff23fSmrg}
470209ff23fSmrg
471b7e1c893Smrgstatic const int dp_clocks[] = {
472ad43ddacSmrg    5400,  // 1 lane, 1.62 Ghz
473ad43ddacSmrg    9000,  // 1 lane, 2.70 Ghz
474ad43ddacSmrg    10800, // 2 lane, 1.62 Ghz
475ad43ddacSmrg    18000, // 2 lane, 2.70 Ghz
476ad43ddacSmrg    21600, // 4 lane, 1.62 Ghz
477ad43ddacSmrg    36000, // 4 lane, 2.70 Ghz
478b7e1c893Smrg};
479b7e1c893Smrgstatic const int num_dp_clocks = sizeof(dp_clocks) / sizeof(int);
480b7e1c893Smrg
481ad43ddacSmrg# define DP_LINK_BW_1_62                    0x06
482ad43ddacSmrg# define DP_LINK_BW_2_7                     0x0a
483ad43ddacSmrg
484209ff23fSmrgstatic int
485ad43ddacSmrgdp_lanes_for_mode_clock(RADEONOutputPrivatePtr radeon_output,
486ad43ddacSmrg			int mode_clock)
487209ff23fSmrg{
488b7e1c893Smrg    int i;
489ad43ddacSmrg    int max_link_bw = radeon_output->dpcd[1];
490ad43ddacSmrg
491ad43ddacSmrg    switch (max_link_bw) {
492ad43ddacSmrg    case DP_LINK_BW_1_62:
493ad43ddacSmrg    default:
494ad43ddacSmrg	for (i = 0; i < num_dp_clocks; i++) {
495ad43ddacSmrg	    if (i % 2)
496ad43ddacSmrg		continue;
497ad43ddacSmrg	    if (dp_clocks[i] > (mode_clock / 10)) {
498ad43ddacSmrg		if (i < 2)
499ad43ddacSmrg		    return 1;
500ad43ddacSmrg		else if (i < 4)
501ad43ddacSmrg		    return 2;
502ad43ddacSmrg		else
503ad43ddacSmrg		    return 4;
504ad43ddacSmrg	    }
505ad43ddacSmrg	}
506ad43ddacSmrg	break;
507ad43ddacSmrg    case DP_LINK_BW_2_7:
508ad43ddacSmrg	for (i = 0; i < num_dp_clocks; i++) {
509ad43ddacSmrg	    if (dp_clocks[i] > (mode_clock / 10)) {
510ad43ddacSmrg		if (i < 2)
511ad43ddacSmrg		    return 1;
512ad43ddacSmrg		else if (i < 4)
513ad43ddacSmrg		    return 2;
514ad43ddacSmrg		else
515ad43ddacSmrg		    return 4;
516ad43ddacSmrg	    }
517ad43ddacSmrg	}
518ad43ddacSmrg        break;
519ad43ddacSmrg    }
520209ff23fSmrg
521b7e1c893Smrg    return 0;
522b7e1c893Smrg}
523209ff23fSmrg
524b7e1c893Smrgstatic int
525ad43ddacSmrgdp_link_clock_for_mode_clock(RADEONOutputPrivatePtr radeon_output,
526ad43ddacSmrg			     int mode_clock)
527b7e1c893Smrg{
528b7e1c893Smrg    int i;
529ad43ddacSmrg    int max_link_bw = radeon_output->dpcd[1];
530209ff23fSmrg
531ad43ddacSmrg    switch (max_link_bw) {
532ad43ddacSmrg    case DP_LINK_BW_1_62:
533ad43ddacSmrg    default:
534ad43ddacSmrg	return 16200;
535ad43ddacSmrg	break;
536ad43ddacSmrg    case DP_LINK_BW_2_7:
537ad43ddacSmrg	for (i = 0; i < num_dp_clocks; i++)
538ad43ddacSmrg	    if (dp_clocks[i] > (mode_clock / 10))
539ad43ddacSmrg		return (i % 2) ? 27000 : 16200;
540ad43ddacSmrg        break;
541ad43ddacSmrg    }
542b7e1c893Smrg
543b7e1c893Smrg    return 0;
544209ff23fSmrg}
545209ff23fSmrg
546ad43ddacSmrg/*
547ad43ddacSmrg * DIG Encoder/Transmitter Setup
548ad43ddacSmrg *
549ad43ddacSmrg * DCE 3.0/3.1
550ad43ddacSmrg * - 2 DIG transmitter blocks. UNIPHY (links A and B) and LVTMA.
551ad43ddacSmrg * Supports up to 3 digital outputs
552ad43ddacSmrg * - 2 DIG encoder blocks.
553ad43ddacSmrg * DIG1 can drive UNIPHY link A or link B
554ad43ddacSmrg * DIG2 can drive UNIPHY link B or LVTMA
555ad43ddacSmrg *
556ad43ddacSmrg * DCE 3.2
557ad43ddacSmrg * - 3 DIG transmitter blocks. UNIPHY0/1/2 (links A and B).
558ad43ddacSmrg * Supports up to 5 digital outputs
559ad43ddacSmrg * - 2 DIG encoder blocks.
560ad43ddacSmrg * DIG1/2 can drive UNIPHY0/1/2 link A or link B
561ad43ddacSmrg *
562ad43ddacSmrg * Routing
563ad43ddacSmrg * crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links)
564ad43ddacSmrg * Examples:
565ad43ddacSmrg * crtc0 -> dig2 -> LVTMA links A+B
566ad43ddacSmrg * crtc1 -> dig1 -> UNIPHY0 link B
567ad43ddacSmrg */
568209ff23fSmrgstatic int
569b7e1c893Smrgatombios_output_dig_encoder_setup(xf86OutputPtr output, int action)
570209ff23fSmrg{
571209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
572209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
573b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
574209ff23fSmrg    DIG_ENCODER_CONTROL_PS_ALLOCATION disp_data;
575209ff23fSmrg    AtomBiosArgRec data;
576209ff23fSmrg    unsigned char *space;
577ad43ddacSmrg    int index = 0, major, minor;
578b7e1c893Smrg    int clock = radeon_output->pixel_clock;
579b7e1c893Smrg
580b7e1c893Smrg    if (radeon_encoder == NULL)
581b7e1c893Smrg	return ATOM_NOT_IMPLEMENTED;
582b7e1c893Smrg
583b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
584b7e1c893Smrg
585ad43ddacSmrg    if (radeon_output->dig_encoder)
586ad43ddacSmrg        index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
587ad43ddacSmrg    else
588ad43ddacSmrg        index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
589209ff23fSmrg
590b7e1c893Smrg    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
591b7e1c893Smrg
592b7e1c893Smrg    disp_data.ucAction = action;
593b7e1c893Smrg    disp_data.usPixelClock = cpu_to_le16(clock / 10);
594b7e1c893Smrg
595b7e1c893Smrg    if (IS_DCE32_VARIANT) {
596b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
597b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
598b7e1c893Smrg	    disp_data.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1;
599b7e1c893Smrg	    break;
600b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
601b7e1c893Smrg	    disp_data.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2;
602b7e1c893Smrg	    break;
603b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
604b7e1c893Smrg	    disp_data.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3;
605b7e1c893Smrg	    break;
606b7e1c893Smrg	}
607b7e1c893Smrg    } else {
608b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
609b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
610b7e1c893Smrg	    disp_data.ucConfig = ATOM_ENCODER_CONFIG_UNIPHY;
611b7e1c893Smrg	    break;
612b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
613b7e1c893Smrg	    disp_data.ucConfig = ATOM_ENCODER_CONFIG_LVTMA;
614b7e1c893Smrg	    break;
615b7e1c893Smrg	}
616209ff23fSmrg    }
617209ff23fSmrg
618b7e1c893Smrg    disp_data.ucEncoderMode = atombios_get_encoder_mode(output);
619b7e1c893Smrg
620b7e1c893Smrg    if (disp_data.ucEncoderMode == ATOM_ENCODER_MODE_DP) {
621ad43ddacSmrg	if (dp_link_clock_for_mode_clock(radeon_output, clock) == 27000)
622b7e1c893Smrg	    disp_data.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
623ad43ddacSmrg	disp_data.ucLaneNum = dp_lanes_for_mode_clock(radeon_output, clock);
624ad43ddacSmrg    } else if (clock > 165000)
625209ff23fSmrg	disp_data.ucLaneNum = 8;
626ad43ddacSmrg    else
627209ff23fSmrg	disp_data.ucLaneNum = 4;
628ad43ddacSmrg
629ad43ddacSmrg    if (radeon_output->linkb)
630ad43ddacSmrg	disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
631ad43ddacSmrg    else
632ad43ddacSmrg	disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
633209ff23fSmrg
634b7e1c893Smrg    data.exec.index = index;
635209ff23fSmrg    data.exec.dataSpace = (void *)&space;
636209ff23fSmrg    data.exec.pspace = &disp_data;
637209ff23fSmrg
638209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
639ad43ddacSmrg	ErrorF("Output DIG%d encoder setup success\n", radeon_output->dig_encoder);
640209ff23fSmrg	return ATOM_SUCCESS;
641209ff23fSmrg    }
642209ff23fSmrg
643ad43ddacSmrg    ErrorF("Output DIG%d setup failed\n", radeon_output->dig_encoder);
644209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
645209ff23fSmrg
646209ff23fSmrg}
647209ff23fSmrg
648ad43ddacSmrgstatic int
649ad43ddacSmrgatombios_dce4_output_dig_encoder_setup(xf86OutputPtr output, int action)
650ad43ddacSmrg{
651ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
652ad43ddacSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
653ad43ddacSmrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
654ad43ddacSmrg    DIG_ENCODER_CONTROL_PARAMETERS_V3 disp_data;
655ad43ddacSmrg    AtomBiosArgRec data;
656ad43ddacSmrg    unsigned char *space;
657ad43ddacSmrg    int index;
658ad43ddacSmrg    int clock = radeon_output->pixel_clock;
659ad43ddacSmrg
660ad43ddacSmrg    if (radeon_encoder == NULL)
661ad43ddacSmrg	return ATOM_NOT_IMPLEMENTED;
662ad43ddacSmrg
663ad43ddacSmrg    memset(&disp_data,0, sizeof(disp_data));
664ad43ddacSmrg
665ad43ddacSmrg    index = GetIndexIntoMasterTable(COMMAND, DIGxEncoderControl);
666ad43ddacSmrg
667ad43ddacSmrg    disp_data.ucAction = action;
668ad43ddacSmrg    disp_data.usPixelClock = cpu_to_le16(clock / 10);
669ad43ddacSmrg    disp_data.ucEncoderMode = atombios_get_encoder_mode(output);
670ad43ddacSmrg    disp_data.acConfig.ucDigSel = radeon_output->dig_encoder;
671ad43ddacSmrg
672ad43ddacSmrg    if (disp_data.ucEncoderMode == ATOM_ENCODER_MODE_DP) {
673ad43ddacSmrg	if (dp_link_clock_for_mode_clock(radeon_output, clock) == 27000)
674ad43ddacSmrg	    disp_data.acConfig.ucDPLinkRate = 1;
675ad43ddacSmrg	disp_data.ucLaneNum = dp_lanes_for_mode_clock(radeon_output, clock);
676ad43ddacSmrg    } else if (clock > 165000)
677ad43ddacSmrg	disp_data.ucLaneNum = 8;
678ad43ddacSmrg    else
679ad43ddacSmrg	disp_data.ucLaneNum = 4;
680ad43ddacSmrg
681ad43ddacSmrg    disp_data.ucBitPerColor = PANEL_8BIT_PER_COLOR;
682ad43ddacSmrg
683ad43ddacSmrg    data.exec.index = index;
684ad43ddacSmrg    data.exec.dataSpace = (void *)&space;
685ad43ddacSmrg    data.exec.pspace = &disp_data;
686ad43ddacSmrg
687ad43ddacSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
688ad43ddacSmrg	ErrorF("Output DIG%d encoder setup success\n", radeon_output->dig_encoder);
689ad43ddacSmrg	return ATOM_SUCCESS;
690ad43ddacSmrg    }
691ad43ddacSmrg
692ad43ddacSmrg    ErrorF("Output DIG%d setup failed\n", radeon_output->dig_encoder);
693ad43ddacSmrg    return ATOM_NOT_IMPLEMENTED;
694ad43ddacSmrg}
695ad43ddacSmrg
696b7e1c893Smrgunion dig_transmitter_control {
697b7e1c893Smrg    DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1;
698b7e1c893Smrg    DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2;
699ad43ddacSmrg    DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3;
700b7e1c893Smrg};
701b7e1c893Smrg
702209ff23fSmrgstatic int
703ad43ddacSmrgatombios_output_dig_transmitter_setup(xf86OutputPtr output, int action, uint8_t lane_num, uint8_t lane_set)
704209ff23fSmrg{
705209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
706209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
707b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
708b7e1c893Smrg    union dig_transmitter_control disp_data;
709209ff23fSmrg    AtomBiosArgRec data;
710209ff23fSmrg    unsigned char *space;
711b7e1c893Smrg    int index = 0, num = 0;
712b7e1c893Smrg    int major, minor;
713b7e1c893Smrg    int clock = radeon_output->pixel_clock;
714b7e1c893Smrg
715b7e1c893Smrg    if (radeon_encoder == NULL)
716b7e1c893Smrg        return ATOM_NOT_IMPLEMENTED;
717b7e1c893Smrg
718b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
719b7e1c893Smrg
720ad43ddacSmrg    if (IS_DCE32_VARIANT || IS_DCE4_VARIANT)
721b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
722b7e1c893Smrg    else {
723b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
724b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
725b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DIG1TransmitterControl);
726b7e1c893Smrg	    break;
727b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
728b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DIG2TransmitterControl);
729b7e1c893Smrg	    break;
730b7e1c893Smrg	}
731b7e1c893Smrg    }
732209ff23fSmrg
733b7e1c893Smrg    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
734b7e1c893Smrg
735b7e1c893Smrg    disp_data.v1.ucAction = action;
736b7e1c893Smrg
737ad43ddacSmrg    if (IS_DCE4_VARIANT) {
738ad43ddacSmrg	if (action == ATOM_TRANSMITTER_ACTION_INIT) {
739ad43ddacSmrg	    disp_data.v3.usInitInfo = radeon_output->connector_object_id;
740ad43ddacSmrg	} else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
741ad43ddacSmrg	    disp_data.v3.asMode.ucLaneSel = lane_num;
742ad43ddacSmrg	    disp_data.v3.asMode.ucLaneSet = lane_set;
743209ff23fSmrg	} else {
744ad43ddacSmrg	    if (radeon_output->MonType == MT_DP) {
745ad43ddacSmrg		disp_data.v3.usPixelClock =
746ad43ddacSmrg		    cpu_to_le16(dp_link_clock_for_mode_clock(radeon_output, clock));
747ad43ddacSmrg	    } else if (clock > 165000) {
748ad43ddacSmrg		disp_data.v3.usPixelClock = cpu_to_le16((clock / 2) / 10);
749ad43ddacSmrg		disp_data.v3.acConfig.fDualLinkConnector = 1;
750ad43ddacSmrg	    } else {
751ad43ddacSmrg		disp_data.v3.usPixelClock = cpu_to_le16(clock / 10);
752ad43ddacSmrg	    }
753b7e1c893Smrg	}
754ad43ddacSmrg
755ad43ddacSmrg	if (radeon_output->MonType == MT_DP)
756ad43ddacSmrg	    disp_data.v3.ucLaneNum = dp_lanes_for_mode_clock(radeon_output, clock);
757ad43ddacSmrg	else if (clock > 165000)
758ad43ddacSmrg	    disp_data.v3.ucLaneNum = 8;
759ad43ddacSmrg	else
760ad43ddacSmrg	    disp_data.v3.ucLaneNum = 4;
761ad43ddacSmrg
762ad43ddacSmrg	if (radeon_output->linkb) {
763ad43ddacSmrg	    disp_data.v3.acConfig.ucLinkSel = 1;
764b7e1c893Smrg	    disp_data.v2.acConfig.ucEncoderSel = 1;
765ad43ddacSmrg	}
766ad43ddacSmrg
767ad43ddacSmrg	// select the PLL for the UNIPHY
768ad43ddacSmrg	if (radeon_output->MonType == MT_DP)
769ad43ddacSmrg	    disp_data.v3.acConfig.ucRefClkSource = 2; /* ext clk */
770ad43ddacSmrg	else
771ad43ddacSmrg	    disp_data.v3.acConfig.ucRefClkSource = radeon_output->pll_id;
772ad43ddacSmrg
773ad43ddacSmrg	switch (radeon_encoder->encoder_id) {
774ad43ddacSmrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
775ad43ddacSmrg	    disp_data.v3.acConfig.ucTransmitterSel = 0;
776ad43ddacSmrg	    num = 0;
777ad43ddacSmrg	    break;
778ad43ddacSmrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
779ad43ddacSmrg	    disp_data.v3.acConfig.ucTransmitterSel = 1;
780ad43ddacSmrg	    num = 1;
781ad43ddacSmrg	    break;
782ad43ddacSmrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
783ad43ddacSmrg	    disp_data.v3.acConfig.ucTransmitterSel = 2;
784ad43ddacSmrg	    num = 2;
785ad43ddacSmrg	    break;
786ad43ddacSmrg	}
787ad43ddacSmrg
788ad43ddacSmrg	if (radeon_output->MonType == MT_DP)
789ad43ddacSmrg	    disp_data.v3.acConfig.fCoherentMode = 1; /* DP requires coherent */
790ad43ddacSmrg	else if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) {
791ad43ddacSmrg	    if (radeon_output->coherent_mode)
792ad43ddacSmrg		disp_data.v3.acConfig.fCoherentMode = 1;
793ad43ddacSmrg	}
794ad43ddacSmrg    } else if (IS_DCE32_VARIANT) {
795ad43ddacSmrg	if (action == ATOM_TRANSMITTER_ACTION_INIT) {
796ad43ddacSmrg	    disp_data.v2.usInitInfo = radeon_output->connector_object_id;
797ad43ddacSmrg	} else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
798ad43ddacSmrg	    disp_data.v2.asMode.ucLaneSel = lane_num;
799ad43ddacSmrg	    disp_data.v2.asMode.ucLaneSet = lane_set;
800ad43ddacSmrg	} else {
801ad43ddacSmrg	    if (radeon_output->MonType == MT_DP) {
802ad43ddacSmrg		disp_data.v2.usPixelClock =
803ad43ddacSmrg		    cpu_to_le16(dp_link_clock_for_mode_clock(radeon_output, clock));
804ad43ddacSmrg		disp_data.v2.acConfig.fDPConnector = 1;
805ad43ddacSmrg	    } else if (clock > 165000) {
806ad43ddacSmrg		disp_data.v2.usPixelClock = cpu_to_le16((clock / 2) / 10);
807ad43ddacSmrg		disp_data.v2.acConfig.fDualLinkConnector = 1;
808ad43ddacSmrg	    } else {
809ad43ddacSmrg		disp_data.v2.usPixelClock = cpu_to_le16(clock / 10);
810ad43ddacSmrg	    }
811ad43ddacSmrg	}
812ad43ddacSmrg	if (radeon_output->dig_encoder)
813ad43ddacSmrg	    disp_data.v2.acConfig.ucEncoderSel = 1;
814ad43ddacSmrg
815ad43ddacSmrg	if (radeon_output->linkb)
816ad43ddacSmrg	    disp_data.v2.acConfig.ucLinkSel = 1;
817b7e1c893Smrg
818b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
819b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
820b7e1c893Smrg	    disp_data.v2.acConfig.ucTransmitterSel = 0;
821b7e1c893Smrg	    num = 0;
822b7e1c893Smrg	    break;
823b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
824b7e1c893Smrg	    disp_data.v2.acConfig.ucTransmitterSel = 1;
825b7e1c893Smrg	    num = 1;
826b7e1c893Smrg	    break;
827b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
828b7e1c893Smrg	    disp_data.v2.acConfig.ucTransmitterSel = 2;
829b7e1c893Smrg	    num = 2;
830b7e1c893Smrg	    break;
831b7e1c893Smrg	}
832b7e1c893Smrg
833ad43ddacSmrg	if (radeon_output->MonType == MT_DP)
834ad43ddacSmrg	    disp_data.v2.acConfig.fCoherentMode = 1; /* DP requires coherent */
835ad43ddacSmrg	else if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) {
836ad43ddacSmrg	    if (radeon_output->coherent_mode)
837b7e1c893Smrg		disp_data.v2.acConfig.fCoherentMode = 1;
838209ff23fSmrg	}
839209ff23fSmrg    } else {
840b7e1c893Smrg	disp_data.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL;
841b7e1c893Smrg
842ad43ddacSmrg	if (action == ATOM_TRANSMITTER_ACTION_INIT) {
843ad43ddacSmrg	    disp_data.v1.usInitInfo = radeon_output->connector_object_id;
844ad43ddacSmrg	} else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
845ad43ddacSmrg	    disp_data.v1.asMode.ucLaneSel = lane_num;
846ad43ddacSmrg	    disp_data.v1.asMode.ucLaneSet = lane_set;
847ad43ddacSmrg	} else {
848ad43ddacSmrg	    if (radeon_output->MonType == MT_DP)
849ad43ddacSmrg		disp_data.v1.usPixelClock =
850ad43ddacSmrg		    cpu_to_le16(dp_link_clock_for_mode_clock(radeon_output, clock));
851ad43ddacSmrg	    else if (clock > 165000)
852ad43ddacSmrg		disp_data.v1.usPixelClock = cpu_to_le16((clock / 2) / 10);
853ad43ddacSmrg	    else
854ad43ddacSmrg		disp_data.v1.usPixelClock = cpu_to_le16(clock / 10);
855ad43ddacSmrg	}
856ad43ddacSmrg
857ad43ddacSmrg	if (radeon_output->dig_encoder)
858ad43ddacSmrg	    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
859209ff23fSmrg	else
860ad43ddacSmrg	    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
861b7e1c893Smrg
862b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
863b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
864b7e1c893Smrg	    if (info->IsIGP) {
865b7e1c893Smrg		if (clock > 165000) {
866b7e1c893Smrg		    if (radeon_output->igp_lane_info & 0x3)
867b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7;
868b7e1c893Smrg		    else if (radeon_output->igp_lane_info & 0xc)
869b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15;
870b7e1c893Smrg		} else {
871b7e1c893Smrg		    if (radeon_output->igp_lane_info & 0x1)
872b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3;
873b7e1c893Smrg		    else if (radeon_output->igp_lane_info & 0x2)
874b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7;
875b7e1c893Smrg		    else if (radeon_output->igp_lane_info & 0x4)
876b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11;
877b7e1c893Smrg		    else if (radeon_output->igp_lane_info & 0x8)
878b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15;
879b7e1c893Smrg		}
880b7e1c893Smrg	    }
881b7e1c893Smrg	    break;
882b7e1c893Smrg	}
883ad43ddacSmrg	if (clock > 165000)
884ad43ddacSmrg	    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK;
885ad43ddacSmrg	if (radeon_output->linkb)
886ad43ddacSmrg	    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB;
887ad43ddacSmrg	else
888ad43ddacSmrg	    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA;
889209ff23fSmrg
890ad43ddacSmrg	if (radeon_output->MonType == MT_DP)
891ad43ddacSmrg	    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;  /* DP requires coherent */
892ad43ddacSmrg	else if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) {
893ad43ddacSmrg	    if (radeon_output->coherent_mode)
894b7e1c893Smrg		disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
895b7e1c893Smrg	}
896b7e1c893Smrg    }
897209ff23fSmrg
898b7e1c893Smrg    data.exec.index = index;
899209ff23fSmrg    data.exec.dataSpace = (void *)&space;
900209ff23fSmrg    data.exec.pspace = &disp_data;
901209ff23fSmrg
902209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
903b7e1c893Smrg	if (IS_DCE32_VARIANT)
904b7e1c893Smrg	    ErrorF("Output UNIPHY%d transmitter setup success\n", num);
905b7e1c893Smrg	else
906b7e1c893Smrg	   ErrorF("Output DIG%d transmitter setup success\n", num);
907209ff23fSmrg	return ATOM_SUCCESS;
908209ff23fSmrg    }
909209ff23fSmrg
910b7e1c893Smrg    ErrorF("Output DIG%d transmitter setup failed\n", num);
911209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
912209ff23fSmrg
913209ff23fSmrg}
914209ff23fSmrg
915c503f109Smrgstatic void atom_rv515_force_tv_scaler(ScrnInfoPtr pScrn, RADEONCrtcPrivatePtr radeon_crtc)
916b7e1c893Smrg{
917b7e1c893Smrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
918b7e1c893Smrg    unsigned char *RADEONMMIO = info->MMIO;
919c503f109Smrg    int index_reg = 0x6578, data_reg = 0x657c;
920c503f109Smrg
921c503f109Smrg    index_reg += radeon_crtc->crtc_offset;
922c503f109Smrg    data_reg += radeon_crtc->crtc_offset;
923c503f109Smrg
924c503f109Smrg    OUTREG(0x659C + radeon_crtc->crtc_offset, 0x0);
925c503f109Smrg    OUTREG(0x6594 + radeon_crtc->crtc_offset, 0x705);
926c503f109Smrg    OUTREG(0x65A4 + radeon_crtc->crtc_offset, 0x10001);
927c503f109Smrg    OUTREG(0x65D8 + radeon_crtc->crtc_offset, 0x0);
928c503f109Smrg    OUTREG(0x65B0 + radeon_crtc->crtc_offset, 0x0);
929c503f109Smrg    OUTREG(0x65C0 + radeon_crtc->crtc_offset, 0x0);
930c503f109Smrg    OUTREG(0x65D4 + radeon_crtc->crtc_offset, 0x0);
931c503f109Smrg    OUTREG(index_reg,0x0);
932c503f109Smrg    OUTREG(data_reg,0x841880A8);
933c503f109Smrg    OUTREG(index_reg,0x1);
934c503f109Smrg    OUTREG(data_reg,0x84208680);
935c503f109Smrg    OUTREG(index_reg,0x2);
936c503f109Smrg    OUTREG(data_reg,0xBFF880B0);
937c503f109Smrg    OUTREG(index_reg,0x100);
938c503f109Smrg    OUTREG(data_reg,0x83D88088);
939c503f109Smrg    OUTREG(index_reg,0x101);
940c503f109Smrg    OUTREG(data_reg,0x84608680);
941c503f109Smrg    OUTREG(index_reg,0x102);
942c503f109Smrg    OUTREG(data_reg,0xBFF080D0);
943c503f109Smrg    OUTREG(index_reg,0x200);
944c503f109Smrg    OUTREG(data_reg,0x83988068);
945c503f109Smrg    OUTREG(index_reg,0x201);
946c503f109Smrg    OUTREG(data_reg,0x84A08680);
947c503f109Smrg    OUTREG(index_reg,0x202);
948c503f109Smrg    OUTREG(data_reg,0xBFF080F8);
949c503f109Smrg    OUTREG(index_reg,0x300);
950c503f109Smrg    OUTREG(data_reg,0x83588058);
951c503f109Smrg    OUTREG(index_reg,0x301);
952c503f109Smrg    OUTREG(data_reg,0x84E08660);
953c503f109Smrg    OUTREG(index_reg,0x302);
954c503f109Smrg    OUTREG(data_reg,0xBFF88120);
955c503f109Smrg    OUTREG(index_reg,0x400);
956c503f109Smrg    OUTREG(data_reg,0x83188040);
957c503f109Smrg    OUTREG(index_reg,0x401);
958c503f109Smrg    OUTREG(data_reg,0x85008660);
959c503f109Smrg    OUTREG(index_reg,0x402);
960c503f109Smrg    OUTREG(data_reg,0xBFF88150);
961c503f109Smrg    OUTREG(index_reg,0x500);
962c503f109Smrg    OUTREG(data_reg,0x82D88030);
963c503f109Smrg    OUTREG(index_reg,0x501);
964c503f109Smrg    OUTREG(data_reg,0x85408640);
965c503f109Smrg    OUTREG(index_reg,0x502);
966c503f109Smrg    OUTREG(data_reg,0xBFF88180);
967c503f109Smrg    OUTREG(index_reg,0x600);
968c503f109Smrg    OUTREG(data_reg,0x82A08018);
969c503f109Smrg    OUTREG(index_reg,0x601);
970c503f109Smrg    OUTREG(data_reg,0x85808620);
971c503f109Smrg    OUTREG(index_reg,0x602);
972c503f109Smrg    OUTREG(data_reg,0xBFF081B8);
973c503f109Smrg    OUTREG(index_reg,0x700);
974c503f109Smrg    OUTREG(data_reg,0x82608010);
975c503f109Smrg    OUTREG(index_reg,0x701);
976c503f109Smrg    OUTREG(data_reg,0x85A08600);
977c503f109Smrg    OUTREG(index_reg,0x702);
978c503f109Smrg    OUTREG(data_reg,0x800081F0);
979c503f109Smrg    OUTREG(index_reg,0x800);
980c503f109Smrg    OUTREG(data_reg,0x8228BFF8);
981c503f109Smrg    OUTREG(index_reg,0x801);
982c503f109Smrg    OUTREG(data_reg,0x85E085E0);
983c503f109Smrg    OUTREG(index_reg,0x802);
984c503f109Smrg    OUTREG(data_reg,0xBFF88228);
985c503f109Smrg    OUTREG(index_reg,0x10000);
986c503f109Smrg    OUTREG(data_reg,0x82A8BF00);
987c503f109Smrg    OUTREG(index_reg,0x10001);
988c503f109Smrg    OUTREG(data_reg,0x82A08CC0);
989c503f109Smrg    OUTREG(index_reg,0x10002);
990c503f109Smrg    OUTREG(data_reg,0x8008BEF8);
991c503f109Smrg    OUTREG(index_reg,0x10100);
992c503f109Smrg    OUTREG(data_reg,0x81F0BF28);
993c503f109Smrg    OUTREG(index_reg,0x10101);
994c503f109Smrg    OUTREG(data_reg,0x83608CA0);
995c503f109Smrg    OUTREG(index_reg,0x10102);
996c503f109Smrg    OUTREG(data_reg,0x8018BED0);
997c503f109Smrg    OUTREG(index_reg,0x10200);
998c503f109Smrg    OUTREG(data_reg,0x8148BF38);
999c503f109Smrg    OUTREG(index_reg,0x10201);
1000c503f109Smrg    OUTREG(data_reg,0x84408C80);
1001c503f109Smrg    OUTREG(index_reg,0x10202);
1002c503f109Smrg    OUTREG(data_reg,0x8008BEB8);
1003c503f109Smrg    OUTREG(index_reg,0x10300);
1004c503f109Smrg    OUTREG(data_reg,0x80B0BF78);
1005c503f109Smrg    OUTREG(index_reg,0x10301);
1006c503f109Smrg    OUTREG(data_reg,0x85008C20);
1007c503f109Smrg    OUTREG(index_reg,0x10302);
1008c503f109Smrg    OUTREG(data_reg,0x8020BEA0);
1009c503f109Smrg    OUTREG(index_reg,0x10400);
1010c503f109Smrg    OUTREG(data_reg,0x8028BF90);
1011c503f109Smrg    OUTREG(index_reg,0x10401);
1012c503f109Smrg    OUTREG(data_reg,0x85E08BC0);
1013c503f109Smrg    OUTREG(index_reg,0x10402);
1014c503f109Smrg    OUTREG(data_reg,0x8018BE90);
1015c503f109Smrg    OUTREG(index_reg,0x10500);
1016c503f109Smrg    OUTREG(data_reg,0xBFB8BFB0);
1017c503f109Smrg    OUTREG(index_reg,0x10501);
1018c503f109Smrg    OUTREG(data_reg,0x86C08B40);
1019c503f109Smrg    OUTREG(index_reg,0x10502);
1020c503f109Smrg    OUTREG(data_reg,0x8010BE90);
1021c503f109Smrg    OUTREG(index_reg,0x10600);
1022c503f109Smrg    OUTREG(data_reg,0xBF58BFC8);
1023c503f109Smrg    OUTREG(index_reg,0x10601);
1024c503f109Smrg    OUTREG(data_reg,0x87A08AA0);
1025c503f109Smrg    OUTREG(index_reg,0x10602);
1026c503f109Smrg    OUTREG(data_reg,0x8010BE98);
1027c503f109Smrg    OUTREG(index_reg,0x10700);
1028c503f109Smrg    OUTREG(data_reg,0xBF10BFF0);
1029c503f109Smrg    OUTREG(index_reg,0x10701);
1030c503f109Smrg    OUTREG(data_reg,0x886089E0);
1031c503f109Smrg    OUTREG(index_reg,0x10702);
1032c503f109Smrg    OUTREG(data_reg,0x8018BEB0);
1033c503f109Smrg    OUTREG(index_reg,0x10800);
1034c503f109Smrg    OUTREG(data_reg,0xBED8BFE8);
1035c503f109Smrg    OUTREG(index_reg,0x10801);
1036c503f109Smrg    OUTREG(data_reg,0x89408940);
1037c503f109Smrg    OUTREG(index_reg,0x10802);
1038c503f109Smrg    OUTREG(data_reg,0xBFE8BED8);
1039c503f109Smrg    OUTREG(index_reg,0x20000);
1040c503f109Smrg    OUTREG(data_reg,0x80008000);
1041c503f109Smrg    OUTREG(index_reg,0x20001);
1042c503f109Smrg    OUTREG(data_reg,0x90008000);
1043c503f109Smrg    OUTREG(index_reg,0x20002);
1044c503f109Smrg    OUTREG(data_reg,0x80008000);
1045c503f109Smrg    OUTREG(index_reg,0x20003);
1046c503f109Smrg    OUTREG(data_reg,0x80008000);
1047c503f109Smrg    OUTREG(index_reg,0x20100);
1048c503f109Smrg    OUTREG(data_reg,0x80108000);
1049c503f109Smrg    OUTREG(index_reg,0x20101);
1050c503f109Smrg    OUTREG(data_reg,0x8FE0BF70);
1051c503f109Smrg    OUTREG(index_reg,0x20102);
1052c503f109Smrg    OUTREG(data_reg,0xBFE880C0);
1053c503f109Smrg    OUTREG(index_reg,0x20103);
1054c503f109Smrg    OUTREG(data_reg,0x80008000);
1055c503f109Smrg    OUTREG(index_reg,0x20200);
1056c503f109Smrg    OUTREG(data_reg,0x8018BFF8);
1057c503f109Smrg    OUTREG(index_reg,0x20201);
1058c503f109Smrg    OUTREG(data_reg,0x8F80BF08);
1059c503f109Smrg    OUTREG(index_reg,0x20202);
1060c503f109Smrg    OUTREG(data_reg,0xBFD081A0);
1061c503f109Smrg    OUTREG(index_reg,0x20203);
1062c503f109Smrg    OUTREG(data_reg,0xBFF88000);
1063c503f109Smrg    OUTREG(index_reg,0x20300);
1064c503f109Smrg    OUTREG(data_reg,0x80188000);
1065c503f109Smrg    OUTREG(index_reg,0x20301);
1066c503f109Smrg    OUTREG(data_reg,0x8EE0BEC0);
1067c503f109Smrg    OUTREG(index_reg,0x20302);
1068c503f109Smrg    OUTREG(data_reg,0xBFB082A0);
1069c503f109Smrg    OUTREG(index_reg,0x20303);
1070c503f109Smrg    OUTREG(data_reg,0x80008000);
1071c503f109Smrg    OUTREG(index_reg,0x20400);
1072c503f109Smrg    OUTREG(data_reg,0x80188000);
1073c503f109Smrg    OUTREG(index_reg,0x20401);
1074c503f109Smrg    OUTREG(data_reg,0x8E00BEA0);
1075c503f109Smrg    OUTREG(index_reg,0x20402);
1076c503f109Smrg    OUTREG(data_reg,0xBF8883C0);
1077c503f109Smrg    OUTREG(index_reg,0x20403);
1078c503f109Smrg    OUTREG(data_reg,0x80008000);
1079c503f109Smrg    OUTREG(index_reg,0x20500);
1080c503f109Smrg    OUTREG(data_reg,0x80188000);
1081c503f109Smrg    OUTREG(index_reg,0x20501);
1082c503f109Smrg    OUTREG(data_reg,0x8D00BE90);
1083c503f109Smrg    OUTREG(index_reg,0x20502);
1084c503f109Smrg    OUTREG(data_reg,0xBF588500);
1085c503f109Smrg    OUTREG(index_reg,0x20503);
1086c503f109Smrg    OUTREG(data_reg,0x80008008);
1087c503f109Smrg    OUTREG(index_reg,0x20600);
1088c503f109Smrg    OUTREG(data_reg,0x80188000);
1089c503f109Smrg    OUTREG(index_reg,0x20601);
1090c503f109Smrg    OUTREG(data_reg,0x8BC0BE98);
1091c503f109Smrg    OUTREG(index_reg,0x20602);
1092c503f109Smrg    OUTREG(data_reg,0xBF308660);
1093c503f109Smrg    OUTREG(index_reg,0x20603);
1094c503f109Smrg    OUTREG(data_reg,0x80008008);
1095c503f109Smrg    OUTREG(index_reg,0x20700);
1096c503f109Smrg    OUTREG(data_reg,0x80108000);
1097c503f109Smrg    OUTREG(index_reg,0x20701);
1098c503f109Smrg    OUTREG(data_reg,0x8A80BEB0);
1099c503f109Smrg    OUTREG(index_reg,0x20702);
1100c503f109Smrg    OUTREG(data_reg,0xBF0087C0);
1101c503f109Smrg    OUTREG(index_reg,0x20703);
1102c503f109Smrg    OUTREG(data_reg,0x80008008);
1103c503f109Smrg    OUTREG(index_reg,0x20800);
1104c503f109Smrg    OUTREG(data_reg,0x80108000);
1105c503f109Smrg    OUTREG(index_reg,0x20801);
1106c503f109Smrg    OUTREG(data_reg,0x8920BED0);
1107c503f109Smrg    OUTREG(index_reg,0x20802);
1108c503f109Smrg    OUTREG(data_reg,0xBED08920);
1109c503f109Smrg    OUTREG(index_reg,0x20803);
1110c503f109Smrg    OUTREG(data_reg,0x80008010);
1111c503f109Smrg    OUTREG(index_reg,0x30000);
1112c503f109Smrg    OUTREG(data_reg,0x90008000);
1113c503f109Smrg    OUTREG(index_reg,0x30001);
1114c503f109Smrg    OUTREG(data_reg,0x80008000);
1115c503f109Smrg    OUTREG(index_reg,0x30100);
1116c503f109Smrg    OUTREG(data_reg,0x8FE0BF90);
1117c503f109Smrg    OUTREG(index_reg,0x30101);
1118c503f109Smrg    OUTREG(data_reg,0xBFF880A0);
1119c503f109Smrg    OUTREG(index_reg,0x30200);
1120c503f109Smrg    OUTREG(data_reg,0x8F60BF40);
1121c503f109Smrg    OUTREG(index_reg,0x30201);
1122c503f109Smrg    OUTREG(data_reg,0xBFE88180);
1123c503f109Smrg    OUTREG(index_reg,0x30300);
1124c503f109Smrg    OUTREG(data_reg,0x8EC0BF00);
1125c503f109Smrg    OUTREG(index_reg,0x30301);
1126c503f109Smrg    OUTREG(data_reg,0xBFC88280);
1127c503f109Smrg    OUTREG(index_reg,0x30400);
1128c503f109Smrg    OUTREG(data_reg,0x8DE0BEE0);
1129c503f109Smrg    OUTREG(index_reg,0x30401);
1130c503f109Smrg    OUTREG(data_reg,0xBFA083A0);
1131c503f109Smrg    OUTREG(index_reg,0x30500);
1132c503f109Smrg    OUTREG(data_reg,0x8CE0BED0);
1133c503f109Smrg    OUTREG(index_reg,0x30501);
1134c503f109Smrg    OUTREG(data_reg,0xBF7884E0);
1135c503f109Smrg    OUTREG(index_reg,0x30600);
1136c503f109Smrg    OUTREG(data_reg,0x8BA0BED8);
1137c503f109Smrg    OUTREG(index_reg,0x30601);
1138c503f109Smrg    OUTREG(data_reg,0xBF508640);
1139c503f109Smrg    OUTREG(index_reg,0x30700);
1140c503f109Smrg    OUTREG(data_reg,0x8A60BEE8);
1141c503f109Smrg    OUTREG(index_reg,0x30701);
1142c503f109Smrg    OUTREG(data_reg,0xBF2087A0);
1143c503f109Smrg    OUTREG(index_reg,0x30800);
1144c503f109Smrg    OUTREG(data_reg,0x8900BF00);
1145c503f109Smrg    OUTREG(index_reg,0x30801);
1146c503f109Smrg    OUTREG(data_reg,0xBF008900);
1147b7e1c893Smrg}
1148b7e1c893Smrg
1149209ff23fSmrgstatic int
1150b7e1c893Smrgatombios_output_yuv_setup(xf86OutputPtr output, Bool enable)
1151209ff23fSmrg{
1152209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1153209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1154b7e1c893Smrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1155b7e1c893Smrg    ENABLE_YUV_PS_ALLOCATION disp_data;
1156209ff23fSmrg    AtomBiosArgRec data;
1157209ff23fSmrg    unsigned char *space;
1158b7e1c893Smrg    unsigned char *RADEONMMIO = info->MMIO;
1159b7e1c893Smrg    uint32_t temp, reg;
1160209ff23fSmrg
1161b7e1c893Smrg    if (info->ChipFamily >= CHIP_FAMILY_R600)
1162b7e1c893Smrg	reg = R600_BIOS_3_SCRATCH;
1163b7e1c893Smrg    else
1164b7e1c893Smrg	reg = RADEON_BIOS_3_SCRATCH;
1165b7e1c893Smrg
1166b7e1c893Smrg    //fix up scratch reg handling
1167b7e1c893Smrg    temp = INREG(reg);
1168b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1169b7e1c893Smrg	OUTREG(reg, (ATOM_S3_TV1_ACTIVE |
1170b7e1c893Smrg		     (radeon_crtc->crtc_id << 18)));
1171b7e1c893Smrg    else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1172b7e1c893Smrg	OUTREG(reg, (ATOM_S3_CV_ACTIVE |
1173b7e1c893Smrg		     (radeon_crtc->crtc_id << 24)));
1174b7e1c893Smrg    else
1175b7e1c893Smrg	OUTREG(reg, 0);
1176209ff23fSmrg
1177b7e1c893Smrg    memset(&disp_data, 0, sizeof(disp_data));
1178209ff23fSmrg
1179b7e1c893Smrg    if (enable)
1180b7e1c893Smrg	disp_data.ucEnable = ATOM_ENABLE;
1181b7e1c893Smrg    disp_data.ucCRTC = radeon_crtc->crtc_id;
1182209ff23fSmrg
1183b7e1c893Smrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableYUV);
1184209ff23fSmrg    data.exec.dataSpace = (void *)&space;
1185209ff23fSmrg    data.exec.pspace = &disp_data;
1186209ff23fSmrg
1187209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
1188b7e1c893Smrg
1189b7e1c893Smrg	OUTREG(reg, temp);
1190b7e1c893Smrg
1191b7e1c893Smrg	ErrorF("crtc %d YUV %s setup success\n", radeon_crtc->crtc_id, enable ? "enable" : "disable");
1192209ff23fSmrg	return ATOM_SUCCESS;
1193209ff23fSmrg    }
1194209ff23fSmrg
1195b7e1c893Smrg    OUTREG(reg, temp);
1196b7e1c893Smrg
1197b7e1c893Smrg    ErrorF("crtc %d YUV %s setup failed\n", radeon_crtc->crtc_id, enable ? "enable" : "disable");
1198209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
1199209ff23fSmrg
1200209ff23fSmrg}
1201209ff23fSmrg
1202209ff23fSmrgstatic int
1203b7e1c893Smrgatombios_output_overscan_setup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
1204209ff23fSmrg{
1205209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1206b7e1c893Smrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1207209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1208b7e1c893Smrg    SET_CRTC_OVERSCAN_PS_ALLOCATION overscan_param;
1209209ff23fSmrg    AtomBiosArgRec data;
1210209ff23fSmrg    unsigned char *space;
1211b7e1c893Smrg    memset(&overscan_param, 0, sizeof(overscan_param));
1212209ff23fSmrg
1213b7e1c893Smrg    overscan_param.usOverscanRight = 0;
1214b7e1c893Smrg    overscan_param.usOverscanLeft = 0;
1215b7e1c893Smrg    overscan_param.usOverscanBottom = 0;
1216b7e1c893Smrg    overscan_param.usOverscanTop = 0;
1217b7e1c893Smrg    overscan_param.ucCRTC = radeon_crtc->crtc_id;
1218b7e1c893Smrg
1219b7e1c893Smrg    if (radeon_output->Flags & RADEON_USE_RMX) {
1220b7e1c893Smrg	if (radeon_output->rmx_type == RMX_FULL) {
1221b7e1c893Smrg	    overscan_param.usOverscanRight = 0;
1222b7e1c893Smrg	    overscan_param.usOverscanLeft = 0;
1223b7e1c893Smrg	    overscan_param.usOverscanBottom = 0;
1224b7e1c893Smrg	    overscan_param.usOverscanTop = 0;
1225b7e1c893Smrg	} else if (radeon_output->rmx_type == RMX_CENTER) {
1226b7e1c893Smrg	    overscan_param.usOverscanTop = (adjusted_mode->CrtcVDisplay - mode->CrtcVDisplay) / 2;
1227b7e1c893Smrg	    overscan_param.usOverscanBottom = (adjusted_mode->CrtcVDisplay - mode->CrtcVDisplay) / 2;
1228b7e1c893Smrg	    overscan_param.usOverscanLeft = (adjusted_mode->CrtcHDisplay - mode->CrtcHDisplay) / 2;
1229b7e1c893Smrg	    overscan_param.usOverscanRight = (adjusted_mode->CrtcHDisplay - mode->CrtcHDisplay) / 2;
1230b7e1c893Smrg	} else if (radeon_output->rmx_type == RMX_ASPECT) {
1231b7e1c893Smrg	    int a1 = mode->CrtcVDisplay * adjusted_mode->CrtcHDisplay;
1232b7e1c893Smrg	    int a2 = adjusted_mode->CrtcVDisplay * mode->CrtcHDisplay;
1233b7e1c893Smrg
1234b7e1c893Smrg	    if (a1 > a2) {
1235b7e1c893Smrg		overscan_param.usOverscanLeft = (adjusted_mode->CrtcHDisplay - (a2 / mode->CrtcVDisplay)) / 2;
1236b7e1c893Smrg		overscan_param.usOverscanRight = (adjusted_mode->CrtcHDisplay - (a2 / mode->CrtcVDisplay)) / 2;
1237b7e1c893Smrg	    } else if (a2 > a1) {
1238b7e1c893Smrg		overscan_param.usOverscanLeft = (adjusted_mode->CrtcVDisplay - (a1 / mode->CrtcHDisplay)) / 2;
1239b7e1c893Smrg		overscan_param.usOverscanRight = (adjusted_mode->CrtcVDisplay - (a1 / mode->CrtcHDisplay)) / 2;
1240b7e1c893Smrg	    }
1241209ff23fSmrg	}
1242209ff23fSmrg    }
1243209ff23fSmrg
1244b7e1c893Smrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan);
1245209ff23fSmrg    data.exec.dataSpace = (void *)&space;
1246b7e1c893Smrg    data.exec.pspace = &overscan_param;
1247209ff23fSmrg
1248209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
1249b7e1c893Smrg	ErrorF("Set CRTC %d Overscan success\n", radeon_crtc->crtc_id);
1250b7e1c893Smrg	return ATOM_SUCCESS ;
1251209ff23fSmrg    }
1252209ff23fSmrg
1253b7e1c893Smrg    ErrorF("Set CRTC %d Overscan failed\n", radeon_crtc->crtc_id);
1254209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
1255209ff23fSmrg}
1256209ff23fSmrg
1257209ff23fSmrgstatic int
1258b7e1c893Smrgatombios_output_scaler_setup(xf86OutputPtr output)
1259209ff23fSmrg{
1260209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1261209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1262b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
1263209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1264209ff23fSmrg    ENABLE_SCALER_PS_ALLOCATION disp_data;
1265209ff23fSmrg    AtomBiosArgRec data;
1266209ff23fSmrg    unsigned char *space;
1267209ff23fSmrg
1268b7e1c893Smrg    if (!IS_AVIVO_VARIANT && radeon_crtc->crtc_id)
1269b7e1c893Smrg	return ATOM_SUCCESS;
1270b7e1c893Smrg
1271b7e1c893Smrg    memset(&disp_data, 0, sizeof(disp_data));
1272b7e1c893Smrg
1273209ff23fSmrg    disp_data.ucScaler = radeon_crtc->crtc_id;
1274209ff23fSmrg
1275b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
1276b7e1c893Smrg	switch (tvout->tvStd) {
1277b7e1c893Smrg	case TV_STD_NTSC:
1278b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_NTSC;
1279b7e1c893Smrg	    break;
1280b7e1c893Smrg	case TV_STD_PAL:
1281b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_PAL;
1282b7e1c893Smrg	    break;
1283b7e1c893Smrg	case TV_STD_PAL_M:
1284b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_PALM;
1285b7e1c893Smrg	    break;
1286b7e1c893Smrg	case TV_STD_PAL_60:
1287b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_PAL60;
1288b7e1c893Smrg	    break;
1289b7e1c893Smrg	case TV_STD_NTSC_J:
1290b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_NTSCJ;
1291b7e1c893Smrg	    break;
1292b7e1c893Smrg	case TV_STD_SCART_PAL:
1293b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_PAL; /* ??? */
1294b7e1c893Smrg	    break;
1295b7e1c893Smrg	case TV_STD_SECAM:
1296b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_SECAM;
1297b7e1c893Smrg	    break;
1298b7e1c893Smrg	case TV_STD_PAL_CN:
1299b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_PALCN;
1300b7e1c893Smrg	    break;
1301b7e1c893Smrg	default:
1302b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_NTSC;
1303b7e1c893Smrg	    break;
1304b7e1c893Smrg	}
1305b7e1c893Smrg	disp_data.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
1306b7e1c893Smrg        ErrorF("Using TV scaler %x %x\n", disp_data.ucTVStandard, disp_data.ucEnable);
1307b7e1c893Smrg    } else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) {
1308b7e1c893Smrg	disp_data.ucTVStandard = ATOM_TV_CV;
1309b7e1c893Smrg	disp_data.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
1310b7e1c893Smrg        ErrorF("Using CV scaler %x %x\n", disp_data.ucTVStandard, disp_data.ucEnable);
1311b7e1c893Smrg    } else if (radeon_output->Flags & RADEON_USE_RMX) {
1312209ff23fSmrg	ErrorF("Using RMX\n");
1313209ff23fSmrg	if (radeon_output->rmx_type == RMX_FULL)
1314209ff23fSmrg	    disp_data.ucEnable = ATOM_SCALER_EXPANSION;
1315209ff23fSmrg	else if (radeon_output->rmx_type == RMX_CENTER)
1316209ff23fSmrg	    disp_data.ucEnable = ATOM_SCALER_CENTER;
1317b7e1c893Smrg	else if (radeon_output->rmx_type == RMX_ASPECT)
1318b7e1c893Smrg	    disp_data.ucEnable = ATOM_SCALER_EXPANSION;
1319209ff23fSmrg    } else {
1320209ff23fSmrg	ErrorF("Not using RMX\n");
1321b7e1c893Smrg	if (IS_AVIVO_VARIANT)
1322b7e1c893Smrg	    disp_data.ucEnable = ATOM_SCALER_DISABLE;
1323b7e1c893Smrg	else
1324b7e1c893Smrg	    disp_data.ucEnable = ATOM_SCALER_CENTER;
1325209ff23fSmrg    }
1326209ff23fSmrg
1327209ff23fSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
1328209ff23fSmrg    data.exec.dataSpace = (void *)&space;
1329209ff23fSmrg    data.exec.pspace = &disp_data;
1330209ff23fSmrg
1331209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
1332b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)
1333b7e1c893Smrg	    && info->ChipFamily >= CHIP_FAMILY_RV515 && info->ChipFamily <= CHIP_FAMILY_RV570) {
1334b7e1c893Smrg	    ErrorF("forcing TV scaler\n");
1335c503f109Smrg	    atom_rv515_force_tv_scaler(output->scrn, radeon_crtc);
1336b7e1c893Smrg	}
1337209ff23fSmrg	ErrorF("scaler %d setup success\n", radeon_crtc->crtc_id);
1338209ff23fSmrg	return ATOM_SUCCESS;
1339209ff23fSmrg    }
1340209ff23fSmrg
1341209ff23fSmrg    ErrorF("scaler %d setup failed\n", radeon_crtc->crtc_id);
1342209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
1343209ff23fSmrg
1344209ff23fSmrg}
1345209ff23fSmrg
1346b7e1c893Smrgvoid
1347b7e1c893Smrgatombios_output_dpms(xf86OutputPtr output, int mode)
1348209ff23fSmrg{
1349b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1350b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
1351209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1352209ff23fSmrg    DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION disp_data;
1353209ff23fSmrg    AtomBiosArgRec data;
1354209ff23fSmrg    unsigned char *space;
1355209ff23fSmrg    int index = 0;
1356b7e1c893Smrg    Bool is_dig = FALSE;
1357209ff23fSmrg
1358b7e1c893Smrg    if (radeon_encoder == NULL)
1359b7e1c893Smrg        return;
1360b7e1c893Smrg
1361b7e1c893Smrg    switch (radeon_encoder->encoder_id) {
1362b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1363b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
1364209ff23fSmrg	index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl);
1365209ff23fSmrg	break;
1366b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1367b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1368b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1369b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1370b7e1c893Smrg	is_dig = TRUE;
1371209ff23fSmrg	break;
1372b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1373b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DDI:
1374b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
1375b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
1376209ff23fSmrg	break;
1377b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
1378209ff23fSmrg	index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
1379209ff23fSmrg	break;
1380b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1381b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT))
1382b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
1383b7e1c893Smrg	else
1384b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl);
1385209ff23fSmrg	break;
1386b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
1387b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1388ad43ddacSmrg	if (IS_DCE32_VARIANT)
1389b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl);
1390ad43ddacSmrg	else {
1391ad43ddacSmrg	    if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1392ad43ddacSmrg		index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
1393ad43ddacSmrg	    else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1394ad43ddacSmrg		index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
1395ad43ddacSmrg	    else
1396ad43ddacSmrg		index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl);
1397ad43ddacSmrg	}
1398209ff23fSmrg	break;
1399b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1400b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1401ad43ddacSmrg	if (IS_DCE32_VARIANT)
1402b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl);
1403ad43ddacSmrg	else {
1404ad43ddacSmrg	    if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1405ad43ddacSmrg		index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
1406ad43ddacSmrg	    else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1407ad43ddacSmrg		index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
1408ad43ddacSmrg	    else
1409ad43ddacSmrg		index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl);
1410ad43ddacSmrg	}
1411209ff23fSmrg	break;
1412209ff23fSmrg    }
1413209ff23fSmrg
1414209ff23fSmrg    switch (mode) {
1415209ff23fSmrg    case DPMSModeOn:
1416b7e1c893Smrg	radeon_encoder->devices |= radeon_output->active_device;
1417ad43ddacSmrg	if (is_dig) {
1418ad43ddacSmrg	    atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0);
1419ad43ddacSmrg	    if (((radeon_output->ConnectorType == CONNECTOR_DISPLAY_PORT) ||
1420ad43ddacSmrg		 (radeon_output->ConnectorType == CONNECTOR_EDP)) &&
1421ad43ddacSmrg		(radeon_output->MonType == MT_DP)) {
1422ad43ddacSmrg		do_displayport_link_train(output);
1423ad43ddacSmrg		if (IS_DCE4_VARIANT)
1424ad43ddacSmrg		    atombios_dce4_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_VIDEO_ON);
1425ad43ddacSmrg	    }
1426ad43ddacSmrg	}
1427b7e1c893Smrg	else {
1428b7e1c893Smrg	    disp_data.ucAction = ATOM_ENABLE;
1429b7e1c893Smrg	    data.exec.index = index;
1430b7e1c893Smrg	    data.exec.dataSpace = (void *)&space;
1431b7e1c893Smrg	    data.exec.pspace = &disp_data;
1432b7e1c893Smrg
1433b7e1c893Smrg	    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS)
1434b7e1c893Smrg		ErrorF("Output %s enable success\n",
1435b7e1c893Smrg		       device_name[radeon_get_device_index(radeon_output->active_device)]);
1436b7e1c893Smrg	    else
1437b7e1c893Smrg		ErrorF("Output %s enable failed\n",
1438b7e1c893Smrg		       device_name[radeon_get_device_index(radeon_output->active_device)]);
1439b7e1c893Smrg	}
1440c503f109Smrg	/* at least for TV atom fails to reassociate the correct crtc source at dpms on */
1441c503f109Smrg	if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1442c503f109Smrg		atombios_set_output_crtc_source(output);
1443209ff23fSmrg	break;
1444209ff23fSmrg    case DPMSModeStandby:
1445209ff23fSmrg    case DPMSModeSuspend:
1446209ff23fSmrg    case DPMSModeOff:
1447b7e1c893Smrg	radeon_encoder->devices &= ~(radeon_output->active_device);
1448b7e1c893Smrg	if (!radeon_encoder->devices) {
1449ad43ddacSmrg	    if (is_dig) {
1450ad43ddacSmrg		if (((radeon_output->ConnectorType == CONNECTOR_DISPLAY_PORT) ||
1451ad43ddacSmrg		     (radeon_output->ConnectorType == CONNECTOR_EDP)) &&
1452ad43ddacSmrg		    (radeon_output->MonType == MT_DP)) {
1453ad43ddacSmrg		    if (IS_DCE4_VARIANT)
1454ad43ddacSmrg			atombios_dce4_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_VIDEO_OFF);
1455ad43ddacSmrg		}
1456ad43ddacSmrg		atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0);
1457ad43ddacSmrg	    } else {
1458b7e1c893Smrg		disp_data.ucAction = ATOM_DISABLE;
1459b7e1c893Smrg		data.exec.index = index;
1460b7e1c893Smrg		data.exec.dataSpace = (void *)&space;
1461b7e1c893Smrg		data.exec.pspace = &disp_data;
1462b7e1c893Smrg
1463b7e1c893Smrg		if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data)
1464b7e1c893Smrg		    == ATOM_SUCCESS)
1465b7e1c893Smrg		    ErrorF("Output %s disable success\n",
1466b7e1c893Smrg			   device_name[radeon_get_device_index(radeon_output->active_device)]);
1467b7e1c893Smrg		else
1468b7e1c893Smrg		    ErrorF("Output %s disable failed\n",
1469b7e1c893Smrg			   device_name[radeon_get_device_index(radeon_output->active_device)]);
1470b7e1c893Smrg	    }
1471209ff23fSmrg	}
1472b7e1c893Smrg	break;
1473209ff23fSmrg    }
1474209ff23fSmrg}
1475209ff23fSmrg
1476209ff23fSmrgstatic void
1477209ff23fSmrgatombios_set_output_crtc_source(xf86OutputPtr output)
1478209ff23fSmrg{
1479209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1480209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1481209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1482b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
1483209ff23fSmrg    AtomBiosArgRec data;
1484209ff23fSmrg    unsigned char *space;
1485209ff23fSmrg    SELECT_CRTC_SOURCE_PS_ALLOCATION crtc_src_param;
1486209ff23fSmrg    SELECT_CRTC_SOURCE_PARAMETERS_V2 crtc_src_param2;
1487209ff23fSmrg    int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source);
1488209ff23fSmrg    int major, minor;
1489209ff23fSmrg
1490b7e1c893Smrg    if (radeon_encoder == NULL)
1491b7e1c893Smrg	return;
1492b7e1c893Smrg
1493b7e1c893Smrg    memset(&crtc_src_param, 0, sizeof(crtc_src_param));
1494b7e1c893Smrg    memset(&crtc_src_param2, 0, sizeof(crtc_src_param2));
1495209ff23fSmrg    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
1496209ff23fSmrg
1497209ff23fSmrg    /*ErrorF("select crtc source table is %d %d\n", major, minor);*/
1498209ff23fSmrg
1499209ff23fSmrg    switch(major) {
1500b7e1c893Smrg    case 1:
1501209ff23fSmrg	switch(minor) {
1502209ff23fSmrg	case 0:
1503209ff23fSmrg	case 1:
1504209ff23fSmrg	default:
1505b7e1c893Smrg	    if (IS_AVIVO_VARIANT)
1506b7e1c893Smrg		crtc_src_param.ucCRTC = radeon_crtc->crtc_id;
1507b7e1c893Smrg	    else {
1508b7e1c893Smrg		if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1)
1509b7e1c893Smrg		    crtc_src_param.ucCRTC = radeon_crtc->crtc_id;
1510b7e1c893Smrg		else
1511b7e1c893Smrg		    crtc_src_param.ucCRTC = radeon_crtc->crtc_id << 2;
1512b7e1c893Smrg	    }
1513b7e1c893Smrg	    switch (radeon_encoder->encoder_id) {
1514b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1515b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
1516b7e1c893Smrg		crtc_src_param.ucDevice = ATOM_DEVICE_DFP1_INDEX;
1517b7e1c893Smrg		break;
1518b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
1519b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1520b7e1c893Smrg		if (radeon_output->active_device & ATOM_DEVICE_LCD1_SUPPORT)
1521209ff23fSmrg		    crtc_src_param.ucDevice = ATOM_DEVICE_LCD1_INDEX;
1522b7e1c893Smrg		else
1523b7e1c893Smrg		    crtc_src_param.ucDevice = ATOM_DEVICE_DFP3_INDEX;
1524b7e1c893Smrg		break;
1525b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1526b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DDI:
1527b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
1528b7e1c893Smrg		crtc_src_param.ucDevice = ATOM_DEVICE_DFP2_INDEX;
1529b7e1c893Smrg		break;
1530b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
1531b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1532b7e1c893Smrg		if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1533b7e1c893Smrg		    crtc_src_param.ucDevice = ATOM_DEVICE_TV1_INDEX;
1534b7e1c893Smrg		else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1535b7e1c893Smrg		    crtc_src_param.ucDevice = ATOM_DEVICE_CV_INDEX;
1536b7e1c893Smrg		else
1537b7e1c893Smrg		    crtc_src_param.ucDevice = ATOM_DEVICE_CRT1_INDEX;
1538b7e1c893Smrg		break;
1539b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1540b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1541b7e1c893Smrg		if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1542209ff23fSmrg		    crtc_src_param.ucDevice = ATOM_DEVICE_TV1_INDEX;
1543b7e1c893Smrg		else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1544209ff23fSmrg		    crtc_src_param.ucDevice = ATOM_DEVICE_CV_INDEX;
1545b7e1c893Smrg		else
1546b7e1c893Smrg		    crtc_src_param.ucDevice = ATOM_DEVICE_CRT2_INDEX;
1547b7e1c893Smrg		break;
1548209ff23fSmrg	    }
1549209ff23fSmrg	    data.exec.pspace = &crtc_src_param;
1550209ff23fSmrg	    /*ErrorF("device sourced: 0x%x\n", crtc_src_param.ucDevice);*/
1551209ff23fSmrg	    break;
1552209ff23fSmrg	case 2:
1553209ff23fSmrg	    crtc_src_param2.ucCRTC = radeon_crtc->crtc_id;
1554b7e1c893Smrg	    crtc_src_param2.ucEncodeMode = atombios_get_encoder_mode(output);
1555b7e1c893Smrg	    switch (radeon_encoder->encoder_id) {
1556b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1557b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1558b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1559b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1560ad43ddacSmrg 		switch (radeon_output->dig_encoder) {
1561ad43ddacSmrg 		case 0:
1562ad43ddacSmrg 		    crtc_src_param2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
1563ad43ddacSmrg 		    break;
1564ad43ddacSmrg 		case 1:
1565ad43ddacSmrg 		    crtc_src_param2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
1566ad43ddacSmrg 		    break;
1567ad43ddacSmrg 		case 2:
1568ad43ddacSmrg 		    crtc_src_param2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID;
1569ad43ddacSmrg 		    break;
1570ad43ddacSmrg 		case 3:
1571ad43ddacSmrg 		    crtc_src_param2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID;
1572ad43ddacSmrg 		    break;
1573ad43ddacSmrg 		case 4:
1574ad43ddacSmrg 		    crtc_src_param2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID;
1575ad43ddacSmrg 		    break;
1576ad43ddacSmrg 		case 5:
1577ad43ddacSmrg 		    crtc_src_param2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID;
1578ad43ddacSmrg 		    break;
1579ad43ddacSmrg 		}
1580b7e1c893Smrg		break;
1581b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1582b7e1c893Smrg		if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1583b7e1c893Smrg		    crtc_src_param2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1584b7e1c893Smrg		else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1585b7e1c893Smrg		    crtc_src_param2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1586b7e1c893Smrg		else
1587b7e1c893Smrg		    crtc_src_param2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID;
1588b7e1c893Smrg		break;
1589b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1590b7e1c893Smrg		if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1591b7e1c893Smrg		    crtc_src_param2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1592b7e1c893Smrg		else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1593b7e1c893Smrg		    crtc_src_param2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1594b7e1c893Smrg		else
1595b7e1c893Smrg		    crtc_src_param2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID;
1596b7e1c893Smrg		break;
1597209ff23fSmrg	    }
1598209ff23fSmrg	    data.exec.pspace = &crtc_src_param2;
1599209ff23fSmrg	    /*ErrorF("device sourced: 0x%x\n", crtc_src_param2.ucEncoderID);*/
1600209ff23fSmrg	    break;
1601209ff23fSmrg	}
1602209ff23fSmrg	break;
1603209ff23fSmrg    default:
1604b7e1c893Smrg	ErrorF("Unknown table version\n");
1605b7e1c893Smrg	exit(-1);
1606209ff23fSmrg    }
1607209ff23fSmrg
1608209ff23fSmrg    data.exec.index = index;
1609209ff23fSmrg    data.exec.dataSpace = (void *)&space;
1610209ff23fSmrg
1611209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
1612209ff23fSmrg	ErrorF("Set CRTC %d Source success\n", radeon_crtc->crtc_id);
1613209ff23fSmrg	return;
1614209ff23fSmrg    }
1615209ff23fSmrg
1616209ff23fSmrg    ErrorF("Set CRTC Source failed\n");
1617209ff23fSmrg    return;
1618209ff23fSmrg}
1619209ff23fSmrg
1620b7e1c893Smrgstatic void
1621b7e1c893Smrgatombios_apply_output_quirks(xf86OutputPtr output, DisplayModePtr mode)
1622b7e1c893Smrg{
1623b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1624b7e1c893Smrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1625b7e1c893Smrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1626b7e1c893Smrg    unsigned char *RADEONMMIO = info->MMIO;
1627b7e1c893Smrg
1628b7e1c893Smrg    /* Funky macbooks */
1629b7e1c893Smrg    if ((info->Chipset == PCI_CHIP_RV530_71C5) &&
1630b7e1c893Smrg	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x106b) &&
1631b7e1c893Smrg	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x0080)) {
1632b7e1c893Smrg	if (radeon_output->MonType == MT_LCD) {
1633b7e1c893Smrg	    if (radeon_output->devices & ATOM_DEVICE_LCD1_SUPPORT) {
1634b7e1c893Smrg		uint32_t lvtma_bit_depth_control = INREG(AVIVO_LVTMA_BIT_DEPTH_CONTROL);
1635b7e1c893Smrg
1636b7e1c893Smrg		lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN;
1637b7e1c893Smrg		lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN;
1638b7e1c893Smrg
1639b7e1c893Smrg		OUTREG(AVIVO_LVTMA_BIT_DEPTH_CONTROL, lvtma_bit_depth_control);
1640b7e1c893Smrg	    }
1641b7e1c893Smrg	}
1642b7e1c893Smrg    }
1643b7e1c893Smrg
1644b7e1c893Smrg    /* set scaler clears this on some chips */
1645ad43ddacSmrg    if (!(radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT))) {
1646ad43ddacSmrg	if (IS_AVIVO_VARIANT && (mode->Flags & V_INTERLACE))
1647ad43ddacSmrg	    OUTREG(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, AVIVO_D1MODE_INTERLEAVE_EN);
1648ad43ddacSmrg    }
1649ad43ddacSmrg
1650ad43ddacSmrg    if (IS_DCE32_VARIANT &&
1651ad43ddacSmrg	(!IS_DCE4_VARIANT) &&
1652ad43ddacSmrg	(radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT))) {
1653ad43ddacSmrg	radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
1654ad43ddacSmrg	if (radeon_encoder == NULL)
1655ad43ddacSmrg	    return;
1656ad43ddacSmrg	/* XXX: need to sort out why transmitter control table sometimes sets this to a
1657ad43ddacSmrg	 * different golden value.
1658ad43ddacSmrg	 */
1659ad43ddacSmrg	if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY2) {
1660ad43ddacSmrg	    OUTREG(0x7ec4, 0x00824002);
1661ad43ddacSmrg	}
1662ad43ddacSmrg    }
1663b7e1c893Smrg}
1664b7e1c893Smrg
1665ad43ddacSmrgstatic void
1666ad43ddacSmrgatombios_pick_dig_encoder(xf86OutputPtr output)
1667ad43ddacSmrg{
1668ad43ddacSmrg    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(output->scrn);
1669ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1670ad43ddacSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1671ad43ddacSmrg    radeon_encoder_ptr radeon_encoder = NULL;
1672ad43ddacSmrg    Bool is_lvtma = FALSE;
1673ad43ddacSmrg    int i, mode;
1674ad43ddacSmrg    uint32_t dig_enc_use_mask = 0;
1675ad43ddacSmrg
1676ad43ddacSmrg    /* non digital encoders don't need a dig block */
1677ad43ddacSmrg    mode = atombios_get_encoder_mode(output);
1678ad43ddacSmrg    if (mode == ATOM_ENCODER_MODE_CRT ||
1679ad43ddacSmrg        mode == ATOM_ENCODER_MODE_TV ||
1680ad43ddacSmrg        mode == ATOM_ENCODER_MODE_CV)
1681ad43ddacSmrg        return;
1682ad43ddacSmrg
1683ad43ddacSmrg    if (IS_DCE4_VARIANT) {
1684ad43ddacSmrg        radeon_encoder = radeon_get_encoder(output);
1685ad43ddacSmrg
1686ad43ddacSmrg	switch (radeon_encoder->encoder_id) {
1687ad43ddacSmrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1688ad43ddacSmrg	    if (radeon_output->linkb)
1689ad43ddacSmrg		radeon_output->dig_encoder = 1;
1690ad43ddacSmrg	    else
1691ad43ddacSmrg		radeon_output->dig_encoder = 0;
1692ad43ddacSmrg	    break;
1693ad43ddacSmrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1694ad43ddacSmrg	    if (radeon_output->linkb)
1695ad43ddacSmrg		radeon_output->dig_encoder = 3;
1696ad43ddacSmrg	    else
1697ad43ddacSmrg		radeon_output->dig_encoder = 2;
1698ad43ddacSmrg	    break;
1699ad43ddacSmrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1700ad43ddacSmrg	    if (radeon_output->linkb)
1701ad43ddacSmrg		radeon_output->dig_encoder = 5;
1702ad43ddacSmrg	    else
1703ad43ddacSmrg		radeon_output->dig_encoder = 4;
1704ad43ddacSmrg	    break;
1705ad43ddacSmrg	default:
1706ad43ddacSmrg	    ErrorF("Unknown encoder\n");
1707ad43ddacSmrg	    break;
1708ad43ddacSmrg	}
1709ad43ddacSmrg	return;
1710ad43ddacSmrg    }
1711ad43ddacSmrg
1712ad43ddacSmrg    if (IS_DCE32_VARIANT) {
1713ad43ddacSmrg        RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1714ad43ddacSmrg        radeon_output->dig_encoder = radeon_crtc->crtc_id;
1715ad43ddacSmrg        return;
1716ad43ddacSmrg    }
1717ad43ddacSmrg
1718ad43ddacSmrg    for (i = 0; i < xf86_config->num_output; i++) {
1719ad43ddacSmrg        xf86OutputPtr test = xf86_config->output[i];
1720ad43ddacSmrg        RADEONOutputPrivatePtr radeon_test = test->driver_private;
1721ad43ddacSmrg        radeon_encoder = radeon_get_encoder(test);
1722ad43ddacSmrg
1723ad43ddacSmrg        if (!radeon_encoder || !test->crtc)
1724ad43ddacSmrg            continue;
1725ad43ddacSmrg
1726ad43ddacSmrg        if (output == test && radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA)
1727ad43ddacSmrg            is_lvtma = TRUE;
1728ad43ddacSmrg        if (output != test && (radeon_test->dig_encoder >= 0))
1729ad43ddacSmrg            dig_enc_use_mask |= (1 << radeon_test->dig_encoder);
1730ad43ddacSmrg
1731ad43ddacSmrg    }
1732ad43ddacSmrg    if (is_lvtma) {
1733ad43ddacSmrg        if (dig_enc_use_mask & 0x2)
1734ad43ddacSmrg            ErrorF("Need digital encoder 2 for LVTMA and it isn't free - stealing\n");
1735ad43ddacSmrg        radeon_output->dig_encoder = 1;
1736ad43ddacSmrg        return;
1737ad43ddacSmrg    }
1738ad43ddacSmrg    if (!(dig_enc_use_mask & 1))
1739ad43ddacSmrg        radeon_output->dig_encoder = 0;
1740ad43ddacSmrg    else
1741ad43ddacSmrg        radeon_output->dig_encoder = 1;
1742ad43ddacSmrg}
1743209ff23fSmrgvoid
1744209ff23fSmrgatombios_output_mode_set(xf86OutputPtr output,
1745209ff23fSmrg			 DisplayModePtr mode,
1746209ff23fSmrg			 DisplayModePtr adjusted_mode)
1747209ff23fSmrg{
1748209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1749b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
1750209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1751b7e1c893Smrg    if (radeon_encoder == NULL)
1752ad43ddacSmrg	return;
1753209ff23fSmrg
1754b7e1c893Smrg    radeon_output->pixel_clock = adjusted_mode->Clock;
1755ad43ddacSmrg    atombios_pick_dig_encoder(output);
1756b7e1c893Smrg    atombios_output_overscan_setup(output, mode, adjusted_mode);
1757b7e1c893Smrg    atombios_output_scaler_setup(output);
1758209ff23fSmrg    atombios_set_output_crtc_source(output);
1759209ff23fSmrg
1760b7e1c893Smrg    if (IS_AVIVO_VARIANT) {
1761b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT))
1762b7e1c893Smrg	    atombios_output_yuv_setup(output, TRUE);
1763b7e1c893Smrg	else
1764b7e1c893Smrg	    atombios_output_yuv_setup(output, FALSE);
1765209ff23fSmrg    }
1766209ff23fSmrg
1767b7e1c893Smrg    switch (radeon_encoder->encoder_id) {
1768b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1769b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
1770b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
1771b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1772b7e1c893Smrg	atombios_output_digital_setup(output, PANEL_ENCODER_ACTION_ENABLE);
1773b7e1c893Smrg	break;
1774b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1775b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1776b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1777b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1778b7e1c893Smrg	/* disable encoder and transmitter */
1779b7e1c893Smrg	/* setup and enable the encoder and transmitter */
1780ad43ddacSmrg	atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
1781ad43ddacSmrg	if (IS_DCE4_VARIANT)
1782ad43ddacSmrg	    atombios_dce4_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_SETUP);
1783ad43ddacSmrg	else {
1784ad43ddacSmrg	    atombios_output_dig_encoder_setup(output, ATOM_DISABLE);
1785ad43ddacSmrg	    atombios_output_dig_encoder_setup(output, ATOM_ENABLE);
1786ad43ddacSmrg	}
1787b7e1c893Smrg	atombios_output_dig_encoder_setup(output, ATOM_ENABLE);
1788ad43ddacSmrg	atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
1789ad43ddacSmrg	atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0);
1790ad43ddacSmrg	atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
1791b7e1c893Smrg	break;
1792b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DDI:
1793b7e1c893Smrg	atombios_output_ddia_setup(output, ATOM_ENABLE);
1794b7e1c893Smrg	break;
1795b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1796b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
1797b7e1c893Smrg	atombios_external_tmds_setup(output, ATOM_ENABLE);
1798b7e1c893Smrg	break;
1799b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
1800b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1801b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1802b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1803b7e1c893Smrg	atombios_output_dac_setup(output, ATOM_ENABLE);
18042f39173dSmrg	if (radeon_output->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) {
18052f39173dSmrg		if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))
18062f39173dSmrg			atombios_output_tv_setup(output, ATOM_ENABLE);
18072f39173dSmrg		else
18082f39173dSmrg			atombios_output_tv_setup(output, ATOM_DISABLE);
18092f39173dSmrg	}
1810b7e1c893Smrg	break;
1811b7e1c893Smrg    }
1812b7e1c893Smrg    atombios_apply_output_quirks(output, adjusted_mode);
1813209ff23fSmrg}
1814209ff23fSmrg
1815209ff23fSmrgstatic AtomBiosResult
1816209ff23fSmrgatom_bios_dac_load_detect(atomBiosHandlePtr atomBIOS, xf86OutputPtr output)
1817209ff23fSmrg{
1818209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1819209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1820209ff23fSmrg    DAC_LOAD_DETECTION_PS_ALLOCATION dac_data;
1821209ff23fSmrg    AtomBiosArgRec data;
1822209ff23fSmrg    unsigned char *space;
1823b7e1c893Smrg    int major, minor;
1824b7e1c893Smrg    int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection);
1825b7e1c893Smrg
1826b7e1c893Smrg    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
1827209ff23fSmrg
1828209ff23fSmrg    dac_data.sDacload.ucMisc = 0;
1829209ff23fSmrg
1830209ff23fSmrg    if (radeon_output->devices & ATOM_DEVICE_CRT1_SUPPORT) {
1831b7e1c893Smrg	dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT);
1832b7e1c893Smrg	if (info->encoders[ATOM_DEVICE_CRT1_INDEX] &&
1833b7e1c893Smrg	    ((info->encoders[ATOM_DEVICE_CRT1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
1834b7e1c893Smrg	     (info->encoders[ATOM_DEVICE_CRT1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)))
1835209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_A;
1836b7e1c893Smrg	else
1837209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_B;
1838209ff23fSmrg    } else if (radeon_output->devices & ATOM_DEVICE_CRT2_SUPPORT) {
1839b7e1c893Smrg	dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT);
1840b7e1c893Smrg	if (info->encoders[ATOM_DEVICE_CRT2_INDEX] &&
1841b7e1c893Smrg	    ((info->encoders[ATOM_DEVICE_CRT2_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
1842b7e1c893Smrg	     (info->encoders[ATOM_DEVICE_CRT2_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)))
1843209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_A;
1844b7e1c893Smrg	else
1845209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_B;
1846209ff23fSmrg    } else if (radeon_output->devices & ATOM_DEVICE_CV_SUPPORT) {
1847b7e1c893Smrg	dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT);
1848b7e1c893Smrg	if (info->encoders[ATOM_DEVICE_CV_INDEX] &&
1849b7e1c893Smrg	    ((info->encoders[ATOM_DEVICE_CV_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
1850b7e1c893Smrg	     (info->encoders[ATOM_DEVICE_CV_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)))
1851209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_A;
1852b7e1c893Smrg	else
1853209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_B;
1854b7e1c893Smrg	if (minor >= 3)
1855b7e1c893Smrg	    dac_data.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
1856209ff23fSmrg    } else if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) {
1857b7e1c893Smrg	dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT);
1858b7e1c893Smrg	if (info->encoders[ATOM_DEVICE_TV1_INDEX] &&
1859b7e1c893Smrg	    ((info->encoders[ATOM_DEVICE_TV1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
1860b7e1c893Smrg	     (info->encoders[ATOM_DEVICE_TV1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)))
1861209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_A;
1862b7e1c893Smrg	else
1863209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_B;
1864b7e1c893Smrg	if (minor >= 3)
1865b7e1c893Smrg	    dac_data.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
1866b7e1c893Smrg    } else
1867209ff23fSmrg	return ATOM_NOT_IMPLEMENTED;
1868209ff23fSmrg
1869b7e1c893Smrg    data.exec.index = index;
1870209ff23fSmrg    data.exec.dataSpace = (void *)&space;
1871209ff23fSmrg    data.exec.pspace = &dac_data;
1872209ff23fSmrg
1873209ff23fSmrg    if (RHDAtomBiosFunc(atomBIOS->scrnIndex, atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
1874209ff23fSmrg	ErrorF("Dac detection success\n");
1875209ff23fSmrg	return ATOM_SUCCESS ;
1876209ff23fSmrg    }
1877209ff23fSmrg
1878209ff23fSmrg    ErrorF("DAC detection failed\n");
1879209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
1880209ff23fSmrg}
1881209ff23fSmrg
1882209ff23fSmrgRADEONMonitorType
1883b7e1c893Smrgatombios_dac_detect(xf86OutputPtr output)
1884209ff23fSmrg{
1885b7e1c893Smrg    ScrnInfoPtr pScrn = output->scrn;
1886209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
1887209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
1888209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1889209ff23fSmrg    RADEONMonitorType MonType = MT_NONE;
1890209ff23fSmrg    AtomBiosResult ret;
1891c503f109Smrg    RADEONSavePtr save = info->ModeReg;
1892209ff23fSmrg
1893b7e1c893Smrg    if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) {
1894209ff23fSmrg	if (xf86ReturnOptValBool(info->Options, OPTION_FORCE_TVOUT, FALSE)) {
1895b7e1c893Smrg	    if (radeon_output->ConnectorType == CONNECTOR_STV)
1896209ff23fSmrg		return MT_STV;
1897209ff23fSmrg	    else
1898209ff23fSmrg		return MT_CTV;
1899209ff23fSmrg	}
1900209ff23fSmrg    }
1901209ff23fSmrg
1902209ff23fSmrg    ret = atom_bios_dac_load_detect(info->atomBIOS, output);
1903209ff23fSmrg    if (ret == ATOM_SUCCESS) {
1904209ff23fSmrg	if (info->ChipFamily >= CHIP_FAMILY_R600)
1905c503f109Smrg	    save->bios_0_scratch = INREG(R600_BIOS_0_SCRATCH);
1906209ff23fSmrg	else
1907c503f109Smrg	    save->bios_0_scratch = INREG(RADEON_BIOS_0_SCRATCH);
1908c503f109Smrg	/*ErrorF("DAC connect %08X\n", (unsigned int)save->bios_0_scratch);*/
1909209ff23fSmrg
1910209ff23fSmrg	if (radeon_output->devices & ATOM_DEVICE_CRT1_SUPPORT) {
1911c503f109Smrg	    if (save->bios_0_scratch & ATOM_S0_CRT1_MASK)
1912209ff23fSmrg		MonType = MT_CRT;
1913209ff23fSmrg	} else if (radeon_output->devices & ATOM_DEVICE_CRT2_SUPPORT) {
1914c503f109Smrg	    if (save->bios_0_scratch & ATOM_S0_CRT2_MASK)
1915209ff23fSmrg		MonType = MT_CRT;
1916209ff23fSmrg	} else if (radeon_output->devices & ATOM_DEVICE_CV_SUPPORT) {
1917c503f109Smrg	    if (save->bios_0_scratch & (ATOM_S0_CV_MASK | ATOM_S0_CV_MASK_A))
1918209ff23fSmrg		MonType = MT_CV;
1919209ff23fSmrg	} else if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) {
1920c503f109Smrg	    if (save->bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A))
1921209ff23fSmrg		MonType = MT_CTV;
1922c503f109Smrg	    else if (save->bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A))
1923209ff23fSmrg		MonType = MT_STV;
1924209ff23fSmrg	}
1925209ff23fSmrg    }
1926209ff23fSmrg
1927209ff23fSmrg    return MonType;
1928209ff23fSmrg}
1929209ff23fSmrg
1930ad43ddacSmrg#define AUX_NATIVE_WRITE                    0x8
1931ad43ddacSmrg#define AUX_NATIVE_READ                     0x9
1932ad43ddacSmrg
1933ad43ddacSmrg#define AUX_I2C_WRITE                       0x0
1934ad43ddacSmrg#define AUX_I2C_READ                        0x1
1935ad43ddacSmrg#define AUX_I2C_STATUS                      0x2
1936ad43ddacSmrg#define AUX_I2C_MOT                         0x4
1937ad43ddacSmrg
1938ad43ddacSmrg#define DP_DPCD_REV                         0x0
1939ad43ddacSmrg#define DP_MAX_LINK_RATE                    0x1
1940ad43ddacSmrg#define DP_MAX_LANE_COUNT                   0x2
1941ad43ddacSmrg#define DP_MAX_DOWNSPREAD                   0x3
1942ad43ddacSmrg#define DP_NORP                             0x4
1943ad43ddacSmrg#define DP_DOWNSTREAMPORT_PRESENT           0x5
1944ad43ddacSmrg#define DP_MAIN_LINK_CHANNEL_CONFIG         0x6
1945ad43ddacSmrg#define DP_DP11_DOWNSTREAM_PORT_COUNT       0x7
1946ad43ddacSmrg
1947ad43ddacSmrg/* from intel i830_dp.h */
1948ad43ddacSmrg#define DP_LINK_BW_SET                      0x100
1949ad43ddacSmrg//# define DP_LINK_BW_1_62                    0x06
1950ad43ddacSmrg//# define DP_LINK_BW_2_7                     0x0a
1951ad43ddacSmrg#define DP_LANE_COUNT_SET                   0x101
1952ad43ddacSmrg# define DP_LANE_COUNT_MASK                 0x0f
1953ad43ddacSmrg# define DP_LANE_COUNT_ENHANCED_FRAME_EN    (1 << 7)
1954ad43ddacSmrg
1955ad43ddacSmrg#define DP_TRAINING_PATTERN_SET             0x102
1956ad43ddacSmrg
1957ad43ddacSmrg# define DP_TRAINING_PATTERN_DISABLE        0
1958ad43ddacSmrg# define DP_TRAINING_PATTERN_1              1
1959ad43ddacSmrg# define DP_TRAINING_PATTERN_2              2
1960ad43ddacSmrg# define DP_TRAINING_PATTERN_MASK           0x3
1961ad43ddacSmrg
1962ad43ddacSmrg# define DP_LINK_QUAL_PATTERN_DISABLE       (0 << 2)
1963ad43ddacSmrg# define DP_LINK_QUAL_PATTERN_D10_2         (1 << 2)
1964ad43ddacSmrg# define DP_LINK_QUAL_PATTERN_ERROR_RATE    (2 << 2)
1965ad43ddacSmrg# define DP_LINK_QUAL_PATTERN_PRBS7         (3 << 2)
1966ad43ddacSmrg# define DP_LINK_QUAL_PATTERN_MASK          (3 << 2)
1967ad43ddacSmrg# define DP_RECOVERED_CLOCK_OUT_EN          (1 << 4)
1968ad43ddacSmrg# define DP_LINK_SCRAMBLING_DISABLE         (1 << 5)
1969ad43ddacSmrg
1970ad43ddacSmrg# define DP_SYMBOL_ERROR_COUNT_BOTH         (0 << 6)
1971ad43ddacSmrg# define DP_SYMBOL_ERROR_COUNT_DISPARITY    (1 << 6)
1972ad43ddacSmrg# define DP_SYMBOL_ERROR_COUNT_SYMBOL       (2 << 6)
1973ad43ddacSmrg# define DP_SYMBOL_ERROR_COUNT_MASK         (3 << 6)
1974ad43ddacSmrg
1975ad43ddacSmrg#define DP_TRAINING_LANE0_SET               0x103
1976ad43ddacSmrg#define DP_TRAINING_LANE1_SET               0x104
1977ad43ddacSmrg#define DP_TRAINING_LANE2_SET               0x105
1978ad43ddacSmrg#define DP_TRAINING_LANE3_SET               0x106
1979ad43ddacSmrg# define DP_TRAIN_VOLTAGE_SWING_MASK        0x3
1980ad43ddacSmrg# define DP_TRAIN_VOLTAGE_SWING_SHIFT       0
1981ad43ddacSmrg# define DP_TRAIN_MAX_SWING_REACHED         (1 << 2)
1982ad43ddacSmrg# define DP_TRAIN_VOLTAGE_SWING_400         (0 << 0)
1983ad43ddacSmrg# define DP_TRAIN_VOLTAGE_SWING_600         (1 << 0)
1984ad43ddacSmrg# define DP_TRAIN_VOLTAGE_SWING_800         (2 << 0)
1985ad43ddacSmrg# define DP_TRAIN_VOLTAGE_SWING_1200        (3 << 0)
1986ad43ddacSmrg
1987ad43ddacSmrg# define DP_TRAIN_PRE_EMPHASIS_MASK         (3 << 3)
1988ad43ddacSmrg# define DP_TRAIN_PRE_EMPHASIS_0            (0 << 3)
1989ad43ddacSmrg# define DP_TRAIN_PRE_EMPHASIS_3_5          (1 << 3)
1990ad43ddacSmrg# define DP_TRAIN_PRE_EMPHASIS_6            (2 << 3)
1991ad43ddacSmrg# define DP_TRAIN_PRE_EMPHASIS_9_5          (3 << 3)
1992ad43ddacSmrg
1993ad43ddacSmrg# define DP_TRAIN_PRE_EMPHASIS_SHIFT        3
1994ad43ddacSmrg# define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED  (1 << 5)
1995ad43ddacSmrg#define DP_DOWNSPREAD_CTRL                  0x107
1996ad43ddacSmrg# define DP_SPREAD_AMP_0_5                  (1 << 4)
1997ad43ddacSmrg
1998ad43ddacSmrg#define DP_MAIN_LINK_CHANNEL_CODING_SET     0x108
1999ad43ddacSmrg# define DP_SET_ANSI_8B10B                  (1 << 0)
2000ad43ddacSmrg
2001ad43ddacSmrg#define DP_LANE0_1_STATUS                   0x202
2002ad43ddacSmrg#define DP_LANE2_3_STATUS                   0x203
2003ad43ddacSmrg
2004ad43ddacSmrg# define DP_LANE_CR_DONE                    (1 << 0)
2005ad43ddacSmrg# define DP_LANE_CHANNEL_EQ_DONE            (1 << 1)
2006ad43ddacSmrg# define DP_LANE_SYMBOL_LOCKED              (1 << 2)
2007ad43ddacSmrg
2008ad43ddacSmrg#define DP_LANE_ALIGN_STATUS_UPDATED        0x204
2009ad43ddacSmrg#define DP_INTERLANE_ALIGN_DONE             (1 << 0)
2010ad43ddacSmrg#define DP_DOWNSTREAM_PORT_STATUS_CHANGED   (1 << 6)
2011ad43ddacSmrg#define DP_LINK_STATUS_UPDATED              (1 << 7)
2012ad43ddacSmrg
2013ad43ddacSmrg#define DP_SINK_STATUS                      0x205
2014ad43ddacSmrg
2015ad43ddacSmrg#define DP_RECEIVE_PORT_0_STATUS            (1 << 0)
2016ad43ddacSmrg#define DP_RECEIVE_PORT_1_STATUS            (1 << 1)
2017ad43ddacSmrg
2018ad43ddacSmrg#define DP_ADJUST_REQUEST_LANE0_1           0x206
2019ad43ddacSmrg#define DP_ADJUST_REQUEST_LANE2_3           0x207
2020ad43ddacSmrg
2021ad43ddacSmrg#define DP_ADJUST_VOLTAGE_SWING_LANE0_MASK  0x03
2022ad43ddacSmrg#define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT 0
2023ad43ddacSmrg#define DP_ADJUST_PRE_EMPHASIS_LANE0_MASK   0x0c
2024ad43ddacSmrg#define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT  2
2025ad43ddacSmrg#define DP_ADJUST_VOLTAGE_SWING_LANE1_MASK  0x30
2026ad43ddacSmrg#define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT 4
2027ad43ddacSmrg#define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK   0xc0
2028ad43ddacSmrg#define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT  6
2029ad43ddacSmrg
2030ad43ddacSmrg#define DP_LINK_STATUS_SIZE                 6
2031ad43ddacSmrg#define DP_LINK_CONFIGURATION_SIZE          9
2032ad43ddacSmrg
2033ad43ddacSmrg#define DP_SET_POWER_D0  0x1
2034ad43ddacSmrg#define DP_SET_POWER_D3  0x2
2035ad43ddacSmrg
2036ad43ddacSmrgstatic inline int atom_dp_get_encoder_id(xf86OutputPtr output)
2037ad43ddacSmrg{
2038ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2039ad43ddacSmrg    int ret = 0;
2040ad43ddacSmrg    if (radeon_output->dig_encoder)
2041ad43ddacSmrg        ret |= ATOM_DP_CONFIG_DIG2_ENCODER;
2042ad43ddacSmrg    else
2043ad43ddacSmrg        ret |= ATOM_DP_CONFIG_DIG1_ENCODER;
2044ad43ddacSmrg    if (radeon_output->linkb)
2045ad43ddacSmrg        ret |= ATOM_DP_CONFIG_LINK_B;
2046ad43ddacSmrg    else
2047ad43ddacSmrg        ret |= ATOM_DP_CONFIG_LINK_A;
2048ad43ddacSmrg    return ret;
2049ad43ddacSmrg}
2050ad43ddacSmrg
2051ad43ddacSmrgunion aux_channel_transaction {
2052ad43ddacSmrg    PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
2053ad43ddacSmrg    PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
2054ad43ddacSmrg};
2055ad43ddacSmrg
2056ad43ddacSmrgBool
2057ad43ddacSmrgRADEONProcessAuxCH(xf86OutputPtr output, uint8_t *req_bytes, uint8_t num_bytes,
2058ad43ddacSmrg		   uint8_t *read_byte, uint8_t read_buf_len, uint8_t delay)
2059ad43ddacSmrg{
2060ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2061ad43ddacSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
2062ad43ddacSmrg    union aux_channel_transaction args;
2063ad43ddacSmrg    AtomBiosArgRec data;
2064ad43ddacSmrg    unsigned char *space;
2065ad43ddacSmrg    unsigned char *base;
2066ad43ddacSmrg
2067ad43ddacSmrg    memset(&args, 0, sizeof(args));
2068ad43ddacSmrg    if (info->atomBIOS->fbBase)
2069ad43ddacSmrg	base = info->FB + info->atomBIOS->fbBase;
2070ad43ddacSmrg    else if (info->atomBIOS->scratchBase)
2071ad43ddacSmrg	base = (unsigned char *)info->atomBIOS->scratchBase;
2072ad43ddacSmrg    else
2073ad43ddacSmrg	return FALSE;
2074ad43ddacSmrg
2075ad43ddacSmrg    memcpy(base, req_bytes, num_bytes);
2076ad43ddacSmrg
2077ad43ddacSmrg    args.v1.lpAuxRequest = 0;
2078ad43ddacSmrg    args.v1.lpDataOut = 16;
2079ad43ddacSmrg    args.v1.ucDataOutLen = 0;
2080ad43ddacSmrg    args.v1.ucChannelID = radeon_output->ucI2cId;
2081ad43ddacSmrg    args.v1.ucDelay = delay / 10; /* 10 usec */
2082ad43ddacSmrg    if (IS_DCE4_VARIANT)
2083ad43ddacSmrg	args.v2.ucHPD_ID = radeon_output->hpd_id;
2084ad43ddacSmrg
2085ad43ddacSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
2086ad43ddacSmrg    data.exec.dataSpace = (void *)&space;
2087ad43ddacSmrg    data.exec.pspace = &args;
2088ad43ddacSmrg
2089ad43ddacSmrg    RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data);
2090ad43ddacSmrg    if (args.v1.ucReplyStatus) {
2091ad43ddacSmrg	ErrorF("failed to get auxch %02x%02x %02x %02x %02x\n",
2092ad43ddacSmrg	       req_bytes[1], req_bytes[0], req_bytes[2], req_bytes[3], args.v1.ucReplyStatus);
2093ad43ddacSmrg	return FALSE;
2094ad43ddacSmrg    }
2095ad43ddacSmrg    if (args.v1.ucDataOutLen && read_byte && read_buf_len) {
2096ad43ddacSmrg	if (read_buf_len < args.v1.ucDataOutLen) {
2097ad43ddacSmrg	    ErrorF("%s: Buffer too small for return answer %d %d\n", __func__, read_buf_len, args.v1.ucDataOutLen);
2098ad43ddacSmrg	    return FALSE;
2099ad43ddacSmrg	}
2100ad43ddacSmrg	{
2101ad43ddacSmrg	    int len = read_buf_len < args.v1.ucDataOutLen ? read_buf_len : args.v1.ucDataOutLen;
2102ad43ddacSmrg	    memcpy(read_byte, base+16, len);
2103ad43ddacSmrg	}
2104ad43ddacSmrg    }
2105ad43ddacSmrg    return TRUE;
2106ad43ddacSmrg}
2107ad43ddacSmrg
2108ad43ddacSmrgstatic int
2109ad43ddacSmrgRADEONDPEncoderService(xf86OutputPtr output, int action, uint8_t ucconfig, uint8_t lane_num)
2110ad43ddacSmrg{
2111ad43ddacSmrg    RADEONInfoPtr info = RADEONPTR(output->scrn);
2112ad43ddacSmrg    DP_ENCODER_SERVICE_PARAMETERS args;
2113ad43ddacSmrg    AtomBiosArgRec data;
2114ad43ddacSmrg    unsigned char *space;
2115ad43ddacSmrg
2116ad43ddacSmrg    memset(&args, 0, sizeof(args));
2117ad43ddacSmrg
2118ad43ddacSmrg    args.ucLinkClock = 0;
2119ad43ddacSmrg    args.ucConfig = ucconfig;
2120ad43ddacSmrg    args.ucAction = action;
2121ad43ddacSmrg    args.ucLaneNum = lane_num;
2122ad43ddacSmrg    args.ucStatus = 0;
2123ad43ddacSmrg
2124ad43ddacSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, DPEncoderService);
2125ad43ddacSmrg    data.exec.dataSpace = (void *)&space;
2126ad43ddacSmrg    data.exec.pspace = &args;
2127ad43ddacSmrg
2128ad43ddacSmrg    RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data);
2129ad43ddacSmrg
2130ad43ddacSmrg    ErrorF("%s: %d\n", __func__, args.ucStatus);
2131ad43ddacSmrg    return args.ucStatus;
2132ad43ddacSmrg}
2133ad43ddacSmrg
2134ad43ddacSmrgint RADEON_DP_GetSinkType(xf86OutputPtr output)
2135ad43ddacSmrg{
2136ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2137ad43ddacSmrg
2138ad43ddacSmrg    return RADEONDPEncoderService(output, ATOM_DP_ACTION_GET_SINK_TYPE, radeon_output->ucI2cId, 0);
2139ad43ddacSmrg}
2140ad43ddacSmrg
2141ad43ddacSmrgstatic Bool atom_dp_aux_native_write(xf86OutputPtr output, uint16_t address,
2142ad43ddacSmrg				     uint8_t send_bytes, uint8_t *send)
2143ad43ddacSmrg{
2144ad43ddacSmrg    uint8_t msg[20];
2145ad43ddacSmrg    uint8_t msg_len, dp_msg_len;
2146ad43ddacSmrg    int ret;
2147ad43ddacSmrg
2148ad43ddacSmrg    dp_msg_len = 4;
2149ad43ddacSmrg    msg[0] = address;
2150ad43ddacSmrg    msg[1] = address >> 8;
2151ad43ddacSmrg    msg[2] = AUX_NATIVE_WRITE << 4;
2152ad43ddacSmrg    dp_msg_len += send_bytes;
2153ad43ddacSmrg    msg[3] = (dp_msg_len << 4)| (send_bytes - 1);
2154ad43ddacSmrg
2155ad43ddacSmrg    if (0)
2156ad43ddacSmrg	ErrorF("writing %02x %02x %02x, %d, %d\n", msg[0], msg[1], msg[3], send_bytes, dp_msg_len);
2157ad43ddacSmrg    if (send_bytes > 16)
2158ad43ddacSmrg	return FALSE;
2159ad43ddacSmrg
2160ad43ddacSmrg    memcpy(&msg[4], send, send_bytes);
2161ad43ddacSmrg    msg_len = 4 + send_bytes;
2162ad43ddacSmrg    ret = RADEONProcessAuxCH(output, msg, msg_len, NULL, 0, 0);
2163ad43ddacSmrg    return ret;
2164ad43ddacSmrg}
2165ad43ddacSmrg
2166ad43ddacSmrgstatic Bool atom_dp_aux_native_read(xf86OutputPtr output, uint16_t address,
2167ad43ddacSmrg				    uint8_t delay,
2168ad43ddacSmrg				    uint8_t expected_bytes, uint8_t *read_p)
2169ad43ddacSmrg{
2170ad43ddacSmrg    uint8_t msg[20];
2171ad43ddacSmrg    uint8_t msg_len, dp_msg_len;
2172ad43ddacSmrg    int ret;
2173ad43ddacSmrg
2174ad43ddacSmrg    msg_len = 4;
2175ad43ddacSmrg    dp_msg_len = 4;
2176ad43ddacSmrg    msg[0] = address;
2177ad43ddacSmrg    msg[1] = address >> 8;
2178ad43ddacSmrg    msg[2] = AUX_NATIVE_READ << 4;
2179ad43ddacSmrg    msg[3] = (dp_msg_len) << 4;
2180ad43ddacSmrg    msg[3] |= expected_bytes - 1;
2181ad43ddacSmrg
2182ad43ddacSmrg    if (0)
2183ad43ddacSmrg	ErrorF("reading %02x %02x %02x, %d, %d\n", msg[0], msg[1], msg[3], expected_bytes, dp_msg_len);
2184ad43ddacSmrg    ret = RADEONProcessAuxCH(output, msg, msg_len, read_p, expected_bytes, delay);
2185ad43ddacSmrg    return ret;
2186ad43ddacSmrg}
2187ad43ddacSmrg
2188ad43ddacSmrg/* fill out the DPCD structure */
2189ad43ddacSmrgvoid RADEON_DP_GetDPCD(xf86OutputPtr output)
2190ad43ddacSmrg{
2191ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2192ad43ddacSmrg    uint8_t msg[25];
2193ad43ddacSmrg    int ret;
2194ad43ddacSmrg
2195ad43ddacSmrg    ret = atom_dp_aux_native_read(output, DP_DPCD_REV, 0, 8, msg);
2196ad43ddacSmrg    if (ret) {
2197ad43ddacSmrg	memcpy(radeon_output->dpcd, msg, 8);
2198ad43ddacSmrg	if (0) {
2199ad43ddacSmrg	    int i;
2200ad43ddacSmrg	    ErrorF("DPCD: ");
2201ad43ddacSmrg	    for (i = 0; i < 8; i++)
2202ad43ddacSmrg		ErrorF("%02x ", radeon_output->dpcd[i]);
2203ad43ddacSmrg	    ErrorF("\n");
2204ad43ddacSmrg	}
2205ad43ddacSmrg	ret = atom_dp_aux_native_read(output, DP_LINK_BW_SET, 0, 2, msg);
2206ad43ddacSmrg	if (0) {
2207ad43ddacSmrg	    ErrorF("0x200: %02x %02x\n", msg[0], msg[1]);
2208ad43ddacSmrg	}
2209ad43ddacSmrg	return;
2210ad43ddacSmrg    }
2211ad43ddacSmrg    radeon_output->dpcd[0] = 0;
2212ad43ddacSmrg    return;
2213ad43ddacSmrg}
2214ad43ddacSmrg
2215ad43ddacSmrg
2216ad43ddacSmrgenum dp_aux_i2c_mode {
2217ad43ddacSmrg    dp_aux_i2c_start,
2218ad43ddacSmrg    dp_aux_i2c_write,
2219ad43ddacSmrg    dp_aux_i2c_read,
2220ad43ddacSmrg    dp_aux_i2c_stop,
2221ad43ddacSmrg};
2222ad43ddacSmrg
2223ad43ddacSmrg
2224ad43ddacSmrgstatic Bool atom_dp_aux_i2c_transaction(xf86OutputPtr output, uint16_t address,
2225ad43ddacSmrg				       enum dp_aux_i2c_mode mode,
2226ad43ddacSmrg				       uint8_t write_byte, uint8_t *read_byte)
2227ad43ddacSmrg{
2228ad43ddacSmrg    uint8_t msg[8], msg_len, dp_msg_len;
2229ad43ddacSmrg    int ret;
2230ad43ddacSmrg    int auxch_cmd = 0;
2231ad43ddacSmrg
2232ad43ddacSmrg    memset(msg, 0, 8);
2233ad43ddacSmrg
2234ad43ddacSmrg    if (mode != dp_aux_i2c_stop)
2235ad43ddacSmrg	auxch_cmd = AUX_I2C_MOT;
2236ad43ddacSmrg
2237ad43ddacSmrg    if (address & 1)
2238ad43ddacSmrg	auxch_cmd |= AUX_I2C_READ;
2239ad43ddacSmrg    else
2240ad43ddacSmrg    	auxch_cmd |= AUX_I2C_WRITE;
2241ad43ddacSmrg
2242ad43ddacSmrg    msg[2] = auxch_cmd << 4;
2243ad43ddacSmrg
2244ad43ddacSmrg    msg[4] = 0;
2245ad43ddacSmrg    msg[0] = (address >> 1);
2246ad43ddacSmrg    msg[1] = (address >> 9);
2247ad43ddacSmrg
2248ad43ddacSmrg    msg_len = 4;
2249ad43ddacSmrg    dp_msg_len = 3;
2250ad43ddacSmrg    switch (mode) {
2251ad43ddacSmrg    case dp_aux_i2c_read:
2252ad43ddacSmrg	/* bottom bits is byte count - 1 so for 1 byte == 0 */
2253ad43ddacSmrg	dp_msg_len += 1;
2254ad43ddacSmrg	break;
2255ad43ddacSmrg    case dp_aux_i2c_write:
2256ad43ddacSmrg	dp_msg_len += 2;
2257ad43ddacSmrg	msg[4] = write_byte;
2258ad43ddacSmrg	msg_len++;
2259ad43ddacSmrg	break;
2260ad43ddacSmrg    default:
2261ad43ddacSmrg	break;
2262ad43ddacSmrg    }
2263ad43ddacSmrg    msg[3] = dp_msg_len << 4;
2264ad43ddacSmrg
2265ad43ddacSmrg    ret = RADEONProcessAuxCH(output, msg, msg_len, read_byte, 1, 0);
2266ad43ddacSmrg    return ret;
2267ad43ddacSmrg}
2268ad43ddacSmrg
2269ad43ddacSmrgstatic Bool
2270ad43ddacSmrgatom_dp_i2c_address(I2CDevPtr dev, I2CSlaveAddr addr)
2271ad43ddacSmrg{
2272ad43ddacSmrg    I2CBusPtr bus = dev->pI2CBus;
2273ad43ddacSmrg    xf86OutputPtr output = bus->DriverPrivate.ptr;
2274ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2275ad43ddacSmrg    int ret;
2276ad43ddacSmrg
2277ad43ddacSmrg    radeon_output->dp_i2c_addr = addr;
2278ad43ddacSmrg    radeon_output->dp_i2c_running = TRUE;
2279ad43ddacSmrg
2280ad43ddacSmrg    /* call i2c start */
2281ad43ddacSmrg    ret = atom_dp_aux_i2c_transaction(output, radeon_output->dp_i2c_addr,
2282ad43ddacSmrg				      dp_aux_i2c_start, 0, NULL);
2283ad43ddacSmrg
2284ad43ddacSmrg    return ret;
2285ad43ddacSmrg}
2286ad43ddacSmrgstatic Bool
2287ad43ddacSmrgatom_dp_i2c_start(I2CBusPtr bus, int timeout)
2288ad43ddacSmrg{
2289ad43ddacSmrg    ErrorF("%s\n", __func__);
2290ad43ddacSmrg    return TRUE;
2291ad43ddacSmrg}
2292ad43ddacSmrg
2293ad43ddacSmrgstatic void
2294ad43ddacSmrgatom_dp_i2c_stop(I2CDevPtr dev)
2295ad43ddacSmrg{
2296ad43ddacSmrg    I2CBusPtr bus = dev->pI2CBus;
2297ad43ddacSmrg    xf86OutputPtr output = bus->DriverPrivate.ptr;
2298ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2299ad43ddacSmrg
2300ad43ddacSmrg    if (radeon_output->dp_i2c_running)
2301ad43ddacSmrg	atom_dp_aux_i2c_transaction(output, radeon_output->dp_i2c_addr,
2302ad43ddacSmrg				    dp_aux_i2c_stop, 0, NULL);
2303ad43ddacSmrg    radeon_output->dp_i2c_running = FALSE;
2304ad43ddacSmrg}
2305ad43ddacSmrg
2306ad43ddacSmrg
2307ad43ddacSmrgstatic Bool
2308ad43ddacSmrgatom_dp_i2c_put_byte(I2CDevPtr dev, I2CByte byte)
2309ad43ddacSmrg{
2310ad43ddacSmrg    I2CBusPtr bus = dev->pI2CBus;
2311ad43ddacSmrg    xf86OutputPtr output = bus->DriverPrivate.ptr;
2312ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2313ad43ddacSmrg    Bool ret;
2314ad43ddacSmrg
2315ad43ddacSmrg    ret = (atom_dp_aux_i2c_transaction(output, radeon_output->dp_i2c_addr,
2316ad43ddacSmrg				       dp_aux_i2c_write, byte, NULL));
2317ad43ddacSmrg    return ret;
2318ad43ddacSmrg}
2319ad43ddacSmrg
2320ad43ddacSmrgstatic Bool
2321ad43ddacSmrgatom_dp_i2c_get_byte(I2CDevPtr dev, I2CByte *byte_ret, Bool last)
2322ad43ddacSmrg{
2323ad43ddacSmrg    I2CBusPtr bus = dev->pI2CBus;
2324ad43ddacSmrg    xf86OutputPtr output = bus->DriverPrivate.ptr;
2325ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2326ad43ddacSmrg    Bool ret;
2327ad43ddacSmrg
2328ad43ddacSmrg    ret = (atom_dp_aux_i2c_transaction(output, radeon_output->dp_i2c_addr,
2329ad43ddacSmrg				       dp_aux_i2c_read, 0, byte_ret));
2330ad43ddacSmrg    return ret;
2331ad43ddacSmrg}
2332ad43ddacSmrg
2333ad43ddacSmrgBool
2334ad43ddacSmrgRADEON_DP_I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, char *name, xf86OutputPtr output)
2335ad43ddacSmrg{
2336ad43ddacSmrg    I2CBusPtr pI2CBus;
2337ad43ddacSmrg
2338ad43ddacSmrg    pI2CBus = xf86CreateI2CBusRec();
2339ad43ddacSmrg    if (!pI2CBus) return FALSE;
2340ad43ddacSmrg
2341ad43ddacSmrg    pI2CBus->BusName = name;
2342ad43ddacSmrg    pI2CBus->scrnIndex = pScrn->scrnIndex;
2343ad43ddacSmrg    pI2CBus->I2CGetByte = atom_dp_i2c_get_byte;
2344ad43ddacSmrg    pI2CBus->I2CPutByte = atom_dp_i2c_put_byte;
2345ad43ddacSmrg    pI2CBus->I2CAddress = atom_dp_i2c_address;
2346ad43ddacSmrg    pI2CBus->I2CStart = atom_dp_i2c_start;
2347ad43ddacSmrg    pI2CBus->I2CStop = atom_dp_i2c_stop;
2348ad43ddacSmrg    pI2CBus->DriverPrivate.ptr = output;
2349ad43ddacSmrg
2350ad43ddacSmrg    /*
2351ad43ddacSmrg     * These were set incorrectly in the server pre-1.3, Having
2352ad43ddacSmrg     * duplicate settings is sub-optimal, but this lets the driver
2353ad43ddacSmrg     * work with older servers
2354ad43ddacSmrg     */
2355ad43ddacSmrg    pI2CBus->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */
2356ad43ddacSmrg    pI2CBus->StartTimeout = 550;
2357ad43ddacSmrg    pI2CBus->BitTimeout = 40;
2358ad43ddacSmrg    pI2CBus->AcknTimeout = 40;
2359ad43ddacSmrg    pI2CBus->RiseFallTime = 20;
2360ad43ddacSmrg
2361ad43ddacSmrg    if (!xf86I2CBusInit(pI2CBus))
2362ad43ddacSmrg	return FALSE;
2363ad43ddacSmrg
2364ad43ddacSmrg    *bus_ptr = pI2CBus;
2365ad43ddacSmrg    return TRUE;
2366ad43ddacSmrg}
2367ad43ddacSmrg
2368ad43ddacSmrg
2369ad43ddacSmrgstatic uint8_t dp_link_status(uint8_t link_status[DP_LINK_STATUS_SIZE], int r)
2370ad43ddacSmrg{
2371ad43ddacSmrg    return link_status[r - DP_LANE0_1_STATUS];
2372ad43ddacSmrg}
2373ad43ddacSmrg
2374ad43ddacSmrgstatic uint8_t dp_get_lane_status(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane)
2375ad43ddacSmrg{
2376ad43ddacSmrg    int i = DP_LANE0_1_STATUS + (lane >> 1);
2377ad43ddacSmrg    int s = (lane & 1) * 4;
2378ad43ddacSmrg    uint8_t l = dp_link_status(link_status, i);
2379ad43ddacSmrg    return (l >> s) & 0xf;
2380ad43ddacSmrg}
2381ad43ddacSmrg
2382ad43ddacSmrgstatic Bool dp_clock_recovery_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
2383ad43ddacSmrg{
2384ad43ddacSmrg    int lane;
2385ad43ddacSmrg
2386ad43ddacSmrg    uint8_t lane_status;
2387ad43ddacSmrg
2388ad43ddacSmrg    for (lane = 0; lane < lane_count; lane++) {
2389ad43ddacSmrg	lane_status = dp_get_lane_status(link_status, lane);
2390ad43ddacSmrg	if ((lane_status & DP_LANE_CR_DONE) == 0)
2391ad43ddacSmrg	    return FALSE;
2392ad43ddacSmrg    }
2393ad43ddacSmrg    return TRUE;
2394ad43ddacSmrg}
2395ad43ddacSmrg
2396ad43ddacSmrg
2397ad43ddacSmrg/* Check to see if channel eq is done on all channels */
2398ad43ddacSmrg#define CHANNEL_EQ_BITS (DP_LANE_CR_DONE|\
2399ad43ddacSmrg			 DP_LANE_CHANNEL_EQ_DONE|\
2400ad43ddacSmrg			 DP_LANE_SYMBOL_LOCKED)
2401ad43ddacSmrgstatic Bool
2402ad43ddacSmrgdp_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
2403ad43ddacSmrg{
2404ad43ddacSmrg    uint8_t lane_align;
2405ad43ddacSmrg    uint8_t lane_status;
2406ad43ddacSmrg    int lane;
2407ad43ddacSmrg
2408ad43ddacSmrg    lane_align = dp_link_status(link_status,
2409ad43ddacSmrg				DP_LANE_ALIGN_STATUS_UPDATED);
2410ad43ddacSmrg    if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
2411ad43ddacSmrg	return FALSE;
2412ad43ddacSmrg    for (lane = 0; lane < lane_count; lane++) {
2413ad43ddacSmrg	lane_status = dp_get_lane_status(link_status, lane);
2414ad43ddacSmrg	if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS)
2415ad43ddacSmrg	    return FALSE;
2416ad43ddacSmrg    }
2417ad43ddacSmrg    return TRUE;
2418ad43ddacSmrg}
2419ad43ddacSmrg
2420ad43ddacSmrg/*
2421ad43ddacSmrg * Fetch AUX CH registers 0x202 - 0x207 which contain
2422ad43ddacSmrg * link status information
2423ad43ddacSmrg */
2424ad43ddacSmrgstatic Bool
2425ad43ddacSmrgatom_dp_get_link_status(xf86OutputPtr output,
2426ad43ddacSmrg			  uint8_t link_status[DP_LINK_STATUS_SIZE])
2427ad43ddacSmrg{
2428ad43ddacSmrg    ScrnInfoPtr pScrn = output->scrn;
2429ad43ddacSmrg    int ret;
2430ad43ddacSmrg    ret = atom_dp_aux_native_read(output, DP_LANE0_1_STATUS, 100,
2431ad43ddacSmrg				  DP_LINK_STATUS_SIZE, link_status);
2432ad43ddacSmrg    if (!ret) {
2433ad43ddacSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "dp link status failed\n");
2434ad43ddacSmrg	return FALSE;
2435ad43ddacSmrg    }
2436ad43ddacSmrg    ErrorF("link status %02x %02x %02x %02x %02x %02x\n", link_status[0], link_status[1],
2437ad43ddacSmrg	   link_status[2], link_status[3], link_status[4], link_status[5]);
2438ad43ddacSmrg
2439ad43ddacSmrg    return TRUE;
2440ad43ddacSmrg}
2441ad43ddacSmrg
2442ad43ddacSmrgstatic uint8_t
2443ad43ddacSmrgdp_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE],
2444ad43ddacSmrg			      int lane)
2445ad43ddacSmrg
2446ad43ddacSmrg{
2447ad43ddacSmrg    int     i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
2448ad43ddacSmrg    int     s = ((lane & 1) ?
2449ad43ddacSmrg                 DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT :
2450ad43ddacSmrg                 DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT);
2451ad43ddacSmrg    uint8_t l = dp_link_status(link_status, i);
2452ad43ddacSmrg
2453ad43ddacSmrg    return ((l >> s) & 3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
2454ad43ddacSmrg}
2455ad43ddacSmrg
2456ad43ddacSmrgstatic uint8_t
2457ad43ddacSmrgdp_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZE],
2458ad43ddacSmrg				   int lane)
2459ad43ddacSmrg{
2460ad43ddacSmrg    int     i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
2461ad43ddacSmrg    int     s = ((lane & 1) ?
2462ad43ddacSmrg                 DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT :
2463ad43ddacSmrg                 DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT);
2464ad43ddacSmrg    uint8_t l = dp_link_status(link_status, i);
2465ad43ddacSmrg
2466ad43ddacSmrg    return ((l >> s) & 3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
2467ad43ddacSmrg}
2468ad43ddacSmrg
2469ad43ddacSmrgstatic char     *voltage_names[] = {
2470ad43ddacSmrg        "0.4V", "0.6V", "0.8V", "1.2V"
2471ad43ddacSmrg};
2472ad43ddacSmrgstatic char     *pre_emph_names[] = {
2473ad43ddacSmrg        "0dB", "3.5dB", "6dB", "9.5dB"
2474ad43ddacSmrg};
2475ad43ddacSmrg
2476ad43ddacSmrg/*
2477ad43ddacSmrg * These are source-specific values; current Intel hardware supports
2478ad43ddacSmrg * a maximum voltage of 800mV and a maximum pre-emphasis of 6dB
2479ad43ddacSmrg */
2480ad43ddacSmrg#define DP_VOLTAGE_MAX         DP_TRAIN_VOLTAGE_SWING_1200
2481ad43ddacSmrg
2482ad43ddacSmrgstatic uint8_t
2483ad43ddacSmrgdp_pre_emphasis_max(uint8_t voltage_swing)
2484ad43ddacSmrg{
2485ad43ddacSmrg    switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
2486ad43ddacSmrg    case DP_TRAIN_VOLTAGE_SWING_400:
2487ad43ddacSmrg        return DP_TRAIN_PRE_EMPHASIS_6;
2488ad43ddacSmrg    case DP_TRAIN_VOLTAGE_SWING_600:
2489ad43ddacSmrg        return DP_TRAIN_PRE_EMPHASIS_6;
2490ad43ddacSmrg    case DP_TRAIN_VOLTAGE_SWING_800:
2491ad43ddacSmrg        return DP_TRAIN_PRE_EMPHASIS_3_5;
2492ad43ddacSmrg    case DP_TRAIN_VOLTAGE_SWING_1200:
2493ad43ddacSmrg    default:
2494ad43ddacSmrg        return DP_TRAIN_PRE_EMPHASIS_0;
2495ad43ddacSmrg    }
2496ad43ddacSmrg}
2497ad43ddacSmrg
2498ad43ddacSmrgstatic void dp_set_training(xf86OutputPtr output, uint8_t training)
2499ad43ddacSmrg{
2500ad43ddacSmrg    atom_dp_aux_native_write(output, DP_TRAINING_PATTERN_SET, 1, &training);
2501ad43ddacSmrg}
2502ad43ddacSmrg
2503ad43ddacSmrgstatic void dp_set_power(xf86OutputPtr output, uint8_t power_state)
2504ad43ddacSmrg{
2505ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2506ad43ddacSmrg
2507ad43ddacSmrg    if (radeon_output->dpcd[0] >= 0x11) {
2508ad43ddacSmrg	atom_dp_aux_native_write(output, 0x600, 1, &power_state);
2509ad43ddacSmrg    }
2510ad43ddacSmrg}
2511ad43ddacSmrg
2512ad43ddacSmrgstatic void
2513ad43ddacSmrgdp_get_adjust_train(xf86OutputPtr output,
2514ad43ddacSmrg		      uint8_t link_status[DP_LINK_STATUS_SIZE],
2515ad43ddacSmrg		      int lane_count,
2516ad43ddacSmrg		      uint8_t train_set[4])
2517ad43ddacSmrg{
2518ad43ddacSmrg    ScrnInfoPtr pScrn = output->scrn;
2519ad43ddacSmrg    uint8_t v = 0;
2520ad43ddacSmrg    uint8_t p = 0;
2521ad43ddacSmrg    int lane;
2522ad43ddacSmrg
2523ad43ddacSmrg    for (lane = 0; lane < lane_count; lane++) {
2524ad43ddacSmrg	uint8_t this_v = dp_get_adjust_request_voltage(link_status, lane);
2525ad43ddacSmrg	uint8_t this_p = dp_get_adjust_request_pre_emphasis(link_status, lane);
2526ad43ddacSmrg
2527ad43ddacSmrg	if (0) {
2528ad43ddacSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2529ad43ddacSmrg		       "requested signal parameters: lane %d voltage %s pre_emph %s\n",
2530ad43ddacSmrg		       lane,
2531ad43ddacSmrg		       voltage_names[this_v >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
2532ad43ddacSmrg		       pre_emph_names[this_p >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);
2533ad43ddacSmrg	}
2534ad43ddacSmrg	if (this_v > v)
2535ad43ddacSmrg	    v = this_v;
2536ad43ddacSmrg	if (this_p > p)
2537ad43ddacSmrg	    p = this_p;
2538ad43ddacSmrg    }
2539ad43ddacSmrg
2540ad43ddacSmrg    if (v >= DP_VOLTAGE_MAX)
2541ad43ddacSmrg	v = DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED;
2542ad43ddacSmrg
2543ad43ddacSmrg    if (p >= dp_pre_emphasis_max(v))
2544ad43ddacSmrg	p = dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
2545ad43ddacSmrg
2546ad43ddacSmrg    if (0) {
2547ad43ddacSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2548ad43ddacSmrg		   "using signal parameters: voltage %s pre_emph %s\n",
2549ad43ddacSmrg		   voltage_names[(v & DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
2550ad43ddacSmrg		   pre_emph_names[(p & DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);
2551ad43ddacSmrg    }
2552ad43ddacSmrg    for (lane = 0; lane < 4; lane++)
2553ad43ddacSmrg	train_set[lane] = v | p;
2554ad43ddacSmrg}
2555ad43ddacSmrg
2556ad43ddacSmrgstatic int radeon_dp_max_lane_count(xf86OutputPtr output)
2557ad43ddacSmrg{
2558ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2559ad43ddacSmrg    int max_lane_count = 4;
2560ad43ddacSmrg
2561ad43ddacSmrg    if (radeon_output->dpcd[0] >= 0x11) {
2562ad43ddacSmrg	max_lane_count = radeon_output->dpcd[2] & 0x1f;
2563ad43ddacSmrg	switch(max_lane_count) {
2564ad43ddacSmrg	case 1: case 2: case 4:
2565ad43ddacSmrg	    break;
2566ad43ddacSmrg	default:
2567ad43ddacSmrg	    max_lane_count = 4;
2568ad43ddacSmrg	}
2569ad43ddacSmrg    }
2570ad43ddacSmrg    return max_lane_count;
2571ad43ddacSmrg}
2572ad43ddacSmrg
2573ad43ddacSmrgstatic int radeon_dp_max_link_bw(xf86OutputPtr output)
2574ad43ddacSmrg{
2575ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2576ad43ddacSmrg    int max_link_bw = radeon_output->dpcd[1];
2577ad43ddacSmrg    switch(max_link_bw) {
2578ad43ddacSmrg    case DP_LINK_BW_1_62:
2579ad43ddacSmrg    case DP_LINK_BW_2_7:
2580ad43ddacSmrg	break;
2581ad43ddacSmrg    default:
2582ad43ddacSmrg	max_link_bw = DP_LINK_BW_1_62;
2583ad43ddacSmrg	break;
2584ad43ddacSmrg    }
2585ad43ddacSmrg    return max_link_bw;
2586ad43ddacSmrg}
2587ad43ddacSmrg
2588ad43ddacSmrgstatic int radeon_dp_link_clock(uint8_t link_bw)
2589ad43ddacSmrg{
2590ad43ddacSmrg    if (link_bw == DP_LINK_BW_2_7)
2591ad43ddacSmrg	return 270000;
2592ad43ddacSmrg    else
2593ad43ddacSmrg	return 162000;
2594ad43ddacSmrg}
2595ad43ddacSmrg
2596ad43ddacSmrg
2597ad43ddacSmrg/* I think this is a fiction */
2598ad43ddacSmrgstatic int radeon_dp_link_required(int pixel_clock)
2599ad43ddacSmrg{
2600ad43ddacSmrg    return pixel_clock * 3;
2601ad43ddacSmrg}
2602ad43ddacSmrg
2603ad43ddacSmrgBool radeon_dp_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
2604ad43ddacSmrg{
2605ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2606ad43ddacSmrg    int lane_count, clock;
2607ad43ddacSmrg    int max_lane_count = radeon_dp_max_lane_count(output);
2608ad43ddacSmrg    int max_clock = radeon_dp_max_link_bw(output) == DP_LINK_BW_2_7 ? 1 : 0;
2609ad43ddacSmrg    static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
2610ad43ddacSmrg
2611ad43ddacSmrg    for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
2612ad43ddacSmrg	for (clock = 0; clock <= max_clock; clock++) {
2613ad43ddacSmrg	    int link_avail = radeon_dp_link_clock(bws[clock]) * lane_count;
2614ad43ddacSmrg
2615ad43ddacSmrg	    if (radeon_dp_link_required(mode->Clock) <= link_avail) {
2616ad43ddacSmrg		radeon_output->dp_lane_count = lane_count;
2617ad43ddacSmrg		radeon_output->dp_clock = radeon_dp_link_clock(bws[clock]);
2618ad43ddacSmrg		if (0)
2619ad43ddacSmrg			xf86DrvMsg(0, X_INFO,
2620ad43ddacSmrg				   "lane_count %d clock %d\n",
2621ad43ddacSmrg				   radeon_output->dp_lane_count,
2622ad43ddacSmrg				   radeon_output->dp_clock);
2623ad43ddacSmrg		return TRUE;
2624ad43ddacSmrg	    }
2625ad43ddacSmrg	}
2626ad43ddacSmrg    }
2627ad43ddacSmrg    return FALSE;
2628ad43ddacSmrg}
2629ad43ddacSmrg
2630ad43ddacSmrgstatic void dp_update_dpvs_emph(xf86OutputPtr output, uint8_t train_set[4])
2631ad43ddacSmrg{
2632ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2633ad43ddacSmrg    int i;
2634ad43ddacSmrg    for (i = 0; i < radeon_output->dp_lane_count; i++)
2635ad43ddacSmrg	atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH, i, train_set[i]);
2636ad43ddacSmrg
2637ad43ddacSmrg    atom_dp_aux_native_write(output, DP_TRAINING_LANE0_SET, radeon_output->dp_lane_count, train_set);
2638ad43ddacSmrg}
2639ad43ddacSmrg
2640ad43ddacSmrgstatic void do_displayport_link_train(xf86OutputPtr output)
2641ad43ddacSmrg{
2642ad43ddacSmrg    ScrnInfoPtr pScrn = output->scrn;
2643ad43ddacSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
2644ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2645ad43ddacSmrg    int enc_id = atom_dp_get_encoder_id(output);
2646ad43ddacSmrg    Bool clock_recovery;
2647ad43ddacSmrg    uint8_t link_status[DP_LINK_STATUS_SIZE];
2648ad43ddacSmrg    uint8_t tries, voltage, ss_cntl;
2649ad43ddacSmrg    uint8_t train_set[4];
2650ad43ddacSmrg    int i;
2651ad43ddacSmrg    Bool channel_eq;
2652ad43ddacSmrg    uint8_t dp_link_configuration[DP_LINK_CONFIGURATION_SIZE];
2653ad43ddacSmrg
2654ad43ddacSmrg    memset(train_set, 0, 4);
2655ad43ddacSmrg
2656ad43ddacSmrg    /* set up link configuration */
2657ad43ddacSmrg    memset(dp_link_configuration, 0, DP_LINK_CONFIGURATION_SIZE);
2658ad43ddacSmrg
2659ad43ddacSmrg    if (radeon_output->dp_clock == 270000)
2660ad43ddacSmrg	dp_link_configuration[0] = DP_LINK_BW_2_7;
2661ad43ddacSmrg    else
2662ad43ddacSmrg	dp_link_configuration[0] = DP_LINK_BW_1_62;
2663ad43ddacSmrg    dp_link_configuration[1] = radeon_output->dp_lane_count;
2664ad43ddacSmrg
2665ad43ddacSmrg    if (radeon_output->dpcd[0] >= 0x11) {
2666ad43ddacSmrg	dp_link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
2667ad43ddacSmrg    }
2668ad43ddacSmrg
2669ad43ddacSmrg    /* power up to D0 */
2670ad43ddacSmrg    dp_set_power(output, DP_SET_POWER_D0);
2671ad43ddacSmrg
2672ad43ddacSmrg    /* disable training */
2673ad43ddacSmrg    dp_set_training(output, DP_TRAINING_PATTERN_DISABLE);
2674ad43ddacSmrg
2675ad43ddacSmrg    /* write link rate / num / eh framing */
2676ad43ddacSmrg    atom_dp_aux_native_write(output, DP_LINK_BW_SET, 2,
2677ad43ddacSmrg			     dp_link_configuration);
2678ad43ddacSmrg
2679ad43ddacSmrg    /* write ss cntl */
2680ad43ddacSmrg    ss_cntl = 0;
2681ad43ddacSmrg    atom_dp_aux_native_write(output, DP_DOWNSPREAD_CTRL, 1,
2682ad43ddacSmrg			     &ss_cntl);
2683ad43ddacSmrg
2684ad43ddacSmrg    /* start local training start */
2685ad43ddacSmrg    if (IS_DCE4_VARIANT) {
2686ad43ddacSmrg	atombios_dce4_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_LINK_TRAINING_START);
2687ad43ddacSmrg	atombios_dce4_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1);
2688ad43ddacSmrg    } else {
2689ad43ddacSmrg	RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_START, enc_id, 0);
2690ad43ddacSmrg	RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, enc_id, 0);
2691ad43ddacSmrg    }
2692ad43ddacSmrg
2693ad43ddacSmrg    usleep(400);
2694ad43ddacSmrg    dp_set_training(output, DP_TRAINING_PATTERN_1);
2695ad43ddacSmrg    dp_update_dpvs_emph(output, train_set);
2696ad43ddacSmrg
2697ad43ddacSmrg    /* loop around doing configuration reads and DP encoder setups */
2698ad43ddacSmrg    clock_recovery = FALSE;
2699ad43ddacSmrg    tries = 0;
2700ad43ddacSmrg    voltage = 0xff;
2701ad43ddacSmrg    for (;;) {
2702ad43ddacSmrg      	usleep(100);
2703ad43ddacSmrg	if (!atom_dp_get_link_status(output, link_status))
2704ad43ddacSmrg	    break;
2705ad43ddacSmrg
2706ad43ddacSmrg	if (dp_clock_recovery_ok(link_status, radeon_output->dp_lane_count)) {
2707ad43ddacSmrg	    clock_recovery = TRUE;
2708ad43ddacSmrg	    break;
2709ad43ddacSmrg	}
2710ad43ddacSmrg
2711ad43ddacSmrg	for (i = 0; i < radeon_output->dp_lane_count; i++)
2712ad43ddacSmrg	    if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
2713ad43ddacSmrg		break;
2714ad43ddacSmrg	if (i == radeon_output->dp_lane_count) {
2715ad43ddacSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2716ad43ddacSmrg		       "clock recovery reached max voltage\n");
2717ad43ddacSmrg	    break;
2718ad43ddacSmrg	}
2719ad43ddacSmrg
2720ad43ddacSmrg	/* Check to see if we've tried the same voltage 5 times */
2721ad43ddacSmrg	if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
2722ad43ddacSmrg	    ++tries;
2723ad43ddacSmrg	    if (tries == 5) {
2724ad43ddacSmrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2725ad43ddacSmrg			   "clock recovery tried 5 times\n");
2726ad43ddacSmrg		break;
2727ad43ddacSmrg	    }
2728ad43ddacSmrg	} else
2729ad43ddacSmrg	    tries = 0;
2730ad43ddacSmrg
2731ad43ddacSmrg	voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
2732ad43ddacSmrg
2733ad43ddacSmrg        dp_get_adjust_train(output, link_status, radeon_output->dp_lane_count, train_set);
2734ad43ddacSmrg	dp_update_dpvs_emph(output, train_set);
2735ad43ddacSmrg
2736ad43ddacSmrg    }
2737ad43ddacSmrg
2738ad43ddacSmrg    if (!clock_recovery)
2739ad43ddacSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2740ad43ddacSmrg		   "clock recovery failed\n");
2741ad43ddacSmrg
2742ad43ddacSmrg    /* channel equalization */
2743ad43ddacSmrg    tries = 0;
2744ad43ddacSmrg    channel_eq = FALSE;
2745ad43ddacSmrg    dp_set_training(output, DP_TRAINING_PATTERN_2);
2746ad43ddacSmrg    if (IS_DCE4_VARIANT)
2747ad43ddacSmrg	atombios_dce4_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2);
2748ad43ddacSmrg    else
2749ad43ddacSmrg	RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, enc_id, 1);
2750ad43ddacSmrg
2751ad43ddacSmrg    for (;;) {
2752ad43ddacSmrg	usleep(400);
2753ad43ddacSmrg	if (!atom_dp_get_link_status(output, link_status))
2754ad43ddacSmrg	    break;
2755ad43ddacSmrg
2756ad43ddacSmrg	if (dp_channel_eq_ok(link_status, radeon_output->dp_lane_count)) {
2757ad43ddacSmrg	    channel_eq = TRUE;
2758ad43ddacSmrg	    break;
2759ad43ddacSmrg	}
2760ad43ddacSmrg
2761ad43ddacSmrg	/* Try 5 times */
2762ad43ddacSmrg	if (tries > 5) {
2763ad43ddacSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2764ad43ddacSmrg		       "channel eq failed: 5 tries\n");
2765ad43ddacSmrg	    break;
2766ad43ddacSmrg	}
2767ad43ddacSmrg
2768ad43ddacSmrg	/* Compute new train_set as requested by target */
2769ad43ddacSmrg        dp_get_adjust_train(output, link_status, radeon_output->dp_lane_count, train_set);
2770ad43ddacSmrg	dp_update_dpvs_emph(output, train_set);
2771ad43ddacSmrg
2772ad43ddacSmrg	++tries;
2773ad43ddacSmrg    }
2774ad43ddacSmrg
2775ad43ddacSmrg    if (!channel_eq)
2776ad43ddacSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2777ad43ddacSmrg		   "channel eq failed\n");
2778ad43ddacSmrg
2779ad43ddacSmrg    dp_set_training(output, DP_TRAINING_PATTERN_DISABLE);
2780ad43ddacSmrg    if (IS_DCE4_VARIANT)
2781ad43ddacSmrg	atombios_dce4_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE);
2782ad43ddacSmrg    else
2783ad43ddacSmrg	RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_COMPLETE, enc_id, 0);
2784ad43ddacSmrg
2785ad43ddacSmrg}
2786ad43ddacSmrg
2787