legacy_crtc.c revision f1bc02b7
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"
48b7e1c893Smrg#include "radeon_atombios.h"
49209ff23fSmrg
50209ff23fSmrg#ifdef XF86DRI
51209ff23fSmrg#define _XF86DRI_SERVER_
52b7e1c893Smrg#include "radeon_drm.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
107b7e1c893Smrgvoid
108b7e1c893SmrgRADEONRestoreCrtcBase(ScrnInfoPtr pScrn,
109b7e1c893Smrg		      RADEONSavePtr restore)
110b7e1c893Smrg{
111b7e1c893Smrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
112b7e1c893Smrg    unsigned char *RADEONMMIO = info->MMIO;
113b7e1c893Smrg
114b7e1c893Smrg    if (IS_R300_VARIANT)
115b7e1c893Smrg	OUTREG(R300_CRTC_TILE_X0_Y0,    restore->crtc_tile_x0_y0);
116b7e1c893Smrg    OUTREG(RADEON_CRTC_OFFSET_CNTL,     restore->crtc_offset_cntl);
117b7e1c893Smrg    OUTREG(RADEON_CRTC_OFFSET,          restore->crtc_offset);
118b7e1c893Smrg}
119b7e1c893Smrg
120b7e1c893Smrgvoid
121b7e1c893SmrgRADEONRestoreCrtc2Base(ScrnInfoPtr pScrn,
122b7e1c893Smrg		       RADEONSavePtr restore)
123b7e1c893Smrg{
124b7e1c893Smrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
125b7e1c893Smrg    unsigned char *RADEONMMIO = info->MMIO;
126b7e1c893Smrg
127b7e1c893Smrg    if (IS_R300_VARIANT)
128b7e1c893Smrg	OUTREG(R300_CRTC2_TILE_X0_Y0,    restore->crtc2_tile_x0_y0);
129b7e1c893Smrg    OUTREG(RADEON_CRTC2_OFFSET_CNTL,     restore->crtc2_offset_cntl);
130b7e1c893Smrg    OUTREG(RADEON_CRTC2_OFFSET,          restore->crtc2_offset);
131b7e1c893Smrg}
132209ff23fSmrg
133209ff23fSmrg/* Write CRTC registers */
134209ff23fSmrgvoid
135209ff23fSmrgRADEONRestoreCrtcRegisters(ScrnInfoPtr pScrn,
136209ff23fSmrg			   RADEONSavePtr restore)
137209ff23fSmrg{
138209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
139209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
140209ff23fSmrg
141209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
142209ff23fSmrg		   "Programming CRTC1, offset: 0x%08x\n",
143209ff23fSmrg		   (unsigned)restore->crtc_offset);
144209ff23fSmrg
145209ff23fSmrg    /* We prevent the CRTC from hitting the memory controller until
146209ff23fSmrg     * fully programmed
147209ff23fSmrg     */
148209ff23fSmrg    OUTREG(RADEON_CRTC_GEN_CNTL, restore->crtc_gen_cntl |
149209ff23fSmrg	   RADEON_CRTC_DISP_REQ_EN_B);
150209ff23fSmrg
151209ff23fSmrg    OUTREGP(RADEON_CRTC_EXT_CNTL,
152209ff23fSmrg	    restore->crtc_ext_cntl,
153209ff23fSmrg	    RADEON_CRTC_VSYNC_DIS |
154209ff23fSmrg	    RADEON_CRTC_HSYNC_DIS |
155209ff23fSmrg	    RADEON_CRTC_DISPLAY_DIS);
156209ff23fSmrg
157209ff23fSmrg    OUTREG(RADEON_CRTC_H_TOTAL_DISP,    restore->crtc_h_total_disp);
158209ff23fSmrg    OUTREG(RADEON_CRTC_H_SYNC_STRT_WID, restore->crtc_h_sync_strt_wid);
159209ff23fSmrg    OUTREG(RADEON_CRTC_V_TOTAL_DISP,    restore->crtc_v_total_disp);
160209ff23fSmrg    OUTREG(RADEON_CRTC_V_SYNC_STRT_WID, restore->crtc_v_sync_strt_wid);
161209ff23fSmrg
162b7e1c893Smrg    RADEONRestoreCrtcBase(pScrn, restore);
163209ff23fSmrg
164209ff23fSmrg    OUTREG(RADEON_CRTC_PITCH,           restore->crtc_pitch);
165209ff23fSmrg    OUTREG(RADEON_DISP_MERGE_CNTL,      restore->disp_merge_cntl);
166209ff23fSmrg
167209ff23fSmrg    if (info->IsDellServer) {
168209ff23fSmrg	OUTREG(RADEON_TV_DAC_CNTL, restore->tv_dac_cntl);
169209ff23fSmrg	OUTREG(RADEON_DISP_HW_DEBUG, restore->disp_hw_debug);
170209ff23fSmrg	OUTREG(RADEON_DAC_CNTL2, restore->dac2_cntl);
171209ff23fSmrg	OUTREG(RADEON_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl);
172209ff23fSmrg    }
173209ff23fSmrg
174209ff23fSmrg    OUTREG(RADEON_CRTC_GEN_CNTL, restore->crtc_gen_cntl);
175209ff23fSmrg}
176209ff23fSmrg
177209ff23fSmrg/* Write CRTC2 registers */
178209ff23fSmrgvoid
179209ff23fSmrgRADEONRestoreCrtc2Registers(ScrnInfoPtr pScrn,
180209ff23fSmrg			    RADEONSavePtr restore)
181209ff23fSmrg{
182209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
183209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
184209ff23fSmrg    /*    uint32_t	   crtc2_gen_cntl;*/
185209ff23fSmrg
186209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
187209ff23fSmrg		   "Programming CRTC2, offset: 0x%08x\n",
188209ff23fSmrg		   (unsigned)restore->crtc2_offset);
189209ff23fSmrg
190209ff23fSmrg    /* We prevent the CRTC from hitting the memory controller until
191209ff23fSmrg     * fully programmed
192209ff23fSmrg     */
193209ff23fSmrg    OUTREG(RADEON_CRTC2_GEN_CNTL,
194209ff23fSmrg	   restore->crtc2_gen_cntl | RADEON_CRTC2_VSYNC_DIS |
195209ff23fSmrg	   RADEON_CRTC2_HSYNC_DIS | RADEON_CRTC2_DISP_DIS |
196209ff23fSmrg	   RADEON_CRTC2_DISP_REQ_EN_B);
197209ff23fSmrg
198209ff23fSmrg    OUTREG(RADEON_CRTC2_H_TOTAL_DISP,    restore->crtc2_h_total_disp);
199209ff23fSmrg    OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, restore->crtc2_h_sync_strt_wid);
200209ff23fSmrg    OUTREG(RADEON_CRTC2_V_TOTAL_DISP,    restore->crtc2_v_total_disp);
201209ff23fSmrg    OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, restore->crtc2_v_sync_strt_wid);
202209ff23fSmrg
203209ff23fSmrg    OUTREG(RADEON_FP_H2_SYNC_STRT_WID,   restore->fp_h2_sync_strt_wid);
204209ff23fSmrg    OUTREG(RADEON_FP_V2_SYNC_STRT_WID,   restore->fp_v2_sync_strt_wid);
205209ff23fSmrg
206b7e1c893Smrg    RADEONRestoreCrtc2Base(pScrn, restore);
207209ff23fSmrg
208209ff23fSmrg    OUTREG(RADEON_CRTC2_PITCH,           restore->crtc2_pitch);
209209ff23fSmrg    OUTREG(RADEON_DISP2_MERGE_CNTL,      restore->disp2_merge_cntl);
210209ff23fSmrg
211209ff23fSmrg    OUTREG(RADEON_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl);
212209ff23fSmrg
213209ff23fSmrg}
214209ff23fSmrg
215209ff23fSmrgstatic void
216209ff23fSmrgRADEONPLLWaitForReadUpdateComplete(ScrnInfoPtr pScrn)
217209ff23fSmrg{
218209ff23fSmrg    int i = 0;
219209ff23fSmrg
220209ff23fSmrg    /* FIXME: Certain revisions of R300 can't recover here.  Not sure of
221209ff23fSmrg       the cause yet, but this workaround will mask the problem for now.
222209ff23fSmrg       Other chips usually will pass at the very first test, so the
223209ff23fSmrg       workaround shouldn't have any effect on them. */
224209ff23fSmrg    for (i = 0;
225209ff23fSmrg	 (i < 10000 &&
226209ff23fSmrg	  INPLL(pScrn, RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R);
227209ff23fSmrg	 i++);
228209ff23fSmrg}
229209ff23fSmrg
230209ff23fSmrgstatic void
231209ff23fSmrgRADEONPLLWriteUpdate(ScrnInfoPtr pScrn)
232209ff23fSmrg{
233209ff23fSmrg    while (INPLL(pScrn, RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R);
234209ff23fSmrg
235209ff23fSmrg    OUTPLLP(pScrn, RADEON_PPLL_REF_DIV,
236209ff23fSmrg	    RADEON_PPLL_ATOMIC_UPDATE_W,
237209ff23fSmrg	    ~(RADEON_PPLL_ATOMIC_UPDATE_W));
238209ff23fSmrg}
239209ff23fSmrg
240209ff23fSmrgstatic void
241209ff23fSmrgRADEONPLL2WaitForReadUpdateComplete(ScrnInfoPtr pScrn)
242209ff23fSmrg{
243209ff23fSmrg    int i = 0;
244209ff23fSmrg
245209ff23fSmrg    /* FIXME: Certain revisions of R300 can't recover here.  Not sure of
246209ff23fSmrg       the cause yet, but this workaround will mask the problem for now.
247209ff23fSmrg       Other chips usually will pass at the very first test, so the
248209ff23fSmrg       workaround shouldn't have any effect on them. */
249209ff23fSmrg    for (i = 0;
250209ff23fSmrg	 (i < 10000 &&
251209ff23fSmrg	  INPLL(pScrn, RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R);
252209ff23fSmrg	 i++);
253209ff23fSmrg}
254209ff23fSmrg
255209ff23fSmrgstatic void
256209ff23fSmrgRADEONPLL2WriteUpdate(ScrnInfoPtr pScrn)
257209ff23fSmrg{
258209ff23fSmrg    while (INPLL(pScrn, RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R);
259209ff23fSmrg
260209ff23fSmrg    OUTPLLP(pScrn, RADEON_P2PLL_REF_DIV,
261209ff23fSmrg	    RADEON_P2PLL_ATOMIC_UPDATE_W,
262209ff23fSmrg	    ~(RADEON_P2PLL_ATOMIC_UPDATE_W));
263209ff23fSmrg}
264209ff23fSmrg
265209ff23fSmrgstatic uint8_t
266209ff23fSmrgRADEONComputePLLGain(uint16_t reference_freq, uint16_t ref_div,
267209ff23fSmrg		     uint16_t fb_div)
268209ff23fSmrg{
269209ff23fSmrg    unsigned vcoFreq;
270209ff23fSmrg
271209ff23fSmrg    if (!ref_div)
272209ff23fSmrg	return 1;
273209ff23fSmrg
274209ff23fSmrg    vcoFreq = ((unsigned)reference_freq * fb_div) / ref_div;
275209ff23fSmrg
276209ff23fSmrg    /*
277209ff23fSmrg     * This is horribly crude: the VCO frequency range is divided into
278209ff23fSmrg     * 3 parts, each part having a fixed PLL gain value.
279209ff23fSmrg     */
280209ff23fSmrg    if (vcoFreq >= 30000)
281209ff23fSmrg	/*
282209ff23fSmrg	 * [300..max] MHz : 7
283209ff23fSmrg	 */
284209ff23fSmrg	return 7;
285209ff23fSmrg    else if (vcoFreq >= 18000)
286209ff23fSmrg	/*
287209ff23fSmrg	 * [180..300) MHz : 4
288209ff23fSmrg	 */
289209ff23fSmrg        return 4;
290209ff23fSmrg    else
291209ff23fSmrg	/*
292209ff23fSmrg	 * [0..180) MHz : 1
293209ff23fSmrg	 */
294209ff23fSmrg        return 1;
295209ff23fSmrg}
296209ff23fSmrg
297209ff23fSmrg/* Write PLL registers */
298209ff23fSmrgvoid
299209ff23fSmrgRADEONRestorePLLRegisters(ScrnInfoPtr pScrn,
300209ff23fSmrg			  RADEONSavePtr restore)
301209ff23fSmrg{
302209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
303209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
304209ff23fSmrg    uint8_t pllGain;
305209ff23fSmrg
306209ff23fSmrg#if defined(__powerpc__)
307209ff23fSmrg    /* apparently restoring the pll causes a hang??? */
3081764dec5Smacallan    if ((info->MacModel == RADEON_MAC_IBOOK) ||
3091764dec5Smacallan        (info->MacModel == RADEON_MAC_MINI_INTERNAL))
310209ff23fSmrg	return;
311209ff23fSmrg#endif
312209ff23fSmrg
313209ff23fSmrg    pllGain = RADEONComputePLLGain(info->pll.reference_freq,
314209ff23fSmrg				   restore->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK,
315209ff23fSmrg				   restore->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK);
316209ff23fSmrg
317209ff23fSmrg    if (info->IsMobility) {
318209ff23fSmrg        /* A temporal workaround for the occational blanking on certain laptop panels.
319209ff23fSmrg           This appears to related to the PLL divider registers (fail to lock?).
320209ff23fSmrg	   It occurs even when all dividers are the same with their old settings.
321209ff23fSmrg           In this case we really don't need to fiddle with PLL registers.
322209ff23fSmrg           By doing this we can avoid the blanking problem with some panels.
323209ff23fSmrg        */
324209ff23fSmrg        if ((restore->ppll_ref_div == (INPLL(pScrn, RADEON_PPLL_REF_DIV) & RADEON_PPLL_REF_DIV_MASK)) &&
325209ff23fSmrg	    (restore->ppll_div_3 == (INPLL(pScrn, RADEON_PPLL_DIV_3) &
326209ff23fSmrg				     (RADEON_PPLL_POST3_DIV_MASK | RADEON_PPLL_FB3_DIV_MASK)))) {
327209ff23fSmrg	    OUTREGP(RADEON_CLOCK_CNTL_INDEX,
328209ff23fSmrg		    RADEON_PLL_DIV_SEL,
329209ff23fSmrg		    ~(RADEON_PLL_DIV_SEL));
330209ff23fSmrg	    RADEONPllErrataAfterIndex(info);
331209ff23fSmrg	    return;
332209ff23fSmrg	}
333209ff23fSmrg    }
334209ff23fSmrg
335209ff23fSmrg    OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL,
336209ff23fSmrg	    RADEON_VCLK_SRC_SEL_CPUCLK,
337209ff23fSmrg	    ~(RADEON_VCLK_SRC_SEL_MASK));
338209ff23fSmrg
339209ff23fSmrg    OUTPLLP(pScrn,
340209ff23fSmrg	    RADEON_PPLL_CNTL,
341209ff23fSmrg	    RADEON_PPLL_RESET
342209ff23fSmrg	    | RADEON_PPLL_ATOMIC_UPDATE_EN
343209ff23fSmrg	    | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN
344209ff23fSmrg	    | ((uint32_t)pllGain << RADEON_PPLL_PVG_SHIFT),
345209ff23fSmrg	    ~(RADEON_PPLL_RESET
346209ff23fSmrg	      | RADEON_PPLL_ATOMIC_UPDATE_EN
347209ff23fSmrg	      | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN
348209ff23fSmrg	      | RADEON_PPLL_PVG_MASK));
349209ff23fSmrg
350209ff23fSmrg    OUTREGP(RADEON_CLOCK_CNTL_INDEX,
351209ff23fSmrg	    RADEON_PLL_DIV_SEL,
352209ff23fSmrg	    ~(RADEON_PLL_DIV_SEL));
353209ff23fSmrg    RADEONPllErrataAfterIndex(info);
354209ff23fSmrg
355209ff23fSmrg    if (IS_R300_VARIANT ||
356209ff23fSmrg	(info->ChipFamily == CHIP_FAMILY_RS300) ||
357209ff23fSmrg	(info->ChipFamily == CHIP_FAMILY_RS400) ||
358209ff23fSmrg	(info->ChipFamily == CHIP_FAMILY_RS480)) {
359209ff23fSmrg	if (restore->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {
360209ff23fSmrg	    /* When restoring console mode, use saved PPLL_REF_DIV
361209ff23fSmrg	     * setting.
362209ff23fSmrg	     */
363209ff23fSmrg	    OUTPLLP(pScrn, RADEON_PPLL_REF_DIV,
364209ff23fSmrg		    restore->ppll_ref_div,
365209ff23fSmrg		    0);
366209ff23fSmrg	} else {
367209ff23fSmrg	    /* R300 uses ref_div_acc field as real ref divider */
368209ff23fSmrg	    OUTPLLP(pScrn, RADEON_PPLL_REF_DIV,
369209ff23fSmrg		    (restore->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT),
370209ff23fSmrg		    ~R300_PPLL_REF_DIV_ACC_MASK);
371209ff23fSmrg	}
372209ff23fSmrg    } else {
373209ff23fSmrg	OUTPLLP(pScrn, RADEON_PPLL_REF_DIV,
374209ff23fSmrg		restore->ppll_ref_div,
375209ff23fSmrg		~RADEON_PPLL_REF_DIV_MASK);
376209ff23fSmrg    }
377209ff23fSmrg
378209ff23fSmrg    OUTPLLP(pScrn, RADEON_PPLL_DIV_3,
379209ff23fSmrg	    restore->ppll_div_3,
380209ff23fSmrg	    ~RADEON_PPLL_FB3_DIV_MASK);
381209ff23fSmrg
382209ff23fSmrg    OUTPLLP(pScrn, RADEON_PPLL_DIV_3,
383209ff23fSmrg	    restore->ppll_div_3,
384209ff23fSmrg	    ~RADEON_PPLL_POST3_DIV_MASK);
385209ff23fSmrg
386209ff23fSmrg    RADEONPLLWriteUpdate(pScrn);
387209ff23fSmrg    RADEONPLLWaitForReadUpdateComplete(pScrn);
388209ff23fSmrg
389209ff23fSmrg    OUTPLL(pScrn, RADEON_HTOTAL_CNTL, restore->htotal_cntl);
390209ff23fSmrg
391209ff23fSmrg    OUTPLLP(pScrn, RADEON_PPLL_CNTL,
392209ff23fSmrg	    0,
393209ff23fSmrg	    ~(RADEON_PPLL_RESET
394209ff23fSmrg	      | RADEON_PPLL_SLEEP
395209ff23fSmrg	      | RADEON_PPLL_ATOMIC_UPDATE_EN
396209ff23fSmrg	      | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN));
397209ff23fSmrg
398209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
399209ff23fSmrg		   "Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
400209ff23fSmrg		   restore->ppll_ref_div,
401209ff23fSmrg		   restore->ppll_div_3,
402209ff23fSmrg		   (unsigned)restore->htotal_cntl,
403209ff23fSmrg		   INPLL(pScrn, RADEON_PPLL_CNTL));
404209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
405209ff23fSmrg		   "Wrote: rd=%d, fd=%d, pd=%d\n",
406209ff23fSmrg		   restore->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK,
407209ff23fSmrg		   restore->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK,
408209ff23fSmrg		   (restore->ppll_div_3 & RADEON_PPLL_POST3_DIV_MASK) >> 16);
409209ff23fSmrg
410209ff23fSmrg    usleep(50000); /* Let the clock to lock */
411209ff23fSmrg
412209ff23fSmrg    OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL,
413209ff23fSmrg	    RADEON_VCLK_SRC_SEL_PPLLCLK,
414209ff23fSmrg	    ~(RADEON_VCLK_SRC_SEL_MASK));
415209ff23fSmrg
416209ff23fSmrg    /*OUTPLL(pScrn, RADEON_VCLK_ECP_CNTL, restore->vclk_ecp_cntl);*/
417209ff23fSmrg
418209ff23fSmrg    ErrorF("finished PLL1\n");
419209ff23fSmrg
420209ff23fSmrg}
421209ff23fSmrg
422209ff23fSmrg/* Write PLL2 registers */
423209ff23fSmrgvoid
424209ff23fSmrgRADEONRestorePLL2Registers(ScrnInfoPtr pScrn,
425209ff23fSmrg			   RADEONSavePtr restore)
426209ff23fSmrg{
427209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
428209ff23fSmrg    uint8_t pllGain;
429209ff23fSmrg
430209ff23fSmrg    pllGain = RADEONComputePLLGain(info->pll.reference_freq,
431209ff23fSmrg                                   restore->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK,
432209ff23fSmrg                                   restore->p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK);
433209ff23fSmrg
434209ff23fSmrg
435209ff23fSmrg    OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL,
436209ff23fSmrg	    RADEON_PIX2CLK_SRC_SEL_CPUCLK,
437209ff23fSmrg	    ~(RADEON_PIX2CLK_SRC_SEL_MASK));
438209ff23fSmrg
439209ff23fSmrg    OUTPLLP(pScrn,
440209ff23fSmrg	    RADEON_P2PLL_CNTL,
441209ff23fSmrg	    RADEON_P2PLL_RESET
442209ff23fSmrg	    | RADEON_P2PLL_ATOMIC_UPDATE_EN
443209ff23fSmrg	    | ((uint32_t)pllGain << RADEON_P2PLL_PVG_SHIFT),
444209ff23fSmrg	    ~(RADEON_P2PLL_RESET
445209ff23fSmrg	      | RADEON_P2PLL_ATOMIC_UPDATE_EN
446209ff23fSmrg	      | RADEON_P2PLL_PVG_MASK));
447209ff23fSmrg
448209ff23fSmrg
449209ff23fSmrg    OUTPLLP(pScrn, RADEON_P2PLL_REF_DIV,
450209ff23fSmrg	    restore->p2pll_ref_div,
451209ff23fSmrg	    ~RADEON_P2PLL_REF_DIV_MASK);
452209ff23fSmrg
453209ff23fSmrg    OUTPLLP(pScrn, RADEON_P2PLL_DIV_0,
454209ff23fSmrg	    restore->p2pll_div_0,
455209ff23fSmrg	    ~RADEON_P2PLL_FB0_DIV_MASK);
456209ff23fSmrg
457209ff23fSmrg    OUTPLLP(pScrn, RADEON_P2PLL_DIV_0,
458209ff23fSmrg	    restore->p2pll_div_0,
459209ff23fSmrg	    ~RADEON_P2PLL_POST0_DIV_MASK);
460209ff23fSmrg
461209ff23fSmrg    RADEONPLL2WriteUpdate(pScrn);
462209ff23fSmrg    RADEONPLL2WaitForReadUpdateComplete(pScrn);
463209ff23fSmrg
464209ff23fSmrg    OUTPLL(pScrn, RADEON_HTOTAL2_CNTL, restore->htotal_cntl2);
465209ff23fSmrg
466209ff23fSmrg    OUTPLLP(pScrn, RADEON_P2PLL_CNTL,
467209ff23fSmrg	    0,
468209ff23fSmrg	    ~(RADEON_P2PLL_RESET
469209ff23fSmrg	      | RADEON_P2PLL_SLEEP
470209ff23fSmrg	      | RADEON_P2PLL_ATOMIC_UPDATE_EN));
471209ff23fSmrg
472209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
473209ff23fSmrg		   "Wrote2: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
474209ff23fSmrg		   (unsigned)restore->p2pll_ref_div,
475209ff23fSmrg		   (unsigned)restore->p2pll_div_0,
476209ff23fSmrg		   (unsigned)restore->htotal_cntl2,
477209ff23fSmrg		   INPLL(pScrn, RADEON_P2PLL_CNTL));
478209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
479209ff23fSmrg		   "Wrote2: rd=%u, fd=%u, pd=%u\n",
480209ff23fSmrg		   (unsigned)restore->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK,
481209ff23fSmrg		   (unsigned)restore->p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK,
482209ff23fSmrg		   (unsigned)((restore->p2pll_div_0 &
483209ff23fSmrg			       RADEON_P2PLL_POST0_DIV_MASK) >>16));
484209ff23fSmrg
485209ff23fSmrg    usleep(5000); /* Let the clock to lock */
486209ff23fSmrg
487209ff23fSmrg    OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL,
488209ff23fSmrg	    RADEON_PIX2CLK_SRC_SEL_P2PLLCLK,
489209ff23fSmrg	    ~(RADEON_PIX2CLK_SRC_SEL_MASK));
490209ff23fSmrg
491209ff23fSmrg    OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, restore->pixclks_cntl);
492209ff23fSmrg
493209ff23fSmrg    ErrorF("finished PLL2\n");
494209ff23fSmrg
495209ff23fSmrg}
496209ff23fSmrg
497209ff23fSmrg/* Read common registers */
498209ff23fSmrgvoid
499209ff23fSmrgRADEONSaveCommonRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save)
500209ff23fSmrg{
501209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
502209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
503209ff23fSmrg
504209ff23fSmrg    save->ovr_clr            = INREG(RADEON_OVR_CLR);
505209ff23fSmrg    save->ovr_wid_left_right = INREG(RADEON_OVR_WID_LEFT_RIGHT);
506209ff23fSmrg    save->ovr_wid_top_bottom = INREG(RADEON_OVR_WID_TOP_BOTTOM);
507209ff23fSmrg    save->ov0_scale_cntl     = INREG(RADEON_OV0_SCALE_CNTL);
508209ff23fSmrg    save->subpic_cntl        = INREG(RADEON_SUBPIC_CNTL);
509209ff23fSmrg    save->viph_control       = INREG(RADEON_VIPH_CONTROL);
510209ff23fSmrg    save->i2c_cntl_1         = INREG(RADEON_I2C_CNTL_1);
511209ff23fSmrg    save->gen_int_cntl       = INREG(RADEON_GEN_INT_CNTL);
512209ff23fSmrg    save->cap0_trig_cntl     = INREG(RADEON_CAP0_TRIG_CNTL);
513209ff23fSmrg    save->cap1_trig_cntl     = INREG(RADEON_CAP1_TRIG_CNTL);
514209ff23fSmrg    save->bus_cntl           = INREG(RADEON_BUS_CNTL);
515209ff23fSmrg    save->surface_cntl	     = INREG(RADEON_SURFACE_CNTL);
516209ff23fSmrg    save->grph_buffer_cntl   = INREG(RADEON_GRPH_BUFFER_CNTL);
517209ff23fSmrg    save->grph2_buffer_cntl  = INREG(RADEON_GRPH2_BUFFER_CNTL);
518209ff23fSmrg
519209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_RS400) ||
520209ff23fSmrg	(info->ChipFamily == CHIP_FAMILY_RS480)) {
521209ff23fSmrg	save->disp2_req_cntl1 = INREG(RS400_DISP2_REQ_CNTL1);
522209ff23fSmrg	save->disp2_req_cntl2 = INREG(RS400_DISP2_REQ_CNTL2);
523209ff23fSmrg	save->dmif_mem_cntl1  = INREG(RS400_DMIF_MEM_CNTL1);
524209ff23fSmrg	save->disp1_req_cntl1 = INREG(RS400_DISP1_REQ_CNTL1);
525209ff23fSmrg    }
526209ff23fSmrg}
527209ff23fSmrg
528209ff23fSmrg/* Read CRTC registers */
529209ff23fSmrgvoid
530209ff23fSmrgRADEONSaveCrtcRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save)
531209ff23fSmrg{
532209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
533209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
534209ff23fSmrg
535209ff23fSmrg    save->crtc_gen_cntl        = INREG(RADEON_CRTC_GEN_CNTL);
536209ff23fSmrg    save->crtc_ext_cntl        = INREG(RADEON_CRTC_EXT_CNTL);
537209ff23fSmrg    save->crtc_h_total_disp    = INREG(RADEON_CRTC_H_TOTAL_DISP);
538209ff23fSmrg    save->crtc_h_sync_strt_wid = INREG(RADEON_CRTC_H_SYNC_STRT_WID);
539209ff23fSmrg    save->crtc_v_total_disp    = INREG(RADEON_CRTC_V_TOTAL_DISP);
540209ff23fSmrg    save->crtc_v_sync_strt_wid = INREG(RADEON_CRTC_V_SYNC_STRT_WID);
541209ff23fSmrg
542209ff23fSmrg    save->crtc_offset          = INREG(RADEON_CRTC_OFFSET);
543209ff23fSmrg    save->crtc_offset_cntl     = INREG(RADEON_CRTC_OFFSET_CNTL);
544209ff23fSmrg    save->crtc_pitch           = INREG(RADEON_CRTC_PITCH);
545209ff23fSmrg    save->disp_merge_cntl      = INREG(RADEON_DISP_MERGE_CNTL);
546209ff23fSmrg
547209ff23fSmrg    if (IS_R300_VARIANT)
548209ff23fSmrg	save->crtc_tile_x0_y0 =  INREG(R300_CRTC_TILE_X0_Y0);
549209ff23fSmrg
550209ff23fSmrg    if (info->IsDellServer) {
551209ff23fSmrg	save->tv_dac_cntl      = INREG(RADEON_TV_DAC_CNTL);
552209ff23fSmrg	save->dac2_cntl        = INREG(RADEON_DAC_CNTL2);
553209ff23fSmrg	save->disp_hw_debug    = INREG (RADEON_DISP_HW_DEBUG);
554209ff23fSmrg	save->crtc2_gen_cntl   = INREG(RADEON_CRTC2_GEN_CNTL);
555209ff23fSmrg    }
556209ff23fSmrg
557209ff23fSmrg    /* track if the crtc is enabled for text restore */
558209ff23fSmrg    if (save->crtc_ext_cntl & RADEON_CRTC_DISPLAY_DIS)
559209ff23fSmrg	info->crtc_on = FALSE;
560209ff23fSmrg    else
561209ff23fSmrg	info->crtc_on = TRUE;
562209ff23fSmrg
563209ff23fSmrg}
564209ff23fSmrg
565209ff23fSmrg/* Read CRTC2 registers */
566209ff23fSmrgvoid
567209ff23fSmrgRADEONSaveCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save)
568209ff23fSmrg{
569209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
570209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
571209ff23fSmrg
572209ff23fSmrg    save->crtc2_gen_cntl        = INREG(RADEON_CRTC2_GEN_CNTL);
573209ff23fSmrg    save->crtc2_h_total_disp    = INREG(RADEON_CRTC2_H_TOTAL_DISP);
574209ff23fSmrg    save->crtc2_h_sync_strt_wid = INREG(RADEON_CRTC2_H_SYNC_STRT_WID);
575209ff23fSmrg    save->crtc2_v_total_disp    = INREG(RADEON_CRTC2_V_TOTAL_DISP);
576209ff23fSmrg    save->crtc2_v_sync_strt_wid = INREG(RADEON_CRTC2_V_SYNC_STRT_WID);
577b7e1c893Smrg
578209ff23fSmrg    save->crtc2_offset          = INREG(RADEON_CRTC2_OFFSET);
579209ff23fSmrg    save->crtc2_offset_cntl     = INREG(RADEON_CRTC2_OFFSET_CNTL);
580209ff23fSmrg    save->crtc2_pitch           = INREG(RADEON_CRTC2_PITCH);
581209ff23fSmrg
582209ff23fSmrg    if (IS_R300_VARIANT)
583209ff23fSmrg	save->crtc2_tile_x0_y0 =  INREG(R300_CRTC2_TILE_X0_Y0);
584209ff23fSmrg
585209ff23fSmrg    save->fp_h2_sync_strt_wid   = INREG (RADEON_FP_H2_SYNC_STRT_WID);
586209ff23fSmrg    save->fp_v2_sync_strt_wid   = INREG (RADEON_FP_V2_SYNC_STRT_WID);
587209ff23fSmrg
588209ff23fSmrg    save->disp2_merge_cntl      = INREG(RADEON_DISP2_MERGE_CNTL);
589209ff23fSmrg
590209ff23fSmrg    /* track if the crtc is enabled for text restore */
591209ff23fSmrg    if (save->crtc2_gen_cntl & RADEON_CRTC2_DISP_DIS)
592209ff23fSmrg	info->crtc2_on = FALSE;
593209ff23fSmrg    else
594209ff23fSmrg	info->crtc2_on = TRUE;
595209ff23fSmrg
596209ff23fSmrg}
597209ff23fSmrg
598209ff23fSmrg/* Read PLL registers */
599209ff23fSmrgvoid
600209ff23fSmrgRADEONSavePLLRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save)
601209ff23fSmrg{
602209ff23fSmrg    save->ppll_ref_div = INPLL(pScrn, RADEON_PPLL_REF_DIV);
603209ff23fSmrg    save->ppll_div_3   = INPLL(pScrn, RADEON_PPLL_DIV_3);
604209ff23fSmrg    save->htotal_cntl  = INPLL(pScrn, RADEON_HTOTAL_CNTL);
605209ff23fSmrg    save->vclk_ecp_cntl = INPLL(pScrn, RADEON_VCLK_ECP_CNTL);
606209ff23fSmrg
607209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
608209ff23fSmrg		   "Read: 0x%08x 0x%08x 0x%08x\n",
609209ff23fSmrg		   save->ppll_ref_div,
610209ff23fSmrg		   save->ppll_div_3,
611209ff23fSmrg		   (unsigned)save->htotal_cntl);
612209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
613209ff23fSmrg		   "Read: rd=%d, fd=%d, pd=%d\n",
614209ff23fSmrg		   save->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK,
615209ff23fSmrg		   save->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK,
616209ff23fSmrg		   (save->ppll_div_3 & RADEON_PPLL_POST3_DIV_MASK) >> 16);
617209ff23fSmrg}
618209ff23fSmrg
619209ff23fSmrg/* Read PLL registers */
620209ff23fSmrgvoid
621209ff23fSmrgRADEONSavePLL2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save)
622209ff23fSmrg{
623209ff23fSmrg    save->p2pll_ref_div = INPLL(pScrn, RADEON_P2PLL_REF_DIV);
624209ff23fSmrg    save->p2pll_div_0   = INPLL(pScrn, RADEON_P2PLL_DIV_0);
625209ff23fSmrg    save->htotal_cntl2  = INPLL(pScrn, RADEON_HTOTAL2_CNTL);
626209ff23fSmrg    save->pixclks_cntl  = INPLL(pScrn, RADEON_PIXCLKS_CNTL);
627209ff23fSmrg
628209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
629209ff23fSmrg		   "Read: 0x%08x 0x%08x 0x%08x\n",
630209ff23fSmrg		   (unsigned)save->p2pll_ref_div,
631209ff23fSmrg		   (unsigned)save->p2pll_div_0,
632209ff23fSmrg		   (unsigned)save->htotal_cntl2);
633209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
634209ff23fSmrg		   "Read: rd=%u, fd=%u, pd=%u\n",
635209ff23fSmrg		   (unsigned)(save->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK),
636209ff23fSmrg		   (unsigned)(save->p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK),
637209ff23fSmrg		   (unsigned)((save->p2pll_div_0 & RADEON_P2PLL_POST0_DIV_MASK)
638209ff23fSmrg			      >> 16));
639209ff23fSmrg}
640209ff23fSmrg
641209ff23fSmrgvoid
642209ff23fSmrgradeon_crtc_modeset_ioctl(xf86CrtcPtr crtc, Bool post)
643209ff23fSmrg{
644209ff23fSmrg#if defined(XF86DRI) && defined(DRM_IOCTL_MODESET_CTL)
645209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(crtc->scrn);
646209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
647209ff23fSmrg    struct drm_modeset_ctl modeset;
648b7e1c893Smrg    unsigned char *RADEONMMIO = info->MMIO;
649b7e1c893Smrg
650b7e1c893Smrg    if (!info->directRenderingEnabled)
651b7e1c893Smrg	return;
652209ff23fSmrg
653c503f109Smrg    if (info->ChipFamily >= CHIP_FAMILY_R600)
654c503f109Smrg	return;
655c503f109Smrg
656209ff23fSmrg    modeset.crtc = radeon_crtc->crtc_id;
657209ff23fSmrg    modeset.cmd = post ? _DRM_POST_MODESET : _DRM_PRE_MODESET;
658209ff23fSmrg
659b7e1c893Smrg    ioctl(info->dri->drmFD, DRM_IOCTL_MODESET_CTL, &modeset);
660b7e1c893Smrg
661b7e1c893Smrg    info->ModeReg->gen_int_cntl = INREG( RADEON_GEN_INT_CNTL );
662209ff23fSmrg#endif
663209ff23fSmrg}
664209ff23fSmrg
665209ff23fSmrgvoid
666209ff23fSmrglegacy_crtc_dpms(xf86CrtcPtr crtc, int mode)
667209ff23fSmrg{
668c503f109Smrg    uint32_t mask;
669209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
670209ff23fSmrg    RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
671209ff23fSmrg    unsigned char *RADEONMMIO = pRADEONEnt->MMIO;
672209ff23fSmrg
673c503f109Smrg    if (radeon_crtc->crtc_id)
674f1bc02b7Smrg	mask = (RADEON_CRTC2_DISP_DIS |
675c503f109Smrg		RADEON_CRTC2_VSYNC_DIS |
676c503f109Smrg		RADEON_CRTC2_HSYNC_DIS |
677c503f109Smrg		RADEON_CRTC2_DISP_REQ_EN_B);
678c503f109Smrg    else
679c503f109Smrg	mask = (RADEON_CRTC_DISPLAY_DIS |
680c503f109Smrg		RADEON_CRTC_HSYNC_DIS |
681c503f109Smrg		RADEON_CRTC_VSYNC_DIS);
682209ff23fSmrg
683209ff23fSmrg    switch(mode) {
684209ff23fSmrg    case DPMSModeOn:
685209ff23fSmrg	if (radeon_crtc->crtc_id) {
686f1bc02b7Smrg	    OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_EN, ~(RADEON_CRTC2_EN | mask));
687209ff23fSmrg	} else {
688c503f109Smrg	    OUTREGP(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_EN, ~(RADEON_CRTC_EN | RADEON_CRTC_DISP_REQ_EN_B));
689209ff23fSmrg	    OUTREGP(RADEON_CRTC_EXT_CNTL, 0, ~mask);
690209ff23fSmrg	}
691209ff23fSmrg	break;
692209ff23fSmrg    case DPMSModeStandby:
693209ff23fSmrg    case DPMSModeSuspend:
694209ff23fSmrg    case DPMSModeOff:
695209ff23fSmrg	if (radeon_crtc->crtc_id) {
696f1bc02b7Smrg	    OUTREGP(RADEON_CRTC2_GEN_CNTL, mask, ~(RADEON_CRTC2_EN | mask));
697209ff23fSmrg	} else {
698c503f109Smrg	    OUTREGP(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, ~(RADEON_CRTC_EN | RADEON_CRTC_DISP_REQ_EN_B));
699209ff23fSmrg	    OUTREGP(RADEON_CRTC_EXT_CNTL, mask, ~mask);
700209ff23fSmrg	}
701209ff23fSmrg	break;
702209ff23fSmrg    }
703209ff23fSmrg}
704209ff23fSmrg
705209ff23fSmrg
706209ff23fSmrg/* Define common registers for requested video mode */
707b7e1c893Smrgvoid
708209ff23fSmrgRADEONInitCommonRegisters(RADEONSavePtr save, RADEONInfoPtr info)
709209ff23fSmrg{
710209ff23fSmrg    save->ovr_clr            = 0;
711209ff23fSmrg    save->ovr_wid_left_right = 0;
712209ff23fSmrg    save->ovr_wid_top_bottom = 0;
713209ff23fSmrg    save->ov0_scale_cntl     = 0;
714209ff23fSmrg    save->subpic_cntl        = 0;
715209ff23fSmrg    save->viph_control       = 0;
716209ff23fSmrg    save->i2c_cntl_1         = 0;
717209ff23fSmrg    save->rbbm_soft_reset    = 0;
718209ff23fSmrg    save->cap0_trig_cntl     = 0;
719209ff23fSmrg    save->cap1_trig_cntl     = 0;
720209ff23fSmrg    save->bus_cntl           = info->BusCntl;
721209ff23fSmrg
722209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_RS400) ||
723209ff23fSmrg	(info->ChipFamily == CHIP_FAMILY_RS480)) {
724209ff23fSmrg	save->disp2_req_cntl1 = info->SavedReg->disp2_req_cntl1;
725209ff23fSmrg	save->disp2_req_cntl2 = info->SavedReg->disp2_req_cntl2;
726209ff23fSmrg	save->dmif_mem_cntl1  = info->SavedReg->dmif_mem_cntl1;
727209ff23fSmrg	save->disp1_req_cntl1 = info->SavedReg->disp1_req_cntl1;
728209ff23fSmrg    }
729209ff23fSmrg
730209ff23fSmrg    /*
731209ff23fSmrg     * If bursts are enabled, turn on discards
732209ff23fSmrg     * Radeon doesn't have write bursts
733209ff23fSmrg     */
734209ff23fSmrg    if (save->bus_cntl & (RADEON_BUS_READ_BURST))
735209ff23fSmrg	save->bus_cntl |= RADEON_BUS_RD_DISCARD_EN;
736209ff23fSmrg}
737209ff23fSmrg
738b7e1c893Smrgvoid
739209ff23fSmrgRADEONInitSurfaceCntl(xf86CrtcPtr crtc, RADEONSavePtr save)
740209ff23fSmrg{
741209ff23fSmrg    save->surface_cntl = 0;
742209ff23fSmrg
743209ff23fSmrg#if X_BYTE_ORDER == X_BIG_ENDIAN
744209ff23fSmrg    /* We must set both apertures as they can be both used to map the entire
745209ff23fSmrg     * video memory. -BenH.
746209ff23fSmrg     */
747209ff23fSmrg    switch (crtc->scrn->bitsPerPixel) {
748209ff23fSmrg    case 16:
749209ff23fSmrg	save->surface_cntl |= RADEON_NONSURF_AP0_SWP_16BPP;
750209ff23fSmrg	save->surface_cntl |= RADEON_NONSURF_AP1_SWP_16BPP;
751209ff23fSmrg	break;
752209ff23fSmrg
753209ff23fSmrg    case 32:
754209ff23fSmrg	save->surface_cntl |= RADEON_NONSURF_AP0_SWP_32BPP;
755209ff23fSmrg	save->surface_cntl |= RADEON_NONSURF_AP1_SWP_32BPP;
756209ff23fSmrg	break;
757209ff23fSmrg    }
758209ff23fSmrg#endif
759209ff23fSmrg
760209ff23fSmrg}
761209ff23fSmrg
762b7e1c893Smrgvoid
763209ff23fSmrgRADEONInitCrtcBase(xf86CrtcPtr crtc, RADEONSavePtr save,
764209ff23fSmrg		   int x, int y)
765209ff23fSmrg{
766209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
767209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
768209ff23fSmrg    int    Base;
769209ff23fSmrg#ifdef XF86DRI
770b7e1c893Smrg    drm_radeon_sarea_t *pSAREAPriv;
771209ff23fSmrg    XF86DRISAREAPtr pSAREA;
772209ff23fSmrg#endif
773209ff23fSmrg
774209ff23fSmrg    save->crtc_offset      = pScrn->fbOffset;
775209ff23fSmrg#ifdef XF86DRI
776b7e1c893Smrg    if (info->dri && info->dri->allowPageFlip)
777209ff23fSmrg	save->crtc_offset_cntl = RADEON_CRTC_OFFSET_FLIP_CNTL;
778209ff23fSmrg    else
779209ff23fSmrg#endif
780209ff23fSmrg	save->crtc_offset_cntl = 0;
781209ff23fSmrg
782209ff23fSmrg    if (info->tilingEnabled && (crtc->rotatedData == NULL)) {
783209ff23fSmrg       if (IS_R300_VARIANT)
784209ff23fSmrg          save->crtc_offset_cntl |= (R300_CRTC_X_Y_MODE_EN |
785209ff23fSmrg				     R300_CRTC_MICRO_TILE_BUFFER_DIS |
786209ff23fSmrg				     R300_CRTC_MACRO_TILE_EN);
787209ff23fSmrg       else
788209ff23fSmrg          save->crtc_offset_cntl |= RADEON_CRTC_TILE_EN;
789209ff23fSmrg    }
790209ff23fSmrg    else {
791209ff23fSmrg       if (IS_R300_VARIANT)
792209ff23fSmrg          save->crtc_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN |
793209ff23fSmrg				      R300_CRTC_MICRO_TILE_BUFFER_DIS |
794209ff23fSmrg				      R300_CRTC_MACRO_TILE_EN);
795209ff23fSmrg       else
796209ff23fSmrg          save->crtc_offset_cntl &= ~RADEON_CRTC_TILE_EN;
797209ff23fSmrg    }
798209ff23fSmrg
799209ff23fSmrg    Base = pScrn->fbOffset;
800209ff23fSmrg
801209ff23fSmrg    if (info->tilingEnabled && (crtc->rotatedData == NULL)) {
802209ff23fSmrg        if (IS_R300_VARIANT) {
803209ff23fSmrg	/* On r300/r400 when tiling is enabled crtc_offset is set to the address of
804209ff23fSmrg	 * the surface.  the x/y offsets are handled by the X_Y tile reg for each crtc
805209ff23fSmrg	 * Makes tiling MUCH easier.
806209ff23fSmrg	 */
807209ff23fSmrg             save->crtc_tile_x0_y0 = x | (y << 16);
808209ff23fSmrg             Base &= ~0x7ff;
809209ff23fSmrg         } else {
810209ff23fSmrg	     /* note we cannot really simply use the info->ModeReg.crtc_offset_cntl value, since the
811209ff23fSmrg		drm might have set FLIP_CNTL since we wrote that. Unfortunately FLIP_CNTL causes
812209ff23fSmrg		flickering when scrolling vertically in a virtual screen, possibly because crtc will
813209ff23fSmrg		pick up the new offset value at the end of each scanline, but the new offset_cntl value
814209ff23fSmrg		only after a vsync. We'd probably need to wait (in drm) for vsync and only then update
815209ff23fSmrg		OFFSET and OFFSET_CNTL, if the y coord has changed. Seems hard to fix. */
816209ff23fSmrg	     /*save->crtc_offset_cntl = INREG(RADEON_CRTC_OFFSET_CNTL) & ~0xf;*/
817209ff23fSmrg#if 0
818209ff23fSmrg	     /* try to get rid of flickering when scrolling at least for 2d */
819209ff23fSmrg#ifdef XF86DRI
820209ff23fSmrg	     if (!info->have3DWindows)
821209ff23fSmrg#endif
822209ff23fSmrg		 save->crtc_offset_cntl &= ~RADEON_CRTC_OFFSET_FLIP_CNTL;
823209ff23fSmrg#endif
824209ff23fSmrg
825209ff23fSmrg             int byteshift = info->CurrentLayout.bitsPerPixel >> 4;
826209ff23fSmrg             /* crtc uses 256(bytes)x8 "half-tile" start addresses? */
827209ff23fSmrg             int tile_addr = (((y >> 3) * info->CurrentLayout.displayWidth + x) >> (8 - byteshift)) << 11;
828209ff23fSmrg             Base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8);
829209ff23fSmrg             save->crtc_offset_cntl = save->crtc_offset_cntl | (y % 16);
830209ff23fSmrg         }
831209ff23fSmrg    }
832209ff23fSmrg    else {
833209ff23fSmrg       int offset = y * info->CurrentLayout.displayWidth + x;
834209ff23fSmrg       switch (info->CurrentLayout.pixel_code) {
835209ff23fSmrg       case 15:
836209ff23fSmrg       case 16: offset *= 2; break;
837209ff23fSmrg       case 24: offset *= 3; break;
838209ff23fSmrg       case 32: offset *= 4; break;
839209ff23fSmrg       }
840209ff23fSmrg       Base += offset;
841209ff23fSmrg    }
842209ff23fSmrg
843209ff23fSmrg    if (crtc->rotatedData != NULL) {
844209ff23fSmrg	Base = pScrn->fbOffset + (char *)crtc->rotatedData - (char *)info->FB;
845209ff23fSmrg    }
846209ff23fSmrg
847209ff23fSmrg    Base &= ~7;                 /* 3 lower bits are always 0 */
848209ff23fSmrg
849209ff23fSmrg
850209ff23fSmrg#ifdef XF86DRI
851209ff23fSmrg    if (info->directRenderingInited) {
852209ff23fSmrg	/* note cannot use pScrn->pScreen since this is unitialized when called from
853209ff23fSmrg	   RADEONScreenInit, and we need to call from there to get mergedfb + pageflip working */
854209ff23fSmrg        /*** NOTE: r3/4xx will need sarea and drm pageflip updates to handle the xytile regs for
855209ff23fSmrg	 *** pageflipping!
856209ff23fSmrg	 ***/
857209ff23fSmrg	pSAREAPriv = DRIGetSAREAPrivate(screenInfo.screens[pScrn->scrnIndex]);
858209ff23fSmrg	/* can't get at sarea in a semi-sane way? */
859209ff23fSmrg	pSAREA = (void *)((char*)pSAREAPriv - sizeof(XF86DRISAREARec));
860209ff23fSmrg
861209ff23fSmrg	pSAREA->frame.x = (Base  / info->CurrentLayout.pixel_bytes)
862209ff23fSmrg	    % info->CurrentLayout.displayWidth;
863209ff23fSmrg	pSAREA->frame.y = (Base / info->CurrentLayout.pixel_bytes)
864209ff23fSmrg	    / info->CurrentLayout.displayWidth;
865209ff23fSmrg	pSAREA->frame.width = pScrn->frameX1 - x + 1;
866209ff23fSmrg	pSAREA->frame.height = pScrn->frameY1 - y + 1;
867209ff23fSmrg
868209ff23fSmrg	if (pSAREAPriv->pfCurrentPage == 1) {
869b7e1c893Smrg	    Base += info->dri->backOffset - info->dri->frontOffset;
870209ff23fSmrg	}
871209ff23fSmrg    }
872209ff23fSmrg#endif
873209ff23fSmrg    save->crtc_offset = Base;
874209ff23fSmrg
875209ff23fSmrg}
876209ff23fSmrg
877209ff23fSmrg/* Define CRTC registers for requested video mode */
878209ff23fSmrgstatic Bool
879209ff23fSmrgRADEONInitCrtcRegisters(xf86CrtcPtr crtc, RADEONSavePtr save,
880209ff23fSmrg			DisplayModePtr mode)
881209ff23fSmrg{
882209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
883209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
884209ff23fSmrg    int    format;
885209ff23fSmrg    int    hsync_start;
886209ff23fSmrg    int    hsync_wid;
887209ff23fSmrg    int    vsync_wid;
888209ff23fSmrg
889209ff23fSmrg    switch (info->CurrentLayout.pixel_code) {
890209ff23fSmrg    case 4:  format = 1; break;
891209ff23fSmrg    case 8:  format = 2; break;
892209ff23fSmrg    case 15: format = 3; break;      /*  555 */
893209ff23fSmrg    case 16: format = 4; break;      /*  565 */
894209ff23fSmrg    case 24: format = 5; break;      /*  RGB */
895209ff23fSmrg    case 32: format = 6; break;      /* xRGB */
896209ff23fSmrg    default:
897209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
898209ff23fSmrg		   "Unsupported pixel depth (%d)\n",
899209ff23fSmrg		   info->CurrentLayout.bitsPerPixel);
900209ff23fSmrg	return FALSE;
901209ff23fSmrg    }
902209ff23fSmrg
903209ff23fSmrg    /*save->bios_4_scratch = info->SavedReg->bios_4_scratch;*/
904209ff23fSmrg    save->crtc_gen_cntl = (RADEON_CRTC_EXT_DISP_EN
905209ff23fSmrg			   | (format << 8)
906209ff23fSmrg			   | ((mode->Flags & V_DBLSCAN)
907209ff23fSmrg			      ? RADEON_CRTC_DBL_SCAN_EN
908209ff23fSmrg			      : 0)
909209ff23fSmrg			   | ((mode->Flags & V_CSYNC)
910209ff23fSmrg			      ? RADEON_CRTC_CSYNC_EN
911209ff23fSmrg			      : 0)
912209ff23fSmrg			   | ((mode->Flags & V_INTERLACE)
913209ff23fSmrg			      ? RADEON_CRTC_INTERLACE_EN
914209ff23fSmrg			      : 0));
915209ff23fSmrg
916f1bc02b7Smrg    /* 200M freezes on VT switch sometimes if CRTC is disabled */
917f1bc02b7Smrg    if ((info->ChipFamily == CHIP_FAMILY_RS400) ||
918f1bc02b7Smrg	(info->ChipFamily == CHIP_FAMILY_RS480))
919f1bc02b7Smrg	save->crtc_gen_cntl |= RADEON_CRTC_EN;
920f1bc02b7Smrg
921209ff23fSmrg    save->crtc_ext_cntl |= (RADEON_XCRT_CNT_EN|
922209ff23fSmrg			    RADEON_CRTC_VSYNC_DIS |
923209ff23fSmrg			    RADEON_CRTC_HSYNC_DIS |
924209ff23fSmrg			    RADEON_CRTC_DISPLAY_DIS);
925209ff23fSmrg
926209ff23fSmrg    save->disp_merge_cntl = info->SavedReg->disp_merge_cntl;
927209ff23fSmrg    save->disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN;
928209ff23fSmrg
929209ff23fSmrg    save->crtc_h_total_disp = ((((mode->CrtcHTotal / 8) - 1) & 0x3ff)
930209ff23fSmrg			       | ((((mode->CrtcHDisplay / 8) - 1) & 0x1ff)
931209ff23fSmrg				  << 16));
932209ff23fSmrg
933209ff23fSmrg    hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8;
934209ff23fSmrg    if (!hsync_wid)       hsync_wid = 1;
935209ff23fSmrg    hsync_start = mode->CrtcHSyncStart - 8;
936209ff23fSmrg
937209ff23fSmrg    save->crtc_h_sync_strt_wid = ((hsync_start & 0x1fff)
938209ff23fSmrg				  | ((hsync_wid & 0x3f) << 16)
939209ff23fSmrg				  | ((mode->Flags & V_NHSYNC)
940209ff23fSmrg				     ? RADEON_CRTC_H_SYNC_POL
941209ff23fSmrg				     : 0));
942209ff23fSmrg
943209ff23fSmrg				/* This works for double scan mode. */
944209ff23fSmrg    save->crtc_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff)
945209ff23fSmrg			       | ((mode->CrtcVDisplay - 1) << 16));
946209ff23fSmrg
947209ff23fSmrg    vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart;
948209ff23fSmrg    if (!vsync_wid)       vsync_wid = 1;
949209ff23fSmrg
950209ff23fSmrg    save->crtc_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff)
951209ff23fSmrg				  | ((vsync_wid & 0x1f) << 16)
952209ff23fSmrg				  | ((mode->Flags & V_NVSYNC)
953209ff23fSmrg				     ? RADEON_CRTC_V_SYNC_POL
954209ff23fSmrg				     : 0));
955209ff23fSmrg
956209ff23fSmrg    save->crtc_pitch  = (((pScrn->displayWidth * pScrn->bitsPerPixel) +
957209ff23fSmrg			  ((pScrn->bitsPerPixel * 8) -1)) /
958209ff23fSmrg			 (pScrn->bitsPerPixel * 8));
959209ff23fSmrg    save->crtc_pitch |= save->crtc_pitch << 16;
960209ff23fSmrg
961209ff23fSmrg    if (info->IsDellServer) {
962209ff23fSmrg	save->dac2_cntl = info->SavedReg->dac2_cntl;
963209ff23fSmrg	save->tv_dac_cntl = info->SavedReg->tv_dac_cntl;
964209ff23fSmrg	save->crtc2_gen_cntl = info->SavedReg->crtc2_gen_cntl;
965209ff23fSmrg	save->disp_hw_debug = info->SavedReg->disp_hw_debug;
966209ff23fSmrg
967209ff23fSmrg	save->dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL;
968209ff23fSmrg	save->dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL;
969209ff23fSmrg
970209ff23fSmrg	/* For CRT on DAC2, don't turn it on if BIOS didn't
971209ff23fSmrg	   enable it, even it's detected.
972209ff23fSmrg	*/
973209ff23fSmrg	save->disp_hw_debug |= RADEON_CRT2_DISP1_SEL;
974209ff23fSmrg	save->tv_dac_cntl &= ~((1<<2) | (3<<8) | (7<<24) | (0xff<<16));
975209ff23fSmrg	save->tv_dac_cntl |= (0x03 | (2<<8) | (0x58<<16));
976209ff23fSmrg    }
977209ff23fSmrg
978209ff23fSmrg    return TRUE;
979209ff23fSmrg}
980209ff23fSmrg
981209ff23fSmrg
982b7e1c893Smrgvoid
983209ff23fSmrgRADEONInitCrtc2Base(xf86CrtcPtr crtc, RADEONSavePtr save,
984209ff23fSmrg		    int x, int y)
985209ff23fSmrg{
986209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
987209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
988209ff23fSmrg    int    Base;
989209ff23fSmrg#ifdef XF86DRI
990b7e1c893Smrg    drm_radeon_sarea_t *pSAREAPriv;
991209ff23fSmrg    XF86DRISAREAPtr pSAREA;
992209ff23fSmrg#endif
993209ff23fSmrg
994209ff23fSmrg    /* It seems all fancy options apart from pflip can be safely disabled
995209ff23fSmrg     */
996209ff23fSmrg    save->crtc2_offset      = pScrn->fbOffset;
997209ff23fSmrg#ifdef XF86DRI
998b7e1c893Smrg    if (info->dri && info->dri->allowPageFlip)
999209ff23fSmrg	save->crtc2_offset_cntl = RADEON_CRTC_OFFSET_FLIP_CNTL;
1000209ff23fSmrg    else
1001209ff23fSmrg#endif
1002209ff23fSmrg	save->crtc2_offset_cntl = 0;
1003209ff23fSmrg
1004209ff23fSmrg    if (info->tilingEnabled && (crtc->rotatedData == NULL)) {
1005209ff23fSmrg       if (IS_R300_VARIANT)
1006209ff23fSmrg          save->crtc2_offset_cntl |= (R300_CRTC_X_Y_MODE_EN |
1007209ff23fSmrg				      R300_CRTC_MICRO_TILE_BUFFER_DIS |
1008209ff23fSmrg				      R300_CRTC_MACRO_TILE_EN);
1009209ff23fSmrg       else
1010209ff23fSmrg          save->crtc2_offset_cntl |= RADEON_CRTC_TILE_EN;
1011209ff23fSmrg    }
1012209ff23fSmrg    else {
1013209ff23fSmrg       if (IS_R300_VARIANT)
1014209ff23fSmrg          save->crtc2_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN |
1015209ff23fSmrg				      R300_CRTC_MICRO_TILE_BUFFER_DIS |
1016209ff23fSmrg				      R300_CRTC_MACRO_TILE_EN);
1017209ff23fSmrg       else
1018209ff23fSmrg          save->crtc2_offset_cntl &= ~RADEON_CRTC_TILE_EN;
1019209ff23fSmrg    }
1020209ff23fSmrg
1021209ff23fSmrg    Base = pScrn->fbOffset;
1022209ff23fSmrg
1023209ff23fSmrg    if (info->tilingEnabled && (crtc->rotatedData == NULL)) {
1024209ff23fSmrg        if (IS_R300_VARIANT) {
1025209ff23fSmrg	/* On r300/r400 when tiling is enabled crtc_offset is set to the address of
1026209ff23fSmrg	 * the surface.  the x/y offsets are handled by the X_Y tile reg for each crtc
1027209ff23fSmrg	 * Makes tiling MUCH easier.
1028209ff23fSmrg	 */
1029209ff23fSmrg             save->crtc2_tile_x0_y0 = x | (y << 16);
1030209ff23fSmrg             Base &= ~0x7ff;
1031209ff23fSmrg         } else {
1032209ff23fSmrg	     /* note we cannot really simply use the info->ModeReg.crtc_offset_cntl value, since the
1033209ff23fSmrg		drm might have set FLIP_CNTL since we wrote that. Unfortunately FLIP_CNTL causes
1034209ff23fSmrg		flickering when scrolling vertically in a virtual screen, possibly because crtc will
1035209ff23fSmrg		pick up the new offset value at the end of each scanline, but the new offset_cntl value
1036209ff23fSmrg		only after a vsync. We'd probably need to wait (in drm) for vsync and only then update
1037209ff23fSmrg		OFFSET and OFFSET_CNTL, if the y coord has changed. Seems hard to fix. */
1038209ff23fSmrg	     /*save->crtc2_offset_cntl = INREG(RADEON_CRTC2_OFFSET_CNTL) & ~0xf;*/
1039209ff23fSmrg#if 0
1040209ff23fSmrg	     /* try to get rid of flickering when scrolling at least for 2d */
1041209ff23fSmrg#ifdef XF86DRI
1042209ff23fSmrg	     if (!info->have3DWindows)
1043209ff23fSmrg#endif
1044209ff23fSmrg		 save->crtc2_offset_cntl &= ~RADEON_CRTC_OFFSET_FLIP_CNTL;
1045209ff23fSmrg#endif
1046209ff23fSmrg
1047209ff23fSmrg             int byteshift = info->CurrentLayout.bitsPerPixel >> 4;
1048209ff23fSmrg             /* crtc uses 256(bytes)x8 "half-tile" start addresses? */
1049209ff23fSmrg             int tile_addr = (((y >> 3) * info->CurrentLayout.displayWidth + x) >> (8 - byteshift)) << 11;
1050209ff23fSmrg             Base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8);
1051209ff23fSmrg             save->crtc2_offset_cntl = save->crtc_offset_cntl | (y % 16);
1052209ff23fSmrg         }
1053209ff23fSmrg    }
1054209ff23fSmrg    else {
1055209ff23fSmrg       int offset = y * info->CurrentLayout.displayWidth + x;
1056209ff23fSmrg       switch (info->CurrentLayout.pixel_code) {
1057209ff23fSmrg       case 15:
1058209ff23fSmrg       case 16: offset *= 2; break;
1059209ff23fSmrg       case 24: offset *= 3; break;
1060209ff23fSmrg       case 32: offset *= 4; break;
1061209ff23fSmrg       }
1062209ff23fSmrg       Base += offset;
1063209ff23fSmrg    }
1064209ff23fSmrg
1065209ff23fSmrg    if (crtc->rotatedData != NULL) {
1066209ff23fSmrg	Base = pScrn->fbOffset + (char *)crtc->rotatedData - (char *)info->FB;
1067209ff23fSmrg    }
1068209ff23fSmrg
1069209ff23fSmrg    Base &= ~7;                 /* 3 lower bits are always 0 */
1070209ff23fSmrg
1071209ff23fSmrg#ifdef XF86DRI
1072209ff23fSmrg    if (info->directRenderingInited) {
1073209ff23fSmrg	/* note cannot use pScrn->pScreen since this is unitialized when called from
1074209ff23fSmrg	   RADEONScreenInit, and we need to call from there to get mergedfb + pageflip working */
1075209ff23fSmrg        /*** NOTE: r3/4xx will need sarea and drm pageflip updates to handle the xytile regs for
1076209ff23fSmrg	 *** pageflipping!
1077209ff23fSmrg	 ***/
1078209ff23fSmrg	pSAREAPriv = DRIGetSAREAPrivate(screenInfo.screens[pScrn->scrnIndex]);
1079209ff23fSmrg	/* can't get at sarea in a semi-sane way? */
1080209ff23fSmrg	pSAREA = (void *)((char*)pSAREAPriv - sizeof(XF86DRISAREARec));
1081209ff23fSmrg
1082209ff23fSmrg	pSAREAPriv->crtc2_base = Base;
1083209ff23fSmrg
1084209ff23fSmrg	if (pSAREAPriv->pfCurrentPage == 1) {
1085b7e1c893Smrg	    Base += info->dri->backOffset - info->dri->frontOffset;
1086209ff23fSmrg	}
1087209ff23fSmrg    }
1088209ff23fSmrg#endif
1089209ff23fSmrg    save->crtc2_offset = Base;
1090209ff23fSmrg
1091209ff23fSmrg}
1092209ff23fSmrg
1093209ff23fSmrg
1094209ff23fSmrg/* Define CRTC2 registers for requested video mode */
1095209ff23fSmrgstatic Bool
1096209ff23fSmrgRADEONInitCrtc2Registers(xf86CrtcPtr crtc, RADEONSavePtr save,
1097209ff23fSmrg			 DisplayModePtr mode)
1098209ff23fSmrg{
1099209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
1100209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1101209ff23fSmrg    int    format;
1102209ff23fSmrg    int    hsync_start;
1103209ff23fSmrg    int    hsync_wid;
1104209ff23fSmrg    int    vsync_wid;
1105209ff23fSmrg
1106209ff23fSmrg    switch (info->CurrentLayout.pixel_code) {
1107209ff23fSmrg    case 4:  format = 1; break;
1108209ff23fSmrg    case 8:  format = 2; break;
1109209ff23fSmrg    case 15: format = 3; break;      /*  555 */
1110209ff23fSmrg    case 16: format = 4; break;      /*  565 */
1111209ff23fSmrg    case 24: format = 5; break;      /*  RGB */
1112209ff23fSmrg    case 32: format = 6; break;      /* xRGB */
1113209ff23fSmrg    default:
1114209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1115209ff23fSmrg		   "Unsupported pixel depth (%d)\n",
1116209ff23fSmrg		   info->CurrentLayout.bitsPerPixel);
1117209ff23fSmrg	return FALSE;
1118209ff23fSmrg    }
1119209ff23fSmrg
1120209ff23fSmrg    save->crtc2_h_total_disp =
1121209ff23fSmrg	((((mode->CrtcHTotal / 8) - 1) & 0x3ff)
1122209ff23fSmrg	 | ((((mode->CrtcHDisplay / 8) - 1) & 0x1ff) << 16));
1123209ff23fSmrg
1124209ff23fSmrg    hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8;
1125209ff23fSmrg    if (!hsync_wid)       hsync_wid = 1;
1126209ff23fSmrg    hsync_start = mode->CrtcHSyncStart - 8;
1127209ff23fSmrg
1128209ff23fSmrg    save->crtc2_h_sync_strt_wid = ((hsync_start & 0x1fff)
1129209ff23fSmrg				   | ((hsync_wid & 0x3f) << 16)
1130209ff23fSmrg				   | ((mode->Flags & V_NHSYNC)
1131209ff23fSmrg				      ? RADEON_CRTC_H_SYNC_POL
1132209ff23fSmrg				      : 0));
1133209ff23fSmrg
1134209ff23fSmrg				/* This works for double scan mode. */
1135209ff23fSmrg    save->crtc2_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff)
1136209ff23fSmrg				| ((mode->CrtcVDisplay - 1) << 16));
1137209ff23fSmrg
1138209ff23fSmrg    vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart;
1139209ff23fSmrg    if (!vsync_wid)       vsync_wid = 1;
1140209ff23fSmrg
1141209ff23fSmrg    save->crtc2_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff)
1142209ff23fSmrg				   | ((vsync_wid & 0x1f) << 16)
1143209ff23fSmrg				   | ((mode->Flags & V_NVSYNC)
1144209ff23fSmrg				      ? RADEON_CRTC2_V_SYNC_POL
1145209ff23fSmrg				      : 0));
1146209ff23fSmrg
1147209ff23fSmrg    save->crtc2_pitch  = ((pScrn->displayWidth * pScrn->bitsPerPixel) +
1148209ff23fSmrg			  ((pScrn->bitsPerPixel * 8) -1)) / (pScrn->bitsPerPixel * 8);
1149209ff23fSmrg    save->crtc2_pitch |= save->crtc2_pitch << 16;
1150209ff23fSmrg
1151209ff23fSmrg    /* check to see if TV DAC is enabled for another crtc and keep it enabled */
1152209ff23fSmrg    if (save->crtc2_gen_cntl & RADEON_CRTC2_CRT2_ON)
1153209ff23fSmrg	save->crtc2_gen_cntl = RADEON_CRTC2_CRT2_ON;
1154209ff23fSmrg    else
1155209ff23fSmrg	save->crtc2_gen_cntl = 0;
1156209ff23fSmrg
1157c503f109Smrg    save->crtc2_gen_cntl |= ((format << 8)
1158209ff23fSmrg			     | RADEON_CRTC2_VSYNC_DIS
1159209ff23fSmrg			     | RADEON_CRTC2_HSYNC_DIS
1160209ff23fSmrg			     | RADEON_CRTC2_DISP_DIS
1161209ff23fSmrg			     | ((mode->Flags & V_DBLSCAN)
1162209ff23fSmrg				? RADEON_CRTC2_DBL_SCAN_EN
1163209ff23fSmrg				: 0)
1164209ff23fSmrg			     | ((mode->Flags & V_CSYNC)
1165209ff23fSmrg				? RADEON_CRTC2_CSYNC_EN
1166209ff23fSmrg				: 0)
1167209ff23fSmrg			     | ((mode->Flags & V_INTERLACE)
1168209ff23fSmrg				? RADEON_CRTC2_INTERLACE_EN
1169209ff23fSmrg				: 0));
1170209ff23fSmrg
1171f1bc02b7Smrg    /* 200M freezes on VT switch sometimes if CRTC is disabled */
1172f1bc02b7Smrg    if ((info->ChipFamily == CHIP_FAMILY_RS400) ||
1173f1bc02b7Smrg	(info->ChipFamily == CHIP_FAMILY_RS480))
1174f1bc02b7Smrg	save->crtc2_gen_cntl |= RADEON_CRTC2_EN;
1175f1bc02b7Smrg
1176209ff23fSmrg    save->disp2_merge_cntl = info->SavedReg->disp2_merge_cntl;
1177209ff23fSmrg    save->disp2_merge_cntl &= ~(RADEON_DISP2_RGB_OFFSET_EN);
1178209ff23fSmrg
1179209ff23fSmrg    save->fp_h2_sync_strt_wid = save->crtc2_h_sync_strt_wid;
1180209ff23fSmrg    save->fp_v2_sync_strt_wid = save->crtc2_v_sync_strt_wid;
1181209ff23fSmrg
1182209ff23fSmrg    return TRUE;
1183209ff23fSmrg}
1184209ff23fSmrg
1185209ff23fSmrg
1186209ff23fSmrg/* Define PLL registers for requested video mode */
1187209ff23fSmrgstatic void
1188209ff23fSmrgRADEONInitPLLRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save,
1189209ff23fSmrg		       RADEONPLLPtr pll, DisplayModePtr mode,
1190209ff23fSmrg		       int flags)
1191209ff23fSmrg{
1192209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1193209ff23fSmrg    uint32_t feedback_div = 0;
1194f1bc02b7Smrg    uint32_t frac_fb_div = 0;
1195209ff23fSmrg    uint32_t reference_div = 0;
1196209ff23fSmrg    uint32_t post_divider = 0;
1197209ff23fSmrg    uint32_t freq = 0;
1198209ff23fSmrg
1199209ff23fSmrg    struct {
1200209ff23fSmrg	int divider;
1201209ff23fSmrg	int bitvalue;
1202209ff23fSmrg    } *post_div, post_divs[]   = {
1203209ff23fSmrg				/* From RAGE 128 VR/RAGE 128 GL Register
1204209ff23fSmrg				 * Reference Manual (Technical Reference
1205209ff23fSmrg				 * Manual P/N RRG-G04100-C Rev. 0.04), page
1206209ff23fSmrg				 * 3-17 (PLL_DIV_[3:0]).
1207209ff23fSmrg				 */
1208209ff23fSmrg	{  1, 0 },              /* VCLK_SRC                 */
1209209ff23fSmrg	{  2, 1 },              /* VCLK_SRC/2               */
1210209ff23fSmrg	{  4, 2 },              /* VCLK_SRC/4               */
1211209ff23fSmrg	{  8, 3 },              /* VCLK_SRC/8               */
1212209ff23fSmrg	{  3, 4 },              /* VCLK_SRC/3               */
1213209ff23fSmrg	{ 16, 5 },              /* VCLK_SRC/16              */
1214209ff23fSmrg	{  6, 6 },              /* VCLK_SRC/6               */
1215209ff23fSmrg	{ 12, 7 },              /* VCLK_SRC/12              */
1216209ff23fSmrg	{  0, 0 }
1217209ff23fSmrg    };
1218209ff23fSmrg
1219209ff23fSmrg
1220209ff23fSmrg    if ((flags & RADEON_PLL_USE_BIOS_DIVS) && info->UseBiosDividers) {
1221209ff23fSmrg       save->ppll_ref_div = info->RefDivider;
1222209ff23fSmrg       save->ppll_div_3   = info->FeedbackDivider | (info->PostDivider << 16);
1223209ff23fSmrg       save->htotal_cntl  = 0;
1224209ff23fSmrg       return;
1225209ff23fSmrg    }
1226209ff23fSmrg
1227f1bc02b7Smrg    RADEONComputePLL(pScrn, pll, mode->Clock, &freq, &feedback_div, &frac_fb_div, &reference_div, &post_divider, flags);
1228209ff23fSmrg
1229209ff23fSmrg    for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
1230209ff23fSmrg	if (post_div->divider == post_divider)
1231209ff23fSmrg	    break;
1232209ff23fSmrg    }
1233209ff23fSmrg
1234209ff23fSmrg    if (!post_div->divider) {
1235209ff23fSmrg	save->pll_output_freq = freq;
1236209ff23fSmrg	post_div = &post_divs[0];
1237209ff23fSmrg    }
1238209ff23fSmrg
1239209ff23fSmrg    save->dot_clock_freq = freq;
1240209ff23fSmrg    save->feedback_div   = feedback_div;
1241209ff23fSmrg    save->reference_div  = reference_div;
1242209ff23fSmrg    save->post_div       = post_divider;
1243209ff23fSmrg
1244209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
1245209ff23fSmrg		   "dc=%u, of=%u, fd=%d, rd=%d, pd=%d\n",
1246209ff23fSmrg		   (unsigned)save->dot_clock_freq,
1247209ff23fSmrg		   (unsigned)save->pll_output_freq,
1248209ff23fSmrg		   save->feedback_div,
1249209ff23fSmrg		   save->reference_div,
1250209ff23fSmrg		   save->post_div);
1251209ff23fSmrg
1252209ff23fSmrg    save->ppll_ref_div   = save->reference_div;
1253209ff23fSmrg
1254209ff23fSmrg#if defined(__powerpc__)
1255209ff23fSmrg    /* apparently programming this otherwise causes a hang??? */
12561764dec5Smacallan    if ((info->MacModel == RADEON_MAC_IBOOK) ||
12571764dec5Smacallan        (info->MacModel == RADEON_MAC_MINI_INTERNAL))
1258209ff23fSmrg	save->ppll_div_3 = 0x000600ad;
1259209ff23fSmrg    else
1260209ff23fSmrg#endif
1261209ff23fSmrg    save->ppll_div_3     = (save->feedback_div | (post_div->bitvalue << 16));
1262209ff23fSmrg
1263209ff23fSmrg    save->htotal_cntl    = mode->HTotal & 0x7;
1264209ff23fSmrg
1265209ff23fSmrg    save->vclk_ecp_cntl = (info->SavedReg->vclk_ecp_cntl &
1266209ff23fSmrg	    ~RADEON_VCLK_SRC_SEL_MASK) | RADEON_VCLK_SRC_SEL_PPLLCLK;
1267209ff23fSmrg}
1268209ff23fSmrg
1269209ff23fSmrg/* Define PLL2 registers for requested video mode */
1270209ff23fSmrgstatic void
1271209ff23fSmrgRADEONInitPLL2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save,
1272209ff23fSmrg			RADEONPLLPtr pll, DisplayModePtr mode,
1273209ff23fSmrg			int flags)
1274209ff23fSmrg{
1275209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1276209ff23fSmrg    uint32_t feedback_div = 0;
1277f1bc02b7Smrg    uint32_t frac_fb_div = 0;
1278209ff23fSmrg    uint32_t reference_div = 0;
1279209ff23fSmrg    uint32_t post_divider = 0;
1280209ff23fSmrg    uint32_t freq = 0;
1281209ff23fSmrg
1282209ff23fSmrg    struct {
1283209ff23fSmrg	int divider;
1284209ff23fSmrg	int bitvalue;
1285209ff23fSmrg    } *post_div, post_divs[]   = {
1286209ff23fSmrg				/* From RAGE 128 VR/RAGE 128 GL Register
1287209ff23fSmrg				 * Reference Manual (Technical Reference
1288209ff23fSmrg				 * Manual P/N RRG-G04100-C Rev. 0.04), page
1289209ff23fSmrg				 * 3-17 (PLL_DIV_[3:0]).
1290209ff23fSmrg				 */
1291209ff23fSmrg	{  1, 0 },              /* VCLK_SRC                 */
1292209ff23fSmrg	{  2, 1 },              /* VCLK_SRC/2               */
1293209ff23fSmrg	{  4, 2 },              /* VCLK_SRC/4               */
1294209ff23fSmrg	{  8, 3 },              /* VCLK_SRC/8               */
1295209ff23fSmrg	{  3, 4 },              /* VCLK_SRC/3               */
1296209ff23fSmrg	{  6, 6 },              /* VCLK_SRC/6               */
1297209ff23fSmrg	{ 12, 7 },              /* VCLK_SRC/12              */
1298209ff23fSmrg	{  0, 0 }
1299209ff23fSmrg    };
1300209ff23fSmrg
1301209ff23fSmrg    if ((flags & RADEON_PLL_USE_BIOS_DIVS) && info->UseBiosDividers) {
1302209ff23fSmrg       save->p2pll_ref_div = info->RefDivider;
1303209ff23fSmrg       save->p2pll_div_0   = info->FeedbackDivider | (info->PostDivider << 16);
1304209ff23fSmrg       save->htotal_cntl2  = 0;
1305209ff23fSmrg       return;
1306209ff23fSmrg    }
1307209ff23fSmrg
1308f1bc02b7Smrg    RADEONComputePLL(pScrn, pll, mode->Clock, &freq, &feedback_div, &frac_fb_div, &reference_div, &post_divider, flags);
1309209ff23fSmrg
1310209ff23fSmrg    for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
1311209ff23fSmrg	if (post_div->divider == post_divider)
1312209ff23fSmrg	    break;
1313209ff23fSmrg    }
1314209ff23fSmrg
1315209ff23fSmrg    if (!post_div->divider) {
1316209ff23fSmrg	save->pll_output_freq_2 = freq;
1317209ff23fSmrg	post_div = &post_divs[0];
1318209ff23fSmrg    }
1319209ff23fSmrg
1320209ff23fSmrg    save->dot_clock_freq_2 = freq;
1321209ff23fSmrg    save->feedback_div_2   = feedback_div;
1322209ff23fSmrg    save->reference_div_2  = reference_div;
1323209ff23fSmrg    save->post_div_2       = post_divider;
1324209ff23fSmrg
1325209ff23fSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
1326209ff23fSmrg		   "dc=%u, of=%u, fd=%d, rd=%d, pd=%d\n",
1327209ff23fSmrg		   (unsigned)save->dot_clock_freq_2,
1328209ff23fSmrg		   (unsigned)save->pll_output_freq_2,
1329209ff23fSmrg		   save->feedback_div_2,
1330209ff23fSmrg		   save->reference_div_2,
1331209ff23fSmrg		   save->post_div_2);
1332209ff23fSmrg
1333209ff23fSmrg    save->p2pll_ref_div    = save->reference_div_2;
1334209ff23fSmrg
1335209ff23fSmrg    save->p2pll_div_0      = (save->feedback_div_2 |
1336209ff23fSmrg			      (post_div->bitvalue << 16));
1337209ff23fSmrg
1338209ff23fSmrg    save->htotal_cntl2     = mode->HTotal & 0x7;
1339209ff23fSmrg
1340209ff23fSmrg    save->pixclks_cntl     = ((info->SavedReg->pixclks_cntl &
1341209ff23fSmrg			       ~(RADEON_PIX2CLK_SRC_SEL_MASK)) |
1342209ff23fSmrg			      RADEON_PIX2CLK_SRC_SEL_P2PLLCLK);
1343209ff23fSmrg}
1344209ff23fSmrg
1345209ff23fSmrgstatic void
1346209ff23fSmrgradeon_update_tv_routing(ScrnInfoPtr pScrn, RADEONSavePtr restore)
1347209ff23fSmrg{
1348209ff23fSmrg    /* pixclks_cntl controls tv clock routing */
1349209ff23fSmrg    OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, restore->pixclks_cntl);
1350209ff23fSmrg}
1351209ff23fSmrg
1352209ff23fSmrg/* Calculate display buffer watermark to prevent buffer underflow */
1353b7e1c893Smrgvoid
1354b7e1c893SmrgRADEONInitDispBandwidthLegacy(ScrnInfoPtr pScrn,
1355b7e1c893Smrg			      DisplayModePtr mode1, int pixel_bytes1,
1356b7e1c893Smrg			      DisplayModePtr mode2, int pixel_bytes2)
1357209ff23fSmrg{
1358b7e1c893Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
1359209ff23fSmrg    RADEONEntPtr pRADEONEnt   = RADEONEntPriv(pScrn);
1360209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
1361209ff23fSmrg
1362209ff23fSmrg    uint32_t temp, data, mem_trcd, mem_trp, mem_tras, mem_trbs=0;
1363209ff23fSmrg    float mem_tcas;
1364209ff23fSmrg    int k1, c;
1365209ff23fSmrg
1366f1bc02b7Smrg    float MemTcas[8]  = {0, 1, 2, 3, 0, 1.5, 2.5, 0.0};
1367f1bc02b7Smrg    float MemTcas_rs480[8]  = {0, 1, 2, 3, 0, 1.5, 2.5, 3.5};
1368209ff23fSmrg    float MemTcas2[8] = {0, 1, 2, 3, 4, 5, 6, 7};
1369209ff23fSmrg    float MemTrbs[8]  = {1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5};
1370f1bc02b7Smrg    float MemTrbs_r4xx[8]  = {4, 5, 6, 7, 8, 9, 10, 11};
1371209ff23fSmrg
1372209ff23fSmrg    float mem_bw, peak_disp_bw;
1373209ff23fSmrg    float min_mem_eff = 0.8;
1374209ff23fSmrg    float sclk_eff, sclk_delay;
1375209ff23fSmrg    float mc_latency_mclk, mc_latency_sclk, cur_latency_mclk, cur_latency_sclk;
1376b7e1c893Smrg    float disp_latency, disp_latency_overhead, disp_drain_rate = 0, disp_drain_rate2;
1377209ff23fSmrg    float pix_clk, pix_clk2; /* in MHz */
1378209ff23fSmrg    int cur_size = 16;       /* in octawords */
1379b7e1c893Smrg    int critical_point = 0, critical_point2;
1380209ff23fSmrg    int stop_req, max_stop_req;
1381209ff23fSmrg    float read_return_rate, time_disp1_drop_priority;
1382209ff23fSmrg
1383209ff23fSmrg    /*
1384209ff23fSmrg     * Set display0/1 priority up on r3/4xx in the memory controller for
1385209ff23fSmrg     * high res modes if the user specifies HIGH for displaypriority
1386209ff23fSmrg     * option.
1387209ff23fSmrg     */
1388209ff23fSmrg    if ((info->DispPriority == 2) && IS_R300_VARIANT) {
1389209ff23fSmrg	uint32_t mc_init_misc_lat_timer = INREG(R300_MC_INIT_MISC_LAT_TIMER);
1390b7e1c893Smrg	mc_init_misc_lat_timer &= ~(R300_MC_DISP1R_INIT_LAT_MASK << R300_MC_DISP1R_INIT_LAT_SHIFT);
1391b7e1c893Smrg	mc_init_misc_lat_timer &= ~(R300_MC_DISP0R_INIT_LAT_MASK << R300_MC_DISP0R_INIT_LAT_SHIFT);
1392b7e1c893Smrg	if (pRADEONEnt->pCrtc[1]->enabled)
1393b7e1c893Smrg	    mc_init_misc_lat_timer |= (1 << R300_MC_DISP1R_INIT_LAT_SHIFT); /* display 1 */
1394b7e1c893Smrg	if (pRADEONEnt->pCrtc[0]->enabled)
1395b7e1c893Smrg	    mc_init_misc_lat_timer |= (1 << R300_MC_DISP0R_INIT_LAT_SHIFT); /* display 0 */
1396209ff23fSmrg	OUTREG(R300_MC_INIT_MISC_LAT_TIMER, mc_init_misc_lat_timer);
1397209ff23fSmrg    }
1398209ff23fSmrg
1399209ff23fSmrg    /*
1400209ff23fSmrg     * Determine if there is enough bandwidth for current display mode
1401209ff23fSmrg     */
1402209ff23fSmrg    mem_bw = info->mclk * (info->RamWidth / 8) * (info->IsDDR ? 2 : 1);
1403209ff23fSmrg
1404b7e1c893Smrg    pix_clk = 0;
1405b7e1c893Smrg    pix_clk2 = 0;
1406b7e1c893Smrg    peak_disp_bw = 0;
1407b7e1c893Smrg    if (mode1) {
1408b7e1c893Smrg	pix_clk = mode1->Clock/1000.0;
1409b7e1c893Smrg	peak_disp_bw += (pix_clk * pixel_bytes1);
1410b7e1c893Smrg    }
1411b7e1c893Smrg    if (mode2) {
1412209ff23fSmrg	pix_clk2 = mode2->Clock/1000.0;
1413b7e1c893Smrg	peak_disp_bw += (pix_clk2 * pixel_bytes2);
1414b7e1c893Smrg    }
1415209ff23fSmrg
1416209ff23fSmrg    if (peak_disp_bw >= mem_bw * min_mem_eff) {
1417209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1418209ff23fSmrg		   "You may not have enough display bandwidth for current mode\n"
1419209ff23fSmrg		   "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n");
1420209ff23fSmrg    }
1421209ff23fSmrg
1422209ff23fSmrg    /*  Get values from the EXT_MEM_CNTL register...converting its contents. */
1423209ff23fSmrg    temp = INREG(RADEON_MEM_TIMING_CNTL);
1424209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_RV100) || info->IsIGP) { /* RV100, M6, IGPs */
1425f1bc02b7Smrg	mem_trcd = ((temp >> 2) & 0x3) + 1;
1426f1bc02b7Smrg	mem_trp  = ((temp & 0x3)) + 1;
1427f1bc02b7Smrg	mem_tras = ((temp & 0x70) >> 4) + 1;
1428f1bc02b7Smrg    } else if (info->ChipFamily == CHIP_FAMILY_R300 ||
1429f1bc02b7Smrg	       info->ChipFamily == CHIP_FAMILY_R350) { /* r300, r350 */
1430f1bc02b7Smrg	mem_trcd = (temp & 0x7) + 1;
1431f1bc02b7Smrg	mem_trp = ((temp >> 8) & 0x7) + 1;
1432f1bc02b7Smrg	mem_tras = ((temp >> 11) & 0xf) + 4;
1433f1bc02b7Smrg    } else if (info->ChipFamily == CHIP_FAMILY_RV350 ||
1434f1bc02b7Smrg	       info->ChipFamily <= CHIP_FAMILY_RV380) {
1435f1bc02b7Smrg	/* rv3x0 */
1436f1bc02b7Smrg	mem_trcd = (temp & 0x7) + 3;
1437f1bc02b7Smrg	mem_trp = ((temp >> 8) & 0x7) + 3;
1438f1bc02b7Smrg	mem_tras = ((temp >> 11) & 0xf) + 6;
1439f1bc02b7Smrg    } else if (info->ChipFamily == CHIP_FAMILY_R420 ||
1440f1bc02b7Smrg	       info->ChipFamily == CHIP_FAMILY_RV410) {
1441f1bc02b7Smrg	/* r4xx */
1442f1bc02b7Smrg	mem_trcd = (temp & 0xf) + 3;
1443f1bc02b7Smrg	if (mem_trcd > 15)
1444f1bc02b7Smrg	    mem_trcd = 15;
1445f1bc02b7Smrg	mem_trp = ((temp >> 8) & 0xf) + 3;
1446f1bc02b7Smrg	if (mem_trp > 15)
1447f1bc02b7Smrg	    mem_trp = 15;
1448f1bc02b7Smrg	mem_tras = ((temp >> 12) & 0x1f) + 6;
1449f1bc02b7Smrg	if (mem_tras > 31)
1450f1bc02b7Smrg	    mem_tras = 31;
1451f1bc02b7Smrg    } else { /* RV200, R200 */
1452f1bc02b7Smrg	mem_trcd = (temp & 0x7) + 1;
1453f1bc02b7Smrg	mem_trp = ((temp >> 8) & 0x7) + 1;
1454f1bc02b7Smrg	mem_tras = ((temp >> 12) & 0xf) + 4;
1455209ff23fSmrg    }
1456209ff23fSmrg
1457209ff23fSmrg    /* Get values from the MEM_SDRAM_MODE_REG register...converting its */
1458209ff23fSmrg    temp = INREG(RADEON_MEM_SDRAM_MODE_REG);
1459209ff23fSmrg    data = (temp & (7<<20)) >> 20;
1460209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_RV100) || info->IsIGP) { /* RV100, M6, IGPs */
1461f1bc02b7Smrg	if (info->ChipFamily == CHIP_FAMILY_RS480) /* don't think rs400 */
1462f1bc02b7Smrg	    mem_tcas = MemTcas_rs480[data];
1463f1bc02b7Smrg	else
1464f1bc02b7Smrg	    mem_tcas = MemTcas[data];
1465209ff23fSmrg    } else {
1466209ff23fSmrg	mem_tcas = MemTcas2 [data];
1467209ff23fSmrg    }
1468f1bc02b7Smrg    if (info->ChipFamily == CHIP_FAMILY_RS400 ||
1469f1bc02b7Smrg	info->ChipFamily == CHIP_FAMILY_RS480) {
1470f1bc02b7Smrg	/* extra cas latency stored in bits 23-25 0-4 clocks */
1471f1bc02b7Smrg	data = (temp >> 23) & 0x7;
1472f1bc02b7Smrg	if (data < 5)
1473f1bc02b7Smrg	    mem_tcas += data;
1474f1bc02b7Smrg    }
1475209ff23fSmrg
1476f1bc02b7Smrg    if (IS_R300_VARIANT && !info->IsIGP) {
1477209ff23fSmrg	/* on the R300, Tcas is included in Trbs.
1478b7e1c893Smrg	 */
1479209ff23fSmrg	temp = INREG(RADEON_MEM_CNTL);
1480209ff23fSmrg	data = (R300_MEM_NUM_CHANNELS_MASK & temp);
1481209ff23fSmrg	if (data == 1) {
1482209ff23fSmrg	    if (R300_MEM_USE_CD_CH_ONLY & temp) {
1483209ff23fSmrg		temp  = INREG(R300_MC_IND_INDEX);
1484209ff23fSmrg		temp &= ~R300_MC_IND_ADDR_MASK;
1485209ff23fSmrg		temp |= R300_MC_READ_CNTL_CD_mcind;
1486209ff23fSmrg		OUTREG(R300_MC_IND_INDEX, temp);
1487209ff23fSmrg		temp  = INREG(R300_MC_IND_DATA);
1488209ff23fSmrg		data = (R300_MEM_RBS_POSITION_C_MASK & temp);
1489209ff23fSmrg	    } else {
1490209ff23fSmrg		temp = INREG(R300_MC_READ_CNTL_AB);
1491209ff23fSmrg		data = (R300_MEM_RBS_POSITION_A_MASK & temp);
1492209ff23fSmrg	    }
1493209ff23fSmrg	} else {
1494209ff23fSmrg	    temp = INREG(R300_MC_READ_CNTL_AB);
1495209ff23fSmrg	    data = (R300_MEM_RBS_POSITION_A_MASK & temp);
1496209ff23fSmrg	}
1497209ff23fSmrg
1498f1bc02b7Smrg	if (info->ChipFamily == CHIP_FAMILY_RV410 ||
1499f1bc02b7Smrg	    info->ChipFamily == CHIP_FAMILY_R420)
1500f1bc02b7Smrg	    mem_trbs = MemTrbs_r4xx[data];
1501f1bc02b7Smrg	else
1502f1bc02b7Smrg	    mem_trbs = MemTrbs[data];
1503209ff23fSmrg	mem_tcas += mem_trbs;
1504209ff23fSmrg    }
1505209ff23fSmrg
1506209ff23fSmrg    if ((info->ChipFamily == CHIP_FAMILY_RV100) || info->IsIGP) { /* RV100, M6, IGPs */
1507209ff23fSmrg	/* DDR64 SCLK_EFF = SCLK for analysis */
1508209ff23fSmrg	sclk_eff = info->sclk;
1509209ff23fSmrg    } else {
1510209ff23fSmrg#ifdef XF86DRI
1511209ff23fSmrg	if (info->directRenderingEnabled)
1512b7e1c893Smrg	    sclk_eff = info->sclk - (info->dri->agpMode * 50.0 / 3.0);
1513209ff23fSmrg	else
1514209ff23fSmrg#endif
1515209ff23fSmrg	    sclk_eff = info->sclk;
1516209ff23fSmrg    }
1517209ff23fSmrg
1518b7e1c893Smrg    /*
1519b7e1c893Smrg      Find the memory controller latency for the display client.
1520209ff23fSmrg    */
1521209ff23fSmrg    if (IS_R300_VARIANT) {
1522209ff23fSmrg	/*not enough for R350 ???*/
1523209ff23fSmrg	/*
1524209ff23fSmrg	if (!mode2) sclk_delay = 150;
1525209ff23fSmrg	else {
1526209ff23fSmrg	    if (info->RamWidth == 256) sclk_delay = 87;
1527209ff23fSmrg	    else sclk_delay = 97;
1528209ff23fSmrg	}
1529209ff23fSmrg	*/
1530209ff23fSmrg	sclk_delay = 250;
1531209ff23fSmrg    } else {
1532209ff23fSmrg	if ((info->ChipFamily == CHIP_FAMILY_RV100) ||
1533209ff23fSmrg	    info->IsIGP) {
1534209ff23fSmrg	    if (info->IsDDR) sclk_delay = 41;
1535209ff23fSmrg	    else sclk_delay = 33;
1536209ff23fSmrg	} else {
1537209ff23fSmrg	    if (info->RamWidth == 128) sclk_delay = 57;
1538209ff23fSmrg	    else sclk_delay = 41;
1539209ff23fSmrg	}
1540209ff23fSmrg    }
1541209ff23fSmrg
1542209ff23fSmrg    mc_latency_sclk = sclk_delay / sclk_eff;
1543209ff23fSmrg
1544209ff23fSmrg    if (info->IsDDR) {
1545209ff23fSmrg	if (info->RamWidth == 32) {
1546209ff23fSmrg	    k1 = 40;
1547209ff23fSmrg	    c  = 3;
1548209ff23fSmrg	} else {
1549209ff23fSmrg	    k1 = 20;
1550209ff23fSmrg	    c  = 1;
1551209ff23fSmrg	}
1552209ff23fSmrg    } else {
1553209ff23fSmrg	k1 = 40;
1554209ff23fSmrg	c  = 3;
1555209ff23fSmrg    }
1556209ff23fSmrg    mc_latency_mclk = ((2.0*mem_trcd + mem_tcas*c + 4.0*mem_tras + 4.0*mem_trp + k1) /
1557209ff23fSmrg		       info->mclk) + (4.0 / sclk_eff);
1558209ff23fSmrg
1559209ff23fSmrg    /*
1560209ff23fSmrg      HW cursor time assuming worst case of full size colour cursor.
1561209ff23fSmrg    */
1562209ff23fSmrg    cur_latency_mclk = (mem_trp + MAX(mem_tras, (mem_trcd + 2*(cur_size - (info->IsDDR+1))))) / info->mclk;
1563209ff23fSmrg    cur_latency_sclk = cur_size / sclk_eff;
1564209ff23fSmrg
1565209ff23fSmrg    /*
1566209ff23fSmrg      Find the total latency for the display data.
1567209ff23fSmrg    */
1568209ff23fSmrg    disp_latency_overhead = 8.0 / info->sclk;
1569209ff23fSmrg    mc_latency_mclk = mc_latency_mclk + disp_latency_overhead + cur_latency_mclk;
1570209ff23fSmrg    mc_latency_sclk = mc_latency_sclk + disp_latency_overhead + cur_latency_sclk;
1571209ff23fSmrg    disp_latency = MAX(mc_latency_mclk, mc_latency_sclk);
1572209ff23fSmrg
1573b7e1c893Smrg    /* setup Max GRPH_STOP_REQ default value */
1574b7e1c893Smrg    if (IS_RV100_VARIANT)
1575b7e1c893Smrg	max_stop_req = 0x5c;
1576209ff23fSmrg    else
1577b7e1c893Smrg	max_stop_req  = 0x7c;
1578209ff23fSmrg
1579b7e1c893Smrg    if (mode1) {
1580b7e1c893Smrg	/*  CRTC1
1581b7e1c893Smrg	    Set GRPH_BUFFER_CNTL register using h/w defined optimal values.
1582b7e1c893Smrg	    GRPH_STOP_REQ <= MIN[ 0x7C, (CRTC_H_DISP + 1) * (bit depth) / 0x10 ]
1583b7e1c893Smrg	*/
1584b7e1c893Smrg	stop_req = mode1->HDisplay * pixel_bytes1 / 16;
1585209ff23fSmrg
1586b7e1c893Smrg	if (stop_req > max_stop_req)
1587b7e1c893Smrg	    stop_req = max_stop_req;
1588209ff23fSmrg
1589b7e1c893Smrg	/*
1590b7e1c893Smrg	  Find the drain rate of the display buffer.
1591b7e1c893Smrg	*/
1592b7e1c893Smrg	disp_drain_rate = pix_clk / (16.0/pixel_bytes1);
1593209ff23fSmrg
1594b7e1c893Smrg	/*
1595b7e1c893Smrg	  Find the critical point of the display buffer.
1596b7e1c893Smrg	*/
1597b7e1c893Smrg	critical_point= (uint32_t)(disp_drain_rate * disp_latency + 0.5);
1598209ff23fSmrg
1599b7e1c893Smrg	/* ???? */
1600b7e1c893Smrg	/*
1601b7e1c893Smrg	  temp = (info->SavedReg.grph_buffer_cntl & RADEON_GRPH_CRITICAL_POINT_MASK) >> RADEON_GRPH_CRITICAL_POINT_SHIFT;
1602b7e1c893Smrg	  if (critical_point < temp) critical_point = temp;
1603b7e1c893Smrg	*/
1604b7e1c893Smrg	if (info->DispPriority == 2) {
1605b7e1c893Smrg	    critical_point = 0;
1606b7e1c893Smrg	}
1607209ff23fSmrg
1608b7e1c893Smrg	/*
1609b7e1c893Smrg	  The critical point should never be above max_stop_req-4.  Setting
1610b7e1c893Smrg	  GRPH_CRITICAL_CNTL = 0 will thus force high priority all the time.
1611b7e1c893Smrg	*/
1612b7e1c893Smrg	if (max_stop_req - critical_point < 4) critical_point = 0;
1613b7e1c893Smrg
1614b7e1c893Smrg	if (critical_point == 0 && mode2 && info->ChipFamily == CHIP_FAMILY_R300) {
1615b7e1c893Smrg	    /* some R300 cards have problem with this set to 0, when CRTC2 is enabled.*/
1616b7e1c893Smrg	    critical_point = 0x10;
1617b7e1c893Smrg	}
1618b7e1c893Smrg
1619b7e1c893Smrg	temp = info->SavedReg->grph_buffer_cntl;
1620b7e1c893Smrg	temp &= ~(RADEON_GRPH_STOP_REQ_MASK);
1621b7e1c893Smrg	temp |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT);
1622b7e1c893Smrg	temp &= ~(RADEON_GRPH_START_REQ_MASK);
1623b7e1c893Smrg	if ((info->ChipFamily == CHIP_FAMILY_R350) &&
1624b7e1c893Smrg	    (stop_req > 0x15)) {
1625b7e1c893Smrg	    stop_req -= 0x10;
1626b7e1c893Smrg	}
1627b7e1c893Smrg	temp |= (stop_req << RADEON_GRPH_START_REQ_SHIFT);
1628b7e1c893Smrg
1629b7e1c893Smrg	temp |= RADEON_GRPH_BUFFER_SIZE;
1630b7e1c893Smrg	temp &= ~(RADEON_GRPH_CRITICAL_CNTL   |
1631b7e1c893Smrg		  RADEON_GRPH_CRITICAL_AT_SOF |
1632b7e1c893Smrg		  RADEON_GRPH_STOP_CNTL);
1633b7e1c893Smrg	/*
1634b7e1c893Smrg	  Write the result into the register.
1635b7e1c893Smrg	*/
1636b7e1c893Smrg	OUTREG(RADEON_GRPH_BUFFER_CNTL, ((temp & ~RADEON_GRPH_CRITICAL_POINT_MASK) |
1637b7e1c893Smrg					 (critical_point << RADEON_GRPH_CRITICAL_POINT_SHIFT)));
1638209ff23fSmrg
1639209ff23fSmrg#if 0
1640b7e1c893Smrg	if ((info->ChipFamily == CHIP_FAMILY_RS400) ||
1641b7e1c893Smrg	    (info->ChipFamily == CHIP_FAMILY_RS480)) {
1642b7e1c893Smrg	    /* attempt to program RS400 disp regs correctly ??? */
1643b7e1c893Smrg	    temp = info->SavedReg->disp1_req_cntl1;
1644b7e1c893Smrg	    temp &= ~(RS400_DISP1_START_REQ_LEVEL_MASK |
1645b7e1c893Smrg		      RS400_DISP1_STOP_REQ_LEVEL_MASK);
1646b7e1c893Smrg	    OUTREG(RS400_DISP1_REQ_CNTL1, (temp |
1647b7e1c893Smrg					   (critical_point << RS400_DISP1_START_REQ_LEVEL_SHIFT) |
1648b7e1c893Smrg					   (critical_point << RS400_DISP1_STOP_REQ_LEVEL_SHIFT)));
1649b7e1c893Smrg	    temp = info->SavedReg->dmif_mem_cntl1;
1650b7e1c893Smrg	    temp &= ~(RS400_DISP1_CRITICAL_POINT_START_MASK |
1651b7e1c893Smrg		      RS400_DISP1_CRITICAL_POINT_STOP_MASK);
1652b7e1c893Smrg	    OUTREG(RS400_DMIF_MEM_CNTL1, (temp |
1653b7e1c893Smrg					  (critical_point << RS400_DISP1_CRITICAL_POINT_START_SHIFT) |
1654b7e1c893Smrg					  (critical_point << RS400_DISP1_CRITICAL_POINT_STOP_SHIFT)));
1655b7e1c893Smrg	}
1656209ff23fSmrg#endif
1657209ff23fSmrg
1658b7e1c893Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
1659b7e1c893Smrg		       "GRPH_BUFFER_CNTL from %x to %x\n",
1660b7e1c893Smrg		       (unsigned int)info->SavedReg->grph_buffer_cntl,
1661b7e1c893Smrg		       (unsigned int)INREG(RADEON_GRPH_BUFFER_CNTL));
1662b7e1c893Smrg    }
1663209ff23fSmrg
1664209ff23fSmrg    if (mode2) {
1665209ff23fSmrg	stop_req = mode2->HDisplay * pixel_bytes2 / 16;
1666209ff23fSmrg
1667209ff23fSmrg	if (stop_req > max_stop_req) stop_req = max_stop_req;
1668209ff23fSmrg
1669b7e1c893Smrg	/*
1670b7e1c893Smrg	  Find the drain rate of the display buffer.
1671b7e1c893Smrg	*/
1672b7e1c893Smrg	disp_drain_rate2 = pix_clk2 / (16.0/pixel_bytes2);
1673b7e1c893Smrg
1674209ff23fSmrg	temp = info->SavedReg->grph2_buffer_cntl;
1675209ff23fSmrg	temp &= ~(RADEON_GRPH_STOP_REQ_MASK);
1676209ff23fSmrg	temp |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT);
1677209ff23fSmrg	temp &= ~(RADEON_GRPH_START_REQ_MASK);
1678209ff23fSmrg	if ((info->ChipFamily == CHIP_FAMILY_R350) &&
1679209ff23fSmrg	    (stop_req > 0x15)) {
1680209ff23fSmrg	    stop_req -= 0x10;
1681209ff23fSmrg	}
1682209ff23fSmrg	temp |= (stop_req << RADEON_GRPH_START_REQ_SHIFT);
1683209ff23fSmrg	temp |= RADEON_GRPH_BUFFER_SIZE;
1684209ff23fSmrg	temp &= ~(RADEON_GRPH_CRITICAL_CNTL   |
1685209ff23fSmrg		  RADEON_GRPH_CRITICAL_AT_SOF |
1686209ff23fSmrg		  RADEON_GRPH_STOP_CNTL);
1687209ff23fSmrg
1688209ff23fSmrg	if ((info->ChipFamily == CHIP_FAMILY_RS100) ||
1689209ff23fSmrg	    (info->ChipFamily == CHIP_FAMILY_RS200))
1690209ff23fSmrg	    critical_point2 = 0;
1691209ff23fSmrg	else {
1692209ff23fSmrg	    read_return_rate = MIN(info->sclk, info->mclk*(info->RamWidth*(info->IsDDR+1)/128));
1693b7e1c893Smrg	    if (mode1)
1694b7e1c893Smrg		time_disp1_drop_priority = critical_point / (read_return_rate - disp_drain_rate);
1695b7e1c893Smrg	    else
1696b7e1c893Smrg		time_disp1_drop_priority = 0;
1697209ff23fSmrg
1698209ff23fSmrg	    critical_point2 = (uint32_t)((disp_latency + time_disp1_drop_priority +
1699209ff23fSmrg					disp_latency) * disp_drain_rate2 + 0.5);
1700209ff23fSmrg
1701209ff23fSmrg	    if (info->DispPriority == 2) {
1702209ff23fSmrg		critical_point2 = 0;
1703209ff23fSmrg	    }
1704209ff23fSmrg
1705209ff23fSmrg	    if (max_stop_req - critical_point2 < 4) critical_point2 = 0;
1706209ff23fSmrg
1707209ff23fSmrg	}
1708209ff23fSmrg
1709209ff23fSmrg	if (critical_point2 == 0 && info->ChipFamily == CHIP_FAMILY_R300) {
1710209ff23fSmrg	    /* some R300 cards have problem with this set to 0 */
1711209ff23fSmrg	    critical_point2 = 0x10;
1712209ff23fSmrg	}
1713209ff23fSmrg
1714209ff23fSmrg	OUTREG(RADEON_GRPH2_BUFFER_CNTL, ((temp & ~RADEON_GRPH_CRITICAL_POINT_MASK) |
1715209ff23fSmrg					  (critical_point2 << RADEON_GRPH_CRITICAL_POINT_SHIFT)));
1716209ff23fSmrg
1717209ff23fSmrg	if ((info->ChipFamily == CHIP_FAMILY_RS400) ||
1718209ff23fSmrg	    (info->ChipFamily == CHIP_FAMILY_RS480)) {
1719209ff23fSmrg#if 0
1720209ff23fSmrg	    /* attempt to program RS400 disp2 regs correctly ??? */
1721209ff23fSmrg	    temp = info->SavedReg->disp2_req_cntl1;
1722209ff23fSmrg	    temp &= ~(RS400_DISP2_START_REQ_LEVEL_MASK |
1723209ff23fSmrg		      RS400_DISP2_STOP_REQ_LEVEL_MASK);
1724209ff23fSmrg	    OUTREG(RS400_DISP2_REQ_CNTL1, (temp |
1725209ff23fSmrg					   (critical_point2 << RS400_DISP1_START_REQ_LEVEL_SHIFT) |
1726209ff23fSmrg					   (critical_point2 << RS400_DISP1_STOP_REQ_LEVEL_SHIFT)));
1727209ff23fSmrg	    temp = info->SavedReg->disp2_req_cntl2;
1728209ff23fSmrg	    temp &= ~(RS400_DISP2_CRITICAL_POINT_START_MASK |
1729209ff23fSmrg		      RS400_DISP2_CRITICAL_POINT_STOP_MASK);
1730209ff23fSmrg	    OUTREG(RS400_DISP2_REQ_CNTL2, (temp |
1731209ff23fSmrg					   (critical_point2 << RS400_DISP2_CRITICAL_POINT_START_SHIFT) |
1732209ff23fSmrg					   (critical_point2 << RS400_DISP2_CRITICAL_POINT_STOP_SHIFT)));
1733209ff23fSmrg#endif
1734209ff23fSmrg	    OUTREG(RS400_DISP2_REQ_CNTL1, 0x105DC1CC);
1735209ff23fSmrg	    OUTREG(RS400_DISP2_REQ_CNTL2, 0x2749D000);
1736209ff23fSmrg	    OUTREG(RS400_DMIF_MEM_CNTL1,  0x29CA71DC);
1737209ff23fSmrg	    OUTREG(RS400_DISP1_REQ_CNTL1, 0x28FBC3AC);
1738209ff23fSmrg	}
1739209ff23fSmrg
1740209ff23fSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
1741209ff23fSmrg		       "GRPH2_BUFFER_CNTL from %x to %x\n",
1742209ff23fSmrg		       (unsigned int)info->SavedReg->grph2_buffer_cntl,
1743209ff23fSmrg		       (unsigned int)INREG(RADEON_GRPH2_BUFFER_CNTL));
1744209ff23fSmrg    }
1745209ff23fSmrg}
1746209ff23fSmrg
1747209ff23fSmrgvoid
1748209ff23fSmrglegacy_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
1749209ff23fSmrg		     DisplayModePtr adjusted_mode, int x, int y)
1750209ff23fSmrg{
1751209ff23fSmrg    ScrnInfoPtr pScrn = crtc->scrn;
1752209ff23fSmrg    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1753209ff23fSmrg    RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
1754209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
1755209ff23fSmrg    int i = 0;
1756209ff23fSmrg    double dot_clock = 0;
1757b7e1c893Smrg    int pll_flags = RADEON_PLL_LEGACY;
1758209ff23fSmrg    Bool update_tv_routing = FALSE;
1759209ff23fSmrg    Bool tilingChanged = FALSE;
1760209ff23fSmrg
1761b7e1c893Smrg    if (adjusted_mode->Clock > 200000) /* range limits??? */
1762b7e1c893Smrg	pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
1763b7e1c893Smrg    else
1764b7e1c893Smrg	pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
1765b7e1c893Smrg
1766209ff23fSmrg    if (info->allowColorTiling) {
1767209ff23fSmrg	radeon_crtc->can_tile = (adjusted_mode->Flags & (V_DBLSCAN | V_INTERLACE)) ? FALSE : TRUE;
1768209ff23fSmrg	tilingChanged = RADEONSetTiling(pScrn);
1769209ff23fSmrg    }
1770209ff23fSmrg
1771209ff23fSmrg    for (i = 0; i < xf86_config->num_output; i++) {
1772209ff23fSmrg	xf86OutputPtr output = xf86_config->output[i];
1773209ff23fSmrg	RADEONOutputPrivatePtr radeon_output = output->driver_private;
1774209ff23fSmrg
1775209ff23fSmrg	if (output->crtc == crtc) {
1776b7e1c893Smrg	    if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT |
1777b7e1c893Smrg						ATOM_DEVICE_DFP_SUPPORT))
1778209ff23fSmrg		pll_flags |= RADEON_PLL_NO_ODD_POST_DIV;
1779b7e1c893Smrg	    if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT))
1780209ff23fSmrg		pll_flags |= (RADEON_PLL_USE_BIOS_DIVS | RADEON_PLL_USE_REF_DIV);
1781209ff23fSmrg	}
1782209ff23fSmrg    }
1783209ff23fSmrg
1784209ff23fSmrg
1785209ff23fSmrg    ErrorF("init memmap\n");
1786209ff23fSmrg    RADEONInitMemMapRegisters(pScrn, info->ModeReg, info);
1787209ff23fSmrg    ErrorF("init common\n");
1788209ff23fSmrg    RADEONInitCommonRegisters(info->ModeReg, info);
1789209ff23fSmrg
1790209ff23fSmrg    RADEONInitSurfaceCntl(crtc, info->ModeReg);
1791209ff23fSmrg
1792209ff23fSmrg    switch (radeon_crtc->crtc_id) {
1793209ff23fSmrg    case 0:
1794209ff23fSmrg	ErrorF("init crtc1\n");
1795209ff23fSmrg	RADEONInitCrtcRegisters(crtc, info->ModeReg, adjusted_mode);
1796209ff23fSmrg	RADEONInitCrtcBase(crtc, info->ModeReg, x, y);
1797209ff23fSmrg	dot_clock = adjusted_mode->Clock / 1000.0;
1798209ff23fSmrg	if (dot_clock) {
1799209ff23fSmrg	    ErrorF("init pll1\n");
1800209ff23fSmrg	    RADEONInitPLLRegisters(pScrn, info->ModeReg, &info->pll, adjusted_mode, pll_flags);
1801209ff23fSmrg	} else {
1802209ff23fSmrg	    info->ModeReg->ppll_ref_div = info->SavedReg->ppll_ref_div;
1803209ff23fSmrg	    info->ModeReg->ppll_div_3   = info->SavedReg->ppll_div_3;
1804209ff23fSmrg	    info->ModeReg->htotal_cntl  = info->SavedReg->htotal_cntl;
1805209ff23fSmrg	}
1806209ff23fSmrg	break;
1807209ff23fSmrg    case 1:
1808209ff23fSmrg	ErrorF("init crtc2\n");
1809209ff23fSmrg	RADEONInitCrtc2Registers(crtc, info->ModeReg, adjusted_mode);
1810209ff23fSmrg	RADEONInitCrtc2Base(crtc, info->ModeReg, x, y);
1811209ff23fSmrg	dot_clock = adjusted_mode->Clock / 1000.0;
1812209ff23fSmrg	if (dot_clock) {
1813209ff23fSmrg	    ErrorF("init pll2\n");
1814209ff23fSmrg	    RADEONInitPLL2Registers(pScrn, info->ModeReg, &info->pll, adjusted_mode, pll_flags);
1815209ff23fSmrg	}
1816209ff23fSmrg	break;
1817209ff23fSmrg    }
1818209ff23fSmrg
1819209ff23fSmrg    for (i = 0; i < xf86_config->num_output; i++) {
1820209ff23fSmrg	xf86OutputPtr output = xf86_config->output[i];
1821209ff23fSmrg	RADEONOutputPrivatePtr radeon_output = output->driver_private;
1822209ff23fSmrg
1823209ff23fSmrg	if (output->crtc == crtc) {
1824b7e1c893Smrg	    if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
1825209ff23fSmrg		switch (radeon_crtc->crtc_id) {
1826209ff23fSmrg		case 0:
1827209ff23fSmrg		    RADEONAdjustCrtcRegistersForTV(pScrn, info->ModeReg, adjusted_mode, output);
1828209ff23fSmrg		    RADEONAdjustPLLRegistersForTV(pScrn, info->ModeReg, adjusted_mode, output);
1829209ff23fSmrg		    update_tv_routing = TRUE;
1830209ff23fSmrg		    break;
1831209ff23fSmrg		case 1:
1832209ff23fSmrg		    RADEONAdjustCrtc2RegistersForTV(pScrn, info->ModeReg, adjusted_mode, output);
1833209ff23fSmrg		    RADEONAdjustPLL2RegistersForTV(pScrn, info->ModeReg, adjusted_mode, output);
1834209ff23fSmrg		    break;
1835209ff23fSmrg		}
1836209ff23fSmrg	    }
1837209ff23fSmrg	}
1838209ff23fSmrg    }
1839209ff23fSmrg
1840209ff23fSmrg    ErrorF("restore memmap\n");
1841209ff23fSmrg    RADEONRestoreMemMapRegisters(pScrn, info->ModeReg);
1842209ff23fSmrg    ErrorF("restore common\n");
1843209ff23fSmrg    RADEONRestoreCommonRegisters(pScrn, info->ModeReg);
1844209ff23fSmrg
1845209ff23fSmrg    switch (radeon_crtc->crtc_id) {
1846209ff23fSmrg    case 0:
1847209ff23fSmrg	ErrorF("restore crtc1\n");
1848209ff23fSmrg	RADEONRestoreCrtcRegisters(pScrn, info->ModeReg);
1849209ff23fSmrg	ErrorF("restore pll1\n");
1850209ff23fSmrg	RADEONRestorePLLRegisters(pScrn, info->ModeReg);
1851209ff23fSmrg	break;
1852209ff23fSmrg    case 1:
1853209ff23fSmrg	ErrorF("restore crtc2\n");
1854209ff23fSmrg	RADEONRestoreCrtc2Registers(pScrn, info->ModeReg);
1855209ff23fSmrg	ErrorF("restore pll2\n");
1856209ff23fSmrg	RADEONRestorePLL2Registers(pScrn, info->ModeReg);
1857209ff23fSmrg	break;
1858209ff23fSmrg    }
1859209ff23fSmrg
1860209ff23fSmrg    /* pixclks_cntl handles tv-out clock routing */
1861209ff23fSmrg    if (update_tv_routing)
1862209ff23fSmrg	radeon_update_tv_routing(pScrn, info->ModeReg);
1863209ff23fSmrg
1864209ff23fSmrg    if (info->DispPriority)
1865b7e1c893Smrg	RADEONInitDispBandwidth(pScrn);
1866b7e1c893Smrg
1867b7e1c893Smrg    radeon_crtc->initialized = TRUE;
1868209ff23fSmrg
1869209ff23fSmrg    if (tilingChanged) {
1870209ff23fSmrg	/* need to redraw front buffer, I guess this can be considered a hack ? */
1871209ff23fSmrg	/* if this is called during ScreenInit() we don't have pScrn->pScreen yet */
1872209ff23fSmrg	if (pScrn->pScreen)
1873209ff23fSmrg	    xf86EnableDisableFBAccess(pScrn->scrnIndex, FALSE);
1874209ff23fSmrg	RADEONChangeSurfaces(pScrn);
1875209ff23fSmrg	if (pScrn->pScreen)
1876209ff23fSmrg	    xf86EnableDisableFBAccess(pScrn->scrnIndex, TRUE);
1877209ff23fSmrg	/* xf86SetRootClip would do, but can't access that here */
1878209ff23fSmrg    }
1879209ff23fSmrg
1880209ff23fSmrg    /* reset ecp_div for Xv */
1881209ff23fSmrg    info->ecp_div = -1;
1882209ff23fSmrg
1883209ff23fSmrg}
1884209ff23fSmrg
1885