atidsp.c revision 32b578d3
132b578d3Smrg/*
232b578d3Smrg * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
332b578d3Smrg *
432b578d3Smrg * Permission to use, copy, modify, distribute, and sell this software and its
532b578d3Smrg * documentation for any purpose is hereby granted without fee, provided that
632b578d3Smrg * the above copyright notice appear in all copies and that both that copyright
732b578d3Smrg * notice and this permission notice appear in supporting documentation, and
832b578d3Smrg * that the name of Marc Aurele La France not be used in advertising or
932b578d3Smrg * publicity pertaining to distribution of the software without specific,
1032b578d3Smrg * written prior permission.  Marc Aurele La France makes no representations
1132b578d3Smrg * about the suitability of this software for any purpose.  It is provided
1232b578d3Smrg * "as-is" without express or implied warranty.
1332b578d3Smrg *
1432b578d3Smrg * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1532b578d3Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO
1632b578d3Smrg * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1732b578d3Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1832b578d3Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1932b578d3Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2032b578d3Smrg * PERFORMANCE OF THIS SOFTWARE.
2132b578d3Smrg */
2232b578d3Smrg
2332b578d3Smrg#ifdef HAVE_CONFIG_H
2432b578d3Smrg#include "config.h"
2532b578d3Smrg#endif
2632b578d3Smrg#include "ati.h"
2732b578d3Smrg#include "atichip.h"
2832b578d3Smrg#include "atidsp.h"
2932b578d3Smrg#include "atimach64io.h"
3032b578d3Smrg#include "atividmem.h"
3132b578d3Smrg
3232b578d3Smrg/*
3332b578d3Smrg * ATIDSPPreInit --
3432b578d3Smrg *
3532b578d3Smrg * This function initialises global variables used to set DSP registers on a
3632b578d3Smrg * VT-B or later.
3732b578d3Smrg */
3832b578d3SmrgBool
3932b578d3SmrgATIDSPPreInit
4032b578d3Smrg(
4132b578d3Smrg    int    iScreen,
4232b578d3Smrg    ATIPtr pATI
4332b578d3Smrg)
4432b578d3Smrg{
4532b578d3Smrg    CARD32 IOValue, dsp_config, dsp_on_off, vga_dsp_config, vga_dsp_on_off;
4632b578d3Smrg    int trp;
4732b578d3Smrg
4832b578d3Smrg    /*
4932b578d3Smrg     * VT-B's and later have additional post-dividers that are not powers of
5032b578d3Smrg     * two.
5132b578d3Smrg     */
5232b578d3Smrg    pATI->ClockDescriptor.NumD = 8;
5332b578d3Smrg
5432b578d3Smrg    /* Retrieve XCLK settings */
5532b578d3Smrg    IOValue = ATIMach64GetPLLReg(PLL_XCLK_CNTL);
5632b578d3Smrg    pATI->XCLKPostDivider = GetBits(IOValue, PLL_XCLK_SRC_SEL);
5732b578d3Smrg    pATI->XCLKReferenceDivider = 1;
5832b578d3Smrg    switch (pATI->XCLKPostDivider)
5932b578d3Smrg    {
6032b578d3Smrg        case 0:  case 1:  case 2:  case 3:
6132b578d3Smrg            break;
6232b578d3Smrg
6332b578d3Smrg        case 4:
6432b578d3Smrg            pATI->XCLKReferenceDivider = 3;
6532b578d3Smrg            pATI->XCLKPostDivider = 0;
6632b578d3Smrg            break;
6732b578d3Smrg
6832b578d3Smrg        default:
6932b578d3Smrg            xf86DrvMsg(iScreen, X_ERROR,
7032b578d3Smrg                "Unsupported XCLK source:  %d.\n", pATI->XCLKPostDivider);
7132b578d3Smrg            return FALSE;
7232b578d3Smrg    }
7332b578d3Smrg
7432b578d3Smrg    pATI->XCLKPostDivider -= GetBits(IOValue, PLL_MFB_TIMES_4_2B);
7532b578d3Smrg    pATI->XCLKFeedbackDivider = ATIMach64GetPLLReg(PLL_MCLK_FB_DIV);
7632b578d3Smrg
7732b578d3Smrg    xf86DrvMsgVerb(iScreen, X_INFO, 2,
7832b578d3Smrg        "Engine XCLK %.3f MHz;  Refresh rate code %ld.\n",
7932b578d3Smrg        ATIDivide(pATI->XCLKFeedbackDivider * pATI->ReferenceNumerator,
8032b578d3Smrg                  pATI->XCLKReferenceDivider * pATI->ClockDescriptor.MaxM *
8132b578d3Smrg                  pATI->ReferenceDenominator, 1 - pATI->XCLKPostDivider, 0) /
8232b578d3Smrg        (double)1000.0,
8332b578d3Smrg        GetBits(pATI->LockData.mem_cntl, CTL_MEM_REFRESH_RATE_B));
8432b578d3Smrg
8532b578d3Smrg    /* Compute maximum RAS delay and friends */
8632b578d3Smrg    trp = GetBits(pATI->LockData.mem_cntl, CTL_MEM_TRP);
8732b578d3Smrg    pATI->XCLKPageFaultDelay = GetBits(pATI->LockData.mem_cntl, CTL_MEM_TRCD) +
8832b578d3Smrg        GetBits(pATI->LockData.mem_cntl, CTL_MEM_TCRD) + trp + 2;
8932b578d3Smrg    pATI->XCLKMaxRASDelay = GetBits(pATI->LockData.mem_cntl, CTL_MEM_TRAS) +
9032b578d3Smrg        trp + 2;
9132b578d3Smrg    pATI->DisplayFIFODepth = 32;
9232b578d3Smrg
9332b578d3Smrg    if (pATI->Chip < ATI_CHIP_264VT4)
9432b578d3Smrg    {
9532b578d3Smrg        pATI->XCLKPageFaultDelay += 2;
9632b578d3Smrg        pATI->XCLKMaxRASDelay += 3;
9732b578d3Smrg        pATI->DisplayFIFODepth = 24;
9832b578d3Smrg    }
9932b578d3Smrg
10032b578d3Smrg    switch (pATI->MemoryType)
10132b578d3Smrg    {
10232b578d3Smrg        case MEM_264_DRAM:
10332b578d3Smrg            if (pATI->VideoRAM <= 1024)
10432b578d3Smrg            {
10532b578d3Smrg                pATI->DisplayLoopLatency = 10;
10632b578d3Smrg            }
10732b578d3Smrg            else
10832b578d3Smrg            {
10932b578d3Smrg                pATI->DisplayLoopLatency = 8;
11032b578d3Smrg                pATI->XCLKPageFaultDelay += 2;
11132b578d3Smrg            }
11232b578d3Smrg            break;
11332b578d3Smrg
11432b578d3Smrg        case MEM_264_EDO:
11532b578d3Smrg        case MEM_264_PSEUDO_EDO:
11632b578d3Smrg            if (pATI->VideoRAM <= 1024)
11732b578d3Smrg            {
11832b578d3Smrg                pATI->DisplayLoopLatency = 9;
11932b578d3Smrg            }
12032b578d3Smrg            else
12132b578d3Smrg            {
12232b578d3Smrg                pATI->DisplayLoopLatency = 8;
12332b578d3Smrg                pATI->XCLKPageFaultDelay++;
12432b578d3Smrg            }
12532b578d3Smrg            break;
12632b578d3Smrg
12732b578d3Smrg        case MEM_264_SDRAM:
12832b578d3Smrg            if (pATI->VideoRAM <= 1024)
12932b578d3Smrg            {
13032b578d3Smrg                pATI->DisplayLoopLatency = 11;
13132b578d3Smrg            }
13232b578d3Smrg            else
13332b578d3Smrg            {
13432b578d3Smrg                pATI->DisplayLoopLatency = 10;
13532b578d3Smrg                pATI->XCLKPageFaultDelay++;
13632b578d3Smrg            }
13732b578d3Smrg            break;
13832b578d3Smrg
13932b578d3Smrg        case MEM_264_SGRAM:
14032b578d3Smrg            pATI->DisplayLoopLatency = 8;
14132b578d3Smrg            pATI->XCLKPageFaultDelay += 3;
14232b578d3Smrg            break;
14332b578d3Smrg
14432b578d3Smrg        default:                /* Set maximums */
14532b578d3Smrg            pATI->DisplayLoopLatency = 11;
14632b578d3Smrg            pATI->XCLKPageFaultDelay += 3;
14732b578d3Smrg            break;
14832b578d3Smrg    }
14932b578d3Smrg
15032b578d3Smrg    if (pATI->XCLKMaxRASDelay <= pATI->XCLKPageFaultDelay)
15132b578d3Smrg        pATI->XCLKMaxRASDelay = pATI->XCLKPageFaultDelay + 1;
15232b578d3Smrg
15332b578d3Smrg    /* Allow BIOS to override */
15432b578d3Smrg    dsp_config = inr(DSP_CONFIG);
15532b578d3Smrg    dsp_on_off = inr(DSP_ON_OFF);
15632b578d3Smrg    vga_dsp_config = inr(VGA_DSP_CONFIG);
15732b578d3Smrg    vga_dsp_on_off = inr(VGA_DSP_ON_OFF);
15832b578d3Smrg
15932b578d3Smrg    if (dsp_config)
16032b578d3Smrg        pATI->DisplayLoopLatency = GetBits(dsp_config, DSP_LOOP_LATENCY);
16132b578d3Smrg
16232b578d3Smrg    if ((!dsp_on_off && (pATI->Chip < ATI_CHIP_264GTPRO)) ||
16332b578d3Smrg        ((dsp_on_off == vga_dsp_on_off) &&
16432b578d3Smrg         (!dsp_config || !((dsp_config ^ vga_dsp_config) & DSP_XCLKS_PER_QW))))
16532b578d3Smrg    {
16632b578d3Smrg        if (ATIDivide(GetBits(vga_dsp_on_off, VGA_DSP_OFF),
16732b578d3Smrg                      GetBits(vga_dsp_config, VGA_DSP_XCLKS_PER_QW), 5, 1) > 24)
16832b578d3Smrg            pATI->DisplayFIFODepth = 32;
16932b578d3Smrg        else
17032b578d3Smrg            pATI->DisplayFIFODepth = 24;
17132b578d3Smrg    }
17232b578d3Smrg
17332b578d3Smrg    return TRUE;
17432b578d3Smrg}
17532b578d3Smrg
17632b578d3Smrg/*
17732b578d3Smrg * ATIDSPSave --
17832b578d3Smrg *
17932b578d3Smrg * This function is called to remember DSP register values on VT-B and later
18032b578d3Smrg * controllers.
18132b578d3Smrg */
18232b578d3Smrgvoid
18332b578d3SmrgATIDSPSave
18432b578d3Smrg(
18532b578d3Smrg    ATIPtr   pATI,
18632b578d3Smrg    ATIHWPtr pATIHW
18732b578d3Smrg)
18832b578d3Smrg{
18932b578d3Smrg    pATIHW->dsp_on_off = inr(DSP_ON_OFF);
19032b578d3Smrg    pATIHW->dsp_config = inr(DSP_CONFIG);
19132b578d3Smrg}
19232b578d3Smrg
19332b578d3Smrg
19432b578d3Smrg/*
19532b578d3Smrg * ATIDSPCalculate --
19632b578d3Smrg *
19732b578d3Smrg * This function sets up DSP register values for a VTB or later.  Note that
19832b578d3Smrg * this would be slightly different if VCLK 0 or 1 were used for the mode
19932b578d3Smrg * instead.  In that case, this function would set VGA_DSP_CONFIG and
20032b578d3Smrg * VGA_DSP_ON_OFF, would have to zero out DSP_CONFIG and DSP_ON_OFF, and would
20132b578d3Smrg * have to consider that VGA_DSP_CONFIG is partitioned slightly differently
20232b578d3Smrg * than DSP_CONFIG.
20332b578d3Smrg */
20432b578d3Smrgvoid
20532b578d3SmrgATIDSPCalculate
20632b578d3Smrg(
20732b578d3Smrg    ATIPtr         pATI,
20832b578d3Smrg    ATIHWPtr       pATIHW,
20932b578d3Smrg    DisplayModePtr pMode
21032b578d3Smrg)
21132b578d3Smrg{
21232b578d3Smrg    int Multiplier, Divider;
21332b578d3Smrg    int RASMultiplier = pATI->XCLKMaxRASDelay, RASDivider = 1;
21432b578d3Smrg    int dsp_precision, dsp_on, dsp_off, dsp_xclks;
21532b578d3Smrg    int tmp, vshift, xshift;
21632b578d3Smrg
21732b578d3Smrg#   define Maximum_DSP_PRECISION ((int)MaxBits(DSP_PRECISION))
21832b578d3Smrg
21932b578d3Smrg    /* Compute a memory-to-screen bandwidth ratio */
22032b578d3Smrg    Multiplier = pATI->XCLKFeedbackDivider *
22132b578d3Smrg        pATI->ClockDescriptor.PostDividers[pATIHW->PostDivider];
22232b578d3Smrg    Divider = pATIHW->FeedbackDivider * pATI->XCLKReferenceDivider;
22332b578d3Smrg
22432b578d3Smrg    {
22532b578d3Smrg        Divider *= pATI->bitsPerPixel / 4;
22632b578d3Smrg    }
22732b578d3Smrg
22832b578d3Smrg    /* Start by assuming a display FIFO width of 64 bits */
22932b578d3Smrg    vshift = (6 - 2) - pATI->XCLKPostDivider;
23032b578d3Smrg
23132b578d3Smrg    if (pATI->OptionPanelDisplay && (pATI->LCDPanelID >= 0))
23232b578d3Smrg    {
23332b578d3Smrg        /* Compensate for horizontal stretching */
23432b578d3Smrg        Multiplier *= pATI->LCDHorizontal;
23532b578d3Smrg        Divider *= pMode->HDisplay & ~7;
23632b578d3Smrg
23732b578d3Smrg        RASMultiplier *= pATI->LCDHorizontal;
23832b578d3Smrg        RASDivider *= pMode->HDisplay & ~7;
23932b578d3Smrg    }
24032b578d3Smrg
24132b578d3Smrg    /* Determine dsp_precision first */
24232b578d3Smrg    tmp = ATIDivide(Multiplier * pATI->DisplayFIFODepth, Divider, vshift, -1);
24332b578d3Smrg    for (dsp_precision = -5;  tmp;  dsp_precision++)
24432b578d3Smrg        tmp >>= 1;
24532b578d3Smrg    if (dsp_precision < 0)
24632b578d3Smrg        dsp_precision = 0;
24732b578d3Smrg    else if (dsp_precision > Maximum_DSP_PRECISION)
24832b578d3Smrg        dsp_precision = Maximum_DSP_PRECISION;
24932b578d3Smrg
25032b578d3Smrg    xshift = 6 - dsp_precision;
25132b578d3Smrg    vshift += xshift;
25232b578d3Smrg
25332b578d3Smrg    /* Move on to dsp_off */
25432b578d3Smrg    dsp_off = ATIDivide(Multiplier * (pATI->DisplayFIFODepth - 1), Divider,
25532b578d3Smrg        vshift, -1) - ATIDivide(1, 1, vshift - xshift, 1);
25632b578d3Smrg
25732b578d3Smrg    /* Next is dsp_on */
25832b578d3Smrg    {
25932b578d3Smrg        dsp_on = ATIDivide(Multiplier, Divider, vshift, 1);
26032b578d3Smrg        tmp = ATIDivide(RASMultiplier, RASDivider, xshift, 1);
26132b578d3Smrg        if (dsp_on < tmp)
26232b578d3Smrg            dsp_on = tmp;
26332b578d3Smrg        dsp_on += (tmp * 2) +
26432b578d3Smrg            ATIDivide(pATI->XCLKPageFaultDelay, 1, xshift, 1);
26532b578d3Smrg    }
26632b578d3Smrg
26732b578d3Smrg    /* Calculate rounding factor and apply it to dsp_on */
26832b578d3Smrg    tmp = ((1 << (Maximum_DSP_PRECISION - dsp_precision)) - 1) >> 1;
26932b578d3Smrg    dsp_on = ((dsp_on + tmp) / (tmp + 1)) * (tmp + 1);
27032b578d3Smrg
27132b578d3Smrg    if (dsp_on >= ((dsp_off / (tmp + 1)) * (tmp + 1)))
27232b578d3Smrg    {
27332b578d3Smrg        dsp_on = dsp_off - ATIDivide(Multiplier, Divider, vshift, -1);
27432b578d3Smrg        dsp_on = (dsp_on / (tmp + 1)) * (tmp + 1);
27532b578d3Smrg    }
27632b578d3Smrg
27732b578d3Smrg    /* Last but not least:  dsp_xclks */
27832b578d3Smrg    dsp_xclks = ATIDivide(Multiplier, Divider, vshift + 5, 1);
27932b578d3Smrg
28032b578d3Smrg    /* Build DSP register contents */
28132b578d3Smrg    pATIHW->dsp_on_off = SetBits(dsp_on, DSP_ON) |
28232b578d3Smrg        SetBits(dsp_off, DSP_OFF);
28332b578d3Smrg    pATIHW->dsp_config = SetBits(dsp_precision, DSP_PRECISION) |
28432b578d3Smrg        SetBits(dsp_xclks, DSP_XCLKS_PER_QW) |
28532b578d3Smrg        SetBits(pATI->DisplayLoopLatency, DSP_LOOP_LATENCY);
28632b578d3Smrg}
28732b578d3Smrg
28832b578d3Smrg/*
28932b578d3Smrg * ATIDSPSet --
29032b578d3Smrg *
29132b578d3Smrg * This function is called to set DSP registers on VT-B and later controllers.
29232b578d3Smrg */
29332b578d3Smrgvoid
29432b578d3SmrgATIDSPSet
29532b578d3Smrg(
29632b578d3Smrg    ATIPtr   pATI,
29732b578d3Smrg    ATIHWPtr pATIHW
29832b578d3Smrg)
29932b578d3Smrg{
30032b578d3Smrg    outr(DSP_ON_OFF, pATIHW->dsp_on_off);
30132b578d3Smrg    outr(DSP_CONFIG, pATIHW->dsp_config);
30232b578d3Smrg}
303