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
68921a55d8Smrg#define AUX_NATIVE_WRITE                    0x8
69921a55d8Smrg#define AUX_NATIVE_READ                     0x9
70921a55d8Smrg
71921a55d8Smrg#define AUX_I2C_WRITE                       0x0
72921a55d8Smrg#define AUX_I2C_READ                        0x1
73921a55d8Smrg#define AUX_I2C_STATUS                      0x2
74921a55d8Smrg#define AUX_I2C_MOT                         0x4
75921a55d8Smrg
76921a55d8Smrg#define DP_DPCD_REV                         0x0
77921a55d8Smrg#define DP_MAX_LINK_RATE                    0x1
78921a55d8Smrg#define DP_MAX_LANE_COUNT                   0x2
79921a55d8Smrg#define DP_MAX_DOWNSPREAD                   0x3
80921a55d8Smrg#define DP_NORP                             0x4
81921a55d8Smrg#define DP_DOWNSTREAMPORT_PRESENT           0x5
82921a55d8Smrg#define DP_MAIN_LINK_CHANNEL_CONFIG         0x6
83921a55d8Smrg#define DP_DP11_DOWNSTREAM_PORT_COUNT       0x7
84921a55d8Smrg
85921a55d8Smrg/* from intel i830_dp.h */
86921a55d8Smrg#define DP_LINK_BW_SET                      0x100
87921a55d8Smrg//# define DP_LINK_BW_1_62                    0x06
88921a55d8Smrg//# define DP_LINK_BW_2_7                     0x0a
89921a55d8Smrg#define DP_LANE_COUNT_SET                   0x101
90921a55d8Smrg# define DP_LANE_COUNT_MASK                 0x0f
91921a55d8Smrg# define DP_LANE_COUNT_ENHANCED_FRAME_EN    (1 << 7)
92921a55d8Smrg
93921a55d8Smrg#define DP_TRAINING_PATTERN_SET             0x102
94921a55d8Smrg
95921a55d8Smrg# define DP_TRAINING_PATTERN_DISABLE        0
96921a55d8Smrg# define DP_TRAINING_PATTERN_1              1
97921a55d8Smrg# define DP_TRAINING_PATTERN_2              2
98921a55d8Smrg# define DP_TRAINING_PATTERN_MASK           0x3
99921a55d8Smrg
100921a55d8Smrg# define DP_LINK_QUAL_PATTERN_DISABLE       (0 << 2)
101921a55d8Smrg# define DP_LINK_QUAL_PATTERN_D10_2         (1 << 2)
102921a55d8Smrg# define DP_LINK_QUAL_PATTERN_ERROR_RATE    (2 << 2)
103921a55d8Smrg# define DP_LINK_QUAL_PATTERN_PRBS7         (3 << 2)
104921a55d8Smrg# define DP_LINK_QUAL_PATTERN_MASK          (3 << 2)
105921a55d8Smrg# define DP_RECOVERED_CLOCK_OUT_EN          (1 << 4)
106921a55d8Smrg# define DP_LINK_SCRAMBLING_DISABLE         (1 << 5)
107921a55d8Smrg
108921a55d8Smrg# define DP_SYMBOL_ERROR_COUNT_BOTH         (0 << 6)
109921a55d8Smrg# define DP_SYMBOL_ERROR_COUNT_DISPARITY    (1 << 6)
110921a55d8Smrg# define DP_SYMBOL_ERROR_COUNT_SYMBOL       (2 << 6)
111921a55d8Smrg# define DP_SYMBOL_ERROR_COUNT_MASK         (3 << 6)
112921a55d8Smrg
113921a55d8Smrg#define DP_TRAINING_LANE0_SET               0x103
114921a55d8Smrg#define DP_TRAINING_LANE1_SET               0x104
115921a55d8Smrg#define DP_TRAINING_LANE2_SET               0x105
116921a55d8Smrg#define DP_TRAINING_LANE3_SET               0x106
117921a55d8Smrg# define DP_TRAIN_VOLTAGE_SWING_MASK        0x3
118921a55d8Smrg# define DP_TRAIN_VOLTAGE_SWING_SHIFT       0
119921a55d8Smrg# define DP_TRAIN_MAX_SWING_REACHED         (1 << 2)
120921a55d8Smrg# define DP_TRAIN_VOLTAGE_SWING_400         (0 << 0)
121921a55d8Smrg# define DP_TRAIN_VOLTAGE_SWING_600         (1 << 0)
122921a55d8Smrg# define DP_TRAIN_VOLTAGE_SWING_800         (2 << 0)
123921a55d8Smrg# define DP_TRAIN_VOLTAGE_SWING_1200        (3 << 0)
124921a55d8Smrg
125921a55d8Smrg# define DP_TRAIN_PRE_EMPHASIS_MASK         (3 << 3)
126921a55d8Smrg# define DP_TRAIN_PRE_EMPHASIS_0            (0 << 3)
127921a55d8Smrg# define DP_TRAIN_PRE_EMPHASIS_3_5          (1 << 3)
128921a55d8Smrg# define DP_TRAIN_PRE_EMPHASIS_6            (2 << 3)
129921a55d8Smrg# define DP_TRAIN_PRE_EMPHASIS_9_5          (3 << 3)
130921a55d8Smrg
131921a55d8Smrg# define DP_TRAIN_PRE_EMPHASIS_SHIFT        3
132921a55d8Smrg# define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED  (1 << 5)
133921a55d8Smrg#define DP_DOWNSPREAD_CTRL                  0x107
134921a55d8Smrg# define DP_SPREAD_AMP_0_5                  (1 << 4)
135921a55d8Smrg
136921a55d8Smrg#define DP_MAIN_LINK_CHANNEL_CODING_SET     0x108
137921a55d8Smrg# define DP_SET_ANSI_8B10B                  (1 << 0)
138921a55d8Smrg
139921a55d8Smrg#define DP_LANE0_1_STATUS                   0x202
140921a55d8Smrg#define DP_LANE2_3_STATUS                   0x203
141921a55d8Smrg
142921a55d8Smrg# define DP_LANE_CR_DONE                    (1 << 0)
143921a55d8Smrg# define DP_LANE_CHANNEL_EQ_DONE            (1 << 1)
144921a55d8Smrg# define DP_LANE_SYMBOL_LOCKED              (1 << 2)
145921a55d8Smrg
146921a55d8Smrg#define DP_LANE_ALIGN_STATUS_UPDATED        0x204
147921a55d8Smrg#define DP_INTERLANE_ALIGN_DONE             (1 << 0)
148921a55d8Smrg#define DP_DOWNSTREAM_PORT_STATUS_CHANGED   (1 << 6)
149921a55d8Smrg#define DP_LINK_STATUS_UPDATED              (1 << 7)
150921a55d8Smrg
151921a55d8Smrg#define DP_SINK_STATUS                      0x205
152921a55d8Smrg
153921a55d8Smrg#define DP_RECEIVE_PORT_0_STATUS            (1 << 0)
154921a55d8Smrg#define DP_RECEIVE_PORT_1_STATUS            (1 << 1)
155921a55d8Smrg
156921a55d8Smrg#define DP_ADJUST_REQUEST_LANE0_1           0x206
157921a55d8Smrg#define DP_ADJUST_REQUEST_LANE2_3           0x207
158921a55d8Smrg
159921a55d8Smrg#define DP_ADJUST_VOLTAGE_SWING_LANE0_MASK  0x03
160921a55d8Smrg#define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT 0
161921a55d8Smrg#define DP_ADJUST_PRE_EMPHASIS_LANE0_MASK   0x0c
162921a55d8Smrg#define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT  2
163921a55d8Smrg#define DP_ADJUST_VOLTAGE_SWING_LANE1_MASK  0x30
164921a55d8Smrg#define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT 4
165921a55d8Smrg#define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK   0xc0
166921a55d8Smrg#define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT  6
167921a55d8Smrg
168921a55d8Smrg#define DP_LINK_STATUS_SIZE                 6
169921a55d8Smrg#define DP_LINK_CONFIGURATION_SIZE          9
170921a55d8Smrg
171921a55d8Smrg#define DP_SET_POWER_D0  0x1
172921a55d8Smrg#define DP_SET_POWER_D3  0x2
173921a55d8Smrg
174ad43ddacSmrgstatic void do_displayport_link_train(xf86OutputPtr output);
175ad43ddacSmrg
176209ff23fSmrgstatic int
177b7e1c893Smrgatombios_output_dac_setup(xf86OutputPtr output, int action)
178209ff23fSmrg{
179209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
180209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
181b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
182b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
183209ff23fSmrg    DAC_ENCODER_CONTROL_PS_ALLOCATION disp_data;
184209ff23fSmrg    AtomBiosArgRec data;
185209ff23fSmrg    unsigned char *space;
186b7e1c893Smrg    int index = 0, num = 0;
187b7e1c893Smrg    int clock = radeon_output->pixel_clock;
188b7e1c893Smrg
189b7e1c893Smrg    if (radeon_encoder == NULL)
190b7e1c893Smrg	return ATOM_NOT_IMPLEMENTED;
191b7e1c893Smrg
192b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
193b7e1c893Smrg
194b7e1c893Smrg    switch (radeon_encoder->encoder_id) {
195b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
196b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
197b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl);
198b7e1c893Smrg	num = 1;
199b7e1c893Smrg	break;
200b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
201b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
202b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl);
203b7e1c893Smrg	num = 2;
204b7e1c893Smrg	break;
205b7e1c893Smrg    }
206209ff23fSmrg
207b7e1c893Smrg    disp_data.ucAction =action;
208209ff23fSmrg
209b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_CRT_SUPPORT))
210209ff23fSmrg	disp_data.ucDacStandard = ATOM_DAC1_PS2;
211b7e1c893Smrg    else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
212209ff23fSmrg	disp_data.ucDacStandard = ATOM_DAC1_CV;
213b7e1c893Smrg    else {
214b7e1c893Smrg	switch (tvout->tvStd) {
215209ff23fSmrg	case TV_STD_PAL:
216209ff23fSmrg	case TV_STD_PAL_M:
217209ff23fSmrg	case TV_STD_SCART_PAL:
218209ff23fSmrg	case TV_STD_SECAM:
219209ff23fSmrg	case TV_STD_PAL_CN:
220209ff23fSmrg	    disp_data.ucDacStandard = ATOM_DAC1_PAL;
221209ff23fSmrg	    break;
222209ff23fSmrg	case TV_STD_NTSC:
223209ff23fSmrg	case TV_STD_NTSC_J:
224209ff23fSmrg	case TV_STD_PAL_60:
225209ff23fSmrg	default:
226b7e1c893Smrg	    disp_data.ucDacStandard = ATOM_DAC1_NTSC;
227209ff23fSmrg	    break;
228209ff23fSmrg	}
229209ff23fSmrg    }
230b7e1c893Smrg    disp_data.usPixelClock = cpu_to_le16(clock / 10);
231209ff23fSmrg
232b7e1c893Smrg    data.exec.index = index;
233209ff23fSmrg    data.exec.dataSpace = (void *)&space;
234209ff23fSmrg    data.exec.pspace = &disp_data;
235209ff23fSmrg
23668105dcbSveego    if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
237042789b0Sveego/*	ErrorF("Output DAC%d setup success\n", num); */
238209ff23fSmrg	return ATOM_SUCCESS;
239209ff23fSmrg    }
240209ff23fSmrg
241b7e1c893Smrg    ErrorF("Output DAC%d setup failed\n", num);
242209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
243209ff23fSmrg
244209ff23fSmrg}
245209ff23fSmrg
246209ff23fSmrgstatic int
247b7e1c893Smrgatombios_output_tv_setup(xf86OutputPtr output, int action)
248209ff23fSmrg{
249209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
250b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
251209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
252209ff23fSmrg    TV_ENCODER_CONTROL_PS_ALLOCATION disp_data;
253209ff23fSmrg    AtomBiosArgRec data;
254209ff23fSmrg    unsigned char *space;
255b7e1c893Smrg    int clock = radeon_output->pixel_clock;
256b7e1c893Smrg
257b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
258209ff23fSmrg
259b7e1c893Smrg    disp_data.sTVEncoder.ucAction = action;
260209ff23fSmrg
261b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
262209ff23fSmrg	disp_data.sTVEncoder.ucTvStandard = ATOM_TV_CV;
263209ff23fSmrg    else {
264b7e1c893Smrg	switch (tvout->tvStd) {
265209ff23fSmrg	case TV_STD_NTSC:
266209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSC;
267209ff23fSmrg	    break;
268209ff23fSmrg	case TV_STD_PAL:
269209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL;
270209ff23fSmrg	    break;
271209ff23fSmrg	case TV_STD_PAL_M:
272209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PALM;
273209ff23fSmrg	    break;
274209ff23fSmrg	case TV_STD_PAL_60:
275209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL60;
276209ff23fSmrg	    break;
277209ff23fSmrg	case TV_STD_NTSC_J:
278209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSCJ;
279209ff23fSmrg	    break;
280209ff23fSmrg	case TV_STD_SCART_PAL:
281209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PAL; /* ??? */
282209ff23fSmrg	    break;
283209ff23fSmrg	case TV_STD_SECAM:
284209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_SECAM;
285209ff23fSmrg	    break;
286209ff23fSmrg	case TV_STD_PAL_CN:
287209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_PALCN;
288209ff23fSmrg	    break;
289209ff23fSmrg	default:
290209ff23fSmrg	    disp_data.sTVEncoder.ucTvStandard = ATOM_TV_NTSC;
291209ff23fSmrg	    break;
292209ff23fSmrg	}
293209ff23fSmrg    }
294209ff23fSmrg
295b7e1c893Smrg    disp_data.sTVEncoder.usPixelClock = cpu_to_le16(clock / 10);
296209ff23fSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl);
297209ff23fSmrg    data.exec.dataSpace = (void *)&space;
298209ff23fSmrg    data.exec.pspace = &disp_data;
299209ff23fSmrg
30068105dcbSveego    if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
301042789b0Sveego/*	ErrorF("Output TV setup success\n"); */
302209ff23fSmrg	return ATOM_SUCCESS;
303209ff23fSmrg    }
304209ff23fSmrg
305b7e1c893Smrg    ErrorF("Output TV setup failed\n");
306209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
307209ff23fSmrg
308209ff23fSmrg}
309209ff23fSmrg
310209ff23fSmrgint
311b7e1c893Smrgatombios_external_tmds_setup(xf86OutputPtr output, int action)
312209ff23fSmrg{
313b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
314b7e1c893Smrg    ScrnInfoPtr pScrn = output->scrn;
315b7e1c893Smrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
316209ff23fSmrg    ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION disp_data;
317209ff23fSmrg    AtomBiosArgRec data;
318209ff23fSmrg    unsigned char *space;
319b7e1c893Smrg    int clock = radeon_output->pixel_clock;
320209ff23fSmrg
321b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
322209ff23fSmrg
323b7e1c893Smrg    disp_data.sXTmdsEncoder.ucEnable = action;
324b7e1c893Smrg
325b7e1c893Smrg    if (clock > 165000)
326b7e1c893Smrg	disp_data.sXTmdsEncoder.ucMisc = PANEL_ENCODER_MISC_DUAL;
327209ff23fSmrg
328b7e1c893Smrg    if (pScrn->rgbBits == 8)
329209ff23fSmrg	disp_data.sXTmdsEncoder.ucMisc |= (1 << 1);
330209ff23fSmrg
331209ff23fSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
332209ff23fSmrg    data.exec.dataSpace = (void *)&space;
333209ff23fSmrg    data.exec.pspace = &disp_data;
334209ff23fSmrg
33568105dcbSveego    if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
336042789b0Sveego/*	ErrorF("External TMDS setup success\n"); */
337209ff23fSmrg	return ATOM_SUCCESS;
338209ff23fSmrg    }
339209ff23fSmrg
340209ff23fSmrg    ErrorF("External TMDS setup failed\n");
341209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
342209ff23fSmrg}
343209ff23fSmrg
344209ff23fSmrgstatic int
345b7e1c893Smrgatombios_output_ddia_setup(xf86OutputPtr output, int action)
346209ff23fSmrg{
347b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
348209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
349209ff23fSmrg    DVO_ENCODER_CONTROL_PS_ALLOCATION disp_data;
350209ff23fSmrg    AtomBiosArgRec data;
351209ff23fSmrg    unsigned char *space;
352b7e1c893Smrg    int clock = radeon_output->pixel_clock;
353b7e1c893Smrg
354b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
355209ff23fSmrg
356b7e1c893Smrg    disp_data.sDVOEncoder.ucAction = action;
357b7e1c893Smrg    disp_data.sDVOEncoder.usPixelClock = cpu_to_le16(clock / 10);
358209ff23fSmrg
359b7e1c893Smrg    if (clock > 165000)
360209ff23fSmrg	disp_data.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = PANEL_ENCODER_MISC_DUAL;
361209ff23fSmrg
362209ff23fSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
363209ff23fSmrg    data.exec.dataSpace = (void *)&space;
364209ff23fSmrg    data.exec.pspace = &disp_data;
365209ff23fSmrg
36668105dcbSveego    if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
367042789b0Sveego/*	ErrorF("DDIA setup success\n"); */
368209ff23fSmrg	return ATOM_SUCCESS;
369209ff23fSmrg    }
370209ff23fSmrg
371209ff23fSmrg    ErrorF("DDIA setup failed\n");
372209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
373209ff23fSmrg}
374209ff23fSmrg
375209ff23fSmrgstatic int
376b7e1c893Smrgatombios_output_digital_setup(xf86OutputPtr output, int action)
377209ff23fSmrg{
378b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
379b7e1c893Smrg    ScrnInfoPtr pScrn = output->scrn;
380b7e1c893Smrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
381b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
382b7e1c893Smrg    LVDS_ENCODER_CONTROL_PS_ALLOCATION disp_data;
383b7e1c893Smrg    LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 disp_data2;
384209ff23fSmrg    AtomBiosArgRec data;
385209ff23fSmrg    unsigned char *space;
386b7e1c893Smrg    int index = 0;
387b7e1c893Smrg    int major, minor;
388b7e1c893Smrg    int lvds_misc = 0;
389b7e1c893Smrg    int clock = radeon_output->pixel_clock;
390209ff23fSmrg
391b7e1c893Smrg    if (radeon_encoder == NULL)
392b7e1c893Smrg	return ATOM_NOT_IMPLEMENTED;
393b7e1c893Smrg
394b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
395b7e1c893Smrg	radeon_lvds_ptr lvds = (radeon_lvds_ptr)radeon_encoder->dev_priv;
396b7e1c893Smrg	if (lvds == NULL)
397b7e1c893Smrg	    return ATOM_NOT_IMPLEMENTED;
398b7e1c893Smrg	lvds_misc = lvds->lvds_misc;
399b7e1c893Smrg    }
400b7e1c893Smrg
401b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
402b7e1c893Smrg    memset(&disp_data2,0, sizeof(disp_data2));
403b7e1c893Smrg
404b7e1c893Smrg    switch (radeon_encoder->encoder_id) {
405b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
406b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl);
407b7e1c893Smrg	break;
408b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
409b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
410b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl);
411b7e1c893Smrg	break;
412b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
413b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
414b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT))
415b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl);
416b7e1c893Smrg	else
417b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl);
418b7e1c893Smrg	break;
419b7e1c893Smrg    }
420b7e1c893Smrg
421b7e1c893Smrg    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
422b7e1c893Smrg
423b7e1c893Smrg    /*ErrorF("table is %d %d\n", major, minor);*/
424b7e1c893Smrg    switch (major) {
425b7e1c893Smrg    case 0:
426b7e1c893Smrg    case 1:
427b7e1c893Smrg    case 2:
428b7e1c893Smrg	switch (minor) {
429b7e1c893Smrg	case 1:
430b7e1c893Smrg	    disp_data.ucMisc = 0;
431b7e1c893Smrg	    disp_data.ucAction = action;
432b7e1c893Smrg	    if ((radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_A) ||
433b7e1c893Smrg		(radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_B))
434b7e1c893Smrg		disp_data.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
435b7e1c893Smrg	    disp_data.usPixelClock = cpu_to_le16(clock / 10);
436b7e1c893Smrg	    if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
437b7e1c893Smrg		if (lvds_misc & (1 << 0))
438b7e1c893Smrg		    disp_data.ucMisc |= PANEL_ENCODER_MISC_DUAL;
439b7e1c893Smrg		if (lvds_misc & (1 << 1))
440b7e1c893Smrg		    disp_data.ucMisc |= (1 << 1);
441b7e1c893Smrg	    } else {
442b7e1c893Smrg		if (radeon_output->linkb)
443b7e1c893Smrg		    disp_data.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
444b7e1c893Smrg		if (clock > 165000)
445b7e1c893Smrg		    disp_data.ucMisc |= PANEL_ENCODER_MISC_DUAL;
446b7e1c893Smrg		if (pScrn->rgbBits == 8)
447b7e1c893Smrg		    disp_data.ucMisc |= (1 << 1);
448b7e1c893Smrg	    }
449b7e1c893Smrg	    data.exec.pspace = &disp_data;
450b7e1c893Smrg	    break;
451b7e1c893Smrg	case 2:
452b7e1c893Smrg	case 3:
453b7e1c893Smrg	    disp_data2.ucMisc = 0;
454b7e1c893Smrg	    disp_data2.ucAction = action;
455b7e1c893Smrg	    if (minor == 3) {
456b7e1c893Smrg		if (radeon_output->coherent_mode) {
457b7e1c893Smrg		    disp_data2.ucMisc |= PANEL_ENCODER_MISC_COHERENT;
458b7e1c893Smrg		    xf86DrvMsg(output->scrn->scrnIndex, X_INFO, "Coherent Mode enabled\n");
459b7e1c893Smrg		}
460b7e1c893Smrg	    }
461b7e1c893Smrg	    if ((radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_A) ||
462b7e1c893Smrg		(radeon_output->ConnectorType == CONNECTOR_HDMI_TYPE_B))
463b7e1c893Smrg		disp_data2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
464b7e1c893Smrg	    disp_data2.usPixelClock = cpu_to_le16(clock / 10);
465b7e1c893Smrg	    disp_data2.ucTruncate = 0;
466b7e1c893Smrg	    disp_data2.ucSpatial = 0;
467b7e1c893Smrg	    disp_data2.ucTemporal = 0;
468b7e1c893Smrg	    disp_data2.ucFRC = 0;
469b7e1c893Smrg	    if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
470b7e1c893Smrg		if (lvds_misc & (1 << 0))
471b7e1c893Smrg		    disp_data2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
472b7e1c893Smrg		if (lvds_misc & (1 << 5)) {
473b7e1c893Smrg		    disp_data2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN;
474b7e1c893Smrg		    if (lvds_misc & (1 << 1))
475b7e1c893Smrg			disp_data2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH;
476b7e1c893Smrg		}
477b7e1c893Smrg		if (lvds_misc & (1 << 6)) {
478b7e1c893Smrg		    disp_data2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN;
479b7e1c893Smrg		    if (lvds_misc & (1 << 1))
480b7e1c893Smrg			disp_data2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH;
481b7e1c893Smrg		    if (((lvds_misc >> 2) & 0x3) == 2)
482b7e1c893Smrg			disp_data2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4;
483b7e1c893Smrg		}
484b7e1c893Smrg	    } else {
485b7e1c893Smrg		if (radeon_output->linkb)
486b7e1c893Smrg		    disp_data2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
487b7e1c893Smrg		if (clock > 165000)
488b7e1c893Smrg		    disp_data2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
489b7e1c893Smrg	    }
490b7e1c893Smrg	    data.exec.pspace = &disp_data2;
491b7e1c893Smrg	    break;
492b7e1c893Smrg	default:
493b7e1c893Smrg	    ErrorF("Unknown table version\n");
494b7e1c893Smrg	    exit(-1);
495b7e1c893Smrg	}
496b7e1c893Smrg	break;
497b7e1c893Smrg    default:
498b7e1c893Smrg	ErrorF("Unknown table version\n");
499b7e1c893Smrg	exit(-1);
500b7e1c893Smrg    }
501b7e1c893Smrg
502b7e1c893Smrg    data.exec.index = index;
503209ff23fSmrg    data.exec.dataSpace = (void *)&space;
504209ff23fSmrg
50568105dcbSveego    if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
506042789b0Sveego/*	ErrorF("Output digital setup success\n"); */
507209ff23fSmrg	return ATOM_SUCCESS;
508209ff23fSmrg    }
509209ff23fSmrg
510b7e1c893Smrg    ErrorF("Output digital setup failed\n");
511209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
512209ff23fSmrg}
513209ff23fSmrg
514209ff23fSmrgstatic int
515b7e1c893Smrgatombios_maybe_hdmi_mode(xf86OutputPtr output)
516209ff23fSmrg{
517b7e1c893Smrg#ifndef EDID_COMPLETE_RAWDATA
518b7e1c893Smrg    /* there's no getting this right unless we have complete EDID */
519921a55d8Smrg    return ATOM_ENCODER_MODE_DVI;
520b7e1c893Smrg#else
521b7e1c893Smrg    if (output && xf86MonitorIsHDMI(output->MonInfo))
522b7e1c893Smrg	return ATOM_ENCODER_MODE_HDMI;
523b7e1c893Smrg
524b7e1c893Smrg    return ATOM_ENCODER_MODE_DVI;
525b7e1c893Smrg#endif
526b7e1c893Smrg}
527209ff23fSmrg
528b7e1c893Smrgint
529b7e1c893Smrgatombios_get_encoder_mode(xf86OutputPtr output)
530b7e1c893Smrg{
5310974d292Smrg    ScrnInfoPtr pScrn = output->scrn;
5320974d292Smrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
533b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
534209ff23fSmrg
535b7e1c893Smrg    /* DVI should really be atombios_maybe_hdmi_mode() as well */
536b7e1c893Smrg    switch (radeon_output->ConnectorType) {
537b7e1c893Smrg    case CONNECTOR_DVI_I:
538b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT))
539b7e1c893Smrg	    return ATOM_ENCODER_MODE_DVI;
540b7e1c893Smrg	else
541b7e1c893Smrg	    return ATOM_ENCODER_MODE_CRT;
542b7e1c893Smrg	break;
543b7e1c893Smrg    case CONNECTOR_DVI_D:
544b7e1c893Smrg    default:
545b7e1c893Smrg	return ATOM_ENCODER_MODE_DVI;
546b7e1c893Smrg	break;
547b7e1c893Smrg    case CONNECTOR_HDMI_TYPE_A:
548b7e1c893Smrg    case CONNECTOR_HDMI_TYPE_B:
5490974d292Smrg	if (IS_DCE4_VARIANT)
5500974d292Smrg	    return ATOM_ENCODER_MODE_DVI;
5510974d292Smrg	else
5520974d292Smrg	    return atombios_maybe_hdmi_mode(output);
553b7e1c893Smrg	break;
554b7e1c893Smrg    case CONNECTOR_LVDS:
555b7e1c893Smrg	return ATOM_ENCODER_MODE_LVDS;
556b7e1c893Smrg	break;
557b7e1c893Smrg    case CONNECTOR_DISPLAY_PORT:
558ad43ddacSmrg    case CONNECTOR_EDP:
559b7e1c893Smrg	if (radeon_output->MonType == MT_DP)
560b7e1c893Smrg	    return ATOM_ENCODER_MODE_DP;
5610974d292Smrg	else {
5620974d292Smrg	    if (IS_DCE4_VARIANT)
5630974d292Smrg	        return ATOM_ENCODER_MODE_DVI;
5640974d292Smrg	    else
5650974d292Smrg	        return atombios_maybe_hdmi_mode(output);
5660974d292Smrg	}
567b7e1c893Smrg	break;
568b7e1c893Smrg    case CONNECTOR_DVI_A:
569b7e1c893Smrg    case CONNECTOR_VGA:
570b7e1c893Smrg    case CONNECTOR_STV:
571b7e1c893Smrg    case CONNECTOR_CTV:
572b7e1c893Smrg    case CONNECTOR_DIN:
573b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
574b7e1c893Smrg	    return ATOM_ENCODER_MODE_TV;
575b7e1c893Smrg	else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
576b7e1c893Smrg	    return ATOM_ENCODER_MODE_CV;
577b7e1c893Smrg	else
578b7e1c893Smrg	    return ATOM_ENCODER_MODE_CRT;
579b7e1c893Smrg	break;
580209ff23fSmrg    }
581209ff23fSmrg
582209ff23fSmrg}
583209ff23fSmrg
584b7e1c893Smrgstatic const int dp_clocks[] = {
585ad43ddacSmrg    5400,  // 1 lane, 1.62 Ghz
586ad43ddacSmrg    9000,  // 1 lane, 2.70 Ghz
587ad43ddacSmrg    10800, // 2 lane, 1.62 Ghz
588ad43ddacSmrg    18000, // 2 lane, 2.70 Ghz
589ad43ddacSmrg    21600, // 4 lane, 1.62 Ghz
590ad43ddacSmrg    36000, // 4 lane, 2.70 Ghz
591b7e1c893Smrg};
592b7e1c893Smrgstatic const int num_dp_clocks = sizeof(dp_clocks) / sizeof(int);
593b7e1c893Smrg
594ad43ddacSmrg# define DP_LINK_BW_1_62                    0x06
595ad43ddacSmrg# define DP_LINK_BW_2_7                     0x0a
596921a55d8Smrgstatic int radeon_dp_max_lane_count(xf86OutputPtr output);
597ad43ddacSmrg
598209ff23fSmrgstatic int
599921a55d8Smrgdp_lanes_for_mode_clock(xf86OutputPtr output, int mode_clock)
600209ff23fSmrg{
601921a55d8Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
602b7e1c893Smrg    int i;
603ad43ddacSmrg    int max_link_bw = radeon_output->dpcd[1];
604921a55d8Smrg    int max_lane_count = radeon_dp_max_lane_count(output);
605ad43ddacSmrg
606ad43ddacSmrg    switch (max_link_bw) {
607ad43ddacSmrg    case DP_LINK_BW_1_62:
608ad43ddacSmrg    default:
609ad43ddacSmrg	for (i = 0; i < num_dp_clocks; i++) {
610921a55d8Smrg		if (i % 2)
611921a55d8Smrg			continue;
612921a55d8Smrg		switch (max_lane_count) {
613921a55d8Smrg		case 1:
614921a55d8Smrg			if (i > 1)
615921a55d8Smrg				return 0;
616921a55d8Smrg			break;
617921a55d8Smrg		case 2:
618921a55d8Smrg			if (i > 3)
619921a55d8Smrg				return 0;
620921a55d8Smrg			break;
621921a55d8Smrg		case 4:
622921a55d8Smrg		default:
623921a55d8Smrg			break;
624921a55d8Smrg		}
625921a55d8Smrg		if (dp_clocks[i] > (mode_clock/10)) {
626921a55d8Smrg			if (i < 2)
627921a55d8Smrg				return 1;
628921a55d8Smrg			else if (i < 4)
629921a55d8Smrg				return 2;
630921a55d8Smrg			else
631921a55d8Smrg				return 4;
632921a55d8Smrg		}
633ad43ddacSmrg	}
634ad43ddacSmrg	break;
635ad43ddacSmrg    case DP_LINK_BW_2_7:
636ad43ddacSmrg	for (i = 0; i < num_dp_clocks; i++) {
637921a55d8Smrg		switch (max_lane_count) {
638921a55d8Smrg		case 1:
639921a55d8Smrg			if (i > 1)
640921a55d8Smrg				return 0;
641921a55d8Smrg			break;
642921a55d8Smrg		case 2:
643921a55d8Smrg			if (i > 3)
644921a55d8Smrg				return 0;
645921a55d8Smrg			break;
646921a55d8Smrg		case 4:
647921a55d8Smrg		default:
648921a55d8Smrg			break;
649921a55d8Smrg		}
650921a55d8Smrg		if (dp_clocks[i] > (mode_clock/10)) {
651921a55d8Smrg			if (i < 2)
652921a55d8Smrg				return 1;
653921a55d8Smrg			else if (i < 4)
654921a55d8Smrg				return 2;
655921a55d8Smrg			else
656921a55d8Smrg				return 4;
657921a55d8Smrg		}
658ad43ddacSmrg	}
659ad43ddacSmrg        break;
660ad43ddacSmrg    }
661209ff23fSmrg
662b7e1c893Smrg    return 0;
663b7e1c893Smrg}
664209ff23fSmrg
665b7e1c893Smrgstatic int
666921a55d8Smrgdp_link_clock_for_mode_clock(xf86OutputPtr output, int mode_clock)
667b7e1c893Smrg{
668921a55d8Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
669b7e1c893Smrg    int i;
670ad43ddacSmrg    int max_link_bw = radeon_output->dpcd[1];
671921a55d8Smrg    int max_lane_count = radeon_dp_max_lane_count(output);
672209ff23fSmrg
673ad43ddacSmrg    switch (max_link_bw) {
674ad43ddacSmrg    case DP_LINK_BW_1_62:
675ad43ddacSmrg    default:
676921a55d8Smrg	for (i = 0; i < num_dp_clocks; i++) {
677921a55d8Smrg		if (i % 2)
678921a55d8Smrg			continue;
679921a55d8Smrg		switch (max_lane_count) {
680921a55d8Smrg		case 1:
681921a55d8Smrg			if (i > 1)
682921a55d8Smrg				return 0;
683921a55d8Smrg			break;
684921a55d8Smrg		case 2:
685921a55d8Smrg			if (i > 3)
686921a55d8Smrg				return 0;
687921a55d8Smrg			break;
688921a55d8Smrg		case 4:
689921a55d8Smrg		default:
690921a55d8Smrg			break;
691921a55d8Smrg		}
692921a55d8Smrg		if (dp_clocks[i] > (mode_clock/10))
693921a55d8Smrg			return 16200;
694921a55d8Smrg	}
695ad43ddacSmrg	break;
696ad43ddacSmrg    case DP_LINK_BW_2_7:
697921a55d8Smrg	for (i = 0; i < num_dp_clocks; i++) {
698921a55d8Smrg		switch (max_lane_count) {
699921a55d8Smrg		case 1:
700921a55d8Smrg			if (i > 1)
701921a55d8Smrg				return 0;
702921a55d8Smrg			break;
703921a55d8Smrg		case 2:
704921a55d8Smrg			if (i > 3)
705921a55d8Smrg				return 0;
706921a55d8Smrg			break;
707921a55d8Smrg		case 4:
708921a55d8Smrg		default:
709921a55d8Smrg			break;
710921a55d8Smrg		}
711921a55d8Smrg		if (dp_clocks[i] > (mode_clock/10))
712921a55d8Smrg			return (i % 2) ? 27000 : 16200;
713921a55d8Smrg	}
714ad43ddacSmrg        break;
715ad43ddacSmrg    }
716b7e1c893Smrg
717b7e1c893Smrg    return 0;
718209ff23fSmrg}
719209ff23fSmrg
720ad43ddacSmrg/*
721ad43ddacSmrg * DIG Encoder/Transmitter Setup
722ad43ddacSmrg *
723ad43ddacSmrg * DCE 3.0/3.1
724ad43ddacSmrg * - 2 DIG transmitter blocks. UNIPHY (links A and B) and LVTMA.
725ad43ddacSmrg * Supports up to 3 digital outputs
726ad43ddacSmrg * - 2 DIG encoder blocks.
727ad43ddacSmrg * DIG1 can drive UNIPHY link A or link B
728ad43ddacSmrg * DIG2 can drive UNIPHY link B or LVTMA
729ad43ddacSmrg *
730ad43ddacSmrg * DCE 3.2
731ad43ddacSmrg * - 3 DIG transmitter blocks. UNIPHY0/1/2 (links A and B).
732ad43ddacSmrg * Supports up to 5 digital outputs
733ad43ddacSmrg * - 2 DIG encoder blocks.
734ad43ddacSmrg * DIG1/2 can drive UNIPHY0/1/2 link A or link B
735ad43ddacSmrg *
7360974d292Smrg * DCE 4.0
7370974d292Smrg * - 3 DIG transmitter blocks UNPHY0/1/2 (links A and B).
7380974d292Smrg * Supports up to 6 digital outputs
7390974d292Smrg * - 6 DIG encoder blocks.
7400974d292Smrg * - DIG to PHY mapping is hardcoded
7410974d292Smrg * DIG1 drives UNIPHY0 link A, A+B
7420974d292Smrg * DIG2 drives UNIPHY0 link B
7430974d292Smrg * DIG3 drives UNIPHY1 link A, A+B
7440974d292Smrg * DIG4 drives UNIPHY1 link B
7450974d292Smrg * DIG5 drives UNIPHY2 link A, A+B
7460974d292Smrg * DIG6 drives UNIPHY2 link B
7470974d292Smrg *
748ad43ddacSmrg * Routing
749ad43ddacSmrg * crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links)
750ad43ddacSmrg * Examples:
751ad43ddacSmrg * crtc0 -> dig2 -> LVTMA links A+B
752ad43ddacSmrg * crtc1 -> dig1 -> UNIPHY0 link B
7530974d292Smrg * crtc0 -> dig1 -> UNIPHY2 link  A   -> LVDS
7540974d292Smrg * crtc1 -> dig2 -> UNIPHY1 link  B+A -> TMDS/HDMI
755ad43ddacSmrg */
7560974d292Smrg
7570974d292Smrgunion dig_encoder_control {
7580974d292Smrg	DIG_ENCODER_CONTROL_PS_ALLOCATION v1;
7590974d292Smrg	DIG_ENCODER_CONTROL_PARAMETERS_V2 v2;
7600974d292Smrg	DIG_ENCODER_CONTROL_PARAMETERS_V3 v3;
7610974d292Smrg};
7620974d292Smrg
763209ff23fSmrgstatic int
764b7e1c893Smrgatombios_output_dig_encoder_setup(xf86OutputPtr output, int action)
765209ff23fSmrg{
766209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
767209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
768b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
7690974d292Smrg    union dig_encoder_control disp_data;
770209ff23fSmrg    AtomBiosArgRec data;
771209ff23fSmrg    unsigned char *space;
772ad43ddacSmrg    int index = 0, major, minor;
773b7e1c893Smrg    int clock = radeon_output->pixel_clock;
774b7e1c893Smrg
775b7e1c893Smrg    if (radeon_encoder == NULL)
776b7e1c893Smrg	return ATOM_NOT_IMPLEMENTED;
777b7e1c893Smrg
778b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
779b7e1c893Smrg
7800974d292Smrg    if (IS_DCE4_VARIANT)
7810974d292Smrg	index = GetIndexIntoMasterTable(COMMAND, DIGxEncoderControl);
7820974d292Smrg    else if (radeon_output->dig_encoder)
783ad43ddacSmrg        index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
784ad43ddacSmrg    else
785ad43ddacSmrg        index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
786209ff23fSmrg
787b7e1c893Smrg    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
788b7e1c893Smrg
7890974d292Smrg    disp_data.v1.ucAction = action;
7900974d292Smrg    disp_data.v1.usPixelClock = cpu_to_le16(clock / 10);
7910974d292Smrg    disp_data.v1.ucEncoderMode = atombios_get_encoder_mode(output);
792b7e1c893Smrg
7930974d292Smrg    if (disp_data.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) {
794921a55d8Smrg	if (dp_link_clock_for_mode_clock(output, clock) == 27000)
7950974d292Smrg	    disp_data.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
796921a55d8Smrg	disp_data.v1.ucLaneNum = dp_lanes_for_mode_clock(output, clock);
7970974d292Smrg    } else if (clock > 165000)
7980974d292Smrg	disp_data.v1.ucLaneNum = 8;
7990974d292Smrg    else
8000974d292Smrg	disp_data.v1.ucLaneNum = 4;
8010974d292Smrg
8020974d292Smrg    if (IS_DCE4_VARIANT) {
8030974d292Smrg	disp_data.v3.acConfig.ucDigSel = radeon_output->dig_encoder;
8040974d292Smrg	disp_data.v3.ucBitPerColor = PANEL_8BIT_PER_COLOR;
8050974d292Smrg    } else {
806b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
807b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
8080974d292Smrg	    disp_data.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1;
809b7e1c893Smrg	    break;
810b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
811921a55d8Smrg	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
8120974d292Smrg	    disp_data.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2;
813b7e1c893Smrg	    break;
814b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
8150974d292Smrg	    disp_data.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3;
816b7e1c893Smrg	    break;
817b7e1c893Smrg	}
8180974d292Smrg	if (radeon_output->linkb)
8190974d292Smrg	    disp_data.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
8200974d292Smrg	else
8210974d292Smrg	    disp_data.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
822209ff23fSmrg    }
823209ff23fSmrg
824b7e1c893Smrg    data.exec.index = index;
825209ff23fSmrg    data.exec.dataSpace = (void *)&space;
826209ff23fSmrg    data.exec.pspace = &disp_data;
827209ff23fSmrg
82868105dcbSveego    if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
829042789b0Sveego/*	ErrorF("Output DIG%d encoder setup success\n", radeon_output->dig_encoder); */
830209ff23fSmrg	return ATOM_SUCCESS;
831209ff23fSmrg    }
832209ff23fSmrg
833ad43ddacSmrg    ErrorF("Output DIG%d setup failed\n", radeon_output->dig_encoder);
834209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
835209ff23fSmrg
836209ff23fSmrg}
837209ff23fSmrg
838b7e1c893Smrgunion dig_transmitter_control {
839b7e1c893Smrg    DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1;
840b7e1c893Smrg    DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2;
841ad43ddacSmrg    DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3;
842b7e1c893Smrg};
843b7e1c893Smrg
844209ff23fSmrgstatic int
845ad43ddacSmrgatombios_output_dig_transmitter_setup(xf86OutputPtr output, int action, uint8_t lane_num, uint8_t lane_set)
846209ff23fSmrg{
847209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
848209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
849b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
850b7e1c893Smrg    union dig_transmitter_control disp_data;
851209ff23fSmrg    AtomBiosArgRec data;
852209ff23fSmrg    unsigned char *space;
853b7e1c893Smrg    int index = 0, num = 0;
854b7e1c893Smrg    int major, minor;
855b7e1c893Smrg    int clock = radeon_output->pixel_clock;
856b7e1c893Smrg
857b7e1c893Smrg    if (radeon_encoder == NULL)
858b7e1c893Smrg        return ATOM_NOT_IMPLEMENTED;
859b7e1c893Smrg
860b7e1c893Smrg    memset(&disp_data,0, sizeof(disp_data));
861b7e1c893Smrg
862ad43ddacSmrg    if (IS_DCE32_VARIANT || IS_DCE4_VARIANT)
863b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
864b7e1c893Smrg    else {
865b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
866b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
867b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DIG1TransmitterControl);
868b7e1c893Smrg	    break;
869b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
870b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DIG2TransmitterControl);
871b7e1c893Smrg	    break;
872b7e1c893Smrg	}
873b7e1c893Smrg    }
874209ff23fSmrg
875b7e1c893Smrg    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
876b7e1c893Smrg
877b7e1c893Smrg    disp_data.v1.ucAction = action;
8780974d292Smrg    if (action == ATOM_TRANSMITTER_ACTION_INIT) {
8790974d292Smrg        disp_data.v1.usInitInfo = radeon_output->connector_object_id;
8800974d292Smrg    } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
8810974d292Smrg	disp_data.v1.asMode.ucLaneSel = lane_num;
8820974d292Smrg	disp_data.v1.asMode.ucLaneSet = lane_set;
8830974d292Smrg    } else {
8840974d292Smrg	if (radeon_output->MonType == MT_DP)
8850974d292Smrg	    disp_data.v1.usPixelClock =
886921a55d8Smrg		cpu_to_le16(dp_link_clock_for_mode_clock(output, clock));
8870974d292Smrg	else if (clock > 165000)
8880974d292Smrg	    disp_data.v1.usPixelClock = cpu_to_le16((clock / 2) / 10);
8890974d292Smrg	else
8900974d292Smrg	    disp_data.v1.usPixelClock = cpu_to_le16(clock / 10);
8910974d292Smrg    }
892b7e1c893Smrg
893ad43ddacSmrg    if (IS_DCE4_VARIANT) {
894ad43ddacSmrg	if (radeon_output->MonType == MT_DP)
895921a55d8Smrg	    disp_data.v3.ucLaneNum = dp_lanes_for_mode_clock(output, clock);
896ad43ddacSmrg	else if (clock > 165000)
897ad43ddacSmrg	    disp_data.v3.ucLaneNum = 8;
898ad43ddacSmrg	else
899ad43ddacSmrg	    disp_data.v3.ucLaneNum = 4;
900ad43ddacSmrg
901ad43ddacSmrg	if (radeon_output->linkb) {
902ad43ddacSmrg	    disp_data.v3.acConfig.ucLinkSel = 1;
903b7e1c893Smrg	    disp_data.v2.acConfig.ucEncoderSel = 1;
904ad43ddacSmrg	}
905ad43ddacSmrg
906ad43ddacSmrg	// select the PLL for the UNIPHY
9070974d292Smrg	if (radeon_output->MonType == MT_DP && info->dp_extclk)
908ad43ddacSmrg	    disp_data.v3.acConfig.ucRefClkSource = 2; /* ext clk */
909ad43ddacSmrg	else
910ad43ddacSmrg	    disp_data.v3.acConfig.ucRefClkSource = radeon_output->pll_id;
911ad43ddacSmrg
912ad43ddacSmrg	switch (radeon_encoder->encoder_id) {
913ad43ddacSmrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
914ad43ddacSmrg	    disp_data.v3.acConfig.ucTransmitterSel = 0;
915ad43ddacSmrg	    num = 0;
916ad43ddacSmrg	    break;
917ad43ddacSmrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
918ad43ddacSmrg	    disp_data.v3.acConfig.ucTransmitterSel = 1;
919ad43ddacSmrg	    num = 1;
920ad43ddacSmrg	    break;
921ad43ddacSmrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
922ad43ddacSmrg	    disp_data.v3.acConfig.ucTransmitterSel = 2;
923ad43ddacSmrg	    num = 2;
924ad43ddacSmrg	    break;
925ad43ddacSmrg	}
926ad43ddacSmrg
927ad43ddacSmrg	if (radeon_output->MonType == MT_DP)
928ad43ddacSmrg	    disp_data.v3.acConfig.fCoherentMode = 1; /* DP requires coherent */
929ad43ddacSmrg	else if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) {
930ad43ddacSmrg	    if (radeon_output->coherent_mode)
931ad43ddacSmrg		disp_data.v3.acConfig.fCoherentMode = 1;
9320974d292Smrg	    if (clock > 165000)
9330974d292Smrg		disp_data.v3.acConfig.fDualLinkConnector = 1;
934ad43ddacSmrg	}
935ad43ddacSmrg    } else if (IS_DCE32_VARIANT) {
936ad43ddacSmrg	if (radeon_output->dig_encoder)
937ad43ddacSmrg	    disp_data.v2.acConfig.ucEncoderSel = 1;
938ad43ddacSmrg
939ad43ddacSmrg	if (radeon_output->linkb)
940ad43ddacSmrg	    disp_data.v2.acConfig.ucLinkSel = 1;
941b7e1c893Smrg
942b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
943b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
944b7e1c893Smrg	    disp_data.v2.acConfig.ucTransmitterSel = 0;
945b7e1c893Smrg	    num = 0;
946b7e1c893Smrg	    break;
947b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
948b7e1c893Smrg	    disp_data.v2.acConfig.ucTransmitterSel = 1;
949b7e1c893Smrg	    num = 1;
950b7e1c893Smrg	    break;
951b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
952b7e1c893Smrg	    disp_data.v2.acConfig.ucTransmitterSel = 2;
953b7e1c893Smrg	    num = 2;
954b7e1c893Smrg	    break;
955b7e1c893Smrg	}
956b7e1c893Smrg
957ad43ddacSmrg	if (radeon_output->MonType == MT_DP)
958ad43ddacSmrg	    disp_data.v2.acConfig.fCoherentMode = 1; /* DP requires coherent */
959ad43ddacSmrg	else if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) {
960ad43ddacSmrg	    if (radeon_output->coherent_mode)
961b7e1c893Smrg		disp_data.v2.acConfig.fCoherentMode = 1;
962921a55d8Smrg	    if (clock > 165000)
963921a55d8Smrg		disp_data.v2.acConfig.fDualLinkConnector = 1;
964209ff23fSmrg	}
965209ff23fSmrg    } else {
966b7e1c893Smrg	disp_data.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL;
967b7e1c893Smrg
968ad43ddacSmrg	if (radeon_output->dig_encoder)
969ad43ddacSmrg	    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
970209ff23fSmrg	else
971ad43ddacSmrg	    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
972b7e1c893Smrg
973b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
974b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
975b7e1c893Smrg	    if (info->IsIGP) {
976b7e1c893Smrg		if (clock > 165000) {
977b7e1c893Smrg		    if (radeon_output->igp_lane_info & 0x3)
978b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7;
979b7e1c893Smrg		    else if (radeon_output->igp_lane_info & 0xc)
980b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15;
981b7e1c893Smrg		} else {
982b7e1c893Smrg		    if (radeon_output->igp_lane_info & 0x1)
983b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3;
984b7e1c893Smrg		    else if (radeon_output->igp_lane_info & 0x2)
985b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7;
986b7e1c893Smrg		    else if (radeon_output->igp_lane_info & 0x4)
987b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11;
988b7e1c893Smrg		    else if (radeon_output->igp_lane_info & 0x8)
989b7e1c893Smrg			disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15;
990b7e1c893Smrg		}
991b7e1c893Smrg	    }
992b7e1c893Smrg	    break;
993b7e1c893Smrg	}
994ad43ddacSmrg	if (radeon_output->linkb)
995ad43ddacSmrg	    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB;
996ad43ddacSmrg	else
997ad43ddacSmrg	    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA;
998209ff23fSmrg
999ad43ddacSmrg	if (radeon_output->MonType == MT_DP)
1000ad43ddacSmrg	    disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;  /* DP requires coherent */
1001ad43ddacSmrg	else if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT)) {
1002ad43ddacSmrg	    if (radeon_output->coherent_mode)
1003b7e1c893Smrg		disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
10040974d292Smrg	    if (clock > 165000)
10050974d292Smrg		disp_data.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK;
1006b7e1c893Smrg	}
1007b7e1c893Smrg    }
1008209ff23fSmrg
1009b7e1c893Smrg    data.exec.index = index;
1010209ff23fSmrg    data.exec.dataSpace = (void *)&space;
1011209ff23fSmrg    data.exec.pspace = &disp_data;
1012209ff23fSmrg
101368105dcbSveego    if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
1014042789b0Sveego/*
1015b7e1c893Smrg	if (IS_DCE32_VARIANT)
1016b7e1c893Smrg	    ErrorF("Output UNIPHY%d transmitter setup success\n", num);
1017b7e1c893Smrg	else
1018b7e1c893Smrg	   ErrorF("Output DIG%d transmitter setup success\n", num);
1019042789b0Sveego*/
1020209ff23fSmrg	return ATOM_SUCCESS;
1021209ff23fSmrg    }
1022209ff23fSmrg
1023b7e1c893Smrg    ErrorF("Output DIG%d transmitter setup failed\n", num);
1024209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
1025209ff23fSmrg
1026209ff23fSmrg}
1027209ff23fSmrg
1028c503f109Smrgstatic void atom_rv515_force_tv_scaler(ScrnInfoPtr pScrn, RADEONCrtcPrivatePtr radeon_crtc)
1029b7e1c893Smrg{
1030b7e1c893Smrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
1031b7e1c893Smrg    unsigned char *RADEONMMIO = info->MMIO;
1032c503f109Smrg    int index_reg = 0x6578, data_reg = 0x657c;
1033c503f109Smrg
1034c503f109Smrg    index_reg += radeon_crtc->crtc_offset;
1035c503f109Smrg    data_reg += radeon_crtc->crtc_offset;
1036c503f109Smrg
1037c503f109Smrg    OUTREG(0x659C + radeon_crtc->crtc_offset, 0x0);
1038c503f109Smrg    OUTREG(0x6594 + radeon_crtc->crtc_offset, 0x705);
1039c503f109Smrg    OUTREG(0x65A4 + radeon_crtc->crtc_offset, 0x10001);
1040c503f109Smrg    OUTREG(0x65D8 + radeon_crtc->crtc_offset, 0x0);
1041c503f109Smrg    OUTREG(0x65B0 + radeon_crtc->crtc_offset, 0x0);
1042c503f109Smrg    OUTREG(0x65C0 + radeon_crtc->crtc_offset, 0x0);
1043c503f109Smrg    OUTREG(0x65D4 + radeon_crtc->crtc_offset, 0x0);
1044c503f109Smrg    OUTREG(index_reg,0x0);
1045c503f109Smrg    OUTREG(data_reg,0x841880A8);
1046c503f109Smrg    OUTREG(index_reg,0x1);
1047c503f109Smrg    OUTREG(data_reg,0x84208680);
1048c503f109Smrg    OUTREG(index_reg,0x2);
1049c503f109Smrg    OUTREG(data_reg,0xBFF880B0);
1050c503f109Smrg    OUTREG(index_reg,0x100);
1051c503f109Smrg    OUTREG(data_reg,0x83D88088);
1052c503f109Smrg    OUTREG(index_reg,0x101);
1053c503f109Smrg    OUTREG(data_reg,0x84608680);
1054c503f109Smrg    OUTREG(index_reg,0x102);
1055c503f109Smrg    OUTREG(data_reg,0xBFF080D0);
1056c503f109Smrg    OUTREG(index_reg,0x200);
1057c503f109Smrg    OUTREG(data_reg,0x83988068);
1058c503f109Smrg    OUTREG(index_reg,0x201);
1059c503f109Smrg    OUTREG(data_reg,0x84A08680);
1060c503f109Smrg    OUTREG(index_reg,0x202);
1061c503f109Smrg    OUTREG(data_reg,0xBFF080F8);
1062c503f109Smrg    OUTREG(index_reg,0x300);
1063c503f109Smrg    OUTREG(data_reg,0x83588058);
1064c503f109Smrg    OUTREG(index_reg,0x301);
1065c503f109Smrg    OUTREG(data_reg,0x84E08660);
1066c503f109Smrg    OUTREG(index_reg,0x302);
1067c503f109Smrg    OUTREG(data_reg,0xBFF88120);
1068c503f109Smrg    OUTREG(index_reg,0x400);
1069c503f109Smrg    OUTREG(data_reg,0x83188040);
1070c503f109Smrg    OUTREG(index_reg,0x401);
1071c503f109Smrg    OUTREG(data_reg,0x85008660);
1072c503f109Smrg    OUTREG(index_reg,0x402);
1073c503f109Smrg    OUTREG(data_reg,0xBFF88150);
1074c503f109Smrg    OUTREG(index_reg,0x500);
1075c503f109Smrg    OUTREG(data_reg,0x82D88030);
1076c503f109Smrg    OUTREG(index_reg,0x501);
1077c503f109Smrg    OUTREG(data_reg,0x85408640);
1078c503f109Smrg    OUTREG(index_reg,0x502);
1079c503f109Smrg    OUTREG(data_reg,0xBFF88180);
1080c503f109Smrg    OUTREG(index_reg,0x600);
1081c503f109Smrg    OUTREG(data_reg,0x82A08018);
1082c503f109Smrg    OUTREG(index_reg,0x601);
1083c503f109Smrg    OUTREG(data_reg,0x85808620);
1084c503f109Smrg    OUTREG(index_reg,0x602);
1085c503f109Smrg    OUTREG(data_reg,0xBFF081B8);
1086c503f109Smrg    OUTREG(index_reg,0x700);
1087c503f109Smrg    OUTREG(data_reg,0x82608010);
1088c503f109Smrg    OUTREG(index_reg,0x701);
1089c503f109Smrg    OUTREG(data_reg,0x85A08600);
1090c503f109Smrg    OUTREG(index_reg,0x702);
1091c503f109Smrg    OUTREG(data_reg,0x800081F0);
1092c503f109Smrg    OUTREG(index_reg,0x800);
1093c503f109Smrg    OUTREG(data_reg,0x8228BFF8);
1094c503f109Smrg    OUTREG(index_reg,0x801);
1095c503f109Smrg    OUTREG(data_reg,0x85E085E0);
1096c503f109Smrg    OUTREG(index_reg,0x802);
1097c503f109Smrg    OUTREG(data_reg,0xBFF88228);
1098c503f109Smrg    OUTREG(index_reg,0x10000);
1099c503f109Smrg    OUTREG(data_reg,0x82A8BF00);
1100c503f109Smrg    OUTREG(index_reg,0x10001);
1101c503f109Smrg    OUTREG(data_reg,0x82A08CC0);
1102c503f109Smrg    OUTREG(index_reg,0x10002);
1103c503f109Smrg    OUTREG(data_reg,0x8008BEF8);
1104c503f109Smrg    OUTREG(index_reg,0x10100);
1105c503f109Smrg    OUTREG(data_reg,0x81F0BF28);
1106c503f109Smrg    OUTREG(index_reg,0x10101);
1107c503f109Smrg    OUTREG(data_reg,0x83608CA0);
1108c503f109Smrg    OUTREG(index_reg,0x10102);
1109c503f109Smrg    OUTREG(data_reg,0x8018BED0);
1110c503f109Smrg    OUTREG(index_reg,0x10200);
1111c503f109Smrg    OUTREG(data_reg,0x8148BF38);
1112c503f109Smrg    OUTREG(index_reg,0x10201);
1113c503f109Smrg    OUTREG(data_reg,0x84408C80);
1114c503f109Smrg    OUTREG(index_reg,0x10202);
1115c503f109Smrg    OUTREG(data_reg,0x8008BEB8);
1116c503f109Smrg    OUTREG(index_reg,0x10300);
1117c503f109Smrg    OUTREG(data_reg,0x80B0BF78);
1118c503f109Smrg    OUTREG(index_reg,0x10301);
1119c503f109Smrg    OUTREG(data_reg,0x85008C20);
1120c503f109Smrg    OUTREG(index_reg,0x10302);
1121c503f109Smrg    OUTREG(data_reg,0x8020BEA0);
1122c503f109Smrg    OUTREG(index_reg,0x10400);
1123c503f109Smrg    OUTREG(data_reg,0x8028BF90);
1124c503f109Smrg    OUTREG(index_reg,0x10401);
1125c503f109Smrg    OUTREG(data_reg,0x85E08BC0);
1126c503f109Smrg    OUTREG(index_reg,0x10402);
1127c503f109Smrg    OUTREG(data_reg,0x8018BE90);
1128c503f109Smrg    OUTREG(index_reg,0x10500);
1129c503f109Smrg    OUTREG(data_reg,0xBFB8BFB0);
1130c503f109Smrg    OUTREG(index_reg,0x10501);
1131c503f109Smrg    OUTREG(data_reg,0x86C08B40);
1132c503f109Smrg    OUTREG(index_reg,0x10502);
1133c503f109Smrg    OUTREG(data_reg,0x8010BE90);
1134c503f109Smrg    OUTREG(index_reg,0x10600);
1135c503f109Smrg    OUTREG(data_reg,0xBF58BFC8);
1136c503f109Smrg    OUTREG(index_reg,0x10601);
1137c503f109Smrg    OUTREG(data_reg,0x87A08AA0);
1138c503f109Smrg    OUTREG(index_reg,0x10602);
1139c503f109Smrg    OUTREG(data_reg,0x8010BE98);
1140c503f109Smrg    OUTREG(index_reg,0x10700);
1141c503f109Smrg    OUTREG(data_reg,0xBF10BFF0);
1142c503f109Smrg    OUTREG(index_reg,0x10701);
1143c503f109Smrg    OUTREG(data_reg,0x886089E0);
1144c503f109Smrg    OUTREG(index_reg,0x10702);
1145c503f109Smrg    OUTREG(data_reg,0x8018BEB0);
1146c503f109Smrg    OUTREG(index_reg,0x10800);
1147c503f109Smrg    OUTREG(data_reg,0xBED8BFE8);
1148c503f109Smrg    OUTREG(index_reg,0x10801);
1149c503f109Smrg    OUTREG(data_reg,0x89408940);
1150c503f109Smrg    OUTREG(index_reg,0x10802);
1151c503f109Smrg    OUTREG(data_reg,0xBFE8BED8);
1152c503f109Smrg    OUTREG(index_reg,0x20000);
1153c503f109Smrg    OUTREG(data_reg,0x80008000);
1154c503f109Smrg    OUTREG(index_reg,0x20001);
1155c503f109Smrg    OUTREG(data_reg,0x90008000);
1156c503f109Smrg    OUTREG(index_reg,0x20002);
1157c503f109Smrg    OUTREG(data_reg,0x80008000);
1158c503f109Smrg    OUTREG(index_reg,0x20003);
1159c503f109Smrg    OUTREG(data_reg,0x80008000);
1160c503f109Smrg    OUTREG(index_reg,0x20100);
1161c503f109Smrg    OUTREG(data_reg,0x80108000);
1162c503f109Smrg    OUTREG(index_reg,0x20101);
1163c503f109Smrg    OUTREG(data_reg,0x8FE0BF70);
1164c503f109Smrg    OUTREG(index_reg,0x20102);
1165c503f109Smrg    OUTREG(data_reg,0xBFE880C0);
1166c503f109Smrg    OUTREG(index_reg,0x20103);
1167c503f109Smrg    OUTREG(data_reg,0x80008000);
1168c503f109Smrg    OUTREG(index_reg,0x20200);
1169c503f109Smrg    OUTREG(data_reg,0x8018BFF8);
1170c503f109Smrg    OUTREG(index_reg,0x20201);
1171c503f109Smrg    OUTREG(data_reg,0x8F80BF08);
1172c503f109Smrg    OUTREG(index_reg,0x20202);
1173c503f109Smrg    OUTREG(data_reg,0xBFD081A0);
1174c503f109Smrg    OUTREG(index_reg,0x20203);
1175c503f109Smrg    OUTREG(data_reg,0xBFF88000);
1176c503f109Smrg    OUTREG(index_reg,0x20300);
1177c503f109Smrg    OUTREG(data_reg,0x80188000);
1178c503f109Smrg    OUTREG(index_reg,0x20301);
1179c503f109Smrg    OUTREG(data_reg,0x8EE0BEC0);
1180c503f109Smrg    OUTREG(index_reg,0x20302);
1181c503f109Smrg    OUTREG(data_reg,0xBFB082A0);
1182c503f109Smrg    OUTREG(index_reg,0x20303);
1183c503f109Smrg    OUTREG(data_reg,0x80008000);
1184c503f109Smrg    OUTREG(index_reg,0x20400);
1185c503f109Smrg    OUTREG(data_reg,0x80188000);
1186c503f109Smrg    OUTREG(index_reg,0x20401);
1187c503f109Smrg    OUTREG(data_reg,0x8E00BEA0);
1188c503f109Smrg    OUTREG(index_reg,0x20402);
1189c503f109Smrg    OUTREG(data_reg,0xBF8883C0);
1190c503f109Smrg    OUTREG(index_reg,0x20403);
1191c503f109Smrg    OUTREG(data_reg,0x80008000);
1192c503f109Smrg    OUTREG(index_reg,0x20500);
1193c503f109Smrg    OUTREG(data_reg,0x80188000);
1194c503f109Smrg    OUTREG(index_reg,0x20501);
1195c503f109Smrg    OUTREG(data_reg,0x8D00BE90);
1196c503f109Smrg    OUTREG(index_reg,0x20502);
1197c503f109Smrg    OUTREG(data_reg,0xBF588500);
1198c503f109Smrg    OUTREG(index_reg,0x20503);
1199c503f109Smrg    OUTREG(data_reg,0x80008008);
1200c503f109Smrg    OUTREG(index_reg,0x20600);
1201c503f109Smrg    OUTREG(data_reg,0x80188000);
1202c503f109Smrg    OUTREG(index_reg,0x20601);
1203c503f109Smrg    OUTREG(data_reg,0x8BC0BE98);
1204c503f109Smrg    OUTREG(index_reg,0x20602);
1205c503f109Smrg    OUTREG(data_reg,0xBF308660);
1206c503f109Smrg    OUTREG(index_reg,0x20603);
1207c503f109Smrg    OUTREG(data_reg,0x80008008);
1208c503f109Smrg    OUTREG(index_reg,0x20700);
1209c503f109Smrg    OUTREG(data_reg,0x80108000);
1210c503f109Smrg    OUTREG(index_reg,0x20701);
1211c503f109Smrg    OUTREG(data_reg,0x8A80BEB0);
1212c503f109Smrg    OUTREG(index_reg,0x20702);
1213c503f109Smrg    OUTREG(data_reg,0xBF0087C0);
1214c503f109Smrg    OUTREG(index_reg,0x20703);
1215c503f109Smrg    OUTREG(data_reg,0x80008008);
1216c503f109Smrg    OUTREG(index_reg,0x20800);
1217c503f109Smrg    OUTREG(data_reg,0x80108000);
1218c503f109Smrg    OUTREG(index_reg,0x20801);
1219c503f109Smrg    OUTREG(data_reg,0x8920BED0);
1220c503f109Smrg    OUTREG(index_reg,0x20802);
1221c503f109Smrg    OUTREG(data_reg,0xBED08920);
1222c503f109Smrg    OUTREG(index_reg,0x20803);
1223c503f109Smrg    OUTREG(data_reg,0x80008010);
1224c503f109Smrg    OUTREG(index_reg,0x30000);
1225c503f109Smrg    OUTREG(data_reg,0x90008000);
1226c503f109Smrg    OUTREG(index_reg,0x30001);
1227c503f109Smrg    OUTREG(data_reg,0x80008000);
1228c503f109Smrg    OUTREG(index_reg,0x30100);
1229c503f109Smrg    OUTREG(data_reg,0x8FE0BF90);
1230c503f109Smrg    OUTREG(index_reg,0x30101);
1231c503f109Smrg    OUTREG(data_reg,0xBFF880A0);
1232c503f109Smrg    OUTREG(index_reg,0x30200);
1233c503f109Smrg    OUTREG(data_reg,0x8F60BF40);
1234c503f109Smrg    OUTREG(index_reg,0x30201);
1235c503f109Smrg    OUTREG(data_reg,0xBFE88180);
1236c503f109Smrg    OUTREG(index_reg,0x30300);
1237c503f109Smrg    OUTREG(data_reg,0x8EC0BF00);
1238c503f109Smrg    OUTREG(index_reg,0x30301);
1239c503f109Smrg    OUTREG(data_reg,0xBFC88280);
1240c503f109Smrg    OUTREG(index_reg,0x30400);
1241c503f109Smrg    OUTREG(data_reg,0x8DE0BEE0);
1242c503f109Smrg    OUTREG(index_reg,0x30401);
1243c503f109Smrg    OUTREG(data_reg,0xBFA083A0);
1244c503f109Smrg    OUTREG(index_reg,0x30500);
1245c503f109Smrg    OUTREG(data_reg,0x8CE0BED0);
1246c503f109Smrg    OUTREG(index_reg,0x30501);
1247c503f109Smrg    OUTREG(data_reg,0xBF7884E0);
1248c503f109Smrg    OUTREG(index_reg,0x30600);
1249c503f109Smrg    OUTREG(data_reg,0x8BA0BED8);
1250c503f109Smrg    OUTREG(index_reg,0x30601);
1251c503f109Smrg    OUTREG(data_reg,0xBF508640);
1252c503f109Smrg    OUTREG(index_reg,0x30700);
1253c503f109Smrg    OUTREG(data_reg,0x8A60BEE8);
1254c503f109Smrg    OUTREG(index_reg,0x30701);
1255c503f109Smrg    OUTREG(data_reg,0xBF2087A0);
1256c503f109Smrg    OUTREG(index_reg,0x30800);
1257c503f109Smrg    OUTREG(data_reg,0x8900BF00);
1258c503f109Smrg    OUTREG(index_reg,0x30801);
1259c503f109Smrg    OUTREG(data_reg,0xBF008900);
1260b7e1c893Smrg}
1261b7e1c893Smrg
1262209ff23fSmrgstatic int
1263b7e1c893Smrgatombios_output_yuv_setup(xf86OutputPtr output, Bool enable)
1264209ff23fSmrg{
1265209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1266209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1267b7e1c893Smrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1268b7e1c893Smrg    ENABLE_YUV_PS_ALLOCATION disp_data;
1269209ff23fSmrg    AtomBiosArgRec data;
1270209ff23fSmrg    unsigned char *space;
1271b7e1c893Smrg    unsigned char *RADEONMMIO = info->MMIO;
1272b7e1c893Smrg    uint32_t temp, reg;
1273209ff23fSmrg
1274b7e1c893Smrg    if (info->ChipFamily >= CHIP_FAMILY_R600)
1275b7e1c893Smrg	reg = R600_BIOS_3_SCRATCH;
1276b7e1c893Smrg    else
1277b7e1c893Smrg	reg = RADEON_BIOS_3_SCRATCH;
1278b7e1c893Smrg
1279b7e1c893Smrg    //fix up scratch reg handling
1280b7e1c893Smrg    temp = INREG(reg);
1281b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1282b7e1c893Smrg	OUTREG(reg, (ATOM_S3_TV1_ACTIVE |
1283b7e1c893Smrg		     (radeon_crtc->crtc_id << 18)));
1284b7e1c893Smrg    else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1285b7e1c893Smrg	OUTREG(reg, (ATOM_S3_CV_ACTIVE |
1286b7e1c893Smrg		     (radeon_crtc->crtc_id << 24)));
1287b7e1c893Smrg    else
1288b7e1c893Smrg	OUTREG(reg, 0);
1289209ff23fSmrg
1290b7e1c893Smrg    memset(&disp_data, 0, sizeof(disp_data));
1291209ff23fSmrg
1292b7e1c893Smrg    if (enable)
1293b7e1c893Smrg	disp_data.ucEnable = ATOM_ENABLE;
1294b7e1c893Smrg    disp_data.ucCRTC = radeon_crtc->crtc_id;
1295209ff23fSmrg
1296b7e1c893Smrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableYUV);
1297209ff23fSmrg    data.exec.dataSpace = (void *)&space;
1298209ff23fSmrg    data.exec.pspace = &disp_data;
1299209ff23fSmrg
130068105dcbSveego    if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
1301b7e1c893Smrg
1302b7e1c893Smrg	OUTREG(reg, temp);
1303b7e1c893Smrg
1304042789b0Sveego/*	ErrorF("crtc %d YUV %s setup success\n", radeon_crtc->crtc_id, enable ? "enable" : "disable"); */
1305209ff23fSmrg	return ATOM_SUCCESS;
1306209ff23fSmrg    }
1307209ff23fSmrg
1308b7e1c893Smrg    OUTREG(reg, temp);
1309b7e1c893Smrg
1310b7e1c893Smrg    ErrorF("crtc %d YUV %s setup failed\n", radeon_crtc->crtc_id, enable ? "enable" : "disable");
1311209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
1312209ff23fSmrg
1313209ff23fSmrg}
1314209ff23fSmrg
1315209ff23fSmrgstatic int
1316b7e1c893Smrgatombios_output_overscan_setup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
1317209ff23fSmrg{
1318209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1319b7e1c893Smrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1320209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1321b7e1c893Smrg    SET_CRTC_OVERSCAN_PS_ALLOCATION overscan_param;
1322209ff23fSmrg    AtomBiosArgRec data;
1323209ff23fSmrg    unsigned char *space;
1324b7e1c893Smrg    memset(&overscan_param, 0, sizeof(overscan_param));
1325209ff23fSmrg
1326b7e1c893Smrg    overscan_param.usOverscanRight = 0;
1327b7e1c893Smrg    overscan_param.usOverscanLeft = 0;
1328b7e1c893Smrg    overscan_param.usOverscanBottom = 0;
1329b7e1c893Smrg    overscan_param.usOverscanTop = 0;
1330b7e1c893Smrg    overscan_param.ucCRTC = radeon_crtc->crtc_id;
1331b7e1c893Smrg
1332b7e1c893Smrg    if (radeon_output->Flags & RADEON_USE_RMX) {
1333b7e1c893Smrg	if (radeon_output->rmx_type == RMX_FULL) {
1334b7e1c893Smrg	    overscan_param.usOverscanRight = 0;
1335b7e1c893Smrg	    overscan_param.usOverscanLeft = 0;
1336b7e1c893Smrg	    overscan_param.usOverscanBottom = 0;
1337b7e1c893Smrg	    overscan_param.usOverscanTop = 0;
1338b7e1c893Smrg	} else if (radeon_output->rmx_type == RMX_CENTER) {
1339b7e1c893Smrg	    overscan_param.usOverscanTop = (adjusted_mode->CrtcVDisplay - mode->CrtcVDisplay) / 2;
1340b7e1c893Smrg	    overscan_param.usOverscanBottom = (adjusted_mode->CrtcVDisplay - mode->CrtcVDisplay) / 2;
1341b7e1c893Smrg	    overscan_param.usOverscanLeft = (adjusted_mode->CrtcHDisplay - mode->CrtcHDisplay) / 2;
1342b7e1c893Smrg	    overscan_param.usOverscanRight = (adjusted_mode->CrtcHDisplay - mode->CrtcHDisplay) / 2;
1343b7e1c893Smrg	} else if (radeon_output->rmx_type == RMX_ASPECT) {
1344b7e1c893Smrg	    int a1 = mode->CrtcVDisplay * adjusted_mode->CrtcHDisplay;
1345b7e1c893Smrg	    int a2 = adjusted_mode->CrtcVDisplay * mode->CrtcHDisplay;
1346b7e1c893Smrg
1347b7e1c893Smrg	    if (a1 > a2) {
1348b7e1c893Smrg		overscan_param.usOverscanLeft = (adjusted_mode->CrtcHDisplay - (a2 / mode->CrtcVDisplay)) / 2;
1349b7e1c893Smrg		overscan_param.usOverscanRight = (adjusted_mode->CrtcHDisplay - (a2 / mode->CrtcVDisplay)) / 2;
1350b7e1c893Smrg	    } else if (a2 > a1) {
1351b7e1c893Smrg		overscan_param.usOverscanLeft = (adjusted_mode->CrtcVDisplay - (a1 / mode->CrtcHDisplay)) / 2;
1352b7e1c893Smrg		overscan_param.usOverscanRight = (adjusted_mode->CrtcVDisplay - (a1 / mode->CrtcHDisplay)) / 2;
1353b7e1c893Smrg	    }
1354209ff23fSmrg	}
1355209ff23fSmrg    }
1356209ff23fSmrg
1357b7e1c893Smrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan);
1358209ff23fSmrg    data.exec.dataSpace = (void *)&space;
1359b7e1c893Smrg    data.exec.pspace = &overscan_param;
1360209ff23fSmrg
136168105dcbSveego    if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
1362042789b0Sveego/*	ErrorF("Set CRTC %d Overscan success\n", radeon_crtc->crtc_id); */
1363b7e1c893Smrg	return ATOM_SUCCESS ;
1364209ff23fSmrg    }
1365209ff23fSmrg
1366b7e1c893Smrg    ErrorF("Set CRTC %d Overscan failed\n", radeon_crtc->crtc_id);
1367209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
1368209ff23fSmrg}
1369209ff23fSmrg
1370209ff23fSmrgstatic int
1371b7e1c893Smrgatombios_output_scaler_setup(xf86OutputPtr output)
1372209ff23fSmrg{
1373209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1374209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1375b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
1376209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1377209ff23fSmrg    ENABLE_SCALER_PS_ALLOCATION disp_data;
1378209ff23fSmrg    AtomBiosArgRec data;
1379209ff23fSmrg    unsigned char *space;
1380209ff23fSmrg
1381b7e1c893Smrg    if (!IS_AVIVO_VARIANT && radeon_crtc->crtc_id)
1382b7e1c893Smrg	return ATOM_SUCCESS;
1383b7e1c893Smrg
1384b7e1c893Smrg    memset(&disp_data, 0, sizeof(disp_data));
1385b7e1c893Smrg
1386209ff23fSmrg    disp_data.ucScaler = radeon_crtc->crtc_id;
1387209ff23fSmrg
1388b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
1389b7e1c893Smrg	switch (tvout->tvStd) {
1390b7e1c893Smrg	case TV_STD_NTSC:
1391b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_NTSC;
1392b7e1c893Smrg	    break;
1393b7e1c893Smrg	case TV_STD_PAL:
1394b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_PAL;
1395b7e1c893Smrg	    break;
1396b7e1c893Smrg	case TV_STD_PAL_M:
1397b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_PALM;
1398b7e1c893Smrg	    break;
1399b7e1c893Smrg	case TV_STD_PAL_60:
1400b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_PAL60;
1401b7e1c893Smrg	    break;
1402b7e1c893Smrg	case TV_STD_NTSC_J:
1403b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_NTSCJ;
1404b7e1c893Smrg	    break;
1405b7e1c893Smrg	case TV_STD_SCART_PAL:
1406b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_PAL; /* ??? */
1407b7e1c893Smrg	    break;
1408b7e1c893Smrg	case TV_STD_SECAM:
1409b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_SECAM;
1410b7e1c893Smrg	    break;
1411b7e1c893Smrg	case TV_STD_PAL_CN:
1412b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_PALCN;
1413b7e1c893Smrg	    break;
1414b7e1c893Smrg	default:
1415b7e1c893Smrg	    disp_data.ucTVStandard = ATOM_TV_NTSC;
1416b7e1c893Smrg	    break;
1417b7e1c893Smrg	}
1418b7e1c893Smrg	disp_data.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
1419042789b0Sveego/*        ErrorF("Using TV scaler %x %x\n", disp_data.ucTVStandard, disp_data.ucEnable); */
1420b7e1c893Smrg    } else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) {
1421b7e1c893Smrg	disp_data.ucTVStandard = ATOM_TV_CV;
1422b7e1c893Smrg	disp_data.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
1423042789b0Sveego/*        ErrorF("Using CV scaler %x %x\n", disp_data.ucTVStandard, disp_data.ucEnable); */
1424b7e1c893Smrg    } else if (radeon_output->Flags & RADEON_USE_RMX) {
1425042789b0Sveego/*	ErrorF("Using RMX\n"); */
1426209ff23fSmrg	if (radeon_output->rmx_type == RMX_FULL)
1427209ff23fSmrg	    disp_data.ucEnable = ATOM_SCALER_EXPANSION;
1428209ff23fSmrg	else if (radeon_output->rmx_type == RMX_CENTER)
1429209ff23fSmrg	    disp_data.ucEnable = ATOM_SCALER_CENTER;
1430b7e1c893Smrg	else if (radeon_output->rmx_type == RMX_ASPECT)
1431b7e1c893Smrg	    disp_data.ucEnable = ATOM_SCALER_EXPANSION;
1432209ff23fSmrg    } else {
1433042789b0Sveego/*	ErrorF("Not using RMX\n"); */
1434b7e1c893Smrg	if (IS_AVIVO_VARIANT)
1435b7e1c893Smrg	    disp_data.ucEnable = ATOM_SCALER_DISABLE;
1436b7e1c893Smrg	else
1437b7e1c893Smrg	    disp_data.ucEnable = ATOM_SCALER_CENTER;
1438209ff23fSmrg    }
1439209ff23fSmrg
1440209ff23fSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
1441209ff23fSmrg    data.exec.dataSpace = (void *)&space;
1442209ff23fSmrg    data.exec.pspace = &disp_data;
1443209ff23fSmrg
144468105dcbSveego    if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
1445b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)
1446b7e1c893Smrg	    && info->ChipFamily >= CHIP_FAMILY_RV515 && info->ChipFamily <= CHIP_FAMILY_RV570) {
1447042789b0Sveego/*	    ErrorF("forcing TV scaler\n"); */
1448c503f109Smrg	    atom_rv515_force_tv_scaler(output->scrn, radeon_crtc);
1449b7e1c893Smrg	}
1450042789b0Sveego/*	ErrorF("scaler %d setup success\n", radeon_crtc->crtc_id); */
1451209ff23fSmrg	return ATOM_SUCCESS;
1452209ff23fSmrg    }
1453209ff23fSmrg
1454209ff23fSmrg    ErrorF("scaler %d setup failed\n", radeon_crtc->crtc_id);
1455209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
1456209ff23fSmrg
1457209ff23fSmrg}
1458209ff23fSmrg
1459b7e1c893Smrgvoid
1460b7e1c893Smrgatombios_output_dpms(xf86OutputPtr output, int mode)
1461209ff23fSmrg{
1462b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1463b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
1464209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1465209ff23fSmrg    DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION disp_data;
1466209ff23fSmrg    AtomBiosArgRec data;
1467209ff23fSmrg    unsigned char *space;
1468209ff23fSmrg    int index = 0;
1469b7e1c893Smrg    Bool is_dig = FALSE;
147040732134Srjs    unsigned char *RADEONMMIO = info->MMIO;
147140732134Srjs    uint32_t reg = 0;
1472209ff23fSmrg
1473b7e1c893Smrg    if (radeon_encoder == NULL)
1474b7e1c893Smrg        return;
1475b7e1c893Smrg
1476b7e1c893Smrg    switch (radeon_encoder->encoder_id) {
1477b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1478b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
1479209ff23fSmrg	index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl);
1480209ff23fSmrg	break;
1481b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1482b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1483b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1484b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1485b7e1c893Smrg	is_dig = TRUE;
1486209ff23fSmrg	break;
1487b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1488b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DDI:
1489b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
1490b7e1c893Smrg	index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
1491209ff23fSmrg	break;
1492b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
1493209ff23fSmrg	index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
1494209ff23fSmrg	break;
1495b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1496b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT))
1497b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
1498b7e1c893Smrg	else
1499b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl);
1500209ff23fSmrg	break;
1501b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
1502b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1503ad43ddacSmrg	if (IS_DCE32_VARIANT)
1504b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl);
1505ad43ddacSmrg	else {
1506ad43ddacSmrg	    if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1507ad43ddacSmrg		index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
1508ad43ddacSmrg	    else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1509ad43ddacSmrg		index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
1510ad43ddacSmrg	    else
1511ad43ddacSmrg		index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl);
1512ad43ddacSmrg	}
1513209ff23fSmrg	break;
1514b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1515b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1516ad43ddacSmrg	if (IS_DCE32_VARIANT)
1517b7e1c893Smrg	    index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl);
1518ad43ddacSmrg	else {
1519ad43ddacSmrg	    if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1520ad43ddacSmrg		index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
1521ad43ddacSmrg	    else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
1522ad43ddacSmrg		index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
1523ad43ddacSmrg	    else
1524ad43ddacSmrg		index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl);
1525ad43ddacSmrg	}
1526209ff23fSmrg	break;
1527209ff23fSmrg    }
1528209ff23fSmrg
1529209ff23fSmrg    switch (mode) {
1530209ff23fSmrg    case DPMSModeOn:
1531b7e1c893Smrg	radeon_encoder->devices |= radeon_output->active_device;
1532ad43ddacSmrg	if (is_dig) {
1533921a55d8Smrg	    atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0);
1534ad43ddacSmrg	    if (((radeon_output->ConnectorType == CONNECTOR_DISPLAY_PORT) ||
1535ad43ddacSmrg		 (radeon_output->ConnectorType == CONNECTOR_EDP)) &&
1536ad43ddacSmrg		(radeon_output->MonType == MT_DP)) {
1537ad43ddacSmrg		do_displayport_link_train(output);
1538ad43ddacSmrg		if (IS_DCE4_VARIANT)
15390974d292Smrg		    atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_VIDEO_ON);
1540ad43ddacSmrg	    }
1541ad43ddacSmrg	}
1542b7e1c893Smrg	else {
1543b7e1c893Smrg	    disp_data.ucAction = ATOM_ENABLE;
1544b7e1c893Smrg	    data.exec.index = index;
1545b7e1c893Smrg	    data.exec.dataSpace = (void *)&space;
1546b7e1c893Smrg	    data.exec.pspace = &disp_data;
1547b7e1c893Smrg
154840732134Srjs	    /* workaround for DVOOutputControl on some RS690 systems */
154940732134Srjs	    if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DDI) {
155040732134Srjs		reg = INREG(RADEON_BIOS_3_SCRATCH);
155140732134Srjs		OUTREG(RADEON_BIOS_3_SCRATCH, reg & ~ATOM_S3_DFP2I_ACTIVE);
155240732134Srjs	    }
1553042789b0Sveego	    if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) != ATOM_SUCCESS)
1554042789b0Sveego/*
1555b7e1c893Smrg		ErrorF("Output %s enable success\n",
1556b7e1c893Smrg		       device_name[radeon_get_device_index(radeon_output->active_device)]);
1557b7e1c893Smrg	    else
1558042789b0Sveego*/
1559b7e1c893Smrg		ErrorF("Output %s enable failed\n",
1560b7e1c893Smrg		       device_name[radeon_get_device_index(radeon_output->active_device)]);
156140732134Srjs	    if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DDI)
156240732134Srjs		OUTREG(RADEON_BIOS_3_SCRATCH, reg);
1563b7e1c893Smrg	}
1564c503f109Smrg	/* at least for TV atom fails to reassociate the correct crtc source at dpms on */
1565c503f109Smrg	if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
1566c503f109Smrg		atombios_set_output_crtc_source(output);
1567209ff23fSmrg	break;
1568209ff23fSmrg    case DPMSModeStandby:
1569209ff23fSmrg    case DPMSModeSuspend:
1570209ff23fSmrg    case DPMSModeOff:
1571b7e1c893Smrg	radeon_encoder->devices &= ~(radeon_output->active_device);
1572b7e1c893Smrg	if (!radeon_encoder->devices) {
1573ad43ddacSmrg	    if (is_dig) {
1574921a55d8Smrg		atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0);
1575ad43ddacSmrg		if (((radeon_output->ConnectorType == CONNECTOR_DISPLAY_PORT) ||
1576ad43ddacSmrg		     (radeon_output->ConnectorType == CONNECTOR_EDP)) &&
1577ad43ddacSmrg		    (radeon_output->MonType == MT_DP)) {
1578ad43ddacSmrg		    if (IS_DCE4_VARIANT)
15790974d292Smrg			atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_VIDEO_OFF);
1580ad43ddacSmrg		}
1581ad43ddacSmrg	    } else {
1582b7e1c893Smrg		disp_data.ucAction = ATOM_DISABLE;
1583b7e1c893Smrg		data.exec.index = index;
1584b7e1c893Smrg		data.exec.dataSpace = (void *)&space;
1585b7e1c893Smrg		data.exec.pspace = &disp_data;
1586b7e1c893Smrg
158768105dcbSveego		if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data)
1588042789b0Sveego		    != ATOM_SUCCESS)
1589042789b0Sveego/*
1590b7e1c893Smrg		    ErrorF("Output %s disable success\n",
1591b7e1c893Smrg			   device_name[radeon_get_device_index(radeon_output->active_device)]);
1592b7e1c893Smrg		else
1593042789b0Sveego*/
1594b7e1c893Smrg		    ErrorF("Output %s disable failed\n",
1595b7e1c893Smrg			   device_name[radeon_get_device_index(radeon_output->active_device)]);
1596b7e1c893Smrg	    }
1597209ff23fSmrg	}
1598b7e1c893Smrg	break;
1599209ff23fSmrg    }
1600209ff23fSmrg}
1601209ff23fSmrg
16020974d292Smrgunion crtc_source_param {
16030974d292Smrg    SELECT_CRTC_SOURCE_PS_ALLOCATION v1;
16040974d292Smrg    SELECT_CRTC_SOURCE_PARAMETERS_V2 v2;
16050974d292Smrg};
16060974d292Smrg
16070974d292Smrgvoid
1608209ff23fSmrgatombios_set_output_crtc_source(xf86OutputPtr output)
1609209ff23fSmrg{
1610209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1611209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1612209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1613b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
1614209ff23fSmrg    AtomBiosArgRec data;
1615209ff23fSmrg    unsigned char *space;
16160974d292Smrg    union crtc_source_param args;
1617209ff23fSmrg    int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source);
1618209ff23fSmrg    int major, minor;
1619209ff23fSmrg
1620b7e1c893Smrg    if (radeon_encoder == NULL)
1621b7e1c893Smrg	return;
1622b7e1c893Smrg
16230974d292Smrg    memset(&args, 0, sizeof(args));
16240974d292Smrg
1625209ff23fSmrg    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
1626209ff23fSmrg
1627209ff23fSmrg    /*ErrorF("select crtc source table is %d %d\n", major, minor);*/
1628209ff23fSmrg
1629209ff23fSmrg    switch(major) {
1630b7e1c893Smrg    case 1:
1631209ff23fSmrg	switch(minor) {
1632209ff23fSmrg	case 0:
1633209ff23fSmrg	case 1:
1634209ff23fSmrg	default:
1635b7e1c893Smrg	    if (IS_AVIVO_VARIANT)
16360974d292Smrg		args.v1.ucCRTC = radeon_crtc->crtc_id;
1637b7e1c893Smrg	    else {
1638b7e1c893Smrg		if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1)
16390974d292Smrg		    args.v1.ucCRTC = radeon_crtc->crtc_id;
1640b7e1c893Smrg		else
16410974d292Smrg		    args.v1.ucCRTC = radeon_crtc->crtc_id << 2;
1642b7e1c893Smrg	    }
1643b7e1c893Smrg	    switch (radeon_encoder->encoder_id) {
1644b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1645b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
16460974d292Smrg		args.v1.ucDevice = ATOM_DEVICE_DFP1_INDEX;
1647b7e1c893Smrg		break;
1648b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
1649b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1650b7e1c893Smrg		if (radeon_output->active_device & ATOM_DEVICE_LCD1_SUPPORT)
16510974d292Smrg		    args.v1.ucDevice = ATOM_DEVICE_LCD1_INDEX;
1652b7e1c893Smrg		else
16530974d292Smrg		    args.v1.ucDevice = ATOM_DEVICE_DFP3_INDEX;
1654b7e1c893Smrg		break;
1655b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1656b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DDI:
1657b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
16580974d292Smrg		args.v1.ucDevice = ATOM_DEVICE_DFP2_INDEX;
1659b7e1c893Smrg		break;
1660b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
1661b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1662b7e1c893Smrg		if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
16630974d292Smrg		    args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX;
1664b7e1c893Smrg		else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
16650974d292Smrg		    args.v1.ucDevice = ATOM_DEVICE_CV_INDEX;
1666b7e1c893Smrg		else
16670974d292Smrg		    args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX;
1668b7e1c893Smrg		break;
1669b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1670b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1671b7e1c893Smrg		if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
16720974d292Smrg		    args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX;
1673b7e1c893Smrg		else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
16740974d292Smrg		    args.v1.ucDevice = ATOM_DEVICE_CV_INDEX;
1675b7e1c893Smrg		else
16760974d292Smrg		    args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX;
1677b7e1c893Smrg		break;
1678209ff23fSmrg	    }
16790974d292Smrg	    /*ErrorF("device sourced: 0x%x\n", args.v1.ucDevice);*/
1680209ff23fSmrg	    break;
1681209ff23fSmrg	case 2:
16820974d292Smrg	    args.v2.ucCRTC = radeon_crtc->crtc_id;
16830974d292Smrg	    args.v2.ucEncodeMode = atombios_get_encoder_mode(output);
1684b7e1c893Smrg	    switch (radeon_encoder->encoder_id) {
1685b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1686b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1687b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1688b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1689ad43ddacSmrg 		switch (radeon_output->dig_encoder) {
1690ad43ddacSmrg 		case 0:
16910974d292Smrg 		    args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
1692ad43ddacSmrg 		    break;
1693ad43ddacSmrg 		case 1:
16940974d292Smrg 		    args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
1695ad43ddacSmrg 		    break;
1696ad43ddacSmrg 		case 2:
16970974d292Smrg 		    args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID;
1698ad43ddacSmrg 		    break;
1699ad43ddacSmrg 		case 3:
17000974d292Smrg 		    args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID;
1701ad43ddacSmrg 		    break;
1702ad43ddacSmrg 		case 4:
17030974d292Smrg 		    args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID;
1704ad43ddacSmrg 		    break;
1705ad43ddacSmrg 		case 5:
17060974d292Smrg 		    args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID;
1707ad43ddacSmrg 		    break;
1708ad43ddacSmrg 		}
1709b7e1c893Smrg		break;
17100974d292Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
17110974d292Smrg		args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID;
17120974d292Smrg		break;
1713b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1714b7e1c893Smrg		if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
17150974d292Smrg		    args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1716b7e1c893Smrg		else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
17170974d292Smrg		    args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1718b7e1c893Smrg		else
17190974d292Smrg		    args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID;
1720b7e1c893Smrg		break;
1721b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1722b7e1c893Smrg		if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT))
17230974d292Smrg		    args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1724b7e1c893Smrg		else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT))
17250974d292Smrg		    args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1726b7e1c893Smrg		else
17270974d292Smrg		    args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID;
1728b7e1c893Smrg		break;
1729209ff23fSmrg	    }
17300974d292Smrg	    /*ErrorF("device sourced: 0x%x\n", args.v2.ucEncoderID);*/
1731209ff23fSmrg	    break;
1732209ff23fSmrg	}
1733209ff23fSmrg	break;
1734209ff23fSmrg    default:
1735b7e1c893Smrg	ErrorF("Unknown table version\n");
1736b7e1c893Smrg	exit(-1);
1737209ff23fSmrg    }
1738209ff23fSmrg
17390974d292Smrg    data.exec.pspace = &args;
1740209ff23fSmrg    data.exec.index = index;
1741209ff23fSmrg    data.exec.dataSpace = (void *)&space;
1742209ff23fSmrg
174368105dcbSveego    if (RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
1744042789b0Sveego/*	ErrorF("Set CRTC %d Source success\n", radeon_crtc->crtc_id); */
1745209ff23fSmrg	return;
1746209ff23fSmrg    }
1747209ff23fSmrg
1748209ff23fSmrg    ErrorF("Set CRTC Source failed\n");
1749209ff23fSmrg    return;
1750209ff23fSmrg}
1751209ff23fSmrg
1752b7e1c893Smrgstatic void
1753b7e1c893Smrgatombios_apply_output_quirks(xf86OutputPtr output, DisplayModePtr mode)
1754b7e1c893Smrg{
1755b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1756b7e1c893Smrg    RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1757b7e1c893Smrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1758b7e1c893Smrg    unsigned char *RADEONMMIO = info->MMIO;
1759b7e1c893Smrg
1760b7e1c893Smrg    /* Funky macbooks */
1761b7e1c893Smrg    if ((info->Chipset == PCI_CHIP_RV530_71C5) &&
1762b7e1c893Smrg	(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x106b) &&
1763b7e1c893Smrg	(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x0080)) {
1764b7e1c893Smrg	if (radeon_output->MonType == MT_LCD) {
1765b7e1c893Smrg	    if (radeon_output->devices & ATOM_DEVICE_LCD1_SUPPORT) {
1766b7e1c893Smrg		uint32_t lvtma_bit_depth_control = INREG(AVIVO_LVTMA_BIT_DEPTH_CONTROL);
1767b7e1c893Smrg
1768b7e1c893Smrg		lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN;
1769b7e1c893Smrg		lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN;
1770b7e1c893Smrg
1771b7e1c893Smrg		OUTREG(AVIVO_LVTMA_BIT_DEPTH_CONTROL, lvtma_bit_depth_control);
1772b7e1c893Smrg	    }
1773b7e1c893Smrg	}
1774b7e1c893Smrg    }
1775b7e1c893Smrg
1776b7e1c893Smrg    /* set scaler clears this on some chips */
1777ad43ddacSmrg    if (!(radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT))) {
1778ad43ddacSmrg	if (IS_AVIVO_VARIANT && (mode->Flags & V_INTERLACE))
1779ad43ddacSmrg	    OUTREG(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, AVIVO_D1MODE_INTERLEAVE_EN);
1780ad43ddacSmrg    }
1781ad43ddacSmrg
1782ad43ddacSmrg    if (IS_DCE32_VARIANT &&
1783ad43ddacSmrg	(!IS_DCE4_VARIANT) &&
1784ad43ddacSmrg	(radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT))) {
1785ad43ddacSmrg	radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
1786ad43ddacSmrg	if (radeon_encoder == NULL)
1787ad43ddacSmrg	    return;
1788ad43ddacSmrg	/* XXX: need to sort out why transmitter control table sometimes sets this to a
1789ad43ddacSmrg	 * different golden value.
1790ad43ddacSmrg	 */
1791ad43ddacSmrg	if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY2) {
1792ad43ddacSmrg	    OUTREG(0x7ec4, 0x00824002);
1793ad43ddacSmrg	}
1794ad43ddacSmrg    }
1795b7e1c893Smrg}
1796b7e1c893Smrg
1797b13dfe66Smrgvoid
1798ad43ddacSmrgatombios_pick_dig_encoder(xf86OutputPtr output)
1799ad43ddacSmrg{
1800ad43ddacSmrg    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(output->scrn);
1801ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1802ad43ddacSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1803ad43ddacSmrg    radeon_encoder_ptr radeon_encoder = NULL;
1804ad43ddacSmrg    Bool is_lvtma = FALSE;
1805ad43ddacSmrg    int i, mode;
1806ad43ddacSmrg    uint32_t dig_enc_use_mask = 0;
1807ad43ddacSmrg
1808ad43ddacSmrg    /* non digital encoders don't need a dig block */
1809ad43ddacSmrg    mode = atombios_get_encoder_mode(output);
1810ad43ddacSmrg    if (mode == ATOM_ENCODER_MODE_CRT ||
1811ad43ddacSmrg        mode == ATOM_ENCODER_MODE_TV ||
1812ad43ddacSmrg        mode == ATOM_ENCODER_MODE_CV)
1813ad43ddacSmrg        return;
1814ad43ddacSmrg
1815ad43ddacSmrg    if (IS_DCE4_VARIANT) {
1816ad43ddacSmrg        radeon_encoder = radeon_get_encoder(output);
1817ad43ddacSmrg
1818921a55d8Smrg	if (IS_DCE41_VARIANT) {
1819ad43ddacSmrg	    if (radeon_output->linkb)
1820ad43ddacSmrg		radeon_output->dig_encoder = 1;
1821ad43ddacSmrg	    else
1822ad43ddacSmrg		radeon_output->dig_encoder = 0;
1823921a55d8Smrg	} else {
1824921a55d8Smrg	    switch (radeon_encoder->encoder_id) {
1825921a55d8Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1826921a55d8Smrg		if (radeon_output->linkb)
1827921a55d8Smrg		    radeon_output->dig_encoder = 1;
1828921a55d8Smrg		else
1829921a55d8Smrg		    radeon_output->dig_encoder = 0;
1830921a55d8Smrg		break;
1831921a55d8Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1832921a55d8Smrg		if (radeon_output->linkb)
1833921a55d8Smrg		    radeon_output->dig_encoder = 3;
1834921a55d8Smrg		else
1835921a55d8Smrg		    radeon_output->dig_encoder = 2;
1836921a55d8Smrg		break;
1837921a55d8Smrg	    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1838921a55d8Smrg		if (radeon_output->linkb)
1839921a55d8Smrg		    radeon_output->dig_encoder = 5;
1840921a55d8Smrg		else
1841921a55d8Smrg		    radeon_output->dig_encoder = 4;
1842921a55d8Smrg		break;
1843921a55d8Smrg	    default:
1844921a55d8Smrg		ErrorF("Unknown encoder\n");
1845921a55d8Smrg		break;
1846921a55d8Smrg	    }
1847ad43ddacSmrg	}
1848ad43ddacSmrg	return;
1849ad43ddacSmrg    }
1850ad43ddacSmrg
1851ad43ddacSmrg    if (IS_DCE32_VARIANT) {
1852ad43ddacSmrg        RADEONCrtcPrivatePtr radeon_crtc = output->crtc->driver_private;
1853ad43ddacSmrg        radeon_output->dig_encoder = radeon_crtc->crtc_id;
1854ad43ddacSmrg        return;
1855ad43ddacSmrg    }
1856ad43ddacSmrg
1857ad43ddacSmrg    for (i = 0; i < xf86_config->num_output; i++) {
1858ad43ddacSmrg        xf86OutputPtr test = xf86_config->output[i];
1859ad43ddacSmrg        RADEONOutputPrivatePtr radeon_test = test->driver_private;
1860ad43ddacSmrg        radeon_encoder = radeon_get_encoder(test);
1861ad43ddacSmrg
1862ad43ddacSmrg        if (!radeon_encoder || !test->crtc)
1863ad43ddacSmrg            continue;
1864ad43ddacSmrg
1865ad43ddacSmrg        if (output == test && radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA)
1866ad43ddacSmrg            is_lvtma = TRUE;
1867ad43ddacSmrg        if (output != test && (radeon_test->dig_encoder >= 0))
1868ad43ddacSmrg            dig_enc_use_mask |= (1 << radeon_test->dig_encoder);
1869ad43ddacSmrg
1870ad43ddacSmrg    }
1871ad43ddacSmrg    if (is_lvtma) {
1872ad43ddacSmrg        if (dig_enc_use_mask & 0x2)
1873ad43ddacSmrg            ErrorF("Need digital encoder 2 for LVTMA and it isn't free - stealing\n");
1874ad43ddacSmrg        radeon_output->dig_encoder = 1;
1875ad43ddacSmrg        return;
1876ad43ddacSmrg    }
1877ad43ddacSmrg    if (!(dig_enc_use_mask & 1))
1878ad43ddacSmrg        radeon_output->dig_encoder = 0;
1879ad43ddacSmrg    else
1880ad43ddacSmrg        radeon_output->dig_encoder = 1;
1881ad43ddacSmrg}
1882209ff23fSmrgvoid
1883209ff23fSmrgatombios_output_mode_set(xf86OutputPtr output,
1884209ff23fSmrg			 DisplayModePtr mode,
1885209ff23fSmrg			 DisplayModePtr adjusted_mode)
1886209ff23fSmrg{
1887209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1888b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
1889209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1890b7e1c893Smrg    if (radeon_encoder == NULL)
1891ad43ddacSmrg	return;
1892209ff23fSmrg
1893b7e1c893Smrg    radeon_output->pixel_clock = adjusted_mode->Clock;
1894b7e1c893Smrg    atombios_output_overscan_setup(output, mode, adjusted_mode);
1895b7e1c893Smrg    atombios_output_scaler_setup(output);
1896209ff23fSmrg    atombios_set_output_crtc_source(output);
1897209ff23fSmrg
18980974d292Smrg    if (IS_AVIVO_VARIANT && !IS_DCE4_VARIANT) {
1899b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT))
1900b7e1c893Smrg	    atombios_output_yuv_setup(output, TRUE);
1901b7e1c893Smrg	else
1902b7e1c893Smrg	    atombios_output_yuv_setup(output, FALSE);
1903209ff23fSmrg    }
1904209ff23fSmrg
1905b7e1c893Smrg    switch (radeon_encoder->encoder_id) {
1906b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1907b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
1908b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
1909b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1910b7e1c893Smrg	atombios_output_digital_setup(output, PANEL_ENCODER_ACTION_ENABLE);
1911b7e1c893Smrg	break;
1912b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1913b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1914b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1915b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1916b7e1c893Smrg	/* disable encoder and transmitter */
1917b7e1c893Smrg	/* setup and enable the encoder and transmitter */
19180974d292Smrg	if (IS_DCE4_VARIANT) {
19190974d292Smrg	    atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
19200974d292Smrg	    atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_SETUP);
19210974d292Smrg	    atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
19220974d292Smrg	    atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
19230974d292Smrg	} else {
19240974d292Smrg	    atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
1925ad43ddacSmrg	    atombios_output_dig_encoder_setup(output, ATOM_DISABLE);
1926ad43ddacSmrg	    atombios_output_dig_encoder_setup(output, ATOM_ENABLE);
19270974d292Smrg
19280974d292Smrg	    atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
19290974d292Smrg	    atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0);
19300974d292Smrg	    atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
1931ad43ddacSmrg	}
1932b7e1c893Smrg	break;
1933b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DDI:
1934b7e1c893Smrg	atombios_output_ddia_setup(output, ATOM_ENABLE);
1935b7e1c893Smrg	break;
1936b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1937b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
1938b7e1c893Smrg	atombios_external_tmds_setup(output, ATOM_ENABLE);
1939b7e1c893Smrg	break;
1940b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
1941b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1942b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1943b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1944b7e1c893Smrg	atombios_output_dac_setup(output, ATOM_ENABLE);
19452f39173dSmrg	if (radeon_output->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) {
19462f39173dSmrg		if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))
19472f39173dSmrg			atombios_output_tv_setup(output, ATOM_ENABLE);
19482f39173dSmrg		else
19492f39173dSmrg			atombios_output_tv_setup(output, ATOM_DISABLE);
19502f39173dSmrg	}
1951b7e1c893Smrg	break;
1952b7e1c893Smrg    }
1953b7e1c893Smrg    atombios_apply_output_quirks(output, adjusted_mode);
1954209ff23fSmrg}
1955209ff23fSmrg
1956209ff23fSmrgstatic AtomBiosResult
1957209ff23fSmrgatom_bios_dac_load_detect(atomBiosHandlePtr atomBIOS, xf86OutputPtr output)
1958209ff23fSmrg{
1959209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1960209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
1961209ff23fSmrg    DAC_LOAD_DETECTION_PS_ALLOCATION dac_data;
1962209ff23fSmrg    AtomBiosArgRec data;
1963209ff23fSmrg    unsigned char *space;
1964b7e1c893Smrg    int major, minor;
1965b7e1c893Smrg    int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection);
1966b7e1c893Smrg
1967b7e1c893Smrg    atombios_get_command_table_version(info->atomBIOS, index, &major, &minor);
1968209ff23fSmrg
1969209ff23fSmrg    dac_data.sDacload.ucMisc = 0;
1970209ff23fSmrg
1971209ff23fSmrg    if (radeon_output->devices & ATOM_DEVICE_CRT1_SUPPORT) {
1972b7e1c893Smrg	dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT);
1973b7e1c893Smrg	if (info->encoders[ATOM_DEVICE_CRT1_INDEX] &&
1974b7e1c893Smrg	    ((info->encoders[ATOM_DEVICE_CRT1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
1975b7e1c893Smrg	     (info->encoders[ATOM_DEVICE_CRT1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)))
1976209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_A;
1977b7e1c893Smrg	else
1978209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_B;
1979209ff23fSmrg    } else if (radeon_output->devices & ATOM_DEVICE_CRT2_SUPPORT) {
1980b7e1c893Smrg	dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT);
1981b7e1c893Smrg	if (info->encoders[ATOM_DEVICE_CRT2_INDEX] &&
1982b7e1c893Smrg	    ((info->encoders[ATOM_DEVICE_CRT2_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
1983b7e1c893Smrg	     (info->encoders[ATOM_DEVICE_CRT2_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)))
1984209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_A;
1985b7e1c893Smrg	else
1986209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_B;
1987209ff23fSmrg    } else if (radeon_output->devices & ATOM_DEVICE_CV_SUPPORT) {
1988b7e1c893Smrg	dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT);
1989b7e1c893Smrg	if (info->encoders[ATOM_DEVICE_CV_INDEX] &&
1990b7e1c893Smrg	    ((info->encoders[ATOM_DEVICE_CV_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
1991b7e1c893Smrg	     (info->encoders[ATOM_DEVICE_CV_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)))
1992209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_A;
1993b7e1c893Smrg	else
1994209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_B;
1995b7e1c893Smrg	if (minor >= 3)
1996b7e1c893Smrg	    dac_data.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
1997209ff23fSmrg    } else if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) {
1998b7e1c893Smrg	dac_data.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT);
1999b7e1c893Smrg	if (info->encoders[ATOM_DEVICE_TV1_INDEX] &&
2000b7e1c893Smrg	    ((info->encoders[ATOM_DEVICE_TV1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
2001b7e1c893Smrg	     (info->encoders[ATOM_DEVICE_TV1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)))
2002209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_A;
2003b7e1c893Smrg	else
2004209ff23fSmrg	    dac_data.sDacload.ucDacType = ATOM_DAC_B;
2005b7e1c893Smrg	if (minor >= 3)
2006b7e1c893Smrg	    dac_data.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
2007b7e1c893Smrg    } else
2008209ff23fSmrg	return ATOM_NOT_IMPLEMENTED;
2009209ff23fSmrg
2010b7e1c893Smrg    data.exec.index = index;
2011209ff23fSmrg    data.exec.dataSpace = (void *)&space;
2012209ff23fSmrg    data.exec.pspace = &dac_data;
2013209ff23fSmrg
201468105dcbSveego    if (RHDAtomBiosFunc(atomBIOS->pScrn, atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
2015042789b0Sveego/*	ErrorF("Dac detection success\n"); */
2016209ff23fSmrg	return ATOM_SUCCESS ;
2017209ff23fSmrg    }
2018209ff23fSmrg
2019209ff23fSmrg    ErrorF("DAC detection failed\n");
2020209ff23fSmrg    return ATOM_NOT_IMPLEMENTED;
2021209ff23fSmrg}
2022209ff23fSmrg
2023209ff23fSmrgRADEONMonitorType
2024b7e1c893Smrgatombios_dac_detect(xf86OutputPtr output)
2025209ff23fSmrg{
2026b7e1c893Smrg    ScrnInfoPtr pScrn = output->scrn;
2027209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
2028209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
2029209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2030209ff23fSmrg    RADEONMonitorType MonType = MT_NONE;
2031209ff23fSmrg    AtomBiosResult ret;
2032c503f109Smrg    RADEONSavePtr save = info->ModeReg;
2033209ff23fSmrg
2034b7e1c893Smrg    if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) {
2035209ff23fSmrg	if (xf86ReturnOptValBool(info->Options, OPTION_FORCE_TVOUT, FALSE)) {
2036b7e1c893Smrg	    if (radeon_output->ConnectorType == CONNECTOR_STV)
2037209ff23fSmrg		return MT_STV;
2038209ff23fSmrg	    else
2039209ff23fSmrg		return MT_CTV;
2040209ff23fSmrg	}
2041209ff23fSmrg    }
2042209ff23fSmrg
2043209ff23fSmrg    ret = atom_bios_dac_load_detect(info->atomBIOS, output);
2044209ff23fSmrg    if (ret == ATOM_SUCCESS) {
2045209ff23fSmrg	if (info->ChipFamily >= CHIP_FAMILY_R600)
2046c503f109Smrg	    save->bios_0_scratch = INREG(R600_BIOS_0_SCRATCH);
2047209ff23fSmrg	else
2048c503f109Smrg	    save->bios_0_scratch = INREG(RADEON_BIOS_0_SCRATCH);
2049c503f109Smrg	/*ErrorF("DAC connect %08X\n", (unsigned int)save->bios_0_scratch);*/
2050209ff23fSmrg
2051209ff23fSmrg	if (radeon_output->devices & ATOM_DEVICE_CRT1_SUPPORT) {
2052c503f109Smrg	    if (save->bios_0_scratch & ATOM_S0_CRT1_MASK)
2053209ff23fSmrg		MonType = MT_CRT;
2054209ff23fSmrg	} else if (radeon_output->devices & ATOM_DEVICE_CRT2_SUPPORT) {
2055c503f109Smrg	    if (save->bios_0_scratch & ATOM_S0_CRT2_MASK)
2056209ff23fSmrg		MonType = MT_CRT;
2057209ff23fSmrg	} else if (radeon_output->devices & ATOM_DEVICE_CV_SUPPORT) {
2058c503f109Smrg	    if (save->bios_0_scratch & (ATOM_S0_CV_MASK | ATOM_S0_CV_MASK_A))
2059209ff23fSmrg		MonType = MT_CV;
2060209ff23fSmrg	} else if (radeon_output->devices & ATOM_DEVICE_TV1_SUPPORT) {
2061c503f109Smrg	    if (save->bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A))
2062209ff23fSmrg		MonType = MT_CTV;
2063c503f109Smrg	    else if (save->bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A))
2064209ff23fSmrg		MonType = MT_STV;
2065209ff23fSmrg	}
2066209ff23fSmrg    }
2067209ff23fSmrg
2068209ff23fSmrg    return MonType;
2069209ff23fSmrg}
2070209ff23fSmrg
2071ad43ddacSmrg
2072ad43ddacSmrgstatic inline int atom_dp_get_encoder_id(xf86OutputPtr output)
2073ad43ddacSmrg{
2074ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2075ad43ddacSmrg    int ret = 0;
2076ad43ddacSmrg    if (radeon_output->dig_encoder)
2077ad43ddacSmrg        ret |= ATOM_DP_CONFIG_DIG2_ENCODER;
2078ad43ddacSmrg    else
2079ad43ddacSmrg        ret |= ATOM_DP_CONFIG_DIG1_ENCODER;
2080ad43ddacSmrg    if (radeon_output->linkb)
2081ad43ddacSmrg        ret |= ATOM_DP_CONFIG_LINK_B;
2082ad43ddacSmrg    else
2083ad43ddacSmrg        ret |= ATOM_DP_CONFIG_LINK_A;
2084ad43ddacSmrg    return ret;
2085ad43ddacSmrg}
2086ad43ddacSmrg
2087ad43ddacSmrgunion aux_channel_transaction {
2088ad43ddacSmrg    PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
2089ad43ddacSmrg    PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
2090ad43ddacSmrg};
2091ad43ddacSmrg
2092ad43ddacSmrgBool
2093ad43ddacSmrgRADEONProcessAuxCH(xf86OutputPtr output, uint8_t *req_bytes, uint8_t num_bytes,
2094ad43ddacSmrg		   uint8_t *read_byte, uint8_t read_buf_len, uint8_t delay)
2095ad43ddacSmrg{
2096ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2097ad43ddacSmrg    RADEONInfoPtr info       = RADEONPTR(output->scrn);
2098ad43ddacSmrg    union aux_channel_transaction args;
2099ad43ddacSmrg    AtomBiosArgRec data;
2100ad43ddacSmrg    unsigned char *space;
2101ad43ddacSmrg    unsigned char *base;
21020974d292Smrg    int retry_count = 0;
2103ad43ddacSmrg
2104ad43ddacSmrg    memset(&args, 0, sizeof(args));
2105ad43ddacSmrg    if (info->atomBIOS->fbBase)
2106ad43ddacSmrg	base = info->FB + info->atomBIOS->fbBase;
2107ad43ddacSmrg    else if (info->atomBIOS->scratchBase)
2108ad43ddacSmrg	base = (unsigned char *)info->atomBIOS->scratchBase;
2109ad43ddacSmrg    else
2110ad43ddacSmrg	return FALSE;
2111ad43ddacSmrg
21120974d292Smrgretry:
2113ad43ddacSmrg    memcpy(base, req_bytes, num_bytes);
2114ad43ddacSmrg
2115ad43ddacSmrg    args.v1.lpAuxRequest = 0;
2116ad43ddacSmrg    args.v1.lpDataOut = 16;
2117ad43ddacSmrg    args.v1.ucDataOutLen = 0;
2118ad43ddacSmrg    args.v1.ucChannelID = radeon_output->ucI2cId;
2119ad43ddacSmrg    args.v1.ucDelay = delay / 10; /* 10 usec */
2120ad43ddacSmrg    if (IS_DCE4_VARIANT)
2121ad43ddacSmrg	args.v2.ucHPD_ID = radeon_output->hpd_id;
2122ad43ddacSmrg
2123ad43ddacSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
2124ad43ddacSmrg    data.exec.dataSpace = (void *)&space;
2125ad43ddacSmrg    data.exec.pspace = &args;
2126ad43ddacSmrg
212768105dcbSveego    RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data);
21280974d292Smrg    if (args.v1.ucReplyStatus && !args.v1.ucDataOutLen) {
21290974d292Smrg	if (args.v1.ucReplyStatus == 0x20 && retry_count++ < 10)
21300974d292Smrg		goto retry;
21310974d292Smrg	ErrorF("failed to get auxch %02x%02x %02x %02x %02x after %d retries\n",
21320974d292Smrg	       req_bytes[1], req_bytes[0], req_bytes[2], req_bytes[3], args.v1.ucReplyStatus, retry_count);
2133ad43ddacSmrg	return FALSE;
2134ad43ddacSmrg    }
2135ad43ddacSmrg    if (args.v1.ucDataOutLen && read_byte && read_buf_len) {
2136ad43ddacSmrg	if (read_buf_len < args.v1.ucDataOutLen) {
2137ad43ddacSmrg	    ErrorF("%s: Buffer too small for return answer %d %d\n", __func__, read_buf_len, args.v1.ucDataOutLen);
2138ad43ddacSmrg	    return FALSE;
2139ad43ddacSmrg	}
2140ad43ddacSmrg	{
2141ad43ddacSmrg	    int len = read_buf_len < args.v1.ucDataOutLen ? read_buf_len : args.v1.ucDataOutLen;
2142ad43ddacSmrg	    memcpy(read_byte, base+16, len);
2143ad43ddacSmrg	}
2144ad43ddacSmrg    }
2145ad43ddacSmrg    return TRUE;
2146ad43ddacSmrg}
2147ad43ddacSmrg
2148ad43ddacSmrgstatic int
2149ad43ddacSmrgRADEONDPEncoderService(xf86OutputPtr output, int action, uint8_t ucconfig, uint8_t lane_num)
2150ad43ddacSmrg{
2151ad43ddacSmrg    RADEONInfoPtr info = RADEONPTR(output->scrn);
2152ad43ddacSmrg    DP_ENCODER_SERVICE_PARAMETERS args;
2153ad43ddacSmrg    AtomBiosArgRec data;
2154ad43ddacSmrg    unsigned char *space;
2155ad43ddacSmrg
2156ad43ddacSmrg    memset(&args, 0, sizeof(args));
2157ad43ddacSmrg
2158ad43ddacSmrg    args.ucLinkClock = 0;
2159ad43ddacSmrg    args.ucConfig = ucconfig;
2160ad43ddacSmrg    args.ucAction = action;
2161ad43ddacSmrg    args.ucLaneNum = lane_num;
2162ad43ddacSmrg    args.ucStatus = 0;
2163ad43ddacSmrg
2164ad43ddacSmrg    data.exec.index = GetIndexIntoMasterTable(COMMAND, DPEncoderService);
2165ad43ddacSmrg    data.exec.dataSpace = (void *)&space;
2166ad43ddacSmrg    data.exec.pspace = &args;
2167ad43ddacSmrg
216868105dcbSveego    RHDAtomBiosFunc(info->atomBIOS->pScrn, info->atomBIOS, ATOMBIOS_EXEC, &data);
2169ad43ddacSmrg
2170042789b0Sveego/*    ErrorF("%s: %d %d\n", __func__, action, args.ucStatus); */
2171ad43ddacSmrg    return args.ucStatus;
2172ad43ddacSmrg}
2173ad43ddacSmrg
2174ad43ddacSmrgint RADEON_DP_GetSinkType(xf86OutputPtr output)
2175ad43ddacSmrg{
2176ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2177ad43ddacSmrg
2178ad43ddacSmrg    return RADEONDPEncoderService(output, ATOM_DP_ACTION_GET_SINK_TYPE, radeon_output->ucI2cId, 0);
2179ad43ddacSmrg}
2180ad43ddacSmrg
2181ad43ddacSmrgstatic Bool atom_dp_aux_native_write(xf86OutputPtr output, uint16_t address,
2182ad43ddacSmrg				     uint8_t send_bytes, uint8_t *send)
2183ad43ddacSmrg{
2184ad43ddacSmrg    uint8_t msg[20];
2185ad43ddacSmrg    uint8_t msg_len, dp_msg_len;
2186ad43ddacSmrg    int ret;
2187ad43ddacSmrg
2188ad43ddacSmrg    dp_msg_len = 4;
2189ad43ddacSmrg    msg[0] = address;
2190ad43ddacSmrg    msg[1] = address >> 8;
2191ad43ddacSmrg    msg[2] = AUX_NATIVE_WRITE << 4;
2192ad43ddacSmrg    dp_msg_len += send_bytes;
2193ad43ddacSmrg    msg[3] = (dp_msg_len << 4)| (send_bytes - 1);
2194ad43ddacSmrg
2195ad43ddacSmrg    if (0)
2196ad43ddacSmrg	ErrorF("writing %02x %02x %02x, %d, %d\n", msg[0], msg[1], msg[3], send_bytes, dp_msg_len);
2197ad43ddacSmrg    if (send_bytes > 16)
2198ad43ddacSmrg	return FALSE;
2199ad43ddacSmrg
2200ad43ddacSmrg    memcpy(&msg[4], send, send_bytes);
2201ad43ddacSmrg    msg_len = 4 + send_bytes;
2202ad43ddacSmrg    ret = RADEONProcessAuxCH(output, msg, msg_len, NULL, 0, 0);
2203ad43ddacSmrg    return ret;
2204ad43ddacSmrg}
2205ad43ddacSmrg
2206ad43ddacSmrgstatic Bool atom_dp_aux_native_read(xf86OutputPtr output, uint16_t address,
2207ad43ddacSmrg				    uint8_t delay,
2208ad43ddacSmrg				    uint8_t expected_bytes, uint8_t *read_p)
2209ad43ddacSmrg{
2210ad43ddacSmrg    uint8_t msg[20];
2211ad43ddacSmrg    uint8_t msg_len, dp_msg_len;
2212ad43ddacSmrg    int ret;
2213ad43ddacSmrg
2214ad43ddacSmrg    msg_len = 4;
2215ad43ddacSmrg    dp_msg_len = 4;
2216ad43ddacSmrg    msg[0] = address;
2217ad43ddacSmrg    msg[1] = address >> 8;
2218ad43ddacSmrg    msg[2] = AUX_NATIVE_READ << 4;
2219ad43ddacSmrg    msg[3] = (dp_msg_len) << 4;
2220ad43ddacSmrg    msg[3] |= expected_bytes - 1;
2221ad43ddacSmrg
2222ad43ddacSmrg    if (0)
2223ad43ddacSmrg	ErrorF("reading %02x %02x %02x, %d, %d\n", msg[0], msg[1], msg[3], expected_bytes, dp_msg_len);
2224ad43ddacSmrg    ret = RADEONProcessAuxCH(output, msg, msg_len, read_p, expected_bytes, delay);
2225ad43ddacSmrg    return ret;
2226ad43ddacSmrg}
2227ad43ddacSmrg
2228ad43ddacSmrg/* fill out the DPCD structure */
2229ad43ddacSmrgvoid RADEON_DP_GetDPCD(xf86OutputPtr output)
2230ad43ddacSmrg{
2231ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2232ad43ddacSmrg    uint8_t msg[25];
2233ad43ddacSmrg    int ret;
2234ad43ddacSmrg
2235ad43ddacSmrg    ret = atom_dp_aux_native_read(output, DP_DPCD_REV, 0, 8, msg);
2236ad43ddacSmrg    if (ret) {
2237ad43ddacSmrg	memcpy(radeon_output->dpcd, msg, 8);
2238ad43ddacSmrg	if (0) {
2239ad43ddacSmrg	    int i;
2240ad43ddacSmrg	    ErrorF("DPCD: ");
2241ad43ddacSmrg	    for (i = 0; i < 8; i++)
2242ad43ddacSmrg		ErrorF("%02x ", radeon_output->dpcd[i]);
2243ad43ddacSmrg	    ErrorF("\n");
2244ad43ddacSmrg	}
2245ad43ddacSmrg	ret = atom_dp_aux_native_read(output, DP_LINK_BW_SET, 0, 2, msg);
2246ad43ddacSmrg	if (0) {
2247ad43ddacSmrg	    ErrorF("0x200: %02x %02x\n", msg[0], msg[1]);
2248ad43ddacSmrg	}
2249ad43ddacSmrg	return;
2250ad43ddacSmrg    }
2251ad43ddacSmrg    radeon_output->dpcd[0] = 0;
2252ad43ddacSmrg    return;
2253ad43ddacSmrg}
2254ad43ddacSmrg
2255ad43ddacSmrg
2256ad43ddacSmrgenum dp_aux_i2c_mode {
2257ad43ddacSmrg    dp_aux_i2c_start,
2258ad43ddacSmrg    dp_aux_i2c_write,
2259ad43ddacSmrg    dp_aux_i2c_read,
2260ad43ddacSmrg    dp_aux_i2c_stop,
2261ad43ddacSmrg};
2262ad43ddacSmrg
2263ad43ddacSmrg
2264ad43ddacSmrgstatic Bool atom_dp_aux_i2c_transaction(xf86OutputPtr output, uint16_t address,
2265ad43ddacSmrg				       enum dp_aux_i2c_mode mode,
2266ad43ddacSmrg				       uint8_t write_byte, uint8_t *read_byte)
2267ad43ddacSmrg{
2268ad43ddacSmrg    uint8_t msg[8], msg_len, dp_msg_len;
2269ad43ddacSmrg    int ret;
2270ad43ddacSmrg    int auxch_cmd = 0;
2271ad43ddacSmrg
2272ad43ddacSmrg    memset(msg, 0, 8);
2273ad43ddacSmrg
2274ad43ddacSmrg    if (mode != dp_aux_i2c_stop)
2275ad43ddacSmrg	auxch_cmd = AUX_I2C_MOT;
2276ad43ddacSmrg
2277ad43ddacSmrg    if (address & 1)
2278ad43ddacSmrg	auxch_cmd |= AUX_I2C_READ;
2279ad43ddacSmrg    else
2280ad43ddacSmrg    	auxch_cmd |= AUX_I2C_WRITE;
2281ad43ddacSmrg
2282ad43ddacSmrg    msg[2] = auxch_cmd << 4;
2283ad43ddacSmrg
2284ad43ddacSmrg    msg[4] = 0;
2285ad43ddacSmrg    msg[0] = (address >> 1);
2286ad43ddacSmrg    msg[1] = (address >> 9);
2287ad43ddacSmrg
2288ad43ddacSmrg    msg_len = 4;
2289ad43ddacSmrg    dp_msg_len = 3;
2290ad43ddacSmrg    switch (mode) {
2291ad43ddacSmrg    case dp_aux_i2c_read:
2292ad43ddacSmrg	/* bottom bits is byte count - 1 so for 1 byte == 0 */
2293ad43ddacSmrg	dp_msg_len += 1;
2294ad43ddacSmrg	break;
2295ad43ddacSmrg    case dp_aux_i2c_write:
2296ad43ddacSmrg	dp_msg_len += 2;
2297ad43ddacSmrg	msg[4] = write_byte;
2298ad43ddacSmrg	msg_len++;
2299ad43ddacSmrg	break;
2300ad43ddacSmrg    default:
2301ad43ddacSmrg	break;
2302ad43ddacSmrg    }
2303ad43ddacSmrg    msg[3] = dp_msg_len << 4;
2304ad43ddacSmrg
2305ad43ddacSmrg    ret = RADEONProcessAuxCH(output, msg, msg_len, read_byte, 1, 0);
2306ad43ddacSmrg    return ret;
2307ad43ddacSmrg}
2308ad43ddacSmrg
2309ad43ddacSmrgstatic Bool
2310ad43ddacSmrgatom_dp_i2c_address(I2CDevPtr dev, I2CSlaveAddr addr)
2311ad43ddacSmrg{
2312ad43ddacSmrg    I2CBusPtr bus = dev->pI2CBus;
2313ad43ddacSmrg    xf86OutputPtr output = bus->DriverPrivate.ptr;
2314ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2315ad43ddacSmrg    int ret;
2316ad43ddacSmrg
2317ad43ddacSmrg    radeon_output->dp_i2c_addr = addr;
2318ad43ddacSmrg    radeon_output->dp_i2c_running = TRUE;
2319ad43ddacSmrg
2320ad43ddacSmrg    /* call i2c start */
2321ad43ddacSmrg    ret = atom_dp_aux_i2c_transaction(output, radeon_output->dp_i2c_addr,
2322ad43ddacSmrg				      dp_aux_i2c_start, 0, NULL);
2323ad43ddacSmrg
2324ad43ddacSmrg    return ret;
2325ad43ddacSmrg}
2326ad43ddacSmrgstatic Bool
2327ad43ddacSmrgatom_dp_i2c_start(I2CBusPtr bus, int timeout)
2328ad43ddacSmrg{
2329042789b0Sveego/*    ErrorF("%s\n", __func__); */
2330ad43ddacSmrg    return TRUE;
2331ad43ddacSmrg}
2332ad43ddacSmrg
2333ad43ddacSmrgstatic void
2334ad43ddacSmrgatom_dp_i2c_stop(I2CDevPtr dev)
2335ad43ddacSmrg{
2336ad43ddacSmrg    I2CBusPtr bus = dev->pI2CBus;
2337ad43ddacSmrg    xf86OutputPtr output = bus->DriverPrivate.ptr;
2338ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2339ad43ddacSmrg
2340ad43ddacSmrg    if (radeon_output->dp_i2c_running)
2341ad43ddacSmrg	atom_dp_aux_i2c_transaction(output, radeon_output->dp_i2c_addr,
2342ad43ddacSmrg				    dp_aux_i2c_stop, 0, NULL);
2343ad43ddacSmrg    radeon_output->dp_i2c_running = FALSE;
2344ad43ddacSmrg}
2345ad43ddacSmrg
2346ad43ddacSmrg
2347ad43ddacSmrgstatic Bool
2348ad43ddacSmrgatom_dp_i2c_put_byte(I2CDevPtr dev, I2CByte byte)
2349ad43ddacSmrg{
2350ad43ddacSmrg    I2CBusPtr bus = dev->pI2CBus;
2351ad43ddacSmrg    xf86OutputPtr output = bus->DriverPrivate.ptr;
2352ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2353ad43ddacSmrg    Bool ret;
2354ad43ddacSmrg
2355ad43ddacSmrg    ret = (atom_dp_aux_i2c_transaction(output, radeon_output->dp_i2c_addr,
2356ad43ddacSmrg				       dp_aux_i2c_write, byte, NULL));
2357ad43ddacSmrg    return ret;
2358ad43ddacSmrg}
2359ad43ddacSmrg
2360ad43ddacSmrgstatic Bool
2361ad43ddacSmrgatom_dp_i2c_get_byte(I2CDevPtr dev, I2CByte *byte_ret, Bool last)
2362ad43ddacSmrg{
2363ad43ddacSmrg    I2CBusPtr bus = dev->pI2CBus;
2364ad43ddacSmrg    xf86OutputPtr output = bus->DriverPrivate.ptr;
2365ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2366ad43ddacSmrg    Bool ret;
2367ad43ddacSmrg
2368ad43ddacSmrg    ret = (atom_dp_aux_i2c_transaction(output, radeon_output->dp_i2c_addr,
2369ad43ddacSmrg				       dp_aux_i2c_read, 0, byte_ret));
2370ad43ddacSmrg    return ret;
2371ad43ddacSmrg}
2372ad43ddacSmrg
2373ad43ddacSmrgBool
2374ad43ddacSmrgRADEON_DP_I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, char *name, xf86OutputPtr output)
2375ad43ddacSmrg{
2376ad43ddacSmrg    I2CBusPtr pI2CBus;
2377ad43ddacSmrg
2378ad43ddacSmrg    pI2CBus = xf86CreateI2CBusRec();
2379ad43ddacSmrg    if (!pI2CBus) return FALSE;
2380ad43ddacSmrg
2381ad43ddacSmrg    pI2CBus->BusName = name;
2382ad43ddacSmrg    pI2CBus->scrnIndex = pScrn->scrnIndex;
2383ad43ddacSmrg    pI2CBus->I2CGetByte = atom_dp_i2c_get_byte;
2384ad43ddacSmrg    pI2CBus->I2CPutByte = atom_dp_i2c_put_byte;
2385ad43ddacSmrg    pI2CBus->I2CAddress = atom_dp_i2c_address;
2386ad43ddacSmrg    pI2CBus->I2CStart = atom_dp_i2c_start;
2387ad43ddacSmrg    pI2CBus->I2CStop = atom_dp_i2c_stop;
2388ad43ddacSmrg    pI2CBus->DriverPrivate.ptr = output;
2389ad43ddacSmrg
2390ad43ddacSmrg    /*
2391ad43ddacSmrg     * These were set incorrectly in the server pre-1.3, Having
2392ad43ddacSmrg     * duplicate settings is sub-optimal, but this lets the driver
2393ad43ddacSmrg     * work with older servers
2394ad43ddacSmrg     */
2395ad43ddacSmrg    pI2CBus->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */
2396ad43ddacSmrg    pI2CBus->StartTimeout = 550;
2397ad43ddacSmrg    pI2CBus->BitTimeout = 40;
2398ad43ddacSmrg    pI2CBus->AcknTimeout = 40;
2399ad43ddacSmrg    pI2CBus->RiseFallTime = 20;
2400ad43ddacSmrg
2401ad43ddacSmrg    if (!xf86I2CBusInit(pI2CBus))
2402ad43ddacSmrg	return FALSE;
2403ad43ddacSmrg
2404ad43ddacSmrg    *bus_ptr = pI2CBus;
2405ad43ddacSmrg    return TRUE;
2406ad43ddacSmrg}
2407ad43ddacSmrg
2408ad43ddacSmrg
2409ad43ddacSmrgstatic uint8_t dp_link_status(uint8_t link_status[DP_LINK_STATUS_SIZE], int r)
2410ad43ddacSmrg{
2411ad43ddacSmrg    return link_status[r - DP_LANE0_1_STATUS];
2412ad43ddacSmrg}
2413ad43ddacSmrg
2414ad43ddacSmrgstatic uint8_t dp_get_lane_status(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane)
2415ad43ddacSmrg{
2416ad43ddacSmrg    int i = DP_LANE0_1_STATUS + (lane >> 1);
2417ad43ddacSmrg    int s = (lane & 1) * 4;
2418ad43ddacSmrg    uint8_t l = dp_link_status(link_status, i);
2419ad43ddacSmrg    return (l >> s) & 0xf;
2420ad43ddacSmrg}
2421ad43ddacSmrg
2422ad43ddacSmrgstatic Bool dp_clock_recovery_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
2423ad43ddacSmrg{
2424ad43ddacSmrg    int lane;
2425ad43ddacSmrg
2426ad43ddacSmrg    uint8_t lane_status;
2427ad43ddacSmrg
2428ad43ddacSmrg    for (lane = 0; lane < lane_count; lane++) {
2429ad43ddacSmrg	lane_status = dp_get_lane_status(link_status, lane);
2430ad43ddacSmrg	if ((lane_status & DP_LANE_CR_DONE) == 0)
2431ad43ddacSmrg	    return FALSE;
2432ad43ddacSmrg    }
2433ad43ddacSmrg    return TRUE;
2434ad43ddacSmrg}
2435ad43ddacSmrg
2436ad43ddacSmrg
2437ad43ddacSmrg/* Check to see if channel eq is done on all channels */
2438ad43ddacSmrg#define CHANNEL_EQ_BITS (DP_LANE_CR_DONE|\
2439ad43ddacSmrg			 DP_LANE_CHANNEL_EQ_DONE|\
2440ad43ddacSmrg			 DP_LANE_SYMBOL_LOCKED)
2441ad43ddacSmrgstatic Bool
2442ad43ddacSmrgdp_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
2443ad43ddacSmrg{
2444ad43ddacSmrg    uint8_t lane_align;
2445ad43ddacSmrg    uint8_t lane_status;
2446ad43ddacSmrg    int lane;
2447ad43ddacSmrg
2448ad43ddacSmrg    lane_align = dp_link_status(link_status,
2449ad43ddacSmrg				DP_LANE_ALIGN_STATUS_UPDATED);
2450ad43ddacSmrg    if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
2451ad43ddacSmrg	return FALSE;
2452ad43ddacSmrg    for (lane = 0; lane < lane_count; lane++) {
2453ad43ddacSmrg	lane_status = dp_get_lane_status(link_status, lane);
2454ad43ddacSmrg	if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS)
2455ad43ddacSmrg	    return FALSE;
2456ad43ddacSmrg    }
2457ad43ddacSmrg    return TRUE;
2458ad43ddacSmrg}
2459ad43ddacSmrg
2460ad43ddacSmrg/*
2461ad43ddacSmrg * Fetch AUX CH registers 0x202 - 0x207 which contain
2462ad43ddacSmrg * link status information
2463ad43ddacSmrg */
2464ad43ddacSmrgstatic Bool
2465ad43ddacSmrgatom_dp_get_link_status(xf86OutputPtr output,
2466ad43ddacSmrg			  uint8_t link_status[DP_LINK_STATUS_SIZE])
2467ad43ddacSmrg{
2468ad43ddacSmrg    ScrnInfoPtr pScrn = output->scrn;
2469ad43ddacSmrg    int ret;
2470ad43ddacSmrg    ret = atom_dp_aux_native_read(output, DP_LANE0_1_STATUS, 100,
2471ad43ddacSmrg				  DP_LINK_STATUS_SIZE, link_status);
2472ad43ddacSmrg    if (!ret) {
2473ad43ddacSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "dp link status failed\n");
2474ad43ddacSmrg	return FALSE;
2475ad43ddacSmrg    }
2476042789b0Sveego/*    ErrorF("link status %02x %02x %02x %02x %02x %02x\n", link_status[0], link_status[1],
2477042789b0Sveego	   link_status[2], link_status[3], link_status[4], link_status[5]); */
2478ad43ddacSmrg
2479ad43ddacSmrg    return TRUE;
2480ad43ddacSmrg}
2481ad43ddacSmrg
2482ad43ddacSmrgstatic uint8_t
2483ad43ddacSmrgdp_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE],
2484ad43ddacSmrg			      int lane)
2485ad43ddacSmrg
2486ad43ddacSmrg{
2487ad43ddacSmrg    int     i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
2488ad43ddacSmrg    int     s = ((lane & 1) ?
2489ad43ddacSmrg                 DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT :
2490ad43ddacSmrg                 DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT);
2491ad43ddacSmrg    uint8_t l = dp_link_status(link_status, i);
2492ad43ddacSmrg
2493ad43ddacSmrg    return ((l >> s) & 3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
2494ad43ddacSmrg}
2495ad43ddacSmrg
2496ad43ddacSmrgstatic uint8_t
2497ad43ddacSmrgdp_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZE],
2498ad43ddacSmrg				   int lane)
2499ad43ddacSmrg{
2500ad43ddacSmrg    int     i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
2501ad43ddacSmrg    int     s = ((lane & 1) ?
2502ad43ddacSmrg                 DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT :
2503ad43ddacSmrg                 DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT);
2504ad43ddacSmrg    uint8_t l = dp_link_status(link_status, i);
2505ad43ddacSmrg
2506ad43ddacSmrg    return ((l >> s) & 3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
2507ad43ddacSmrg}
2508ad43ddacSmrg
2509ad43ddacSmrgstatic char     *voltage_names[] = {
2510ad43ddacSmrg        "0.4V", "0.6V", "0.8V", "1.2V"
2511ad43ddacSmrg};
2512ad43ddacSmrgstatic char     *pre_emph_names[] = {
2513ad43ddacSmrg        "0dB", "3.5dB", "6dB", "9.5dB"
2514ad43ddacSmrg};
2515ad43ddacSmrg
2516ad43ddacSmrg/*
2517ad43ddacSmrg * These are source-specific values; current Intel hardware supports
2518ad43ddacSmrg * a maximum voltage of 800mV and a maximum pre-emphasis of 6dB
2519ad43ddacSmrg */
2520ad43ddacSmrg#define DP_VOLTAGE_MAX         DP_TRAIN_VOLTAGE_SWING_1200
2521ad43ddacSmrg
2522ad43ddacSmrgstatic uint8_t
2523ad43ddacSmrgdp_pre_emphasis_max(uint8_t voltage_swing)
2524ad43ddacSmrg{
2525ad43ddacSmrg    switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
2526ad43ddacSmrg    case DP_TRAIN_VOLTAGE_SWING_400:
2527ad43ddacSmrg        return DP_TRAIN_PRE_EMPHASIS_6;
2528ad43ddacSmrg    case DP_TRAIN_VOLTAGE_SWING_600:
2529ad43ddacSmrg        return DP_TRAIN_PRE_EMPHASIS_6;
2530ad43ddacSmrg    case DP_TRAIN_VOLTAGE_SWING_800:
2531ad43ddacSmrg        return DP_TRAIN_PRE_EMPHASIS_3_5;
2532ad43ddacSmrg    case DP_TRAIN_VOLTAGE_SWING_1200:
2533ad43ddacSmrg    default:
2534ad43ddacSmrg        return DP_TRAIN_PRE_EMPHASIS_0;
2535ad43ddacSmrg    }
2536ad43ddacSmrg}
2537ad43ddacSmrg
2538ad43ddacSmrgstatic void dp_set_training(xf86OutputPtr output, uint8_t training)
2539ad43ddacSmrg{
2540ad43ddacSmrg    atom_dp_aux_native_write(output, DP_TRAINING_PATTERN_SET, 1, &training);
2541ad43ddacSmrg}
2542ad43ddacSmrg
2543ad43ddacSmrgstatic void dp_set_power(xf86OutputPtr output, uint8_t power_state)
2544ad43ddacSmrg{
2545ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2546ad43ddacSmrg
2547ad43ddacSmrg    if (radeon_output->dpcd[0] >= 0x11) {
2548ad43ddacSmrg	atom_dp_aux_native_write(output, 0x600, 1, &power_state);
2549ad43ddacSmrg    }
2550ad43ddacSmrg}
2551ad43ddacSmrg
2552ad43ddacSmrgstatic void
2553ad43ddacSmrgdp_get_adjust_train(xf86OutputPtr output,
2554ad43ddacSmrg		      uint8_t link_status[DP_LINK_STATUS_SIZE],
2555ad43ddacSmrg		      int lane_count,
2556ad43ddacSmrg		      uint8_t train_set[4])
2557ad43ddacSmrg{
2558ad43ddacSmrg    ScrnInfoPtr pScrn = output->scrn;
2559ad43ddacSmrg    uint8_t v = 0;
2560ad43ddacSmrg    uint8_t p = 0;
2561ad43ddacSmrg    int lane;
2562ad43ddacSmrg
2563ad43ddacSmrg    for (lane = 0; lane < lane_count; lane++) {
2564ad43ddacSmrg	uint8_t this_v = dp_get_adjust_request_voltage(link_status, lane);
2565ad43ddacSmrg	uint8_t this_p = dp_get_adjust_request_pre_emphasis(link_status, lane);
2566ad43ddacSmrg
2567ad43ddacSmrg	if (0) {
2568ad43ddacSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2569ad43ddacSmrg		       "requested signal parameters: lane %d voltage %s pre_emph %s\n",
2570ad43ddacSmrg		       lane,
2571ad43ddacSmrg		       voltage_names[this_v >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
2572ad43ddacSmrg		       pre_emph_names[this_p >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);
2573ad43ddacSmrg	}
2574ad43ddacSmrg	if (this_v > v)
2575ad43ddacSmrg	    v = this_v;
2576ad43ddacSmrg	if (this_p > p)
2577ad43ddacSmrg	    p = this_p;
2578ad43ddacSmrg    }
2579ad43ddacSmrg
2580ad43ddacSmrg    if (v >= DP_VOLTAGE_MAX)
2581ad43ddacSmrg	v = DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED;
2582ad43ddacSmrg
2583ad43ddacSmrg    if (p >= dp_pre_emphasis_max(v))
2584ad43ddacSmrg	p = dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
2585ad43ddacSmrg
2586ad43ddacSmrg    if (0) {
2587ad43ddacSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2588ad43ddacSmrg		   "using signal parameters: voltage %s pre_emph %s\n",
2589ad43ddacSmrg		   voltage_names[(v & DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
2590ad43ddacSmrg		   pre_emph_names[(p & DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT]);
2591ad43ddacSmrg    }
2592ad43ddacSmrg    for (lane = 0; lane < 4; lane++)
2593ad43ddacSmrg	train_set[lane] = v | p;
2594ad43ddacSmrg}
2595ad43ddacSmrg
2596ad43ddacSmrgstatic int radeon_dp_max_lane_count(xf86OutputPtr output)
2597ad43ddacSmrg{
2598ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2599ad43ddacSmrg    int max_lane_count = 4;
2600ad43ddacSmrg
2601ad43ddacSmrg    if (radeon_output->dpcd[0] >= 0x11) {
2602ad43ddacSmrg	max_lane_count = radeon_output->dpcd[2] & 0x1f;
2603ad43ddacSmrg	switch(max_lane_count) {
2604ad43ddacSmrg	case 1: case 2: case 4:
2605ad43ddacSmrg	    break;
2606ad43ddacSmrg	default:
2607ad43ddacSmrg	    max_lane_count = 4;
2608ad43ddacSmrg	}
2609ad43ddacSmrg    }
2610ad43ddacSmrg    return max_lane_count;
2611ad43ddacSmrg}
2612ad43ddacSmrg
2613ad43ddacSmrgBool radeon_dp_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode)
2614ad43ddacSmrg{
2615921a55d8Smrg	RADEONOutputPrivatePtr radeon_output = output->driver_private;
2616921a55d8Smrg	int clock = adjusted_mode->Clock;
2617921a55d8Smrg
2618921a55d8Smrg	radeon_output->dp_lane_count = dp_lanes_for_mode_clock(output, clock);
2619921a55d8Smrg	radeon_output->dp_clock = dp_link_clock_for_mode_clock(output, clock);
2620921a55d8Smrg	if (!radeon_output->dp_lane_count || !radeon_output->dp_clock)
2621921a55d8Smrg		return FALSE;
2622921a55d8Smrg	return TRUE;
2623ad43ddacSmrg}
2624ad43ddacSmrg
2625ad43ddacSmrgstatic void dp_update_dpvs_emph(xf86OutputPtr output, uint8_t train_set[4])
2626ad43ddacSmrg{
2627ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2628ad43ddacSmrg    int i;
2629ad43ddacSmrg    for (i = 0; i < radeon_output->dp_lane_count; i++)
2630ad43ddacSmrg	atombios_output_dig_transmitter_setup(output, ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH, i, train_set[i]);
2631ad43ddacSmrg
2632ad43ddacSmrg    atom_dp_aux_native_write(output, DP_TRAINING_LANE0_SET, radeon_output->dp_lane_count, train_set);
2633ad43ddacSmrg}
2634ad43ddacSmrg
2635ad43ddacSmrgstatic void do_displayport_link_train(xf86OutputPtr output)
2636ad43ddacSmrg{
2637ad43ddacSmrg    ScrnInfoPtr pScrn = output->scrn;
2638ad43ddacSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
2639ad43ddacSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
2640ad43ddacSmrg    int enc_id = atom_dp_get_encoder_id(output);
2641ad43ddacSmrg    Bool clock_recovery;
2642ad43ddacSmrg    uint8_t link_status[DP_LINK_STATUS_SIZE];
2643ad43ddacSmrg    uint8_t tries, voltage, ss_cntl;
2644ad43ddacSmrg    uint8_t train_set[4];
2645ad43ddacSmrg    int i;
2646ad43ddacSmrg    Bool channel_eq;
2647ad43ddacSmrg    uint8_t dp_link_configuration[DP_LINK_CONFIGURATION_SIZE];
2648ad43ddacSmrg
2649ad43ddacSmrg    memset(train_set, 0, 4);
2650ad43ddacSmrg
2651ad43ddacSmrg    /* set up link configuration */
2652ad43ddacSmrg    memset(dp_link_configuration, 0, DP_LINK_CONFIGURATION_SIZE);
2653ad43ddacSmrg
2654921a55d8Smrg    if (radeon_output->dp_clock == 27000)
2655ad43ddacSmrg	dp_link_configuration[0] = DP_LINK_BW_2_7;
2656ad43ddacSmrg    else
2657ad43ddacSmrg	dp_link_configuration[0] = DP_LINK_BW_1_62;
2658ad43ddacSmrg    dp_link_configuration[1] = radeon_output->dp_lane_count;
2659ad43ddacSmrg
2660ad43ddacSmrg    if (radeon_output->dpcd[0] >= 0x11) {
2661ad43ddacSmrg	dp_link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
2662ad43ddacSmrg    }
2663ad43ddacSmrg
2664ad43ddacSmrg    /* power up to D0 */
2665ad43ddacSmrg    dp_set_power(output, DP_SET_POWER_D0);
2666ad43ddacSmrg
2667ad43ddacSmrg    /* disable training */
2668ad43ddacSmrg    dp_set_training(output, DP_TRAINING_PATTERN_DISABLE);
2669ad43ddacSmrg
2670ad43ddacSmrg    /* write link rate / num / eh framing */
2671ad43ddacSmrg    atom_dp_aux_native_write(output, DP_LINK_BW_SET, 2,
2672ad43ddacSmrg			     dp_link_configuration);
2673ad43ddacSmrg
2674ad43ddacSmrg    /* write ss cntl */
2675ad43ddacSmrg    ss_cntl = 0;
2676ad43ddacSmrg    atom_dp_aux_native_write(output, DP_DOWNSPREAD_CTRL, 1,
2677ad43ddacSmrg			     &ss_cntl);
2678ad43ddacSmrg
2679ad43ddacSmrg    /* start local training start */
2680ad43ddacSmrg    if (IS_DCE4_VARIANT) {
26810974d292Smrg	atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_LINK_TRAINING_START);
26820974d292Smrg	atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1);
2683ad43ddacSmrg    } else {
2684ad43ddacSmrg	RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_START, enc_id, 0);
2685ad43ddacSmrg	RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, enc_id, 0);
2686ad43ddacSmrg    }
2687ad43ddacSmrg
2688ad43ddacSmrg    usleep(400);
2689ad43ddacSmrg    dp_set_training(output, DP_TRAINING_PATTERN_1);
2690ad43ddacSmrg    dp_update_dpvs_emph(output, train_set);
2691ad43ddacSmrg
2692ad43ddacSmrg    /* loop around doing configuration reads and DP encoder setups */
2693ad43ddacSmrg    clock_recovery = FALSE;
2694ad43ddacSmrg    tries = 0;
2695ad43ddacSmrg    voltage = 0xff;
2696ad43ddacSmrg    for (;;) {
2697ad43ddacSmrg      	usleep(100);
2698ad43ddacSmrg	if (!atom_dp_get_link_status(output, link_status))
2699ad43ddacSmrg	    break;
2700ad43ddacSmrg
2701ad43ddacSmrg	if (dp_clock_recovery_ok(link_status, radeon_output->dp_lane_count)) {
2702ad43ddacSmrg	    clock_recovery = TRUE;
2703ad43ddacSmrg	    break;
2704ad43ddacSmrg	}
2705ad43ddacSmrg
2706ad43ddacSmrg	for (i = 0; i < radeon_output->dp_lane_count; i++)
2707ad43ddacSmrg	    if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
2708ad43ddacSmrg		break;
2709ad43ddacSmrg	if (i == radeon_output->dp_lane_count) {
2710ad43ddacSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2711ad43ddacSmrg		       "clock recovery reached max voltage\n");
2712ad43ddacSmrg	    break;
2713ad43ddacSmrg	}
2714ad43ddacSmrg
2715ad43ddacSmrg	/* Check to see if we've tried the same voltage 5 times */
2716ad43ddacSmrg	if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
2717ad43ddacSmrg	    ++tries;
2718ad43ddacSmrg	    if (tries == 5) {
2719ad43ddacSmrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2720ad43ddacSmrg			   "clock recovery tried 5 times\n");
2721ad43ddacSmrg		break;
2722ad43ddacSmrg	    }
2723ad43ddacSmrg	} else
2724ad43ddacSmrg	    tries = 0;
2725ad43ddacSmrg
2726ad43ddacSmrg	voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
2727ad43ddacSmrg
2728ad43ddacSmrg        dp_get_adjust_train(output, link_status, radeon_output->dp_lane_count, train_set);
2729ad43ddacSmrg	dp_update_dpvs_emph(output, train_set);
2730ad43ddacSmrg
2731ad43ddacSmrg    }
2732ad43ddacSmrg
2733ad43ddacSmrg    if (!clock_recovery)
2734ad43ddacSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2735ad43ddacSmrg		   "clock recovery failed\n");
2736ad43ddacSmrg
2737ad43ddacSmrg    /* channel equalization */
2738ad43ddacSmrg    tries = 0;
2739ad43ddacSmrg    channel_eq = FALSE;
2740ad43ddacSmrg    dp_set_training(output, DP_TRAINING_PATTERN_2);
2741ad43ddacSmrg    if (IS_DCE4_VARIANT)
27420974d292Smrg	atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2);
2743ad43ddacSmrg    else
2744ad43ddacSmrg	RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, enc_id, 1);
2745ad43ddacSmrg
2746ad43ddacSmrg    for (;;) {
2747ad43ddacSmrg	usleep(400);
2748ad43ddacSmrg	if (!atom_dp_get_link_status(output, link_status))
2749ad43ddacSmrg	    break;
2750ad43ddacSmrg
2751ad43ddacSmrg	if (dp_channel_eq_ok(link_status, radeon_output->dp_lane_count)) {
2752ad43ddacSmrg	    channel_eq = TRUE;
2753ad43ddacSmrg	    break;
2754ad43ddacSmrg	}
2755ad43ddacSmrg
2756ad43ddacSmrg	/* Try 5 times */
2757ad43ddacSmrg	if (tries > 5) {
2758ad43ddacSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2759ad43ddacSmrg		       "channel eq failed: 5 tries\n");
2760ad43ddacSmrg	    break;
2761ad43ddacSmrg	}
2762ad43ddacSmrg
2763ad43ddacSmrg	/* Compute new train_set as requested by target */
2764ad43ddacSmrg        dp_get_adjust_train(output, link_status, radeon_output->dp_lane_count, train_set);
2765ad43ddacSmrg	dp_update_dpvs_emph(output, train_set);
2766ad43ddacSmrg
2767ad43ddacSmrg	++tries;
2768ad43ddacSmrg    }
2769ad43ddacSmrg
2770ad43ddacSmrg    if (!channel_eq)
2771ad43ddacSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2772ad43ddacSmrg		   "channel eq failed\n");
2773ad43ddacSmrg
2774ad43ddacSmrg    dp_set_training(output, DP_TRAINING_PATTERN_DISABLE);
2775ad43ddacSmrg    if (IS_DCE4_VARIANT)
27760974d292Smrg	atombios_output_dig_encoder_setup(output, ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE);
2777ad43ddacSmrg    else
2778ad43ddacSmrg	RADEONDPEncoderService(output, ATOM_DP_ACTION_TRAINING_COMPLETE, enc_id, 0);
2779ad43ddacSmrg
2780ad43ddacSmrg}
2781ad43ddacSmrg
2782