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