1 /*
2 * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of Marc Aurele La France not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. Marc Aurele La France makes no representations
11 * about the suitability of this software for any purpose. It is provided
12 * "as-is" without express or implied warranty.
13 *
14 * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
16 * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include "ati.h"
27 #include "atichip.h"
28 #include "atidsp.h"
29 #include "atimach64io.h"
30 #include "atividmem.h"
31
32 /*
33 * ATIDSPPreInit --
34 *
35 * This function initialises global variables used to set DSP registers on a
36 * VT-B or later.
37 */
38 Bool
ATIDSPPreInit(int iScreen,ATIPtr pATI)39 ATIDSPPreInit
40 (
41 int iScreen,
42 ATIPtr pATI
43 )
44 {
45 CARD32 IOValue, dsp_config, dsp_on_off, vga_dsp_config, vga_dsp_on_off;
46 int trp;
47
48 /*
49 * VT-B's and later have additional post-dividers that are not powers of
50 * two.
51 */
52 pATI->ClockDescriptor.NumD = 8;
53
54 /* Retrieve XCLK settings */
55 IOValue = ATIMach64GetPLLReg(PLL_XCLK_CNTL);
56 pATI->XCLKPostDivider = GetBits(IOValue, PLL_XCLK_SRC_SEL);
57 pATI->XCLKReferenceDivider = 1;
58 switch (pATI->XCLKPostDivider)
59 {
60 case 0: case 1: case 2: case 3:
61 break;
62
63 case 4:
64 pATI->XCLKReferenceDivider = 3;
65 pATI->XCLKPostDivider = 0;
66 break;
67
68 default:
69 xf86DrvMsg(iScreen, X_ERROR,
70 "Unsupported XCLK source: %d.\n", pATI->XCLKPostDivider);
71 return FALSE;
72 }
73
74 pATI->XCLKPostDivider -= GetBits(IOValue, PLL_MFB_TIMES_4_2B);
75 pATI->XCLKFeedbackDivider = ATIMach64GetPLLReg(PLL_MCLK_FB_DIV);
76
77 xf86DrvMsgVerb(iScreen, X_INFO, 2,
78 "Engine XCLK %.3f MHz; Refresh rate code %ld.\n",
79 ATIDivide(pATI->XCLKFeedbackDivider * pATI->ReferenceNumerator,
80 pATI->XCLKReferenceDivider * pATI->ClockDescriptor.MaxM *
81 pATI->ReferenceDenominator, 1 - pATI->XCLKPostDivider, 0) /
82 (double)1000.0,
83 GetBits(pATI->LockData.mem_cntl, CTL_MEM_REFRESH_RATE_B));
84
85 /* Compute maximum RAS delay and friends */
86 trp = GetBits(pATI->LockData.mem_cntl, CTL_MEM_TRP);
87 pATI->XCLKPageFaultDelay = GetBits(pATI->LockData.mem_cntl, CTL_MEM_TRCD) +
88 GetBits(pATI->LockData.mem_cntl, CTL_MEM_TCRD) + trp + 2;
89 pATI->XCLKMaxRASDelay = GetBits(pATI->LockData.mem_cntl, CTL_MEM_TRAS) +
90 trp + 2;
91 pATI->DisplayFIFODepth = 32;
92
93 if (pATI->Chip < ATI_CHIP_264VT4)
94 {
95 pATI->XCLKPageFaultDelay += 2;
96 pATI->XCLKMaxRASDelay += 3;
97 pATI->DisplayFIFODepth = 24;
98 }
99
100 switch (pATI->MemoryType)
101 {
102 case MEM_264_DRAM:
103 if (pATI->VideoRAM <= 1024)
104 {
105 pATI->DisplayLoopLatency = 10;
106 }
107 else
108 {
109 pATI->DisplayLoopLatency = 8;
110 pATI->XCLKPageFaultDelay += 2;
111 }
112 break;
113
114 case MEM_264_EDO:
115 case MEM_264_PSEUDO_EDO:
116 if (pATI->VideoRAM <= 1024)
117 {
118 pATI->DisplayLoopLatency = 9;
119 }
120 else
121 {
122 pATI->DisplayLoopLatency = 8;
123 pATI->XCLKPageFaultDelay++;
124 }
125 break;
126
127 case MEM_264_SDRAM:
128 if (pATI->VideoRAM <= 1024)
129 {
130 pATI->DisplayLoopLatency = 11;
131 }
132 else
133 {
134 pATI->DisplayLoopLatency = 10;
135 pATI->XCLKPageFaultDelay++;
136 }
137 break;
138
139 case MEM_264_SGRAM:
140 pATI->DisplayLoopLatency = 8;
141 pATI->XCLKPageFaultDelay += 3;
142 break;
143
144 default: /* Set maximums */
145 pATI->DisplayLoopLatency = 11;
146 pATI->XCLKPageFaultDelay += 3;
147 break;
148 }
149
150 if (pATI->XCLKMaxRASDelay <= pATI->XCLKPageFaultDelay)
151 pATI->XCLKMaxRASDelay = pATI->XCLKPageFaultDelay + 1;
152
153 /* Allow BIOS to override */
154 dsp_config = inr(DSP_CONFIG);
155 dsp_on_off = inr(DSP_ON_OFF);
156 vga_dsp_config = inr(VGA_DSP_CONFIG);
157 vga_dsp_on_off = inr(VGA_DSP_ON_OFF);
158
159 if (dsp_config)
160 pATI->DisplayLoopLatency = GetBits(dsp_config, DSP_LOOP_LATENCY);
161
162 if ((!dsp_on_off && (pATI->Chip < ATI_CHIP_264GTPRO)) ||
163 ((dsp_on_off == vga_dsp_on_off) &&
164 (!dsp_config || !((dsp_config ^ vga_dsp_config) & DSP_XCLKS_PER_QW))))
165 {
166 if (ATIDivide(GetBits(vga_dsp_on_off, VGA_DSP_OFF),
167 GetBits(vga_dsp_config, VGA_DSP_XCLKS_PER_QW), 5, 1) > 24)
168 pATI->DisplayFIFODepth = 32;
169 else
170 pATI->DisplayFIFODepth = 24;
171 }
172
173 return TRUE;
174 }
175
176 /*
177 * ATIDSPSave --
178 *
179 * This function is called to remember DSP register values on VT-B and later
180 * controllers.
181 */
182 void
ATIDSPSave(ATIPtr pATI,ATIHWPtr pATIHW)183 ATIDSPSave
184 (
185 ATIPtr pATI,
186 ATIHWPtr pATIHW
187 )
188 {
189 pATIHW->dsp_on_off = inr(DSP_ON_OFF);
190 pATIHW->dsp_config = inr(DSP_CONFIG);
191 }
192
193
194 /*
195 * ATIDSPCalculate --
196 *
197 * This function sets up DSP register values for a VTB or later. Note that
198 * this would be slightly different if VCLK 0 or 1 were used for the mode
199 * instead. In that case, this function would set VGA_DSP_CONFIG and
200 * VGA_DSP_ON_OFF, would have to zero out DSP_CONFIG and DSP_ON_OFF, and would
201 * have to consider that VGA_DSP_CONFIG is partitioned slightly differently
202 * than DSP_CONFIG.
203 */
204 void
ATIDSPCalculate(ATIPtr pATI,ATIHWPtr pATIHW,DisplayModePtr pMode)205 ATIDSPCalculate
206 (
207 ATIPtr pATI,
208 ATIHWPtr pATIHW,
209 DisplayModePtr pMode
210 )
211 {
212 int Multiplier, Divider;
213 int RASMultiplier = pATI->XCLKMaxRASDelay, RASDivider = 1;
214 int dsp_precision, dsp_on, dsp_off, dsp_xclks;
215 int tmp, vshift, xshift;
216
217 # define Maximum_DSP_PRECISION ((int)MaxBits(DSP_PRECISION))
218
219 /* Compute a memory-to-screen bandwidth ratio */
220 Multiplier = pATI->XCLKFeedbackDivider *
221 pATI->ClockDescriptor.PostDividers[pATIHW->PostDivider];
222 Divider = pATIHW->FeedbackDivider * pATI->XCLKReferenceDivider;
223
224 {
225 Divider *= pATI->bitsPerPixel / 4;
226 }
227
228 /* Start by assuming a display FIFO width of 64 bits */
229 vshift = (6 - 2) - pATI->XCLKPostDivider;
230
231 if (pATI->OptionPanelDisplay && (pATI->LCDPanelID >= 0))
232 {
233 /* Compensate for horizontal stretching */
234 Multiplier *= pATI->LCDHorizontal;
235 Divider *= pMode->HDisplay & ~7;
236
237 RASMultiplier *= pATI->LCDHorizontal;
238 RASDivider *= pMode->HDisplay & ~7;
239 }
240
241 /* Determine dsp_precision first */
242 tmp = ATIDivide(Multiplier * pATI->DisplayFIFODepth, Divider, vshift, -1);
243 for (dsp_precision = -5; tmp; dsp_precision++)
244 tmp >>= 1;
245 if (dsp_precision < 0)
246 dsp_precision = 0;
247 else if (dsp_precision > Maximum_DSP_PRECISION)
248 dsp_precision = Maximum_DSP_PRECISION;
249
250 xshift = 6 - dsp_precision;
251 vshift += xshift;
252
253 /* Move on to dsp_off */
254 dsp_off = ATIDivide(Multiplier * (pATI->DisplayFIFODepth - 1), Divider,
255 vshift, -1) - ATIDivide(1, 1, vshift - xshift, 1);
256
257 /* Next is dsp_on */
258 {
259 dsp_on = ATIDivide(Multiplier, Divider, vshift, 1);
260 tmp = ATIDivide(RASMultiplier, RASDivider, xshift, 1);
261 if (dsp_on < tmp)
262 dsp_on = tmp;
263 dsp_on += (tmp * 2) +
264 ATIDivide(pATI->XCLKPageFaultDelay, 1, xshift, 1);
265 }
266
267 /* Calculate rounding factor and apply it to dsp_on */
268 tmp = ((1 << (Maximum_DSP_PRECISION - dsp_precision)) - 1) >> 1;
269 dsp_on = ((dsp_on + tmp) / (tmp + 1)) * (tmp + 1);
270
271 if (dsp_on >= ((dsp_off / (tmp + 1)) * (tmp + 1)))
272 {
273 dsp_on = dsp_off - ATIDivide(Multiplier, Divider, vshift, -1);
274 dsp_on = (dsp_on / (tmp + 1)) * (tmp + 1);
275 }
276
277 /* Last but not least: dsp_xclks */
278 dsp_xclks = ATIDivide(Multiplier, Divider, vshift + 5, 1);
279
280 /* Build DSP register contents */
281 pATIHW->dsp_on_off = SetBits(dsp_on, DSP_ON) |
282 SetBits(dsp_off, DSP_OFF);
283 pATIHW->dsp_config = SetBits(dsp_precision, DSP_PRECISION) |
284 SetBits(dsp_xclks, DSP_XCLKS_PER_QW) |
285 SetBits(pATI->DisplayLoopLatency, DSP_LOOP_LATENCY);
286 }
287
288 /*
289 * ATIDSPSet --
290 *
291 * This function is called to set DSP registers on VT-B and later controllers.
292 */
293 void
ATIDSPSet(ATIPtr pATI,ATIHWPtr pATIHW)294 ATIDSPSet
295 (
296 ATIPtr pATI,
297 ATIHWPtr pATIHW
298 )
299 {
300 outr(DSP_ON_OFF, pATIHW->dsp_on_off);
301 outr(DSP_CONFIG, pATIHW->dsp_config);
302 }
303