legacy_crtc.c revision 209ff23f
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
49209ff23fSmrg#ifdef XF86DRI
50209ff23fSmrg#define _XF86DRI_SERVER_
51209ff23fSmrg#include "radeon_dri.h"
52209ff23fSmrg#include "radeon_sarea.h"
53209ff23fSmrg#include "sarea.h"
54209ff23fSmrg#ifdef DRM_IOCTL_MODESET_CTL
55209ff23fSmrg#include <sys/ioctl.h>
56209ff23fSmrg#endif
57209ff23fSmrg#endif
58209ff23fSmrg
59209ff23fSmrg/* Write common registers */
60209ff23fSmrgvoid
61209ff23fSmrgRADEONRestoreCommonRegisters(ScrnInfoPtr pScrn,
62209ff23fSmrg			     RADEONSavePtr restore)
63209ff23fSmrg{
64209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
65209ff23fSmrg    RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
66209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
67209ff23fSmrg
68209ff23fSmrg    if (info->IsSecondary)
69209ff23fSmrg      return;
70209ff23fSmrg
71209ff23fSmrg    OUTREG(RADEON_OVR_CLR,            restore->ovr_clr);
72209ff23fSmrg    OUTREG(RADEON_OVR_WID_LEFT_RIGHT, restore->ovr_wid_left_right);
73209ff23fSmrg    OUTREG(RADEON_OVR_WID_TOP_BOTTOM, restore->ovr_wid_top_bottom);
74209ff23fSmrg    OUTREG(RADEON_OV0_SCALE_CNTL,     restore->ov0_scale_cntl);
75209ff23fSmrg    OUTREG(RADEON_SUBPIC_CNTL,        restore->subpic_cntl);
76209ff23fSmrg    OUTREG(RADEON_VIPH_CONTROL,       restore->viph_control);
77209ff23fSmrg    OUTREG(RADEON_I2C_CNTL_1,         restore->i2c_cntl_1);
78209ff23fSmrg    OUTREG(RADEON_GEN_INT_CNTL,       restore->gen_int_cntl);
79209ff23fSmrg    OUTREG(RADEON_CAP0_TRIG_CNTL,     restore->cap0_trig_cntl);
80209ff23fSmrg    OUTREG(RADEON_CAP1_TRIG_CNTL,     restore->cap1_trig_cntl);
81209ff23fSmrg    OUTREG(RADEON_BUS_CNTL,           restore->bus_cntl);
82209ff23fSmrg    OUTREG(RADEON_SURFACE_CNTL,       restore->surface_cntl);
83209ff23fSmrg
84209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_RS400)  ||
85209ff23fSmrg	(info->ChipFamily == CHIP_FAMILY_RS480)) {
86209ff23fSmrg	OUTREG(RS400_DISP2_REQ_CNTL1, restore->disp2_req_cntl1);
87209ff23fSmrg	OUTREG(RS400_DISP2_REQ_CNTL2, restore->disp2_req_cntl2);
88209ff23fSmrg	OUTREG(RS400_DMIF_MEM_CNTL1,  restore->dmif_mem_cntl1);
89209ff23fSmrg	OUTREG(RS400_DISP1_REQ_CNTL1, restore->disp1_req_cntl1);
90209ff23fSmrg    }
91209ff23fSmrg
92209ff23fSmrg    /* Workaround for the VT switching problem in dual-head mode.  This
93209ff23fSmrg     * problem only occurs on RV style chips, typically when a FP and
94209ff23fSmrg     * CRT are connected.
95209ff23fSmrg     */
96209ff23fSmrg    if (pRADEONEnt->HasCRTC2 &&
97209ff23fSmrg	info->ChipFamily != CHIP_FAMILY_R200 &&
98209ff23fSmrg	!IS_R300_VARIANT) {
99209ff23fSmrg	uint32_t tmp;
100209ff23fSmrg
101209ff23fSmrg	tmp = INREG(RADEON_DAC_CNTL2);
102209ff23fSmrg	OUTREG(RADEON_DAC_CNTL2, tmp & ~RADEON_DAC2_DAC_CLK_SEL);
103209ff23fSmrg	usleep(100000);
104209ff23fSmrg    }
105209ff23fSmrg}
106209ff23fSmrg
107209ff23fSmrg
108209ff23fSmrg/* Write CRTC registers */
109209ff23fSmrgvoid
110209ff23fSmrgRADEONRestoreCrtcRegisters(ScrnInfoPtr pScrn,
111209ff23fSmrg			   RADEONSavePtr restore)
112209ff23fSmrg{
113209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
114209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
115209ff23fSmrg
116209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
117209ff23fSmrg		   "Programming CRTC1, offset: 0x%08x\n",
118209ff23fSmrg		   (unsigned)restore->crtc_offset);
119209ff23fSmrg
120209ff23fSmrg    /* We prevent the CRTC from hitting the memory controller until
121209ff23fSmrg     * fully programmed
122209ff23fSmrg     */
123209ff23fSmrg    OUTREG(RADEON_CRTC_GEN_CNTL, restore->crtc_gen_cntl |
124209ff23fSmrg	   RADEON_CRTC_DISP_REQ_EN_B);
125209ff23fSmrg
126209ff23fSmrg    OUTREGP(RADEON_CRTC_EXT_CNTL,
127209ff23fSmrg	    restore->crtc_ext_cntl,
128209ff23fSmrg	    RADEON_CRTC_VSYNC_DIS |
129209ff23fSmrg	    RADEON_CRTC_HSYNC_DIS |
130209ff23fSmrg	    RADEON_CRTC_DISPLAY_DIS);
131209ff23fSmrg
132209ff23fSmrg    OUTREG(RADEON_CRTC_H_TOTAL_DISP,    restore->crtc_h_total_disp);
133209ff23fSmrg    OUTREG(RADEON_CRTC_H_SYNC_STRT_WID, restore->crtc_h_sync_strt_wid);
134209ff23fSmrg    OUTREG(RADEON_CRTC_V_TOTAL_DISP,    restore->crtc_v_total_disp);
135209ff23fSmrg    OUTREG(RADEON_CRTC_V_SYNC_STRT_WID, restore->crtc_v_sync_strt_wid);
136209ff23fSmrg
137209ff23fSmrg    if (IS_R300_VARIANT)
138209ff23fSmrg	OUTREG(R300_CRTC_TILE_X0_Y0, restore->crtc_tile_x0_y0);
139209ff23fSmrg    OUTREG(RADEON_CRTC_OFFSET_CNTL,     restore->crtc_offset_cntl);
140209ff23fSmrg    OUTREG(RADEON_CRTC_OFFSET,          restore->crtc_offset);
141209ff23fSmrg
142209ff23fSmrg    OUTREG(RADEON_CRTC_PITCH,           restore->crtc_pitch);
143209ff23fSmrg    OUTREG(RADEON_DISP_MERGE_CNTL,      restore->disp_merge_cntl);
144209ff23fSmrg
145209ff23fSmrg    if (info->IsDellServer) {
146209ff23fSmrg	OUTREG(RADEON_TV_DAC_CNTL, restore->tv_dac_cntl);
147209ff23fSmrg	OUTREG(RADEON_DISP_HW_DEBUG, restore->disp_hw_debug);
148209ff23fSmrg	OUTREG(RADEON_DAC_CNTL2, restore->dac2_cntl);
149209ff23fSmrg	OUTREG(RADEON_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl);
150209ff23fSmrg    }
151209ff23fSmrg
152209ff23fSmrg    OUTREG(RADEON_CRTC_GEN_CNTL, restore->crtc_gen_cntl);
153209ff23fSmrg}
154209ff23fSmrg
155209ff23fSmrg/* Write CRTC2 registers */
156209ff23fSmrgvoid
157209ff23fSmrgRADEONRestoreCrtc2Registers(ScrnInfoPtr pScrn,
158209ff23fSmrg			    RADEONSavePtr restore)
159209ff23fSmrg{
160209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
161209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
162209ff23fSmrg    /*    uint32_t	   crtc2_gen_cntl;*/
163209ff23fSmrg
164209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
165209ff23fSmrg		   "Programming CRTC2, offset: 0x%08x\n",
166209ff23fSmrg		   (unsigned)restore->crtc2_offset);
167209ff23fSmrg
168209ff23fSmrg    /* We prevent the CRTC from hitting the memory controller until
169209ff23fSmrg     * fully programmed
170209ff23fSmrg     */
171209ff23fSmrg    OUTREG(RADEON_CRTC2_GEN_CNTL,
172209ff23fSmrg	   restore->crtc2_gen_cntl | RADEON_CRTC2_VSYNC_DIS |
173209ff23fSmrg	   RADEON_CRTC2_HSYNC_DIS | RADEON_CRTC2_DISP_DIS |
174209ff23fSmrg	   RADEON_CRTC2_DISP_REQ_EN_B);
175209ff23fSmrg
176209ff23fSmrg    OUTREG(RADEON_CRTC2_H_TOTAL_DISP,    restore->crtc2_h_total_disp);
177209ff23fSmrg    OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, restore->crtc2_h_sync_strt_wid);
178209ff23fSmrg    OUTREG(RADEON_CRTC2_V_TOTAL_DISP,    restore->crtc2_v_total_disp);
179209ff23fSmrg    OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, restore->crtc2_v_sync_strt_wid);
180209ff23fSmrg
181209ff23fSmrg    OUTREG(RADEON_FP_H2_SYNC_STRT_WID,   restore->fp_h2_sync_strt_wid);
182209ff23fSmrg    OUTREG(RADEON_FP_V2_SYNC_STRT_WID,   restore->fp_v2_sync_strt_wid);
183209ff23fSmrg
184209ff23fSmrg    if (IS_R300_VARIANT)
185209ff23fSmrg	OUTREG(R300_CRTC2_TILE_X0_Y0, restore->crtc2_tile_x0_y0);
186209ff23fSmrg    OUTREG(RADEON_CRTC2_OFFSET_CNTL,     restore->crtc2_offset_cntl);
187209ff23fSmrg    OUTREG(RADEON_CRTC2_OFFSET,          restore->crtc2_offset);
188209ff23fSmrg
189209ff23fSmrg    OUTREG(RADEON_CRTC2_PITCH,           restore->crtc2_pitch);
190209ff23fSmrg    OUTREG(RADEON_DISP2_MERGE_CNTL,      restore->disp2_merge_cntl);
191209ff23fSmrg
192209ff23fSmrg    OUTREG(RADEON_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl);
193209ff23fSmrg
194209ff23fSmrg}
195209ff23fSmrg
196209ff23fSmrgstatic void
197209ff23fSmrgRADEONPLLWaitForReadUpdateComplete(ScrnInfoPtr pScrn)
198209ff23fSmrg{
199209ff23fSmrg    int i = 0;
200209ff23fSmrg
201209ff23fSmrg    /* FIXME: Certain revisions of R300 can't recover here.  Not sure of
202209ff23fSmrg       the cause yet, but this workaround will mask the problem for now.
203209ff23fSmrg       Other chips usually will pass at the very first test, so the
204209ff23fSmrg       workaround shouldn't have any effect on them. */
205209ff23fSmrg    for (i = 0;
206209ff23fSmrg	 (i < 10000 &&
207209ff23fSmrg	  INPLL(pScrn, RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R);
208209ff23fSmrg	 i++);
209209ff23fSmrg}
210209ff23fSmrg
211209ff23fSmrgstatic void
212209ff23fSmrgRADEONPLLWriteUpdate(ScrnInfoPtr pScrn)
213209ff23fSmrg{
214209ff23fSmrg    while (INPLL(pScrn, RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R);
215209ff23fSmrg
216209ff23fSmrg    OUTPLLP(pScrn, RADEON_PPLL_REF_DIV,
217209ff23fSmrg	    RADEON_PPLL_ATOMIC_UPDATE_W,
218209ff23fSmrg	    ~(RADEON_PPLL_ATOMIC_UPDATE_W));
219209ff23fSmrg}
220209ff23fSmrg
221209ff23fSmrgstatic void
222209ff23fSmrgRADEONPLL2WaitForReadUpdateComplete(ScrnInfoPtr pScrn)
223209ff23fSmrg{
224209ff23fSmrg    int i = 0;
225209ff23fSmrg
226209ff23fSmrg    /* FIXME: Certain revisions of R300 can't recover here.  Not sure of
227209ff23fSmrg       the cause yet, but this workaround will mask the problem for now.
228209ff23fSmrg       Other chips usually will pass at the very first test, so the
229209ff23fSmrg       workaround shouldn't have any effect on them. */
230209ff23fSmrg    for (i = 0;
231209ff23fSmrg	 (i < 10000 &&
232209ff23fSmrg	  INPLL(pScrn, RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R);
233209ff23fSmrg	 i++);
234209ff23fSmrg}
235209ff23fSmrg
236209ff23fSmrgstatic void
237209ff23fSmrgRADEONPLL2WriteUpdate(ScrnInfoPtr pScrn)
238209ff23fSmrg{
239209ff23fSmrg    while (INPLL(pScrn, RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R);
240209ff23fSmrg
241209ff23fSmrg    OUTPLLP(pScrn, RADEON_P2PLL_REF_DIV,
242209ff23fSmrg	    RADEON_P2PLL_ATOMIC_UPDATE_W,
243209ff23fSmrg	    ~(RADEON_P2PLL_ATOMIC_UPDATE_W));
244209ff23fSmrg}
245209ff23fSmrg
246209ff23fSmrgstatic uint8_t
247209ff23fSmrgRADEONComputePLLGain(uint16_t reference_freq, uint16_t ref_div,
248209ff23fSmrg		     uint16_t fb_div)
249209ff23fSmrg{
250209ff23fSmrg    unsigned vcoFreq;
251209ff23fSmrg
252209ff23fSmrg    if (!ref_div)
253209ff23fSmrg	return 1;
254209ff23fSmrg
255209ff23fSmrg    vcoFreq = ((unsigned)reference_freq * fb_div) / ref_div;
256209ff23fSmrg
257209ff23fSmrg    /*
258209ff23fSmrg     * This is horribly crude: the VCO frequency range is divided into
259209ff23fSmrg     * 3 parts, each part having a fixed PLL gain value.
260209ff23fSmrg     */
261209ff23fSmrg    if (vcoFreq >= 30000)
262209ff23fSmrg	/*
263209ff23fSmrg	 * [300..max] MHz : 7
264209ff23fSmrg	 */
265209ff23fSmrg	return 7;
266209ff23fSmrg    else if (vcoFreq >= 18000)
267209ff23fSmrg	/*
268209ff23fSmrg	 * [180..300) MHz : 4
269209ff23fSmrg	 */
270209ff23fSmrg        return 4;
271209ff23fSmrg    else
272209ff23fSmrg	/*
273209ff23fSmrg	 * [0..180) MHz : 1
274209ff23fSmrg	 */
275209ff23fSmrg        return 1;
276209ff23fSmrg}
277209ff23fSmrg
278209ff23fSmrg/* Write PLL registers */
279209ff23fSmrgvoid
280209ff23fSmrgRADEONRestorePLLRegisters(ScrnInfoPtr pScrn,
281209ff23fSmrg			  RADEONSavePtr restore)
282209ff23fSmrg{
283209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
284209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
285209ff23fSmrg    uint8_t pllGain;
286209ff23fSmrg
287209ff23fSmrg#if defined(__powerpc__)
288209ff23fSmrg    /* apparently restoring the pll causes a hang??? */
289209ff23fSmrg    if (info->MacModel == RADEON_MAC_IBOOK)
290209ff23fSmrg	return;
291209ff23fSmrg#endif
292209ff23fSmrg
293209ff23fSmrg    pllGain = RADEONComputePLLGain(info->pll.reference_freq,
294209ff23fSmrg				   restore->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK,
295209ff23fSmrg				   restore->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK);
296209ff23fSmrg
297209ff23fSmrg    if (info->IsMobility) {
298209ff23fSmrg        /* A temporal workaround for the occational blanking on certain laptop panels.
299209ff23fSmrg           This appears to related to the PLL divider registers (fail to lock?).
300209ff23fSmrg	   It occurs even when all dividers are the same with their old settings.
301209ff23fSmrg           In this case we really don't need to fiddle with PLL registers.
302209ff23fSmrg           By doing this we can avoid the blanking problem with some panels.
303209ff23fSmrg        */
304209ff23fSmrg        if ((restore->ppll_ref_div == (INPLL(pScrn, RADEON_PPLL_REF_DIV) & RADEON_PPLL_REF_DIV_MASK)) &&
305209ff23fSmrg	    (restore->ppll_div_3 == (INPLL(pScrn, RADEON_PPLL_DIV_3) &
306209ff23fSmrg				     (RADEON_PPLL_POST3_DIV_MASK | RADEON_PPLL_FB3_DIV_MASK)))) {
307209ff23fSmrg	    OUTREGP(RADEON_CLOCK_CNTL_INDEX,
308209ff23fSmrg		    RADEON_PLL_DIV_SEL,
309209ff23fSmrg		    ~(RADEON_PLL_DIV_SEL));
310209ff23fSmrg	    RADEONPllErrataAfterIndex(info);
311209ff23fSmrg	    return;
312209ff23fSmrg	}
313209ff23fSmrg    }
314209ff23fSmrg
315209ff23fSmrg    OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL,
316209ff23fSmrg	    RADEON_VCLK_SRC_SEL_CPUCLK,
317209ff23fSmrg	    ~(RADEON_VCLK_SRC_SEL_MASK));
318209ff23fSmrg
319209ff23fSmrg    OUTPLLP(pScrn,
320209ff23fSmrg	    RADEON_PPLL_CNTL,
321209ff23fSmrg	    RADEON_PPLL_RESET
322209ff23fSmrg	    | RADEON_PPLL_ATOMIC_UPDATE_EN
323209ff23fSmrg	    | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN
324209ff23fSmrg	    | ((uint32_t)pllGain << RADEON_PPLL_PVG_SHIFT),
325209ff23fSmrg	    ~(RADEON_PPLL_RESET
326209ff23fSmrg	      | RADEON_PPLL_ATOMIC_UPDATE_EN
327209ff23fSmrg	      | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN
328209ff23fSmrg	      | RADEON_PPLL_PVG_MASK));
329209ff23fSmrg
330209ff23fSmrg    OUTREGP(RADEON_CLOCK_CNTL_INDEX,
331209ff23fSmrg	    RADEON_PLL_DIV_SEL,
332209ff23fSmrg	    ~(RADEON_PLL_DIV_SEL));
333209ff23fSmrg    RADEONPllErrataAfterIndex(info);
334209ff23fSmrg
335209ff23fSmrg    if (IS_R300_VARIANT ||
336209ff23fSmrg	(info->ChipFamily == CHIP_FAMILY_RS300) ||
337209ff23fSmrg	(info->ChipFamily == CHIP_FAMILY_RS400) ||
338209ff23fSmrg	(info->ChipFamily == CHIP_FAMILY_RS480)) {
339209ff23fSmrg	if (restore->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {
340209ff23fSmrg	    /* When restoring console mode, use saved PPLL_REF_DIV
341209ff23fSmrg	     * setting.
342209ff23fSmrg	     */
343209ff23fSmrg	    OUTPLLP(pScrn, RADEON_PPLL_REF_DIV,
344209ff23fSmrg		    restore->ppll_ref_div,
345209ff23fSmrg		    0);
346209ff23fSmrg	} else {
347209ff23fSmrg	    /* R300 uses ref_div_acc field as real ref divider */
348209ff23fSmrg	    OUTPLLP(pScrn, RADEON_PPLL_REF_DIV,
349209ff23fSmrg		    (restore->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT),
350209ff23fSmrg		    ~R300_PPLL_REF_DIV_ACC_MASK);
351209ff23fSmrg	}
352209ff23fSmrg    } else {
353209ff23fSmrg	OUTPLLP(pScrn, RADEON_PPLL_REF_DIV,
354209ff23fSmrg		restore->ppll_ref_div,
355209ff23fSmrg		~RADEON_PPLL_REF_DIV_MASK);
356209ff23fSmrg    }
357209ff23fSmrg
358209ff23fSmrg    OUTPLLP(pScrn, RADEON_PPLL_DIV_3,
359209ff23fSmrg	    restore->ppll_div_3,
360209ff23fSmrg	    ~RADEON_PPLL_FB3_DIV_MASK);
361209ff23fSmrg
362209ff23fSmrg    OUTPLLP(pScrn, RADEON_PPLL_DIV_3,
363209ff23fSmrg	    restore->ppll_div_3,
364209ff23fSmrg	    ~RADEON_PPLL_POST3_DIV_MASK);
365209ff23fSmrg
366209ff23fSmrg    RADEONPLLWriteUpdate(pScrn);
367209ff23fSmrg    RADEONPLLWaitForReadUpdateComplete(pScrn);
368209ff23fSmrg
369209ff23fSmrg    OUTPLL(pScrn, RADEON_HTOTAL_CNTL, restore->htotal_cntl);
370209ff23fSmrg
371209ff23fSmrg    OUTPLLP(pScrn, RADEON_PPLL_CNTL,
372209ff23fSmrg	    0,
373209ff23fSmrg	    ~(RADEON_PPLL_RESET
374209ff23fSmrg	      | RADEON_PPLL_SLEEP
375209ff23fSmrg	      | RADEON_PPLL_ATOMIC_UPDATE_EN
376209ff23fSmrg	      | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN));
377209ff23fSmrg
378209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
379209ff23fSmrg		   "Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
380209ff23fSmrg		   restore->ppll_ref_div,
381209ff23fSmrg		   restore->ppll_div_3,
382209ff23fSmrg		   (unsigned)restore->htotal_cntl,
383209ff23fSmrg		   INPLL(pScrn, RADEON_PPLL_CNTL));
384209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
385209ff23fSmrg		   "Wrote: rd=%d, fd=%d, pd=%d\n",
386209ff23fSmrg		   restore->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK,
387209ff23fSmrg		   restore->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK,
388209ff23fSmrg		   (restore->ppll_div_3 & RADEON_PPLL_POST3_DIV_MASK) >> 16);
389209ff23fSmrg
390209ff23fSmrg    usleep(50000); /* Let the clock to lock */
391209ff23fSmrg
392209ff23fSmrg    OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL,
393209ff23fSmrg	    RADEON_VCLK_SRC_SEL_PPLLCLK,
394209ff23fSmrg	    ~(RADEON_VCLK_SRC_SEL_MASK));
395209ff23fSmrg
396209ff23fSmrg    /*OUTPLL(pScrn, RADEON_VCLK_ECP_CNTL, restore->vclk_ecp_cntl);*/
397209ff23fSmrg
398209ff23fSmrg    ErrorF("finished PLL1\n");
399209ff23fSmrg
400209ff23fSmrg}
401209ff23fSmrg
402209ff23fSmrg/* Write PLL2 registers */
403209ff23fSmrgvoid
404209ff23fSmrgRADEONRestorePLL2Registers(ScrnInfoPtr pScrn,
405209ff23fSmrg			   RADEONSavePtr restore)
406209ff23fSmrg{
407209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
408209ff23fSmrg    uint8_t pllGain;
409209ff23fSmrg
410209ff23fSmrg    pllGain = RADEONComputePLLGain(info->pll.reference_freq,
411209ff23fSmrg                                   restore->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK,
412209ff23fSmrg                                   restore->p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK);
413209ff23fSmrg
414209ff23fSmrg
415209ff23fSmrg    OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL,
416209ff23fSmrg	    RADEON_PIX2CLK_SRC_SEL_CPUCLK,
417209ff23fSmrg	    ~(RADEON_PIX2CLK_SRC_SEL_MASK));
418209ff23fSmrg
419209ff23fSmrg    OUTPLLP(pScrn,
420209ff23fSmrg	    RADEON_P2PLL_CNTL,
421209ff23fSmrg	    RADEON_P2PLL_RESET
422209ff23fSmrg	    | RADEON_P2PLL_ATOMIC_UPDATE_EN
423209ff23fSmrg	    | ((uint32_t)pllGain << RADEON_P2PLL_PVG_SHIFT),
424209ff23fSmrg	    ~(RADEON_P2PLL_RESET
425209ff23fSmrg	      | RADEON_P2PLL_ATOMIC_UPDATE_EN
426209ff23fSmrg	      | RADEON_P2PLL_PVG_MASK));
427209ff23fSmrg
428209ff23fSmrg
429209ff23fSmrg    OUTPLLP(pScrn, RADEON_P2PLL_REF_DIV,
430209ff23fSmrg	    restore->p2pll_ref_div,
431209ff23fSmrg	    ~RADEON_P2PLL_REF_DIV_MASK);
432209ff23fSmrg
433209ff23fSmrg    OUTPLLP(pScrn, RADEON_P2PLL_DIV_0,
434209ff23fSmrg	    restore->p2pll_div_0,
435209ff23fSmrg	    ~RADEON_P2PLL_FB0_DIV_MASK);
436209ff23fSmrg
437209ff23fSmrg    OUTPLLP(pScrn, RADEON_P2PLL_DIV_0,
438209ff23fSmrg	    restore->p2pll_div_0,
439209ff23fSmrg	    ~RADEON_P2PLL_POST0_DIV_MASK);
440209ff23fSmrg
441209ff23fSmrg    RADEONPLL2WriteUpdate(pScrn);
442209ff23fSmrg    RADEONPLL2WaitForReadUpdateComplete(pScrn);
443209ff23fSmrg
444209ff23fSmrg    OUTPLL(pScrn, RADEON_HTOTAL2_CNTL, restore->htotal_cntl2);
445209ff23fSmrg
446209ff23fSmrg    OUTPLLP(pScrn, RADEON_P2PLL_CNTL,
447209ff23fSmrg	    0,
448209ff23fSmrg	    ~(RADEON_P2PLL_RESET
449209ff23fSmrg	      | RADEON_P2PLL_SLEEP
450209ff23fSmrg	      | RADEON_P2PLL_ATOMIC_UPDATE_EN));
451209ff23fSmrg
452209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
453209ff23fSmrg		   "Wrote2: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
454209ff23fSmrg		   (unsigned)restore->p2pll_ref_div,
455209ff23fSmrg		   (unsigned)restore->p2pll_div_0,
456209ff23fSmrg		   (unsigned)restore->htotal_cntl2,
457209ff23fSmrg		   INPLL(pScrn, RADEON_P2PLL_CNTL));
458209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
459209ff23fSmrg		   "Wrote2: rd=%u, fd=%u, pd=%u\n",
460209ff23fSmrg		   (unsigned)restore->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK,
461209ff23fSmrg		   (unsigned)restore->p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK,
462209ff23fSmrg		   (unsigned)((restore->p2pll_div_0 &
463209ff23fSmrg			       RADEON_P2PLL_POST0_DIV_MASK) >>16));
464209ff23fSmrg
465209ff23fSmrg    usleep(5000); /* Let the clock to lock */
466209ff23fSmrg
467209ff23fSmrg    OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL,
468209ff23fSmrg	    RADEON_PIX2CLK_SRC_SEL_P2PLLCLK,
469209ff23fSmrg	    ~(RADEON_PIX2CLK_SRC_SEL_MASK));
470209ff23fSmrg
471209ff23fSmrg    OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, restore->pixclks_cntl);
472209ff23fSmrg
473209ff23fSmrg    ErrorF("finished PLL2\n");
474209ff23fSmrg
475209ff23fSmrg}
476209ff23fSmrg
477209ff23fSmrg/* Read common registers */
478209ff23fSmrgvoid
479209ff23fSmrgRADEONSaveCommonRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save)
480209ff23fSmrg{
481209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
482209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
483209ff23fSmrg
484209ff23fSmrg    save->ovr_clr            = INREG(RADEON_OVR_CLR);
485209ff23fSmrg    save->ovr_wid_left_right = INREG(RADEON_OVR_WID_LEFT_RIGHT);
486209ff23fSmrg    save->ovr_wid_top_bottom = INREG(RADEON_OVR_WID_TOP_BOTTOM);
487209ff23fSmrg    save->ov0_scale_cntl     = INREG(RADEON_OV0_SCALE_CNTL);
488209ff23fSmrg    save->subpic_cntl        = INREG(RADEON_SUBPIC_CNTL);
489209ff23fSmrg    save->viph_control       = INREG(RADEON_VIPH_CONTROL);
490209ff23fSmrg    save->i2c_cntl_1         = INREG(RADEON_I2C_CNTL_1);
491209ff23fSmrg    save->gen_int_cntl       = INREG(RADEON_GEN_INT_CNTL);
492209ff23fSmrg    save->cap0_trig_cntl     = INREG(RADEON_CAP0_TRIG_CNTL);
493209ff23fSmrg    save->cap1_trig_cntl     = INREG(RADEON_CAP1_TRIG_CNTL);
494209ff23fSmrg    save->bus_cntl           = INREG(RADEON_BUS_CNTL);
495209ff23fSmrg    save->surface_cntl	     = INREG(RADEON_SURFACE_CNTL);
496209ff23fSmrg    save->grph_buffer_cntl   = INREG(RADEON_GRPH_BUFFER_CNTL);
497209ff23fSmrg    save->grph2_buffer_cntl  = INREG(RADEON_GRPH2_BUFFER_CNTL);
498209ff23fSmrg
499209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_RS400) ||
500209ff23fSmrg	(info->ChipFamily == CHIP_FAMILY_RS480)) {
501209ff23fSmrg	save->disp2_req_cntl1 = INREG(RS400_DISP2_REQ_CNTL1);
502209ff23fSmrg	save->disp2_req_cntl2 = INREG(RS400_DISP2_REQ_CNTL2);
503209ff23fSmrg	save->dmif_mem_cntl1  = INREG(RS400_DMIF_MEM_CNTL1);
504209ff23fSmrg	save->disp1_req_cntl1 = INREG(RS400_DISP1_REQ_CNTL1);
505209ff23fSmrg    }
506209ff23fSmrg}
507209ff23fSmrg
508209ff23fSmrg/* Read CRTC registers */
509209ff23fSmrgvoid
510209ff23fSmrgRADEONSaveCrtcRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save)
511209ff23fSmrg{
512209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
513209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
514209ff23fSmrg
515209ff23fSmrg    save->crtc_gen_cntl        = INREG(RADEON_CRTC_GEN_CNTL);
516209ff23fSmrg    save->crtc_ext_cntl        = INREG(RADEON_CRTC_EXT_CNTL);
517209ff23fSmrg    save->crtc_h_total_disp    = INREG(RADEON_CRTC_H_TOTAL_DISP);
518209ff23fSmrg    save->crtc_h_sync_strt_wid = INREG(RADEON_CRTC_H_SYNC_STRT_WID);
519209ff23fSmrg    save->crtc_v_total_disp    = INREG(RADEON_CRTC_V_TOTAL_DISP);
520209ff23fSmrg    save->crtc_v_sync_strt_wid = INREG(RADEON_CRTC_V_SYNC_STRT_WID);
521209ff23fSmrg
522209ff23fSmrg    save->crtc_offset          = INREG(RADEON_CRTC_OFFSET);
523209ff23fSmrg    save->crtc_offset_cntl     = INREG(RADEON_CRTC_OFFSET_CNTL);
524209ff23fSmrg    save->crtc_pitch           = INREG(RADEON_CRTC_PITCH);
525209ff23fSmrg    save->disp_merge_cntl      = INREG(RADEON_DISP_MERGE_CNTL);
526209ff23fSmrg
527209ff23fSmrg    if (IS_R300_VARIANT)
528209ff23fSmrg	save->crtc_tile_x0_y0 =  INREG(R300_CRTC_TILE_X0_Y0);
529209ff23fSmrg
530209ff23fSmrg    if (info->IsDellServer) {
531209ff23fSmrg	save->tv_dac_cntl      = INREG(RADEON_TV_DAC_CNTL);
532209ff23fSmrg	save->dac2_cntl        = INREG(RADEON_DAC_CNTL2);
533209ff23fSmrg	save->disp_hw_debug    = INREG (RADEON_DISP_HW_DEBUG);
534209ff23fSmrg	save->crtc2_gen_cntl   = INREG(RADEON_CRTC2_GEN_CNTL);
535209ff23fSmrg    }
536209ff23fSmrg
537209ff23fSmrg    /* track if the crtc is enabled for text restore */
538209ff23fSmrg    if (save->crtc_ext_cntl & RADEON_CRTC_DISPLAY_DIS)
539209ff23fSmrg	info->crtc_on = FALSE;
540209ff23fSmrg    else
541209ff23fSmrg	info->crtc_on = TRUE;
542209ff23fSmrg
543209ff23fSmrg}
544209ff23fSmrg
545209ff23fSmrg/* Read CRTC2 registers */
546209ff23fSmrgvoid
547209ff23fSmrgRADEONSaveCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save)
548209ff23fSmrg{
549209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
550209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
551209ff23fSmrg
552209ff23fSmrg    save->crtc2_gen_cntl        = INREG(RADEON_CRTC2_GEN_CNTL);
553209ff23fSmrg    save->crtc2_h_total_disp    = INREG(RADEON_CRTC2_H_TOTAL_DISP);
554209ff23fSmrg    save->crtc2_h_sync_strt_wid = INREG(RADEON_CRTC2_H_SYNC_STRT_WID);
555209ff23fSmrg    save->crtc2_v_total_disp    = INREG(RADEON_CRTC2_V_TOTAL_DISP);
556209ff23fSmrg    save->crtc2_v_sync_strt_wid = INREG(RADEON_CRTC2_V_SYNC_STRT_WID);
557209ff23fSmrg    save->crtc2_offset          = INREG(RADEON_CRTC2_OFFSET);
558209ff23fSmrg    save->crtc2_offset_cntl     = INREG(RADEON_CRTC2_OFFSET_CNTL);
559209ff23fSmrg    save->crtc2_pitch           = INREG(RADEON_CRTC2_PITCH);
560209ff23fSmrg
561209ff23fSmrg    if (IS_R300_VARIANT)
562209ff23fSmrg	save->crtc2_tile_x0_y0 =  INREG(R300_CRTC2_TILE_X0_Y0);
563209ff23fSmrg
564209ff23fSmrg    save->fp_h2_sync_strt_wid   = INREG (RADEON_FP_H2_SYNC_STRT_WID);
565209ff23fSmrg    save->fp_v2_sync_strt_wid   = INREG (RADEON_FP_V2_SYNC_STRT_WID);
566209ff23fSmrg
567209ff23fSmrg    save->disp2_merge_cntl      = INREG(RADEON_DISP2_MERGE_CNTL);
568209ff23fSmrg
569209ff23fSmrg    /* track if the crtc is enabled for text restore */
570209ff23fSmrg    if (save->crtc2_gen_cntl & RADEON_CRTC2_DISP_DIS)
571209ff23fSmrg	info->crtc2_on = FALSE;
572209ff23fSmrg    else
573209ff23fSmrg	info->crtc2_on = TRUE;
574209ff23fSmrg
575209ff23fSmrg}
576209ff23fSmrg
577209ff23fSmrg/* Read PLL registers */
578209ff23fSmrgvoid
579209ff23fSmrgRADEONSavePLLRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save)
580209ff23fSmrg{
581209ff23fSmrg    save->ppll_ref_div = INPLL(pScrn, RADEON_PPLL_REF_DIV);
582209ff23fSmrg    save->ppll_div_3   = INPLL(pScrn, RADEON_PPLL_DIV_3);
583209ff23fSmrg    save->htotal_cntl  = INPLL(pScrn, RADEON_HTOTAL_CNTL);
584209ff23fSmrg    save->vclk_ecp_cntl = INPLL(pScrn, RADEON_VCLK_ECP_CNTL);
585209ff23fSmrg
586209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
587209ff23fSmrg		   "Read: 0x%08x 0x%08x 0x%08x\n",
588209ff23fSmrg		   save->ppll_ref_div,
589209ff23fSmrg		   save->ppll_div_3,
590209ff23fSmrg		   (unsigned)save->htotal_cntl);
591209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
592209ff23fSmrg		   "Read: rd=%d, fd=%d, pd=%d\n",
593209ff23fSmrg		   save->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK,
594209ff23fSmrg		   save->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK,
595209ff23fSmrg		   (save->ppll_div_3 & RADEON_PPLL_POST3_DIV_MASK) >> 16);
596209ff23fSmrg}
597209ff23fSmrg
598209ff23fSmrg/* Read PLL registers */
599209ff23fSmrgvoid
600209ff23fSmrgRADEONSavePLL2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save)
601209ff23fSmrg{
602209ff23fSmrg    save->p2pll_ref_div = INPLL(pScrn, RADEON_P2PLL_REF_DIV);
603209ff23fSmrg    save->p2pll_div_0   = INPLL(pScrn, RADEON_P2PLL_DIV_0);
604209ff23fSmrg    save->htotal_cntl2  = INPLL(pScrn, RADEON_HTOTAL2_CNTL);
605209ff23fSmrg    save->pixclks_cntl  = INPLL(pScrn, RADEON_PIXCLKS_CNTL);
606209ff23fSmrg
607209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
608209ff23fSmrg		   "Read: 0x%08x 0x%08x 0x%08x\n",
609209ff23fSmrg		   (unsigned)save->p2pll_ref_div,
610209ff23fSmrg		   (unsigned)save->p2pll_div_0,
611209ff23fSmrg		   (unsigned)save->htotal_cntl2);
612209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
613209ff23fSmrg		   "Read: rd=%u, fd=%u, pd=%u\n",
614209ff23fSmrg		   (unsigned)(save->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK),
615209ff23fSmrg		   (unsigned)(save->p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK),
616209ff23fSmrg		   (unsigned)((save->p2pll_div_0 & RADEON_P2PLL_POST0_DIV_MASK)
617209ff23fSmrg			      >> 16));
618209ff23fSmrg}
619209ff23fSmrg
620209ff23fSmrgvoid
621209ff23fSmrgradeon_crtc_modeset_ioctl(xf86CrtcPtr crtc, Bool post)
622209ff23fSmrg{
623209ff23fSmrg#if defined(XF86DRI) && defined(DRM_IOCTL_MODESET_CTL)
624209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(crtc->scrn);
625209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
626209ff23fSmrg    struct drm_modeset_ctl modeset;
627209ff23fSmrg
628209ff23fSmrg    modeset.crtc = radeon_crtc->crtc_id;
629209ff23fSmrg    modeset.cmd = post ? _DRM_POST_MODESET : _DRM_PRE_MODESET;
630209ff23fSmrg
631209ff23fSmrg    ioctl(info->drmFD, DRM_IOCTL_MODESET_CTL, &modeset);
632209ff23fSmrg#endif
633209ff23fSmrg}
634209ff23fSmrg
635209ff23fSmrgvoid
636209ff23fSmrglegacy_crtc_dpms(xf86CrtcPtr crtc, int mode)
637209ff23fSmrg{
638209ff23fSmrg    int mask;
639209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
640209ff23fSmrg    RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
641209ff23fSmrg    unsigned char *RADEONMMIO = pRADEONEnt->MMIO;
642209ff23fSmrg
643209ff23fSmrg    mask = radeon_crtc->crtc_id ? (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS | RADEON_CRTC2_DISP_REQ_EN_B) : (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_HSYNC_DIS | RADEON_CRTC_VSYNC_DIS);
644209ff23fSmrg
645209ff23fSmrg    if (mode == DPMSModeOff)
646209ff23fSmrg	radeon_crtc_modeset_ioctl(crtc, FALSE);
647209ff23fSmrg
648209ff23fSmrg    switch(mode) {
649209ff23fSmrg    case DPMSModeOn:
650209ff23fSmrg	if (radeon_crtc->crtc_id) {
651209ff23fSmrg	    OUTREGP(RADEON_CRTC2_GEN_CNTL, 0, ~mask);
652209ff23fSmrg	} else {
653209ff23fSmrg	    OUTREGP(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_DISP_REQ_EN_B);
654209ff23fSmrg	    OUTREGP(RADEON_CRTC_EXT_CNTL, 0, ~mask);
655209ff23fSmrg	}
656209ff23fSmrg	break;
657209ff23fSmrg    case DPMSModeStandby:
658209ff23fSmrg	if (radeon_crtc->crtc_id) {
659209ff23fSmrg	    OUTREGP(RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_HSYNC_DIS), ~mask);
660209ff23fSmrg	} else {
661209ff23fSmrg	    OUTREGP(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_DISP_REQ_EN_B);
662209ff23fSmrg	    OUTREGP(RADEON_CRTC_EXT_CNTL, (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_HSYNC_DIS), ~mask);
663209ff23fSmrg	}
664209ff23fSmrg	break;
665209ff23fSmrg    case DPMSModeSuspend:
666209ff23fSmrg	if (radeon_crtc->crtc_id) {
667209ff23fSmrg	    OUTREGP(RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS), ~mask);
668209ff23fSmrg	} else {
669209ff23fSmrg	    OUTREGP(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_DISP_REQ_EN_B);
670209ff23fSmrg	    OUTREGP(RADEON_CRTC_EXT_CNTL, (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS), ~mask);
671209ff23fSmrg	}
672209ff23fSmrg	break;
673209ff23fSmrg    case DPMSModeOff:
674209ff23fSmrg	if (radeon_crtc->crtc_id) {
675209ff23fSmrg	    OUTREGP(RADEON_CRTC2_GEN_CNTL, mask, ~mask);
676209ff23fSmrg	} else {
677209ff23fSmrg	    OUTREGP(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, ~RADEON_CRTC_DISP_REQ_EN_B);
678209ff23fSmrg	    OUTREGP(RADEON_CRTC_EXT_CNTL, mask, ~mask);
679209ff23fSmrg	}
680209ff23fSmrg	break;
681209ff23fSmrg    }
682209ff23fSmrg
683209ff23fSmrg    if (mode != DPMSModeOff) {
684209ff23fSmrg	radeon_crtc_modeset_ioctl(crtc, TRUE);
685209ff23fSmrg	radeon_crtc_load_lut(crtc);
686209ff23fSmrg    }
687209ff23fSmrg}
688209ff23fSmrg
689209ff23fSmrg
690209ff23fSmrg/* Define common registers for requested video mode */
691209ff23fSmrgstatic void
692209ff23fSmrgRADEONInitCommonRegisters(RADEONSavePtr save, RADEONInfoPtr info)
693209ff23fSmrg{
694209ff23fSmrg    save->ovr_clr            = 0;
695209ff23fSmrg    save->ovr_wid_left_right = 0;
696209ff23fSmrg    save->ovr_wid_top_bottom = 0;
697209ff23fSmrg    save->ov0_scale_cntl     = 0;
698209ff23fSmrg    save->subpic_cntl        = 0;
699209ff23fSmrg    save->viph_control       = 0;
700209ff23fSmrg    save->i2c_cntl_1         = 0;
701209ff23fSmrg    save->rbbm_soft_reset    = 0;
702209ff23fSmrg    save->cap0_trig_cntl     = 0;
703209ff23fSmrg    save->cap1_trig_cntl     = 0;
704209ff23fSmrg    save->bus_cntl           = info->BusCntl;
705209ff23fSmrg
706209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_RS400) ||
707209ff23fSmrg	(info->ChipFamily == CHIP_FAMILY_RS480)) {
708209ff23fSmrg	save->disp2_req_cntl1 = info->SavedReg->disp2_req_cntl1;
709209ff23fSmrg	save->disp2_req_cntl2 = info->SavedReg->disp2_req_cntl2;
710209ff23fSmrg	save->dmif_mem_cntl1  = info->SavedReg->dmif_mem_cntl1;
711209ff23fSmrg	save->disp1_req_cntl1 = info->SavedReg->disp1_req_cntl1;
712209ff23fSmrg    }
713209ff23fSmrg
714209ff23fSmrg    /*
715209ff23fSmrg     * If bursts are enabled, turn on discards
716209ff23fSmrg     * Radeon doesn't have write bursts
717209ff23fSmrg     */
718209ff23fSmrg    if (save->bus_cntl & (RADEON_BUS_READ_BURST))
719209ff23fSmrg	save->bus_cntl |= RADEON_BUS_RD_DISCARD_EN;
720209ff23fSmrg}
721209ff23fSmrg
722209ff23fSmrgstatic void
723209ff23fSmrgRADEONInitSurfaceCntl(xf86CrtcPtr crtc, RADEONSavePtr save)
724209ff23fSmrg{
725209ff23fSmrg    save->surface_cntl = 0;
726209ff23fSmrg
727209ff23fSmrg#if X_BYTE_ORDER == X_BIG_ENDIAN
728209ff23fSmrg    /* We must set both apertures as they can be both used to map the entire
729209ff23fSmrg     * video memory. -BenH.
730209ff23fSmrg     */
731209ff23fSmrg    switch (crtc->scrn->bitsPerPixel) {
732209ff23fSmrg    case 16:
733209ff23fSmrg	save->surface_cntl |= RADEON_NONSURF_AP0_SWP_16BPP;
734209ff23fSmrg	save->surface_cntl |= RADEON_NONSURF_AP1_SWP_16BPP;
735209ff23fSmrg	break;
736209ff23fSmrg
737209ff23fSmrg    case 32:
738209ff23fSmrg	save->surface_cntl |= RADEON_NONSURF_AP0_SWP_32BPP;
739209ff23fSmrg	save->surface_cntl |= RADEON_NONSURF_AP1_SWP_32BPP;
740209ff23fSmrg	break;
741209ff23fSmrg    }
742209ff23fSmrg#endif
743209ff23fSmrg
744209ff23fSmrg}
745209ff23fSmrg
746209ff23fSmrg
747209ff23fSmrgstatic Bool
748209ff23fSmrgRADEONInitCrtcBase(xf86CrtcPtr crtc, RADEONSavePtr save,
749209ff23fSmrg		   int x, int y)
750209ff23fSmrg{
751209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
752209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
753209ff23fSmrg    int    Base;
754209ff23fSmrg#ifdef XF86DRI
755209ff23fSmrg    RADEONSAREAPrivPtr pSAREAPriv;
756209ff23fSmrg    XF86DRISAREAPtr pSAREA;
757209ff23fSmrg#endif
758209ff23fSmrg
759209ff23fSmrg    save->crtc_offset      = pScrn->fbOffset;
760209ff23fSmrg#ifdef XF86DRI
761209ff23fSmrg    if (info->allowPageFlip)
762209ff23fSmrg	save->crtc_offset_cntl = RADEON_CRTC_OFFSET_FLIP_CNTL;
763209ff23fSmrg    else
764209ff23fSmrg#endif
765209ff23fSmrg	save->crtc_offset_cntl = 0;
766209ff23fSmrg
767209ff23fSmrg    if (info->tilingEnabled && (crtc->rotatedData == NULL)) {
768209ff23fSmrg       if (IS_R300_VARIANT)
769209ff23fSmrg          save->crtc_offset_cntl |= (R300_CRTC_X_Y_MODE_EN |
770209ff23fSmrg				     R300_CRTC_MICRO_TILE_BUFFER_DIS |
771209ff23fSmrg				     R300_CRTC_MACRO_TILE_EN);
772209ff23fSmrg       else
773209ff23fSmrg          save->crtc_offset_cntl |= RADEON_CRTC_TILE_EN;
774209ff23fSmrg    }
775209ff23fSmrg    else {
776209ff23fSmrg       if (IS_R300_VARIANT)
777209ff23fSmrg          save->crtc_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN |
778209ff23fSmrg				      R300_CRTC_MICRO_TILE_BUFFER_DIS |
779209ff23fSmrg				      R300_CRTC_MACRO_TILE_EN);
780209ff23fSmrg       else
781209ff23fSmrg          save->crtc_offset_cntl &= ~RADEON_CRTC_TILE_EN;
782209ff23fSmrg    }
783209ff23fSmrg
784209ff23fSmrg    Base = pScrn->fbOffset;
785209ff23fSmrg
786209ff23fSmrg    if (info->tilingEnabled && (crtc->rotatedData == NULL)) {
787209ff23fSmrg        if (IS_R300_VARIANT) {
788209ff23fSmrg	/* On r300/r400 when tiling is enabled crtc_offset is set to the address of
789209ff23fSmrg	 * the surface.  the x/y offsets are handled by the X_Y tile reg for each crtc
790209ff23fSmrg	 * Makes tiling MUCH easier.
791209ff23fSmrg	 */
792209ff23fSmrg             save->crtc_tile_x0_y0 = x | (y << 16);
793209ff23fSmrg             Base &= ~0x7ff;
794209ff23fSmrg         } else {
795209ff23fSmrg	     /* note we cannot really simply use the info->ModeReg.crtc_offset_cntl value, since the
796209ff23fSmrg		drm might have set FLIP_CNTL since we wrote that. Unfortunately FLIP_CNTL causes
797209ff23fSmrg		flickering when scrolling vertically in a virtual screen, possibly because crtc will
798209ff23fSmrg		pick up the new offset value at the end of each scanline, but the new offset_cntl value
799209ff23fSmrg		only after a vsync. We'd probably need to wait (in drm) for vsync and only then update
800209ff23fSmrg		OFFSET and OFFSET_CNTL, if the y coord has changed. Seems hard to fix. */
801209ff23fSmrg	     /*save->crtc_offset_cntl = INREG(RADEON_CRTC_OFFSET_CNTL) & ~0xf;*/
802209ff23fSmrg#if 0
803209ff23fSmrg	     /* try to get rid of flickering when scrolling at least for 2d */
804209ff23fSmrg#ifdef XF86DRI
805209ff23fSmrg	     if (!info->have3DWindows)
806209ff23fSmrg#endif
807209ff23fSmrg		 save->crtc_offset_cntl &= ~RADEON_CRTC_OFFSET_FLIP_CNTL;
808209ff23fSmrg#endif
809209ff23fSmrg
810209ff23fSmrg             int byteshift = info->CurrentLayout.bitsPerPixel >> 4;
811209ff23fSmrg             /* crtc uses 256(bytes)x8 "half-tile" start addresses? */
812209ff23fSmrg             int tile_addr = (((y >> 3) * info->CurrentLayout.displayWidth + x) >> (8 - byteshift)) << 11;
813209ff23fSmrg             Base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8);
814209ff23fSmrg             save->crtc_offset_cntl = save->crtc_offset_cntl | (y % 16);
815209ff23fSmrg         }
816209ff23fSmrg    }
817209ff23fSmrg    else {
818209ff23fSmrg       int offset = y * info->CurrentLayout.displayWidth + x;
819209ff23fSmrg       switch (info->CurrentLayout.pixel_code) {
820209ff23fSmrg       case 15:
821209ff23fSmrg       case 16: offset *= 2; break;
822209ff23fSmrg       case 24: offset *= 3; break;
823209ff23fSmrg       case 32: offset *= 4; break;
824209ff23fSmrg       }
825209ff23fSmrg       Base += offset;
826209ff23fSmrg    }
827209ff23fSmrg
828209ff23fSmrg    if (crtc->rotatedData != NULL) {
829209ff23fSmrg	Base = pScrn->fbOffset + (char *)crtc->rotatedData - (char *)info->FB;
830209ff23fSmrg    }
831209ff23fSmrg
832209ff23fSmrg    Base &= ~7;                 /* 3 lower bits are always 0 */
833209ff23fSmrg
834209ff23fSmrg
835209ff23fSmrg#ifdef XF86DRI
836209ff23fSmrg    if (info->directRenderingInited) {
837209ff23fSmrg	/* note cannot use pScrn->pScreen since this is unitialized when called from
838209ff23fSmrg	   RADEONScreenInit, and we need to call from there to get mergedfb + pageflip working */
839209ff23fSmrg        /*** NOTE: r3/4xx will need sarea and drm pageflip updates to handle the xytile regs for
840209ff23fSmrg	 *** pageflipping!
841209ff23fSmrg	 ***/
842209ff23fSmrg	pSAREAPriv = DRIGetSAREAPrivate(screenInfo.screens[pScrn->scrnIndex]);
843209ff23fSmrg	/* can't get at sarea in a semi-sane way? */
844209ff23fSmrg	pSAREA = (void *)((char*)pSAREAPriv - sizeof(XF86DRISAREARec));
845209ff23fSmrg
846209ff23fSmrg	pSAREA->frame.x = (Base  / info->CurrentLayout.pixel_bytes)
847209ff23fSmrg	    % info->CurrentLayout.displayWidth;
848209ff23fSmrg	pSAREA->frame.y = (Base / info->CurrentLayout.pixel_bytes)
849209ff23fSmrg	    / info->CurrentLayout.displayWidth;
850209ff23fSmrg	pSAREA->frame.width = pScrn->frameX1 - x + 1;
851209ff23fSmrg	pSAREA->frame.height = pScrn->frameY1 - y + 1;
852209ff23fSmrg
853209ff23fSmrg	if (pSAREAPriv->pfCurrentPage == 1) {
854209ff23fSmrg	    Base += info->backOffset - info->frontOffset;
855209ff23fSmrg	}
856209ff23fSmrg    }
857209ff23fSmrg#endif
858209ff23fSmrg    save->crtc_offset = Base;
859209ff23fSmrg
860209ff23fSmrg    return TRUE;
861209ff23fSmrg
862209ff23fSmrg}
863209ff23fSmrg
864209ff23fSmrg/* Define CRTC registers for requested video mode */
865209ff23fSmrgstatic Bool
866209ff23fSmrgRADEONInitCrtcRegisters(xf86CrtcPtr crtc, RADEONSavePtr save,
867209ff23fSmrg			DisplayModePtr mode)
868209ff23fSmrg{
869209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
870209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
871209ff23fSmrg    int    format;
872209ff23fSmrg    int    hsync_start;
873209ff23fSmrg    int    hsync_wid;
874209ff23fSmrg    int    vsync_wid;
875209ff23fSmrg
876209ff23fSmrg    switch (info->CurrentLayout.pixel_code) {
877209ff23fSmrg    case 4:  format = 1; break;
878209ff23fSmrg    case 8:  format = 2; break;
879209ff23fSmrg    case 15: format = 3; break;      /*  555 */
880209ff23fSmrg    case 16: format = 4; break;      /*  565 */
881209ff23fSmrg    case 24: format = 5; break;      /*  RGB */
882209ff23fSmrg    case 32: format = 6; break;      /* xRGB */
883209ff23fSmrg    default:
884209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
885209ff23fSmrg		   "Unsupported pixel depth (%d)\n",
886209ff23fSmrg		   info->CurrentLayout.bitsPerPixel);
887209ff23fSmrg	return FALSE;
888209ff23fSmrg    }
889209ff23fSmrg
890209ff23fSmrg    /*save->bios_4_scratch = info->SavedReg->bios_4_scratch;*/
891209ff23fSmrg    save->crtc_gen_cntl = (RADEON_CRTC_EXT_DISP_EN
892209ff23fSmrg			   | RADEON_CRTC_EN
893209ff23fSmrg			   | (format << 8)
894209ff23fSmrg			   | ((mode->Flags & V_DBLSCAN)
895209ff23fSmrg			      ? RADEON_CRTC_DBL_SCAN_EN
896209ff23fSmrg			      : 0)
897209ff23fSmrg			   | ((mode->Flags & V_CSYNC)
898209ff23fSmrg			      ? RADEON_CRTC_CSYNC_EN
899209ff23fSmrg			      : 0)
900209ff23fSmrg			   | ((mode->Flags & V_INTERLACE)
901209ff23fSmrg			      ? RADEON_CRTC_INTERLACE_EN
902209ff23fSmrg			      : 0));
903209ff23fSmrg
904209ff23fSmrg    save->crtc_ext_cntl |= (RADEON_XCRT_CNT_EN|
905209ff23fSmrg			    RADEON_CRTC_VSYNC_DIS |
906209ff23fSmrg			    RADEON_CRTC_HSYNC_DIS |
907209ff23fSmrg			    RADEON_CRTC_DISPLAY_DIS);
908209ff23fSmrg
909209ff23fSmrg    save->disp_merge_cntl = info->SavedReg->disp_merge_cntl;
910209ff23fSmrg    save->disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN;
911209ff23fSmrg
912209ff23fSmrg    save->crtc_h_total_disp = ((((mode->CrtcHTotal / 8) - 1) & 0x3ff)
913209ff23fSmrg			       | ((((mode->CrtcHDisplay / 8) - 1) & 0x1ff)
914209ff23fSmrg				  << 16));
915209ff23fSmrg
916209ff23fSmrg    hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8;
917209ff23fSmrg    if (!hsync_wid)       hsync_wid = 1;
918209ff23fSmrg    hsync_start = mode->CrtcHSyncStart - 8;
919209ff23fSmrg
920209ff23fSmrg    save->crtc_h_sync_strt_wid = ((hsync_start & 0x1fff)
921209ff23fSmrg				  | ((hsync_wid & 0x3f) << 16)
922209ff23fSmrg				  | ((mode->Flags & V_NHSYNC)
923209ff23fSmrg				     ? RADEON_CRTC_H_SYNC_POL
924209ff23fSmrg				     : 0));
925209ff23fSmrg
926209ff23fSmrg				/* This works for double scan mode. */
927209ff23fSmrg    save->crtc_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff)
928209ff23fSmrg			       | ((mode->CrtcVDisplay - 1) << 16));
929209ff23fSmrg
930209ff23fSmrg    vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart;
931209ff23fSmrg    if (!vsync_wid)       vsync_wid = 1;
932209ff23fSmrg
933209ff23fSmrg    save->crtc_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff)
934209ff23fSmrg				  | ((vsync_wid & 0x1f) << 16)
935209ff23fSmrg				  | ((mode->Flags & V_NVSYNC)
936209ff23fSmrg				     ? RADEON_CRTC_V_SYNC_POL
937209ff23fSmrg				     : 0));
938209ff23fSmrg
939209ff23fSmrg    save->crtc_pitch  = (((pScrn->displayWidth * pScrn->bitsPerPixel) +
940209ff23fSmrg			  ((pScrn->bitsPerPixel * 8) -1)) /
941209ff23fSmrg			 (pScrn->bitsPerPixel * 8));
942209ff23fSmrg    save->crtc_pitch |= save->crtc_pitch << 16;
943209ff23fSmrg
944209ff23fSmrg    if (info->IsDellServer) {
945209ff23fSmrg	save->dac2_cntl = info->SavedReg->dac2_cntl;
946209ff23fSmrg	save->tv_dac_cntl = info->SavedReg->tv_dac_cntl;
947209ff23fSmrg	save->crtc2_gen_cntl = info->SavedReg->crtc2_gen_cntl;
948209ff23fSmrg	save->disp_hw_debug = info->SavedReg->disp_hw_debug;
949209ff23fSmrg
950209ff23fSmrg	save->dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL;
951209ff23fSmrg	save->dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL;
952209ff23fSmrg
953209ff23fSmrg	/* For CRT on DAC2, don't turn it on if BIOS didn't
954209ff23fSmrg	   enable it, even it's detected.
955209ff23fSmrg	*/
956209ff23fSmrg	save->disp_hw_debug |= RADEON_CRT2_DISP1_SEL;
957209ff23fSmrg	save->tv_dac_cntl &= ~((1<<2) | (3<<8) | (7<<24) | (0xff<<16));
958209ff23fSmrg	save->tv_dac_cntl |= (0x03 | (2<<8) | (0x58<<16));
959209ff23fSmrg    }
960209ff23fSmrg
961209ff23fSmrg    return TRUE;
962209ff23fSmrg}
963209ff23fSmrg
964209ff23fSmrg
965209ff23fSmrgstatic Bool
966209ff23fSmrgRADEONInitCrtc2Base(xf86CrtcPtr crtc, RADEONSavePtr save,
967209ff23fSmrg		    int x, int y)
968209ff23fSmrg{
969209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
970209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
971209ff23fSmrg    int    Base;
972209ff23fSmrg#ifdef XF86DRI
973209ff23fSmrg    RADEONSAREAPrivPtr pSAREAPriv;
974209ff23fSmrg    XF86DRISAREAPtr pSAREA;
975209ff23fSmrg#endif
976209ff23fSmrg
977209ff23fSmrg    /* It seems all fancy options apart from pflip can be safely disabled
978209ff23fSmrg     */
979209ff23fSmrg    save->crtc2_offset      = pScrn->fbOffset;
980209ff23fSmrg#ifdef XF86DRI
981209ff23fSmrg    if (info->allowPageFlip)
982209ff23fSmrg	save->crtc2_offset_cntl = RADEON_CRTC_OFFSET_FLIP_CNTL;
983209ff23fSmrg    else
984209ff23fSmrg#endif
985209ff23fSmrg	save->crtc2_offset_cntl = 0;
986209ff23fSmrg
987209ff23fSmrg    if (info->tilingEnabled && (crtc->rotatedData == NULL)) {
988209ff23fSmrg       if (IS_R300_VARIANT)
989209ff23fSmrg          save->crtc2_offset_cntl |= (R300_CRTC_X_Y_MODE_EN |
990209ff23fSmrg				      R300_CRTC_MICRO_TILE_BUFFER_DIS |
991209ff23fSmrg				      R300_CRTC_MACRO_TILE_EN);
992209ff23fSmrg       else
993209ff23fSmrg          save->crtc2_offset_cntl |= RADEON_CRTC_TILE_EN;
994209ff23fSmrg    }
995209ff23fSmrg    else {
996209ff23fSmrg       if (IS_R300_VARIANT)
997209ff23fSmrg          save->crtc2_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN |
998209ff23fSmrg				      R300_CRTC_MICRO_TILE_BUFFER_DIS |
999209ff23fSmrg				      R300_CRTC_MACRO_TILE_EN);
1000209ff23fSmrg       else
1001209ff23fSmrg          save->crtc2_offset_cntl &= ~RADEON_CRTC_TILE_EN;
1002209ff23fSmrg    }
1003209ff23fSmrg
1004209ff23fSmrg    Base = pScrn->fbOffset;
1005209ff23fSmrg
1006209ff23fSmrg    if (info->tilingEnabled && (crtc->rotatedData == NULL)) {
1007209ff23fSmrg        if (IS_R300_VARIANT) {
1008209ff23fSmrg	/* On r300/r400 when tiling is enabled crtc_offset is set to the address of
1009209ff23fSmrg	 * the surface.  the x/y offsets are handled by the X_Y tile reg for each crtc
1010209ff23fSmrg	 * Makes tiling MUCH easier.
1011209ff23fSmrg	 */
1012209ff23fSmrg             save->crtc2_tile_x0_y0 = x | (y << 16);
1013209ff23fSmrg             Base &= ~0x7ff;
1014209ff23fSmrg         } else {
1015209ff23fSmrg	     /* note we cannot really simply use the info->ModeReg.crtc_offset_cntl value, since the
1016209ff23fSmrg		drm might have set FLIP_CNTL since we wrote that. Unfortunately FLIP_CNTL causes
1017209ff23fSmrg		flickering when scrolling vertically in a virtual screen, possibly because crtc will
1018209ff23fSmrg		pick up the new offset value at the end of each scanline, but the new offset_cntl value
1019209ff23fSmrg		only after a vsync. We'd probably need to wait (in drm) for vsync and only then update
1020209ff23fSmrg		OFFSET and OFFSET_CNTL, if the y coord has changed. Seems hard to fix. */
1021209ff23fSmrg	     /*save->crtc2_offset_cntl = INREG(RADEON_CRTC2_OFFSET_CNTL) & ~0xf;*/
1022209ff23fSmrg#if 0
1023209ff23fSmrg	     /* try to get rid of flickering when scrolling at least for 2d */
1024209ff23fSmrg#ifdef XF86DRI
1025209ff23fSmrg	     if (!info->have3DWindows)
1026209ff23fSmrg#endif
1027209ff23fSmrg		 save->crtc2_offset_cntl &= ~RADEON_CRTC_OFFSET_FLIP_CNTL;
1028209ff23fSmrg#endif
1029209ff23fSmrg
1030209ff23fSmrg             int byteshift = info->CurrentLayout.bitsPerPixel >> 4;
1031209ff23fSmrg             /* crtc uses 256(bytes)x8 "half-tile" start addresses? */
1032209ff23fSmrg             int tile_addr = (((y >> 3) * info->CurrentLayout.displayWidth + x) >> (8 - byteshift)) << 11;
1033209ff23fSmrg             Base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8);
1034209ff23fSmrg             save->crtc2_offset_cntl = save->crtc_offset_cntl | (y % 16);
1035209ff23fSmrg         }
1036209ff23fSmrg    }
1037209ff23fSmrg    else {
1038209ff23fSmrg       int offset = y * info->CurrentLayout.displayWidth + x;
1039209ff23fSmrg       switch (info->CurrentLayout.pixel_code) {
1040209ff23fSmrg       case 15:
1041209ff23fSmrg       case 16: offset *= 2; break;
1042209ff23fSmrg       case 24: offset *= 3; break;
1043209ff23fSmrg       case 32: offset *= 4; break;
1044209ff23fSmrg       }
1045209ff23fSmrg       Base += offset;
1046209ff23fSmrg    }
1047209ff23fSmrg
1048209ff23fSmrg    if (crtc->rotatedData != NULL) {
1049209ff23fSmrg	Base = pScrn->fbOffset + (char *)crtc->rotatedData - (char *)info->FB;
1050209ff23fSmrg    }
1051209ff23fSmrg
1052209ff23fSmrg    Base &= ~7;                 /* 3 lower bits are always 0 */
1053209ff23fSmrg
1054209ff23fSmrg#ifdef XF86DRI
1055209ff23fSmrg    if (info->directRenderingInited) {
1056209ff23fSmrg	/* note cannot use pScrn->pScreen since this is unitialized when called from
1057209ff23fSmrg	   RADEONScreenInit, and we need to call from there to get mergedfb + pageflip working */
1058209ff23fSmrg        /*** NOTE: r3/4xx will need sarea and drm pageflip updates to handle the xytile regs for
1059209ff23fSmrg	 *** pageflipping!
1060209ff23fSmrg	 ***/
1061209ff23fSmrg	pSAREAPriv = DRIGetSAREAPrivate(screenInfo.screens[pScrn->scrnIndex]);
1062209ff23fSmrg	/* can't get at sarea in a semi-sane way? */
1063209ff23fSmrg	pSAREA = (void *)((char*)pSAREAPriv - sizeof(XF86DRISAREARec));
1064209ff23fSmrg
1065209ff23fSmrg	pSAREAPriv->crtc2_base = Base;
1066209ff23fSmrg
1067209ff23fSmrg	if (pSAREAPriv->pfCurrentPage == 1) {
1068209ff23fSmrg	    Base += info->backOffset - info->frontOffset;
1069209ff23fSmrg	}
1070209ff23fSmrg    }
1071209ff23fSmrg#endif
1072209ff23fSmrg    save->crtc2_offset = Base;
1073209ff23fSmrg
1074209ff23fSmrg    return TRUE;
1075209ff23fSmrg}
1076209ff23fSmrg
1077209ff23fSmrg
1078209ff23fSmrg/* Define CRTC2 registers for requested video mode */
1079209ff23fSmrgstatic Bool
1080209ff23fSmrgRADEONInitCrtc2Registers(xf86CrtcPtr crtc, RADEONSavePtr save,
1081209ff23fSmrg			 DisplayModePtr mode)
1082209ff23fSmrg{
1083209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
1084209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1085209ff23fSmrg    int    format;
1086209ff23fSmrg    int    hsync_start;
1087209ff23fSmrg    int    hsync_wid;
1088209ff23fSmrg    int    vsync_wid;
1089209ff23fSmrg
1090209ff23fSmrg    switch (info->CurrentLayout.pixel_code) {
1091209ff23fSmrg    case 4:  format = 1; break;
1092209ff23fSmrg    case 8:  format = 2; break;
1093209ff23fSmrg    case 15: format = 3; break;      /*  555 */
1094209ff23fSmrg    case 16: format = 4; break;      /*  565 */
1095209ff23fSmrg    case 24: format = 5; break;      /*  RGB */
1096209ff23fSmrg    case 32: format = 6; break;      /* xRGB */
1097209ff23fSmrg    default:
1098209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1099209ff23fSmrg		   "Unsupported pixel depth (%d)\n",
1100209ff23fSmrg		   info->CurrentLayout.bitsPerPixel);
1101209ff23fSmrg	return FALSE;
1102209ff23fSmrg    }
1103209ff23fSmrg
1104209ff23fSmrg    save->crtc2_h_total_disp =
1105209ff23fSmrg	((((mode->CrtcHTotal / 8) - 1) & 0x3ff)
1106209ff23fSmrg	 | ((((mode->CrtcHDisplay / 8) - 1) & 0x1ff) << 16));
1107209ff23fSmrg
1108209ff23fSmrg    hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8;
1109209ff23fSmrg    if (!hsync_wid)       hsync_wid = 1;
1110209ff23fSmrg    hsync_start = mode->CrtcHSyncStart - 8;
1111209ff23fSmrg
1112209ff23fSmrg    save->crtc2_h_sync_strt_wid = ((hsync_start & 0x1fff)
1113209ff23fSmrg				   | ((hsync_wid & 0x3f) << 16)
1114209ff23fSmrg				   | ((mode->Flags & V_NHSYNC)
1115209ff23fSmrg				      ? RADEON_CRTC_H_SYNC_POL
1116209ff23fSmrg				      : 0));
1117209ff23fSmrg
1118209ff23fSmrg				/* This works for double scan mode. */
1119209ff23fSmrg    save->crtc2_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff)
1120209ff23fSmrg				| ((mode->CrtcVDisplay - 1) << 16));
1121209ff23fSmrg
1122209ff23fSmrg    vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart;
1123209ff23fSmrg    if (!vsync_wid)       vsync_wid = 1;
1124209ff23fSmrg
1125209ff23fSmrg    save->crtc2_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff)
1126209ff23fSmrg				   | ((vsync_wid & 0x1f) << 16)
1127209ff23fSmrg				   | ((mode->Flags & V_NVSYNC)
1128209ff23fSmrg				      ? RADEON_CRTC2_V_SYNC_POL
1129209ff23fSmrg				      : 0));
1130209ff23fSmrg
1131209ff23fSmrg    save->crtc2_pitch  = ((pScrn->displayWidth * pScrn->bitsPerPixel) +
1132209ff23fSmrg			  ((pScrn->bitsPerPixel * 8) -1)) / (pScrn->bitsPerPixel * 8);
1133209ff23fSmrg    save->crtc2_pitch |= save->crtc2_pitch << 16;
1134209ff23fSmrg
1135209ff23fSmrg    /* check to see if TV DAC is enabled for another crtc and keep it enabled */
1136209ff23fSmrg    if (save->crtc2_gen_cntl & RADEON_CRTC2_CRT2_ON)
1137209ff23fSmrg	save->crtc2_gen_cntl = RADEON_CRTC2_CRT2_ON;
1138209ff23fSmrg    else
1139209ff23fSmrg	save->crtc2_gen_cntl = 0;
1140209ff23fSmrg
1141209ff23fSmrg    save->crtc2_gen_cntl |= (RADEON_CRTC2_EN
1142209ff23fSmrg			     | (format << 8)
1143209ff23fSmrg			     | RADEON_CRTC2_VSYNC_DIS
1144209ff23fSmrg			     | RADEON_CRTC2_HSYNC_DIS
1145209ff23fSmrg			     | RADEON_CRTC2_DISP_DIS
1146209ff23fSmrg			     | ((mode->Flags & V_DBLSCAN)
1147209ff23fSmrg				? RADEON_CRTC2_DBL_SCAN_EN
1148209ff23fSmrg				: 0)
1149209ff23fSmrg			     | ((mode->Flags & V_CSYNC)
1150209ff23fSmrg				? RADEON_CRTC2_CSYNC_EN
1151209ff23fSmrg				: 0)
1152209ff23fSmrg			     | ((mode->Flags & V_INTERLACE)
1153209ff23fSmrg				? RADEON_CRTC2_INTERLACE_EN
1154209ff23fSmrg				: 0));
1155209ff23fSmrg
1156209ff23fSmrg    save->disp2_merge_cntl = info->SavedReg->disp2_merge_cntl;
1157209ff23fSmrg    save->disp2_merge_cntl &= ~(RADEON_DISP2_RGB_OFFSET_EN);
1158209ff23fSmrg
1159209ff23fSmrg    save->fp_h2_sync_strt_wid = save->crtc2_h_sync_strt_wid;
1160209ff23fSmrg    save->fp_v2_sync_strt_wid = save->crtc2_v_sync_strt_wid;
1161209ff23fSmrg
1162209ff23fSmrg    return TRUE;
1163209ff23fSmrg}
1164209ff23fSmrg
1165209ff23fSmrg
1166209ff23fSmrg/* Define PLL registers for requested video mode */
1167209ff23fSmrgstatic void
1168209ff23fSmrgRADEONInitPLLRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save,
1169209ff23fSmrg		       RADEONPLLPtr pll, DisplayModePtr mode,
1170209ff23fSmrg		       int flags)
1171209ff23fSmrg{
1172209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1173209ff23fSmrg    uint32_t feedback_div = 0;
1174209ff23fSmrg    uint32_t reference_div = 0;
1175209ff23fSmrg    uint32_t post_divider = 0;
1176209ff23fSmrg    uint32_t freq = 0;
1177209ff23fSmrg
1178209ff23fSmrg    struct {
1179209ff23fSmrg	int divider;
1180209ff23fSmrg	int bitvalue;
1181209ff23fSmrg    } *post_div, post_divs[]   = {
1182209ff23fSmrg				/* From RAGE 128 VR/RAGE 128 GL Register
1183209ff23fSmrg				 * Reference Manual (Technical Reference
1184209ff23fSmrg				 * Manual P/N RRG-G04100-C Rev. 0.04), page
1185209ff23fSmrg				 * 3-17 (PLL_DIV_[3:0]).
1186209ff23fSmrg				 */
1187209ff23fSmrg	{  1, 0 },              /* VCLK_SRC                 */
1188209ff23fSmrg	{  2, 1 },              /* VCLK_SRC/2               */
1189209ff23fSmrg	{  4, 2 },              /* VCLK_SRC/4               */
1190209ff23fSmrg	{  8, 3 },              /* VCLK_SRC/8               */
1191209ff23fSmrg	{  3, 4 },              /* VCLK_SRC/3               */
1192209ff23fSmrg	{ 16, 5 },              /* VCLK_SRC/16              */
1193209ff23fSmrg	{  6, 6 },              /* VCLK_SRC/6               */
1194209ff23fSmrg	{ 12, 7 },              /* VCLK_SRC/12              */
1195209ff23fSmrg	{  0, 0 }
1196209ff23fSmrg    };
1197209ff23fSmrg
1198209ff23fSmrg
1199209ff23fSmrg    if ((flags & RADEON_PLL_USE_BIOS_DIVS) && info->UseBiosDividers) {
1200209ff23fSmrg       save->ppll_ref_div = info->RefDivider;
1201209ff23fSmrg       save->ppll_div_3   = info->FeedbackDivider | (info->PostDivider << 16);
1202209ff23fSmrg       save->htotal_cntl  = 0;
1203209ff23fSmrg       return;
1204209ff23fSmrg    }
1205209ff23fSmrg
1206209ff23fSmrg    RADEONComputePLL(pll, mode->Clock, &freq, &feedback_div, &reference_div, &post_divider, flags);
1207209ff23fSmrg
1208209ff23fSmrg    for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
1209209ff23fSmrg	if (post_div->divider == post_divider)
1210209ff23fSmrg	    break;
1211209ff23fSmrg    }
1212209ff23fSmrg
1213209ff23fSmrg    if (!post_div->divider) {
1214209ff23fSmrg	save->pll_output_freq = freq;
1215209ff23fSmrg	post_div = &post_divs[0];
1216209ff23fSmrg    }
1217209ff23fSmrg
1218209ff23fSmrg    save->dot_clock_freq = freq;
1219209ff23fSmrg    save->feedback_div   = feedback_div;
1220209ff23fSmrg    save->reference_div  = reference_div;
1221209ff23fSmrg    save->post_div       = post_divider;
1222209ff23fSmrg
1223209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
1224209ff23fSmrg		   "dc=%u, of=%u, fd=%d, rd=%d, pd=%d\n",
1225209ff23fSmrg		   (unsigned)save->dot_clock_freq,
1226209ff23fSmrg		   (unsigned)save->pll_output_freq,
1227209ff23fSmrg		   save->feedback_div,
1228209ff23fSmrg		   save->reference_div,
1229209ff23fSmrg		   save->post_div);
1230209ff23fSmrg
1231209ff23fSmrg    save->ppll_ref_div   = save->reference_div;
1232209ff23fSmrg
1233209ff23fSmrg#if defined(__powerpc__)
1234209ff23fSmrg    /* apparently programming this otherwise causes a hang??? */
1235209ff23fSmrg    if (info->MacModel == RADEON_MAC_IBOOK)
1236209ff23fSmrg	save->ppll_div_3 = 0x000600ad;
1237209ff23fSmrg    else
1238209ff23fSmrg#endif
1239209ff23fSmrg    save->ppll_div_3     = (save->feedback_div | (post_div->bitvalue << 16));
1240209ff23fSmrg
1241209ff23fSmrg    save->htotal_cntl    = mode->HTotal & 0x7;
1242209ff23fSmrg
1243209ff23fSmrg    save->vclk_ecp_cntl = (info->SavedReg->vclk_ecp_cntl &
1244209ff23fSmrg	    ~RADEON_VCLK_SRC_SEL_MASK) | RADEON_VCLK_SRC_SEL_PPLLCLK;
1245209ff23fSmrg}
1246209ff23fSmrg
1247209ff23fSmrg/* Define PLL2 registers for requested video mode */
1248209ff23fSmrgstatic void
1249209ff23fSmrgRADEONInitPLL2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save,
1250209ff23fSmrg			RADEONPLLPtr pll, DisplayModePtr mode,
1251209ff23fSmrg			int flags)
1252209ff23fSmrg{
1253209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1254209ff23fSmrg    uint32_t feedback_div = 0;
1255209ff23fSmrg    uint32_t reference_div = 0;
1256209ff23fSmrg    uint32_t post_divider = 0;
1257209ff23fSmrg    uint32_t freq = 0;
1258209ff23fSmrg
1259209ff23fSmrg    struct {
1260209ff23fSmrg	int divider;
1261209ff23fSmrg	int bitvalue;
1262209ff23fSmrg    } *post_div, post_divs[]   = {
1263209ff23fSmrg				/* From RAGE 128 VR/RAGE 128 GL Register
1264209ff23fSmrg				 * Reference Manual (Technical Reference
1265209ff23fSmrg				 * Manual P/N RRG-G04100-C Rev. 0.04), page
1266209ff23fSmrg				 * 3-17 (PLL_DIV_[3:0]).
1267209ff23fSmrg				 */
1268209ff23fSmrg	{  1, 0 },              /* VCLK_SRC                 */
1269209ff23fSmrg	{  2, 1 },              /* VCLK_SRC/2               */
1270209ff23fSmrg	{  4, 2 },              /* VCLK_SRC/4               */
1271209ff23fSmrg	{  8, 3 },              /* VCLK_SRC/8               */
1272209ff23fSmrg	{  3, 4 },              /* VCLK_SRC/3               */
1273209ff23fSmrg	{  6, 6 },              /* VCLK_SRC/6               */
1274209ff23fSmrg	{ 12, 7 },              /* VCLK_SRC/12              */
1275209ff23fSmrg	{  0, 0 }
1276209ff23fSmrg    };
1277209ff23fSmrg
1278209ff23fSmrg    if ((flags & RADEON_PLL_USE_BIOS_DIVS) && info->UseBiosDividers) {
1279209ff23fSmrg       save->p2pll_ref_div = info->RefDivider;
1280209ff23fSmrg       save->p2pll_div_0   = info->FeedbackDivider | (info->PostDivider << 16);
1281209ff23fSmrg       save->htotal_cntl2  = 0;
1282209ff23fSmrg       return;
1283209ff23fSmrg    }
1284209ff23fSmrg
1285209ff23fSmrg    RADEONComputePLL(pll, mode->Clock, &freq, &feedback_div, &reference_div, &post_divider, flags);
1286209ff23fSmrg
1287209ff23fSmrg    for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
1288209ff23fSmrg	if (post_div->divider == post_divider)
1289209ff23fSmrg	    break;
1290209ff23fSmrg    }
1291209ff23fSmrg
1292209ff23fSmrg    if (!post_div->divider) {
1293209ff23fSmrg	save->pll_output_freq_2 = freq;
1294209ff23fSmrg	post_div = &post_divs[0];
1295209ff23fSmrg    }
1296209ff23fSmrg
1297209ff23fSmrg    save->dot_clock_freq_2 = freq;
1298209ff23fSmrg    save->feedback_div_2   = feedback_div;
1299209ff23fSmrg    save->reference_div_2  = reference_div;
1300209ff23fSmrg    save->post_div_2       = post_divider;
1301209ff23fSmrg
1302209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
1303209ff23fSmrg		   "dc=%u, of=%u, fd=%d, rd=%d, pd=%d\n",
1304209ff23fSmrg		   (unsigned)save->dot_clock_freq_2,
1305209ff23fSmrg		   (unsigned)save->pll_output_freq_2,
1306209ff23fSmrg		   save->feedback_div_2,
1307209ff23fSmrg		   save->reference_div_2,
1308209ff23fSmrg		   save->post_div_2);
1309209ff23fSmrg
1310209ff23fSmrg    save->p2pll_ref_div    = save->reference_div_2;
1311209ff23fSmrg
1312209ff23fSmrg    save->p2pll_div_0      = (save->feedback_div_2 |
1313209ff23fSmrg			      (post_div->bitvalue << 16));
1314209ff23fSmrg
1315209ff23fSmrg    save->htotal_cntl2     = mode->HTotal & 0x7;
1316209ff23fSmrg
1317209ff23fSmrg    save->pixclks_cntl     = ((info->SavedReg->pixclks_cntl &
1318209ff23fSmrg			       ~(RADEON_PIX2CLK_SRC_SEL_MASK)) |
1319209ff23fSmrg			      RADEON_PIX2CLK_SRC_SEL_P2PLLCLK);
1320209ff23fSmrg}
1321209ff23fSmrg
1322209ff23fSmrgstatic void
1323209ff23fSmrgradeon_update_tv_routing(ScrnInfoPtr pScrn, RADEONSavePtr restore)
1324209ff23fSmrg{
1325209ff23fSmrg    /* pixclks_cntl controls tv clock routing */
1326209ff23fSmrg    OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, restore->pixclks_cntl);
1327209ff23fSmrg}
1328209ff23fSmrg
1329209ff23fSmrg/* Calculate display buffer watermark to prevent buffer underflow */
1330209ff23fSmrgstatic void
1331209ff23fSmrgRADEONInitDispBandwidth2(ScrnInfoPtr pScrn, RADEONInfoPtr info, int pixel_bytes2, DisplayModePtr mode1, DisplayModePtr mode2)
1332209ff23fSmrg{
1333209ff23fSmrg    RADEONEntPtr pRADEONEnt   = RADEONEntPriv(pScrn);
1334209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
1335209ff23fSmrg
1336209ff23fSmrg    uint32_t temp, data, mem_trcd, mem_trp, mem_tras, mem_trbs=0;
1337209ff23fSmrg    float mem_tcas;
1338209ff23fSmrg    int k1, c;
1339209ff23fSmrg    uint32_t MemTrcdExtMemCntl[4]     = {1, 2, 3, 4};
1340209ff23fSmrg    uint32_t MemTrpExtMemCntl[4]      = {1, 2, 3, 4};
1341209ff23fSmrg    uint32_t MemTrasExtMemCntl[8]     = {1, 2, 3, 4, 5, 6, 7, 8};
1342209ff23fSmrg
1343209ff23fSmrg    uint32_t MemTrcdMemTimingCntl[8]     = {1, 2, 3, 4, 5, 6, 7, 8};
1344209ff23fSmrg    uint32_t MemTrpMemTimingCntl[8]      = {1, 2, 3, 4, 5, 6, 7, 8};
1345209ff23fSmrg    uint32_t MemTrasMemTimingCntl[16]    = {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
1346209ff23fSmrg
1347209ff23fSmrg    float MemTcas[8]  = {0, 1, 2, 3, 0, 1.5, 2.5, 0};
1348209ff23fSmrg    float MemTcas2[8] = {0, 1, 2, 3, 4, 5, 6, 7};
1349209ff23fSmrg    float MemTrbs[8]  = {1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5};
1350209ff23fSmrg
1351209ff23fSmrg    float mem_bw, peak_disp_bw;
1352209ff23fSmrg    float min_mem_eff = 0.8;
1353209ff23fSmrg    float sclk_eff, sclk_delay;
1354209ff23fSmrg    float mc_latency_mclk, mc_latency_sclk, cur_latency_mclk, cur_latency_sclk;
1355209ff23fSmrg    float disp_latency, disp_latency_overhead, disp_drain_rate, disp_drain_rate2;
1356209ff23fSmrg    float pix_clk, pix_clk2; /* in MHz */
1357209ff23fSmrg    int cur_size = 16;       /* in octawords */
1358209ff23fSmrg    int critical_point, critical_point2;
1359209ff23fSmrg    int stop_req, max_stop_req;
1360209ff23fSmrg    float read_return_rate, time_disp1_drop_priority;
1361209ff23fSmrg
1362209ff23fSmrg    /*
1363209ff23fSmrg     * Set display0/1 priority up on r3/4xx in the memory controller for
1364209ff23fSmrg     * high res modes if the user specifies HIGH for displaypriority
1365209ff23fSmrg     * option.
1366209ff23fSmrg     */
1367209ff23fSmrg    if ((info->DispPriority == 2) && IS_R300_VARIANT) {
1368209ff23fSmrg	uint32_t mc_init_misc_lat_timer = INREG(R300_MC_INIT_MISC_LAT_TIMER);
1369209ff23fSmrg	if (pRADEONEnt->pCrtc[1]->enabled) {
1370209ff23fSmrg	    mc_init_misc_lat_timer |= 0x1100; /* display 0 and 1 */
1371209ff23fSmrg	} else {
1372209ff23fSmrg	    mc_init_misc_lat_timer |= 0x0100; /* display 0 only */
1373209ff23fSmrg	}
1374209ff23fSmrg	OUTREG(R300_MC_INIT_MISC_LAT_TIMER, mc_init_misc_lat_timer);
1375209ff23fSmrg    }
1376209ff23fSmrg
1377209ff23fSmrg
1378209ff23fSmrg    /* R420 and RV410 family not supported yet */
1379209ff23fSmrg    if (info->ChipFamily == CHIP_FAMILY_R420 || info->ChipFamily == CHIP_FAMILY_RV410) return;
1380209ff23fSmrg
1381209ff23fSmrg    /*
1382209ff23fSmrg     * Determine if there is enough bandwidth for current display mode
1383209ff23fSmrg     */
1384209ff23fSmrg    mem_bw = info->mclk * (info->RamWidth / 8) * (info->IsDDR ? 2 : 1);
1385209ff23fSmrg
1386209ff23fSmrg    pix_clk = mode1->Clock/1000.0;
1387209ff23fSmrg    if (mode2)
1388209ff23fSmrg	pix_clk2 = mode2->Clock/1000.0;
1389209ff23fSmrg    else
1390209ff23fSmrg	pix_clk2 = 0;
1391209ff23fSmrg
1392209ff23fSmrg    peak_disp_bw = (pix_clk * info->CurrentLayout.pixel_bytes);
1393209ff23fSmrg    if (pixel_bytes2)
1394209ff23fSmrg      peak_disp_bw += (pix_clk2 * pixel_bytes2);
1395209ff23fSmrg
1396209ff23fSmrg    if (peak_disp_bw >= mem_bw * min_mem_eff) {
1397209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1398209ff23fSmrg		   "You may not have enough display bandwidth for current mode\n"
1399209ff23fSmrg		   "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n");
1400209ff23fSmrg    }
1401209ff23fSmrg
1402209ff23fSmrg    /*  CRTC1
1403209ff23fSmrg        Set GRPH_BUFFER_CNTL register using h/w defined optimal values.
1404209ff23fSmrg	GRPH_STOP_REQ <= MIN[ 0x7C, (CRTC_H_DISP + 1) * (bit depth) / 0x10 ]
1405209ff23fSmrg    */
1406209ff23fSmrg    stop_req = mode1->HDisplay * info->CurrentLayout.pixel_bytes / 16;
1407209ff23fSmrg
1408209ff23fSmrg    /* setup Max GRPH_STOP_REQ default value */
1409209ff23fSmrg    if (IS_RV100_VARIANT)
1410209ff23fSmrg	max_stop_req = 0x5c;
1411209ff23fSmrg    else
1412209ff23fSmrg	max_stop_req  = 0x7c;
1413209ff23fSmrg    if (stop_req > max_stop_req)
1414209ff23fSmrg	stop_req = max_stop_req;
1415209ff23fSmrg
1416209ff23fSmrg    /*  Get values from the EXT_MEM_CNTL register...converting its contents. */
1417209ff23fSmrg    temp = INREG(RADEON_MEM_TIMING_CNTL);
1418209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_RV100) || info->IsIGP) { /* RV100, M6, IGPs */
1419209ff23fSmrg	mem_trcd      = MemTrcdExtMemCntl[(temp & 0x0c) >> 2];
1420209ff23fSmrg	mem_trp       = MemTrpExtMemCntl[ (temp & 0x03) >> 0];
1421209ff23fSmrg	mem_tras      = MemTrasExtMemCntl[(temp & 0x70) >> 4];
1422209ff23fSmrg    } else { /* RV200 and later */
1423209ff23fSmrg	mem_trcd      = MemTrcdMemTimingCntl[(temp & 0x07) >> 0];
1424209ff23fSmrg	mem_trp       = MemTrpMemTimingCntl[ (temp & 0x700) >> 8];
1425209ff23fSmrg	mem_tras      = MemTrasMemTimingCntl[(temp & 0xf000) >> 12];
1426209ff23fSmrg    }
1427209ff23fSmrg
1428209ff23fSmrg    /* Get values from the MEM_SDRAM_MODE_REG register...converting its */
1429209ff23fSmrg    temp = INREG(RADEON_MEM_SDRAM_MODE_REG);
1430209ff23fSmrg    data = (temp & (7<<20)) >> 20;
1431209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_RV100) || info->IsIGP) { /* RV100, M6, IGPs */
1432209ff23fSmrg	mem_tcas = MemTcas [data];
1433209ff23fSmrg    } else {
1434209ff23fSmrg	mem_tcas = MemTcas2 [data];
1435209ff23fSmrg    }
1436209ff23fSmrg
1437209ff23fSmrg    if (IS_R300_VARIANT) {
1438209ff23fSmrg
1439209ff23fSmrg	/* on the R300, Tcas is included in Trbs.
1440209ff23fSmrg	*/
1441209ff23fSmrg	temp = INREG(RADEON_MEM_CNTL);
1442209ff23fSmrg	data = (R300_MEM_NUM_CHANNELS_MASK & temp);
1443209ff23fSmrg	if (data == 1) {
1444209ff23fSmrg	    if (R300_MEM_USE_CD_CH_ONLY & temp) {
1445209ff23fSmrg		temp  = INREG(R300_MC_IND_INDEX);
1446209ff23fSmrg		temp &= ~R300_MC_IND_ADDR_MASK;
1447209ff23fSmrg		temp |= R300_MC_READ_CNTL_CD_mcind;
1448209ff23fSmrg		OUTREG(R300_MC_IND_INDEX, temp);
1449209ff23fSmrg		temp  = INREG(R300_MC_IND_DATA);
1450209ff23fSmrg		data = (R300_MEM_RBS_POSITION_C_MASK & temp);
1451209ff23fSmrg	    } else {
1452209ff23fSmrg		temp = INREG(R300_MC_READ_CNTL_AB);
1453209ff23fSmrg		data = (R300_MEM_RBS_POSITION_A_MASK & temp);
1454209ff23fSmrg	    }
1455209ff23fSmrg	} else {
1456209ff23fSmrg	    temp = INREG(R300_MC_READ_CNTL_AB);
1457209ff23fSmrg	    data = (R300_MEM_RBS_POSITION_A_MASK & temp);
1458209ff23fSmrg	}
1459209ff23fSmrg
1460209ff23fSmrg	mem_trbs = MemTrbs[data];
1461209ff23fSmrg	mem_tcas += mem_trbs;
1462209ff23fSmrg    }
1463209ff23fSmrg
1464209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_RV100) || info->IsIGP) { /* RV100, M6, IGPs */
1465209ff23fSmrg	/* DDR64 SCLK_EFF = SCLK for analysis */
1466209ff23fSmrg	sclk_eff = info->sclk;
1467209ff23fSmrg    } else {
1468209ff23fSmrg#ifdef XF86DRI
1469209ff23fSmrg	if (info->directRenderingEnabled)
1470209ff23fSmrg	    sclk_eff = info->sclk - (info->agpMode * 50.0 / 3.0);
1471209ff23fSmrg	else
1472209ff23fSmrg#endif
1473209ff23fSmrg	    sclk_eff = info->sclk;
1474209ff23fSmrg    }
1475209ff23fSmrg
1476209ff23fSmrg    /* Find the memory controller latency for the display client.
1477209ff23fSmrg    */
1478209ff23fSmrg    if (IS_R300_VARIANT) {
1479209ff23fSmrg	/*not enough for R350 ???*/
1480209ff23fSmrg	/*
1481209ff23fSmrg	if (!mode2) sclk_delay = 150;
1482209ff23fSmrg	else {
1483209ff23fSmrg	    if (info->RamWidth == 256) sclk_delay = 87;
1484209ff23fSmrg	    else sclk_delay = 97;
1485209ff23fSmrg	}
1486209ff23fSmrg	*/
1487209ff23fSmrg	sclk_delay = 250;
1488209ff23fSmrg    } else {
1489209ff23fSmrg	if ((info->ChipFamily == CHIP_FAMILY_RV100) ||
1490209ff23fSmrg	    info->IsIGP) {
1491209ff23fSmrg	    if (info->IsDDR) sclk_delay = 41;
1492209ff23fSmrg	    else sclk_delay = 33;
1493209ff23fSmrg	} else {
1494209ff23fSmrg	    if (info->RamWidth == 128) sclk_delay = 57;
1495209ff23fSmrg	    else sclk_delay = 41;
1496209ff23fSmrg	}
1497209ff23fSmrg    }
1498209ff23fSmrg
1499209ff23fSmrg    mc_latency_sclk = sclk_delay / sclk_eff;
1500209ff23fSmrg
1501209ff23fSmrg    if (info->IsDDR) {
1502209ff23fSmrg	if (info->RamWidth == 32) {
1503209ff23fSmrg	    k1 = 40;
1504209ff23fSmrg	    c  = 3;
1505209ff23fSmrg	} else {
1506209ff23fSmrg	    k1 = 20;
1507209ff23fSmrg	    c  = 1;
1508209ff23fSmrg	}
1509209ff23fSmrg    } else {
1510209ff23fSmrg	k1 = 40;
1511209ff23fSmrg	c  = 3;
1512209ff23fSmrg    }
1513209ff23fSmrg    mc_latency_mclk = ((2.0*mem_trcd + mem_tcas*c + 4.0*mem_tras + 4.0*mem_trp + k1) /
1514209ff23fSmrg		       info->mclk) + (4.0 / sclk_eff);
1515209ff23fSmrg
1516209ff23fSmrg    /*
1517209ff23fSmrg      HW cursor time assuming worst case of full size colour cursor.
1518209ff23fSmrg    */
1519209ff23fSmrg    cur_latency_mclk = (mem_trp + MAX(mem_tras, (mem_trcd + 2*(cur_size - (info->IsDDR+1))))) / info->mclk;
1520209ff23fSmrg    cur_latency_sclk = cur_size / sclk_eff;
1521209ff23fSmrg
1522209ff23fSmrg    /*
1523209ff23fSmrg      Find the total latency for the display data.
1524209ff23fSmrg    */
1525209ff23fSmrg    disp_latency_overhead = 8.0 / info->sclk;
1526209ff23fSmrg    mc_latency_mclk = mc_latency_mclk + disp_latency_overhead + cur_latency_mclk;
1527209ff23fSmrg    mc_latency_sclk = mc_latency_sclk + disp_latency_overhead + cur_latency_sclk;
1528209ff23fSmrg    disp_latency = MAX(mc_latency_mclk, mc_latency_sclk);
1529209ff23fSmrg
1530209ff23fSmrg    /*
1531209ff23fSmrg      Find the drain rate of the display buffer.
1532209ff23fSmrg    */
1533209ff23fSmrg    disp_drain_rate = pix_clk / (16.0/info->CurrentLayout.pixel_bytes);
1534209ff23fSmrg    if (pixel_bytes2)
1535209ff23fSmrg	disp_drain_rate2 = pix_clk2 / (16.0/pixel_bytes2);
1536209ff23fSmrg    else
1537209ff23fSmrg	disp_drain_rate2 = 0;
1538209ff23fSmrg
1539209ff23fSmrg    /*
1540209ff23fSmrg      Find the critical point of the display buffer.
1541209ff23fSmrg    */
1542209ff23fSmrg    critical_point= (uint32_t)(disp_drain_rate * disp_latency + 0.5);
1543209ff23fSmrg
1544209ff23fSmrg    /* ???? */
1545209ff23fSmrg    /*
1546209ff23fSmrg    temp = (info->SavedReg.grph_buffer_cntl & RADEON_GRPH_CRITICAL_POINT_MASK) >> RADEON_GRPH_CRITICAL_POINT_SHIFT;
1547209ff23fSmrg    if (critical_point < temp) critical_point = temp;
1548209ff23fSmrg    */
1549209ff23fSmrg    if (info->DispPriority == 2) {
1550209ff23fSmrg	critical_point = 0;
1551209ff23fSmrg    }
1552209ff23fSmrg
1553209ff23fSmrg    /*
1554209ff23fSmrg      The critical point should never be above max_stop_req-4.  Setting
1555209ff23fSmrg      GRPH_CRITICAL_CNTL = 0 will thus force high priority all the time.
1556209ff23fSmrg    */
1557209ff23fSmrg    if (max_stop_req - critical_point < 4) critical_point = 0;
1558209ff23fSmrg
1559209ff23fSmrg    if (critical_point == 0 && mode2 && info->ChipFamily == CHIP_FAMILY_R300) {
1560209ff23fSmrg	/* some R300 cards have problem with this set to 0, when CRTC2 is enabled.*/
1561209ff23fSmrg	critical_point = 0x10;
1562209ff23fSmrg    }
1563209ff23fSmrg
1564209ff23fSmrg    temp = info->SavedReg->grph_buffer_cntl;
1565209ff23fSmrg    temp &= ~(RADEON_GRPH_STOP_REQ_MASK);
1566209ff23fSmrg    temp |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT);
1567209ff23fSmrg    temp &= ~(RADEON_GRPH_START_REQ_MASK);
1568209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_R350) &&
1569209ff23fSmrg	(stop_req > 0x15)) {
1570209ff23fSmrg	stop_req -= 0x10;
1571209ff23fSmrg    }
1572209ff23fSmrg    temp |= (stop_req << RADEON_GRPH_START_REQ_SHIFT);
1573209ff23fSmrg
1574209ff23fSmrg    temp |= RADEON_GRPH_BUFFER_SIZE;
1575209ff23fSmrg    temp &= ~(RADEON_GRPH_CRITICAL_CNTL   |
1576209ff23fSmrg	      RADEON_GRPH_CRITICAL_AT_SOF |
1577209ff23fSmrg	      RADEON_GRPH_STOP_CNTL);
1578209ff23fSmrg    /*
1579209ff23fSmrg      Write the result into the register.
1580209ff23fSmrg    */
1581209ff23fSmrg    OUTREG(RADEON_GRPH_BUFFER_CNTL, ((temp & ~RADEON_GRPH_CRITICAL_POINT_MASK) |
1582209ff23fSmrg				     (critical_point << RADEON_GRPH_CRITICAL_POINT_SHIFT)));
1583209ff23fSmrg
1584209ff23fSmrg#if 0
1585209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_RS400) ||
1586209ff23fSmrg	(info->ChipFamily == CHIP_FAMILY_RS480)) {
1587209ff23fSmrg	/* attempt to program RS400 disp regs correctly ??? */
1588209ff23fSmrg	temp = info->SavedReg->disp1_req_cntl1;
1589209ff23fSmrg	temp &= ~(RS400_DISP1_START_REQ_LEVEL_MASK |
1590209ff23fSmrg		  RS400_DISP1_STOP_REQ_LEVEL_MASK);
1591209ff23fSmrg	OUTREG(RS400_DISP1_REQ_CNTL1, (temp |
1592209ff23fSmrg				       (critical_point << RS400_DISP1_START_REQ_LEVEL_SHIFT) |
1593209ff23fSmrg				       (critical_point << RS400_DISP1_STOP_REQ_LEVEL_SHIFT)));
1594209ff23fSmrg	temp = info->SavedReg->dmif_mem_cntl1;
1595209ff23fSmrg	temp &= ~(RS400_DISP1_CRITICAL_POINT_START_MASK |
1596209ff23fSmrg		  RS400_DISP1_CRITICAL_POINT_STOP_MASK);
1597209ff23fSmrg	OUTREG(RS400_DMIF_MEM_CNTL1, (temp |
1598209ff23fSmrg				      (critical_point << RS400_DISP1_CRITICAL_POINT_START_SHIFT) |
1599209ff23fSmrg				      (critical_point << RS400_DISP1_CRITICAL_POINT_STOP_SHIFT)));
1600209ff23fSmrg    }
1601209ff23fSmrg#endif
1602209ff23fSmrg
1603209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
1604209ff23fSmrg		   "GRPH_BUFFER_CNTL from %x to %x\n",
1605209ff23fSmrg		   (unsigned int)info->SavedReg->grph_buffer_cntl,
1606209ff23fSmrg		   (unsigned int)INREG(RADEON_GRPH_BUFFER_CNTL));
1607209ff23fSmrg
1608209ff23fSmrg    if (mode2) {
1609209ff23fSmrg	stop_req = mode2->HDisplay * pixel_bytes2 / 16;
1610209ff23fSmrg
1611209ff23fSmrg	if (stop_req > max_stop_req) stop_req = max_stop_req;
1612209ff23fSmrg
1613209ff23fSmrg	temp = info->SavedReg->grph2_buffer_cntl;
1614209ff23fSmrg	temp &= ~(RADEON_GRPH_STOP_REQ_MASK);
1615209ff23fSmrg	temp |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT);
1616209ff23fSmrg	temp &= ~(RADEON_GRPH_START_REQ_MASK);
1617209ff23fSmrg	if ((info->ChipFamily == CHIP_FAMILY_R350) &&
1618209ff23fSmrg	    (stop_req > 0x15)) {
1619209ff23fSmrg	    stop_req -= 0x10;
1620209ff23fSmrg	}
1621209ff23fSmrg	temp |= (stop_req << RADEON_GRPH_START_REQ_SHIFT);
1622209ff23fSmrg	temp |= RADEON_GRPH_BUFFER_SIZE;
1623209ff23fSmrg	temp &= ~(RADEON_GRPH_CRITICAL_CNTL   |
1624209ff23fSmrg		  RADEON_GRPH_CRITICAL_AT_SOF |
1625209ff23fSmrg		  RADEON_GRPH_STOP_CNTL);
1626209ff23fSmrg
1627209ff23fSmrg	if ((info->ChipFamily == CHIP_FAMILY_RS100) ||
1628209ff23fSmrg	    (info->ChipFamily == CHIP_FAMILY_RS200))
1629209ff23fSmrg	    critical_point2 = 0;
1630209ff23fSmrg	else {
1631209ff23fSmrg	    read_return_rate = MIN(info->sclk, info->mclk*(info->RamWidth*(info->IsDDR+1)/128));
1632209ff23fSmrg	    time_disp1_drop_priority = critical_point / (read_return_rate - disp_drain_rate);
1633209ff23fSmrg
1634209ff23fSmrg	    critical_point2 = (uint32_t)((disp_latency + time_disp1_drop_priority +
1635209ff23fSmrg					disp_latency) * disp_drain_rate2 + 0.5);
1636209ff23fSmrg
1637209ff23fSmrg	    if (info->DispPriority == 2) {
1638209ff23fSmrg		critical_point2 = 0;
1639209ff23fSmrg	    }
1640209ff23fSmrg
1641209ff23fSmrg	    if (max_stop_req - critical_point2 < 4) critical_point2 = 0;
1642209ff23fSmrg
1643209ff23fSmrg	}
1644209ff23fSmrg
1645209ff23fSmrg	if (critical_point2 == 0 && info->ChipFamily == CHIP_FAMILY_R300) {
1646209ff23fSmrg	    /* some R300 cards have problem with this set to 0 */
1647209ff23fSmrg	    critical_point2 = 0x10;
1648209ff23fSmrg	}
1649209ff23fSmrg
1650209ff23fSmrg	OUTREG(RADEON_GRPH2_BUFFER_CNTL, ((temp & ~RADEON_GRPH_CRITICAL_POINT_MASK) |
1651209ff23fSmrg					  (critical_point2 << RADEON_GRPH_CRITICAL_POINT_SHIFT)));
1652209ff23fSmrg
1653209ff23fSmrg	if ((info->ChipFamily == CHIP_FAMILY_RS400) ||
1654209ff23fSmrg	    (info->ChipFamily == CHIP_FAMILY_RS480)) {
1655209ff23fSmrg#if 0
1656209ff23fSmrg	    /* attempt to program RS400 disp2 regs correctly ??? */
1657209ff23fSmrg	    temp = info->SavedReg->disp2_req_cntl1;
1658209ff23fSmrg	    temp &= ~(RS400_DISP2_START_REQ_LEVEL_MASK |
1659209ff23fSmrg		      RS400_DISP2_STOP_REQ_LEVEL_MASK);
1660209ff23fSmrg	    OUTREG(RS400_DISP2_REQ_CNTL1, (temp |
1661209ff23fSmrg					   (critical_point2 << RS400_DISP1_START_REQ_LEVEL_SHIFT) |
1662209ff23fSmrg					   (critical_point2 << RS400_DISP1_STOP_REQ_LEVEL_SHIFT)));
1663209ff23fSmrg	    temp = info->SavedReg->disp2_req_cntl2;
1664209ff23fSmrg	    temp &= ~(RS400_DISP2_CRITICAL_POINT_START_MASK |
1665209ff23fSmrg		      RS400_DISP2_CRITICAL_POINT_STOP_MASK);
1666209ff23fSmrg	    OUTREG(RS400_DISP2_REQ_CNTL2, (temp |
1667209ff23fSmrg					   (critical_point2 << RS400_DISP2_CRITICAL_POINT_START_SHIFT) |
1668209ff23fSmrg					   (critical_point2 << RS400_DISP2_CRITICAL_POINT_STOP_SHIFT)));
1669209ff23fSmrg#endif
1670209ff23fSmrg	    OUTREG(RS400_DISP2_REQ_CNTL1, 0x105DC1CC);
1671209ff23fSmrg	    OUTREG(RS400_DISP2_REQ_CNTL2, 0x2749D000);
1672209ff23fSmrg	    OUTREG(RS400_DMIF_MEM_CNTL1,  0x29CA71DC);
1673209ff23fSmrg	    OUTREG(RS400_DISP1_REQ_CNTL1, 0x28FBC3AC);
1674209ff23fSmrg	}
1675209ff23fSmrg
1676209ff23fSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
1677209ff23fSmrg		       "GRPH2_BUFFER_CNTL from %x to %x\n",
1678209ff23fSmrg		       (unsigned int)info->SavedReg->grph2_buffer_cntl,
1679209ff23fSmrg		       (unsigned int)INREG(RADEON_GRPH2_BUFFER_CNTL));
1680209ff23fSmrg    }
1681209ff23fSmrg}
1682209ff23fSmrg
1683209ff23fSmrgvoid
1684209ff23fSmrgRADEONInitDispBandwidth(ScrnInfoPtr pScrn)
1685209ff23fSmrg{
1686209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
1687209ff23fSmrg    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1688209ff23fSmrg    DisplayModePtr mode1, mode2;
1689209ff23fSmrg    int pixel_bytes2 = 0;
1690209ff23fSmrg
1691209ff23fSmrg    if (info->IsPrimary || info->IsSecondary)
1692209ff23fSmrg	mode1 = &xf86_config->crtc[0]->mode;
1693209ff23fSmrg    else
1694209ff23fSmrg	mode1 = info->CurrentLayout.mode;
1695209ff23fSmrg    mode2 = NULL;
1696209ff23fSmrg    pixel_bytes2 = info->CurrentLayout.pixel_bytes;
1697209ff23fSmrg
1698209ff23fSmrg    if (xf86_config->num_crtc == 2) {
1699209ff23fSmrg      pixel_bytes2 = 0;
1700209ff23fSmrg      mode2 = NULL;
1701209ff23fSmrg
1702209ff23fSmrg      if (xf86_config->crtc[1]->enabled && xf86_config->crtc[0]->enabled) {
1703209ff23fSmrg	pixel_bytes2 = info->CurrentLayout.pixel_bytes;
1704209ff23fSmrg	mode1 = &xf86_config->crtc[0]->mode;
1705209ff23fSmrg	mode2 = &xf86_config->crtc[1]->mode;
1706209ff23fSmrg      } else if (xf86_config->crtc[0]->enabled) {
1707209ff23fSmrg	mode1 = &xf86_config->crtc[0]->mode;
1708209ff23fSmrg      } else if (xf86_config->crtc[1]->enabled) {
1709209ff23fSmrg	mode1 = &xf86_config->crtc[1]->mode;
1710209ff23fSmrg      } else
1711209ff23fSmrg	return;
1712209ff23fSmrg    } else {
1713209ff23fSmrg	if (xf86_config->crtc[0]->enabled)
1714209ff23fSmrg	    mode1 = &xf86_config->crtc[0]->mode;
1715209ff23fSmrg	else
1716209ff23fSmrg	    return;
1717209ff23fSmrg    }
1718209ff23fSmrg
1719209ff23fSmrg    RADEONInitDispBandwidth2(pScrn, info, pixel_bytes2, mode1, mode2);
1720209ff23fSmrg}
1721209ff23fSmrg
1722209ff23fSmrgvoid
1723209ff23fSmrglegacy_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
1724209ff23fSmrg		     DisplayModePtr adjusted_mode, int x, int y)
1725209ff23fSmrg{
1726209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
1727209ff23fSmrg    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1728209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
1729209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
1730209ff23fSmrg    int i = 0;
1731209ff23fSmrg    double dot_clock = 0;
1732209ff23fSmrg    int pll_flags = RADEON_PLL_LEGACY | RADEON_PLL_PREFER_LOW_REF_DIV;
1733209ff23fSmrg    Bool update_tv_routing = FALSE;
1734209ff23fSmrg    Bool tilingChanged = FALSE;
1735209ff23fSmrg
1736209ff23fSmrg    if (info->allowColorTiling) {
1737209ff23fSmrg	radeon_crtc->can_tile = (adjusted_mode->Flags & (V_DBLSCAN | V_INTERLACE)) ? FALSE : TRUE;
1738209ff23fSmrg	tilingChanged = RADEONSetTiling(pScrn);
1739209ff23fSmrg    }
1740209ff23fSmrg
1741209ff23fSmrg    for (i = 0; i < xf86_config->num_output; i++) {
1742209ff23fSmrg	xf86OutputPtr output = xf86_config->output[i];
1743209ff23fSmrg	RADEONOutputPrivatePtr radeon_output = output->driver_private;
1744209ff23fSmrg
1745209ff23fSmrg	if (output->crtc == crtc) {
1746209ff23fSmrg	    if (radeon_output->MonType != MT_CRT)
1747209ff23fSmrg		pll_flags |= RADEON_PLL_NO_ODD_POST_DIV;
1748209ff23fSmrg	    if (radeon_output->MonType == MT_LCD)
1749209ff23fSmrg		pll_flags |= (RADEON_PLL_USE_BIOS_DIVS | RADEON_PLL_USE_REF_DIV);
1750209ff23fSmrg	}
1751209ff23fSmrg    }
1752209ff23fSmrg
1753209ff23fSmrg
1754209ff23fSmrg    ErrorF("init memmap\n");
1755209ff23fSmrg    RADEONInitMemMapRegisters(pScrn, info->ModeReg, info);
1756209ff23fSmrg    ErrorF("init common\n");
1757209ff23fSmrg    RADEONInitCommonRegisters(info->ModeReg, info);
1758209ff23fSmrg
1759209ff23fSmrg    RADEONInitSurfaceCntl(crtc, info->ModeReg);
1760209ff23fSmrg
1761209ff23fSmrg    switch (radeon_crtc->crtc_id) {
1762209ff23fSmrg    case 0:
1763209ff23fSmrg	ErrorF("init crtc1\n");
1764209ff23fSmrg	RADEONInitCrtcRegisters(crtc, info->ModeReg, adjusted_mode);
1765209ff23fSmrg	RADEONInitCrtcBase(crtc, info->ModeReg, x, y);
1766209ff23fSmrg	dot_clock = adjusted_mode->Clock / 1000.0;
1767209ff23fSmrg	if (dot_clock) {
1768209ff23fSmrg	    ErrorF("init pll1\n");
1769209ff23fSmrg	    RADEONInitPLLRegisters(pScrn, info->ModeReg, &info->pll, adjusted_mode, pll_flags);
1770209ff23fSmrg	} else {
1771209ff23fSmrg	    info->ModeReg->ppll_ref_div = info->SavedReg->ppll_ref_div;
1772209ff23fSmrg	    info->ModeReg->ppll_div_3   = info->SavedReg->ppll_div_3;
1773209ff23fSmrg	    info->ModeReg->htotal_cntl  = info->SavedReg->htotal_cntl;
1774209ff23fSmrg	}
1775209ff23fSmrg	break;
1776209ff23fSmrg    case 1:
1777209ff23fSmrg	ErrorF("init crtc2\n");
1778209ff23fSmrg	RADEONInitCrtc2Registers(crtc, info->ModeReg, adjusted_mode);
1779209ff23fSmrg	RADEONInitCrtc2Base(crtc, info->ModeReg, x, y);
1780209ff23fSmrg	dot_clock = adjusted_mode->Clock / 1000.0;
1781209ff23fSmrg	if (dot_clock) {
1782209ff23fSmrg	    ErrorF("init pll2\n");
1783209ff23fSmrg	    RADEONInitPLL2Registers(pScrn, info->ModeReg, &info->pll, adjusted_mode, pll_flags);
1784209ff23fSmrg	}
1785209ff23fSmrg	break;
1786209ff23fSmrg    }
1787209ff23fSmrg
1788209ff23fSmrg    for (i = 0; i < xf86_config->num_output; i++) {
1789209ff23fSmrg	xf86OutputPtr output = xf86_config->output[i];
1790209ff23fSmrg	RADEONOutputPrivatePtr radeon_output = output->driver_private;
1791209ff23fSmrg
1792209ff23fSmrg	if (output->crtc == crtc) {
1793209ff23fSmrg	    if (radeon_output->MonType == MT_STV || radeon_output->MonType == MT_CTV) {
1794209ff23fSmrg		switch (radeon_crtc->crtc_id) {
1795209ff23fSmrg		case 0:
1796209ff23fSmrg		    RADEONAdjustCrtcRegistersForTV(pScrn, info->ModeReg, adjusted_mode, output);
1797209ff23fSmrg		    RADEONAdjustPLLRegistersForTV(pScrn, info->ModeReg, adjusted_mode, output);
1798209ff23fSmrg		    update_tv_routing = TRUE;
1799209ff23fSmrg		    break;
1800209ff23fSmrg		case 1:
1801209ff23fSmrg		    RADEONAdjustCrtc2RegistersForTV(pScrn, info->ModeReg, adjusted_mode, output);
1802209ff23fSmrg		    RADEONAdjustPLL2RegistersForTV(pScrn, info->ModeReg, adjusted_mode, output);
1803209ff23fSmrg		    break;
1804209ff23fSmrg		}
1805209ff23fSmrg	    }
1806209ff23fSmrg	}
1807209ff23fSmrg    }
1808209ff23fSmrg
1809209ff23fSmrg    ErrorF("restore memmap\n");
1810209ff23fSmrg    RADEONRestoreMemMapRegisters(pScrn, info->ModeReg);
1811209ff23fSmrg    ErrorF("restore common\n");
1812209ff23fSmrg    RADEONRestoreCommonRegisters(pScrn, info->ModeReg);
1813209ff23fSmrg
1814209ff23fSmrg    switch (radeon_crtc->crtc_id) {
1815209ff23fSmrg    case 0:
1816209ff23fSmrg	ErrorF("restore crtc1\n");
1817209ff23fSmrg	RADEONRestoreCrtcRegisters(pScrn, info->ModeReg);
1818209ff23fSmrg	ErrorF("restore pll1\n");
1819209ff23fSmrg	RADEONRestorePLLRegisters(pScrn, info->ModeReg);
1820209ff23fSmrg	break;
1821209ff23fSmrg    case 1:
1822209ff23fSmrg	ErrorF("restore crtc2\n");
1823209ff23fSmrg	RADEONRestoreCrtc2Registers(pScrn, info->ModeReg);
1824209ff23fSmrg	ErrorF("restore pll2\n");
1825209ff23fSmrg	RADEONRestorePLL2Registers(pScrn, info->ModeReg);
1826209ff23fSmrg	break;
1827209ff23fSmrg    }
1828209ff23fSmrg
1829209ff23fSmrg    /* pixclks_cntl handles tv-out clock routing */
1830209ff23fSmrg    if (update_tv_routing)
1831209ff23fSmrg	radeon_update_tv_routing(pScrn, info->ModeReg);
1832209ff23fSmrg
1833209ff23fSmrg    if (info->DispPriority)
1834209ff23fSmrg        RADEONInitDispBandwidth(pScrn);
1835209ff23fSmrg
1836209ff23fSmrg    if (tilingChanged) {
1837209ff23fSmrg	/* need to redraw front buffer, I guess this can be considered a hack ? */
1838209ff23fSmrg	/* if this is called during ScreenInit() we don't have pScrn->pScreen yet */
1839209ff23fSmrg	if (pScrn->pScreen)
1840209ff23fSmrg	    xf86EnableDisableFBAccess(pScrn->scrnIndex, FALSE);
1841209ff23fSmrg	RADEONChangeSurfaces(pScrn);
1842209ff23fSmrg	if (pScrn->pScreen)
1843209ff23fSmrg	    xf86EnableDisableFBAccess(pScrn->scrnIndex, TRUE);
1844209ff23fSmrg	/* xf86SetRootClip would do, but can't access that here */
1845209ff23fSmrg    }
1846209ff23fSmrg
1847209ff23fSmrg    /* reset ecp_div for Xv */
1848209ff23fSmrg    info->ecp_div = -1;
1849209ff23fSmrg
1850209ff23fSmrg}
1851209ff23fSmrg
1852