atombios_output.c revision c503f109
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
68c503f109Smrgstatic void atombios_set_output_crtc_source(xf86OutputPtr output);
69c503f109Smrg
70209ff23fSmrgstatic int
71b7e1c893Smrgatombios_output_dac_setup(xf86OutputPtr output, int action)
72209ff23fSmrg{
73209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
74209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
75b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
76b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
77209ff23fSmrg    DAC_ENCODER_CONTROL_PS_ALLOCATION disp_data;
78209ff23fSmrg    AtomBiosArgRec data;
79209ff23fSmrg    unsigned char *space;
80b7e1c893Smrg    int index = 0, num = 0;
81b7e1c893Smrg    int clock = radeon_output->pixel_clock;
82b7e1c893Smrg
83b7e1c893Smrg    if (radeon_encoder == NULL)
84b7e1c893Smrg	return ATOM_NOT_IMPLEMENTED;
85b7e1c893Smrg
86b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
87b7e1c893Smrg
88b7e1c893Smrg    switch (radeon_encoder->encoder_id) {
89b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
90b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
91b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl);
92b7e1c893Smrg	num = 1;
93b7e1c893Smrg	break;
94b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
95b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
96b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl);
97b7e1c893Smrg	num = 2;
98b7e1c893Smrg	break;
99b7e1c893Smrg    }
100209ff23fSmrg
101b7e1c893Smrg    disp_data.ucAction =action;
102209ff23fSmrg
103b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_CRT_SUPPORT))
104209ff23fSmrg	disp_data.ucDacStandard = ATOM_DAC1_PS2;
105b7e1c893Smrg    else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
106209ff23fSmrg	disp_data.ucDacStandard = ATOM_DAC1_CV;
107b7e1c893Smrg    else {
108b7e1c893Smrg	switch (tvout->tvStd) {
109209ff23fSmrg	case TV_STD_PAL:
110209ff23fSmrg	case TV_STD_PAL_M:
111209ff23fSmrg	case TV_STD_SCART_PAL:
112209ff23fSmrg	case TV_STD_SECAM:
113209ff23fSmrg	case TV_STD_PAL_CN:
114209ff23fSmrg	    disp_data.ucDacStandard = ATOM_DAC1_PAL;
115209ff23fSmrg	    break;
116209ff23fSmrg	case TV_STD_NTSC:
117209ff23fSmrg	case TV_STD_NTSC_J:
118209ff23fSmrg	case TV_STD_PAL_60:
119209ff23fSmrg	default:
120b7e1c893Smrg	    disp_data.ucDacStandard = ATOM_DAC1_NTSC;
121209ff23fSmrg	    break;
122209ff23fSmrg	}
123209ff23fSmrg    }
124b7e1c893Smrg    disp_data.usPixelClock = cpu_to_le16(clock / 10);
125209ff23fSmrg
126b7e1c893Smrg    data.exec.index = index;
127209ff23fSmrg    data.exec.dataSpace = (void *)&space;
128209ff23fSmrg    data.exec.pspace = &disp_data;
129209ff23fSmrg
130209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
131b7e1c893Smrg	ErrorF("Output DAC%d setup success\n", num);
132209ff23fSmrg	return ATOM_SUCCESS;
133209ff23fSmrg    }
134209ff23fSmrg
135b7e1c893Smrg    ErrorF("Output DAC%d setup failed\n", num);
136209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
137209ff23fSmrg
138209ff23fSmrg}
139209ff23fSmrg
140209ff23fSmrgstatic int
141b7e1c893Smrgatombios_output_tv_setup(xf86OutputPtr output, int action)
142209ff23fSmrg{
143209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
144b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
145209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
146209ff23fSmrg    TV_ENCODER_CONTROL_PS_ALLOCATION disp_data;
147209ff23fSmrg    AtomBiosArgRec data;
148209ff23fSmrg    unsigned char *space;
149b7e1c893Smrg    int clock = radeon_output->pixel_clock;
150b7e1c893Smrg
151b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
152209ff23fSmrg
153b7e1c893Smrg    disp_data.sTVEncoder.ucAction = action;
154209ff23fSmrg
155b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
156209ff23fSmrg	disp_data.sTVEncoder.ucTvStandard = ATOM_TV_CV;
157209ff23fSmrg    else {
158b7e1c893Smrg	switch (tvout->tvStd) {
159209ff23fSmrg	case TV_STD_NTSC:
160209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSC;
161209ff23fSmrg	    break;
162209ff23fSmrg	case TV_STD_PAL:
163209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL;
164209ff23fSmrg	    break;
165209ff23fSmrg	case TV_STD_PAL_M:
166209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PALM;
167209ff23fSmrg	    break;
168209ff23fSmrg	case TV_STD_PAL_60:
169209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL60;
170209ff23fSmrg	    break;
171209ff23fSmrg	case TV_STD_NTSC_J:
172209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSCJ;
173209ff23fSmrg	    break;
174209ff23fSmrg	case TV_STD_SCART_PAL:
175209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL; /* ??? */
176209ff23fSmrg	    break;
177209ff23fSmrg	case TV_STD_SECAM:
178209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_SECAM;
179209ff23fSmrg	    break;
180209ff23fSmrg	case TV_STD_PAL_CN:
181209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PALCN;
182209ff23fSmrg	    break;
183209ff23fSmrg	default:
184209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSC;
185209ff23fSmrg	    break;
186209ff23fSmrg	}
187209ff23fSmrg    }
188209ff23fSmrg
189b7e1c893Smrg    disp_data.sTVEncoder.usPixelClock = cpu_to_le16(clock / 10);
190209ff23fSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl);
191209ff23fSmrg    data.exec.dataSpace = (void *)&space;
192209ff23fSmrg    data.exec.pspace = &disp_data;
193209ff23fSmrg
194209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
195b7e1c893Smrg	ErrorF("Output TV setup success\n");
196209ff23fSmrg	return ATOM_SUCCESS;
197209ff23fSmrg    }
198209ff23fSmrg
199b7e1c893Smrg    ErrorF("Output TV setup failed\n");
200209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
201209ff23fSmrg
202209ff23fSmrg}
203209ff23fSmrg
204209ff23fSmrgint
205b7e1c893Smrgatombios_external_tmds_setup(xf86OutputPtr output, int action)
206209ff23fSmrg{
207b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
208b7e1c893Smrg    ScrnInfoPtr pScrn = output->scrn;
209b7e1c893Smrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
210209ff23fSmrg    ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION disp_data;
211209ff23fSmrg    AtomBiosArgRec data;
212209ff23fSmrg    unsigned char *space;
213b7e1c893Smrg    int clock = radeon_output->pixel_clock;
214209ff23fSmrg
215b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
216209ff23fSmrg
217b7e1c893Smrg    disp_data.sXTmdsEncoder.ucEnable = action;
218b7e1c893Smrg
219b7e1c893Smrg    if (clock > 165000)
220b7e1c893Smrg	disp_data.sXTmdsEncoder.ucMisc = PANEL_ENCODER_MISC_DUAL;
221209ff23fSmrg
222b7e1c893Smrg    if (pScrn->rgbBits == 8)
223209ff23fSmrg	disp_data.sXTmdsEncoder.ucMisc |= (1 << 1);
224209ff23fSmrg
225209ff23fSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
226209ff23fSmrg    data.exec.dataSpace = (void *)&space;
227209ff23fSmrg    data.exec.pspace = &disp_data;
228209ff23fSmrg
229209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
230209ff23fSmrg	ErrorF("External TMDS setup success\n");
231209ff23fSmrg	return ATOM_SUCCESS;
232209ff23fSmrg    }
233209ff23fSmrg
234209ff23fSmrg    ErrorF("External TMDS setup failed\n");
235209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
236209ff23fSmrg}
237209ff23fSmrg
238209ff23fSmrgstatic int
239b7e1c893Smrgatombios_output_ddia_setup(xf86OutputPtr output, int action)
240209ff23fSmrg{
241b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
242209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
243209ff23fSmrg    DVO_ENCODER_CONTROL_PS_ALLOCATION disp_data;
244209ff23fSmrg    AtomBiosArgRec data;
245209ff23fSmrg    unsigned char *space;
246b7e1c893Smrg    int clock = radeon_output->pixel_clock;
247b7e1c893Smrg
248b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
249209ff23fSmrg
250b7e1c893Smrg    disp_data.sDVOEncoder.ucAction = action;
251b7e1c893Smrg    disp_data.sDVOEncoder.usPixelClock = cpu_to_le16(clock / 10);
252209ff23fSmrg
253b7e1c893Smrg    if (clock > 165000)
254209ff23fSmrg	disp_data.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = PANEL_ENCODER_MISC_DUAL;
255209ff23fSmrg
256209ff23fSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
257209ff23fSmrg    data.exec.dataSpace = (void *)&space;
258209ff23fSmrg    data.exec.pspace = &disp_data;
259209ff23fSmrg
260209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
261209ff23fSmrg	ErrorF("DDIA setup success\n");
262209ff23fSmrg	return ATOM_SUCCESS;
263209ff23fSmrg    }
264209ff23fSmrg
265209ff23fSmrg    ErrorF("DDIA setup failed\n");
266209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
267209ff23fSmrg}
268209ff23fSmrg
269209ff23fSmrgstatic int
270b7e1c893Smrgatombios_output_digital_setup(xf86OutputPtr output, int action)
271209ff23fSmrg{
272b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
273b7e1c893Smrg    ScrnInfoPtr pScrn = output->scrn;
274b7e1c893Smrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
275b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
276b7e1c893Smrg    LVDS_ENCODER_CONTROL_PS_ALLOCATION disp_data;
277b7e1c893Smrg    LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 disp_data2;
278209ff23fSmrg    AtomBiosArgRec data;
279209ff23fSmrg    unsigned char *space;
280b7e1c893Smrg    int index = 0;
281b7e1c893Smrg    int major, minor;
282b7e1c893Smrg    int lvds_misc = 0;
283b7e1c893Smrg    int clock = radeon_output->pixel_clock;
284209ff23fSmrg
285b7e1c893Smrg    if (radeon_encoder == NULL)
286b7e1c893Smrg	return ATOM_NOT_IMPLEMENTED;
287b7e1c893Smrg
288b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
289b7e1c893Smrg	radeon_lvds_ptr lvds = (radeon_lvds_ptr)radeon_encoder->dev_priv;
290b7e1c893Smrg	if (lvds == NULL)
291b7e1c893Smrg	    return ATOM_NOT_IMPLEMENTED;
292b7e1c893Smrg	lvds_misc = lvds->lvds_misc;
293b7e1c893Smrg    }
294b7e1c893Smrg
295b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
296b7e1c893Smrg    memset(&disp_data2,0, sizeof(disp_data2));
297b7e1c893Smrg
298b7e1c893Smrg    switch (radeon_encoder->encoder_id) {
299b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
300b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl);
301b7e1c893Smrg	break;
302b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
303b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
304b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl);
305b7e1c893Smrg	break;
306b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
307b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
308b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT))
309b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl);
310b7e1c893Smrg	else
311b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl);
312b7e1c893Smrg	break;
313b7e1c893Smrg    }
314b7e1c893Smrg
315b7e1c893Smrg    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
316b7e1c893Smrg
317b7e1c893Smrg    /*ErrorF("table is %d %d\n", major, minor);*/
318b7e1c893Smrg    switch (major) {
319b7e1c893Smrg    case 0:
320b7e1c893Smrg    case 1:
321b7e1c893Smrg    case 2:
322b7e1c893Smrg	switch (minor) {
323b7e1c893Smrg	case 1:
324b7e1c893Smrg	    disp_data.ucMisc = 0;
325b7e1c893Smrg	    disp_data.ucAction = action;
326b7e1c893Smrg	    if ((radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_A) ||
327b7e1c893Smrg		(radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_B))
328b7e1c893Smrg		disp_data.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
329b7e1c893Smrg	    disp_data.usPixelClock = cpu_to_le16(clock / 10);
330b7e1c893Smrg	    if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
331b7e1c893Smrg		if (lvds_misc & (1 << 0))
332b7e1c893Smrg		    disp_data.ucMisc |= PANEL_ENCODER_MISC_DUAL;
333b7e1c893Smrg		if (lvds_misc & (1 << 1))
334b7e1c893Smrg		    disp_data.ucMisc |= (1 << 1);
335b7e1c893Smrg	    } else {
336b7e1c893Smrg		if (radeon_output->linkb)
337b7e1c893Smrg		    disp_data.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
338b7e1c893Smrg		if (clock > 165000)
339b7e1c893Smrg		    disp_data.ucMisc |= PANEL_ENCODER_MISC_DUAL;
340b7e1c893Smrg		if (pScrn->rgbBits == 8)
341b7e1c893Smrg		    disp_data.ucMisc |= (1 << 1);
342b7e1c893Smrg	    }
343b7e1c893Smrg	    data.exec.pspace = &disp_data;
344b7e1c893Smrg	    break;
345b7e1c893Smrg	case 2:
346b7e1c893Smrg	case 3:
347b7e1c893Smrg	    disp_data2.ucMisc = 0;
348b7e1c893Smrg	    disp_data2.ucAction = action;
349b7e1c893Smrg	    if (minor == 3) {
350b7e1c893Smrg		if (radeon_output->coherent_mode) {
351b7e1c893Smrg		    disp_data2.ucMisc |= PANEL_ENCODER_MISC_COHERENT;
352b7e1c893Smrg		    xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "Coherent Mode enabled\n");
353b7e1c893Smrg		}
354b7e1c893Smrg	    }
355b7e1c893Smrg	    if ((radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_A) ||
356b7e1c893Smrg		(radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_B))
357b7e1c893Smrg		disp_data2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
358b7e1c893Smrg	    disp_data2.usPixelClock = cpu_to_le16(clock / 10);
359b7e1c893Smrg	    disp_data2.ucTruncate = 0;
360b7e1c893Smrg	    disp_data2.ucSpatial = 0;
361b7e1c893Smrg	    disp_data2.ucTemporal = 0;
362b7e1c893Smrg	    disp_data2.ucFRC = 0;
363b7e1c893Smrg	    if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
364b7e1c893Smrg		if (lvds_misc & (1 << 0))
365b7e1c893Smrg		    disp_data2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
366b7e1c893Smrg		if (lvds_misc & (1 << 5)) {
367b7e1c893Smrg		    disp_data2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN;
368b7e1c893Smrg		    if (lvds_misc & (1 << 1))
369b7e1c893Smrg			disp_data2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH;
370b7e1c893Smrg		}
371b7e1c893Smrg		if (lvds_misc & (1 << 6)) {
372b7e1c893Smrg		    disp_data2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN;
373b7e1c893Smrg		    if (lvds_misc & (1 << 1))
374b7e1c893Smrg			disp_data2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH;
375b7e1c893Smrg		    if (((lvds_misc >> 2) & 0x3) == 2)
376b7e1c893Smrg			disp_data2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4;
377b7e1c893Smrg		}
378b7e1c893Smrg	    } else {
379b7e1c893Smrg		if (radeon_output->linkb)
380b7e1c893Smrg		    disp_data2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
381b7e1c893Smrg		if (clock > 165000)
382b7e1c893Smrg		    disp_data2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
383b7e1c893Smrg	    }
384b7e1c893Smrg	    data.exec.pspace = &disp_data2;
385b7e1c893Smrg	    break;
386b7e1c893Smrg	default:
387b7e1c893Smrg	    ErrorF("Unknown table version\n");
388b7e1c893Smrg	    exit(-1);
389b7e1c893Smrg	}
390b7e1c893Smrg	break;
391b7e1c893Smrg    default:
392b7e1c893Smrg	ErrorF("Unknown table version\n");
393b7e1c893Smrg	exit(-1);
394b7e1c893Smrg    }
395b7e1c893Smrg
396b7e1c893Smrg    data.exec.index = index;
397209ff23fSmrg    data.exec.dataSpace = (void *)&space;
398209ff23fSmrg
399209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
400b7e1c893Smrg	ErrorF("Output digital setup success\n");
401209ff23fSmrg	return ATOM_SUCCESS;
402209ff23fSmrg    }
403209ff23fSmrg
404b7e1c893Smrg    ErrorF("Output digital setup failed\n");
405209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
406209ff23fSmrg}
407209ff23fSmrg
408209ff23fSmrgstatic int
409b7e1c893Smrgatombios_maybe_hdmi_mode(xf86OutputPtr output)
410209ff23fSmrg{
411b7e1c893Smrg#ifndef EDID_COMPLETE_RAWDATA
412b7e1c893Smrg    /* there's no getting this right unless we have complete EDID */
413b7e1c893Smrg    return ATOM_ENCODER_MODE_HDMI;
414b7e1c893Smrg#else
415b7e1c893Smrg    if (output && xf86MonitorIsHDMI(output->MonInfo))
416b7e1c893Smrg	return ATOM_ENCODER_MODE_HDMI;
417b7e1c893Smrg
418b7e1c893Smrg    return ATOM_ENCODER_MODE_DVI;
419b7e1c893Smrg#endif
420b7e1c893Smrg}
421209ff23fSmrg
422b7e1c893Smrgint
423b7e1c893Smrgatombios_get_encoder_mode(xf86OutputPtr output)
424b7e1c893Smrg{
425b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
426209ff23fSmrg
427b7e1c893Smrg    /* DVI should really be atombios_maybe_hdmi_mode() as well */
428b7e1c893Smrg    switch (radeon_output->ConnectorType) {
429b7e1c893Smrg    case CONNECTOR_DVI_I:
430b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT))
431b7e1c893Smrg	    return ATOM_ENCODER_MODE_DVI;
432b7e1c893Smrg	else
433b7e1c893Smrg	    return ATOM_ENCODER_MODE_CRT;
434b7e1c893Smrg	break;
435b7e1c893Smrg    case CONNECTOR_DVI_D:
436b7e1c893Smrg    default:
437b7e1c893Smrg	return ATOM_ENCODER_MODE_DVI;
438b7e1c893Smrg	break;
439b7e1c893Smrg    case CONNECTOR_HDMI_TYPE_A:
440b7e1c893Smrg    case CONNECTOR_HDMI_TYPE_B:
441b7e1c893Smrg	return atombios_maybe_hdmi_mode(output);
442b7e1c893Smrg	break;
443b7e1c893Smrg    case CONNECTOR_LVDS:
444b7e1c893Smrg	return ATOM_ENCODER_MODE_LVDS;
445b7e1c893Smrg	break;
446b7e1c893Smrg    case CONNECTOR_DISPLAY_PORT:
447b7e1c893Smrg	if (radeon_output->MonType == MT_DP)
448b7e1c893Smrg	    return ATOM_ENCODER_MODE_DP;
449b7e1c893Smrg	else
450b7e1c893Smrg	    return atombios_maybe_hdmi_mode(output);
451b7e1c893Smrg	break;
452b7e1c893Smrg    case CONNECTOR_DVI_A:
453b7e1c893Smrg    case CONNECTOR_VGA:
454b7e1c893Smrg    case CONNECTOR_STV:
455b7e1c893Smrg    case CONNECTOR_CTV:
456b7e1c893Smrg    case CONNECTOR_DIN:
457b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
458b7e1c893Smrg	    return ATOM_ENCODER_MODE_TV;
459b7e1c893Smrg	else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
460b7e1c893Smrg	    return ATOM_ENCODER_MODE_CV;
461b7e1c893Smrg	else
462b7e1c893Smrg	    return ATOM_ENCODER_MODE_CRT;
463b7e1c893Smrg	break;
464209ff23fSmrg    }
465209ff23fSmrg
466209ff23fSmrg}
467209ff23fSmrg
468b7e1c893Smrgstatic const int dp_clocks[] = {
469b7e1c893Smrg    16200,
470b7e1c893Smrg    27000,
471b7e1c893Smrg    32400,
472b7e1c893Smrg    54000,
473b7e1c893Smrg    0,
474b7e1c893Smrg    0,
475b7e1c893Smrg    64800,
476b7e1c893Smrg    108000,
477b7e1c893Smrg};
478b7e1c893Smrgstatic const int num_dp_clocks = sizeof(dp_clocks) / sizeof(int);
479b7e1c893Smrg
480209ff23fSmrgstatic int
481b7e1c893Smrgdp_lanes_for_mode_clock(int mode_clock)
482209ff23fSmrg{
483b7e1c893Smrg    int i;
484b7e1c893Smrg
485b7e1c893Smrg    for (i = 0; i < num_dp_clocks; i++)
486b7e1c893Smrg	if (dp_clocks[i] > (mode_clock / 10))
487b7e1c893Smrg	    return (i / 2) + 1;
488209ff23fSmrg
489b7e1c893Smrg    return 0;
490b7e1c893Smrg}
491209ff23fSmrg
492b7e1c893Smrgstatic int
493b7e1c893Smrgdp_link_clock_for_mode_clock(int mode_clock)
494b7e1c893Smrg{
495b7e1c893Smrg    int i;
496209ff23fSmrg
497b7e1c893Smrg    for (i = 0; i < num_dp_clocks; i++)
498b7e1c893Smrg	if (dp_clocks[i] > (mode_clock / 10))
499b7e1c893Smrg	    return (dp_clocks[i % 2]);
500b7e1c893Smrg
501b7e1c893Smrg    return 0;
502209ff23fSmrg}
503209ff23fSmrg
504209ff23fSmrgstatic int
505b7e1c893Smrgatombios_output_dig_encoder_setup(xf86OutputPtr output, int action)
506209ff23fSmrg{
507209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
508209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
509b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
510209ff23fSmrg    DIG_ENCODER_CONTROL_PS_ALLOCATION disp_data;
511209ff23fSmrg    AtomBiosArgRec data;
512209ff23fSmrg    unsigned char *space;
513b7e1c893Smrg    int index = 0, major, minor, num = 0;
514b7e1c893Smrg    int clock = radeon_output->pixel_clock;
515b7e1c893Smrg    int dig_block = radeon_output->dig_block;
516b7e1c893Smrg
517b7e1c893Smrg    if (radeon_encoder == NULL)
518b7e1c893Smrg	return ATOM_NOT_IMPLEMENTED;
519b7e1c893Smrg
520b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
521b7e1c893Smrg
522b7e1c893Smrg    if (IS_DCE32_VARIANT) {
523b7e1c893Smrg	if (dig_block)
524b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
525b7e1c893Smrg	else
526b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
527b7e1c893Smrg	num = dig_block + 1;
528b7e1c893Smrg    } else {
529b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
530b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
531b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
532b7e1c893Smrg	    num = 1;
533b7e1c893Smrg	    break;
534b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
535b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
536b7e1c893Smrg	    num = 2;
537b7e1c893Smrg	    break;
538b7e1c893Smrg	}
539b7e1c893Smrg    }
540209ff23fSmrg
541b7e1c893Smrg    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
542b7e1c893Smrg
543b7e1c893Smrg    disp_data.ucAction = action;
544b7e1c893Smrg    disp_data.usPixelClock = cpu_to_le16(clock / 10);
545b7e1c893Smrg
546b7e1c893Smrg    if (IS_DCE32_VARIANT) {
547b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
548b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
549b7e1c893Smrg	    disp_data.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1;
550b7e1c893Smrg	    break;
551b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
552b7e1c893Smrg	    disp_data.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2;
553b7e1c893Smrg	    break;
554b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
555b7e1c893Smrg	    disp_data.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3;
556b7e1c893Smrg	    break;
557b7e1c893Smrg	}
558b7e1c893Smrg    } else {
559b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
560b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
561b7e1c893Smrg	    disp_data.ucConfig = ATOM_ENCODER_CONFIG_UNIPHY;
562b7e1c893Smrg	    break;
563b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
564b7e1c893Smrg	    disp_data.ucConfig = ATOM_ENCODER_CONFIG_LVTMA;
565b7e1c893Smrg	    break;
566b7e1c893Smrg	}
567209ff23fSmrg    }
568209ff23fSmrg
569b7e1c893Smrg    disp_data.ucEncoderMode = atombios_get_encoder_mode(output);
570b7e1c893Smrg
571b7e1c893Smrg    if (disp_data.ucEncoderMode == ATOM_ENCODER_MODE_DP) {
572b7e1c893Smrg	if (radeon_output->linkb)
573b7e1c893Smrg	    disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
574b7e1c893Smrg	else
575b7e1c893Smrg	    disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
576b7e1c893Smrg
577b7e1c893Smrg	if (dp_link_clock_for_mode_clock(clock) == 27000)
578b7e1c893Smrg	    disp_data.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
579b7e1c893Smrg
580b7e1c893Smrg	disp_data.ucLaneNum = dp_lanes_for_mode_clock(clock);
581b7e1c893Smrg    } else if (clock > 165000) {
582209ff23fSmrg	disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKA_B;
583209ff23fSmrg	disp_data.ucLaneNum = 8;
584209ff23fSmrg    } else {
585b7e1c893Smrg	if (radeon_output->linkb)
586b7e1c893Smrg	    disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
587b7e1c893Smrg	else
588b7e1c893Smrg	    disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
589b7e1c893Smrg
590209ff23fSmrg	disp_data.ucLaneNum = 4;
591209ff23fSmrg    }
592209ff23fSmrg
593b7e1c893Smrg    data.exec.index = index;
594209ff23fSmrg    data.exec.dataSpace = (void *)&space;
595209ff23fSmrg    data.exec.pspace = &disp_data;
596209ff23fSmrg
597209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
598b7e1c893Smrg	ErrorF("Output DIG%d encoder setup success\n", num);
599209ff23fSmrg	return ATOM_SUCCESS;
600209ff23fSmrg    }
601209ff23fSmrg
602b7e1c893Smrg    ErrorF("Output DIG%d setup failed\n", num);
603209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
604209ff23fSmrg
605209ff23fSmrg}
606209ff23fSmrg
607b7e1c893Smrgunion dig_transmitter_control {
608b7e1c893Smrg    DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1;
609b7e1c893Smrg    DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2;
610b7e1c893Smrg};
611b7e1c893Smrg
612209ff23fSmrgstatic int
613b7e1c893Smrgatombios_output_dig_transmitter_setup(xf86OutputPtr output, int action)
614209ff23fSmrg{
615209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
616209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
617b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
618b7e1c893Smrg    union dig_transmitter_control disp_data;
619209ff23fSmrg    AtomBiosArgRec data;
620209ff23fSmrg    unsigned char *space;
621b7e1c893Smrg    int index = 0, num = 0;
622b7e1c893Smrg    int major, minor;
623b7e1c893Smrg    int clock = radeon_output->pixel_clock;
624b7e1c893Smrg    int dig_block = radeon_output->dig_block;
625b7e1c893Smrg
626b7e1c893Smrg    if (radeon_encoder == NULL)
627b7e1c893Smrg        return ATOM_NOT_IMPLEMENTED;
628b7e1c893Smrg
629b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
630b7e1c893Smrg
631b7e1c893Smrg    if (IS_DCE32_VARIANT)
632b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
633b7e1c893Smrg    else {
634b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
635b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
636b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DIG1TransmitterControl);
637b7e1c893Smrg	    break;
638b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
639b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DIG2TransmitterControl);
640b7e1c893Smrg	    break;
641b7e1c893Smrg	}
642b7e1c893Smrg    }
643209ff23fSmrg
644b7e1c893Smrg    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
645b7e1c893Smrg
646b7e1c893Smrg    disp_data.v1.ucAction = action;
647b7e1c893Smrg
648b7e1c893Smrg    if (IS_DCE32_VARIANT) {
649b7e1c893Smrg	if (radeon_output->MonType == MT_DP) {
650b7e1c893Smrg	    disp_data.v2.usPixelClock =
651b7e1c893Smrg		cpu_to_le16(dp_link_clock_for_mode_clock(clock));
652b7e1c893Smrg	    disp_data.v2.acConfig.fDPConnector = 1;
653b7e1c893Smrg	} else if (clock > 165000) {
654b7e1c893Smrg	    disp_data.v2.usPixelClock = cpu_to_le16((clock * 10 * 2) / 100);
655b7e1c893Smrg	    disp_data.v2.acConfig.fDualLinkConnector = 1;
656209ff23fSmrg	} else {
657b7e1c893Smrg	    disp_data.v2.usPixelClock = cpu_to_le16((clock * 10 * 4) / 100);
658b7e1c893Smrg	}
659b7e1c893Smrg	if (dig_block)
660b7e1c893Smrg	    disp_data.v2.acConfig.ucEncoderSel = 1;
661b7e1c893Smrg
662b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
663b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
664b7e1c893Smrg	    disp_data.v2.acConfig.ucTransmitterSel = 0;
665b7e1c893Smrg	    num = 0;
666b7e1c893Smrg	    break;
667b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
668b7e1c893Smrg	    disp_data.v2.acConfig.ucTransmitterSel = 1;
669b7e1c893Smrg	    num = 1;
670b7e1c893Smrg	    break;
671b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
672b7e1c893Smrg	    disp_data.v2.acConfig.ucTransmitterSel = 2;
673b7e1c893Smrg	    num = 2;
674b7e1c893Smrg	    break;
675b7e1c893Smrg	}
676b7e1c893Smrg
677b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) {
678b7e1c893Smrg	    if (radeon_output->coherent_mode) {
679b7e1c893Smrg		disp_data.v2.acConfig.fCoherentMode = 1;
680b7e1c893Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "UNIPHY%d transmitter: Coherent Mode enabled\n",disp_data.v2.acConfig.ucTransmitterSel);
681b7e1c893Smrg	    } else
682b7e1c893Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "UNIPHY%d transmitter: Coherent Mode disabled\n",disp_data.v2.acConfig.ucTransmitterSel);
683209ff23fSmrg	}
684209ff23fSmrg    } else {
685b7e1c893Smrg	disp_data.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL;
686b7e1c893Smrg
687b7e1c893Smrg	if (radeon_output->MonType == MT_DP)
688b7e1c893Smrg	    disp_data.v1.usPixelClock =
689b7e1c893Smrg		cpu_to_le16(dp_link_clock_for_mode_clock(clock));
690209ff23fSmrg	else
691b7e1c893Smrg	    disp_data.v1.usPixelClock = cpu_to_le16((clock) / 10);
692b7e1c893Smrg
693b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
694b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
695b7e1c893Smrg	    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
696b7e1c893Smrg	    if (info->IsIGP) {
697b7e1c893Smrg		if (clock > 165000) {
698b7e1c893Smrg		    disp_data.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK |
699b7e1c893Smrg					      ATOM_TRANSMITTER_CONFIG_LINKA_B);
700b7e1c893Smrg
701b7e1c893Smrg		    if (radeon_output->igp_lane_info & 0x3)
702b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7;
703b7e1c893Smrg		    else if (radeon_output->igp_lane_info & 0xc)
704b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15;
705b7e1c893Smrg		} else {
706b7e1c893Smrg		    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA;
707b7e1c893Smrg		    if (radeon_output->igp_lane_info & 0x1)
708b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3;
709b7e1c893Smrg		    else if (radeon_output->igp_lane_info & 0x2)
710b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7;
711b7e1c893Smrg		    else if (radeon_output->igp_lane_info & 0x4)
712b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11;
713b7e1c893Smrg		    else if (radeon_output->igp_lane_info & 0x8)
714b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15;
715b7e1c893Smrg		}
716b7e1c893Smrg	    } else {
717b7e1c893Smrg		if (clock > 165000)
718b7e1c893Smrg		    disp_data.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK |
719b7e1c893Smrg					      ATOM_TRANSMITTER_CONFIG_LINKA_B |
720b7e1c893Smrg					      ATOM_TRANSMITTER_CONFIG_LANE_0_7);
721b7e1c893Smrg		else {
722b7e1c893Smrg		    /* XXX */
723b7e1c893Smrg		    if (radeon_output->linkb)
724b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
725b7e1c893Smrg		    else
726b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
727b7e1c893Smrg		}
728b7e1c893Smrg	    }
729b7e1c893Smrg	    break;
730b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
731b7e1c893Smrg	    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
732b7e1c893Smrg	    if (clock > 165000)
733b7e1c893Smrg		disp_data.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK |
734b7e1c893Smrg					  ATOM_TRANSMITTER_CONFIG_LINKA_B |
735b7e1c893Smrg					  ATOM_TRANSMITTER_CONFIG_LANE_0_7);
736b7e1c893Smrg	    else {
737b7e1c893Smrg		/* XXX */
738b7e1c893Smrg		if (radeon_output->linkb)
739b7e1c893Smrg		    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
740b7e1c893Smrg		else
741b7e1c893Smrg		    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
742b7e1c893Smrg	    }
743b7e1c893Smrg	    break;
744b7e1c893Smrg	}
745209ff23fSmrg
746b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) {
747b7e1c893Smrg	    if (radeon_output->coherent_mode &&
748b7e1c893Smrg		radeon_output->MonType != MT_DP) {
749b7e1c893Smrg		disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
750b7e1c893Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
751b7e1c893Smrg			"DIG%d transmitter: Coherent Mode enabled\n", num);
752b7e1c893Smrg	    } else {
753b7e1c893Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
754b7e1c893Smrg			"DIG%d transmitter: Coherent Mode disabled\n", num);
755b7e1c893Smrg	    }
756b7e1c893Smrg	}
757b7e1c893Smrg    }
758209ff23fSmrg
759b7e1c893Smrg    data.exec.index = index;
760209ff23fSmrg    data.exec.dataSpace = (void *)&space;
761209ff23fSmrg    data.exec.pspace = &disp_data;
762209ff23fSmrg
763209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
764b7e1c893Smrg	if (IS_DCE32_VARIANT)
765b7e1c893Smrg	    ErrorF("Output UNIPHY%d transmitter setup success\n", num);
766b7e1c893Smrg	else
767b7e1c893Smrg	   ErrorF("Output DIG%d transmitter setup success\n", num);
768209ff23fSmrg	return ATOM_SUCCESS;
769209ff23fSmrg    }
770209ff23fSmrg
771b7e1c893Smrg    ErrorF("Output DIG%d transmitter setup failed\n", num);
772209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
773209ff23fSmrg
774209ff23fSmrg}
775209ff23fSmrg
776c503f109Smrgstatic void atom_rv515_force_tv_scaler(ScrnInfoPtr pScrn, RADEONCrtcPrivatePtr radeon_crtc)
777b7e1c893Smrg{
778b7e1c893Smrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
779b7e1c893Smrg    unsigned char *RADEONMMIO = info->MMIO;
780c503f109Smrg    int index_reg = 0x6578, data_reg = 0x657c;
781c503f109Smrg
782c503f109Smrg    index_reg += radeon_crtc->crtc_offset;
783c503f109Smrg    data_reg += radeon_crtc->crtc_offset;
784c503f109Smrg
785c503f109Smrg    OUTREG(0x659C + radeon_crtc->crtc_offset, 0x0);
786c503f109Smrg    OUTREG(0x6594 + radeon_crtc->crtc_offset, 0x705);
787c503f109Smrg    OUTREG(0x65A4 + radeon_crtc->crtc_offset, 0x10001);
788c503f109Smrg    OUTREG(0x65D8 + radeon_crtc->crtc_offset, 0x0);
789c503f109Smrg    OUTREG(0x65B0 + radeon_crtc->crtc_offset, 0x0);
790c503f109Smrg    OUTREG(0x65C0 + radeon_crtc->crtc_offset, 0x0);
791c503f109Smrg    OUTREG(0x65D4 + radeon_crtc->crtc_offset, 0x0);
792c503f109Smrg    OUTREG(index_reg,0x0);
793c503f109Smrg    OUTREG(data_reg,0x841880A8);
794c503f109Smrg    OUTREG(index_reg,0x1);
795c503f109Smrg    OUTREG(data_reg,0x84208680);
796c503f109Smrg    OUTREG(index_reg,0x2);
797c503f109Smrg    OUTREG(data_reg,0xBFF880B0);
798c503f109Smrg    OUTREG(index_reg,0x100);
799c503f109Smrg    OUTREG(data_reg,0x83D88088);
800c503f109Smrg    OUTREG(index_reg,0x101);
801c503f109Smrg    OUTREG(data_reg,0x84608680);
802c503f109Smrg    OUTREG(index_reg,0x102);
803c503f109Smrg    OUTREG(data_reg,0xBFF080D0);
804c503f109Smrg    OUTREG(index_reg,0x200);
805c503f109Smrg    OUTREG(data_reg,0x83988068);
806c503f109Smrg    OUTREG(index_reg,0x201);
807c503f109Smrg    OUTREG(data_reg,0x84A08680);
808c503f109Smrg    OUTREG(index_reg,0x202);
809c503f109Smrg    OUTREG(data_reg,0xBFF080F8);
810c503f109Smrg    OUTREG(index_reg,0x300);
811c503f109Smrg    OUTREG(data_reg,0x83588058);
812c503f109Smrg    OUTREG(index_reg,0x301);
813c503f109Smrg    OUTREG(data_reg,0x84E08660);
814c503f109Smrg    OUTREG(index_reg,0x302);
815c503f109Smrg    OUTREG(data_reg,0xBFF88120);
816c503f109Smrg    OUTREG(index_reg,0x400);
817c503f109Smrg    OUTREG(data_reg,0x83188040);
818c503f109Smrg    OUTREG(index_reg,0x401);
819c503f109Smrg    OUTREG(data_reg,0x85008660);
820c503f109Smrg    OUTREG(index_reg,0x402);
821c503f109Smrg    OUTREG(data_reg,0xBFF88150);
822c503f109Smrg    OUTREG(index_reg,0x500);
823c503f109Smrg    OUTREG(data_reg,0x82D88030);
824c503f109Smrg    OUTREG(index_reg,0x501);
825c503f109Smrg    OUTREG(data_reg,0x85408640);
826c503f109Smrg    OUTREG(index_reg,0x502);
827c503f109Smrg    OUTREG(data_reg,0xBFF88180);
828c503f109Smrg    OUTREG(index_reg,0x600);
829c503f109Smrg    OUTREG(data_reg,0x82A08018);
830c503f109Smrg    OUTREG(index_reg,0x601);
831c503f109Smrg    OUTREG(data_reg,0x85808620);
832c503f109Smrg    OUTREG(index_reg,0x602);
833c503f109Smrg    OUTREG(data_reg,0xBFF081B8);
834c503f109Smrg    OUTREG(index_reg,0x700);
835c503f109Smrg    OUTREG(data_reg,0x82608010);
836c503f109Smrg    OUTREG(index_reg,0x701);
837c503f109Smrg    OUTREG(data_reg,0x85A08600);
838c503f109Smrg    OUTREG(index_reg,0x702);
839c503f109Smrg    OUTREG(data_reg,0x800081F0);
840c503f109Smrg    OUTREG(index_reg,0x800);
841c503f109Smrg    OUTREG(data_reg,0x8228BFF8);
842c503f109Smrg    OUTREG(index_reg,0x801);
843c503f109Smrg    OUTREG(data_reg,0x85E085E0);
844c503f109Smrg    OUTREG(index_reg,0x802);
845c503f109Smrg    OUTREG(data_reg,0xBFF88228);
846c503f109Smrg    OUTREG(index_reg,0x10000);
847c503f109Smrg    OUTREG(data_reg,0x82A8BF00);
848c503f109Smrg    OUTREG(index_reg,0x10001);
849c503f109Smrg    OUTREG(data_reg,0x82A08CC0);
850c503f109Smrg    OUTREG(index_reg,0x10002);
851c503f109Smrg    OUTREG(data_reg,0x8008BEF8);
852c503f109Smrg    OUTREG(index_reg,0x10100);
853c503f109Smrg    OUTREG(data_reg,0x81F0BF28);
854c503f109Smrg    OUTREG(index_reg,0x10101);
855c503f109Smrg    OUTREG(data_reg,0x83608CA0);
856c503f109Smrg    OUTREG(index_reg,0x10102);
857c503f109Smrg    OUTREG(data_reg,0x8018BED0);
858c503f109Smrg    OUTREG(index_reg,0x10200);
859c503f109Smrg    OUTREG(data_reg,0x8148BF38);
860c503f109Smrg    OUTREG(index_reg,0x10201);
861c503f109Smrg    OUTREG(data_reg,0x84408C80);
862c503f109Smrg    OUTREG(index_reg,0x10202);
863c503f109Smrg    OUTREG(data_reg,0x8008BEB8);
864c503f109Smrg    OUTREG(index_reg,0x10300);
865c503f109Smrg    OUTREG(data_reg,0x80B0BF78);
866c503f109Smrg    OUTREG(index_reg,0x10301);
867c503f109Smrg    OUTREG(data_reg,0x85008C20);
868c503f109Smrg    OUTREG(index_reg,0x10302);
869c503f109Smrg    OUTREG(data_reg,0x8020BEA0);
870c503f109Smrg    OUTREG(index_reg,0x10400);
871c503f109Smrg    OUTREG(data_reg,0x8028BF90);
872c503f109Smrg    OUTREG(index_reg,0x10401);
873c503f109Smrg    OUTREG(data_reg,0x85E08BC0);
874c503f109Smrg    OUTREG(index_reg,0x10402);
875c503f109Smrg    OUTREG(data_reg,0x8018BE90);
876c503f109Smrg    OUTREG(index_reg,0x10500);
877c503f109Smrg    OUTREG(data_reg,0xBFB8BFB0);
878c503f109Smrg    OUTREG(index_reg,0x10501);
879c503f109Smrg    OUTREG(data_reg,0x86C08B40);
880c503f109Smrg    OUTREG(index_reg,0x10502);
881c503f109Smrg    OUTREG(data_reg,0x8010BE90);
882c503f109Smrg    OUTREG(index_reg,0x10600);
883c503f109Smrg    OUTREG(data_reg,0xBF58BFC8);
884c503f109Smrg    OUTREG(index_reg,0x10601);
885c503f109Smrg    OUTREG(data_reg,0x87A08AA0);
886c503f109Smrg    OUTREG(index_reg,0x10602);
887c503f109Smrg    OUTREG(data_reg,0x8010BE98);
888c503f109Smrg    OUTREG(index_reg,0x10700);
889c503f109Smrg    OUTREG(data_reg,0xBF10BFF0);
890c503f109Smrg    OUTREG(index_reg,0x10701);
891c503f109Smrg    OUTREG(data_reg,0x886089E0);
892c503f109Smrg    OUTREG(index_reg,0x10702);
893c503f109Smrg    OUTREG(data_reg,0x8018BEB0);
894c503f109Smrg    OUTREG(index_reg,0x10800);
895c503f109Smrg    OUTREG(data_reg,0xBED8BFE8);
896c503f109Smrg    OUTREG(index_reg,0x10801);
897c503f109Smrg    OUTREG(data_reg,0x89408940);
898c503f109Smrg    OUTREG(index_reg,0x10802);
899c503f109Smrg    OUTREG(data_reg,0xBFE8BED8);
900c503f109Smrg    OUTREG(index_reg,0x20000);
901c503f109Smrg    OUTREG(data_reg,0x80008000);
902c503f109Smrg    OUTREG(index_reg,0x20001);
903c503f109Smrg    OUTREG(data_reg,0x90008000);
904c503f109Smrg    OUTREG(index_reg,0x20002);
905c503f109Smrg    OUTREG(data_reg,0x80008000);
906c503f109Smrg    OUTREG(index_reg,0x20003);
907c503f109Smrg    OUTREG(data_reg,0x80008000);
908c503f109Smrg    OUTREG(index_reg,0x20100);
909c503f109Smrg    OUTREG(data_reg,0x80108000);
910c503f109Smrg    OUTREG(index_reg,0x20101);
911c503f109Smrg    OUTREG(data_reg,0x8FE0BF70);
912c503f109Smrg    OUTREG(index_reg,0x20102);
913c503f109Smrg    OUTREG(data_reg,0xBFE880C0);
914c503f109Smrg    OUTREG(index_reg,0x20103);
915c503f109Smrg    OUTREG(data_reg,0x80008000);
916c503f109Smrg    OUTREG(index_reg,0x20200);
917c503f109Smrg    OUTREG(data_reg,0x8018BFF8);
918c503f109Smrg    OUTREG(index_reg,0x20201);
919c503f109Smrg    OUTREG(data_reg,0x8F80BF08);
920c503f109Smrg    OUTREG(index_reg,0x20202);
921c503f109Smrg    OUTREG(data_reg,0xBFD081A0);
922c503f109Smrg    OUTREG(index_reg,0x20203);
923c503f109Smrg    OUTREG(data_reg,0xBFF88000);
924c503f109Smrg    OUTREG(index_reg,0x20300);
925c503f109Smrg    OUTREG(data_reg,0x80188000);
926c503f109Smrg    OUTREG(index_reg,0x20301);
927c503f109Smrg    OUTREG(data_reg,0x8EE0BEC0);
928c503f109Smrg    OUTREG(index_reg,0x20302);
929c503f109Smrg    OUTREG(data_reg,0xBFB082A0);
930c503f109Smrg    OUTREG(index_reg,0x20303);
931c503f109Smrg    OUTREG(data_reg,0x80008000);
932c503f109Smrg    OUTREG(index_reg,0x20400);
933c503f109Smrg    OUTREG(data_reg,0x80188000);
934c503f109Smrg    OUTREG(index_reg,0x20401);
935c503f109Smrg    OUTREG(data_reg,0x8E00BEA0);
936c503f109Smrg    OUTREG(index_reg,0x20402);
937c503f109Smrg    OUTREG(data_reg,0xBF8883C0);
938c503f109Smrg    OUTREG(index_reg,0x20403);
939c503f109Smrg    OUTREG(data_reg,0x80008000);
940c503f109Smrg    OUTREG(index_reg,0x20500);
941c503f109Smrg    OUTREG(data_reg,0x80188000);
942c503f109Smrg    OUTREG(index_reg,0x20501);
943c503f109Smrg    OUTREG(data_reg,0x8D00BE90);
944c503f109Smrg    OUTREG(index_reg,0x20502);
945c503f109Smrg    OUTREG(data_reg,0xBF588500);
946c503f109Smrg    OUTREG(index_reg,0x20503);
947c503f109Smrg    OUTREG(data_reg,0x80008008);
948c503f109Smrg    OUTREG(index_reg,0x20600);
949c503f109Smrg    OUTREG(data_reg,0x80188000);
950c503f109Smrg    OUTREG(index_reg,0x20601);
951c503f109Smrg    OUTREG(data_reg,0x8BC0BE98);
952c503f109Smrg    OUTREG(index_reg,0x20602);
953c503f109Smrg    OUTREG(data_reg,0xBF308660);
954c503f109Smrg    OUTREG(index_reg,0x20603);
955c503f109Smrg    OUTREG(data_reg,0x80008008);
956c503f109Smrg    OUTREG(index_reg,0x20700);
957c503f109Smrg    OUTREG(data_reg,0x80108000);
958c503f109Smrg    OUTREG(index_reg,0x20701);
959c503f109Smrg    OUTREG(data_reg,0x8A80BEB0);
960c503f109Smrg    OUTREG(index_reg,0x20702);
961c503f109Smrg    OUTREG(data_reg,0xBF0087C0);
962c503f109Smrg    OUTREG(index_reg,0x20703);
963c503f109Smrg    OUTREG(data_reg,0x80008008);
964c503f109Smrg    OUTREG(index_reg,0x20800);
965c503f109Smrg    OUTREG(data_reg,0x80108000);
966c503f109Smrg    OUTREG(index_reg,0x20801);
967c503f109Smrg    OUTREG(data_reg,0x8920BED0);
968c503f109Smrg    OUTREG(index_reg,0x20802);
969c503f109Smrg    OUTREG(data_reg,0xBED08920);
970c503f109Smrg    OUTREG(index_reg,0x20803);
971c503f109Smrg    OUTREG(data_reg,0x80008010);
972c503f109Smrg    OUTREG(index_reg,0x30000);
973c503f109Smrg    OUTREG(data_reg,0x90008000);
974c503f109Smrg    OUTREG(index_reg,0x30001);
975c503f109Smrg    OUTREG(data_reg,0x80008000);
976c503f109Smrg    OUTREG(index_reg,0x30100);
977c503f109Smrg    OUTREG(data_reg,0x8FE0BF90);
978c503f109Smrg    OUTREG(index_reg,0x30101);
979c503f109Smrg    OUTREG(data_reg,0xBFF880A0);
980c503f109Smrg    OUTREG(index_reg,0x30200);
981c503f109Smrg    OUTREG(data_reg,0x8F60BF40);
982c503f109Smrg    OUTREG(index_reg,0x30201);
983c503f109Smrg    OUTREG(data_reg,0xBFE88180);
984c503f109Smrg    OUTREG(index_reg,0x30300);
985c503f109Smrg    OUTREG(data_reg,0x8EC0BF00);
986c503f109Smrg    OUTREG(index_reg,0x30301);
987c503f109Smrg    OUTREG(data_reg,0xBFC88280);
988c503f109Smrg    OUTREG(index_reg,0x30400);
989c503f109Smrg    OUTREG(data_reg,0x8DE0BEE0);
990c503f109Smrg    OUTREG(index_reg,0x30401);
991c503f109Smrg    OUTREG(data_reg,0xBFA083A0);
992c503f109Smrg    OUTREG(index_reg,0x30500);
993c503f109Smrg    OUTREG(data_reg,0x8CE0BED0);
994c503f109Smrg    OUTREG(index_reg,0x30501);
995c503f109Smrg    OUTREG(data_reg,0xBF7884E0);
996c503f109Smrg    OUTREG(index_reg,0x30600);
997c503f109Smrg    OUTREG(data_reg,0x8BA0BED8);
998c503f109Smrg    OUTREG(index_reg,0x30601);
999c503f109Smrg    OUTREG(data_reg,0xBF508640);
1000c503f109Smrg    OUTREG(index_reg,0x30700);
1001c503f109Smrg    OUTREG(data_reg,0x8A60BEE8);
1002c503f109Smrg    OUTREG(index_reg,0x30701);
1003c503f109Smrg    OUTREG(data_reg,0xBF2087A0);
1004c503f109Smrg    OUTREG(index_reg,0x30800);
1005c503f109Smrg    OUTREG(data_reg,0x8900BF00);
1006c503f109Smrg    OUTREG(index_reg,0x30801);
1007c503f109Smrg    OUTREG(data_reg,0xBF008900);
1008b7e1c893Smrg}
1009b7e1c893Smrg
1010209ff23fSmrgstatic int
1011b7e1c893Smrgatombios_output_yuv_setup(xf86OutputPtr output, Bool enable)
1012209ff23fSmrg{
1013209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1014209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1015b7e1c893Smrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1016b7e1c893Smrg    ENABLE_YUV_PS_ALLOCATION disp_data;
1017209ff23fSmrg    AtomBiosArgRec data;
1018209ff23fSmrg    unsigned char *space;
1019b7e1c893Smrg    unsigned char *RADEONMMIO = info->MMIO;
1020b7e1c893Smrg    uint32_t temp, reg;
1021209ff23fSmrg
1022b7e1c893Smrg    if (info->ChipFamily >= CHIP_FAMILY_R600)
1023b7e1c893Smrg	reg = R600_BIOS_3_SCRATCH;
1024b7e1c893Smrg    else
1025b7e1c893Smrg	reg = RADEON_BIOS_3_SCRATCH;
1026b7e1c893Smrg
1027b7e1c893Smrg    //fix up scratch reg handling
1028b7e1c893Smrg    temp = INREG(reg);
1029b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1030b7e1c893Smrg	OUTREG(reg, (ATOM_S3_TV1_ACTIVE |
1031b7e1c893Smrg		     (radeon_crtc->crtc_id << 18)));
1032b7e1c893Smrg    else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1033b7e1c893Smrg	OUTREG(reg, (ATOM_S3_CV_ACTIVE |
1034b7e1c893Smrg		     (radeon_crtc->crtc_id << 24)));
1035b7e1c893Smrg    else
1036b7e1c893Smrg	OUTREG(reg, 0);
1037209ff23fSmrg
1038b7e1c893Smrg    memset(&disp_data, 0, sizeof(disp_data));
1039209ff23fSmrg
1040b7e1c893Smrg    if (enable)
1041b7e1c893Smrg	disp_data.ucEnable = ATOM_ENABLE;
1042b7e1c893Smrg    disp_data.ucCRTC = radeon_crtc->crtc_id;
1043209ff23fSmrg
1044b7e1c893Smrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableYUV);
1045209ff23fSmrg    data.exec.dataSpace = (void *)&space;
1046209ff23fSmrg    data.exec.pspace = &disp_data;
1047209ff23fSmrg
1048209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
1049b7e1c893Smrg
1050b7e1c893Smrg	OUTREG(reg, temp);
1051b7e1c893Smrg
1052b7e1c893Smrg	ErrorF("crtc %d YUV %s setup success\n", radeon_crtc->crtc_id, enable ? "enable" : "disable");
1053209ff23fSmrg	return ATOM_SUCCESS;
1054209ff23fSmrg    }
1055209ff23fSmrg
1056b7e1c893Smrg    OUTREG(reg, temp);
1057b7e1c893Smrg
1058b7e1c893Smrg    ErrorF("crtc %d YUV %s setup failed\n", radeon_crtc->crtc_id, enable ? "enable" : "disable");
1059209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
1060209ff23fSmrg
1061209ff23fSmrg}
1062209ff23fSmrg
1063209ff23fSmrgstatic int
1064b7e1c893Smrgatombios_output_overscan_setup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
1065209ff23fSmrg{
1066209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1067b7e1c893Smrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1068209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1069b7e1c893Smrg    SET_CRTC_OVERSCAN_PS_ALLOCATION overscan_param;
1070209ff23fSmrg    AtomBiosArgRec data;
1071209ff23fSmrg    unsigned char *space;
1072b7e1c893Smrg    memset(&overscan_param, 0, sizeof(overscan_param));
1073209ff23fSmrg
1074b7e1c893Smrg    overscan_param.usOverscanRight = 0;
1075b7e1c893Smrg    overscan_param.usOverscanLeft = 0;
1076b7e1c893Smrg    overscan_param.usOverscanBottom = 0;
1077b7e1c893Smrg    overscan_param.usOverscanTop = 0;
1078b7e1c893Smrg    overscan_param.ucCRTC = radeon_crtc->crtc_id;
1079b7e1c893Smrg
1080b7e1c893Smrg    if (radeon_output->Flags & RADEON_USE_RMX) {
1081b7e1c893Smrg	if (radeon_output->rmx_type == RMX_FULL) {
1082b7e1c893Smrg	    overscan_param.usOverscanRight = 0;
1083b7e1c893Smrg	    overscan_param.usOverscanLeft = 0;
1084b7e1c893Smrg	    overscan_param.usOverscanBottom = 0;
1085b7e1c893Smrg	    overscan_param.usOverscanTop = 0;
1086b7e1c893Smrg	} else if (radeon_output->rmx_type == RMX_CENTER) {
1087b7e1c893Smrg	    overscan_param.usOverscanTop = (adjusted_mode->CrtcVDisplay - mode->CrtcVDisplay) / 2;
1088b7e1c893Smrg	    overscan_param.usOverscanBottom = (adjusted_mode->CrtcVDisplay - mode->CrtcVDisplay) / 2;
1089b7e1c893Smrg	    overscan_param.usOverscanLeft = (adjusted_mode->CrtcHDisplay - mode->CrtcHDisplay) / 2;
1090b7e1c893Smrg	    overscan_param.usOverscanRight = (adjusted_mode->CrtcHDisplay - mode->CrtcHDisplay) / 2;
1091b7e1c893Smrg	} else if (radeon_output->rmx_type == RMX_ASPECT) {
1092b7e1c893Smrg	    int a1 = mode->CrtcVDisplay * adjusted_mode->CrtcHDisplay;
1093b7e1c893Smrg	    int a2 = adjusted_mode->CrtcVDisplay * mode->CrtcHDisplay;
1094b7e1c893Smrg
1095b7e1c893Smrg	    if (a1 > a2) {
1096b7e1c893Smrg		overscan_param.usOverscanLeft = (adjusted_mode->CrtcHDisplay - (a2 / mode->CrtcVDisplay)) / 2;
1097b7e1c893Smrg		overscan_param.usOverscanRight = (adjusted_mode->CrtcHDisplay - (a2 / mode->CrtcVDisplay)) / 2;
1098b7e1c893Smrg	    } else if (a2 > a1) {
1099b7e1c893Smrg		overscan_param.usOverscanLeft = (adjusted_mode->CrtcVDisplay - (a1 / mode->CrtcHDisplay)) / 2;
1100b7e1c893Smrg		overscan_param.usOverscanRight = (adjusted_mode->CrtcVDisplay - (a1 / mode->CrtcHDisplay)) / 2;
1101b7e1c893Smrg	    }
1102209ff23fSmrg	}
1103209ff23fSmrg    }
1104209ff23fSmrg
1105b7e1c893Smrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan);
1106209ff23fSmrg    data.exec.dataSpace = (void *)&space;
1107b7e1c893Smrg    data.exec.pspace = &overscan_param;
1108209ff23fSmrg
1109209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
1110b7e1c893Smrg	ErrorF("Set CRTC %d Overscan success\n", radeon_crtc->crtc_id);
1111b7e1c893Smrg	return ATOM_SUCCESS ;
1112209ff23fSmrg    }
1113209ff23fSmrg
1114b7e1c893Smrg    ErrorF("Set CRTC %d Overscan failed\n", radeon_crtc->crtc_id);
1115209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
1116209ff23fSmrg}
1117209ff23fSmrg
1118209ff23fSmrgstatic int
1119b7e1c893Smrgatombios_output_scaler_setup(xf86OutputPtr output)
1120209ff23fSmrg{
1121209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1122209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1123b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
1124209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1125209ff23fSmrg    ENABLE_SCALER_PS_ALLOCATION disp_data;
1126209ff23fSmrg    AtomBiosArgRec data;
1127209ff23fSmrg    unsigned char *space;
1128209ff23fSmrg
1129b7e1c893Smrg    if (!IS_AVIVO_VARIANT && radeon_crtc->crtc_id)
1130b7e1c893Smrg	return ATOM_SUCCESS;
1131b7e1c893Smrg
1132b7e1c893Smrg    memset(&disp_data, 0, sizeof(disp_data));
1133b7e1c893Smrg
1134209ff23fSmrg    disp_data.ucScaler = radeon_crtc->crtc_id;
1135209ff23fSmrg
1136b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
1137b7e1c893Smrg	switch (tvout->tvStd) {
1138b7e1c893Smrg	case TV_STD_NTSC:
1139b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_NTSC;
1140b7e1c893Smrg	    break;
1141b7e1c893Smrg	case TV_STD_PAL:
1142b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_PAL;
1143b7e1c893Smrg	    break;
1144b7e1c893Smrg	case TV_STD_PAL_M:
1145b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_PALM;
1146b7e1c893Smrg	    break;
1147b7e1c893Smrg	case TV_STD_PAL_60:
1148b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_PAL60;
1149b7e1c893Smrg	    break;
1150b7e1c893Smrg	case TV_STD_NTSC_J:
1151b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_NTSCJ;
1152b7e1c893Smrg	    break;
1153b7e1c893Smrg	case TV_STD_SCART_PAL:
1154b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_PAL; /* ??? */
1155b7e1c893Smrg	    break;
1156b7e1c893Smrg	case TV_STD_SECAM:
1157b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_SECAM;
1158b7e1c893Smrg	    break;
1159b7e1c893Smrg	case TV_STD_PAL_CN:
1160b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_PALCN;
1161b7e1c893Smrg	    break;
1162b7e1c893Smrg	default:
1163b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_NTSC;
1164b7e1c893Smrg	    break;
1165b7e1c893Smrg	}
1166b7e1c893Smrg	disp_data.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
1167b7e1c893Smrg        ErrorF("Using TV scaler %x %x\n", disp_data.ucTVStandard, disp_data.ucEnable);
1168b7e1c893Smrg    } else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) {
1169b7e1c893Smrg	disp_data.ucTVStandard = ATOM_TV_CV;
1170b7e1c893Smrg	disp_data.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
1171b7e1c893Smrg        ErrorF("Using CV scaler %x %x\n", disp_data.ucTVStandard, disp_data.ucEnable);
1172b7e1c893Smrg    } else if (radeon_output->Flags & RADEON_USE_RMX) {
1173209ff23fSmrg	ErrorF("Using RMX\n");
1174209ff23fSmrg	if (radeon_output->rmx_type == RMX_FULL)
1175209ff23fSmrg	    disp_data.ucEnable = ATOM_SCALER_EXPANSION;
1176209ff23fSmrg	else if (radeon_output->rmx_type == RMX_CENTER)
1177209ff23fSmrg	    disp_data.ucEnable = ATOM_SCALER_CENTER;
1178b7e1c893Smrg	else if (radeon_output->rmx_type == RMX_ASPECT)
1179b7e1c893Smrg	    disp_data.ucEnable = ATOM_SCALER_EXPANSION;
1180209ff23fSmrg    } else {
1181209ff23fSmrg	ErrorF("Not using RMX\n");
1182b7e1c893Smrg	if (IS_AVIVO_VARIANT)
1183b7e1c893Smrg	    disp_data.ucEnable = ATOM_SCALER_DISABLE;
1184b7e1c893Smrg	else
1185b7e1c893Smrg	    disp_data.ucEnable = ATOM_SCALER_CENTER;
1186209ff23fSmrg    }
1187209ff23fSmrg
1188209ff23fSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
1189209ff23fSmrg    data.exec.dataSpace = (void *)&space;
1190209ff23fSmrg    data.exec.pspace = &disp_data;
1191209ff23fSmrg
1192209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
1193b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)
1194b7e1c893Smrg	    && info->ChipFamily >= CHIP_FAMILY_RV515 && info->ChipFamily <= CHIP_FAMILY_RV570) {
1195b7e1c893Smrg	    ErrorF("forcing TV scaler\n");
1196c503f109Smrg	    atom_rv515_force_tv_scaler(output->scrn, radeon_crtc);
1197b7e1c893Smrg	}
1198209ff23fSmrg	ErrorF("scaler %d setup success\n", radeon_crtc->crtc_id);
1199209ff23fSmrg	return ATOM_SUCCESS;
1200209ff23fSmrg    }
1201209ff23fSmrg
1202209ff23fSmrg    ErrorF("scaler %d setup failed\n", radeon_crtc->crtc_id);
1203209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
1204209ff23fSmrg
1205209ff23fSmrg}
1206209ff23fSmrg
1207b7e1c893Smrgvoid
1208b7e1c893Smrgatombios_output_dpms(xf86OutputPtr output, int mode)
1209209ff23fSmrg{
1210b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1211b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
1212209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1213209ff23fSmrg    DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION disp_data;
1214209ff23fSmrg    AtomBiosArgRec data;
1215209ff23fSmrg    unsigned char *space;
1216209ff23fSmrg    int index = 0;
1217b7e1c893Smrg    Bool is_dig = FALSE;
1218209ff23fSmrg
1219b7e1c893Smrg    if (radeon_encoder == NULL)
1220b7e1c893Smrg        return;
1221b7e1c893Smrg
1222b7e1c893Smrg    switch (radeon_encoder->encoder_id) {
1223b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1224b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
1225209ff23fSmrg	index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl);
1226209ff23fSmrg	break;
1227b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1228b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1229b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1230b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1231b7e1c893Smrg	is_dig = TRUE;
1232209ff23fSmrg	break;
1233b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1234b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DDI:
1235b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
1236b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
1237209ff23fSmrg	break;
1238b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
1239209ff23fSmrg	index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
1240209ff23fSmrg	break;
1241b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1242b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT))
1243b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
1244b7e1c893Smrg	else
1245b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl);
1246209ff23fSmrg	break;
1247b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
1248b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1249b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1250b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
1251b7e1c893Smrg	else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1252b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
1253b7e1c893Smrg	else
1254b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl);
1255209ff23fSmrg	break;
1256b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1257b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1258b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1259b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
1260b7e1c893Smrg	else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1261b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
1262b7e1c893Smrg	else
1263b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl);
1264209ff23fSmrg	break;
1265209ff23fSmrg    }
1266209ff23fSmrg
1267209ff23fSmrg    switch (mode) {
1268209ff23fSmrg    case DPMSModeOn:
1269b7e1c893Smrg	radeon_encoder->devices |= radeon_output->active_device;
1270b7e1c893Smrg	if (is_dig)
1271b7e1c893Smrg	    atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT);
1272b7e1c893Smrg	else {
1273b7e1c893Smrg	    disp_data.ucAction = ATOM_ENABLE;
1274b7e1c893Smrg	    data.exec.index = index;
1275b7e1c893Smrg	    data.exec.dataSpace = (void *)&space;
1276b7e1c893Smrg	    data.exec.pspace = &disp_data;
1277b7e1c893Smrg
1278b7e1c893Smrg	    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS)
1279b7e1c893Smrg		ErrorF("Output %s enable success\n",
1280b7e1c893Smrg		       device_name[radeon_get_device_index(radeon_output->active_device)]);
1281b7e1c893Smrg	    else
1282b7e1c893Smrg		ErrorF("Output %s enable failed\n",
1283b7e1c893Smrg		       device_name[radeon_get_device_index(radeon_output->active_device)]);
1284b7e1c893Smrg	}
1285c503f109Smrg	/* at least for TV atom fails to reassociate the correct crtc source at dpms on */
1286c503f109Smrg	if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1287c503f109Smrg		atombios_set_output_crtc_source(output);
1288209ff23fSmrg	break;
1289209ff23fSmrg    case DPMSModeStandby:
1290209ff23fSmrg    case DPMSModeSuspend:
1291209ff23fSmrg    case DPMSModeOff:
1292b7e1c893Smrg	radeon_encoder->devices &= ~(radeon_output->active_device);
1293b7e1c893Smrg	if (!radeon_encoder->devices) {
1294b7e1c893Smrg	    if (is_dig)
1295b7e1c893Smrg		atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT);
1296b7e1c893Smrg	    else {
1297b7e1c893Smrg		disp_data.ucAction = ATOM_DISABLE;
1298b7e1c893Smrg		data.exec.index = index;
1299b7e1c893Smrg		data.exec.dataSpace = (void *)&space;
1300b7e1c893Smrg		data.exec.pspace = &disp_data;
1301b7e1c893Smrg
1302b7e1c893Smrg		if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data)
1303b7e1c893Smrg		    == ATOM_SUCCESS)
1304b7e1c893Smrg		    ErrorF("Output %s disable success\n",
1305b7e1c893Smrg			   device_name[radeon_get_device_index(radeon_output->active_device)]);
1306b7e1c893Smrg		else
1307b7e1c893Smrg		    ErrorF("Output %s disable failed\n",
1308b7e1c893Smrg			   device_name[radeon_get_device_index(radeon_output->active_device)]);
1309b7e1c893Smrg	    }
1310209ff23fSmrg	}
1311b7e1c893Smrg	break;
1312209ff23fSmrg    }
1313209ff23fSmrg}
1314209ff23fSmrg
1315209ff23fSmrgstatic void
1316209ff23fSmrgatombios_set_output_crtc_source(xf86OutputPtr output)
1317209ff23fSmrg{
1318209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1319209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1320209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1321b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
1322209ff23fSmrg    AtomBiosArgRec data;
1323209ff23fSmrg    unsigned char *space;
1324209ff23fSmrg    SELECT_CRTC_SOURCE_PS_ALLOCATION crtc_src_param;
1325209ff23fSmrg    SELECT_CRTC_SOURCE_PARAMETERS_V2 crtc_src_param2;
1326209ff23fSmrg    int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source);
1327209ff23fSmrg    int major, minor;
1328209ff23fSmrg
1329b7e1c893Smrg    if (radeon_encoder == NULL)
1330b7e1c893Smrg	return;
1331b7e1c893Smrg
1332b7e1c893Smrg    memset(&crtc_src_param, 0, sizeof(crtc_src_param));
1333b7e1c893Smrg    memset(&crtc_src_param2, 0, sizeof(crtc_src_param2));
1334209ff23fSmrg    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
1335209ff23fSmrg
1336209ff23fSmrg    /*ErrorF("select crtc source table is %d %d\n", major, minor);*/
1337209ff23fSmrg
1338209ff23fSmrg    switch(major) {
1339b7e1c893Smrg    case 1:
1340209ff23fSmrg	switch(minor) {
1341209ff23fSmrg	case 0:
1342209ff23fSmrg	case 1:
1343209ff23fSmrg	default:
1344b7e1c893Smrg	    if (IS_AVIVO_VARIANT)
1345b7e1c893Smrg		crtc_src_param.ucCRTC = radeon_crtc->crtc_id;
1346b7e1c893Smrg	    else {
1347b7e1c893Smrg		if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1)
1348b7e1c893Smrg		    crtc_src_param.ucCRTC = radeon_crtc->crtc_id;
1349b7e1c893Smrg		else
1350b7e1c893Smrg		    crtc_src_param.ucCRTC = radeon_crtc->crtc_id << 2;
1351b7e1c893Smrg	    }
1352b7e1c893Smrg	    switch (radeon_encoder->encoder_id) {
1353b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1354b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
1355b7e1c893Smrg		crtc_src_param.ucDevice = ATOM_DEVICE_DFP1_INDEX;
1356b7e1c893Smrg		break;
1357b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
1358b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1359b7e1c893Smrg		if (radeon_output->active_device & ATOM_DEVICE_LCD1_SUPPORT)
1360209ff23fSmrg		    crtc_src_param.ucDevice = ATOM_DEVICE_LCD1_INDEX;
1361b7e1c893Smrg		else
1362b7e1c893Smrg		    crtc_src_param.ucDevice = ATOM_DEVICE_DFP3_INDEX;
1363b7e1c893Smrg		break;
1364b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1365b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DDI:
1366b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
1367b7e1c893Smrg		crtc_src_param.ucDevice = ATOM_DEVICE_DFP2_INDEX;
1368b7e1c893Smrg		break;
1369b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
1370b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1371b7e1c893Smrg		if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1372b7e1c893Smrg		    crtc_src_param.ucDevice = ATOM_DEVICE_TV1_INDEX;
1373b7e1c893Smrg		else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1374b7e1c893Smrg		    crtc_src_param.ucDevice = ATOM_DEVICE_CV_INDEX;
1375b7e1c893Smrg		else
1376b7e1c893Smrg		    crtc_src_param.ucDevice = ATOM_DEVICE_CRT1_INDEX;
1377b7e1c893Smrg		break;
1378b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1379b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1380b7e1c893Smrg		if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1381209ff23fSmrg		    crtc_src_param.ucDevice = ATOM_DEVICE_TV1_INDEX;
1382b7e1c893Smrg		else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1383209ff23fSmrg		    crtc_src_param.ucDevice = ATOM_DEVICE_CV_INDEX;
1384b7e1c893Smrg		else
1385b7e1c893Smrg		    crtc_src_param.ucDevice = ATOM_DEVICE_CRT2_INDEX;
1386b7e1c893Smrg		break;
1387209ff23fSmrg	    }
1388209ff23fSmrg	    data.exec.pspace = &crtc_src_param;
1389209ff23fSmrg	    /*ErrorF("device sourced: 0x%x\n", crtc_src_param.ucDevice);*/
1390209ff23fSmrg	    break;
1391209ff23fSmrg	case 2:
1392209ff23fSmrg	    crtc_src_param2.ucCRTC = radeon_crtc->crtc_id;
1393b7e1c893Smrg	    crtc_src_param2.ucEncodeMode = atombios_get_encoder_mode(output);
1394b7e1c893Smrg	    switch (radeon_encoder->encoder_id) {
1395b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1396b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1397b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1398b7e1c893Smrg		if (IS_DCE32_VARIANT) {
1399b7e1c893Smrg		    if (radeon_crtc->crtc_id)
1400b7e1c893Smrg			crtc_src_param2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
1401b7e1c893Smrg		    else
1402b7e1c893Smrg			crtc_src_param2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
1403b7e1c893Smrg		} else
1404b7e1c893Smrg		    crtc_src_param2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
1405b7e1c893Smrg		break;
1406b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1407b7e1c893Smrg		crtc_src_param2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
1408b7e1c893Smrg		break;
1409b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1410b7e1c893Smrg		if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1411b7e1c893Smrg		    crtc_src_param2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1412b7e1c893Smrg		else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1413b7e1c893Smrg		    crtc_src_param2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1414b7e1c893Smrg		else
1415b7e1c893Smrg		    crtc_src_param2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID;
1416b7e1c893Smrg		break;
1417b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1418b7e1c893Smrg		if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1419b7e1c893Smrg		    crtc_src_param2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1420b7e1c893Smrg		else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1421b7e1c893Smrg		    crtc_src_param2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1422b7e1c893Smrg		else
1423b7e1c893Smrg		    crtc_src_param2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID;
1424b7e1c893Smrg		break;
1425209ff23fSmrg	    }
1426209ff23fSmrg	    data.exec.pspace = &crtc_src_param2;
1427209ff23fSmrg	    /*ErrorF("device sourced: 0x%x\n", crtc_src_param2.ucEncoderID);*/
1428209ff23fSmrg	    break;
1429209ff23fSmrg	}
1430209ff23fSmrg	break;
1431209ff23fSmrg    default:
1432b7e1c893Smrg	ErrorF("Unknown table version\n");
1433b7e1c893Smrg	exit(-1);
1434209ff23fSmrg    }
1435209ff23fSmrg
1436209ff23fSmrg    data.exec.index = index;
1437209ff23fSmrg    data.exec.dataSpace = (void *)&space;
1438209ff23fSmrg
1439209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
1440209ff23fSmrg	ErrorF("Set CRTC %d Source success\n", radeon_crtc->crtc_id);
1441209ff23fSmrg	return;
1442209ff23fSmrg    }
1443209ff23fSmrg
1444209ff23fSmrg    ErrorF("Set CRTC Source failed\n");
1445209ff23fSmrg    return;
1446209ff23fSmrg}
1447209ff23fSmrg
1448b7e1c893Smrgstatic void
1449b7e1c893Smrgatombios_apply_output_quirks(xf86OutputPtr output, DisplayModePtr mode)
1450b7e1c893Smrg{
1451b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1452b7e1c893Smrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1453b7e1c893Smrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1454b7e1c893Smrg    unsigned char *RADEONMMIO = info->MMIO;
1455b7e1c893Smrg
1456b7e1c893Smrg    /* Funky macbooks */
1457b7e1c893Smrg    if ((info->Chipset == PCI_CHIP_RV530_71C5) &&
1458b7e1c893Smrg	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x106b) &&
1459b7e1c893Smrg	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x0080)) {
1460b7e1c893Smrg	if (radeon_output->MonType == MT_LCD) {
1461b7e1c893Smrg	    if (radeon_output->devices & ATOM_DEVICE_LCD1_SUPPORT) {
1462b7e1c893Smrg		uint32_t lvtma_bit_depth_control = INREG(AVIVO_LVTMA_BIT_DEPTH_CONTROL);
1463b7e1c893Smrg
1464b7e1c893Smrg		lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN;
1465b7e1c893Smrg		lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN;
1466b7e1c893Smrg
1467b7e1c893Smrg		OUTREG(AVIVO_LVTMA_BIT_DEPTH_CONTROL, lvtma_bit_depth_control);
1468b7e1c893Smrg	    }
1469b7e1c893Smrg	}
1470b7e1c893Smrg    }
1471b7e1c893Smrg
1472b7e1c893Smrg    /* set scaler clears this on some chips */
1473b7e1c893Smrg    if (IS_AVIVO_VARIANT && (mode->Flags & V_INTERLACE))
1474b7e1c893Smrg	OUTREG(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, AVIVO_D1MODE_INTERLEAVE_EN);
1475b7e1c893Smrg}
1476b7e1c893Smrg
1477209ff23fSmrgvoid
1478209ff23fSmrgatombios_output_mode_set(xf86OutputPtr output,
1479209ff23fSmrg			 DisplayModePtr mode,
1480209ff23fSmrg			 DisplayModePtr adjusted_mode)
1481209ff23fSmrg{
1482209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1483b7e1c893Smrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1484b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
1485209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1486b7e1c893Smrg    if (radeon_encoder == NULL)
1487b7e1c893Smrg        return;
1488209ff23fSmrg
1489b7e1c893Smrg    radeon_output->pixel_clock = adjusted_mode->Clock;
1490b7e1c893Smrg    radeon_output->dig_block = radeon_crtc->crtc_id;
1491b7e1c893Smrg    atombios_output_overscan_setup(output, mode, adjusted_mode);
1492b7e1c893Smrg    atombios_output_scaler_setup(output);
1493209ff23fSmrg    atombios_set_output_crtc_source(output);
1494209ff23fSmrg
1495b7e1c893Smrg    if (IS_AVIVO_VARIANT) {
1496b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT))
1497b7e1c893Smrg	    atombios_output_yuv_setup(output, TRUE);
1498b7e1c893Smrg	else
1499b7e1c893Smrg	    atombios_output_yuv_setup(output, FALSE);
1500209ff23fSmrg    }
1501209ff23fSmrg
1502b7e1c893Smrg    switch (radeon_encoder->encoder_id) {
1503b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1504b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
1505b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
1506b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1507b7e1c893Smrg	atombios_output_digital_setup(output, PANEL_ENCODER_ACTION_ENABLE);
1508b7e1c893Smrg	break;
1509b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1510b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1511b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1512b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1513b7e1c893Smrg	/* disable encoder and transmitter */
1514b7e1c893Smrg	atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE);
1515b7e1c893Smrg	atombios_output_dig_encoder_setup(output, ATOM_DISABLE);
1516b7e1c893Smrg
1517b7e1c893Smrg	/* setup and enable the encoder and transmitter */
1518b7e1c893Smrg	atombios_output_dig_encoder_setup(output, ATOM_ENABLE);
1519b7e1c893Smrg	atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_SETUP);
1520b7e1c893Smrg	atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE);
1521b7e1c893Smrg	break;
1522b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DDI:
1523b7e1c893Smrg	atombios_output_ddia_setup(output, ATOM_ENABLE);
1524b7e1c893Smrg	break;
1525b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1526b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
1527b7e1c893Smrg	atombios_external_tmds_setup(output, ATOM_ENABLE);
1528b7e1c893Smrg	break;
1529b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
1530b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1531b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1532b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1533b7e1c893Smrg	atombios_output_dac_setup(output, ATOM_ENABLE);
1534b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))
1535b7e1c893Smrg	    atombios_output_tv_setup(output, ATOM_ENABLE);
1536b7e1c893Smrg	break;
1537b7e1c893Smrg    }
1538b7e1c893Smrg    atombios_apply_output_quirks(output, adjusted_mode);
1539209ff23fSmrg}
1540209ff23fSmrg
1541209ff23fSmrgstatic AtomBiosResult
1542209ff23fSmrgatom_bios_dac_load_detect(atomBiosHandlePtr atomBIOS, xf86OutputPtr output)
1543209ff23fSmrg{
1544209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1545209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1546209ff23fSmrg    DAC_LOAD_DETECTION_PS_ALLOCATION dac_data;
1547209ff23fSmrg    AtomBiosArgRec data;
1548209ff23fSmrg    unsigned char *space;
1549b7e1c893Smrg    int major, minor;
1550b7e1c893Smrg    int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection);
1551b7e1c893Smrg
1552b7e1c893Smrg    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
1553209ff23fSmrg
1554209ff23fSmrg    dac_data.sDacload.ucMisc = 0;
1555209ff23fSmrg
1556209ff23fSmrg    if (radeon_output->devices & ATOM_DEVICE_CRT1_SUPPORT) {
1557b7e1c893Smrg	dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT);
1558b7e1c893Smrg	if (info->encoders[ATOM_DEVICE_CRT1_INDEX] &&
1559b7e1c893Smrg	    ((info->encoders[ATOM_DEVICE_CRT1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
1560b7e1c893Smrg	     (info->encoders[ATOM_DEVICE_CRT1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)))
1561209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_A;
1562b7e1c893Smrg	else
1563209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_B;
1564209ff23fSmrg    } else if (radeon_output->devices & ATOM_DEVICE_CRT2_SUPPORT) {
1565b7e1c893Smrg	dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT);
1566b7e1c893Smrg	if (info->encoders[ATOM_DEVICE_CRT2_INDEX] &&
1567b7e1c893Smrg	    ((info->encoders[ATOM_DEVICE_CRT2_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
1568b7e1c893Smrg	     (info->encoders[ATOM_DEVICE_CRT2_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)))
1569209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_A;
1570b7e1c893Smrg	else
1571209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_B;
1572209ff23fSmrg    } else if (radeon_output->devices & ATOM_DEVICE_CV_SUPPORT) {
1573b7e1c893Smrg	dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT);
1574b7e1c893Smrg	if (info->encoders[ATOM_DEVICE_CV_INDEX] &&
1575b7e1c893Smrg	    ((info->encoders[ATOM_DEVICE_CV_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
1576b7e1c893Smrg	     (info->encoders[ATOM_DEVICE_CV_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)))
1577209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_A;
1578b7e1c893Smrg	else
1579209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_B;
1580b7e1c893Smrg	if (minor >= 3)
1581b7e1c893Smrg	    dac_data.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
1582209ff23fSmrg    } else if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) {
1583b7e1c893Smrg	dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT);
1584b7e1c893Smrg	if (info->encoders[ATOM_DEVICE_TV1_INDEX] &&
1585b7e1c893Smrg	    ((info->encoders[ATOM_DEVICE_TV1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
1586b7e1c893Smrg	     (info->encoders[ATOM_DEVICE_TV1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)))
1587209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_A;
1588b7e1c893Smrg	else
1589209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_B;
1590b7e1c893Smrg	if (minor >= 3)
1591b7e1c893Smrg	    dac_data.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
1592b7e1c893Smrg    } else
1593209ff23fSmrg	return ATOM_NOT_IMPLEMENTED;
1594209ff23fSmrg
1595b7e1c893Smrg    data.exec.index = index;
1596209ff23fSmrg    data.exec.dataSpace = (void *)&space;
1597209ff23fSmrg    data.exec.pspace = &dac_data;
1598209ff23fSmrg
1599209ff23fSmrg    if (RHDAtomBiosFunc(atomBIOS->scrnIndex, atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
1600209ff23fSmrg	ErrorF("Dac detection success\n");
1601209ff23fSmrg	return ATOM_SUCCESS ;
1602209ff23fSmrg    }
1603209ff23fSmrg
1604209ff23fSmrg    ErrorF("DAC detection failed\n");
1605209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
1606209ff23fSmrg}
1607209ff23fSmrg
1608209ff23fSmrgRADEONMonitorType
1609b7e1c893Smrgatombios_dac_detect(xf86OutputPtr output)
1610209ff23fSmrg{
1611b7e1c893Smrg    ScrnInfoPtr pScrn = output->scrn;
1612209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
1613209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
1614209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1615209ff23fSmrg    RADEONMonitorType MonType = MT_NONE;
1616209ff23fSmrg    AtomBiosResult ret;
1617c503f109Smrg    RADEONSavePtr save = info->ModeReg;
1618209ff23fSmrg
1619b7e1c893Smrg    if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) {
1620209ff23fSmrg	if (xf86ReturnOptValBool(info->Options, OPTION_FORCE_TVOUT, FALSE)) {
1621b7e1c893Smrg	    if (radeon_output->ConnectorType == CONNECTOR_STV)
1622209ff23fSmrg		return MT_STV;
1623209ff23fSmrg	    else
1624209ff23fSmrg		return MT_CTV;
1625209ff23fSmrg	}
1626209ff23fSmrg    }
1627209ff23fSmrg
1628209ff23fSmrg    ret = atom_bios_dac_load_detect(info->atomBIOS, output);
1629209ff23fSmrg    if (ret == ATOM_SUCCESS) {
1630209ff23fSmrg	if (info->ChipFamily >= CHIP_FAMILY_R600)
1631c503f109Smrg	    save->bios_0_scratch = INREG(R600_BIOS_0_SCRATCH);
1632209ff23fSmrg	else
1633c503f109Smrg	    save->bios_0_scratch = INREG(RADEON_BIOS_0_SCRATCH);
1634c503f109Smrg	/*ErrorF("DAC connect %08X\n", (unsigned int)save->bios_0_scratch);*/
1635209ff23fSmrg
1636209ff23fSmrg	if (radeon_output->devices & ATOM_DEVICE_CRT1_SUPPORT) {
1637c503f109Smrg	    if (save->bios_0_scratch & ATOM_S0_CRT1_MASK)
1638209ff23fSmrg		MonType = MT_CRT;
1639209ff23fSmrg	} else if (radeon_output->devices & ATOM_DEVICE_CRT2_SUPPORT) {
1640c503f109Smrg	    if (save->bios_0_scratch & ATOM_S0_CRT2_MASK)
1641209ff23fSmrg		MonType = MT_CRT;
1642209ff23fSmrg	} else if (radeon_output->devices & ATOM_DEVICE_CV_SUPPORT) {
1643c503f109Smrg	    if (save->bios_0_scratch & (ATOM_S0_CV_MASK | ATOM_S0_CV_MASK_A))
1644209ff23fSmrg		MonType = MT_CV;
1645209ff23fSmrg	} else if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) {
1646c503f109Smrg	    if (save->bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A))
1647209ff23fSmrg		MonType = MT_CTV;
1648c503f109Smrg	    else if (save->bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A))
1649209ff23fSmrg		MonType = MT_STV;
1650209ff23fSmrg	}
1651209ff23fSmrg    }
1652209ff23fSmrg
1653209ff23fSmrg    return MonType;
1654209ff23fSmrg}
1655209ff23fSmrg
1656