atidsp.c revision 32b578d3
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 */
38Bool
39ATIDSPPreInit
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 */
182void
183ATIDSPSave
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 */
204void
205ATIDSPCalculate
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 */
293void
294ATIDSPSet
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