atombios_output.c revision b7e1c893
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 */
37209ff23fSmrg#define DPMS_SERVER
38209ff23fSmrg#include <X11/extensions/dpms.h>
39209ff23fSmrg#include <unistd.h>
40209ff23fSmrg
41209ff23fSmrg#include "radeon.h"
42209ff23fSmrg#include "radeon_reg.h"
43209ff23fSmrg#include "radeon_macros.h"
44209ff23fSmrg#include "radeon_atombios.h"
45209ff23fSmrg
46b7e1c893Smrg#include "ati_pciids_gen.h"
47b7e1c893Smrg
48b7e1c893Smrgconst char *device_name[12] = {
49b7e1c893Smrg    "CRT1",
50b7e1c893Smrg    "LCD1",
51b7e1c893Smrg    "TV1",
52b7e1c893Smrg    "DFP1",
53b7e1c893Smrg    "CRT2",
54b7e1c893Smrg    "LCD2",
55b7e1c893Smrg    "TV2",
56b7e1c893Smrg    "DFP2",
57b7e1c893Smrg    "CV",
58b7e1c893Smrg    "DFP3",
59b7e1c893Smrg    "DFP4",
60b7e1c893Smrg    "DFP5",
61b7e1c893Smrg};
62b7e1c893Smrg
63209ff23fSmrgstatic int
64b7e1c893Smrgatombios_output_dac_setup(xf86OutputPtr output, int action)
65209ff23fSmrg{
66209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
67209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
68b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
69b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
70209ff23fSmrg    DAC_ENCODER_CONTROL_PS_ALLOCATION disp_data;
71209ff23fSmrg    AtomBiosArgRec data;
72209ff23fSmrg    unsigned char *space;
73b7e1c893Smrg    int index = 0, num = 0;
74b7e1c893Smrg    int clock = radeon_output->pixel_clock;
75b7e1c893Smrg
76b7e1c893Smrg    if (radeon_encoder == NULL)
77b7e1c893Smrg	return ATOM_NOT_IMPLEMENTED;
78b7e1c893Smrg
79b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
80b7e1c893Smrg
81b7e1c893Smrg    switch (radeon_encoder->encoder_id) {
82b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
83b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
84b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl);
85b7e1c893Smrg	num = 1;
86b7e1c893Smrg	break;
87b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
88b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
89b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl);
90b7e1c893Smrg	num = 2;
91b7e1c893Smrg	break;
92b7e1c893Smrg    }
93209ff23fSmrg
94b7e1c893Smrg    disp_data.ucAction =action;
95209ff23fSmrg
96b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_CRT_SUPPORT))
97209ff23fSmrg	disp_data.ucDacStandard = ATOM_DAC1_PS2;
98b7e1c893Smrg    else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
99209ff23fSmrg	disp_data.ucDacStandard = ATOM_DAC1_CV;
100b7e1c893Smrg    else {
101b7e1c893Smrg	switch (tvout->tvStd) {
102209ff23fSmrg	case TV_STD_PAL:
103209ff23fSmrg	case TV_STD_PAL_M:
104209ff23fSmrg	case TV_STD_SCART_PAL:
105209ff23fSmrg	case TV_STD_SECAM:
106209ff23fSmrg	case TV_STD_PAL_CN:
107209ff23fSmrg	    disp_data.ucDacStandard = ATOM_DAC1_PAL;
108209ff23fSmrg	    break;
109209ff23fSmrg	case TV_STD_NTSC:
110209ff23fSmrg	case TV_STD_NTSC_J:
111209ff23fSmrg	case TV_STD_PAL_60:
112209ff23fSmrg	default:
113b7e1c893Smrg	    disp_data.ucDacStandard = ATOM_DAC1_NTSC;
114209ff23fSmrg	    break;
115209ff23fSmrg	}
116209ff23fSmrg    }
117b7e1c893Smrg    disp_data.usPixelClock = cpu_to_le16(clock / 10);
118209ff23fSmrg
119b7e1c893Smrg    data.exec.index = index;
120209ff23fSmrg    data.exec.dataSpace = (void *)&space;
121209ff23fSmrg    data.exec.pspace = &disp_data;
122209ff23fSmrg
123209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
124b7e1c893Smrg	ErrorF("Output DAC%d setup success\n", num);
125209ff23fSmrg	return ATOM_SUCCESS;
126209ff23fSmrg    }
127209ff23fSmrg
128b7e1c893Smrg    ErrorF("Output DAC%d setup failed\n", num);
129209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
130209ff23fSmrg
131209ff23fSmrg}
132209ff23fSmrg
133209ff23fSmrgstatic int
134b7e1c893Smrgatombios_output_tv_setup(xf86OutputPtr output, int action)
135209ff23fSmrg{
136209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
137b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
138209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
139209ff23fSmrg    TV_ENCODER_CONTROL_PS_ALLOCATION disp_data;
140209ff23fSmrg    AtomBiosArgRec data;
141209ff23fSmrg    unsigned char *space;
142b7e1c893Smrg    int clock = radeon_output->pixel_clock;
143b7e1c893Smrg
144b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
145209ff23fSmrg
146b7e1c893Smrg    disp_data.sTVEncoder.ucAction = action;
147209ff23fSmrg
148b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
149209ff23fSmrg	disp_data.sTVEncoder.ucTvStandard = ATOM_TV_CV;
150209ff23fSmrg    else {
151b7e1c893Smrg	switch (tvout->tvStd) {
152209ff23fSmrg	case TV_STD_NTSC:
153209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSC;
154209ff23fSmrg	    break;
155209ff23fSmrg	case TV_STD_PAL:
156209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL;
157209ff23fSmrg	    break;
158209ff23fSmrg	case TV_STD_PAL_M:
159209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PALM;
160209ff23fSmrg	    break;
161209ff23fSmrg	case TV_STD_PAL_60:
162209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL60;
163209ff23fSmrg	    break;
164209ff23fSmrg	case TV_STD_NTSC_J:
165209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSCJ;
166209ff23fSmrg	    break;
167209ff23fSmrg	case TV_STD_SCART_PAL:
168209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL; /* ??? */
169209ff23fSmrg	    break;
170209ff23fSmrg	case TV_STD_SECAM:
171209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_SECAM;
172209ff23fSmrg	    break;
173209ff23fSmrg	case TV_STD_PAL_CN:
174209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PALCN;
175209ff23fSmrg	    break;
176209ff23fSmrg	default:
177209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSC;
178209ff23fSmrg	    break;
179209ff23fSmrg	}
180209ff23fSmrg    }
181209ff23fSmrg
182b7e1c893Smrg    disp_data.sTVEncoder.usPixelClock = cpu_to_le16(clock / 10);
183209ff23fSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl);
184209ff23fSmrg    data.exec.dataSpace = (void *)&space;
185209ff23fSmrg    data.exec.pspace = &disp_data;
186209ff23fSmrg
187209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
188b7e1c893Smrg	ErrorF("Output TV setup success\n");
189209ff23fSmrg	return ATOM_SUCCESS;
190209ff23fSmrg    }
191209ff23fSmrg
192b7e1c893Smrg    ErrorF("Output TV setup failed\n");
193209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
194209ff23fSmrg
195209ff23fSmrg}
196209ff23fSmrg
197209ff23fSmrgint
198b7e1c893Smrgatombios_external_tmds_setup(xf86OutputPtr output, int action)
199209ff23fSmrg{
200b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
201b7e1c893Smrg    ScrnInfoPtr pScrn = output->scrn;
202b7e1c893Smrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
203209ff23fSmrg    ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION disp_data;
204209ff23fSmrg    AtomBiosArgRec data;
205209ff23fSmrg    unsigned char *space;
206b7e1c893Smrg    int clock = radeon_output->pixel_clock;
207209ff23fSmrg
208b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
209209ff23fSmrg
210b7e1c893Smrg    disp_data.sXTmdsEncoder.ucEnable = action;
211b7e1c893Smrg
212b7e1c893Smrg    if (clock > 165000)
213b7e1c893Smrg	disp_data.sXTmdsEncoder.ucMisc = PANEL_ENCODER_MISC_DUAL;
214209ff23fSmrg
215b7e1c893Smrg    if (pScrn->rgbBits == 8)
216209ff23fSmrg	disp_data.sXTmdsEncoder.ucMisc |= (1 << 1);
217209ff23fSmrg
218209ff23fSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
219209ff23fSmrg    data.exec.dataSpace = (void *)&space;
220209ff23fSmrg    data.exec.pspace = &disp_data;
221209ff23fSmrg
222209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
223209ff23fSmrg	ErrorF("External TMDS setup success\n");
224209ff23fSmrg	return ATOM_SUCCESS;
225209ff23fSmrg    }
226209ff23fSmrg
227209ff23fSmrg    ErrorF("External TMDS setup failed\n");
228209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
229209ff23fSmrg}
230209ff23fSmrg
231209ff23fSmrgstatic int
232b7e1c893Smrgatombios_output_ddia_setup(xf86OutputPtr output, int action)
233209ff23fSmrg{
234b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
235209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
236209ff23fSmrg    DVO_ENCODER_CONTROL_PS_ALLOCATION disp_data;
237209ff23fSmrg    AtomBiosArgRec data;
238209ff23fSmrg    unsigned char *space;
239b7e1c893Smrg    int clock = radeon_output->pixel_clock;
240b7e1c893Smrg
241b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
242209ff23fSmrg
243b7e1c893Smrg    disp_data.sDVOEncoder.ucAction = action;
244b7e1c893Smrg    disp_data.sDVOEncoder.usPixelClock = cpu_to_le16(clock / 10);
245209ff23fSmrg
246b7e1c893Smrg    if (clock > 165000)
247209ff23fSmrg	disp_data.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = PANEL_ENCODER_MISC_DUAL;
248209ff23fSmrg
249209ff23fSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
250209ff23fSmrg    data.exec.dataSpace = (void *)&space;
251209ff23fSmrg    data.exec.pspace = &disp_data;
252209ff23fSmrg
253209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
254209ff23fSmrg	ErrorF("DDIA setup success\n");
255209ff23fSmrg	return ATOM_SUCCESS;
256209ff23fSmrg    }
257209ff23fSmrg
258209ff23fSmrg    ErrorF("DDIA setup failed\n");
259209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
260209ff23fSmrg}
261209ff23fSmrg
262209ff23fSmrgstatic int
263b7e1c893Smrgatombios_output_digital_setup(xf86OutputPtr output, int action)
264209ff23fSmrg{
265b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
266b7e1c893Smrg    ScrnInfoPtr pScrn = output->scrn;
267b7e1c893Smrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
268b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
269b7e1c893Smrg    LVDS_ENCODER_CONTROL_PS_ALLOCATION disp_data;
270b7e1c893Smrg    LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 disp_data2;
271209ff23fSmrg    AtomBiosArgRec data;
272209ff23fSmrg    unsigned char *space;
273b7e1c893Smrg    int index = 0;
274b7e1c893Smrg    int major, minor;
275b7e1c893Smrg    int lvds_misc = 0;
276b7e1c893Smrg    int clock = radeon_output->pixel_clock;
277209ff23fSmrg
278b7e1c893Smrg    if (radeon_encoder == NULL)
279b7e1c893Smrg	return ATOM_NOT_IMPLEMENTED;
280b7e1c893Smrg
281b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
282b7e1c893Smrg	radeon_lvds_ptr lvds = (radeon_lvds_ptr)radeon_encoder->dev_priv;
283b7e1c893Smrg	if (lvds == NULL)
284b7e1c893Smrg	    return ATOM_NOT_IMPLEMENTED;
285b7e1c893Smrg	lvds_misc = lvds->lvds_misc;
286b7e1c893Smrg    }
287b7e1c893Smrg
288b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
289b7e1c893Smrg    memset(&disp_data2,0, sizeof(disp_data2));
290b7e1c893Smrg
291b7e1c893Smrg    switch (radeon_encoder->encoder_id) {
292b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
293b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl);
294b7e1c893Smrg	break;
295b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
296b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
297b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl);
298b7e1c893Smrg	break;
299b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
300b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
301b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT))
302b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl);
303b7e1c893Smrg	else
304b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl);
305b7e1c893Smrg	break;
306b7e1c893Smrg    }
307b7e1c893Smrg
308b7e1c893Smrg    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
309b7e1c893Smrg
310b7e1c893Smrg    /*ErrorF("table is %d %d\n", major, minor);*/
311b7e1c893Smrg    switch (major) {
312b7e1c893Smrg    case 0:
313b7e1c893Smrg    case 1:
314b7e1c893Smrg    case 2:
315b7e1c893Smrg	switch (minor) {
316b7e1c893Smrg	case 1:
317b7e1c893Smrg	    disp_data.ucMisc = 0;
318b7e1c893Smrg	    disp_data.ucAction = action;
319b7e1c893Smrg	    if ((radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_A) ||
320b7e1c893Smrg		(radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_B))
321b7e1c893Smrg		disp_data.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
322b7e1c893Smrg	    disp_data.usPixelClock = cpu_to_le16(clock / 10);
323b7e1c893Smrg	    if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
324b7e1c893Smrg		if (lvds_misc & (1 << 0))
325b7e1c893Smrg		    disp_data.ucMisc |= PANEL_ENCODER_MISC_DUAL;
326b7e1c893Smrg		if (lvds_misc & (1 << 1))
327b7e1c893Smrg		    disp_data.ucMisc |= (1 << 1);
328b7e1c893Smrg	    } else {
329b7e1c893Smrg		if (radeon_output->linkb)
330b7e1c893Smrg		    disp_data.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
331b7e1c893Smrg		if (clock > 165000)
332b7e1c893Smrg		    disp_data.ucMisc |= PANEL_ENCODER_MISC_DUAL;
333b7e1c893Smrg		if (pScrn->rgbBits == 8)
334b7e1c893Smrg		    disp_data.ucMisc |= (1 << 1);
335b7e1c893Smrg	    }
336b7e1c893Smrg	    data.exec.pspace = &disp_data;
337b7e1c893Smrg	    break;
338b7e1c893Smrg	case 2:
339b7e1c893Smrg	case 3:
340b7e1c893Smrg	    disp_data2.ucMisc = 0;
341b7e1c893Smrg	    disp_data2.ucAction = action;
342b7e1c893Smrg	    if (minor == 3) {
343b7e1c893Smrg		if (radeon_output->coherent_mode) {
344b7e1c893Smrg		    disp_data2.ucMisc |= PANEL_ENCODER_MISC_COHERENT;
345b7e1c893Smrg		    xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "Coherent Mode enabled\n");
346b7e1c893Smrg		}
347b7e1c893Smrg	    }
348b7e1c893Smrg	    if ((radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_A) ||
349b7e1c893Smrg		(radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_B))
350b7e1c893Smrg		disp_data2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
351b7e1c893Smrg	    disp_data2.usPixelClock = cpu_to_le16(clock / 10);
352b7e1c893Smrg	    disp_data2.ucTruncate = 0;
353b7e1c893Smrg	    disp_data2.ucSpatial = 0;
354b7e1c893Smrg	    disp_data2.ucTemporal = 0;
355b7e1c893Smrg	    disp_data2.ucFRC = 0;
356b7e1c893Smrg	    if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
357b7e1c893Smrg		if (lvds_misc & (1 << 0))
358b7e1c893Smrg		    disp_data2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
359b7e1c893Smrg		if (lvds_misc & (1 << 5)) {
360b7e1c893Smrg		    disp_data2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN;
361b7e1c893Smrg		    if (lvds_misc & (1 << 1))
362b7e1c893Smrg			disp_data2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH;
363b7e1c893Smrg		}
364b7e1c893Smrg		if (lvds_misc & (1 << 6)) {
365b7e1c893Smrg		    disp_data2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN;
366b7e1c893Smrg		    if (lvds_misc & (1 << 1))
367b7e1c893Smrg			disp_data2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH;
368b7e1c893Smrg		    if (((lvds_misc >> 2) & 0x3) == 2)
369b7e1c893Smrg			disp_data2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4;
370b7e1c893Smrg		}
371b7e1c893Smrg	    } else {
372b7e1c893Smrg		if (radeon_output->linkb)
373b7e1c893Smrg		    disp_data2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
374b7e1c893Smrg		if (clock > 165000)
375b7e1c893Smrg		    disp_data2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
376b7e1c893Smrg	    }
377b7e1c893Smrg	    data.exec.pspace = &disp_data2;
378b7e1c893Smrg	    break;
379b7e1c893Smrg	default:
380b7e1c893Smrg	    ErrorF("Unknown table version\n");
381b7e1c893Smrg	    exit(-1);
382b7e1c893Smrg	}
383b7e1c893Smrg	break;
384b7e1c893Smrg    default:
385b7e1c893Smrg	ErrorF("Unknown table version\n");
386b7e1c893Smrg	exit(-1);
387b7e1c893Smrg    }
388b7e1c893Smrg
389b7e1c893Smrg    data.exec.index = index;
390209ff23fSmrg    data.exec.dataSpace = (void *)&space;
391209ff23fSmrg
392209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
393b7e1c893Smrg	ErrorF("Output digital setup success\n");
394209ff23fSmrg	return ATOM_SUCCESS;
395209ff23fSmrg    }
396209ff23fSmrg
397b7e1c893Smrg    ErrorF("Output digital setup failed\n");
398209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
399209ff23fSmrg}
400209ff23fSmrg
401209ff23fSmrgstatic int
402b7e1c893Smrgatombios_maybe_hdmi_mode(xf86OutputPtr output)
403209ff23fSmrg{
404b7e1c893Smrg#ifndef EDID_COMPLETE_RAWDATA
405b7e1c893Smrg    /* there's no getting this right unless we have complete EDID */
406b7e1c893Smrg    return ATOM_ENCODER_MODE_HDMI;
407b7e1c893Smrg#else
408b7e1c893Smrg    if (output && xf86MonitorIsHDMI(output->MonInfo))
409b7e1c893Smrg	return ATOM_ENCODER_MODE_HDMI;
410b7e1c893Smrg
411b7e1c893Smrg    return ATOM_ENCODER_MODE_DVI;
412b7e1c893Smrg#endif
413b7e1c893Smrg}
414209ff23fSmrg
415b7e1c893Smrgint
416b7e1c893Smrgatombios_get_encoder_mode(xf86OutputPtr output)
417b7e1c893Smrg{
418b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
419209ff23fSmrg
420b7e1c893Smrg    /* DVI should really be atombios_maybe_hdmi_mode() as well */
421b7e1c893Smrg    switch (radeon_output->ConnectorType) {
422b7e1c893Smrg    case CONNECTOR_DVI_I:
423b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT))
424b7e1c893Smrg	    return ATOM_ENCODER_MODE_DVI;
425b7e1c893Smrg	else
426b7e1c893Smrg	    return ATOM_ENCODER_MODE_CRT;
427b7e1c893Smrg	break;
428b7e1c893Smrg    case CONNECTOR_DVI_D:
429b7e1c893Smrg    default:
430b7e1c893Smrg	return ATOM_ENCODER_MODE_DVI;
431b7e1c893Smrg	break;
432b7e1c893Smrg    case CONNECTOR_HDMI_TYPE_A:
433b7e1c893Smrg    case CONNECTOR_HDMI_TYPE_B:
434b7e1c893Smrg	return atombios_maybe_hdmi_mode(output);
435b7e1c893Smrg	break;
436b7e1c893Smrg    case CONNECTOR_LVDS:
437b7e1c893Smrg	return ATOM_ENCODER_MODE_LVDS;
438b7e1c893Smrg	break;
439b7e1c893Smrg    case CONNECTOR_DISPLAY_PORT:
440b7e1c893Smrg	if (radeon_output->MonType == MT_DP)
441b7e1c893Smrg	    return ATOM_ENCODER_MODE_DP;
442b7e1c893Smrg	else
443b7e1c893Smrg	    return atombios_maybe_hdmi_mode(output);
444b7e1c893Smrg	break;
445b7e1c893Smrg    case CONNECTOR_DVI_A:
446b7e1c893Smrg    case CONNECTOR_VGA:
447b7e1c893Smrg    case CONNECTOR_STV:
448b7e1c893Smrg    case CONNECTOR_CTV:
449b7e1c893Smrg    case CONNECTOR_DIN:
450b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
451b7e1c893Smrg	    return ATOM_ENCODER_MODE_TV;
452b7e1c893Smrg	else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
453b7e1c893Smrg	    return ATOM_ENCODER_MODE_CV;
454b7e1c893Smrg	else
455b7e1c893Smrg	    return ATOM_ENCODER_MODE_CRT;
456b7e1c893Smrg	break;
457209ff23fSmrg    }
458209ff23fSmrg
459209ff23fSmrg}
460209ff23fSmrg
461b7e1c893Smrgstatic const int dp_clocks[] = {
462b7e1c893Smrg    16200,
463b7e1c893Smrg    27000,
464b7e1c893Smrg    32400,
465b7e1c893Smrg    54000,
466b7e1c893Smrg    0,
467b7e1c893Smrg    0,
468b7e1c893Smrg    64800,
469b7e1c893Smrg    108000,
470b7e1c893Smrg};
471b7e1c893Smrgstatic const int num_dp_clocks = sizeof(dp_clocks) / sizeof(int);
472b7e1c893Smrg
473209ff23fSmrgstatic int
474b7e1c893Smrgdp_lanes_for_mode_clock(int mode_clock)
475209ff23fSmrg{
476b7e1c893Smrg    int i;
477b7e1c893Smrg
478b7e1c893Smrg    for (i = 0; i < num_dp_clocks; i++)
479b7e1c893Smrg	if (dp_clocks[i] > (mode_clock / 10))
480b7e1c893Smrg	    return (i / 2) + 1;
481209ff23fSmrg
482b7e1c893Smrg    return 0;
483b7e1c893Smrg}
484209ff23fSmrg
485b7e1c893Smrgstatic int
486b7e1c893Smrgdp_link_clock_for_mode_clock(int mode_clock)
487b7e1c893Smrg{
488b7e1c893Smrg    int i;
489209ff23fSmrg
490b7e1c893Smrg    for (i = 0; i < num_dp_clocks; i++)
491b7e1c893Smrg	if (dp_clocks[i] > (mode_clock / 10))
492b7e1c893Smrg	    return (dp_clocks[i % 2]);
493b7e1c893Smrg
494b7e1c893Smrg    return 0;
495209ff23fSmrg}
496209ff23fSmrg
497209ff23fSmrgstatic int
498b7e1c893Smrgatombios_output_dig_encoder_setup(xf86OutputPtr output, int action)
499209ff23fSmrg{
500209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
501209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
502b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
503209ff23fSmrg    DIG_ENCODER_CONTROL_PS_ALLOCATION disp_data;
504209ff23fSmrg    AtomBiosArgRec data;
505209ff23fSmrg    unsigned char *space;
506b7e1c893Smrg    int index = 0, major, minor, num = 0;
507b7e1c893Smrg    int clock = radeon_output->pixel_clock;
508b7e1c893Smrg    int dig_block = radeon_output->dig_block;
509b7e1c893Smrg
510b7e1c893Smrg    if (radeon_encoder == NULL)
511b7e1c893Smrg	return ATOM_NOT_IMPLEMENTED;
512b7e1c893Smrg
513b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
514b7e1c893Smrg
515b7e1c893Smrg    if (IS_DCE32_VARIANT) {
516b7e1c893Smrg	if (dig_block)
517b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
518b7e1c893Smrg	else
519b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
520b7e1c893Smrg	num = dig_block + 1;
521b7e1c893Smrg    } else {
522b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
523b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
524b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
525b7e1c893Smrg	    num = 1;
526b7e1c893Smrg	    break;
527b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
528b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
529b7e1c893Smrg	    num = 2;
530b7e1c893Smrg	    break;
531b7e1c893Smrg	}
532b7e1c893Smrg    }
533209ff23fSmrg
534b7e1c893Smrg    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
535b7e1c893Smrg
536b7e1c893Smrg    disp_data.ucAction = action;
537b7e1c893Smrg    disp_data.usPixelClock = cpu_to_le16(clock / 10);
538b7e1c893Smrg
539b7e1c893Smrg    if (IS_DCE32_VARIANT) {
540b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
541b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
542b7e1c893Smrg	    disp_data.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1;
543b7e1c893Smrg	    break;
544b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
545b7e1c893Smrg	    disp_data.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2;
546b7e1c893Smrg	    break;
547b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
548b7e1c893Smrg	    disp_data.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3;
549b7e1c893Smrg	    break;
550b7e1c893Smrg	}
551b7e1c893Smrg    } else {
552b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
553b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
554b7e1c893Smrg	    disp_data.ucConfig = ATOM_ENCODER_CONFIG_UNIPHY;
555b7e1c893Smrg	    break;
556b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
557b7e1c893Smrg	    disp_data.ucConfig = ATOM_ENCODER_CONFIG_LVTMA;
558b7e1c893Smrg	    break;
559b7e1c893Smrg	}
560209ff23fSmrg    }
561209ff23fSmrg
562b7e1c893Smrg    disp_data.ucEncoderMode = atombios_get_encoder_mode(output);
563b7e1c893Smrg
564b7e1c893Smrg    if (disp_data.ucEncoderMode == ATOM_ENCODER_MODE_DP) {
565b7e1c893Smrg	if (radeon_output->linkb)
566b7e1c893Smrg	    disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
567b7e1c893Smrg	else
568b7e1c893Smrg	    disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
569b7e1c893Smrg
570b7e1c893Smrg	if (dp_link_clock_for_mode_clock(clock) == 27000)
571b7e1c893Smrg	    disp_data.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
572b7e1c893Smrg
573b7e1c893Smrg	disp_data.ucLaneNum = dp_lanes_for_mode_clock(clock);
574b7e1c893Smrg    } else if (clock > 165000) {
575209ff23fSmrg	disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKA_B;
576209ff23fSmrg	disp_data.ucLaneNum = 8;
577209ff23fSmrg    } else {
578b7e1c893Smrg	if (radeon_output->linkb)
579b7e1c893Smrg	    disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
580b7e1c893Smrg	else
581b7e1c893Smrg	    disp_data.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
582b7e1c893Smrg
583209ff23fSmrg	disp_data.ucLaneNum = 4;
584209ff23fSmrg    }
585209ff23fSmrg
586b7e1c893Smrg    data.exec.index = index;
587209ff23fSmrg    data.exec.dataSpace = (void *)&space;
588209ff23fSmrg    data.exec.pspace = &disp_data;
589209ff23fSmrg
590209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
591b7e1c893Smrg	ErrorF("Output DIG%d encoder setup success\n", num);
592209ff23fSmrg	return ATOM_SUCCESS;
593209ff23fSmrg    }
594209ff23fSmrg
595b7e1c893Smrg    ErrorF("Output DIG%d setup failed\n", num);
596209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
597209ff23fSmrg
598209ff23fSmrg}
599209ff23fSmrg
600b7e1c893Smrgunion dig_transmitter_control {
601b7e1c893Smrg    DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1;
602b7e1c893Smrg    DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2;
603b7e1c893Smrg};
604b7e1c893Smrg
605209ff23fSmrgstatic int
606b7e1c893Smrgatombios_output_dig_transmitter_setup(xf86OutputPtr output, int action)
607209ff23fSmrg{
608209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
609209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
610b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
611b7e1c893Smrg    union dig_transmitter_control disp_data;
612209ff23fSmrg    AtomBiosArgRec data;
613209ff23fSmrg    unsigned char *space;
614b7e1c893Smrg    int index = 0, num = 0;
615b7e1c893Smrg    int major, minor;
616b7e1c893Smrg    int clock = radeon_output->pixel_clock;
617b7e1c893Smrg    int dig_block = radeon_output->dig_block;
618b7e1c893Smrg
619b7e1c893Smrg    if (radeon_encoder == NULL)
620b7e1c893Smrg        return ATOM_NOT_IMPLEMENTED;
621b7e1c893Smrg
622b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
623b7e1c893Smrg
624b7e1c893Smrg    if (IS_DCE32_VARIANT)
625b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
626b7e1c893Smrg    else {
627b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
628b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
629b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DIG1TransmitterControl);
630b7e1c893Smrg	    break;
631b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
632b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DIG2TransmitterControl);
633b7e1c893Smrg	    break;
634b7e1c893Smrg	}
635b7e1c893Smrg    }
636209ff23fSmrg
637b7e1c893Smrg    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
638b7e1c893Smrg
639b7e1c893Smrg    disp_data.v1.ucAction = action;
640b7e1c893Smrg
641b7e1c893Smrg    if (IS_DCE32_VARIANT) {
642b7e1c893Smrg	if (radeon_output->MonType == MT_DP) {
643b7e1c893Smrg	    disp_data.v2.usPixelClock =
644b7e1c893Smrg		cpu_to_le16(dp_link_clock_for_mode_clock(clock));
645b7e1c893Smrg	    disp_data.v2.acConfig.fDPConnector = 1;
646b7e1c893Smrg	} else if (clock > 165000) {
647b7e1c893Smrg	    disp_data.v2.usPixelClock = cpu_to_le16((clock * 10 * 2) / 100);
648b7e1c893Smrg	    disp_data.v2.acConfig.fDualLinkConnector = 1;
649209ff23fSmrg	} else {
650b7e1c893Smrg	    disp_data.v2.usPixelClock = cpu_to_le16((clock * 10 * 4) / 100);
651b7e1c893Smrg	}
652b7e1c893Smrg	if (dig_block)
653b7e1c893Smrg	    disp_data.v2.acConfig.ucEncoderSel = 1;
654b7e1c893Smrg
655b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
656b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
657b7e1c893Smrg	    disp_data.v2.acConfig.ucTransmitterSel = 0;
658b7e1c893Smrg	    num = 0;
659b7e1c893Smrg	    break;
660b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
661b7e1c893Smrg	    disp_data.v2.acConfig.ucTransmitterSel = 1;
662b7e1c893Smrg	    num = 1;
663b7e1c893Smrg	    break;
664b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
665b7e1c893Smrg	    disp_data.v2.acConfig.ucTransmitterSel = 2;
666b7e1c893Smrg	    num = 2;
667b7e1c893Smrg	    break;
668b7e1c893Smrg	}
669b7e1c893Smrg
670b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) {
671b7e1c893Smrg	    if (radeon_output->coherent_mode) {
672b7e1c893Smrg		disp_data.v2.acConfig.fCoherentMode = 1;
673b7e1c893Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "UNIPHY%d transmitter: Coherent Mode enabled\n",disp_data.v2.acConfig.ucTransmitterSel);
674b7e1c893Smrg	    } else
675b7e1c893Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "UNIPHY%d transmitter: Coherent Mode disabled\n",disp_data.v2.acConfig.ucTransmitterSel);
676209ff23fSmrg	}
677209ff23fSmrg    } else {
678b7e1c893Smrg	disp_data.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL;
679b7e1c893Smrg
680b7e1c893Smrg	if (radeon_output->MonType == MT_DP)
681b7e1c893Smrg	    disp_data.v1.usPixelClock =
682b7e1c893Smrg		cpu_to_le16(dp_link_clock_for_mode_clock(clock));
683209ff23fSmrg	else
684b7e1c893Smrg	    disp_data.v1.usPixelClock = cpu_to_le16((clock) / 10);
685b7e1c893Smrg
686b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
687b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
688b7e1c893Smrg	    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
689b7e1c893Smrg	    if (info->IsIGP) {
690b7e1c893Smrg		if (clock > 165000) {
691b7e1c893Smrg		    disp_data.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK |
692b7e1c893Smrg					      ATOM_TRANSMITTER_CONFIG_LINKA_B);
693b7e1c893Smrg
694b7e1c893Smrg		    if (radeon_output->igp_lane_info & 0x3)
695b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7;
696b7e1c893Smrg		    else if (radeon_output->igp_lane_info & 0xc)
697b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15;
698b7e1c893Smrg		} else {
699b7e1c893Smrg		    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA;
700b7e1c893Smrg		    if (radeon_output->igp_lane_info & 0x1)
701b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3;
702b7e1c893Smrg		    else if (radeon_output->igp_lane_info & 0x2)
703b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7;
704b7e1c893Smrg		    else if (radeon_output->igp_lane_info & 0x4)
705b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11;
706b7e1c893Smrg		    else if (radeon_output->igp_lane_info & 0x8)
707b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15;
708b7e1c893Smrg		}
709b7e1c893Smrg	    } else {
710b7e1c893Smrg		if (clock > 165000)
711b7e1c893Smrg		    disp_data.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK |
712b7e1c893Smrg					      ATOM_TRANSMITTER_CONFIG_LINKA_B |
713b7e1c893Smrg					      ATOM_TRANSMITTER_CONFIG_LANE_0_7);
714b7e1c893Smrg		else {
715b7e1c893Smrg		    /* XXX */
716b7e1c893Smrg		    if (radeon_output->linkb)
717b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
718b7e1c893Smrg		    else
719b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
720b7e1c893Smrg		}
721b7e1c893Smrg	    }
722b7e1c893Smrg	    break;
723b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
724b7e1c893Smrg	    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
725b7e1c893Smrg	    if (clock > 165000)
726b7e1c893Smrg		disp_data.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK |
727b7e1c893Smrg					  ATOM_TRANSMITTER_CONFIG_LINKA_B |
728b7e1c893Smrg					  ATOM_TRANSMITTER_CONFIG_LANE_0_7);
729b7e1c893Smrg	    else {
730b7e1c893Smrg		/* XXX */
731b7e1c893Smrg		if (radeon_output->linkb)
732b7e1c893Smrg		    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
733b7e1c893Smrg		else
734b7e1c893Smrg		    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
735b7e1c893Smrg	    }
736b7e1c893Smrg	    break;
737b7e1c893Smrg	}
738209ff23fSmrg
739b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) {
740b7e1c893Smrg	    if (radeon_output->coherent_mode &&
741b7e1c893Smrg		radeon_output->MonType != MT_DP) {
742b7e1c893Smrg		disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
743b7e1c893Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
744b7e1c893Smrg			"DIG%d transmitter: Coherent Mode enabled\n", num);
745b7e1c893Smrg	    } else {
746b7e1c893Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
747b7e1c893Smrg			"DIG%d transmitter: Coherent Mode disabled\n", num);
748b7e1c893Smrg	    }
749b7e1c893Smrg	}
750b7e1c893Smrg    }
751209ff23fSmrg
752b7e1c893Smrg    data.exec.index = index;
753209ff23fSmrg    data.exec.dataSpace = (void *)&space;
754209ff23fSmrg    data.exec.pspace = &disp_data;
755209ff23fSmrg
756209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
757b7e1c893Smrg	if (IS_DCE32_VARIANT)
758b7e1c893Smrg	    ErrorF("Output UNIPHY%d transmitter setup success\n", num);
759b7e1c893Smrg	else
760b7e1c893Smrg	   ErrorF("Output DIG%d transmitter setup success\n", num);
761209ff23fSmrg	return ATOM_SUCCESS;
762209ff23fSmrg    }
763209ff23fSmrg
764b7e1c893Smrg    ErrorF("Output DIG%d transmitter setup failed\n", num);
765209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
766209ff23fSmrg
767209ff23fSmrg}
768209ff23fSmrg
769b7e1c893Smrgstatic void atom_rv515_force_tv_scaler(ScrnInfoPtr pScrn)
770b7e1c893Smrg{
771b7e1c893Smrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
772b7e1c893Smrg    unsigned char *RADEONMMIO = info->MMIO;
773b7e1c893Smrg
774b7e1c893Smrg    OUTREG(0x659C,0x0);
775b7e1c893Smrg    OUTREG(0x6594,0x705);
776b7e1c893Smrg    OUTREG(0x65A4,0x10001);
777b7e1c893Smrg    OUTREG(0x65D8,0x0);
778b7e1c893Smrg    OUTREG(0x65B0,0x0);
779b7e1c893Smrg    OUTREG(0x65C0,0x0);
780b7e1c893Smrg    OUTREG(0x65D4,0x0);
781b7e1c893Smrg    OUTREG(0x6578,0x0);
782b7e1c893Smrg    OUTREG(0x657C,0x841880A8);
783b7e1c893Smrg    OUTREG(0x6578,0x1);
784b7e1c893Smrg    OUTREG(0x657C,0x84208680);
785b7e1c893Smrg    OUTREG(0x6578,0x2);
786b7e1c893Smrg    OUTREG(0x657C,0xBFF880B0);
787b7e1c893Smrg    OUTREG(0x6578,0x100);
788b7e1c893Smrg    OUTREG(0x657C,0x83D88088);
789b7e1c893Smrg    OUTREG(0x6578,0x101);
790b7e1c893Smrg    OUTREG(0x657C,0x84608680);
791b7e1c893Smrg    OUTREG(0x6578,0x102);
792b7e1c893Smrg    OUTREG(0x657C,0xBFF080D0);
793b7e1c893Smrg    OUTREG(0x6578,0x200);
794b7e1c893Smrg    OUTREG(0x657C,0x83988068);
795b7e1c893Smrg    OUTREG(0x6578,0x201);
796b7e1c893Smrg    OUTREG(0x657C,0x84A08680);
797b7e1c893Smrg    OUTREG(0x6578,0x202);
798b7e1c893Smrg    OUTREG(0x657C,0xBFF080F8);
799b7e1c893Smrg    OUTREG(0x6578,0x300);
800b7e1c893Smrg    OUTREG(0x657C,0x83588058);
801b7e1c893Smrg    OUTREG(0x6578,0x301);
802b7e1c893Smrg    OUTREG(0x657C,0x84E08660);
803b7e1c893Smrg    OUTREG(0x6578,0x302);
804b7e1c893Smrg    OUTREG(0x657C,0xBFF88120);
805b7e1c893Smrg    OUTREG(0x6578,0x400);
806b7e1c893Smrg    OUTREG(0x657C,0x83188040);
807b7e1c893Smrg    OUTREG(0x6578,0x401);
808b7e1c893Smrg    OUTREG(0x657C,0x85008660);
809b7e1c893Smrg    OUTREG(0x6578,0x402);
810b7e1c893Smrg    OUTREG(0x657C,0xBFF88150);
811b7e1c893Smrg    OUTREG(0x6578,0x500);
812b7e1c893Smrg    OUTREG(0x657C,0x82D88030);
813b7e1c893Smrg    OUTREG(0x6578,0x501);
814b7e1c893Smrg    OUTREG(0x657C,0x85408640);
815b7e1c893Smrg    OUTREG(0x6578,0x502);
816b7e1c893Smrg    OUTREG(0x657C,0xBFF88180);
817b7e1c893Smrg    OUTREG(0x6578,0x600);
818b7e1c893Smrg    OUTREG(0x657C,0x82A08018);
819b7e1c893Smrg    OUTREG(0x6578,0x601);
820b7e1c893Smrg    OUTREG(0x657C,0x85808620);
821b7e1c893Smrg    OUTREG(0x6578,0x602);
822b7e1c893Smrg    OUTREG(0x657C,0xBFF081B8);
823b7e1c893Smrg    OUTREG(0x6578,0x700);
824b7e1c893Smrg    OUTREG(0x657C,0x82608010);
825b7e1c893Smrg    OUTREG(0x6578,0x701);
826b7e1c893Smrg    OUTREG(0x657C,0x85A08600);
827b7e1c893Smrg    OUTREG(0x6578,0x702);
828b7e1c893Smrg    OUTREG(0x657C,0x800081F0);
829b7e1c893Smrg    OUTREG(0x6578,0x800);
830b7e1c893Smrg    OUTREG(0x657C,0x8228BFF8);
831b7e1c893Smrg    OUTREG(0x6578,0x801);
832b7e1c893Smrg    OUTREG(0x657C,0x85E085E0);
833b7e1c893Smrg    OUTREG(0x6578,0x802);
834b7e1c893Smrg    OUTREG(0x657C,0xBFF88228);
835b7e1c893Smrg    OUTREG(0x6578,0x10000);
836b7e1c893Smrg    OUTREG(0x657C,0x82A8BF00);
837b7e1c893Smrg    OUTREG(0x6578,0x10001);
838b7e1c893Smrg    OUTREG(0x657C,0x82A08CC0);
839b7e1c893Smrg    OUTREG(0x6578,0x10002);
840b7e1c893Smrg    OUTREG(0x657C,0x8008BEF8);
841b7e1c893Smrg    OUTREG(0x6578,0x10100);
842b7e1c893Smrg    OUTREG(0x657C,0x81F0BF28);
843b7e1c893Smrg    OUTREG(0x6578,0x10101);
844b7e1c893Smrg    OUTREG(0x657C,0x83608CA0);
845b7e1c893Smrg    OUTREG(0x6578,0x10102);
846b7e1c893Smrg    OUTREG(0x657C,0x8018BED0);
847b7e1c893Smrg    OUTREG(0x6578,0x10200);
848b7e1c893Smrg    OUTREG(0x657C,0x8148BF38);
849b7e1c893Smrg    OUTREG(0x6578,0x10201);
850b7e1c893Smrg    OUTREG(0x657C,0x84408C80);
851b7e1c893Smrg    OUTREG(0x6578,0x10202);
852b7e1c893Smrg    OUTREG(0x657C,0x8008BEB8);
853b7e1c893Smrg    OUTREG(0x6578,0x10300);
854b7e1c893Smrg    OUTREG(0x657C,0x80B0BF78);
855b7e1c893Smrg    OUTREG(0x6578,0x10301);
856b7e1c893Smrg    OUTREG(0x657C,0x85008C20);
857b7e1c893Smrg    OUTREG(0x6578,0x10302);
858b7e1c893Smrg    OUTREG(0x657C,0x8020BEA0);
859b7e1c893Smrg    OUTREG(0x6578,0x10400);
860b7e1c893Smrg    OUTREG(0x657C,0x8028BF90);
861b7e1c893Smrg    OUTREG(0x6578,0x10401);
862b7e1c893Smrg    OUTREG(0x657C,0x85E08BC0);
863b7e1c893Smrg    OUTREG(0x6578,0x10402);
864b7e1c893Smrg    OUTREG(0x657C,0x8018BE90);
865b7e1c893Smrg    OUTREG(0x6578,0x10500);
866b7e1c893Smrg    OUTREG(0x657C,0xBFB8BFB0);
867b7e1c893Smrg    OUTREG(0x6578,0x10501);
868b7e1c893Smrg    OUTREG(0x657C,0x86C08B40);
869b7e1c893Smrg    OUTREG(0x6578,0x10502);
870b7e1c893Smrg    OUTREG(0x657C,0x8010BE90);
871b7e1c893Smrg    OUTREG(0x6578,0x10600);
872b7e1c893Smrg    OUTREG(0x657C,0xBF58BFC8);
873b7e1c893Smrg    OUTREG(0x6578,0x10601);
874b7e1c893Smrg    OUTREG(0x657C,0x87A08AA0);
875b7e1c893Smrg    OUTREG(0x6578,0x10602);
876b7e1c893Smrg    OUTREG(0x657C,0x8010BE98);
877b7e1c893Smrg    OUTREG(0x6578,0x10700);
878b7e1c893Smrg    OUTREG(0x657C,0xBF10BFF0);
879b7e1c893Smrg    OUTREG(0x6578,0x10701);
880b7e1c893Smrg    OUTREG(0x657C,0x886089E0);
881b7e1c893Smrg    OUTREG(0x6578,0x10702);
882b7e1c893Smrg    OUTREG(0x657C,0x8018BEB0);
883b7e1c893Smrg    OUTREG(0x6578,0x10800);
884b7e1c893Smrg    OUTREG(0x657C,0xBED8BFE8);
885b7e1c893Smrg    OUTREG(0x6578,0x10801);
886b7e1c893Smrg    OUTREG(0x657C,0x89408940);
887b7e1c893Smrg    OUTREG(0x6578,0x10802);
888b7e1c893Smrg    OUTREG(0x657C,0xBFE8BED8);
889b7e1c893Smrg    OUTREG(0x6578,0x20000);
890b7e1c893Smrg    OUTREG(0x657C,0x80008000);
891b7e1c893Smrg    OUTREG(0x6578,0x20001);
892b7e1c893Smrg    OUTREG(0x657C,0x90008000);
893b7e1c893Smrg    OUTREG(0x6578,0x20002);
894b7e1c893Smrg    OUTREG(0x657C,0x80008000);
895b7e1c893Smrg    OUTREG(0x6578,0x20003);
896b7e1c893Smrg    OUTREG(0x657C,0x80008000);
897b7e1c893Smrg    OUTREG(0x6578,0x20100);
898b7e1c893Smrg    OUTREG(0x657C,0x80108000);
899b7e1c893Smrg    OUTREG(0x6578,0x20101);
900b7e1c893Smrg    OUTREG(0x657C,0x8FE0BF70);
901b7e1c893Smrg    OUTREG(0x6578,0x20102);
902b7e1c893Smrg    OUTREG(0x657C,0xBFE880C0);
903b7e1c893Smrg    OUTREG(0x6578,0x20103);
904b7e1c893Smrg    OUTREG(0x657C,0x80008000);
905b7e1c893Smrg    OUTREG(0x6578,0x20200);
906b7e1c893Smrg    OUTREG(0x657C,0x8018BFF8);
907b7e1c893Smrg    OUTREG(0x6578,0x20201);
908b7e1c893Smrg    OUTREG(0x657C,0x8F80BF08);
909b7e1c893Smrg    OUTREG(0x6578,0x20202);
910b7e1c893Smrg    OUTREG(0x657C,0xBFD081A0);
911b7e1c893Smrg    OUTREG(0x6578,0x20203);
912b7e1c893Smrg    OUTREG(0x657C,0xBFF88000);
913b7e1c893Smrg    OUTREG(0x6578,0x20300);
914b7e1c893Smrg    OUTREG(0x657C,0x80188000);
915b7e1c893Smrg    OUTREG(0x6578,0x20301);
916b7e1c893Smrg    OUTREG(0x657C,0x8EE0BEC0);
917b7e1c893Smrg    OUTREG(0x6578,0x20302);
918b7e1c893Smrg    OUTREG(0x657C,0xBFB082A0);
919b7e1c893Smrg    OUTREG(0x6578,0x20303);
920b7e1c893Smrg    OUTREG(0x657C,0x80008000);
921b7e1c893Smrg    OUTREG(0x6578,0x20400);
922b7e1c893Smrg    OUTREG(0x657C,0x80188000);
923b7e1c893Smrg    OUTREG(0x6578,0x20401);
924b7e1c893Smrg    OUTREG(0x657C,0x8E00BEA0);
925b7e1c893Smrg    OUTREG(0x6578,0x20402);
926b7e1c893Smrg    OUTREG(0x657C,0xBF8883C0);
927b7e1c893Smrg    OUTREG(0x6578,0x20403);
928b7e1c893Smrg    OUTREG(0x657C,0x80008000);
929b7e1c893Smrg    OUTREG(0x6578,0x20500);
930b7e1c893Smrg    OUTREG(0x657C,0x80188000);
931b7e1c893Smrg    OUTREG(0x6578,0x20501);
932b7e1c893Smrg    OUTREG(0x657C,0x8D00BE90);
933b7e1c893Smrg    OUTREG(0x6578,0x20502);
934b7e1c893Smrg    OUTREG(0x657C,0xBF588500);
935b7e1c893Smrg    OUTREG(0x6578,0x20503);
936b7e1c893Smrg    OUTREG(0x657C,0x80008008);
937b7e1c893Smrg    OUTREG(0x6578,0x20600);
938b7e1c893Smrg    OUTREG(0x657C,0x80188000);
939b7e1c893Smrg    OUTREG(0x6578,0x20601);
940b7e1c893Smrg    OUTREG(0x657C,0x8BC0BE98);
941b7e1c893Smrg    OUTREG(0x6578,0x20602);
942b7e1c893Smrg    OUTREG(0x657C,0xBF308660);
943b7e1c893Smrg    OUTREG(0x6578,0x20603);
944b7e1c893Smrg    OUTREG(0x657C,0x80008008);
945b7e1c893Smrg    OUTREG(0x6578,0x20700);
946b7e1c893Smrg    OUTREG(0x657C,0x80108000);
947b7e1c893Smrg    OUTREG(0x6578,0x20701);
948b7e1c893Smrg    OUTREG(0x657C,0x8A80BEB0);
949b7e1c893Smrg    OUTREG(0x6578,0x20702);
950b7e1c893Smrg    OUTREG(0x657C,0xBF0087C0);
951b7e1c893Smrg    OUTREG(0x6578,0x20703);
952b7e1c893Smrg    OUTREG(0x657C,0x80008008);
953b7e1c893Smrg    OUTREG(0x6578,0x20800);
954b7e1c893Smrg    OUTREG(0x657C,0x80108000);
955b7e1c893Smrg    OUTREG(0x6578,0x20801);
956b7e1c893Smrg    OUTREG(0x657C,0x8920BED0);
957b7e1c893Smrg    OUTREG(0x6578,0x20802);
958b7e1c893Smrg    OUTREG(0x657C,0xBED08920);
959b7e1c893Smrg    OUTREG(0x6578,0x20803);
960b7e1c893Smrg    OUTREG(0x657C,0x80008010);
961b7e1c893Smrg    OUTREG(0x6578,0x30000);
962b7e1c893Smrg    OUTREG(0x657C,0x90008000);
963b7e1c893Smrg    OUTREG(0x6578,0x30001);
964b7e1c893Smrg    OUTREG(0x657C,0x80008000);
965b7e1c893Smrg    OUTREG(0x6578,0x30100);
966b7e1c893Smrg    OUTREG(0x657C,0x8FE0BF90);
967b7e1c893Smrg    OUTREG(0x6578,0x30101);
968b7e1c893Smrg    OUTREG(0x657C,0xBFF880A0);
969b7e1c893Smrg    OUTREG(0x6578,0x30200);
970b7e1c893Smrg    OUTREG(0x657C,0x8F60BF40);
971b7e1c893Smrg    OUTREG(0x6578,0x30201);
972b7e1c893Smrg    OUTREG(0x657C,0xBFE88180);
973b7e1c893Smrg    OUTREG(0x6578,0x30300);
974b7e1c893Smrg    OUTREG(0x657C,0x8EC0BF00);
975b7e1c893Smrg    OUTREG(0x6578,0x30301);
976b7e1c893Smrg    OUTREG(0x657C,0xBFC88280);
977b7e1c893Smrg    OUTREG(0x6578,0x30400);
978b7e1c893Smrg    OUTREG(0x657C,0x8DE0BEE0);
979b7e1c893Smrg    OUTREG(0x6578,0x30401);
980b7e1c893Smrg    OUTREG(0x657C,0xBFA083A0);
981b7e1c893Smrg    OUTREG(0x6578,0x30500);
982b7e1c893Smrg    OUTREG(0x657C,0x8CE0BED0);
983b7e1c893Smrg    OUTREG(0x6578,0x30501);
984b7e1c893Smrg    OUTREG(0x657C,0xBF7884E0);
985b7e1c893Smrg    OUTREG(0x6578,0x30600);
986b7e1c893Smrg    OUTREG(0x657C,0x8BA0BED8);
987b7e1c893Smrg    OUTREG(0x6578,0x30601);
988b7e1c893Smrg    OUTREG(0x657C,0xBF508640);
989b7e1c893Smrg    OUTREG(0x6578,0x30700);
990b7e1c893Smrg    OUTREG(0x657C,0x8A60BEE8);
991b7e1c893Smrg    OUTREG(0x6578,0x30701);
992b7e1c893Smrg    OUTREG(0x657C,0xBF2087A0);
993b7e1c893Smrg    OUTREG(0x6578,0x30800);
994b7e1c893Smrg    OUTREG(0x657C,0x8900BF00);
995b7e1c893Smrg    OUTREG(0x6578,0x30801);
996b7e1c893Smrg    OUTREG(0x657C,0xBF008900);
997b7e1c893Smrg}
998b7e1c893Smrg
999209ff23fSmrgstatic int
1000b7e1c893Smrgatombios_output_yuv_setup(xf86OutputPtr output, Bool enable)
1001209ff23fSmrg{
1002209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1003209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1004b7e1c893Smrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1005b7e1c893Smrg    ENABLE_YUV_PS_ALLOCATION disp_data;
1006209ff23fSmrg    AtomBiosArgRec data;
1007209ff23fSmrg    unsigned char *space;
1008b7e1c893Smrg    unsigned char *RADEONMMIO = info->MMIO;
1009b7e1c893Smrg    uint32_t temp, reg;
1010209ff23fSmrg
1011b7e1c893Smrg    if (info->ChipFamily >= CHIP_FAMILY_R600)
1012b7e1c893Smrg	reg = R600_BIOS_3_SCRATCH;
1013b7e1c893Smrg    else
1014b7e1c893Smrg	reg = RADEON_BIOS_3_SCRATCH;
1015b7e1c893Smrg
1016b7e1c893Smrg    //fix up scratch reg handling
1017b7e1c893Smrg    temp = INREG(reg);
1018b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1019b7e1c893Smrg	OUTREG(reg, (ATOM_S3_TV1_ACTIVE |
1020b7e1c893Smrg		     (radeon_crtc->crtc_id << 18)));
1021b7e1c893Smrg    else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1022b7e1c893Smrg	OUTREG(reg, (ATOM_S3_CV_ACTIVE |
1023b7e1c893Smrg		     (radeon_crtc->crtc_id << 24)));
1024b7e1c893Smrg    else
1025b7e1c893Smrg	OUTREG(reg, 0);
1026209ff23fSmrg
1027b7e1c893Smrg    memset(&disp_data, 0, sizeof(disp_data));
1028209ff23fSmrg
1029b7e1c893Smrg    if (enable)
1030b7e1c893Smrg	disp_data.ucEnable = ATOM_ENABLE;
1031b7e1c893Smrg    disp_data.ucCRTC = radeon_crtc->crtc_id;
1032209ff23fSmrg
1033b7e1c893Smrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableYUV);
1034209ff23fSmrg    data.exec.dataSpace = (void *)&space;
1035209ff23fSmrg    data.exec.pspace = &disp_data;
1036209ff23fSmrg
1037209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
1038b7e1c893Smrg
1039b7e1c893Smrg	OUTREG(reg, temp);
1040b7e1c893Smrg
1041b7e1c893Smrg	ErrorF("crtc %d YUV %s setup success\n", radeon_crtc->crtc_id, enable ? "enable" : "disable");
1042209ff23fSmrg	return ATOM_SUCCESS;
1043209ff23fSmrg    }
1044209ff23fSmrg
1045b7e1c893Smrg    OUTREG(reg, temp);
1046b7e1c893Smrg
1047b7e1c893Smrg    ErrorF("crtc %d YUV %s setup failed\n", radeon_crtc->crtc_id, enable ? "enable" : "disable");
1048209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
1049209ff23fSmrg
1050209ff23fSmrg}
1051209ff23fSmrg
1052209ff23fSmrgstatic int
1053b7e1c893Smrgatombios_output_overscan_setup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
1054209ff23fSmrg{
1055209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1056b7e1c893Smrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1057209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1058b7e1c893Smrg    SET_CRTC_OVERSCAN_PS_ALLOCATION overscan_param;
1059209ff23fSmrg    AtomBiosArgRec data;
1060209ff23fSmrg    unsigned char *space;
1061b7e1c893Smrg    memset(&overscan_param, 0, sizeof(overscan_param));
1062209ff23fSmrg
1063b7e1c893Smrg    overscan_param.usOverscanRight = 0;
1064b7e1c893Smrg    overscan_param.usOverscanLeft = 0;
1065b7e1c893Smrg    overscan_param.usOverscanBottom = 0;
1066b7e1c893Smrg    overscan_param.usOverscanTop = 0;
1067b7e1c893Smrg    overscan_param.ucCRTC = radeon_crtc->crtc_id;
1068b7e1c893Smrg
1069b7e1c893Smrg    if (radeon_output->Flags & RADEON_USE_RMX) {
1070b7e1c893Smrg	if (radeon_output->rmx_type == RMX_FULL) {
1071b7e1c893Smrg	    overscan_param.usOverscanRight = 0;
1072b7e1c893Smrg	    overscan_param.usOverscanLeft = 0;
1073b7e1c893Smrg	    overscan_param.usOverscanBottom = 0;
1074b7e1c893Smrg	    overscan_param.usOverscanTop = 0;
1075b7e1c893Smrg	} else if (radeon_output->rmx_type == RMX_CENTER) {
1076b7e1c893Smrg	    overscan_param.usOverscanTop = (adjusted_mode->CrtcVDisplay - mode->CrtcVDisplay) / 2;
1077b7e1c893Smrg	    overscan_param.usOverscanBottom = (adjusted_mode->CrtcVDisplay - mode->CrtcVDisplay) / 2;
1078b7e1c893Smrg	    overscan_param.usOverscanLeft = (adjusted_mode->CrtcHDisplay - mode->CrtcHDisplay) / 2;
1079b7e1c893Smrg	    overscan_param.usOverscanRight = (adjusted_mode->CrtcHDisplay - mode->CrtcHDisplay) / 2;
1080b7e1c893Smrg	} else if (radeon_output->rmx_type == RMX_ASPECT) {
1081b7e1c893Smrg	    int a1 = mode->CrtcVDisplay * adjusted_mode->CrtcHDisplay;
1082b7e1c893Smrg	    int a2 = adjusted_mode->CrtcVDisplay * mode->CrtcHDisplay;
1083b7e1c893Smrg
1084b7e1c893Smrg	    if (a1 > a2) {
1085b7e1c893Smrg		overscan_param.usOverscanLeft = (adjusted_mode->CrtcHDisplay - (a2 / mode->CrtcVDisplay)) / 2;
1086b7e1c893Smrg		overscan_param.usOverscanRight = (adjusted_mode->CrtcHDisplay - (a2 / mode->CrtcVDisplay)) / 2;
1087b7e1c893Smrg	    } else if (a2 > a1) {
1088b7e1c893Smrg		overscan_param.usOverscanLeft = (adjusted_mode->CrtcVDisplay - (a1 / mode->CrtcHDisplay)) / 2;
1089b7e1c893Smrg		overscan_param.usOverscanRight = (adjusted_mode->CrtcVDisplay - (a1 / mode->CrtcHDisplay)) / 2;
1090b7e1c893Smrg	    }
1091209ff23fSmrg	}
1092209ff23fSmrg    }
1093209ff23fSmrg
1094b7e1c893Smrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan);
1095209ff23fSmrg    data.exec.dataSpace = (void *)&space;
1096b7e1c893Smrg    data.exec.pspace = &overscan_param;
1097209ff23fSmrg
1098209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
1099b7e1c893Smrg	ErrorF("Set CRTC %d Overscan success\n", radeon_crtc->crtc_id);
1100b7e1c893Smrg	return ATOM_SUCCESS ;
1101209ff23fSmrg    }
1102209ff23fSmrg
1103b7e1c893Smrg    ErrorF("Set CRTC %d Overscan failed\n", radeon_crtc->crtc_id);
1104209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
1105209ff23fSmrg}
1106209ff23fSmrg
1107209ff23fSmrgstatic int
1108b7e1c893Smrgatombios_output_scaler_setup(xf86OutputPtr output)
1109209ff23fSmrg{
1110209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1111209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1112b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
1113209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1114209ff23fSmrg    ENABLE_SCALER_PS_ALLOCATION disp_data;
1115209ff23fSmrg    AtomBiosArgRec data;
1116209ff23fSmrg    unsigned char *space;
1117209ff23fSmrg
1118b7e1c893Smrg    if (!IS_AVIVO_VARIANT && radeon_crtc->crtc_id)
1119b7e1c893Smrg	return ATOM_SUCCESS;
1120b7e1c893Smrg
1121b7e1c893Smrg    memset(&disp_data, 0, sizeof(disp_data));
1122b7e1c893Smrg
1123209ff23fSmrg    disp_data.ucScaler = radeon_crtc->crtc_id;
1124209ff23fSmrg
1125b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
1126b7e1c893Smrg	switch (tvout->tvStd) {
1127b7e1c893Smrg	case TV_STD_NTSC:
1128b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_NTSC;
1129b7e1c893Smrg	    break;
1130b7e1c893Smrg	case TV_STD_PAL:
1131b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_PAL;
1132b7e1c893Smrg	    break;
1133b7e1c893Smrg	case TV_STD_PAL_M:
1134b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_PALM;
1135b7e1c893Smrg	    break;
1136b7e1c893Smrg	case TV_STD_PAL_60:
1137b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_PAL60;
1138b7e1c893Smrg	    break;
1139b7e1c893Smrg	case TV_STD_NTSC_J:
1140b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_NTSCJ;
1141b7e1c893Smrg	    break;
1142b7e1c893Smrg	case TV_STD_SCART_PAL:
1143b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_PAL; /* ??? */
1144b7e1c893Smrg	    break;
1145b7e1c893Smrg	case TV_STD_SECAM:
1146b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_SECAM;
1147b7e1c893Smrg	    break;
1148b7e1c893Smrg	case TV_STD_PAL_CN:
1149b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_PALCN;
1150b7e1c893Smrg	    break;
1151b7e1c893Smrg	default:
1152b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_NTSC;
1153b7e1c893Smrg	    break;
1154b7e1c893Smrg	}
1155b7e1c893Smrg	disp_data.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
1156b7e1c893Smrg        ErrorF("Using TV scaler %x %x\n", disp_data.ucTVStandard, disp_data.ucEnable);
1157b7e1c893Smrg    } else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) {
1158b7e1c893Smrg	disp_data.ucTVStandard = ATOM_TV_CV;
1159b7e1c893Smrg	disp_data.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
1160b7e1c893Smrg        ErrorF("Using CV scaler %x %x\n", disp_data.ucTVStandard, disp_data.ucEnable);
1161b7e1c893Smrg    } else if (radeon_output->Flags & RADEON_USE_RMX) {
1162209ff23fSmrg	ErrorF("Using RMX\n");
1163209ff23fSmrg	if (radeon_output->rmx_type == RMX_FULL)
1164209ff23fSmrg	    disp_data.ucEnable = ATOM_SCALER_EXPANSION;
1165209ff23fSmrg	else if (radeon_output->rmx_type == RMX_CENTER)
1166209ff23fSmrg	    disp_data.ucEnable = ATOM_SCALER_CENTER;
1167b7e1c893Smrg	else if (radeon_output->rmx_type == RMX_ASPECT)
1168b7e1c893Smrg	    disp_data.ucEnable = ATOM_SCALER_EXPANSION;
1169209ff23fSmrg    } else {
1170209ff23fSmrg	ErrorF("Not using RMX\n");
1171b7e1c893Smrg	if (IS_AVIVO_VARIANT)
1172b7e1c893Smrg	    disp_data.ucEnable = ATOM_SCALER_DISABLE;
1173b7e1c893Smrg	else
1174b7e1c893Smrg	    disp_data.ucEnable = ATOM_SCALER_CENTER;
1175209ff23fSmrg    }
1176209ff23fSmrg
1177209ff23fSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
1178209ff23fSmrg    data.exec.dataSpace = (void *)&space;
1179209ff23fSmrg    data.exec.pspace = &disp_data;
1180209ff23fSmrg
1181209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
1182b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)
1183b7e1c893Smrg	    && info->ChipFamily >= CHIP_FAMILY_RV515 && info->ChipFamily <= CHIP_FAMILY_RV570) {
1184b7e1c893Smrg	    ErrorF("forcing TV scaler\n");
1185b7e1c893Smrg	    atom_rv515_force_tv_scaler(output->scrn);
1186b7e1c893Smrg	}
1187209ff23fSmrg	ErrorF("scaler %d setup success\n", radeon_crtc->crtc_id);
1188209ff23fSmrg	return ATOM_SUCCESS;
1189209ff23fSmrg    }
1190209ff23fSmrg
1191209ff23fSmrg    ErrorF("scaler %d setup failed\n", radeon_crtc->crtc_id);
1192209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
1193209ff23fSmrg
1194209ff23fSmrg}
1195209ff23fSmrg
1196b7e1c893Smrgvoid
1197b7e1c893Smrgatombios_output_dpms(xf86OutputPtr output, int mode)
1198209ff23fSmrg{
1199b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1200b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
1201209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1202209ff23fSmrg    DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION disp_data;
1203209ff23fSmrg    AtomBiosArgRec data;
1204209ff23fSmrg    unsigned char *space;
1205209ff23fSmrg    int index = 0;
1206b7e1c893Smrg    Bool is_dig = FALSE;
1207209ff23fSmrg
1208b7e1c893Smrg    if (radeon_encoder == NULL)
1209b7e1c893Smrg        return;
1210b7e1c893Smrg
1211b7e1c893Smrg    switch (radeon_encoder->encoder_id) {
1212b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1213b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
1214209ff23fSmrg	index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl);
1215209ff23fSmrg	break;
1216b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1217b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1218b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1219b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1220b7e1c893Smrg	is_dig = TRUE;
1221209ff23fSmrg	break;
1222b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1223b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DDI:
1224b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
1225b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
1226209ff23fSmrg	break;
1227b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
1228209ff23fSmrg	index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
1229209ff23fSmrg	break;
1230b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1231b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT))
1232b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
1233b7e1c893Smrg	else
1234b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl);
1235209ff23fSmrg	break;
1236b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
1237b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1238b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1239b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
1240b7e1c893Smrg	else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1241b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
1242b7e1c893Smrg	else
1243b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl);
1244209ff23fSmrg	break;
1245b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1246b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1247b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1248b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
1249b7e1c893Smrg	else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1250b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
1251b7e1c893Smrg	else
1252b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl);
1253209ff23fSmrg	break;
1254209ff23fSmrg    }
1255209ff23fSmrg
1256209ff23fSmrg    switch (mode) {
1257209ff23fSmrg    case DPMSModeOn:
1258b7e1c893Smrg	radeon_encoder->devices |= radeon_output->active_device;
1259b7e1c893Smrg	if (is_dig)
1260b7e1c893Smrg	    atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT);
1261b7e1c893Smrg	else {
1262b7e1c893Smrg	    disp_data.ucAction = ATOM_ENABLE;
1263b7e1c893Smrg	    data.exec.index = index;
1264b7e1c893Smrg	    data.exec.dataSpace = (void *)&space;
1265b7e1c893Smrg	    data.exec.pspace = &disp_data;
1266b7e1c893Smrg
1267b7e1c893Smrg	    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS)
1268b7e1c893Smrg		ErrorF("Output %s enable success\n",
1269b7e1c893Smrg		       device_name[radeon_get_device_index(radeon_output->active_device)]);
1270b7e1c893Smrg	    else
1271b7e1c893Smrg		ErrorF("Output %s enable failed\n",
1272b7e1c893Smrg		       device_name[radeon_get_device_index(radeon_output->active_device)]);
1273b7e1c893Smrg	}
1274209ff23fSmrg	break;
1275209ff23fSmrg    case DPMSModeStandby:
1276209ff23fSmrg    case DPMSModeSuspend:
1277209ff23fSmrg    case DPMSModeOff:
1278b7e1c893Smrg	radeon_encoder->devices &= ~(radeon_output->active_device);
1279b7e1c893Smrg	if (!radeon_encoder->devices) {
1280b7e1c893Smrg	    if (is_dig)
1281b7e1c893Smrg		atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT);
1282b7e1c893Smrg	    else {
1283b7e1c893Smrg		disp_data.ucAction = ATOM_DISABLE;
1284b7e1c893Smrg		data.exec.index = index;
1285b7e1c893Smrg		data.exec.dataSpace = (void *)&space;
1286b7e1c893Smrg		data.exec.pspace = &disp_data;
1287b7e1c893Smrg
1288b7e1c893Smrg		if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data)
1289b7e1c893Smrg		    == ATOM_SUCCESS)
1290b7e1c893Smrg		    ErrorF("Output %s disable success\n",
1291b7e1c893Smrg			   device_name[radeon_get_device_index(radeon_output->active_device)]);
1292b7e1c893Smrg		else
1293b7e1c893Smrg		    ErrorF("Output %s disable failed\n",
1294b7e1c893Smrg			   device_name[radeon_get_device_index(radeon_output->active_device)]);
1295b7e1c893Smrg	    }
1296209ff23fSmrg	}
1297b7e1c893Smrg	break;
1298209ff23fSmrg    }
1299209ff23fSmrg}
1300209ff23fSmrg
1301209ff23fSmrgstatic void
1302209ff23fSmrgatombios_set_output_crtc_source(xf86OutputPtr output)
1303209ff23fSmrg{
1304209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1305209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1306209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1307b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
1308209ff23fSmrg    AtomBiosArgRec data;
1309209ff23fSmrg    unsigned char *space;
1310209ff23fSmrg    SELECT_CRTC_SOURCE_PS_ALLOCATION crtc_src_param;
1311209ff23fSmrg    SELECT_CRTC_SOURCE_PARAMETERS_V2 crtc_src_param2;
1312209ff23fSmrg    int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source);
1313209ff23fSmrg    int major, minor;
1314209ff23fSmrg
1315b7e1c893Smrg    if (radeon_encoder == NULL)
1316b7e1c893Smrg	return;
1317b7e1c893Smrg
1318b7e1c893Smrg    memset(&crtc_src_param, 0, sizeof(crtc_src_param));
1319b7e1c893Smrg    memset(&crtc_src_param2, 0, sizeof(crtc_src_param2));
1320209ff23fSmrg    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
1321209ff23fSmrg
1322209ff23fSmrg    /*ErrorF("select crtc source table is %d %d\n", major, minor);*/
1323209ff23fSmrg
1324209ff23fSmrg    switch(major) {
1325b7e1c893Smrg    case 1:
1326209ff23fSmrg	switch(minor) {
1327209ff23fSmrg	case 0:
1328209ff23fSmrg	case 1:
1329209ff23fSmrg	default:
1330b7e1c893Smrg	    if (IS_AVIVO_VARIANT)
1331b7e1c893Smrg		crtc_src_param.ucCRTC = radeon_crtc->crtc_id;
1332b7e1c893Smrg	    else {
1333b7e1c893Smrg		if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1)
1334b7e1c893Smrg		    crtc_src_param.ucCRTC = radeon_crtc->crtc_id;
1335b7e1c893Smrg		else
1336b7e1c893Smrg		    crtc_src_param.ucCRTC = radeon_crtc->crtc_id << 2;
1337b7e1c893Smrg	    }
1338b7e1c893Smrg	    switch (radeon_encoder->encoder_id) {
1339b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1340b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
1341b7e1c893Smrg		crtc_src_param.ucDevice = ATOM_DEVICE_DFP1_INDEX;
1342b7e1c893Smrg		break;
1343b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
1344b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1345b7e1c893Smrg		if (radeon_output->active_device & ATOM_DEVICE_LCD1_SUPPORT)
1346209ff23fSmrg		    crtc_src_param.ucDevice = ATOM_DEVICE_LCD1_INDEX;
1347b7e1c893Smrg		else
1348b7e1c893Smrg		    crtc_src_param.ucDevice = ATOM_DEVICE_DFP3_INDEX;
1349b7e1c893Smrg		break;
1350b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1351b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DDI:
1352b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
1353b7e1c893Smrg		crtc_src_param.ucDevice = ATOM_DEVICE_DFP2_INDEX;
1354b7e1c893Smrg		break;
1355b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
1356b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1357b7e1c893Smrg		if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1358b7e1c893Smrg		    crtc_src_param.ucDevice = ATOM_DEVICE_TV1_INDEX;
1359b7e1c893Smrg		else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1360b7e1c893Smrg		    crtc_src_param.ucDevice = ATOM_DEVICE_CV_INDEX;
1361b7e1c893Smrg		else
1362b7e1c893Smrg		    crtc_src_param.ucDevice = ATOM_DEVICE_CRT1_INDEX;
1363b7e1c893Smrg		break;
1364b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1365b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1366b7e1c893Smrg		if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1367209ff23fSmrg		    crtc_src_param.ucDevice = ATOM_DEVICE_TV1_INDEX;
1368b7e1c893Smrg		else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1369209ff23fSmrg		    crtc_src_param.ucDevice = ATOM_DEVICE_CV_INDEX;
1370b7e1c893Smrg		else
1371b7e1c893Smrg		    crtc_src_param.ucDevice = ATOM_DEVICE_CRT2_INDEX;
1372b7e1c893Smrg		break;
1373209ff23fSmrg	    }
1374209ff23fSmrg	    data.exec.pspace = &crtc_src_param;
1375209ff23fSmrg	    /*ErrorF("device sourced: 0x%x\n", crtc_src_param.ucDevice);*/
1376209ff23fSmrg	    break;
1377209ff23fSmrg	case 2:
1378209ff23fSmrg	    crtc_src_param2.ucCRTC = radeon_crtc->crtc_id;
1379b7e1c893Smrg	    crtc_src_param2.ucEncodeMode = atombios_get_encoder_mode(output);
1380b7e1c893Smrg	    switch (radeon_encoder->encoder_id) {
1381b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1382b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1383b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1384b7e1c893Smrg		if (IS_DCE32_VARIANT) {
1385b7e1c893Smrg		    if (radeon_crtc->crtc_id)
1386b7e1c893Smrg			crtc_src_param2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
1387b7e1c893Smrg		    else
1388b7e1c893Smrg			crtc_src_param2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
1389b7e1c893Smrg		} else
1390b7e1c893Smrg		    crtc_src_param2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
1391b7e1c893Smrg		break;
1392b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1393b7e1c893Smrg		crtc_src_param2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
1394b7e1c893Smrg		break;
1395b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1396b7e1c893Smrg		if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1397b7e1c893Smrg		    crtc_src_param2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1398b7e1c893Smrg		else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1399b7e1c893Smrg		    crtc_src_param2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1400b7e1c893Smrg		else
1401b7e1c893Smrg		    crtc_src_param2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID;
1402b7e1c893Smrg		break;
1403b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1404b7e1c893Smrg		if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1405b7e1c893Smrg		    crtc_src_param2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1406b7e1c893Smrg		else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1407b7e1c893Smrg		    crtc_src_param2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1408b7e1c893Smrg		else
1409b7e1c893Smrg		    crtc_src_param2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID;
1410b7e1c893Smrg		break;
1411209ff23fSmrg	    }
1412209ff23fSmrg	    data.exec.pspace = &crtc_src_param2;
1413209ff23fSmrg	    /*ErrorF("device sourced: 0x%x\n", crtc_src_param2.ucEncoderID);*/
1414209ff23fSmrg	    break;
1415209ff23fSmrg	}
1416209ff23fSmrg	break;
1417209ff23fSmrg    default:
1418b7e1c893Smrg	ErrorF("Unknown table version\n");
1419b7e1c893Smrg	exit(-1);
1420209ff23fSmrg    }
1421209ff23fSmrg
1422209ff23fSmrg    data.exec.index = index;
1423209ff23fSmrg    data.exec.dataSpace = (void *)&space;
1424209ff23fSmrg
1425209ff23fSmrg    if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
1426209ff23fSmrg	ErrorF("Set CRTC %d Source success\n", radeon_crtc->crtc_id);
1427209ff23fSmrg	return;
1428209ff23fSmrg    }
1429209ff23fSmrg
1430209ff23fSmrg    ErrorF("Set CRTC Source failed\n");
1431209ff23fSmrg    return;
1432209ff23fSmrg}
1433209ff23fSmrg
1434b7e1c893Smrgstatic void
1435b7e1c893Smrgatombios_apply_output_quirks(xf86OutputPtr output, DisplayModePtr mode)
1436b7e1c893Smrg{
1437b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1438b7e1c893Smrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1439b7e1c893Smrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1440b7e1c893Smrg    unsigned char *RADEONMMIO = info->MMIO;
1441b7e1c893Smrg
1442b7e1c893Smrg    /* Funky macbooks */
1443b7e1c893Smrg    if ((info->Chipset == PCI_CHIP_RV530_71C5) &&
1444b7e1c893Smrg	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x106b) &&
1445b7e1c893Smrg	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x0080)) {
1446b7e1c893Smrg	if (radeon_output->MonType == MT_LCD) {
1447b7e1c893Smrg	    if (radeon_output->devices & ATOM_DEVICE_LCD1_SUPPORT) {
1448b7e1c893Smrg		uint32_t lvtma_bit_depth_control = INREG(AVIVO_LVTMA_BIT_DEPTH_CONTROL);
1449b7e1c893Smrg
1450b7e1c893Smrg		lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN;
1451b7e1c893Smrg		lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN;
1452b7e1c893Smrg
1453b7e1c893Smrg		OUTREG(AVIVO_LVTMA_BIT_DEPTH_CONTROL, lvtma_bit_depth_control);
1454b7e1c893Smrg	    }
1455b7e1c893Smrg	}
1456b7e1c893Smrg    }
1457b7e1c893Smrg
1458b7e1c893Smrg    /* set scaler clears this on some chips */
1459b7e1c893Smrg    if (IS_AVIVO_VARIANT && (mode->Flags & V_INTERLACE))
1460b7e1c893Smrg	OUTREG(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, AVIVO_D1MODE_INTERLEAVE_EN);
1461b7e1c893Smrg}
1462b7e1c893Smrg
1463209ff23fSmrgvoid
1464209ff23fSmrgatombios_output_mode_set(xf86OutputPtr output,
1465209ff23fSmrg			 DisplayModePtr mode,
1466209ff23fSmrg			 DisplayModePtr adjusted_mode)
1467209ff23fSmrg{
1468209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1469b7e1c893Smrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1470b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
1471209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1472b7e1c893Smrg    if (radeon_encoder == NULL)
1473b7e1c893Smrg        return;
1474209ff23fSmrg
1475b7e1c893Smrg    radeon_output->pixel_clock = adjusted_mode->Clock;
1476b7e1c893Smrg    radeon_output->dig_block = radeon_crtc->crtc_id;
1477b7e1c893Smrg    atombios_output_overscan_setup(output, mode, adjusted_mode);
1478b7e1c893Smrg    atombios_output_scaler_setup(output);
1479209ff23fSmrg    atombios_set_output_crtc_source(output);
1480209ff23fSmrg
1481b7e1c893Smrg    if (IS_AVIVO_VARIANT) {
1482b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT))
1483b7e1c893Smrg	    atombios_output_yuv_setup(output, TRUE);
1484b7e1c893Smrg	else
1485b7e1c893Smrg	    atombios_output_yuv_setup(output, FALSE);
1486209ff23fSmrg    }
1487209ff23fSmrg
1488b7e1c893Smrg    switch (radeon_encoder->encoder_id) {
1489b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1490b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
1491b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
1492b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1493b7e1c893Smrg	atombios_output_digital_setup(output, PANEL_ENCODER_ACTION_ENABLE);
1494b7e1c893Smrg	break;
1495b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1496b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1497b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1498b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1499b7e1c893Smrg	/* disable encoder and transmitter */
1500b7e1c893Smrg	atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE);
1501b7e1c893Smrg	atombios_output_dig_encoder_setup(output, ATOM_DISABLE);
1502b7e1c893Smrg
1503b7e1c893Smrg	/* setup and enable the encoder and transmitter */
1504b7e1c893Smrg	atombios_output_dig_encoder_setup(output, ATOM_ENABLE);
1505b7e1c893Smrg	atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_SETUP);
1506b7e1c893Smrg	atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE);
1507b7e1c893Smrg	break;
1508b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DDI:
1509b7e1c893Smrg	atombios_output_ddia_setup(output, ATOM_ENABLE);
1510b7e1c893Smrg	break;
1511b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1512b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
1513b7e1c893Smrg	atombios_external_tmds_setup(output, ATOM_ENABLE);
1514b7e1c893Smrg	break;
1515b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
1516b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1517b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1518b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1519b7e1c893Smrg	atombios_output_dac_setup(output, ATOM_ENABLE);
1520b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))
1521b7e1c893Smrg	    atombios_output_tv_setup(output, ATOM_ENABLE);
1522b7e1c893Smrg	break;
1523b7e1c893Smrg    }
1524b7e1c893Smrg    atombios_apply_output_quirks(output, adjusted_mode);
1525209ff23fSmrg}
1526209ff23fSmrg
1527209ff23fSmrgstatic AtomBiosResult
1528209ff23fSmrgatom_bios_dac_load_detect(atomBiosHandlePtr atomBIOS, xf86OutputPtr output)
1529209ff23fSmrg{
1530209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1531209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1532209ff23fSmrg    DAC_LOAD_DETECTION_PS_ALLOCATION dac_data;
1533209ff23fSmrg    AtomBiosArgRec data;
1534209ff23fSmrg    unsigned char *space;
1535b7e1c893Smrg    int major, minor;
1536b7e1c893Smrg    int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection);
1537b7e1c893Smrg
1538b7e1c893Smrg    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
1539209ff23fSmrg
1540209ff23fSmrg    dac_data.sDacload.ucMisc = 0;
1541209ff23fSmrg
1542209ff23fSmrg    if (radeon_output->devices & ATOM_DEVICE_CRT1_SUPPORT) {
1543b7e1c893Smrg	dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT);
1544b7e1c893Smrg	if (info->encoders[ATOM_DEVICE_CRT1_INDEX] &&
1545b7e1c893Smrg	    ((info->encoders[ATOM_DEVICE_CRT1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
1546b7e1c893Smrg	     (info->encoders[ATOM_DEVICE_CRT1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)))
1547209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_A;
1548b7e1c893Smrg	else
1549209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_B;
1550209ff23fSmrg    } else if (radeon_output->devices & ATOM_DEVICE_CRT2_SUPPORT) {
1551b7e1c893Smrg	dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT);
1552b7e1c893Smrg	if (info->encoders[ATOM_DEVICE_CRT2_INDEX] &&
1553b7e1c893Smrg	    ((info->encoders[ATOM_DEVICE_CRT2_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
1554b7e1c893Smrg	     (info->encoders[ATOM_DEVICE_CRT2_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)))
1555209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_A;
1556b7e1c893Smrg	else
1557209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_B;
1558209ff23fSmrg    } else if (radeon_output->devices & ATOM_DEVICE_CV_SUPPORT) {
1559b7e1c893Smrg	dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT);
1560b7e1c893Smrg	if (info->encoders[ATOM_DEVICE_CV_INDEX] &&
1561b7e1c893Smrg	    ((info->encoders[ATOM_DEVICE_CV_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
1562b7e1c893Smrg	     (info->encoders[ATOM_DEVICE_CV_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)))
1563209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_A;
1564b7e1c893Smrg	else
1565209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_B;
1566b7e1c893Smrg	if (minor >= 3)
1567b7e1c893Smrg	    dac_data.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
1568209ff23fSmrg    } else if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) {
1569b7e1c893Smrg	dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT);
1570b7e1c893Smrg	if (info->encoders[ATOM_DEVICE_TV1_INDEX] &&
1571b7e1c893Smrg	    ((info->encoders[ATOM_DEVICE_TV1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
1572b7e1c893Smrg	     (info->encoders[ATOM_DEVICE_TV1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)))
1573209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_A;
1574b7e1c893Smrg	else
1575209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_B;
1576b7e1c893Smrg	if (minor >= 3)
1577b7e1c893Smrg	    dac_data.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
1578b7e1c893Smrg    } else
1579209ff23fSmrg	return ATOM_NOT_IMPLEMENTED;
1580209ff23fSmrg
1581b7e1c893Smrg    data.exec.index = index;
1582209ff23fSmrg    data.exec.dataSpace = (void *)&space;
1583209ff23fSmrg    data.exec.pspace = &dac_data;
1584209ff23fSmrg
1585209ff23fSmrg    if (RHDAtomBiosFunc(atomBIOS->scrnIndex, atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
1586209ff23fSmrg	ErrorF("Dac detection success\n");
1587209ff23fSmrg	return ATOM_SUCCESS ;
1588209ff23fSmrg    }
1589209ff23fSmrg
1590209ff23fSmrg    ErrorF("DAC detection failed\n");
1591209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
1592209ff23fSmrg}
1593209ff23fSmrg
1594209ff23fSmrgRADEONMonitorType
1595b7e1c893Smrgatombios_dac_detect(xf86OutputPtr output)
1596209ff23fSmrg{
1597b7e1c893Smrg    ScrnInfoPtr pScrn = output->scrn;
1598209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
1599209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
1600209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1601209ff23fSmrg    RADEONMonitorType MonType = MT_NONE;
1602209ff23fSmrg    AtomBiosResult ret;
1603209ff23fSmrg    uint32_t bios_0_scratch;
1604209ff23fSmrg
1605b7e1c893Smrg    if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) {
1606209ff23fSmrg	if (xf86ReturnOptValBool(info->Options, OPTION_FORCE_TVOUT, FALSE)) {
1607b7e1c893Smrg	    if (radeon_output->ConnectorType == CONNECTOR_STV)
1608209ff23fSmrg		return MT_STV;
1609209ff23fSmrg	    else
1610209ff23fSmrg		return MT_CTV;
1611209ff23fSmrg	}
1612209ff23fSmrg    }
1613209ff23fSmrg
1614209ff23fSmrg    ret = atom_bios_dac_load_detect(info->atomBIOS, output);
1615209ff23fSmrg    if (ret == ATOM_SUCCESS) {
1616209ff23fSmrg	if (info->ChipFamily >= CHIP_FAMILY_R600)
1617209ff23fSmrg	    bios_0_scratch = INREG(R600_BIOS_0_SCRATCH);
1618209ff23fSmrg	else
1619209ff23fSmrg	    bios_0_scratch = INREG(RADEON_BIOS_0_SCRATCH);
1620209ff23fSmrg	/*ErrorF("DAC connect %08X\n", (unsigned int)bios_0_scratch);*/
1621209ff23fSmrg
1622209ff23fSmrg	if (radeon_output->devices & ATOM_DEVICE_CRT1_SUPPORT) {
1623209ff23fSmrg	    if (bios_0_scratch & ATOM_S0_CRT1_MASK)
1624209ff23fSmrg		MonType = MT_CRT;
1625209ff23fSmrg	} else if (radeon_output->devices & ATOM_DEVICE_CRT2_SUPPORT) {
1626209ff23fSmrg	    if (bios_0_scratch & ATOM_S0_CRT2_MASK)
1627209ff23fSmrg		MonType = MT_CRT;
1628209ff23fSmrg	} else if (radeon_output->devices & ATOM_DEVICE_CV_SUPPORT) {
1629209ff23fSmrg	    if (bios_0_scratch & (ATOM_S0_CV_MASK | ATOM_S0_CV_MASK_A))
1630209ff23fSmrg		MonType = MT_CV;
1631209ff23fSmrg	} else if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) {
1632209ff23fSmrg	    if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A))
1633209ff23fSmrg		MonType = MT_CTV;
1634209ff23fSmrg	    else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A))
1635209ff23fSmrg		MonType = MT_STV;
1636209ff23fSmrg	}
1637209ff23fSmrg    }
1638209ff23fSmrg
1639209ff23fSmrg    return MonType;
1640209ff23fSmrg}
1641209ff23fSmrg
1642