1209ff23fSmrg/*
2209ff23fSmrg * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
3209ff23fSmrg *                VA Linux Systems Inc., Fremont, California.
4209ff23fSmrg *
5209ff23fSmrg * All Rights Reserved.
6209ff23fSmrg *
7209ff23fSmrg * Permission is hereby granted, free of charge, to any person obtaining
8209ff23fSmrg * a copy of this software and associated documentation files (the
9209ff23fSmrg * "Software"), to deal in the Software without restriction, including
10209ff23fSmrg * without limitation on the rights to use, copy, modify, merge,
11209ff23fSmrg * publish, distribute, sublicense, and/or sell copies of the Software,
12209ff23fSmrg * and to permit persons to whom the Software is furnished to do so,
13209ff23fSmrg * subject to the following conditions:
14209ff23fSmrg *
15209ff23fSmrg * The above copyright notice and this permission notice (including the
16209ff23fSmrg * next paragraph) shall be included in all copies or substantial
17209ff23fSmrg * portions of the Software.
18209ff23fSmrg *
19209ff23fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20209ff23fSmrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21209ff23fSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22209ff23fSmrg * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
23209ff23fSmrg * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24209ff23fSmrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25209ff23fSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26209ff23fSmrg * DEALINGS IN THE SOFTWARE.
27209ff23fSmrg */
28209ff23fSmrg
29209ff23fSmrg#ifdef HAVE_CONFIG_H
30209ff23fSmrg#include "config.h"
31209ff23fSmrg#endif
32209ff23fSmrg
33209ff23fSmrg#include <string.h>
34209ff23fSmrg#include <stdio.h>
35209ff23fSmrg
36209ff23fSmrg/* X and server generic header files */
37209ff23fSmrg#include "xf86.h"
38209ff23fSmrg#include "xf86_OSproc.h"
39209ff23fSmrg#include "vgaHW.h"
40209ff23fSmrg#include "xf86Modes.h"
41209ff23fSmrg
42209ff23fSmrg/* Driver data structures */
43209ff23fSmrg#include "radeon.h"
44209ff23fSmrg#include "radeon_reg.h"
45209ff23fSmrg#include "radeon_macros.h"
46209ff23fSmrg#include "radeon_probe.h"
47209ff23fSmrg#include "radeon_version.h"
48209ff23fSmrg#include "radeon_tv.h"
49209ff23fSmrg#include "radeon_atombios.h"
50209ff23fSmrg
51b7e1c893Smrg#include "ati_pciids_gen.h"
52b7e1c893Smrg
53209ff23fSmrgstatic RADEONMonitorType radeon_detect_tv(ScrnInfoPtr pScrn);
54209ff23fSmrgstatic RADEONMonitorType radeon_detect_primary_dac(ScrnInfoPtr pScrn, Bool color);
55209ff23fSmrgstatic RADEONMonitorType radeon_detect_tv_dac(ScrnInfoPtr pScrn, Bool color);
56209ff23fSmrgstatic RADEONMonitorType radeon_detect_ext_dac(ScrnInfoPtr pScrn);
57209ff23fSmrg
58b7e1c893Smrgextern Bool
59b7e1c893SmrgRADEONI2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, char *name, RADEONI2CBusPtr pRADEONI2CBus);
60b7e1c893Smrg
61b7e1c893Smrgstatic const RADEONTMDSPll default_tmds_pll[CHIP_FAMILY_LAST][4] =
62b7e1c893Smrg{
63b7e1c893Smrg    {{0, 0}, {0, 0}, {0, 0}, {0, 0}},				/*CHIP_FAMILY_UNKNOW*/
64b7e1c893Smrg    {{0, 0}, {0, 0}, {0, 0}, {0, 0}},				/*CHIP_FAMILY_LEGACY*/
65b7e1c893Smrg    {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}},	/*CHIP_FAMILY_RADEON*/
66b7e1c893Smrg    {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}},	/*CHIP_FAMILY_RV100*/
67b7e1c893Smrg    {{0, 0}, {0, 0}, {0, 0}, {0, 0}},				/*CHIP_FAMILY_RS100*/
68b7e1c893Smrg    {{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}},	/*CHIP_FAMILY_RV200*/
69b7e1c893Smrg    {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}},	/*CHIP_FAMILY_RS200*/
70b7e1c893Smrg    {{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}},	/*CHIP_FAMILY_R200*/
71b7e1c893Smrg    {{15500, 0x81b}, {0xffffffff, 0x83f}, {0, 0}, {0, 0}},	/*CHIP_FAMILY_RV250*/
72b7e1c893Smrg    {{0, 0}, {0, 0}, {0, 0}, {0, 0}},				/*CHIP_FAMILY_RS300*/
73b7e1c893Smrg    {{13000, 0x400f4}, {15000, 0x400f7}, {0xffffffff, 0x40111}, {0, 0}}, /*CHIP_FAMILY_RV280*/
74b7e1c893Smrg    {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}},		/*CHIP_FAMILY_R300*/
75b7e1c893Smrg    {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}},		/*CHIP_FAMILY_R350*/
76b7e1c893Smrg    {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}},	/*CHIP_FAMILY_RV350*/
77b7e1c893Smrg    {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}},	/*CHIP_FAMILY_RV380*/
78b7e1c893Smrg    {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}},		/*CHIP_FAMILY_R420*/
79b7e1c893Smrg    {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}},		/*CHIP_FAMILY_RV410*/ /* FIXME: just values from r420 used... */
80b7e1c893Smrg    {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}},	/*CHIP_FAMILY_RS400*/ /* FIXME: just values from rv380 used... */
81b7e1c893Smrg    {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}},	/*CHIP_FAMILY_RS480*/ /* FIXME: just values from rv380 used... */
82b7e1c893Smrg};
83b7e1c893Smrg
84b7e1c893Smrgstatic const uint32_t default_tvdac_adj [CHIP_FAMILY_LAST] =
85b7e1c893Smrg{
86b7e1c893Smrg    0x00000000,   /* unknown */
87b7e1c893Smrg    0x00000000,   /* legacy */
88b7e1c893Smrg    0x00000000,   /* r100 */
89b7e1c893Smrg    0x00280000,   /* rv100 */
90b7e1c893Smrg    0x00000000,   /* rs100 */
91b7e1c893Smrg    0x00880000,   /* rv200 */
92b7e1c893Smrg    0x00000000,   /* rs200 */
93b7e1c893Smrg    0x00000000,   /* r200 */
94b7e1c893Smrg    0x00770000,   /* rv250 */
95b7e1c893Smrg    0x00290000,   /* rs300 */
96b7e1c893Smrg    0x00560000,   /* rv280 */
97b7e1c893Smrg    0x00780000,   /* r300 */
98b7e1c893Smrg    0x00770000,   /* r350 */
99b7e1c893Smrg    0x00780000,   /* rv350 */
100b7e1c893Smrg    0x00780000,   /* rv380 */
101b7e1c893Smrg    0x01080000,   /* r420 */
102b7e1c893Smrg    0x01080000,   /* rv410 */ /* FIXME: just values from r420 used... */
103b7e1c893Smrg    0x00780000,   /* rs400 */ /* FIXME: just values from rv380 used... */
104b7e1c893Smrg    0x00780000,   /* rs480 */ /* FIXME: just values from rv380 used... */
105b7e1c893Smrg};
106b7e1c893Smrg
107b7e1c893Smrgvoid
108b7e1c893SmrgRADEONGetTVDacAdjInfo(ScrnInfoPtr pScrn, radeon_tvdac_ptr tvdac)
109b7e1c893Smrg{
110b7e1c893Smrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
111b7e1c893Smrg
112b7e1c893Smrg    if (!RADEONGetDAC2InfoFromBIOS(pScrn, tvdac)) {
113b7e1c893Smrg	tvdac->ps2_tvdac_adj = default_tvdac_adj[info->ChipFamily];
114b7e1c893Smrg	if (info->IsMobility) { /* some mobility chips may different */
115b7e1c893Smrg	    if (info->ChipFamily == CHIP_FAMILY_RV250)
116b7e1c893Smrg		tvdac->ps2_tvdac_adj = 0x00880000;
117b7e1c893Smrg	}
118b7e1c893Smrg	tvdac->pal_tvdac_adj = tvdac->ps2_tvdac_adj;
119b7e1c893Smrg	tvdac->ntsc_tvdac_adj = tvdac->ps2_tvdac_adj;
120b7e1c893Smrg    }
121b7e1c893Smrg}
122b7e1c893Smrg
123b7e1c893Smrgvoid
124b7e1c893SmrgRADEONGetTMDSInfoFromTable(ScrnInfoPtr pScrn, radeon_tmds_ptr tmds)
125b7e1c893Smrg{
126b7e1c893Smrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
127b7e1c893Smrg    int i;
128b7e1c893Smrg
129b7e1c893Smrg    for (i = 0; i < 4; i++) {
130b7e1c893Smrg        tmds->tmds_pll[i].value = default_tmds_pll[info->ChipFamily][i].value;
131b7e1c893Smrg        tmds->tmds_pll[i].freq = default_tmds_pll[info->ChipFamily][i].freq;
132b7e1c893Smrg    }
133b7e1c893Smrg}
134b7e1c893Smrg
135b7e1c893Smrgvoid
136b7e1c893SmrgRADEONGetTMDSInfo(ScrnInfoPtr pScrn, radeon_tmds_ptr tmds)
137b7e1c893Smrg{
138b7e1c893Smrg    int i;
139b7e1c893Smrg
140b7e1c893Smrg    for (i = 0; i < 4; i++) {
141b7e1c893Smrg	tmds->tmds_pll[i].value = 0;
142b7e1c893Smrg	tmds->tmds_pll[i].freq = 0;
143b7e1c893Smrg    }
144b7e1c893Smrg
145b7e1c893Smrg    if (!RADEONGetTMDSInfoFromBIOS(pScrn, tmds))
146b7e1c893Smrg	RADEONGetTMDSInfoFromTable(pScrn, tmds);
147b7e1c893Smrg}
148b7e1c893Smrg
149b7e1c893Smrgvoid
150b7e1c893SmrgRADEONGetExtTMDSInfo(ScrnInfoPtr pScrn, radeon_dvo_ptr dvo)
151b7e1c893Smrg{
152b7e1c893Smrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
153b7e1c893Smrg
154b7e1c893Smrg    if (!info->IsAtomBios) {
155b7e1c893Smrg#if defined(__powerpc__)
156b7e1c893Smrg	dvo->dvo_i2c = legacy_setup_i2c_bus(RADEON_GPIO_MONID);
157b7e1c893Smrg	dvo->dvo_i2c_slave_addr = 0x70;
158b7e1c893Smrg#else
159b7e1c893Smrg	if (!RADEONGetExtTMDSInfoFromBIOS(pScrn, dvo)) {
160b7e1c893Smrg	    dvo->dvo_i2c = legacy_setup_i2c_bus(RADEON_GPIO_CRT2_DDC);
161b7e1c893Smrg	    dvo->dvo_i2c_slave_addr = 0x70;
162b7e1c893Smrg	}
163b7e1c893Smrg#endif
164c503f109Smrg	if (RADEONI2CInit(pScrn, &dvo->pI2CBus, "DVO", &dvo->dvo_i2c)) {
165b7e1c893Smrg	    dvo->DVOChip =
166c503f109Smrg		RADEONDVODeviceInit(dvo->pI2CBus, dvo->dvo_i2c_slave_addr);
167b7e1c893Smrg	    if (!dvo->DVOChip)
1682f39173dSmrg		free(dvo->pI2CBus);
169b7e1c893Smrg	}
170b7e1c893Smrg    }
171b7e1c893Smrg}
172b7e1c893Smrg
173b7e1c893Smrgstatic void
174b7e1c893SmrgRADEONGetPanelInfoFromReg (ScrnInfoPtr pScrn, radeon_lvds_ptr lvds)
175b7e1c893Smrg{
176b7e1c893Smrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
177b7e1c893Smrg    unsigned char *RADEONMMIO = info->MMIO;
178b7e1c893Smrg    radeon_native_mode_ptr native_mode = &lvds->native_mode;
179b7e1c893Smrg    uint32_t fp_vert_stretch = INREG(RADEON_FP_VERT_STRETCH);
180b7e1c893Smrg    uint32_t fp_horz_stretch = INREG(RADEON_FP_HORZ_STRETCH);
181b7e1c893Smrg
182b7e1c893Smrg    lvds->PanelPwrDly = 200;
183b7e1c893Smrg    if (fp_vert_stretch & RADEON_VERT_STRETCH_ENABLE) {
184b7e1c893Smrg	native_mode->PanelYRes = ((fp_vert_stretch & RADEON_VERT_PANEL_SIZE) >>
185b7e1c893Smrg				  RADEON_VERT_PANEL_SHIFT) + 1;
186b7e1c893Smrg    } else {
187b7e1c893Smrg	native_mode->PanelYRes = (INREG(RADEON_CRTC_V_TOTAL_DISP)>>16) + 1;
188b7e1c893Smrg    }
189b7e1c893Smrg    if (fp_horz_stretch & RADEON_HORZ_STRETCH_ENABLE) {
190b7e1c893Smrg	native_mode->PanelXRes = (((fp_horz_stretch & RADEON_HORZ_PANEL_SIZE) >>
191b7e1c893Smrg				   RADEON_HORZ_PANEL_SHIFT) + 1) * 8;
192b7e1c893Smrg    } else {
193b7e1c893Smrg	native_mode->PanelXRes = ((INREG(RADEON_CRTC_H_TOTAL_DISP)>>16) + 1) * 8;
194b7e1c893Smrg    }
195b7e1c893Smrg
196b7e1c893Smrg    if ((native_mode->PanelXRes < 640) || (native_mode->PanelYRes < 480)) {
197b7e1c893Smrg	native_mode->PanelXRes = 640;
198b7e1c893Smrg	native_mode->PanelYRes = 480;
199b7e1c893Smrg    }
200b7e1c893Smrg
201b7e1c893Smrg    // move this to crtc function
202b7e1c893Smrg    if (xf86ReturnOptValBool(info->Options, OPTION_LVDS_PROBE_PLL, TRUE)) {
203b7e1c893Smrg           uint32_t ppll_div_sel, ppll_val;
204b7e1c893Smrg
205b7e1c893Smrg           ppll_div_sel = INREG8(RADEON_CLOCK_CNTL_INDEX + 1) & 0x3;
206b7e1c893Smrg	   RADEONPllErrataAfterIndex(info);
207b7e1c893Smrg	   ppll_val = INPLL(pScrn, RADEON_PPLL_DIV_0 + ppll_div_sel);
208b7e1c893Smrg           if ((ppll_val & 0x000707ff) == 0x1bb)
209b7e1c893Smrg		   goto noprobe;
210b7e1c893Smrg	   info->FeedbackDivider = ppll_val & 0x7ff;
211b7e1c893Smrg	   info->PostDivider = (ppll_val >> 16) & 0x7;
212b7e1c893Smrg	   info->RefDivider = info->pll.reference_div;
213b7e1c893Smrg	   info->UseBiosDividers = TRUE;
214b7e1c893Smrg
215b7e1c893Smrg           xf86DrvMsg(pScrn->scrnIndex, X_INFO,
216b7e1c893Smrg                      "Existing panel PLL dividers will be used.\n");
217b7e1c893Smrg    }
218b7e1c893Smrg noprobe:
219b7e1c893Smrg
220b7e1c893Smrg    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
221b7e1c893Smrg	       "Panel size %dx%d is derived, this may not be correct.\n"
222b7e1c893Smrg		   "If not, use PanelSize option to overwrite this setting\n",
223b7e1c893Smrg	       native_mode->PanelXRes, native_mode->PanelYRes);
224b7e1c893Smrg}
225b7e1c893Smrg
226b7e1c893Smrgvoid
227b7e1c893SmrgRADEONGetLVDSInfo (ScrnInfoPtr pScrn, radeon_lvds_ptr lvds)
228b7e1c893Smrg{
229b7e1c893Smrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
230b7e1c893Smrg    radeon_native_mode_ptr native_mode = &lvds->native_mode;
231861b9feeSmrg    const char* s;
232b7e1c893Smrg
233b7e1c893Smrg    if (!RADEONGetLVDSInfoFromBIOS(pScrn, lvds))
234b7e1c893Smrg	RADEONGetPanelInfoFromReg(pScrn, lvds);
235b7e1c893Smrg
236b7e1c893Smrg    if ((s = xf86GetOptValString(info->Options, OPTION_PANEL_SIZE))) {
237b7e1c893Smrg	lvds->PanelPwrDly = 200;
238b7e1c893Smrg	if (sscanf (s, "%dx%d", &native_mode->PanelXRes, &native_mode->PanelYRes) != 2) {
239b7e1c893Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Invalid PanelSize option: %s\n", s);
240b7e1c893Smrg	    RADEONGetPanelInfoFromReg(pScrn, lvds);
241b7e1c893Smrg	}
242b7e1c893Smrg    }
243b7e1c893Smrg}
244b7e1c893Smrg
245209ff23fSmrgvoid
246209ff23fSmrgRADEONRestoreDACRegisters(ScrnInfoPtr pScrn,
247209ff23fSmrg			  RADEONSavePtr restore)
248209ff23fSmrg{
249209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
250209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
251209ff23fSmrg
252209ff23fSmrg    if (IS_R300_VARIANT)
253209ff23fSmrg	OUTREGP(RADEON_GPIOPAD_A, restore->gpiopad_a, ~1);
254209ff23fSmrg
255209ff23fSmrg    OUTREGP(RADEON_DAC_CNTL,
256209ff23fSmrg	    restore->dac_cntl,
257209ff23fSmrg	    RADEON_DAC_RANGE_CNTL |
258209ff23fSmrg	    RADEON_DAC_BLANKING);
259209ff23fSmrg
260209ff23fSmrg    OUTREG(RADEON_DAC_CNTL2, restore->dac2_cntl);
261209ff23fSmrg
262209ff23fSmrg    if ((info->ChipFamily != CHIP_FAMILY_RADEON) &&
263209ff23fSmrg	(info->ChipFamily != CHIP_FAMILY_R200))
264209ff23fSmrg    OUTREG (RADEON_TV_DAC_CNTL, restore->tv_dac_cntl);
265209ff23fSmrg
266209ff23fSmrg    OUTREG(RADEON_DISP_OUTPUT_CNTL, restore->disp_output_cntl);
267209ff23fSmrg
268209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_R200) ||
269209ff23fSmrg	IS_R300_VARIANT) {
270209ff23fSmrg	OUTREG(RADEON_DISP_TV_OUT_CNTL, restore->disp_tv_out_cntl);
271209ff23fSmrg    } else {
272209ff23fSmrg	OUTREG(RADEON_DISP_HW_DEBUG, restore->disp_hw_debug);
273209ff23fSmrg    }
274209ff23fSmrg
275209ff23fSmrg    OUTREG(RADEON_DAC_MACRO_CNTL, restore->dac_macro_cntl);
276209ff23fSmrg
277209ff23fSmrg    /* R200 DAC connected via DVO */
278209ff23fSmrg    if (info->ChipFamily == CHIP_FAMILY_R200)
279209ff23fSmrg	OUTREG(RADEON_FP2_GEN_CNTL, restore->fp2_gen_cntl);
280209ff23fSmrg}
281209ff23fSmrg
282209ff23fSmrg
283209ff23fSmrg/* Write TMDS registers */
284209ff23fSmrgvoid
285209ff23fSmrgRADEONRestoreFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore)
286209ff23fSmrg{
287209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
288209ff23fSmrg    RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
289209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
290209ff23fSmrg
291209ff23fSmrg    OUTREG(RADEON_TMDS_PLL_CNTL,        restore->tmds_pll_cntl);
292209ff23fSmrg    OUTREG(RADEON_TMDS_TRANSMITTER_CNTL,restore->tmds_transmitter_cntl);
293209ff23fSmrg    OUTREG(RADEON_FP_GEN_CNTL,          restore->fp_gen_cntl);
294209ff23fSmrg
295209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_RS400) ||
296209ff23fSmrg	(info->ChipFamily == CHIP_FAMILY_RS480)) {
297209ff23fSmrg	OUTREG(RS400_FP_2ND_GEN_CNTL, restore->fp_2nd_gen_cntl);
298209ff23fSmrg	/*OUTREG(RS400_TMDS2_CNTL, restore->tmds2_cntl);*/
299209ff23fSmrg	OUTREG(RS400_TMDS2_TRANSMITTER_CNTL, restore->tmds2_transmitter_cntl);
300209ff23fSmrg    }
301209ff23fSmrg
302209ff23fSmrg    /* old AIW Radeon has some BIOS initialization problem
303209ff23fSmrg     * with display buffer underflow, only occurs to DFP
304209ff23fSmrg     */
305209ff23fSmrg    if (!pRADEONEnt->HasCRTC2)
306209ff23fSmrg	OUTREG(RADEON_GRPH_BUFFER_CNTL,
307209ff23fSmrg	       INREG(RADEON_GRPH_BUFFER_CNTL) & ~0x7f0000);
308209ff23fSmrg
309209ff23fSmrg}
310209ff23fSmrg
311209ff23fSmrg/* Write FP2 registers */
312209ff23fSmrgvoid
313209ff23fSmrgRADEONRestoreFP2Registers(ScrnInfoPtr pScrn, RADEONSavePtr restore)
314209ff23fSmrg{
315209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
316209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
317209ff23fSmrg
318209ff23fSmrg    OUTREG(RADEON_FP2_GEN_CNTL,         restore->fp2_gen_cntl);
319209ff23fSmrg
320209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_RS400) ||
321209ff23fSmrg	(info->ChipFamily == CHIP_FAMILY_RS480))
322209ff23fSmrg	OUTREG(RS400_FP2_2_GEN_CNTL, restore->fp2_2_gen_cntl);
323209ff23fSmrg}
324209ff23fSmrg
325209ff23fSmrg/* Write RMX registers */
326209ff23fSmrgvoid
327209ff23fSmrgRADEONRestoreRMXRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore)
328209ff23fSmrg{
329209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
330209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
331209ff23fSmrg
332209ff23fSmrg    OUTREG(RADEON_FP_HORZ_STRETCH,      restore->fp_horz_stretch);
333209ff23fSmrg    OUTREG(RADEON_FP_VERT_STRETCH,      restore->fp_vert_stretch);
334209ff23fSmrg    OUTREG(RADEON_CRTC_MORE_CNTL,       restore->crtc_more_cntl);
335209ff23fSmrg    OUTREG(RADEON_FP_HORZ_VERT_ACTIVE,  restore->fp_horz_vert_active);
336209ff23fSmrg    OUTREG(RADEON_FP_H_SYNC_STRT_WID,   restore->fp_h_sync_strt_wid);
337209ff23fSmrg    OUTREG(RADEON_FP_V_SYNC_STRT_WID,   restore->fp_v_sync_strt_wid);
338209ff23fSmrg    OUTREG(RADEON_FP_CRTC_H_TOTAL_DISP, restore->fp_crtc_h_total_disp);
339209ff23fSmrg    OUTREG(RADEON_FP_CRTC_V_TOTAL_DISP, restore->fp_crtc_v_total_disp);
340209ff23fSmrg
341209ff23fSmrg}
342209ff23fSmrg
343209ff23fSmrg/* Write LVDS registers */
344209ff23fSmrgvoid
345209ff23fSmrgRADEONRestoreLVDSRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore)
346209ff23fSmrg{
347209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
348209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
349209ff23fSmrg
350209ff23fSmrg    if (info->IsMobility) {
351209ff23fSmrg	OUTREG(RADEON_LVDS_GEN_CNTL,  restore->lvds_gen_cntl);
352209ff23fSmrg	/*OUTREG(RADEON_LVDS_PLL_CNTL,  restore->lvds_pll_cntl);*/
353209ff23fSmrg
354209ff23fSmrg	if (info->ChipFamily == CHIP_FAMILY_RV410) {
355209ff23fSmrg	    OUTREG(RADEON_CLOCK_CNTL_INDEX, 0);
356209ff23fSmrg	}
357209ff23fSmrg    }
358209ff23fSmrg
359209ff23fSmrg}
360209ff23fSmrg
361209ff23fSmrgvoid
362209ff23fSmrgRADEONSaveDACRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save)
363209ff23fSmrg{
364209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
365209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
366209ff23fSmrg
367209ff23fSmrg    save->dac_cntl              = INREG(RADEON_DAC_CNTL);
368209ff23fSmrg    save->dac2_cntl             = INREG(RADEON_DAC_CNTL2);
369209ff23fSmrg    save->tv_dac_cntl           = INREG(RADEON_TV_DAC_CNTL);
370209ff23fSmrg    save->disp_output_cntl      = INREG(RADEON_DISP_OUTPUT_CNTL);
371209ff23fSmrg    save->disp_tv_out_cntl      = INREG(RADEON_DISP_TV_OUT_CNTL);
372209ff23fSmrg    save->disp_hw_debug         = INREG(RADEON_DISP_HW_DEBUG);
373209ff23fSmrg    save->dac_macro_cntl        = INREG(RADEON_DAC_MACRO_CNTL);
374209ff23fSmrg    save->gpiopad_a             = INREG(RADEON_GPIOPAD_A);
375209ff23fSmrg
376209ff23fSmrg}
377209ff23fSmrg
378209ff23fSmrg/* Read flat panel registers */
379209ff23fSmrgvoid
380209ff23fSmrgRADEONSaveFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save)
381209ff23fSmrg{
382209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
383209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
384209ff23fSmrg
385209ff23fSmrg    save->fp_gen_cntl          = INREG(RADEON_FP_GEN_CNTL);
386209ff23fSmrg    save->fp2_gen_cntl          = INREG (RADEON_FP2_GEN_CNTL);
387209ff23fSmrg    save->fp_horz_stretch      = INREG(RADEON_FP_HORZ_STRETCH);
388209ff23fSmrg    save->fp_vert_stretch      = INREG(RADEON_FP_VERT_STRETCH);
389209ff23fSmrg    save->fp_horz_vert_active  = INREG(RADEON_FP_HORZ_VERT_ACTIVE);
390209ff23fSmrg    save->crtc_more_cntl       = INREG(RADEON_CRTC_MORE_CNTL);
391209ff23fSmrg    save->lvds_gen_cntl        = INREG(RADEON_LVDS_GEN_CNTL);
392209ff23fSmrg    save->lvds_pll_cntl        = INREG(RADEON_LVDS_PLL_CNTL);
393209ff23fSmrg    save->tmds_pll_cntl        = INREG(RADEON_TMDS_PLL_CNTL);
394209ff23fSmrg    save->tmds_transmitter_cntl= INREG(RADEON_TMDS_TRANSMITTER_CNTL);
395209ff23fSmrg
396209ff23fSmrg    save->fp_h_sync_strt_wid   = INREG(RADEON_FP_H_SYNC_STRT_WID);
397209ff23fSmrg    save->fp_v_sync_strt_wid   = INREG(RADEON_FP_V_SYNC_STRT_WID);
398209ff23fSmrg    save->fp_crtc_h_total_disp = INREG(RADEON_FP_CRTC_H_TOTAL_DISP);
399209ff23fSmrg    save->fp_crtc_v_total_disp = INREG(RADEON_FP_CRTC_V_TOTAL_DISP);
400209ff23fSmrg
401209ff23fSmrg    if (info->ChipFamily == CHIP_FAMILY_RV280) {
402209ff23fSmrg	/* bit 22 of TMDS_PLL_CNTL is read-back inverted */
403209ff23fSmrg	save->tmds_pll_cntl ^= (1 << 22);
404209ff23fSmrg    }
405209ff23fSmrg
406209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_RS400) ||
407209ff23fSmrg	(info->ChipFamily == CHIP_FAMILY_RS480)) {
408209ff23fSmrg	save->fp_2nd_gen_cntl         = INREG(RS400_FP_2ND_GEN_CNTL);
409209ff23fSmrg	save->fp2_2_gen_cntl          = INREG(RS400_FP2_2_GEN_CNTL);
410209ff23fSmrg	save->tmds2_cntl              = INREG(RS400_TMDS2_CNTL);
411209ff23fSmrg	save->tmds2_transmitter_cntl  = INREG(RS400_TMDS2_TRANSMITTER_CNTL);
412209ff23fSmrg    }
413209ff23fSmrg
414209ff23fSmrg}
415209ff23fSmrg
416209ff23fSmrgBool
417209ff23fSmrgRADEONDVOReadByte(I2CDevPtr dvo, int addr, uint8_t *ch)
418209ff23fSmrg{
419209ff23fSmrg    if (!xf86I2CReadByte(dvo, addr, ch)) {
420209ff23fSmrg	xf86DrvMsg(dvo->pI2CBus->scrnIndex, X_ERROR,
421209ff23fSmrg		   "Unable to read from %s Slave %d.\n",
422209ff23fSmrg		   dvo->pI2CBus->BusName, dvo->SlaveAddr);
423209ff23fSmrg	return FALSE;
424209ff23fSmrg    }
425209ff23fSmrg    return TRUE;
426209ff23fSmrg}
427209ff23fSmrg
428209ff23fSmrgBool
429209ff23fSmrgRADEONDVOWriteByte(I2CDevPtr dvo, int addr, uint8_t ch)
430209ff23fSmrg{
431209ff23fSmrg    if (!xf86I2CWriteByte(dvo, addr, ch)) {
432209ff23fSmrg	xf86DrvMsg(dvo->pI2CBus->scrnIndex, X_ERROR,
433209ff23fSmrg		   "Unable to write to %s Slave %d.\n",
434209ff23fSmrg		   dvo->pI2CBus->BusName, dvo->SlaveAddr);
435209ff23fSmrg	return FALSE;
436209ff23fSmrg    }
437209ff23fSmrg    return TRUE;
438209ff23fSmrg}
439209ff23fSmrg
440209ff23fSmrgI2CDevPtr
441209ff23fSmrgRADEONDVODeviceInit(I2CBusPtr b, I2CSlaveAddr addr)
442209ff23fSmrg{
443209ff23fSmrg    I2CDevPtr dvo;
444209ff23fSmrg
4452f39173dSmrg    dvo = calloc(1, sizeof(I2CDevRec));
446209ff23fSmrg    if (dvo == NULL)
447209ff23fSmrg	return NULL;
448209ff23fSmrg
449209ff23fSmrg    dvo->DevName = "RADEON DVO Controller";
450209ff23fSmrg    dvo->SlaveAddr = addr;
451209ff23fSmrg    dvo->pI2CBus = b;
452209ff23fSmrg    dvo->StartTimeout = b->StartTimeout;
453209ff23fSmrg    dvo->BitTimeout = b->BitTimeout;
454209ff23fSmrg    dvo->AcknTimeout = b->AcknTimeout;
455209ff23fSmrg    dvo->ByteTimeout = b->ByteTimeout;
456209ff23fSmrg
457209ff23fSmrg    if (xf86I2CDevInit(dvo)) {
458209ff23fSmrg	return dvo;
459209ff23fSmrg    }
460209ff23fSmrg
4612f39173dSmrg    free(dvo);
462209ff23fSmrg    return NULL;
463209ff23fSmrg}
464209ff23fSmrg
465209ff23fSmrgstatic void
466209ff23fSmrgRADEONRestoreDVOChip(ScrnInfoPtr pScrn, xf86OutputPtr output)
467209ff23fSmrg{
468209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
469b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
470b7e1c893Smrg    radeon_dvo_ptr dvo = NULL;
471209ff23fSmrg
472b7e1c893Smrg    if (radeon_encoder == NULL)
473209ff23fSmrg	return;
474209ff23fSmrg
475b7e1c893Smrg    dvo = (radeon_dvo_ptr)radeon_encoder->dev_priv;
476b7e1c893Smrg
477b7e1c893Smrg    if (dvo == NULL)
478b7e1c893Smrg	return;
479209ff23fSmrg
480b7e1c893Smrg    if (!dvo->DVOChip)
481b7e1c893Smrg	return;
482b7e1c893Smrg
483c503f109Smrg    RADEONI2CDoLock(output, dvo->pI2CBus, TRUE);
484209ff23fSmrg    if (!RADEONInitExtTMDSInfoFromBIOS(output)) {
485b7e1c893Smrg	if (dvo->DVOChip) {
486209ff23fSmrg	    switch(info->ext_tmds_chip) {
487209ff23fSmrg	    case RADEON_SIL_164:
488b7e1c893Smrg		RADEONDVOWriteByte(dvo->DVOChip, 0x08, 0x30);
489b7e1c893Smrg		RADEONDVOWriteByte(dvo->DVOChip, 0x09, 0x00);
490b7e1c893Smrg		RADEONDVOWriteByte(dvo->DVOChip, 0x0a, 0x90);
491b7e1c893Smrg		RADEONDVOWriteByte(dvo->DVOChip, 0x0c, 0x89);
492b7e1c893Smrg		RADEONDVOWriteByte(dvo->DVOChip, 0x08, 0x3b);
493209ff23fSmrg		break;
494209ff23fSmrg#if 0
495209ff23fSmrg		/* needs work see bug 10418 */
496209ff23fSmrg	    case RADEON_SIL_1178:
497b7e1c893Smrg		RADEONDVOWriteByte(dvo->DVOChip, 0x0f, 0x44);
498b7e1c893Smrg		RADEONDVOWriteByte(dvo->DVOChip, 0x0f, 0x4c);
499b7e1c893Smrg		RADEONDVOWriteByte(dvo->DVOChip, 0x0e, 0x01);
500b7e1c893Smrg		RADEONDVOWriteByte(dvo->DVOChip, 0x0a, 0x80);
501b7e1c893Smrg                RADEONDVOWriteByte(dvo->DVOChip, 0x09, 0x30);
502b7e1c893Smrg                RADEONDVOWriteByte(dvo->DVOChip, 0x0c, 0xc9);
503b7e1c893Smrg                RADEONDVOWriteByte(dvo->DVOChip, 0x0d, 0x70);
504b7e1c893Smrg                RADEONDVOWriteByte(dvo->DVOChip, 0x08, 0x32);
505b7e1c893Smrg                RADEONDVOWriteByte(dvo->DVOChip, 0x08, 0x33);
506209ff23fSmrg		break;
507209ff23fSmrg#endif
508209ff23fSmrg	    default:
509209ff23fSmrg		break;
510209ff23fSmrg	    }
511209ff23fSmrg	}
512209ff23fSmrg    }
513c503f109Smrg    RADEONI2CDoLock(output, dvo->pI2CBus, FALSE);
514209ff23fSmrg}
515209ff23fSmrg
516209ff23fSmrg#if 0
517209ff23fSmrgstatic RADEONMonitorType
518209ff23fSmrgRADEONCrtIsPhysicallyConnected(ScrnInfoPtr pScrn, int IsCrtDac)
519209ff23fSmrg{
520209ff23fSmrg    RADEONInfoPtr info       = RADEONPTR(pScrn);
521209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
522209ff23fSmrg    int		  bConnected = 0;
523209ff23fSmrg
524209ff23fSmrg    /* the monitor either wasn't connected or it is a non-DDC CRT.
525209ff23fSmrg     * try to probe it
526209ff23fSmrg     */
527209ff23fSmrg    if(IsCrtDac) {
528209ff23fSmrg	unsigned long ulOrigVCLK_ECP_CNTL;
529209ff23fSmrg	unsigned long ulOrigDAC_CNTL;
530209ff23fSmrg	unsigned long ulOrigDAC_MACRO_CNTL;
531209ff23fSmrg	unsigned long ulOrigDAC_EXT_CNTL;
532209ff23fSmrg	unsigned long ulOrigCRTC_EXT_CNTL;
533209ff23fSmrg	unsigned long ulData;
534209ff23fSmrg	unsigned long ulMask;
535209ff23fSmrg
536209ff23fSmrg	ulOrigVCLK_ECP_CNTL = INPLL(pScrn, RADEON_VCLK_ECP_CNTL);
537209ff23fSmrg
538209ff23fSmrg	ulData              = ulOrigVCLK_ECP_CNTL;
539209ff23fSmrg	ulData             &= ~(RADEON_PIXCLK_ALWAYS_ONb
540209ff23fSmrg				| RADEON_PIXCLK_DAC_ALWAYS_ONb);
541209ff23fSmrg	ulMask              = ~(RADEON_PIXCLK_ALWAYS_ONb
542209ff23fSmrg				|RADEON_PIXCLK_DAC_ALWAYS_ONb);
543209ff23fSmrg	OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, ulData, ulMask);
544209ff23fSmrg
545209ff23fSmrg	ulOrigCRTC_EXT_CNTL = INREG(RADEON_CRTC_EXT_CNTL);
546209ff23fSmrg	ulData              = ulOrigCRTC_EXT_CNTL;
547209ff23fSmrg	ulData             |= RADEON_CRTC_CRT_ON;
548209ff23fSmrg	OUTREG(RADEON_CRTC_EXT_CNTL, ulData);
549209ff23fSmrg
550209ff23fSmrg	ulOrigDAC_EXT_CNTL = INREG(RADEON_DAC_EXT_CNTL);
551209ff23fSmrg	ulData             = ulOrigDAC_EXT_CNTL;
552209ff23fSmrg	ulData            &= ~RADEON_DAC_FORCE_DATA_MASK;
553209ff23fSmrg	ulData            |=  (RADEON_DAC_FORCE_BLANK_OFF_EN
554209ff23fSmrg			       |RADEON_DAC_FORCE_DATA_EN
555209ff23fSmrg			       |RADEON_DAC_FORCE_DATA_SEL_MASK);
556209ff23fSmrg	if ((info->ChipFamily == CHIP_FAMILY_RV250) ||
557209ff23fSmrg	    (info->ChipFamily == CHIP_FAMILY_RV280))
558209ff23fSmrg	    ulData |= (0x01b6 << RADEON_DAC_FORCE_DATA_SHIFT);
559209ff23fSmrg	else
560209ff23fSmrg	    ulData |= (0x01ac << RADEON_DAC_FORCE_DATA_SHIFT);
561209ff23fSmrg
562209ff23fSmrg	OUTREG(RADEON_DAC_EXT_CNTL, ulData);
563209ff23fSmrg
564209ff23fSmrg	/* turn on power so testing can go through */
565209ff23fSmrg	ulOrigDAC_CNTL = INREG(RADEON_DAC_CNTL);
566209ff23fSmrg	ulOrigDAC_CNTL &= ~RADEON_DAC_PDWN;
567209ff23fSmrg	OUTREG(RADEON_DAC_CNTL, ulOrigDAC_CNTL);
568209ff23fSmrg
569209ff23fSmrg	ulOrigDAC_MACRO_CNTL = INREG(RADEON_DAC_MACRO_CNTL);
570209ff23fSmrg	ulOrigDAC_MACRO_CNTL &= ~(RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G |
571209ff23fSmrg				  RADEON_DAC_PDWN_B);
572209ff23fSmrg	OUTREG(RADEON_DAC_MACRO_CNTL, ulOrigDAC_MACRO_CNTL);
573209ff23fSmrg
574209ff23fSmrg	/* Enable comparators and set DAC range to PS2 (VGA) output level */
575209ff23fSmrg	ulData = ulOrigDAC_CNTL;
576209ff23fSmrg	ulData |= RADEON_DAC_CMP_EN;
577209ff23fSmrg	ulData &= ~RADEON_DAC_RANGE_CNTL_MASK;
578209ff23fSmrg	ulData |= 0x2;
579209ff23fSmrg	OUTREG(RADEON_DAC_CNTL, ulData);
580209ff23fSmrg
581209ff23fSmrg	/* Settle down */
582209ff23fSmrg	usleep(10000);
583209ff23fSmrg
584209ff23fSmrg	/* Read comparators */
585209ff23fSmrg	ulData     = INREG(RADEON_DAC_CNTL);
586209ff23fSmrg	bConnected =  (RADEON_DAC_CMP_OUTPUT & ulData)?1:0;
587209ff23fSmrg
588209ff23fSmrg	/* Restore things */
589209ff23fSmrg	ulData    = ulOrigVCLK_ECP_CNTL;
590209ff23fSmrg	ulMask    = 0xFFFFFFFFL;
591209ff23fSmrg	OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, ulData, ulMask);
592209ff23fSmrg
593209ff23fSmrg	OUTREG(RADEON_DAC_CNTL,      ulOrigDAC_CNTL     );
594209ff23fSmrg	OUTREG(RADEON_DAC_EXT_CNTL,  ulOrigDAC_EXT_CNTL );
595209ff23fSmrg	OUTREG(RADEON_CRTC_EXT_CNTL, ulOrigCRTC_EXT_CNTL);
596209ff23fSmrg
597209ff23fSmrg	if (!bConnected) {
598209ff23fSmrg	    /* Power DAC down if CRT is not connected */
599209ff23fSmrg            ulOrigDAC_MACRO_CNTL = INREG(RADEON_DAC_MACRO_CNTL);
600209ff23fSmrg            ulOrigDAC_MACRO_CNTL |= (RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G |
601209ff23fSmrg	    	RADEON_DAC_PDWN_B);
602209ff23fSmrg            OUTREG(RADEON_DAC_MACRO_CNTL, ulOrigDAC_MACRO_CNTL);
603209ff23fSmrg
604209ff23fSmrg	    ulData = INREG(RADEON_DAC_CNTL);
605209ff23fSmrg	    ulData |= RADEON_DAC_PDWN;
606209ff23fSmrg	    OUTREG(RADEON_DAC_CNTL, ulData);
607209ff23fSmrg    	}
608209ff23fSmrg    } else { /* TV DAC */
609209ff23fSmrg
610209ff23fSmrg        /* This doesn't seem to work reliably (maybe worse on some OEM cards),
611209ff23fSmrg           for now we always return false. If one wants to connected a
612209ff23fSmrg           non-DDC monitor on the DVI port when CRT port is also connected,
613209ff23fSmrg           he will need to explicitly tell the driver in the config file
614209ff23fSmrg           with Option MonitorLayout.
615209ff23fSmrg        */
616209ff23fSmrg        bConnected = FALSE;
617209ff23fSmrg
618209ff23fSmrg#if 0
619209ff23fSmrg	if (info->ChipFamily == CHIP_FAMILY_R200) {
620209ff23fSmrg	    unsigned long ulOrigGPIO_MONID;
621209ff23fSmrg	    unsigned long ulOrigFP2_GEN_CNTL;
622209ff23fSmrg	    unsigned long ulOrigDISP_OUTPUT_CNTL;
623209ff23fSmrg	    unsigned long ulOrigCRTC2_GEN_CNTL;
624209ff23fSmrg	    unsigned long ulOrigDISP_LIN_TRANS_GRPH_A;
625209ff23fSmrg	    unsigned long ulOrigDISP_LIN_TRANS_GRPH_B;
626209ff23fSmrg	    unsigned long ulOrigDISP_LIN_TRANS_GRPH_C;
627209ff23fSmrg	    unsigned long ulOrigDISP_LIN_TRANS_GRPH_D;
628209ff23fSmrg	    unsigned long ulOrigDISP_LIN_TRANS_GRPH_E;
629209ff23fSmrg	    unsigned long ulOrigDISP_LIN_TRANS_GRPH_F;
630209ff23fSmrg	    unsigned long ulOrigCRTC2_H_TOTAL_DISP;
631209ff23fSmrg	    unsigned long ulOrigCRTC2_V_TOTAL_DISP;
632209ff23fSmrg	    unsigned long ulOrigCRTC2_H_SYNC_STRT_WID;
633209ff23fSmrg	    unsigned long ulOrigCRTC2_V_SYNC_STRT_WID;
634209ff23fSmrg	    unsigned long ulData, i;
635209ff23fSmrg
636209ff23fSmrg	    ulOrigGPIO_MONID = INREG(RADEON_GPIO_MONID);
637209ff23fSmrg	    ulOrigFP2_GEN_CNTL = INREG(RADEON_FP2_GEN_CNTL);
638209ff23fSmrg	    ulOrigDISP_OUTPUT_CNTL = INREG(RADEON_DISP_OUTPUT_CNTL);
639209ff23fSmrg	    ulOrigCRTC2_GEN_CNTL = INREG(RADEON_CRTC2_GEN_CNTL);
640209ff23fSmrg	    ulOrigDISP_LIN_TRANS_GRPH_A = INREG(RADEON_DISP_LIN_TRANS_GRPH_A);
641209ff23fSmrg	    ulOrigDISP_LIN_TRANS_GRPH_B = INREG(RADEON_DISP_LIN_TRANS_GRPH_B);
642209ff23fSmrg	    ulOrigDISP_LIN_TRANS_GRPH_C = INREG(RADEON_DISP_LIN_TRANS_GRPH_C);
643209ff23fSmrg	    ulOrigDISP_LIN_TRANS_GRPH_D = INREG(RADEON_DISP_LIN_TRANS_GRPH_D);
644209ff23fSmrg	    ulOrigDISP_LIN_TRANS_GRPH_E = INREG(RADEON_DISP_LIN_TRANS_GRPH_E);
645209ff23fSmrg	    ulOrigDISP_LIN_TRANS_GRPH_F = INREG(RADEON_DISP_LIN_TRANS_GRPH_F);
646209ff23fSmrg
647209ff23fSmrg	    ulOrigCRTC2_H_TOTAL_DISP = INREG(RADEON_CRTC2_H_TOTAL_DISP);
648209ff23fSmrg	    ulOrigCRTC2_V_TOTAL_DISP = INREG(RADEON_CRTC2_V_TOTAL_DISP);
649209ff23fSmrg	    ulOrigCRTC2_H_SYNC_STRT_WID = INREG(RADEON_CRTC2_H_SYNC_STRT_WID);
650209ff23fSmrg	    ulOrigCRTC2_V_SYNC_STRT_WID = INREG(RADEON_CRTC2_V_SYNC_STRT_WID);
651209ff23fSmrg
652209ff23fSmrg	    ulData     = INREG(RADEON_GPIO_MONID);
653209ff23fSmrg	    ulData    &= ~RADEON_GPIO_A_0;
654209ff23fSmrg	    OUTREG(RADEON_GPIO_MONID, ulData);
655209ff23fSmrg
656209ff23fSmrg	    OUTREG(RADEON_FP2_GEN_CNTL, 0x0a000c0c);
657209ff23fSmrg
658209ff23fSmrg	    OUTREG(RADEON_DISP_OUTPUT_CNTL, 0x00000012);
659209ff23fSmrg
660209ff23fSmrg	    OUTREG(RADEON_CRTC2_GEN_CNTL, 0x06000000);
661209ff23fSmrg	    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_A, 0x00000000);
662209ff23fSmrg	    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_B, 0x000003f0);
663209ff23fSmrg	    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_C, 0x00000000);
664209ff23fSmrg	    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_D, 0x000003f0);
665209ff23fSmrg	    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_E, 0x00000000);
666209ff23fSmrg	    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_F, 0x000003f0);
667209ff23fSmrg	    OUTREG(RADEON_CRTC2_H_TOTAL_DISP, 0x01000008);
668209ff23fSmrg	    OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, 0x00000800);
669209ff23fSmrg	    OUTREG(RADEON_CRTC2_V_TOTAL_DISP, 0x00080001);
670209ff23fSmrg	    OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, 0x00000080);
671209ff23fSmrg
672209ff23fSmrg	    for (i = 0; i < 200; i++) {
673209ff23fSmrg		ulData     = INREG(RADEON_GPIO_MONID);
674209ff23fSmrg		bConnected = (ulData & RADEON_GPIO_Y_0)?1:0;
675209ff23fSmrg		if (!bConnected) break;
676209ff23fSmrg
677209ff23fSmrg		usleep(1000);
678209ff23fSmrg	    }
679209ff23fSmrg
680209ff23fSmrg	    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_A, ulOrigDISP_LIN_TRANS_GRPH_A);
681209ff23fSmrg	    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_B, ulOrigDISP_LIN_TRANS_GRPH_B);
682209ff23fSmrg	    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_C, ulOrigDISP_LIN_TRANS_GRPH_C);
683209ff23fSmrg	    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_D, ulOrigDISP_LIN_TRANS_GRPH_D);
684209ff23fSmrg	    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_E, ulOrigDISP_LIN_TRANS_GRPH_E);
685209ff23fSmrg	    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_F, ulOrigDISP_LIN_TRANS_GRPH_F);
686209ff23fSmrg	    OUTREG(RADEON_CRTC2_H_TOTAL_DISP, ulOrigCRTC2_H_TOTAL_DISP);
687209ff23fSmrg	    OUTREG(RADEON_CRTC2_V_TOTAL_DISP, ulOrigCRTC2_V_TOTAL_DISP);
688209ff23fSmrg	    OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, ulOrigCRTC2_H_SYNC_STRT_WID);
689209ff23fSmrg	    OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, ulOrigCRTC2_V_SYNC_STRT_WID);
690209ff23fSmrg	    OUTREG(RADEON_CRTC2_GEN_CNTL, ulOrigCRTC2_GEN_CNTL);
691209ff23fSmrg	    OUTREG(RADEON_DISP_OUTPUT_CNTL, ulOrigDISP_OUTPUT_CNTL);
692209ff23fSmrg	    OUTREG(RADEON_FP2_GEN_CNTL, ulOrigFP2_GEN_CNTL);
693209ff23fSmrg	    OUTREG(RADEON_GPIO_MONID, ulOrigGPIO_MONID);
694209ff23fSmrg        } else {
695209ff23fSmrg	    unsigned long ulOrigPIXCLKSDATA;
696209ff23fSmrg	    unsigned long ulOrigTV_MASTER_CNTL;
697209ff23fSmrg	    unsigned long ulOrigTV_DAC_CNTL;
698209ff23fSmrg	    unsigned long ulOrigTV_PRE_DAC_MUX_CNTL;
699209ff23fSmrg	    unsigned long ulOrigDAC_CNTL2;
700209ff23fSmrg	    unsigned long ulData;
701209ff23fSmrg	    unsigned long ulMask;
702209ff23fSmrg
703209ff23fSmrg	    ulOrigPIXCLKSDATA = INPLL(pScrn, RADEON_PIXCLKS_CNTL);
704209ff23fSmrg
705209ff23fSmrg	    ulData            = ulOrigPIXCLKSDATA;
706209ff23fSmrg	    ulData           &= ~(RADEON_PIX2CLK_ALWAYS_ONb
707209ff23fSmrg				  | RADEON_PIX2CLK_DAC_ALWAYS_ONb);
708209ff23fSmrg	    ulMask            = ~(RADEON_PIX2CLK_ALWAYS_ONb
709209ff23fSmrg			  | RADEON_PIX2CLK_DAC_ALWAYS_ONb);
710209ff23fSmrg	    OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, ulData, ulMask);
711209ff23fSmrg
712209ff23fSmrg	    ulOrigTV_MASTER_CNTL = INREG(RADEON_TV_MASTER_CNTL);
713209ff23fSmrg	    ulData               = ulOrigTV_MASTER_CNTL;
714209ff23fSmrg	    ulData              &= ~RADEON_TVCLK_ALWAYS_ONb;
715209ff23fSmrg	    OUTREG(RADEON_TV_MASTER_CNTL, ulData);
716209ff23fSmrg
717209ff23fSmrg	    ulOrigDAC_CNTL2 = INREG(RADEON_DAC_CNTL2);
718209ff23fSmrg	    ulData          = ulOrigDAC_CNTL2;
719209ff23fSmrg	    ulData          &= ~RADEON_DAC2_DAC2_CLK_SEL;
720209ff23fSmrg	    OUTREG(RADEON_DAC_CNTL2, ulData);
721209ff23fSmrg
722209ff23fSmrg	    ulOrigTV_DAC_CNTL = INREG(RADEON_TV_DAC_CNTL);
723209ff23fSmrg
724209ff23fSmrg	    ulData  = 0x00880213;
725209ff23fSmrg	    OUTREG(RADEON_TV_DAC_CNTL, ulData);
726209ff23fSmrg
727209ff23fSmrg	    ulOrigTV_PRE_DAC_MUX_CNTL = INREG(RADEON_TV_PRE_DAC_MUX_CNTL);
728209ff23fSmrg
729209ff23fSmrg	    ulData  =  (RADEON_Y_RED_EN
730209ff23fSmrg			| RADEON_C_GRN_EN
731209ff23fSmrg			| RADEON_CMP_BLU_EN
732209ff23fSmrg			| RADEON_RED_MX_FORCE_DAC_DATA
733209ff23fSmrg			| RADEON_GRN_MX_FORCE_DAC_DATA
734209ff23fSmrg			| RADEON_BLU_MX_FORCE_DAC_DATA);
735209ff23fSmrg            if (IS_R300_VARIANT)
736209ff23fSmrg		ulData |= 0x180 << RADEON_TV_FORCE_DAC_DATA_SHIFT;
737209ff23fSmrg	    else
738209ff23fSmrg		ulData |= 0x1f5 << RADEON_TV_FORCE_DAC_DATA_SHIFT;
739209ff23fSmrg	    OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, ulData);
740209ff23fSmrg
741209ff23fSmrg	    usleep(10000);
742209ff23fSmrg
743209ff23fSmrg	    ulData     = INREG(RADEON_TV_DAC_CNTL);
744209ff23fSmrg	    bConnected = (ulData & RADEON_TV_DAC_CMPOUT)?1:0;
745209ff23fSmrg
746209ff23fSmrg	    ulData    = ulOrigPIXCLKSDATA;
747209ff23fSmrg	    ulMask    = 0xFFFFFFFFL;
748209ff23fSmrg	    OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, ulData, ulMask);
749209ff23fSmrg
750209ff23fSmrg	    OUTREG(RADEON_TV_MASTER_CNTL, ulOrigTV_MASTER_CNTL);
751209ff23fSmrg	    OUTREG(RADEON_DAC_CNTL2, ulOrigDAC_CNTL2);
752209ff23fSmrg	    OUTREG(RADEON_TV_DAC_CNTL, ulOrigTV_DAC_CNTL);
753209ff23fSmrg	    OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, ulOrigTV_PRE_DAC_MUX_CNTL);
754209ff23fSmrg	}
755209ff23fSmrg#endif
756209ff23fSmrg	return MT_UNKNOWN;
757209ff23fSmrg    }
758209ff23fSmrg
759209ff23fSmrg    return(bConnected ? MT_CRT : MT_NONE);
760209ff23fSmrg}
761209ff23fSmrg#endif
762209ff23fSmrg
763209ff23fSmrgRADEONMonitorType
764b7e1c893Smrglegacy_dac_detect(xf86OutputPtr output)
765209ff23fSmrg{
766b7e1c893Smrg    ScrnInfoPtr pScrn = output->scrn;
767209ff23fSmrg    RADEONInfoPtr info      = RADEONPTR(pScrn);
768209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
769209ff23fSmrg    RADEONMonitorType found = MT_NONE;
770209ff23fSmrg
771b7e1c893Smrg    if (radeon_output->devices & (ATOM_DEVICE_TV_SUPPORT)) {
772209ff23fSmrg	if (xf86ReturnOptValBool(info->Options, OPTION_FORCE_TVOUT, FALSE)) {
773b7e1c893Smrg	    if (radeon_output->ConnectorType == CONNECTOR_STV)
774209ff23fSmrg		found = MT_STV;
775209ff23fSmrg	    else
776209ff23fSmrg		found = MT_CTV;
777209ff23fSmrg	} else {
778b7e1c893Smrg	    if (radeon_output->load_detection)
779b7e1c893Smrg		found = radeon_detect_tv(pScrn);
780b7e1c893Smrg	}
781b7e1c893Smrg    } else if (radeon_output->devices & (ATOM_DEVICE_CRT2_SUPPORT)) {
782b7e1c893Smrg	if (info->encoders[ATOM_DEVICE_CRT2_INDEX] &&
783b7e1c893Smrg	    (info->encoders[ATOM_DEVICE_CRT2_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1)) {
784b7e1c893Smrg	    if (radeon_output->load_detection)
785b7e1c893Smrg		found = radeon_detect_primary_dac(pScrn, TRUE);
786b7e1c893Smrg	} else {
787b7e1c893Smrg	    if (radeon_output->load_detection) {
788b7e1c893Smrg		if (info->ChipFamily == CHIP_FAMILY_R200)
789b7e1c893Smrg		    found = radeon_detect_ext_dac(pScrn);
790209ff23fSmrg		else
791b7e1c893Smrg		    found = radeon_detect_tv_dac(pScrn, TRUE);
792209ff23fSmrg	    }
793209ff23fSmrg	}
794b7e1c893Smrg    } else if (radeon_output->devices & (ATOM_DEVICE_CRT1_SUPPORT)) {
795b7e1c893Smrg	if (info->encoders[ATOM_DEVICE_CRT1_INDEX] &&
796b7e1c893Smrg	    (info->encoders[ATOM_DEVICE_CRT1_INDEX]->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1)) {
797209ff23fSmrg	    if (radeon_output->load_detection)
798209ff23fSmrg		found = radeon_detect_primary_dac(pScrn, TRUE);
799b7e1c893Smrg	} else {
800209ff23fSmrg	    if (radeon_output->load_detection) {
801209ff23fSmrg		if (info->ChipFamily == CHIP_FAMILY_R200)
802209ff23fSmrg		    found = radeon_detect_ext_dac(pScrn);
803209ff23fSmrg		else
804209ff23fSmrg		    found = radeon_detect_tv_dac(pScrn, TRUE);
805b7e1c893Smrg	    }
806209ff23fSmrg	}
807209ff23fSmrg    }
808209ff23fSmrg
809209ff23fSmrg    return found;
810209ff23fSmrg}
811209ff23fSmrg
812209ff23fSmrg/*
813209ff23fSmrg * Powering done DAC, needed for DPMS problem with ViewSonic P817 (or its variant).
814209ff23fSmrg *
815209ff23fSmrg */
816209ff23fSmrgstatic void
817209ff23fSmrgRADEONDacPowerSet(ScrnInfoPtr pScrn, Bool IsOn, Bool IsPrimaryDAC)
818209ff23fSmrg{
819209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
820209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
821209ff23fSmrg
822209ff23fSmrg    if (IsPrimaryDAC) {
823209ff23fSmrg	uint32_t dac_cntl;
824209ff23fSmrg	uint32_t dac_macro_cntl = 0;
825209ff23fSmrg	dac_cntl = INREG(RADEON_DAC_CNTL);
826209ff23fSmrg	dac_macro_cntl = INREG(RADEON_DAC_MACRO_CNTL);
827209ff23fSmrg	if (IsOn) {
828209ff23fSmrg	    dac_cntl &= ~RADEON_DAC_PDWN;
829209ff23fSmrg	    dac_macro_cntl &= ~(RADEON_DAC_PDWN_R |
830209ff23fSmrg				RADEON_DAC_PDWN_G |
831209ff23fSmrg				RADEON_DAC_PDWN_B);
832209ff23fSmrg	} else {
833209ff23fSmrg	    dac_cntl |= RADEON_DAC_PDWN;
834209ff23fSmrg	    dac_macro_cntl |= (RADEON_DAC_PDWN_R |
835209ff23fSmrg			       RADEON_DAC_PDWN_G |
836209ff23fSmrg			       RADEON_DAC_PDWN_B);
837209ff23fSmrg	}
838209ff23fSmrg	OUTREG(RADEON_DAC_CNTL, dac_cntl);
839209ff23fSmrg	OUTREG(RADEON_DAC_MACRO_CNTL, dac_macro_cntl);
840209ff23fSmrg    } else {
841209ff23fSmrg	uint32_t tv_dac_cntl;
842209ff23fSmrg	uint32_t fp2_gen_cntl;
843209ff23fSmrg
844b7e1c893Smrg	switch(info->ChipFamily) {
845209ff23fSmrg	case CHIP_FAMILY_R420:
846209ff23fSmrg	case CHIP_FAMILY_RV410:
847209ff23fSmrg	    tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL);
848209ff23fSmrg	    if (IsOn) {
849209ff23fSmrg		tv_dac_cntl &= ~(R420_TV_DAC_RDACPD |
850209ff23fSmrg				 R420_TV_DAC_GDACPD |
851209ff23fSmrg				 R420_TV_DAC_BDACPD |
852209ff23fSmrg				 RADEON_TV_DAC_BGSLEEP);
853209ff23fSmrg	    } else {
854209ff23fSmrg		tv_dac_cntl |= (R420_TV_DAC_RDACPD |
855209ff23fSmrg				R420_TV_DAC_GDACPD |
856209ff23fSmrg				R420_TV_DAC_BDACPD |
857209ff23fSmrg				RADEON_TV_DAC_BGSLEEP);
858209ff23fSmrg	    }
859209ff23fSmrg	    OUTREG(RADEON_TV_DAC_CNTL, tv_dac_cntl);
860209ff23fSmrg	    break;
861209ff23fSmrg	case CHIP_FAMILY_R200:
862209ff23fSmrg	    fp2_gen_cntl = INREG(RADEON_FP2_GEN_CNTL);
863209ff23fSmrg	    if (IsOn) {
864209ff23fSmrg		fp2_gen_cntl |= RADEON_FP2_DVO_EN;
865209ff23fSmrg	    } else {
866209ff23fSmrg		fp2_gen_cntl &= ~RADEON_FP2_DVO_EN;
867209ff23fSmrg	    }
868209ff23fSmrg	    OUTREG(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
869209ff23fSmrg	    break;
870209ff23fSmrg	default:
871209ff23fSmrg	    tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL);
872209ff23fSmrg	    if (IsOn) {
873209ff23fSmrg		tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD |
874209ff23fSmrg				 RADEON_TV_DAC_GDACPD |
875209ff23fSmrg				 RADEON_TV_DAC_BDACPD |
876209ff23fSmrg				 RADEON_TV_DAC_BGSLEEP);
877209ff23fSmrg	    } else {
878209ff23fSmrg		tv_dac_cntl |= (RADEON_TV_DAC_RDACPD |
879209ff23fSmrg				RADEON_TV_DAC_GDACPD |
880209ff23fSmrg				RADEON_TV_DAC_BDACPD |
881209ff23fSmrg				RADEON_TV_DAC_BGSLEEP);
882209ff23fSmrg	    }
883209ff23fSmrg	    OUTREG(RADEON_TV_DAC_CNTL, tv_dac_cntl);
884209ff23fSmrg	    break;
885209ff23fSmrg	}
886209ff23fSmrg    }
887209ff23fSmrg}
888209ff23fSmrg
889b7e1c893Smrgvoid
890b7e1c893Smrglegacy_output_dpms(xf86OutputPtr output, int mode)
891209ff23fSmrg{
892209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
893209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
894209ff23fSmrg    RADEONSavePtr save = info->ModeReg;
895209ff23fSmrg    unsigned char * RADEONMMIO = info->MMIO;
896209ff23fSmrg    unsigned long tmp;
897b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
898b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
899209ff23fSmrg
900b7e1c893Smrg    if (radeon_encoder == NULL)
901b7e1c893Smrg	return;
902209ff23fSmrg
903b7e1c893Smrg    switch(mode) {
904b7e1c893Smrg    case DPMSModeOn:
905b7e1c893Smrg	radeon_encoder->devices |= radeon_output->active_device;
906b7e1c893Smrg	switch (radeon_encoder->encoder_id) {
907b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_LVDS:
908b7e1c893Smrg	{
909b7e1c893Smrg	    radeon_lvds_ptr lvds = (radeon_lvds_ptr)radeon_encoder->dev_priv;
910b7e1c893Smrg	    if (lvds == NULL)
911b7e1c893Smrg		return;
912b7e1c893Smrg	    ErrorF("enable LVDS\n");
913b7e1c893Smrg	    tmp = INREG(RADEON_LVDS_GEN_CNTL);
914b7e1c893Smrg	    tmp |= (RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN);
915ad43ddacSmrg#if defined(__powerpc__)
916ad43ddacSmrg	    /* not sure if this is needed on non-Macs */
917ad43ddacSmrg	    if (info->MacModel)
918ad43ddacSmrg		tmp |= RADEON_LVDS_BL_MOD_EN;
919ad43ddacSmrg#endif
920b7e1c893Smrg	    tmp &= ~(RADEON_LVDS_DISPLAY_DIS);
921b7e1c893Smrg	    usleep (lvds->PanelPwrDly * 1000);
922b7e1c893Smrg	    OUTREG(RADEON_LVDS_GEN_CNTL, tmp);
923b7e1c893Smrg	    save->lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN);
924b7e1c893Smrg	    save->lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS);
925b7e1c893Smrg	}
926b7e1c893Smrg	break;
927b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
928b7e1c893Smrg	    ErrorF("enable FP1\n");
929b7e1c893Smrg	    tmp = INREG(RADEON_FP_GEN_CNTL);
930b7e1c893Smrg	    tmp |= (RADEON_FP_FPON | RADEON_FP_TMDS_EN);
931b7e1c893Smrg	    OUTREG(RADEON_FP_GEN_CNTL, tmp);
932b7e1c893Smrg	    save->fp_gen_cntl |= (RADEON_FP_FPON | RADEON_FP_TMDS_EN);
933b7e1c893Smrg	    if ((info->ChipFamily == CHIP_FAMILY_RS400) ||
934b7e1c893Smrg		(info->ChipFamily == CHIP_FAMILY_RS480)) {
935b7e1c893Smrg		tmp = INREG(RS400_FP_2ND_GEN_CNTL);
936b7e1c893Smrg		tmp |= (RS400_FP_2ND_ON | RS400_TMDS_2ND_EN);
937b7e1c893Smrg		OUTREG(RS400_FP_2ND_GEN_CNTL, tmp);
938b7e1c893Smrg		save->fp_2nd_gen_cntl |= (RS400_FP_2ND_ON |
939b7e1c893Smrg					  RS400_TMDS_2ND_EN);
940b7e1c893Smrg	    }
941b7e1c893Smrg	    break;
942b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_DVO1:
943b7e1c893Smrg	    ErrorF("enable FP2\n");
944b7e1c893Smrg	    tmp = INREG(RADEON_FP2_GEN_CNTL);
945b7e1c893Smrg	    tmp &= ~RADEON_FP2_BLANK_EN;
946b7e1c893Smrg	    tmp |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN);
947b7e1c893Smrg	    OUTREG(RADEON_FP2_GEN_CNTL, tmp);
948b7e1c893Smrg	    save->fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN);
949b7e1c893Smrg	    save->fp2_gen_cntl &= ~RADEON_FP2_BLANK_EN;
950b7e1c893Smrg	    if ((info->ChipFamily == CHIP_FAMILY_RS400) ||
951b7e1c893Smrg		(info->ChipFamily == CHIP_FAMILY_RS480)) {
952b7e1c893Smrg		tmp = INREG(RS400_FP2_2_GEN_CNTL);
953b7e1c893Smrg		tmp &= ~RS400_FP2_2_BLANK_EN;
954b7e1c893Smrg		tmp |= (RS400_FP2_2_ON | RS400_FP2_2_DVO2_EN);
955b7e1c893Smrg		OUTREG(RS400_FP2_2_GEN_CNTL, tmp);
956b7e1c893Smrg		save->fp2_2_gen_cntl |= (RS400_FP2_2_ON | RS400_FP2_2_DVO2_EN);
957b7e1c893Smrg		save->fp2_2_gen_cntl &= ~RS400_FP2_2_BLANK_EN;
958b7e1c893Smrg	    }
959b7e1c893Smrg	    break;
960b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_DAC1:
961b7e1c893Smrg	    ErrorF("enable primary dac\n");
962b7e1c893Smrg	    tmp = INREG(RADEON_CRTC_EXT_CNTL);
963b7e1c893Smrg	    tmp |= RADEON_CRTC_CRT_ON;
964b7e1c893Smrg	    OUTREG(RADEON_CRTC_EXT_CNTL, tmp);
965b7e1c893Smrg	    save->crtc_ext_cntl |= RADEON_CRTC_CRT_ON;
966b7e1c893Smrg	    RADEONDacPowerSet(pScrn, TRUE, TRUE);
967b7e1c893Smrg	    break;
968b7e1c893Smrg	case ENCODER_OBJECT_ID_INTERNAL_DAC2:
969b7e1c893Smrg	    if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
970b7e1c893Smrg		ErrorF("enable TV\n");
971b7e1c893Smrg		tmp = INREG(RADEON_TV_MASTER_CNTL);
972b7e1c893Smrg		tmp |= RADEON_TV_ON;
973b7e1c893Smrg		OUTREG(RADEON_TV_MASTER_CNTL, tmp);
974b7e1c893Smrg		radeon_output->tvout.tv_on = TRUE;
975b7e1c893Smrg	    } else {
976b7e1c893Smrg		ErrorF("enable TVDAC\n");
977209ff23fSmrg		if (info->ChipFamily == CHIP_FAMILY_R200) {
978209ff23fSmrg		    tmp = INREG(RADEON_FP2_GEN_CNTL);
979209ff23fSmrg		    tmp |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN);
980209ff23fSmrg		    OUTREG(RADEON_FP2_GEN_CNTL, tmp);
981209ff23fSmrg		    save->fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN);
982209ff23fSmrg		} else {
983209ff23fSmrg		    tmp = INREG(RADEON_CRTC2_GEN_CNTL);
984209ff23fSmrg		    tmp |= RADEON_CRTC2_CRT2_ON;
985209ff23fSmrg		    OUTREG(RADEON_CRTC2_GEN_CNTL, tmp);
986209ff23fSmrg		    save->crtc2_gen_cntl |= RADEON_CRTC2_CRT2_ON;
987209ff23fSmrg		}
988209ff23fSmrg	    }
989b7e1c893Smrg	    RADEONDacPowerSet(pScrn, TRUE, FALSE);
990b7e1c893Smrg	    break;
991b7e1c893Smrg	}
992b7e1c893Smrg	break;
993b7e1c893Smrg    case DPMSModeOff:
994b7e1c893Smrg    case DPMSModeSuspend:
995b7e1c893Smrg    case DPMSModeStandby:
996b7e1c893Smrg	radeon_encoder->devices &= ~(radeon_output->active_device);
997b7e1c893Smrg	if (!radeon_encoder->devices) {
998b7e1c893Smrg	    switch (radeon_encoder->encoder_id) {
999b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
1000b7e1c893Smrg		{
1001b7e1c893Smrg		    unsigned long tmpPixclksCntl = INPLL(pScrn, RADEON_PIXCLKS_CNTL);
10020974d292Smrg		    radeon_lvds_ptr lvds = (radeon_lvds_ptr)radeon_encoder->dev_priv;
10030974d292Smrg		    if (lvds == NULL)
10040974d292Smrg		      return;
1005b7e1c893Smrg		    if (info->IsMobility || info->IsIGP) {
1006b7e1c893Smrg			/* Asic bug, when turning off LVDS_ON, we have to make sure
1007b7e1c893Smrg			   RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
1008b7e1c893Smrg			*/
1009b7e1c893Smrg			OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb);
1010b7e1c893Smrg		    }
1011ad43ddacSmrg#if defined(__powerpc__)
1012ad43ddacSmrg		    /* not sure if this is needed on non-Macs */
1013ad43ddacSmrg		    if (info->MacModel) {
1014ad43ddacSmrg			tmp = INREG(RADEON_LVDS_GEN_CNTL);
1015ad43ddacSmrg			tmp |= RADEON_LVDS_DISPLAY_DIS;
1016ad43ddacSmrg			tmp &= ~RADEON_LVDS_BL_MOD_EN;
1017ad43ddacSmrg			OUTREG(RADEON_LVDS_GEN_CNTL, tmp);
1018ad43ddacSmrg			usleep(100);
1019ad43ddacSmrg			tmp &= ~(RADEON_LVDS_ON | RADEON_LVDS_EN);
1020ad43ddacSmrg			OUTREG(RADEON_LVDS_GEN_CNTL, tmp);
1021ad43ddacSmrg		    } else
1022ad43ddacSmrg#endif
1023ad43ddacSmrg		    {
1024ad43ddacSmrg			tmp = INREG(RADEON_LVDS_GEN_CNTL);
1025ad43ddacSmrg			tmp |= RADEON_LVDS_DISPLAY_DIS;
1026ad43ddacSmrg			tmp &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN);
1027ad43ddacSmrg			OUTREG(RADEON_LVDS_GEN_CNTL, tmp);
1028ad43ddacSmrg		    }
1029b7e1c893Smrg		    save->lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS;
1030b7e1c893Smrg		    save->lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN);
1031b7e1c893Smrg		    if (info->IsMobility || info->IsIGP) {
1032b7e1c893Smrg			OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, tmpPixclksCntl);
1033b7e1c893Smrg		    }
10340974d292Smrg		    usleep (lvds->PanelPwrDly * 1000);
1035b7e1c893Smrg		}
1036b7e1c893Smrg		break;
1037b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1038b7e1c893Smrg		ErrorF("disable FP1\n");
1039209ff23fSmrg		tmp = INREG(RADEON_FP_GEN_CNTL);
1040b7e1c893Smrg		tmp &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN);
1041209ff23fSmrg		OUTREG(RADEON_FP_GEN_CNTL, tmp);
1042b7e1c893Smrg		save->fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN);
1043209ff23fSmrg		if ((info->ChipFamily == CHIP_FAMILY_RS400) ||
1044209ff23fSmrg		    (info->ChipFamily == CHIP_FAMILY_RS480)) {
1045209ff23fSmrg		    tmp = INREG(RS400_FP_2ND_GEN_CNTL);
1046b7e1c893Smrg		    tmp &= ~(RS400_FP_2ND_ON | RS400_TMDS_2ND_EN);
1047209ff23fSmrg		    OUTREG(RS400_FP_2ND_GEN_CNTL, tmp);
1048b7e1c893Smrg		    save->fp_2nd_gen_cntl &= ~(RS400_FP_2ND_ON |
1049b7e1c893Smrg					       RS400_TMDS_2ND_EN);
1050209ff23fSmrg		}
1051b7e1c893Smrg	    break;
1052b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1053b7e1c893Smrg		ErrorF("disable FP2\n");
1054209ff23fSmrg		tmp = INREG(RADEON_FP2_GEN_CNTL);
1055b7e1c893Smrg		tmp |= RADEON_FP2_BLANK_EN;
1056b7e1c893Smrg		tmp &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN);
1057209ff23fSmrg		OUTREG(RADEON_FP2_GEN_CNTL, tmp);
1058b7e1c893Smrg		save->fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN);
1059b7e1c893Smrg		save->fp2_gen_cntl |= RADEON_FP2_BLANK_EN;
1060209ff23fSmrg		if ((info->ChipFamily == CHIP_FAMILY_RS400) ||
1061209ff23fSmrg		    (info->ChipFamily == CHIP_FAMILY_RS480)) {
1062209ff23fSmrg		    tmp = INREG(RS400_FP2_2_GEN_CNTL);
1063b7e1c893Smrg		    tmp |= RS400_FP2_2_BLANK_EN;
1064b7e1c893Smrg		    tmp &= ~(RS400_FP2_2_ON | RS400_FP2_2_DVO2_EN);
1065209ff23fSmrg		    OUTREG(RS400_FP2_2_GEN_CNTL, tmp);
1066b7e1c893Smrg		    save->fp2_2_gen_cntl &= ~(RS400_FP2_2_ON | RS400_FP2_2_DVO2_EN);
1067b7e1c893Smrg		    save->fp2_2_gen_cntl |= RS400_FP2_2_BLANK_EN;
1068209ff23fSmrg		}
1069b7e1c893Smrg		break;
1070b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
1071b7e1c893Smrg		ErrorF("disable primary dac\n");
1072b7e1c893Smrg		tmp = INREG(RADEON_CRTC_EXT_CNTL);
1073b7e1c893Smrg		tmp &= ~RADEON_CRTC_CRT_ON;
1074b7e1c893Smrg		OUTREG(RADEON_CRTC_EXT_CNTL, tmp);
1075b7e1c893Smrg		save->crtc_ext_cntl &= ~RADEON_CRTC_CRT_ON;
1076b7e1c893Smrg		RADEONDacPowerSet(pScrn, FALSE, TRUE);
1077b7e1c893Smrg		break;
1078b7e1c893Smrg	    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1079b7e1c893Smrg		if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
1080b7e1c893Smrg		    ErrorF("disable TV\n");
1081b7e1c893Smrg		    tmp = INREG(RADEON_TV_MASTER_CNTL);
1082b7e1c893Smrg		    tmp &= ~RADEON_TV_ON;
1083b7e1c893Smrg		    OUTREG(RADEON_TV_MASTER_CNTL, tmp);
1084b7e1c893Smrg		    radeon_output->tvout.tv_on = FALSE;
1085b7e1c893Smrg		} else {
1086b7e1c893Smrg		    ErrorF("disable TVDAC\n");
1087209ff23fSmrg		    if (info->ChipFamily == CHIP_FAMILY_R200) {
1088209ff23fSmrg			tmp = INREG(RADEON_FP2_GEN_CNTL);
1089209ff23fSmrg			tmp &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN);
1090209ff23fSmrg			OUTREG(RADEON_FP2_GEN_CNTL, tmp);
1091209ff23fSmrg			save->fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN);
1092209ff23fSmrg		    } else {
1093209ff23fSmrg			tmp = INREG(RADEON_CRTC2_GEN_CNTL);
1094209ff23fSmrg			tmp &= ~RADEON_CRTC2_CRT2_ON;
1095209ff23fSmrg			OUTREG(RADEON_CRTC2_GEN_CNTL, tmp);
1096209ff23fSmrg			save->crtc2_gen_cntl &= ~RADEON_CRTC2_CRT2_ON;
1097209ff23fSmrg		    }
1098209ff23fSmrg		}
1099b7e1c893Smrg		RADEONDacPowerSet(pScrn, FALSE, FALSE);
1100b7e1c893Smrg		break;
1101209ff23fSmrg	    }
1102209ff23fSmrg	}
1103209ff23fSmrg	break;
1104209ff23fSmrg    }
1105209ff23fSmrg}
1106209ff23fSmrg
1107209ff23fSmrgstatic void
1108209ff23fSmrgRADEONInitFPRegisters(xf86OutputPtr output, RADEONSavePtr save,
1109209ff23fSmrg		      DisplayModePtr mode, BOOL IsPrimary)
1110209ff23fSmrg{
1111209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
1112209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1113209ff23fSmrg    RADEONEntPtr  pRADEONEnt = RADEONEntPriv(pScrn);
1114209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1115b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
1116b7e1c893Smrg    radeon_tmds_ptr tmds = NULL;
1117209ff23fSmrg    int i;
1118209ff23fSmrg    uint32_t tmp = info->SavedReg->tmds_pll_cntl & 0xfffff;
1119209ff23fSmrg
1120b7e1c893Smrg    if (radeon_encoder == NULL)
1121b7e1c893Smrg	return;
1122b7e1c893Smrg
1123b7e1c893Smrg    tmds = (radeon_tmds_ptr)radeon_encoder->dev_priv;
1124b7e1c893Smrg
1125b7e1c893Smrg    if (tmds == NULL)
1126b7e1c893Smrg	return;
1127b7e1c893Smrg
1128b7e1c893Smrg    for (i = 0; i < 4; i++) {
1129b7e1c893Smrg	if (tmds->tmds_pll[i].freq == 0)
1130b7e1c893Smrg	    break;
1131b7e1c893Smrg	if ((uint32_t)(mode->Clock / 10) < tmds->tmds_pll[i].freq) {
1132b7e1c893Smrg	    tmp = tmds->tmds_pll[i].value ;
1133209ff23fSmrg	    break;
1134209ff23fSmrg	}
1135209ff23fSmrg    }
1136209ff23fSmrg
1137209ff23fSmrg    if (IS_R300_VARIANT || (info->ChipFamily == CHIP_FAMILY_RV280)) {
1138209ff23fSmrg	if (tmp & 0xfff00000)
1139209ff23fSmrg	    save->tmds_pll_cntl = tmp;
1140209ff23fSmrg	else {
1141209ff23fSmrg	    save->tmds_pll_cntl = info->SavedReg->tmds_pll_cntl & 0xfff00000;
1142209ff23fSmrg	    save->tmds_pll_cntl |= tmp;
1143209ff23fSmrg	}
1144209ff23fSmrg    } else save->tmds_pll_cntl = tmp;
1145209ff23fSmrg
1146209ff23fSmrg    save->tmds_transmitter_cntl = info->SavedReg->tmds_transmitter_cntl &
1147209ff23fSmrg					~(RADEON_TMDS_TRANSMITTER_PLLRST);
1148209ff23fSmrg
1149209ff23fSmrg    if (IS_R300_VARIANT || (info->ChipFamily == CHIP_FAMILY_R200) || !pRADEONEnt->HasCRTC2)
1150209ff23fSmrg	save->tmds_transmitter_cntl &= ~(RADEON_TMDS_TRANSMITTER_PLLEN);
1151209ff23fSmrg    else /* weird, RV chips got this bit reversed? */
1152209ff23fSmrg	save->tmds_transmitter_cntl |= (RADEON_TMDS_TRANSMITTER_PLLEN);
1153209ff23fSmrg
1154209ff23fSmrg    save->fp_gen_cntl = info->SavedReg->fp_gen_cntl |
1155209ff23fSmrg			 (RADEON_FP_CRTC_DONT_SHADOW_VPAR |
1156209ff23fSmrg			  RADEON_FP_CRTC_DONT_SHADOW_HEND );
1157209ff23fSmrg
1158209ff23fSmrg    save->fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN);
1159209ff23fSmrg
1160b7e1c893Smrg    save->fp_gen_cntl &= ~(RADEON_FP_RMX_HVSYNC_CONTROL_EN |
1161b7e1c893Smrg			   RADEON_FP_DFP_SYNC_SEL |
1162b7e1c893Smrg			   RADEON_FP_CRT_SYNC_SEL |
1163b7e1c893Smrg			   RADEON_FP_CRTC_LOCK_8DOT |
1164b7e1c893Smrg			   RADEON_FP_USE_SHADOW_EN |
1165b7e1c893Smrg			   RADEON_FP_CRTC_USE_SHADOW_VEND |
1166b7e1c893Smrg			   RADEON_FP_CRT_SYNC_ALT);
1167b7e1c893Smrg
1168209ff23fSmrg    if (pScrn->rgbBits == 8)
1169209ff23fSmrg	save->fp_gen_cntl |= RADEON_FP_PANEL_FORMAT;  /* 24 bit format */
1170209ff23fSmrg    else
1171209ff23fSmrg	save->fp_gen_cntl &= ~RADEON_FP_PANEL_FORMAT;/* 18 bit format */
1172209ff23fSmrg
1173209ff23fSmrg    if (IsPrimary) {
1174209ff23fSmrg	if ((IS_R300_VARIANT) || (info->ChipFamily == CHIP_FAMILY_R200)) {
1175209ff23fSmrg	    save->fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK;
1176209ff23fSmrg	    if (radeon_output->Flags & RADEON_USE_RMX)
1177209ff23fSmrg		save->fp_gen_cntl |= R200_FP_SOURCE_SEL_RMX;
1178209ff23fSmrg	    else
1179209ff23fSmrg		save->fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC1;
1180209ff23fSmrg	} else
1181b7e1c893Smrg	    save->fp_gen_cntl &= ~RADEON_FP_SEL_CRTC2;
1182209ff23fSmrg    } else {
1183209ff23fSmrg	if ((IS_R300_VARIANT) || (info->ChipFamily == CHIP_FAMILY_R200)) {
1184209ff23fSmrg	    save->fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK;
1185209ff23fSmrg	    save->fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC2;
1186209ff23fSmrg	} else
1187209ff23fSmrg	    save->fp_gen_cntl |= RADEON_FP_SEL_CRTC2;
1188209ff23fSmrg    }
1189209ff23fSmrg
1190209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_RS400) ||
1191209ff23fSmrg	(info->ChipFamily == CHIP_FAMILY_RS480)) {
1192209ff23fSmrg	save->tmds2_transmitter_cntl = info->SavedReg->tmds2_transmitter_cntl &
1193209ff23fSmrg	    ~(RS400_TMDS2_PLLRST);
1194209ff23fSmrg	save->tmds2_transmitter_cntl &= ~(RS400_TMDS2_PLLEN);
1195209ff23fSmrg
1196209ff23fSmrg	save->fp_2nd_gen_cntl = info->SavedReg->fp_2nd_gen_cntl;
1197209ff23fSmrg
1198209ff23fSmrg	if (pScrn->rgbBits == 8)
1199209ff23fSmrg	    save->fp_2nd_gen_cntl |= RS400_PANEL_FORMAT_2ND;  /* 24 bit format */
1200209ff23fSmrg	else
1201209ff23fSmrg	    save->fp_2nd_gen_cntl &= ~RS400_PANEL_FORMAT_2ND;/* 18 bit format */
1202209ff23fSmrg
1203209ff23fSmrg	save->fp_2nd_gen_cntl &= ~RS400_FP_2ND_SOURCE_SEL_MASK;
1204209ff23fSmrg
1205209ff23fSmrg	if (IsPrimary) {
1206209ff23fSmrg	    if (radeon_output->Flags & RADEON_USE_RMX)
1207209ff23fSmrg		save->fp_2nd_gen_cntl |= RS400_FP_2ND_SOURCE_SEL_RMX;
1208209ff23fSmrg	    else
1209209ff23fSmrg		save->fp_2nd_gen_cntl |= RS400_FP_2ND_SOURCE_SEL_CRTC1;
1210209ff23fSmrg	} else
1211209ff23fSmrg	    save->fp_2nd_gen_cntl |= RS400_FP_2ND_SOURCE_SEL_CRTC2;
1212209ff23fSmrg    }
1213209ff23fSmrg
1214209ff23fSmrg}
1215209ff23fSmrg
1216209ff23fSmrgstatic void
1217209ff23fSmrgRADEONInitFP2Registers(xf86OutputPtr output, RADEONSavePtr save,
1218209ff23fSmrg		       DisplayModePtr mode, BOOL IsPrimary)
1219209ff23fSmrg{
1220209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
1221209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
1222209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1223209ff23fSmrg
1224209ff23fSmrg    if (pScrn->rgbBits == 8)
1225209ff23fSmrg	save->fp2_gen_cntl = info->SavedReg->fp2_gen_cntl |
1226209ff23fSmrg				RADEON_FP2_PANEL_FORMAT; /* 24 bit format, */
1227209ff23fSmrg    else
1228209ff23fSmrg	save->fp2_gen_cntl = info->SavedReg->fp2_gen_cntl &
1229209ff23fSmrg				~RADEON_FP2_PANEL_FORMAT;/* 18 bit format, */
1230209ff23fSmrg
1231209ff23fSmrg    save->fp2_gen_cntl &= ~(RADEON_FP2_ON |
1232209ff23fSmrg			    RADEON_FP2_DVO_EN |
1233209ff23fSmrg			    RADEON_FP2_DVO_RATE_SEL_SDR);
1234209ff23fSmrg
1235209ff23fSmrg
1236b7e1c893Smrg    /* XXX: these are oem specific */
1237209ff23fSmrg    if (IS_R300_VARIANT) {
1238b7e1c893Smrg	if ((info->Chipset == PCI_CHIP_RV350_NP) &&
1239b7e1c893Smrg	    (PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1028) &&
1240b7e1c893Smrg	    (PCI_SUB_DEVICE_ID(info->PciInfo) == 0x2001))
1241ad43ddacSmrg	    save->fp2_gen_cntl |= R200_FP2_DVO_CLOCK_MODE_SINGLE; /* Dell Inspiron 8600 */
1242b7e1c893Smrg	else
1243ad43ddacSmrg	    save->fp2_gen_cntl |= RADEON_FP2_PAD_FLOP_EN | R200_FP2_DVO_CLOCK_MODE_SINGLE;
1244ad43ddacSmrg    }
1245ad43ddacSmrg
1246209ff23fSmrg#if 0
1247ad43ddacSmrg    /* DVO configurations:
1248ad43ddacSmrg     * SDR single channel (data rate 165 Mhz, port width 12 bits)
1249ad43ddacSmrg     * DDR single channel (data rate 330 Mhz, port width 12 bits)
1250ad43ddacSmrg     * SDR dual   channel (data rate 330 Mhz, port width 24 bits)
1251ad43ddacSmrg     * - dual channel is only available on r3xx+
1252ad43ddacSmrg     */
1253ad43ddacSmrg    if (info->ChipFamily >= CHIP_FAMILY_R200) {
1254ad43ddacSmrg	if (sdr)
1255ad43ddacSmrg	    save->fp2_gen_cntl |= R200_FP2_DVO_RATE_SEL_SDR;
1256ad43ddacSmrg	if (IS_R300_VARIANT && dual channel)
1257209ff23fSmrg	    save->fp2_gen_cntl |= R300_FP2_DVO_DUAL_CHANNEL_EN;
1258209ff23fSmrg    }
1259ad43ddacSmrg#endif
1260209ff23fSmrg
1261209ff23fSmrg    if (IsPrimary) {
1262209ff23fSmrg	if ((info->ChipFamily == CHIP_FAMILY_R200) || IS_R300_VARIANT) {
1263209ff23fSmrg	    save->fp2_gen_cntl &= ~R200_FP2_SOURCE_SEL_MASK;
1264209ff23fSmrg	    if (radeon_output->Flags & RADEON_USE_RMX)
1265209ff23fSmrg		save->fp2_gen_cntl |= R200_FP2_SOURCE_SEL_RMX;
1266209ff23fSmrg	    else
1267209ff23fSmrg		save->fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC1;
1268b7e1c893Smrg	} else
1269209ff23fSmrg	    save->fp2_gen_cntl &= ~RADEON_FP2_SRC_SEL_CRTC2;
1270209ff23fSmrg    } else {
1271209ff23fSmrg	if ((info->ChipFamily == CHIP_FAMILY_R200) || IS_R300_VARIANT) {
1272209ff23fSmrg	    save->fp2_gen_cntl &= ~R200_FP2_SOURCE_SEL_MASK;
1273209ff23fSmrg	    save->fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2;
1274b7e1c893Smrg	} else
1275209ff23fSmrg	    save->fp2_gen_cntl |= RADEON_FP2_SRC_SEL_CRTC2;
1276209ff23fSmrg    }
1277209ff23fSmrg
1278209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_RS400) ||
1279209ff23fSmrg	(info->ChipFamily == CHIP_FAMILY_RS480)) {
1280209ff23fSmrg	if (pScrn->rgbBits == 8)
1281209ff23fSmrg	    save->fp2_2_gen_cntl = info->SavedReg->fp2_2_gen_cntl |
1282209ff23fSmrg		RS400_FP2_2_PANEL_FORMAT; /* 24 bit format, */
1283209ff23fSmrg	else
1284209ff23fSmrg	    save->fp2_2_gen_cntl = info->SavedReg->fp2_2_gen_cntl &
1285209ff23fSmrg		~RS400_FP2_2_PANEL_FORMAT;/* 18 bit format, */
1286209ff23fSmrg
1287209ff23fSmrg	save->fp2_2_gen_cntl &= ~(RS400_FP2_2_ON |
1288209ff23fSmrg				  RS400_FP2_2_DVO2_EN |
1289209ff23fSmrg				  RS400_FP2_2_SOURCE_SEL_MASK);
1290209ff23fSmrg
1291209ff23fSmrg	if (IsPrimary) {
1292209ff23fSmrg	    if (radeon_output->Flags & RADEON_USE_RMX)
1293209ff23fSmrg		save->fp2_2_gen_cntl |= RS400_FP2_2_SOURCE_SEL_RMX;
1294209ff23fSmrg	    else
1295209ff23fSmrg		save->fp2_2_gen_cntl |= RS400_FP2_2_SOURCE_SEL_CRTC1;
1296209ff23fSmrg	} else
1297209ff23fSmrg	    save->fp2_2_gen_cntl |= RS400_FP2_2_SOURCE_SEL_CRTC2;
1298209ff23fSmrg    }
1299209ff23fSmrg
1300209ff23fSmrg}
1301209ff23fSmrg
1302209ff23fSmrgstatic void
1303209ff23fSmrgRADEONInitLVDSRegisters(xf86OutputPtr output, RADEONSavePtr save,
1304209ff23fSmrg			DisplayModePtr mode, BOOL IsPrimary)
1305209ff23fSmrg{
1306209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
1307209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1308209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1309209ff23fSmrg
1310209ff23fSmrg    save->lvds_pll_cntl = (info->SavedReg->lvds_pll_cntl |
1311209ff23fSmrg			   RADEON_LVDS_PLL_EN);
1312209ff23fSmrg
1313209ff23fSmrg    save->lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET;
1314209ff23fSmrg
1315209ff23fSmrg    save->lvds_gen_cntl = info->SavedReg->lvds_gen_cntl;
1316209ff23fSmrg    save->lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS;
1317209ff23fSmrg    save->lvds_gen_cntl &= ~(RADEON_LVDS_ON |
1318209ff23fSmrg			     RADEON_LVDS_BLON |
1319209ff23fSmrg			     RADEON_LVDS_EN |
1320209ff23fSmrg			     RADEON_LVDS_RST_FM);
1321209ff23fSmrg
1322209ff23fSmrg    if (IS_R300_VARIANT)
1323209ff23fSmrg	save->lvds_pll_cntl &= ~(R300_LVDS_SRC_SEL_MASK);
1324209ff23fSmrg
1325209ff23fSmrg    if (IsPrimary) {
1326209ff23fSmrg	if (IS_R300_VARIANT) {
1327209ff23fSmrg	    if (radeon_output->Flags & RADEON_USE_RMX)
1328209ff23fSmrg		save->lvds_pll_cntl |= R300_LVDS_SRC_SEL_RMX;
1329209ff23fSmrg	} else
1330209ff23fSmrg	    save->lvds_gen_cntl &= ~RADEON_LVDS_SEL_CRTC2;
1331209ff23fSmrg    } else {
1332209ff23fSmrg	if (IS_R300_VARIANT) {
1333209ff23fSmrg	    save->lvds_pll_cntl |= R300_LVDS_SRC_SEL_CRTC2;
1334209ff23fSmrg	} else
1335209ff23fSmrg	    save->lvds_gen_cntl |= RADEON_LVDS_SEL_CRTC2;
1336209ff23fSmrg    }
1337209ff23fSmrg
1338209ff23fSmrg}
1339209ff23fSmrg
1340209ff23fSmrgstatic void
1341209ff23fSmrgRADEONInitRMXRegisters(xf86OutputPtr output, RADEONSavePtr save,
1342209ff23fSmrg		       DisplayModePtr mode)
1343209ff23fSmrg{
1344209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
1345209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1346209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1347b7e1c893Smrg    radeon_native_mode_ptr native_mode = &radeon_output->native_mode;
1348209ff23fSmrg    int    xres = mode->HDisplay;
1349209ff23fSmrg    int    yres = mode->VDisplay;
1350209ff23fSmrg    Bool   Hscale = TRUE, Vscale = TRUE;
1351209ff23fSmrg    int    hsync_wid;
1352209ff23fSmrg    int    vsync_wid;
1353209ff23fSmrg    int    hsync_start;
1354209ff23fSmrg
1355209ff23fSmrg
1356209ff23fSmrg    save->fp_vert_stretch = info->SavedReg->fp_vert_stretch &
1357209ff23fSmrg	                    (RADEON_VERT_STRETCH_RESERVED |
1358209ff23fSmrg			     RADEON_VERT_AUTO_RATIO_INC);
1359209ff23fSmrg    save->fp_horz_stretch = info->SavedReg->fp_horz_stretch &
1360209ff23fSmrg	                    (RADEON_HORZ_FP_LOOP_STRETCH |
1361209ff23fSmrg	                     RADEON_HORZ_AUTO_RATIO_INC);
1362209ff23fSmrg
1363209ff23fSmrg    save->crtc_more_cntl = 0;
1364209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_RS100) ||
1365209ff23fSmrg	(info->ChipFamily == CHIP_FAMILY_RS200)) {
1366209ff23fSmrg	/* This is to workaround the asic bug for RMX, some versions
1367209ff23fSmrg           of BIOS dosen't have this register initialized correctly.
1368209ff23fSmrg	*/
1369209ff23fSmrg	save->crtc_more_cntl |= RADEON_CRTC_H_CUTOFF_ACTIVE_EN;
1370209ff23fSmrg    }
1371209ff23fSmrg
1372209ff23fSmrg
1373209ff23fSmrg    save->fp_crtc_h_total_disp = ((((mode->CrtcHTotal / 8) - 1) & 0x3ff)
1374209ff23fSmrg				  | ((((mode->CrtcHDisplay / 8) - 1) & 0x1ff)
1375209ff23fSmrg				     << 16));
1376209ff23fSmrg
1377209ff23fSmrg    hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8;
1378209ff23fSmrg    if (!hsync_wid)       hsync_wid = 1;
1379209ff23fSmrg    hsync_start = mode->CrtcHSyncStart - 8;
1380209ff23fSmrg
1381209ff23fSmrg    save->fp_h_sync_strt_wid = ((hsync_start & 0x1fff)
1382209ff23fSmrg				| ((hsync_wid & 0x3f) << 16)
1383209ff23fSmrg				| ((mode->Flags & V_NHSYNC)
1384209ff23fSmrg				   ? RADEON_CRTC_H_SYNC_POL
1385209ff23fSmrg				   : 0));
1386209ff23fSmrg
1387209ff23fSmrg    save->fp_crtc_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff)
1388209ff23fSmrg				  | ((mode->CrtcVDisplay - 1) << 16));
1389209ff23fSmrg
1390209ff23fSmrg    vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart;
1391209ff23fSmrg    if (!vsync_wid)       vsync_wid = 1;
1392209ff23fSmrg
1393209ff23fSmrg    save->fp_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff)
1394209ff23fSmrg				| ((vsync_wid & 0x1f) << 16)
1395209ff23fSmrg				| ((mode->Flags & V_NVSYNC)
1396209ff23fSmrg				   ? RADEON_CRTC_V_SYNC_POL
1397209ff23fSmrg				   : 0));
1398209ff23fSmrg
1399209ff23fSmrg    save->fp_horz_vert_active = 0;
1400209ff23fSmrg
1401b7e1c893Smrg    if ((radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) ||
1402b7e1c893Smrg	(radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT))) {
1403209ff23fSmrg
1404b7e1c893Smrg	if (native_mode->PanelXRes == 0 || native_mode->PanelYRes == 0) {
1405209ff23fSmrg	    Hscale = FALSE;
1406209ff23fSmrg	    Vscale = FALSE;
1407b7e1c893Smrg	} else {
1408b7e1c893Smrg	    if (xres > native_mode->PanelXRes)
1409b7e1c893Smrg		xres = native_mode->PanelXRes;
1410b7e1c893Smrg	    if (yres > native_mode->PanelYRes)
1411b7e1c893Smrg		yres = native_mode->PanelYRes;
1412b7e1c893Smrg
1413b7e1c893Smrg	    if (xres == native_mode->PanelXRes)
1414b7e1c893Smrg		Hscale = FALSE;
1415b7e1c893Smrg	    if (yres == native_mode->PanelYRes)
1416b7e1c893Smrg		Vscale = FALSE;
1417b7e1c893Smrg	}
1418209ff23fSmrg
1419b7e1c893Smrg	if ((!Hscale) || (!(radeon_output->Flags & RADEON_USE_RMX)) ||
1420b7e1c893Smrg	    (radeon_output->rmx_type == RMX_CENTER)) {
1421b7e1c893Smrg	    save->fp_horz_stretch |= ((xres/8-1)<<16);
1422b7e1c893Smrg	} else {
1423b7e1c893Smrg	    uint32_t scale, inc;
1424b7e1c893Smrg	    inc = (save->fp_horz_stretch & RADEON_HORZ_AUTO_RATIO_INC) ? 1 : 0;
1425b7e1c893Smrg	    scale = ((xres + inc) * RADEON_HORZ_STRETCH_RATIO_MAX)
1426b7e1c893Smrg		/ native_mode->PanelXRes + 1;
1427b7e1c893Smrg	    save->fp_horz_stretch |= (((scale) & RADEON_HORZ_STRETCH_RATIO_MASK) |
1428b7e1c893Smrg				      RADEON_HORZ_STRETCH_BLEND |
1429b7e1c893Smrg				      RADEON_HORZ_STRETCH_ENABLE |
1430b7e1c893Smrg				      ((native_mode->PanelXRes/8-1)<<16));
1431b7e1c893Smrg	}
1432209ff23fSmrg
1433b7e1c893Smrg	if ((!Vscale) || (!(radeon_output->Flags & RADEON_USE_RMX)) ||
1434b7e1c893Smrg	    (radeon_output->rmx_type == RMX_CENTER)) {
1435b7e1c893Smrg	    save->fp_vert_stretch |= ((yres-1)<<12);
1436b7e1c893Smrg	} else {
1437b7e1c893Smrg	    uint32_t scale, inc;
1438b7e1c893Smrg	    inc = (save->fp_vert_stretch & RADEON_VERT_AUTO_RATIO_INC) ? 1 : 0;
1439b7e1c893Smrg	    scale = ((yres + inc) * RADEON_VERT_STRETCH_RATIO_MAX)
1440b7e1c893Smrg		/ native_mode->PanelYRes + 1;
1441b7e1c893Smrg	    save->fp_vert_stretch |= (((scale) & RADEON_VERT_STRETCH_RATIO_MASK) |
1442b7e1c893Smrg				      RADEON_VERT_STRETCH_ENABLE |
1443b7e1c893Smrg				      RADEON_VERT_STRETCH_BLEND |
1444b7e1c893Smrg				      ((native_mode->PanelYRes-1)<<12));
1445b7e1c893Smrg	}
1446209ff23fSmrg
1447b7e1c893Smrg	if ((radeon_output->rmx_type == RMX_CENTER) &&
1448b7e1c893Smrg	    (radeon_output->Flags & RADEON_USE_RMX)) {
1449b7e1c893Smrg	    int    blank_width;
1450209ff23fSmrg
1451b7e1c893Smrg	    save->crtc_more_cntl |= (RADEON_CRTC_AUTO_HORZ_CENTER_EN |
1452b7e1c893Smrg				     RADEON_CRTC_AUTO_VERT_CENTER_EN);
1453209ff23fSmrg
1454b7e1c893Smrg	    blank_width = (mode->CrtcHBlankEnd - mode->CrtcHBlankStart) / 8;
1455b7e1c893Smrg	    if (blank_width > 110)
1456b7e1c893Smrg		blank_width = 110;
1457209ff23fSmrg
1458b7e1c893Smrg	    save->fp_crtc_h_total_disp = (((blank_width) & 0x3ff)
1459b7e1c893Smrg					  | ((((mode->CrtcHDisplay / 8) - 1) & 0x1ff)
1460b7e1c893Smrg					     << 16));
1461209ff23fSmrg
1462b7e1c893Smrg	    hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8;
1463b7e1c893Smrg	    if (!hsync_wid)
1464b7e1c893Smrg		hsync_wid = 1;
1465209ff23fSmrg
1466b7e1c893Smrg	    save->fp_h_sync_strt_wid = ((((mode->CrtcHSyncStart - mode->CrtcHBlankStart) / 8) & 0x1fff)
1467b7e1c893Smrg					| ((hsync_wid & 0x3f) << 16)
1468b7e1c893Smrg					| ((mode->Flags & V_NHSYNC)
1469b7e1c893Smrg					   ? RADEON_CRTC_H_SYNC_POL
1470b7e1c893Smrg					   : 0));
1471209ff23fSmrg
1472b7e1c893Smrg	    save->fp_crtc_v_total_disp = (((mode->CrtcVBlankEnd - mode->CrtcVBlankStart) & 0xffff)
1473b7e1c893Smrg					  | ((mode->CrtcVDisplay - 1) << 16));
1474209ff23fSmrg
1475b7e1c893Smrg	    vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart;
1476b7e1c893Smrg	    if (!vsync_wid)
1477b7e1c893Smrg		vsync_wid = 1;
1478209ff23fSmrg
1479b7e1c893Smrg	    save->fp_v_sync_strt_wid = ((((mode->CrtcVSyncStart - mode->CrtcVBlankStart) & 0xfff)
1480b7e1c893Smrg					 | ((vsync_wid & 0x1f) << 16)
1481b7e1c893Smrg					 | ((mode->Flags & V_NVSYNC)
1482b7e1c893Smrg					    ? RADEON_CRTC_V_SYNC_POL
1483b7e1c893Smrg					    : 0)));
1484209ff23fSmrg
1485b7e1c893Smrg	    save->fp_horz_vert_active = (((native_mode->PanelYRes) & 0xfff) |
1486b7e1c893Smrg					 (((native_mode->PanelXRes / 8) & 0x1ff) << 16));
1487209ff23fSmrg
1488b7e1c893Smrg	}
1489209ff23fSmrg    }
1490209ff23fSmrg}
1491209ff23fSmrg
1492209ff23fSmrgstatic void
1493209ff23fSmrgRADEONInitDACRegisters(xf86OutputPtr output, RADEONSavePtr save,
1494209ff23fSmrg		       DisplayModePtr mode, BOOL IsPrimary)
1495209ff23fSmrg{
1496209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
1497209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1498209ff23fSmrg
1499209ff23fSmrg    if (IsPrimary) {
1500209ff23fSmrg	if ((info->ChipFamily == CHIP_FAMILY_R200) || IS_R300_VARIANT) {
1501209ff23fSmrg            save->disp_output_cntl = info->SavedReg->disp_output_cntl &
1502209ff23fSmrg					~RADEON_DISP_DAC_SOURCE_MASK;
1503209ff23fSmrg        } else {
1504209ff23fSmrg            save->dac2_cntl = info->SavedReg->dac2_cntl & ~(RADEON_DAC2_DAC_CLK_SEL);
1505209ff23fSmrg        }
1506209ff23fSmrg    } else {
1507209ff23fSmrg        if ((info->ChipFamily == CHIP_FAMILY_R200) || IS_R300_VARIANT) {
1508209ff23fSmrg            save->disp_output_cntl = info->SavedReg->disp_output_cntl &
1509209ff23fSmrg					~RADEON_DISP_DAC_SOURCE_MASK;
1510209ff23fSmrg            save->disp_output_cntl |= RADEON_DISP_DAC_SOURCE_CRTC2;
1511209ff23fSmrg        } else {
1512209ff23fSmrg            save->dac2_cntl = info->SavedReg->dac2_cntl | RADEON_DAC2_DAC_CLK_SEL;
1513209ff23fSmrg        }
1514209ff23fSmrg    }
1515209ff23fSmrg    save->dac_cntl = (RADEON_DAC_MASK_ALL
1516209ff23fSmrg		      | RADEON_DAC_VGA_ADR_EN
1517209ff23fSmrg		      | (info->dac6bits ? 0 : RADEON_DAC_8BIT_EN));
1518209ff23fSmrg
1519209ff23fSmrg    save->dac_macro_cntl = info->SavedReg->dac_macro_cntl;
1520209ff23fSmrg}
1521209ff23fSmrg
1522209ff23fSmrgstatic void
1523209ff23fSmrgRADEONInitTvDacCntl(xf86OutputPtr output, RADEONSavePtr save)
1524209ff23fSmrg{
1525209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
1526209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1527b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
1528b7e1c893Smrg    radeon_tvdac_ptr tvdac = NULL;
1529b7e1c893Smrg
1530b7e1c893Smrg    if (radeon_encoder == NULL)
1531b7e1c893Smrg	return;
1532b7e1c893Smrg
1533b7e1c893Smrg    tvdac = (radeon_tvdac_ptr)radeon_encoder->dev_priv;
1534b7e1c893Smrg
1535b7e1c893Smrg    if (tvdac == NULL)
1536b7e1c893Smrg	return;
1537209ff23fSmrg
1538209ff23fSmrg    if (info->ChipFamily == CHIP_FAMILY_R420 ||
1539209ff23fSmrg	info->ChipFamily == CHIP_FAMILY_RV410) {
1540209ff23fSmrg	save->tv_dac_cntl = info->SavedReg->tv_dac_cntl &
1541209ff23fSmrg			     ~(RADEON_TV_DAC_STD_MASK |
1542209ff23fSmrg			       RADEON_TV_DAC_BGADJ_MASK |
1543209ff23fSmrg			       R420_TV_DAC_DACADJ_MASK |
1544209ff23fSmrg			       R420_TV_DAC_RDACPD |
1545209ff23fSmrg			       R420_TV_DAC_GDACPD |
1546ad43ddacSmrg			       R420_TV_DAC_BDACPD |
1547209ff23fSmrg			       R420_TV_DAC_TVENABLE);
1548209ff23fSmrg    } else {
1549209ff23fSmrg	save->tv_dac_cntl = info->SavedReg->tv_dac_cntl &
1550209ff23fSmrg			     ~(RADEON_TV_DAC_STD_MASK |
1551209ff23fSmrg			       RADEON_TV_DAC_BGADJ_MASK |
1552209ff23fSmrg			       RADEON_TV_DAC_DACADJ_MASK |
1553209ff23fSmrg			       RADEON_TV_DAC_RDACPD |
1554209ff23fSmrg			       RADEON_TV_DAC_GDACPD |
1555ad43ddacSmrg			       RADEON_TV_DAC_BDACPD);
1556209ff23fSmrg    }
1557209ff23fSmrg
1558209ff23fSmrg    save->tv_dac_cntl |= (RADEON_TV_DAC_NBLANK |
1559209ff23fSmrg			  RADEON_TV_DAC_NHOLD |
1560209ff23fSmrg			  RADEON_TV_DAC_STD_PS2 |
1561b7e1c893Smrg			  tvdac->ps2_tvdac_adj);
1562209ff23fSmrg
1563209ff23fSmrg}
1564209ff23fSmrg
1565209ff23fSmrgstatic void
1566209ff23fSmrgRADEONInitDAC2Registers(xf86OutputPtr output, RADEONSavePtr save,
1567209ff23fSmrg			DisplayModePtr mode, BOOL IsPrimary)
1568209ff23fSmrg{
1569209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
1570209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1571209ff23fSmrg
1572209ff23fSmrg    /*0x0028023;*/
1573209ff23fSmrg    RADEONInitTvDacCntl(output, save);
1574209ff23fSmrg
1575209ff23fSmrg    if (IS_R300_VARIANT)
1576209ff23fSmrg	save->gpiopad_a = info->SavedReg->gpiopad_a | 1;
1577209ff23fSmrg
1578209ff23fSmrg    save->dac2_cntl = info->SavedReg->dac2_cntl | RADEON_DAC2_DAC2_CLK_SEL;
1579209ff23fSmrg
1580209ff23fSmrg    if (IsPrimary) {
1581209ff23fSmrg        if (IS_R300_VARIANT) {
1582209ff23fSmrg            save->disp_output_cntl = info->SavedReg->disp_output_cntl &
1583209ff23fSmrg					~RADEON_DISP_TVDAC_SOURCE_MASK;
1584209ff23fSmrg            save->disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC;
1585209ff23fSmrg        } else if (info->ChipFamily == CHIP_FAMILY_R200) {
1586209ff23fSmrg	    save->fp2_gen_cntl = info->SavedReg->fp2_gen_cntl &
1587209ff23fSmrg				  ~(R200_FP2_SOURCE_SEL_MASK |
1588209ff23fSmrg				    RADEON_FP2_DVO_RATE_SEL_SDR);
1589209ff23fSmrg	} else {
1590209ff23fSmrg            save->disp_hw_debug = info->SavedReg->disp_hw_debug | RADEON_CRT2_DISP1_SEL;
1591209ff23fSmrg        }
1592209ff23fSmrg    } else {
1593209ff23fSmrg        if (IS_R300_VARIANT) {
1594209ff23fSmrg            save->disp_output_cntl = info->SavedReg->disp_output_cntl &
1595209ff23fSmrg					~RADEON_DISP_TVDAC_SOURCE_MASK;
1596209ff23fSmrg            save->disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC2;
1597209ff23fSmrg	} else if (info->ChipFamily == CHIP_FAMILY_R200) {
1598209ff23fSmrg	    save->fp2_gen_cntl = info->SavedReg->fp2_gen_cntl &
1599209ff23fSmrg				  ~(R200_FP2_SOURCE_SEL_MASK |
1600209ff23fSmrg				    RADEON_FP2_DVO_RATE_SEL_SDR);
1601209ff23fSmrg            save->fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2;
1602209ff23fSmrg        } else {
1603209ff23fSmrg            save->disp_hw_debug = info->SavedReg->disp_hw_debug &
1604209ff23fSmrg					~RADEON_CRT2_DISP1_SEL;
1605209ff23fSmrg        }
1606209ff23fSmrg    }
1607209ff23fSmrg}
1608209ff23fSmrg
1609209ff23fSmrgvoid
1610209ff23fSmrglegacy_output_mode_set(xf86OutputPtr output, DisplayModePtr mode,
1611b7e1c893Smrg		       DisplayModePtr adjusted_mode)
1612209ff23fSmrg{
1613209ff23fSmrg    ScrnInfoPtr	    pScrn = output->scrn;
1614209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
1615209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1616209ff23fSmrg    xf86CrtcPtr	crtc = output->crtc;
1617209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
1618b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
1619b7e1c893Smrg    Bool is_primary = FALSE;
1620209ff23fSmrg
1621b7e1c893Smrg    if (radeon_encoder == NULL)
1622b7e1c893Smrg	return;
1623209ff23fSmrg
1624b7e1c893Smrg    radeon_output->pixel_clock = adjusted_mode->Clock;
1625b7e1c893Smrg    if (radeon_crtc->crtc_id == 0) {
1626b7e1c893Smrg	ErrorF("set RMX\n");
1627b7e1c893Smrg	is_primary = TRUE;
1628b7e1c893Smrg	RADEONInitRMXRegisters(output, info->ModeReg, adjusted_mode);
1629209ff23fSmrg	RADEONRestoreRMXRegisters(pScrn, info->ModeReg);
1630b7e1c893Smrg    }
1631209ff23fSmrg
1632b7e1c893Smrg    switch (radeon_encoder->encoder_id) {
1633b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_LVDS:
1634b7e1c893Smrg	ErrorF("set LVDS\n");
1635b7e1c893Smrg	RADEONInitLVDSRegisters(output, info->ModeReg, adjusted_mode, is_primary);
1636209ff23fSmrg	RADEONRestoreLVDSRegisters(pScrn, info->ModeReg);
1637209ff23fSmrg	break;
1638b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1639b7e1c893Smrg	ErrorF("set FP1\n");
1640b7e1c893Smrg	RADEONInitFPRegisters(output, info->ModeReg, adjusted_mode, is_primary);
1641b7e1c893Smrg	RADEONRestoreFPRegisters(pScrn, info->ModeReg);
1642b7e1c893Smrg	break;
1643b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1644b7e1c893Smrg	ErrorF("set FP2\n");
1645b7e1c893Smrg	RADEONInitFP2Registers(output, info->ModeReg, adjusted_mode, is_primary);
1646b7e1c893Smrg	if (info->IsAtomBios) {
1647b7e1c893Smrg	    unsigned char *RADEONMMIO = info->MMIO;
1648b7e1c893Smrg	    uint32_t fp2_gen_cntl;
1649b7e1c893Smrg
1650b7e1c893Smrg	    atombios_external_tmds_setup(output, ATOM_ENABLE);
1651b7e1c893Smrg	    fp2_gen_cntl = INREG(RADEON_FP2_GEN_CNTL) & ~R200_FP2_SOURCE_SEL_MASK;
1652b7e1c893Smrg	    if (radeon_crtc->crtc_id == 1)
1653b7e1c893Smrg		fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2;
1654b7e1c893Smrg	    else {
1655b7e1c893Smrg		if (radeon_output->Flags & RADEON_USE_RMX)
1656b7e1c893Smrg		    fp2_gen_cntl |= R200_FP2_SOURCE_SEL_RMX;
1657b7e1c893Smrg		else
1658b7e1c893Smrg		    fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC1;
1659209ff23fSmrg	    }
1660b7e1c893Smrg	    OUTREG(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
1661b7e1c893Smrg	} else {
1662b7e1c893Smrg	    RADEONRestoreFP2Registers(pScrn, info->ModeReg);
1663b7e1c893Smrg	    RADEONRestoreDVOChip(pScrn, output);
1664209ff23fSmrg	}
1665209ff23fSmrg	break;
1666b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC1:
1667b7e1c893Smrg	ErrorF("set primary dac\n");
1668b7e1c893Smrg	RADEONInitDACRegisters(output, info->ModeReg, adjusted_mode, is_primary);
1669209ff23fSmrg	RADEONRestoreDACRegisters(pScrn, info->ModeReg);
1670209ff23fSmrg	break;
1671b7e1c893Smrg    case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1672b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
1673b7e1c893Smrg	    ErrorF("set TV\n");
1674b7e1c893Smrg	    RADEONInitTVRegisters(output, info->ModeReg, adjusted_mode, is_primary);
1675b7e1c893Smrg	    RADEONRestoreDACRegisters(pScrn, info->ModeReg);
1676b7e1c893Smrg	    RADEONRestoreTVRegisters(pScrn, info->ModeReg);
1677b7e1c893Smrg	} else {
1678b7e1c893Smrg	    ErrorF("set TVDAC\n");
1679b7e1c893Smrg	    RADEONInitDAC2Registers(output, info->ModeReg, adjusted_mode, is_primary);
1680b7e1c893Smrg	    RADEONRestoreDACRegisters(pScrn, info->ModeReg);
1681b7e1c893Smrg	}
1682b7e1c893Smrg	break;
1683209ff23fSmrg    }
1684209ff23fSmrg
1685209ff23fSmrg}
1686209ff23fSmrg
1687209ff23fSmrg/* the following functions are based on the load detection code
1688209ff23fSmrg * in the beos radeon driver by Thomas Kurschel and the existing
1689209ff23fSmrg * load detection code in this driver.
1690209ff23fSmrg */
1691209ff23fSmrgstatic RADEONMonitorType
1692209ff23fSmrgradeon_detect_primary_dac(ScrnInfoPtr pScrn, Bool color)
1693209ff23fSmrg{
1694209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
1695209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
1696209ff23fSmrg    uint32_t vclk_ecp_cntl, crtc_ext_cntl;
1697209ff23fSmrg    uint32_t dac_ext_cntl, dac_cntl, dac_macro_cntl, tmp;
1698209ff23fSmrg    RADEONMonitorType found = MT_NONE;
1699209ff23fSmrg
1700209ff23fSmrg    /* save the regs we need */
1701209ff23fSmrg    vclk_ecp_cntl = INPLL(pScrn, RADEON_VCLK_ECP_CNTL);
1702209ff23fSmrg    crtc_ext_cntl = INREG(RADEON_CRTC_EXT_CNTL);
1703209ff23fSmrg    dac_ext_cntl = INREG(RADEON_DAC_EXT_CNTL);
1704209ff23fSmrg    dac_cntl = INREG(RADEON_DAC_CNTL);
1705209ff23fSmrg    dac_macro_cntl = INREG(RADEON_DAC_MACRO_CNTL);
1706209ff23fSmrg
1707209ff23fSmrg    tmp = vclk_ecp_cntl &
1708209ff23fSmrg	~(RADEON_PIXCLK_ALWAYS_ONb | RADEON_PIXCLK_DAC_ALWAYS_ONb);
1709209ff23fSmrg    OUTPLL(pScrn, RADEON_VCLK_ECP_CNTL, tmp);
1710209ff23fSmrg
1711209ff23fSmrg    tmp = crtc_ext_cntl | RADEON_CRTC_CRT_ON;
1712209ff23fSmrg    OUTREG(RADEON_CRTC_EXT_CNTL, tmp);
1713209ff23fSmrg
1714209ff23fSmrg    tmp = RADEON_DAC_FORCE_BLANK_OFF_EN |
1715209ff23fSmrg	RADEON_DAC_FORCE_DATA_EN;
1716209ff23fSmrg
1717209ff23fSmrg    if (color)
1718209ff23fSmrg	tmp |= RADEON_DAC_FORCE_DATA_SEL_RGB;
1719209ff23fSmrg    else
1720209ff23fSmrg	tmp |= RADEON_DAC_FORCE_DATA_SEL_G;
1721209ff23fSmrg
1722209ff23fSmrg    if (IS_R300_VARIANT)
1723209ff23fSmrg	tmp |= (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT);
1724209ff23fSmrg    else
1725209ff23fSmrg	tmp |= (0x180 << RADEON_DAC_FORCE_DATA_SHIFT);
1726209ff23fSmrg
1727209ff23fSmrg    OUTREG(RADEON_DAC_EXT_CNTL, tmp);
1728209ff23fSmrg
1729209ff23fSmrg    tmp = dac_cntl & ~(RADEON_DAC_RANGE_CNTL_MASK | RADEON_DAC_PDWN);
1730209ff23fSmrg    tmp |= RADEON_DAC_RANGE_CNTL_PS2 | RADEON_DAC_CMP_EN;
1731209ff23fSmrg    OUTREG(RADEON_DAC_CNTL, tmp);
1732209ff23fSmrg
1733209ff23fSmrg    tmp &= ~(RADEON_DAC_PDWN_R |
1734209ff23fSmrg	     RADEON_DAC_PDWN_G |
1735209ff23fSmrg	     RADEON_DAC_PDWN_B);
1736209ff23fSmrg
1737209ff23fSmrg    OUTREG(RADEON_DAC_MACRO_CNTL, tmp);
1738209ff23fSmrg
1739209ff23fSmrg    usleep(2000);
1740209ff23fSmrg
1741209ff23fSmrg    if (INREG(RADEON_DAC_CNTL) & RADEON_DAC_CMP_OUTPUT) {
1742209ff23fSmrg	found = MT_CRT;
1743209ff23fSmrg	xf86DrvMsg (pScrn->scrnIndex, X_INFO,
1744209ff23fSmrg		    "Found %s CRT connected to primary DAC\n",
1745209ff23fSmrg		    color ? "color" : "bw");
1746209ff23fSmrg    }
1747209ff23fSmrg
1748209ff23fSmrg    /* restore the regs we used */
1749209ff23fSmrg    OUTREG(RADEON_DAC_CNTL, dac_cntl);
1750209ff23fSmrg    OUTREG(RADEON_DAC_MACRO_CNTL, dac_macro_cntl);
1751209ff23fSmrg    OUTREG(RADEON_DAC_EXT_CNTL, dac_ext_cntl);
1752209ff23fSmrg    OUTREG(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl);
1753209ff23fSmrg    OUTPLL(pScrn, RADEON_VCLK_ECP_CNTL, vclk_ecp_cntl);
1754209ff23fSmrg
1755209ff23fSmrg    return found;
1756209ff23fSmrg}
1757209ff23fSmrg
1758209ff23fSmrgstatic RADEONMonitorType
1759209ff23fSmrgradeon_detect_ext_dac(ScrnInfoPtr pScrn)
1760209ff23fSmrg{
1761209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
1762209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
1763209ff23fSmrg    uint32_t gpio_monid, fp2_gen_cntl, disp_output_cntl, crtc2_gen_cntl;
1764209ff23fSmrg    uint32_t disp_lin_trans_grph_a, disp_lin_trans_grph_b, disp_lin_trans_grph_c;
1765209ff23fSmrg    uint32_t disp_lin_trans_grph_d, disp_lin_trans_grph_e, disp_lin_trans_grph_f;
1766209ff23fSmrg    uint32_t tmp, crtc2_h_total_disp, crtc2_v_total_disp;
1767209ff23fSmrg    uint32_t crtc2_h_sync_strt_wid, crtc2_v_sync_strt_wid;
1768209ff23fSmrg    RADEONMonitorType found = MT_NONE;
1769209ff23fSmrg    int connected = 0;
1770209ff23fSmrg    int i = 0;
1771209ff23fSmrg
1772209ff23fSmrg    /* save the regs we need */
1773209ff23fSmrg    gpio_monid = INREG(RADEON_GPIO_MONID);
1774209ff23fSmrg    fp2_gen_cntl = INREG(RADEON_FP2_GEN_CNTL);
1775209ff23fSmrg    disp_output_cntl = INREG(RADEON_DISP_OUTPUT_CNTL);
1776209ff23fSmrg    crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL);
1777209ff23fSmrg    disp_lin_trans_grph_a = INREG(RADEON_DISP_LIN_TRANS_GRPH_A);
1778209ff23fSmrg    disp_lin_trans_grph_b = INREG(RADEON_DISP_LIN_TRANS_GRPH_B);
1779209ff23fSmrg    disp_lin_trans_grph_c = INREG(RADEON_DISP_LIN_TRANS_GRPH_C);
1780209ff23fSmrg    disp_lin_trans_grph_d = INREG(RADEON_DISP_LIN_TRANS_GRPH_D);
1781209ff23fSmrg    disp_lin_trans_grph_e = INREG(RADEON_DISP_LIN_TRANS_GRPH_E);
1782209ff23fSmrg    disp_lin_trans_grph_f = INREG(RADEON_DISP_LIN_TRANS_GRPH_F);
1783209ff23fSmrg    crtc2_h_total_disp = INREG(RADEON_CRTC2_H_TOTAL_DISP);
1784209ff23fSmrg    crtc2_v_total_disp = INREG(RADEON_CRTC2_V_TOTAL_DISP);
1785209ff23fSmrg    crtc2_h_sync_strt_wid = INREG(RADEON_CRTC2_H_SYNC_STRT_WID);
1786209ff23fSmrg    crtc2_v_sync_strt_wid = INREG(RADEON_CRTC2_V_SYNC_STRT_WID);
1787209ff23fSmrg
1788209ff23fSmrg    tmp = INREG(RADEON_GPIO_MONID);
1789209ff23fSmrg    tmp &= ~RADEON_GPIO_A_0;
1790209ff23fSmrg    OUTREG(RADEON_GPIO_MONID, tmp);
1791209ff23fSmrg
1792209ff23fSmrg    OUTREG(RADEON_FP2_GEN_CNTL,
1793209ff23fSmrg	   RADEON_FP2_ON |
1794209ff23fSmrg	   RADEON_FP2_PANEL_FORMAT |
1795209ff23fSmrg	   R200_FP2_SOURCE_SEL_TRANS_UNIT |
1796209ff23fSmrg	   RADEON_FP2_DVO_EN |
1797209ff23fSmrg	   R200_FP2_DVO_RATE_SEL_SDR);
1798209ff23fSmrg
1799209ff23fSmrg    OUTREG(RADEON_DISP_OUTPUT_CNTL,
1800209ff23fSmrg	   RADEON_DISP_DAC_SOURCE_RMX |
1801209ff23fSmrg	   RADEON_DISP_TRANS_MATRIX_GRAPHICS);
1802209ff23fSmrg
1803209ff23fSmrg    OUTREG(RADEON_CRTC2_GEN_CNTL,
1804209ff23fSmrg	   RADEON_CRTC2_EN |
1805209ff23fSmrg	   RADEON_CRTC2_DISP_REQ_EN_B);
1806209ff23fSmrg
1807209ff23fSmrg    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_A, 0x00000000);
1808209ff23fSmrg    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_B, 0x000003f0);
1809209ff23fSmrg    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_C, 0x00000000);
1810209ff23fSmrg    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_D, 0x000003f0);
1811209ff23fSmrg    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_E, 0x00000000);
1812209ff23fSmrg    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_F, 0x000003f0);
1813209ff23fSmrg
1814209ff23fSmrg    OUTREG(RADEON_CRTC2_H_TOTAL_DISP, 0x01000008);
1815209ff23fSmrg    OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, 0x00000800);
1816209ff23fSmrg    OUTREG(RADEON_CRTC2_V_TOTAL_DISP, 0x00080001);
1817209ff23fSmrg    OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, 0x00000080);
1818209ff23fSmrg
1819209ff23fSmrg    for (i = 0; i < 200; i++) {
1820209ff23fSmrg	tmp = INREG(RADEON_GPIO_MONID);
1821209ff23fSmrg	if (tmp & RADEON_GPIO_Y_0)
1822209ff23fSmrg	    connected = 1;
1823209ff23fSmrg	else
1824209ff23fSmrg	    connected = 0;
1825209ff23fSmrg
1826209ff23fSmrg	if (!connected)
1827209ff23fSmrg	    break;
1828209ff23fSmrg
1829209ff23fSmrg	usleep(1000);
1830209ff23fSmrg    }
1831209ff23fSmrg
1832209ff23fSmrg    if (connected)
1833209ff23fSmrg	found = MT_CRT;
1834209ff23fSmrg
1835209ff23fSmrg    /* restore the regs we used */
1836209ff23fSmrg    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_A, disp_lin_trans_grph_a);
1837209ff23fSmrg    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_B, disp_lin_trans_grph_b);
1838209ff23fSmrg    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_C, disp_lin_trans_grph_c);
1839209ff23fSmrg    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_D, disp_lin_trans_grph_d);
1840209ff23fSmrg    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_E, disp_lin_trans_grph_e);
1841209ff23fSmrg    OUTREG(RADEON_DISP_LIN_TRANS_GRPH_F, disp_lin_trans_grph_f);
1842209ff23fSmrg    OUTREG(RADEON_CRTC2_H_TOTAL_DISP, crtc2_h_total_disp);
1843209ff23fSmrg    OUTREG(RADEON_CRTC2_V_TOTAL_DISP, crtc2_v_total_disp);
1844209ff23fSmrg    OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, crtc2_h_sync_strt_wid);
1845209ff23fSmrg    OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, crtc2_v_sync_strt_wid);
1846209ff23fSmrg    OUTREG(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
1847209ff23fSmrg    OUTREG(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl);
1848209ff23fSmrg    OUTREG(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
1849209ff23fSmrg    OUTREG(RADEON_GPIO_MONID, gpio_monid);
1850209ff23fSmrg
1851209ff23fSmrg    return found;
1852209ff23fSmrg}
1853209ff23fSmrg
1854209ff23fSmrgstatic RADEONMonitorType
1855209ff23fSmrgradeon_detect_tv_dac(ScrnInfoPtr pScrn, Bool color)
1856209ff23fSmrg{
1857209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
1858209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
1859209ff23fSmrg    uint32_t crtc2_gen_cntl, tv_dac_cntl, dac_cntl2, dac_ext_cntl;
1860209ff23fSmrg    uint32_t disp_hw_debug, disp_output_cntl, gpiopad_a, pixclks_cntl, tmp;
1861209ff23fSmrg    RADEONMonitorType found = MT_NONE;
1862209ff23fSmrg
1863209ff23fSmrg    /* save the regs we need */
1864209ff23fSmrg    pixclks_cntl = INPLL(pScrn, RADEON_PIXCLKS_CNTL);
1865209ff23fSmrg    gpiopad_a = IS_R300_VARIANT ? INREG(RADEON_GPIOPAD_A) : 0;
1866209ff23fSmrg    disp_output_cntl = IS_R300_VARIANT ? INREG(RADEON_DISP_OUTPUT_CNTL) : 0;
1867209ff23fSmrg    disp_hw_debug = !IS_R300_VARIANT ? INREG(RADEON_DISP_HW_DEBUG) : 0;
1868209ff23fSmrg    crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL);
1869209ff23fSmrg    tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL);
1870209ff23fSmrg    dac_ext_cntl = INREG(RADEON_DAC_EXT_CNTL);
1871209ff23fSmrg    dac_cntl2 = INREG(RADEON_DAC_CNTL2);
1872209ff23fSmrg
1873209ff23fSmrg    tmp = pixclks_cntl & ~(RADEON_PIX2CLK_ALWAYS_ONb
1874209ff23fSmrg			   | RADEON_PIX2CLK_DAC_ALWAYS_ONb);
1875209ff23fSmrg    OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, tmp);
1876209ff23fSmrg
1877209ff23fSmrg    if (IS_R300_VARIANT) {
1878209ff23fSmrg	OUTREGP(RADEON_GPIOPAD_A, 1, ~1 );
1879209ff23fSmrg    }
1880209ff23fSmrg
1881209ff23fSmrg    tmp = crtc2_gen_cntl & ~RADEON_CRTC2_PIX_WIDTH_MASK;
1882209ff23fSmrg    tmp |= RADEON_CRTC2_CRT2_ON |
1883209ff23fSmrg	(2 << RADEON_CRTC2_PIX_WIDTH_SHIFT);
1884209ff23fSmrg
1885209ff23fSmrg    OUTREG(RADEON_CRTC2_GEN_CNTL, tmp);
1886209ff23fSmrg
1887209ff23fSmrg    if (IS_R300_VARIANT) {
1888209ff23fSmrg	tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK;
1889209ff23fSmrg	tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2;
1890209ff23fSmrg	OUTREG(RADEON_DISP_OUTPUT_CNTL, tmp);
1891209ff23fSmrg    } else {
1892209ff23fSmrg	tmp = disp_hw_debug & ~RADEON_CRT2_DISP1_SEL;
1893209ff23fSmrg	OUTREG(RADEON_DISP_HW_DEBUG, tmp);
1894209ff23fSmrg    }
1895209ff23fSmrg
1896209ff23fSmrg    tmp = RADEON_TV_DAC_NBLANK |
1897209ff23fSmrg	RADEON_TV_DAC_NHOLD |
1898209ff23fSmrg	RADEON_TV_MONITOR_DETECT_EN |
1899209ff23fSmrg	RADEON_TV_DAC_STD_PS2;
1900209ff23fSmrg
1901209ff23fSmrg    OUTREG(RADEON_TV_DAC_CNTL, tmp);
1902209ff23fSmrg
1903209ff23fSmrg    tmp = RADEON_DAC2_FORCE_BLANK_OFF_EN |
1904209ff23fSmrg	RADEON_DAC2_FORCE_DATA_EN;
1905209ff23fSmrg
1906209ff23fSmrg    if (color)
1907209ff23fSmrg	tmp |= RADEON_DAC_FORCE_DATA_SEL_RGB;
1908209ff23fSmrg    else
1909209ff23fSmrg	tmp |= RADEON_DAC_FORCE_DATA_SEL_G;
1910209ff23fSmrg
1911209ff23fSmrg    if (IS_R300_VARIANT)
1912209ff23fSmrg	tmp |= (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT);
1913209ff23fSmrg    else
1914209ff23fSmrg	tmp |= (0x180 << RADEON_DAC_FORCE_DATA_SHIFT);
1915209ff23fSmrg
1916209ff23fSmrg    OUTREG(RADEON_DAC_EXT_CNTL, tmp);
1917209ff23fSmrg
1918209ff23fSmrg    tmp = dac_cntl2 | RADEON_DAC2_DAC2_CLK_SEL | RADEON_DAC2_CMP_EN;
1919209ff23fSmrg    OUTREG(RADEON_DAC_CNTL2, tmp);
1920209ff23fSmrg
1921209ff23fSmrg    usleep(10000);
1922209ff23fSmrg
1923209ff23fSmrg    if (IS_R300_VARIANT) {
1924209ff23fSmrg	if (INREG(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUT_B) {
1925209ff23fSmrg	    found = MT_CRT;
1926209ff23fSmrg	    xf86DrvMsg (pScrn->scrnIndex, X_INFO,
1927209ff23fSmrg			"Found %s CRT connected to TV DAC\n",
1928209ff23fSmrg			color ? "color" : "bw");
1929209ff23fSmrg	}
1930209ff23fSmrg    } else {
1931209ff23fSmrg	if (INREG(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUTPUT) {
1932209ff23fSmrg	    found = MT_CRT;
1933209ff23fSmrg	    xf86DrvMsg (pScrn->scrnIndex, X_INFO,
1934209ff23fSmrg			"Found %s CRT connected to TV DAC\n",
1935209ff23fSmrg			color ? "color" : "bw");
1936209ff23fSmrg	}
1937209ff23fSmrg    }
1938209ff23fSmrg
1939209ff23fSmrg    /* restore regs we used */
1940209ff23fSmrg    OUTREG(RADEON_DAC_CNTL2, dac_cntl2);
1941209ff23fSmrg    OUTREG(RADEON_DAC_EXT_CNTL, dac_ext_cntl);
1942209ff23fSmrg    OUTREG(RADEON_TV_DAC_CNTL, tv_dac_cntl);
1943209ff23fSmrg    OUTREG(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
1944209ff23fSmrg
1945209ff23fSmrg    if (IS_R300_VARIANT) {
1946209ff23fSmrg	OUTREG(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl);
1947209ff23fSmrg	OUTREGP(RADEON_GPIOPAD_A, gpiopad_a, ~1 );
1948209ff23fSmrg    } else {
1949209ff23fSmrg	OUTREG(RADEON_DISP_HW_DEBUG, disp_hw_debug);
1950209ff23fSmrg    }
1951209ff23fSmrg    OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, pixclks_cntl);
1952209ff23fSmrg
1953209ff23fSmrg    return found;
1954209ff23fSmrg}
1955209ff23fSmrg
1956209ff23fSmrgstatic RADEONMonitorType
1957209ff23fSmrgr300_detect_tv(ScrnInfoPtr pScrn)
1958209ff23fSmrg{
1959209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
1960209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
1961209ff23fSmrg    uint32_t tmp, dac_cntl2, crtc2_gen_cntl, dac_ext_cntl, tv_dac_cntl;
1962209ff23fSmrg    uint32_t gpiopad_a, disp_output_cntl;
1963209ff23fSmrg    RADEONMonitorType found = MT_NONE;
1964209ff23fSmrg
1965209ff23fSmrg    /* save the regs we need */
1966209ff23fSmrg    gpiopad_a = INREG(RADEON_GPIOPAD_A);
1967209ff23fSmrg    dac_cntl2 = INREG(RADEON_DAC_CNTL2);
1968209ff23fSmrg    crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL);
1969209ff23fSmrg    dac_ext_cntl = INREG(RADEON_DAC_EXT_CNTL);
1970209ff23fSmrg    tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL);
1971209ff23fSmrg    disp_output_cntl = INREG(RADEON_DISP_OUTPUT_CNTL);
1972209ff23fSmrg
1973209ff23fSmrg    OUTREGP(RADEON_GPIOPAD_A, 0, ~1 );
1974209ff23fSmrg
1975209ff23fSmrg    OUTREG(RADEON_DAC_CNTL2, RADEON_DAC2_DAC2_CLK_SEL );
1976209ff23fSmrg
1977209ff23fSmrg    OUTREG(RADEON_CRTC2_GEN_CNTL,
1978209ff23fSmrg	   RADEON_CRTC2_CRT2_ON | RADEON_CRTC2_VSYNC_TRISTAT );
1979209ff23fSmrg
1980209ff23fSmrg    tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK;
1981209ff23fSmrg    tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2;
1982209ff23fSmrg    OUTREG(RADEON_DISP_OUTPUT_CNTL, tmp);
1983209ff23fSmrg
1984209ff23fSmrg    OUTREG(RADEON_DAC_EXT_CNTL,
1985209ff23fSmrg	   RADEON_DAC2_FORCE_BLANK_OFF_EN |
1986209ff23fSmrg	   RADEON_DAC2_FORCE_DATA_EN |
1987209ff23fSmrg	   RADEON_DAC_FORCE_DATA_SEL_RGB |
1988209ff23fSmrg	   (0xec << RADEON_DAC_FORCE_DATA_SHIFT ));
1989209ff23fSmrg
1990209ff23fSmrg    OUTREG(RADEON_TV_DAC_CNTL,
1991209ff23fSmrg	   RADEON_TV_DAC_STD_NTSC |
1992209ff23fSmrg	   (8 << RADEON_TV_DAC_BGADJ_SHIFT) |
1993209ff23fSmrg	   (6 << RADEON_TV_DAC_DACADJ_SHIFT ));
1994209ff23fSmrg
1995209ff23fSmrg    INREG(RADEON_TV_DAC_CNTL);
1996209ff23fSmrg
1997209ff23fSmrg    usleep(4000);
1998209ff23fSmrg
1999209ff23fSmrg    OUTREG(RADEON_TV_DAC_CNTL,
2000209ff23fSmrg	   RADEON_TV_DAC_NBLANK |
2001209ff23fSmrg	   RADEON_TV_DAC_NHOLD |
2002209ff23fSmrg	   RADEON_TV_MONITOR_DETECT_EN |
2003209ff23fSmrg	   RADEON_TV_DAC_STD_NTSC |
2004209ff23fSmrg	   (8 << RADEON_TV_DAC_BGADJ_SHIFT) |
2005209ff23fSmrg	   (6 << RADEON_TV_DAC_DACADJ_SHIFT ));
2006209ff23fSmrg
2007209ff23fSmrg    INREG(RADEON_TV_DAC_CNTL);
2008209ff23fSmrg
2009209ff23fSmrg    usleep(6000);
2010209ff23fSmrg
2011209ff23fSmrg    tmp = INREG(RADEON_TV_DAC_CNTL);
2012209ff23fSmrg    if ( (tmp & RADEON_TV_DAC_GDACDET) != 0 ) {
2013209ff23fSmrg	found = MT_STV;
2014209ff23fSmrg	xf86DrvMsg (pScrn->scrnIndex, X_INFO,
2015209ff23fSmrg		    "S-Video TV connection detected\n");
2016209ff23fSmrg    } else if ( (tmp & RADEON_TV_DAC_BDACDET) != 0 ) {
2017209ff23fSmrg	found = MT_CTV;
2018209ff23fSmrg	xf86DrvMsg (pScrn->scrnIndex, X_INFO,
2019209ff23fSmrg		    "Composite TV connection detected\n" );
2020209ff23fSmrg    }
2021209ff23fSmrg
2022209ff23fSmrg    OUTREG(RADEON_TV_DAC_CNTL, tv_dac_cntl );
2023209ff23fSmrg    OUTREG(RADEON_DAC_EXT_CNTL, dac_ext_cntl);
2024209ff23fSmrg    OUTREG(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
2025209ff23fSmrg    OUTREG(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl);
2026209ff23fSmrg    OUTREG(RADEON_DAC_CNTL2, dac_cntl2);
2027209ff23fSmrg    OUTREGP(RADEON_GPIOPAD_A, gpiopad_a, ~1);
2028209ff23fSmrg
2029209ff23fSmrg    return found;
2030209ff23fSmrg}
2031209ff23fSmrg
2032209ff23fSmrgstatic RADEONMonitorType
2033209ff23fSmrgradeon_detect_tv(ScrnInfoPtr pScrn)
2034209ff23fSmrg{
2035209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
2036209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
2037209ff23fSmrg    uint32_t tmp, dac_cntl2, tv_master_cntl;
2038209ff23fSmrg    uint32_t tv_dac_cntl, tv_pre_dac_mux_cntl, config_cntl;
2039209ff23fSmrg    RADEONMonitorType found = MT_NONE;
2040209ff23fSmrg
2041209ff23fSmrg    if (IS_R300_VARIANT)
2042209ff23fSmrg	return r300_detect_tv(pScrn);
2043209ff23fSmrg
2044209ff23fSmrg    /* save the regs we need */
2045209ff23fSmrg    dac_cntl2 = INREG(RADEON_DAC_CNTL2);
2046209ff23fSmrg    tv_master_cntl = INREG(RADEON_TV_MASTER_CNTL);
2047209ff23fSmrg    tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL);
2048209ff23fSmrg    config_cntl = INREG(RADEON_CONFIG_CNTL);
2049209ff23fSmrg    tv_pre_dac_mux_cntl = INREG(RADEON_TV_PRE_DAC_MUX_CNTL);
2050209ff23fSmrg
2051209ff23fSmrg    tmp = dac_cntl2 & ~RADEON_DAC2_DAC2_CLK_SEL;
2052209ff23fSmrg    OUTREG(RADEON_DAC_CNTL2, tmp);
2053209ff23fSmrg
2054209ff23fSmrg    tmp = tv_master_cntl | RADEON_TV_ON;
2055209ff23fSmrg    tmp &= ~(RADEON_TV_ASYNC_RST |
2056209ff23fSmrg	     RADEON_RESTART_PHASE_FIX |
2057209ff23fSmrg	     RADEON_CRT_FIFO_CE_EN |
2058209ff23fSmrg	     RADEON_TV_FIFO_CE_EN |
2059209ff23fSmrg	     RADEON_RE_SYNC_NOW_SEL_MASK);
2060209ff23fSmrg    tmp |= RADEON_TV_FIFO_ASYNC_RST | RADEON_CRT_ASYNC_RST;
2061209ff23fSmrg
2062209ff23fSmrg    OUTREG(RADEON_TV_MASTER_CNTL, tmp);
2063209ff23fSmrg
2064209ff23fSmrg    tmp = RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD |
2065209ff23fSmrg	RADEON_TV_MONITOR_DETECT_EN | RADEON_TV_DAC_STD_NTSC |
2066209ff23fSmrg	(8 << RADEON_TV_DAC_BGADJ_SHIFT);
2067209ff23fSmrg
2068209ff23fSmrg    if (config_cntl & RADEON_CFG_ATI_REV_ID_MASK)
2069209ff23fSmrg	tmp |= (4 << RADEON_TV_DAC_DACADJ_SHIFT);
2070209ff23fSmrg    else
2071209ff23fSmrg	tmp |= (8 << RADEON_TV_DAC_DACADJ_SHIFT);
2072209ff23fSmrg
2073209ff23fSmrg    OUTREG(RADEON_TV_DAC_CNTL, tmp);
2074209ff23fSmrg
2075209ff23fSmrg    tmp = RADEON_C_GRN_EN | RADEON_CMP_BLU_EN |
2076209ff23fSmrg	RADEON_RED_MX_FORCE_DAC_DATA |
2077209ff23fSmrg	RADEON_GRN_MX_FORCE_DAC_DATA |
2078209ff23fSmrg	RADEON_BLU_MX_FORCE_DAC_DATA |
2079209ff23fSmrg	(0x109 << RADEON_TV_FORCE_DAC_DATA_SHIFT);
2080209ff23fSmrg
2081209ff23fSmrg    OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, tmp);
2082209ff23fSmrg
2083209ff23fSmrg    usleep(3000);
2084209ff23fSmrg
2085209ff23fSmrg    tmp = INREG(RADEON_TV_DAC_CNTL);
2086209ff23fSmrg    if (tmp & RADEON_TV_DAC_GDACDET) {
2087209ff23fSmrg	found = MT_STV;
2088209ff23fSmrg	xf86DrvMsg (pScrn->scrnIndex, X_INFO,
2089209ff23fSmrg		    "S-Video TV connection detected\n");
2090209ff23fSmrg    } else if (tmp & RADEON_TV_DAC_BDACDET) {
2091209ff23fSmrg	found = MT_CTV;
2092209ff23fSmrg	xf86DrvMsg (pScrn->scrnIndex, X_INFO,
2093209ff23fSmrg		    "Composite TV connection detected\n" );
2094209ff23fSmrg    }
2095209ff23fSmrg
2096209ff23fSmrg    OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, tv_pre_dac_mux_cntl);
2097209ff23fSmrg    OUTREG(RADEON_TV_DAC_CNTL, tv_dac_cntl);
2098209ff23fSmrg    OUTREG(RADEON_TV_MASTER_CNTL, tv_master_cntl);
2099209ff23fSmrg    OUTREG(RADEON_DAC_CNTL2, dac_cntl2);
2100209ff23fSmrg
2101209ff23fSmrg    return found;
2102209ff23fSmrg}
2103