#include "ati.h"
#include "atiadapter.h"
#include "atichip.h"
#include "atidac.h"
#include "atidsp.h"
#include "atimach64io.h"
#include "atimode.h"
#include "atiwonderio.h"
const char *ATIClockNames[] =
{
"unknown",
"IBM VGA compatible",
"crystals",
"ATI 18810 or similar",
"ATI 18811-0 or similar",
"ATI 18811-1 or similar",
"ICS 2494-AM or similar",
"Programmable (BIOS setting 1)",
"Programmable (BIOS setting 2)",
"Programmable (BIOS setting 3)"
};
static CARD16 ATIPostDividers[] = {1, 2, 4, 8, 16, 32, 64, 128},
ATI264xTPostDividers[] = {1, 2, 4, 8, 3, 0, 6, 12};
ClockRec ATIClockDescriptors[] =
{
{
0, 0, 0, 1, 1,
1, 1, 0,
0, NULL,
"Non-programmable"
},
{
257, 512, 257, 1, 1,
46, 46, 0,
4, ATIPostDividers,
"ATI 18818 or ICS 2595 or similar"
},
{
2, 129, 2, 1, 1,
8, 14, 2,
8, ATIPostDividers,
"SGS-Thompson 1703 or similar"
},
{
16, 263, 8, 8, 9,
4, 12, 2,
4, ATIPostDividers,
"Chrontel 8398 or similar"
},
{
2, 255, 0, 1, 1,
45, 45, 0,
4, ATI264xTPostDividers,
"Internal"
},
{
2, 257, 2, 1, 1,
2, 32, 2,
4, ATIPostDividers,
"AT&T 20C408 or similar"
},
{
65, 128, 65, 1, 1,
2, 14, 0,
4, ATIPostDividers,
"IBM RGB 514 or similar"
}
};
static const int
ATIVGAClocks[] =
{
25175, 28322,
-1
};
static const int
ATICrystalFrequencies[] =
{
50000, 56644, 0, 44900, 44900, 50000, 0, 36000,
-1
},
ATI18810Frequencies[] =
{
30240, 32000, 37500, 39000, 42954, 48771, 0, 36000,
40000, 0, 75000, 65000, 50350, 56640, 0, 44900
},
ATI188110Frequencies[] =
{
30240, 32000, 110000, 80000, 42954, 48771, 92400, 36000,
39910, 44900, 75000, 65000, 50350, 56640, 0, 44900
},
ATI188111Frequencies[] =
{
135000, 32000, 110000, 80000, 100000, 126000, 92400, 36000,
39910, 44900, 75000, 65000, 50350, 56640, 0, 44900
},
ATI2494AMFrequencies[] =
{
75000, 77500, 80000, 90000, 25175, 28322, 31500, 36000,
100000, 110000, 126000, 135000, 40000, 44900, 50000, 65000
},
ATIMach64AFrequencies[] =
{
0, 110000, 126000, 135000, 50350, 56640, 63000, 72000,
0, 80000, 75000, 65000, 40000, 44900, 49500, 50000
},
ATIMach64BFrequencies[] =
{
0, 110000, 126000, 135000, 25180, 28320, 31500, 36000,
0, 80000, 75000, 65000, 40000, 44900, 49500, 50000
},
ATIMach64CFrequencies[] =
{
0, 0, 0, 0, 25180, 28320, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
},
*SpecificationClockLine[] =
{
NULL,
ATIVGAClocks,
ATICrystalFrequencies,
ATI18810Frequencies,
ATI188110Frequencies,
ATI188111Frequencies,
ATI2494AMFrequencies,
ATIMach64AFrequencies,
ATIMach64BFrequencies,
ATIMach64CFrequencies,
NULL
};
static const int
ATIPre_2_1_1_Clocks_A[] =
{
18000, 22450, 25175, 28320, 36000, 44900, 50350, 56640,
30240, 32000, 37500, 39000, 40000, 0, 75000, 65000,
-1
},
ATIPre_2_1_1_Clocks_B[] =
{
18000, 22450, 25175, 28320, 36000, 44900, 50350, 56640,
30240, 32000, 110000, 80000, 39910, 44900, 75000, 65000,
-1
},
ATIPre_2_1_1_Clocks_C[] =
{
18000, 22450, 25175, 28320, 36000, 44900, 50350, 56640,
135000, 32000, 110000, 80000, 39910, 44900, 75000, 65000,
-1
},
ATIPre_2_1_1_Clocks_D[] =
{
18000, 32500, 20000, 22450, 36000, 65000, 40000, 44900,
75000, 77500, 80000, 90000, 100000, 110000, 126000, 135000,
-1
},
ATIPre_2_1_1_Clocks_E[] =
{
36000, 25000, 20000, 22450, 72000, 50000, 40000, 44900,
0, 110000, 126000, 135000, 0, 80000, 75000, 65000,
-1
},
ATIPre_2_1_1_Clocks_F[] =
{
18000, 25000, 20000, 22450, 36000, 50000, 40000, 44900,
0, 110000, 126000, 135000, 0, 80000, 75000, 65000,
-1
},
*InvalidClockLine[] =
{
NULL,
ATIVGAClocks,
ATIPre_2_1_1_Clocks_A,
ATIPre_2_1_1_Clocks_B,
ATIPre_2_1_1_Clocks_C,
ATIPre_2_1_1_Clocks_D,
ATIPre_2_1_1_Clocks_E,
ATIPre_2_1_1_Clocks_F,
NULL
};
static const CARD8 ClockMaps[][4] =
{
{ 0, 1, 2, 3},
{ 1, 0, 3, 2},
{ 0, 2, 1, 3},
{ 2, 0, 3, 1},
{ 1, 3, 0, 2}
};
#define ATIVGAWonderClockMap ClockMaps[0]
#define ATIVGAWonderClockUnmap ATIVGAWonderClockMap
#define ATIMachVGAClockMap ClockMaps[1]
#define ATIMachVGAClockUnmap ATIMachVGAClockMap
#define ATIVGAProgrammableClockMap ClockMaps[2]
#define ATIVGAProgrammableClockUnmap ATIVGAProgrammableClockMap
#define ATIAcceleratorClockMap ClockMaps[3]
#define ATIAcceleratorClockUnmap ClockMaps[4]
#define ATIProgrammableClockMap ClockMaps[0]
#define ATIProgrammableClockUnmap ATIProgrammableClockMap
#define MapClockIndex(_ClockMap, _Index) \
(SetBits((_ClockMap)[GetBits(_Index, 0x0CU)], 0x0CU) | \
((_Index) & ~0x0CU))
static int
ATIMatchClockLine
(
ScrnInfoPtr pScreenInfo,
ATIPtr pATI,
const int **ClockLine,
const unsigned short int NumberOfClocks,
const int CalibrationClockNumber,
const int ClockMap
)
{
int ClockChip = 0, ClockChipIndex = 0;
int NumberOfMatchingClocks = 0;
int MinimumGap = CLOCK_TOLERANCE + 1;
#ifndef AVOID_CPIO
if (pATI->Adapter != ATI_ADAPTER_VGA)
#endif
{
if (ClockLine == SpecificationClockLine)
ClockChipIndex++;
}
if (ClockMap)
ClockChipIndex++;
for (; ClockLine[++ClockChipIndex]; )
{
int MaximumGap = 0, ClockCount = 0, ClockIndex = 0;
#ifndef AVOID_CPIO
if ((ClockChipIndex >= ATI_CLOCK_MACH64A) &&
(pATI->Adapter < ATI_ADAPTER_MACH64))
break;
#endif
for (; ClockIndex < NumberOfClocks; ClockIndex++)
{
int Gap, XF86ConfigClock, SpecificationClock;
SpecificationClock = ClockLine[ClockChipIndex]
[MapClockIndex(ClockMaps[ClockMap], ClockIndex)];
if (SpecificationClock < 0)
break;
if (!SpecificationClock)
continue;
XF86ConfigClock = pScreenInfo->clock[ClockIndex];
if (!XF86ConfigClock)
continue;
Gap = abs(XF86ConfigClock - SpecificationClock);
if (Gap >= MinimumGap)
goto SkipThisClockGenerator;
if (!Gap)
{
if (ClockIndex == CalibrationClockNumber)
continue;
}
else if (Gap > MaximumGap)
{
MaximumGap = Gap;
}
ClockCount++;
}
if (ClockCount <= NumberOfMatchingClocks)
continue;
NumberOfMatchingClocks = ClockCount;
ClockChip = ClockChipIndex;
if (!(MinimumGap = MaximumGap))
break;
SkipThisClockGenerator:;
#ifndef AVOID_CPIO
if (pATI->Adapter == ATI_ADAPTER_VGA)
break;
#endif
}
return ClockChip;
}
void
ATIClockPreInit
(
ScrnInfoPtr pScreenInfo,
ATIPtr pATI,
GDevPtr pGDev,
ClockRangePtr pRange
)
{
double ScaleFactor;
unsigned short int NumberOfUndividedClocks;
unsigned short int NumberOfDividers, NumberOfClocks;
int CalibrationClockNumber, CalibrationClockValue;
int ClockIndex, SpecificationClock, ClockMap = 0, Index;
CARD8 CanDisableInterrupts;
#ifndef AVOID_CPIO
CARD8 genmo;
#endif
if (pATI->ProgrammableClock != ATI_CLOCK_FIXED)
{
if ((pATI->ProgrammableClock == ATI_CLOCK_UNKNOWN) ||
(pATI->ProgrammableClock > NumberOf(ATIClockDescriptors)))
{
xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_WARNING, 0,
"Unknown programmable clock generator type (0x%02X)"
" detected.\n", pATI->ProgrammableClock);
}
else if (pATI->ClockDescriptor.MaxN <= 0)
{
xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_WARNING, 0,
"Unsupported programmable clock generator detected: %s.\n",
pATI->ClockDescriptor.ClockName);
}
else
{
pRange->clockIndex = -1;
pScreenInfo->progClock = TRUE;
#ifndef AVOID_CPIO
if (pATI->NewHW.crtc == ATI_CRTC_VGA)
{
pATI->NewHW.ClockMap = ATIVGAProgrammableClockMap;
pATI->NewHW.ClockUnmap = ATIVGAProgrammableClockUnmap;
}
else
#endif
{
pATI->NewHW.ClockMap = ATIProgrammableClockMap;
pATI->NewHW.ClockUnmap = ATIProgrammableClockUnmap;
}
xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED,
"%s programmable clock generator detected.\n",
pATI->ClockDescriptor.ClockName);
if (pATI->ReferenceDenominator == 1)
xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED,
"Reference clock %.3f MHz.\n",
(double)pATI->ReferenceNumerator / 1000.0);
else
xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED,
"Reference clock %.6g/%d (%.3f) MHz.\n",
(double)pATI->ReferenceNumerator / 1000.0,
pATI->ReferenceDenominator,
(double)pATI->ReferenceNumerator /
((double)pATI->ReferenceDenominator * 1000.0));
if (pGDev->numclocks)
xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE,
"XF86Config clocks specification ignored.\n");
if (pATI->ProgrammableClock == ATI_CLOCK_CH8398)
{
pScreenInfo->numClocks = 2;
pScreenInfo->clock[0] = 25175;
pScreenInfo->clock[1] = 28322;
}
else if (pATI->ProgrammableClock == ATI_CLOCK_INTERNAL)
{
pATI->ReferenceNumerator <<= 1;
}
return;
}
}
#ifndef AVOID_CPIO
pATI->NewHW.ClockMap = ATIVGAWonderClockMap;
pATI->NewHW.ClockUnmap = ATIVGAWonderClockUnmap;
#endif
ProbeClocks:
#ifndef AVOID_CPIO
if (pATI->Adapter == ATI_ADAPTER_VGA)
{
NumberOfDividers = 1;
NumberOfUndividedClocks = 4;
CalibrationClockNumber = 1;
CalibrationClockValue = 28322;
}
else
#endif
{
#ifndef AVOID_CPIO
NumberOfDividers = 4;
if ((pATI->Chip <= ATI_CHIP_18800) ||
(pATI->Adapter == ATI_ADAPTER_V4))
{
NumberOfUndividedClocks = 8;
CalibrationClockNumber = 1;
CalibrationClockValue = 56644;
}
else
#endif
{
NumberOfUndividedClocks = 16;
#ifndef AVOID_CPIO
CalibrationClockNumber = 7;
CalibrationClockValue = 36000;
if (pATI->Chip >= ATI_CHIP_68800)
#endif
{
NumberOfDividers = 2;
if (pATI->Chip >= ATI_CHIP_264CT)
{
NumberOfDividers = 1;
NumberOfUndividedClocks = 4;
CalibrationClockNumber = 1;
CalibrationClockValue = 28322;
}
else
#ifndef AVOID_CPIO
if (pATI->Adapter >= ATI_ADAPTER_MACH64)
#endif
{
CalibrationClockNumber = 10 ;
CalibrationClockValue = 75000 ;
}
#ifndef AVOID_CPIO
if (pATI->NewHW.crtc == ATI_CRTC_VGA)
{
pATI->NewHW.ClockMap = ATIMachVGAClockMap;
pATI->NewHW.ClockUnmap = ATIMachVGAClockUnmap;
}
else
#endif
{
pATI->NewHW.ClockMap = ATIAcceleratorClockMap;
pATI->NewHW.ClockUnmap = ATIAcceleratorClockUnmap;
}
}
}
}
pATI->OldHW.ClockMap = pATI->NewHW.ClockMap;
pATI->OldHW.ClockUnmap = pATI->NewHW.ClockUnmap;
NumberOfClocks = NumberOfUndividedClocks * NumberOfDividers;
if (!pGDev->numclocks || pATI->OptionProbeClocks ||
xf86ServerIsOnlyProbing())
{
if (pATI->ProgrammableClock != ATI_CLOCK_FIXED)
{
CalibrationClockNumber = CalibrationClockValue = 0;
for (ClockIndex = 0;
ClockIndex < NumberOfUndividedClocks;
ClockIndex++)
{
if (CalibrationClockValue < pATI->BIOSClocks[ClockIndex])
{
CalibrationClockNumber = ClockIndex;
CalibrationClockValue = pATI->BIOSClocks[ClockIndex];
}
}
CalibrationClockNumber =
MapClockIndex(pATI->NewHW.ClockUnmap, CalibrationClockNumber);
CalibrationClockValue *= 10;
}
#ifndef AVOID_CPIO
if (pATI->VGAAdapter != ATI_ADAPTER_NONE)
{
ATIModeSave(pScreenInfo, pATI, &pATI->OldHW);
if (pATI->CPIO_VGAWonder && (pATI->OldHW.crtc == ATI_CRTC_VGA))
ATIModifyExtReg(pATI, 0xB5U, pATI->OldHW.b5, 0x7FU, 0x00U);
}
#endif
CanDisableInterrupts = TRUE;
for (ClockIndex = 0; ClockIndex < NumberOfClocks; ClockIndex++)
{
pScreenInfo->clock[ClockIndex] = 0;
Index = MapClockIndex(pATI->OldHW.ClockMap, ClockIndex);
switch (pATI->OldHW.crtc)
{
#ifndef AVOID_CPIO
case ATI_CRTC_VGA:
genmo = (inb(R_GENMO) & 0xF3U) | ((Index << 2) & 0x0CU);
if (pATI->CPIO_VGAWonder)
{
if (((Index & 0x03U) == 0x02U) &&
((pATI->Chip <= ATI_CHIP_18800) ||
(pATI->Adapter == ATI_ADAPTER_V4)))
continue;
PutReg(SEQX, 0x00U, 0x00U);
if (pATI->Chip <= ATI_CHIP_18800)
{
ATIModifyExtReg(pATI, 0xB2U, -1, 0xBFU,
Index << 4);
}
else
{
ATIModifyExtReg(pATI, 0xBEU, -1, 0xEFU,
Index << 2);
if (pATI->Adapter != ATI_ADAPTER_V4)
{
Index >>= 1;
ATIModifyExtReg(pATI, 0xB9U, -1, 0xFDU,
Index >> 1);
}
}
ATIModifyExtReg(pATI, 0xB8U, -1, 0x00U,
(Index << 3) & 0xC0U);
}
else
{
if (Index & ~0x03U)
continue;
PutReg(SEQX, 0x00U, 0x00U);
}
outb(GENMO, genmo);
PutReg(SEQX, 0x00U, 0x03U);
break;
#endif
case ATI_CRTC_MACH64:
out8(CLOCK_CNTL, CLOCK_STROBE |
SetBits(Index, CLOCK_SELECT | CLOCK_DIVIDER));
break;
default:
continue;
}
usleep(50000);
xf86SetPriority(TRUE);
if (CanDisableInterrupts && !xf86DisableInterrupts())
{
xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
"Unable to disable interrupts; Clock probe will not be as"
" accurate.\n");
CanDisableInterrupts = FALSE;
}
switch (pATI->OldHW.crtc)
{
#ifndef AVOID_CPIO
case ATI_CRTC_VGA:
Index = 1 << 19;
while (!(inb(GENS1(pATI->CPIO_VGABase)) & 0x08U))
if (Index-- <= 0)
goto EnableInterrupts;
Index = 1 << 19;
while (inb(GENS1(pATI->CPIO_VGABase)) & 0x08U)
if (Index-- <= 0)
goto EnableInterrupts;
Index = 1 << 19;
while (!(inb(GENS1(pATI->CPIO_VGABase)) & 0x08U))
if (Index-- <= 0)
goto EnableInterrupts;
for (Index = 0; Index < 8; Index++)
{
while (inb(GENS1(pATI->CPIO_VGABase)) & 0x08U)
pScreenInfo->clock[ClockIndex]++;
while (!(inb(GENS1(pATI->CPIO_VGABase)) & 0x08U))
pScreenInfo->clock[ClockIndex]++;
}
break;
#endif
case ATI_CRTC_MACH64:
Index = 1 << 19;
while (!(inr(CRTC_INT_CNTL) & CRTC_VBLANK))
if (Index-- <= 0)
goto EnableInterrupts;
Index = 1 << 19;
while (inr(CRTC_INT_CNTL) & CRTC_VBLANK)
if (Index-- <= 0)
goto EnableInterrupts;
Index = 1 << 19;
while (!(inr(CRTC_INT_CNTL) & CRTC_VBLANK))
if (Index-- <= 0)
goto EnableInterrupts;
for (Index = 0; Index < 4; Index++)
{
while (inr(CRTC_INT_CNTL) & CRTC_VBLANK)
pScreenInfo->clock[ClockIndex]++;
while (!(inr(CRTC_INT_CNTL) & CRTC_VBLANK))
pScreenInfo->clock[ClockIndex]++;
}
break;
default:
break;
}
EnableInterrupts:
if (CanDisableInterrupts)
xf86EnableInterrupts();
xf86SetPriority(FALSE);
}
ScaleFactor = (double)CalibrationClockValue *
(double)pScreenInfo->clock[CalibrationClockNumber];
for (ClockIndex = 0; ClockIndex < NumberOfClocks; ClockIndex++)
{
if (ClockIndex == CalibrationClockNumber)
pScreenInfo->clock[ClockIndex] = CalibrationClockValue;
else if (pScreenInfo->clock[ClockIndex])
pScreenInfo->clock[ClockIndex] =
(int)(((ScaleFactor /
(double)pScreenInfo->clock[ClockIndex]) +
5) / 10) * 10;
}
pScreenInfo->numClocks = NumberOfClocks;
#ifndef AVOID_CPIO
if (pATI->VGAAdapter != ATI_ADAPTER_NONE)
{
ATIModeSet(pScreenInfo, pATI, &pATI->OldHW);
xfree(pATI->OldHW.frame_buffer);
pATI->OldHW.frame_buffer = NULL;
}
#endif
pATI->OptionProbeClocks = TRUE;
pATI->Clock = ATIMatchClockLine(pScreenInfo, pATI,
SpecificationClockLine, NumberOfUndividedClocks,
CalibrationClockNumber, 0);
#ifndef AVOID_CPIO
if ((pATI->Chip <= ATI_CHIP_18800) ||
(pATI->Adapter == ATI_ADAPTER_V4))
{
if (pATI->Clock > ATI_CLOCK_CRYSTALS)
pATI->Clock = ATI_CLOCK_NONE;
}
else
#endif
{
if (pATI->Clock == ATI_CLOCK_CRYSTALS)
pATI->Clock = ATI_CLOCK_NONE;
}
}
else
{
if (NumberOfClocks > pGDev->numclocks)
{
NumberOfClocks = pGDev->numclocks;
if (NumberOfUndividedClocks > NumberOfClocks)
NumberOfUndividedClocks = NumberOfClocks;
}
for (ClockIndex = 0; ClockIndex < NumberOfClocks; ClockIndex++)
pScreenInfo->clock[ClockIndex] = pGDev->clock[ClockIndex];
pScreenInfo->numClocks = NumberOfClocks;
pATI->Clock = ATIMatchClockLine(pScreenInfo, pATI,
SpecificationClockLine, NumberOfUndividedClocks, -1, 0);
#ifndef AVOID_CPIO
if (pATI->Adapter != ATI_ADAPTER_VGA)
#endif
{
if (pATI->Clock == ATI_CLOCK_NONE)
{
if (ATIMatchClockLine(pScreenInfo, pATI, InvalidClockLine,
NumberOfClocks, -1, 0))
{
pATI->OptionProbeClocks = TRUE;
}
else
#ifndef AVOID_CPIO
if ((pATI->Chip >= ATI_CHIP_18800) &&
(pATI->Adapter != ATI_ADAPTER_V4))
#endif
{
while ((++ClockMap, ClockMap %= NumberOf(ClockMaps)))
{
pATI->Clock = ATIMatchClockLine(pScreenInfo, pATI,
SpecificationClockLine, NumberOfUndividedClocks,
-1, ClockMap);
if (pATI->Clock != ATI_CLOCK_NONE)
{
xf86DrvMsgVerb(pScreenInfo->scrnIndex,
X_WARNING, 0,
"XF86Config clock ordering incorrect. Clocks"
" will be reordered.\n");
break;
}
}
}
}
else
#ifndef AVOID_CPIO
if ((pATI->Chip <= ATI_CHIP_18800) ||
(pATI->Adapter == ATI_ADAPTER_V4))
{
if (pATI->Clock > ATI_CLOCK_CRYSTALS)
pATI->OptionProbeClocks = TRUE;
}
else
#endif
{
if (pATI->Clock == ATI_CLOCK_CRYSTALS)
pATI->OptionProbeClocks = TRUE;
}
if (pATI->OptionProbeClocks)
{
xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_WARNING, 0,
"Invalid or obsolete XF86Config clocks line rejected.\n"
" Clocks will be probed.\n");
goto ProbeClocks;
}
}
}
if (pATI->ProgrammableClock != ATI_CLOCK_FIXED)
{
pATI->ProgrammableClock = ATI_CLOCK_FIXED;
}
else if (pATI->Clock == ATI_CLOCK_NONE)
{
xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_WARNING, 0,
"Unknown clock generator detected.\n");
}
else
#ifndef AVOID_CPIO
if (pATI->Clock == ATI_CLOCK_CRYSTALS)
{
xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED,
"This adapter uses crystals to generate clock frequencies.\n");
}
else if (pATI->Clock != ATI_CLOCK_VGA)
#endif
{
xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED,
"%s clock chip detected.\n", ATIClockNames[pATI->Clock]);
}
if (pATI->Clock != ATI_CLOCK_NONE)
{
for (ClockIndex = 0;
ClockIndex < NumberOfUndividedClocks;
ClockIndex++)
{
SpecificationClock =
SpecificationClockLine[pATI->Clock][ClockIndex];
if (SpecificationClock < 0)
break;
if (!ClockMap)
{
if (!pScreenInfo->clock[ClockIndex])
continue;
if (!SpecificationClock)
{
if (pATI->Clock != ATI_CLOCK_CRYSTALS)
continue;
}
else
{
if (abs(SpecificationClock -
pScreenInfo->clock[ClockIndex]) > CLOCK_TOLERANCE)
continue;
}
}
pScreenInfo->clock[ClockIndex] = SpecificationClock;
}
for (ClockIndex = NumberOfUndividedClocks;
ClockIndex < NumberOfClocks;
ClockIndex++)
pScreenInfo->clock[ClockIndex] = ATIDivide(
pScreenInfo->clock[ClockIndex % NumberOfUndividedClocks],
(ClockIndex / NumberOfUndividedClocks) + 1, 0, 0);
}
xf86ShowClocks(pScreenInfo, pATI->OptionProbeClocks ? X_PROBED : X_CONFIG);
for (ClockIndex = 0; ClockIndex < NumberOfClocks; ClockIndex++)
if (pScreenInfo->clock[ClockIndex] > pRange->maxClock)
pScreenInfo->clock[ClockIndex] = 0;
}
void
ATIClockSave
(
ScrnInfoPtr pScreenInfo,
ATIPtr pATI,
ATIHWPtr pATIHW
)
{
if (pScreenInfo->vtSema && (pATI->ProgrammableClock > ATI_CLOCK_FIXED))
{
#ifndef AVOID_CPIO
if (pATIHW->crtc == ATI_CRTC_VGA)
{
pATIHW->ClockMap = ATIVGAProgrammableClockMap;
pATIHW->ClockUnmap = ATIVGAProgrammableClockUnmap;
}
else
#endif
{
pATIHW->ClockMap = ATIProgrammableClockMap;
pATIHW->ClockUnmap = ATIProgrammableClockUnmap;
}
}
else
{
#ifndef AVOID_CPIO
if (pATIHW->crtc != ATI_CRTC_VGA)
#endif
{
pATIHW->ClockMap = ATIAcceleratorClockMap;
pATIHW->ClockUnmap = ATIAcceleratorClockUnmap;
}
#ifndef AVOID_CPIO
else if (pATI->Chip < ATI_CHIP_68800)
{
pATIHW->ClockMap = ATIVGAWonderClockMap;
pATIHW->ClockUnmap = ATIVGAWonderClockUnmap;
}
else
{
pATIHW->ClockMap = ATIMachVGAClockMap;
pATIHW->ClockUnmap = ATIMachVGAClockUnmap;
}
#endif
}
}
Bool
ATIClockCalculate
(
int iScreen,
ATIPtr pATI,
ATIHWPtr pATIHW,
DisplayModePtr pMode
)
{
int N, M, D;
int ClockSelect, N1, MinimumGap;
int Frequency, Multiple;
pATIHW->FeedbackDivider = pATIHW->ReferenceDivider = pATIHW->PostDivider = 0;
if ((pATI->ProgrammableClock <= ATI_CLOCK_FIXED) ||
((pATI->ProgrammableClock == ATI_CLOCK_CH8398) &&
(pMode->ClockIndex < 2)))
{
ClockSelect = pMode->ClockIndex;
}
else
{
MinimumGap = ((unsigned int)(-1)) >> 1;
for (M = pATI->ClockDescriptor.MinM;
M <= pATI->ClockDescriptor.MaxM;
M++)
{
for (D = 0; D < pATI->ClockDescriptor.NumD; D++)
{
if (!pATI->ClockDescriptor.PostDividers[D])
continue;
if (pATI->maxClock &&
((pATI->maxClock / pATI->ClockDescriptor.PostDividers[D]) <
pMode->Clock))
continue;
Multiple = M * pATI->ReferenceDenominator *
pATI->ClockDescriptor.PostDividers[D];
N = ATIDivide(pMode->Clock * Multiple,
pATI->ReferenceNumerator, 0, 0);
if (N < pATI->ClockDescriptor.MinN)
N = pATI->ClockDescriptor.MinN;
else if (N > pATI->ClockDescriptor.MaxN)
N = pATI->ClockDescriptor.MaxN;
N -= pATI->ClockDescriptor.NAdjust;
N1 = (N / pATI->ClockDescriptor.N1) * pATI->ClockDescriptor.N2;
if (N > N1)
N = ATIDivide(N1 + 1, pATI->ClockDescriptor.N1, 0, 1);
N += pATI->ClockDescriptor.NAdjust;
N1 += pATI->ClockDescriptor.NAdjust;
for (; ; N = N1)
{
Frequency = abs(ATIDivide(N * pATI->ReferenceNumerator,
Multiple, 0, 0) - pMode->Clock);
if ((Frequency < MinimumGap) ||
((Frequency == MinimumGap) &&
(pATIHW->FeedbackDivider < N)))
{
pATIHW->FeedbackDivider = N;
pATIHW->ReferenceDivider = M;
pATIHW->PostDivider = D;
MinimumGap = Frequency;
}
if (N <= N1)
break;
}
}
}
Multiple = pATIHW->ReferenceDivider * pATI->ReferenceDenominator *
pATI->ClockDescriptor.PostDividers[pATIHW->PostDivider];
Frequency = pATIHW->FeedbackDivider * pATI->ReferenceNumerator;
Frequency = ATIDivide(Frequency, Multiple, 0, 0);
if (abs(Frequency - pMode->Clock) > CLOCK_TOLERANCE)
{
xf86DrvMsg(iScreen, X_ERROR,
"Unable to programme clock %.3fMHz for mode %s.\n",
(double)(pMode->Clock) / 1000.0, pMode->name);
return FALSE;
}
pMode->SynthClock = Frequency;
ClockSelect = pATI->ClockNumberToProgramme;
xf86ErrorFVerb(4,
"\n Programming clock %d to %.3fMHz for mode %s."
" N=%d, M=%d, D=%d.\n",
ClockSelect, (double)Frequency / 1000.0, pMode->name,
pATIHW->FeedbackDivider, pATIHW->ReferenceDivider,
pATIHW->PostDivider);
if (pATI->Chip >= ATI_CHIP_264VTB)
ATIDSPCalculate(pATI, pATIHW, pMode);
}
pATIHW->clock = ClockSelect;
ClockSelect = MapClockIndex(pATIHW->ClockMap, ClockSelect);
switch (pATIHW->crtc)
{
#ifndef AVOID_CPIO
case ATI_CRTC_VGA:
pATIHW->genmo = (pATIHW->genmo & 0xF3U) |
((ClockSelect << 2) & 0x0CU);
if (pATI->CPIO_VGAWonder)
{
if (pATI->Chip <= ATI_CHIP_18800)
{
pATIHW->b2 = (pATIHW->b2 & 0xBFU) |
((ClockSelect << 4) & 0x40U);
}
else
{
pATIHW->be = (pATIHW->be & 0xEFU) |
((ClockSelect << 2) & 0x10U);
if (pATI->Adapter != ATI_ADAPTER_V4)
{
ClockSelect >>= 1;
pATIHW->b9 = (pATIHW->b9 & 0xFDU) |
((ClockSelect >> 1) & 0x02U);
}
}
pATIHW->b8 = (pATIHW->b8 & 0x3FU) |
((ClockSelect << 3) & 0xC0U);
}
break;
#endif
case ATI_CRTC_MACH64:
pATIHW->clock_cntl = CLOCK_STROBE |
SetBits(ClockSelect, CLOCK_SELECT | CLOCK_DIVIDER);
break;
default:
break;
}
return TRUE;
}
void
ATIClockSet
(
ATIPtr pATI,
ATIHWPtr pATIHW
)
{
CARD32 crtc_gen_cntl, tmp;
CARD8 clock_cntl0;
CARD8 tmp2;
unsigned int Programme;
int N = pATIHW->FeedbackDivider - pATI->ClockDescriptor.NAdjust;
int M = pATIHW->ReferenceDivider - pATI->ClockDescriptor.MAdjust;
int D = pATIHW->PostDivider;
crtc_gen_cntl = inr(CRTC_GEN_CNTL);
if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN))
outr(CRTC_GEN_CNTL, crtc_gen_cntl | CRTC_EXT_DISP_EN);
switch (pATI->ProgrammableClock)
{
case ATI_CLOCK_ICS2595:
clock_cntl0 = in8(CLOCK_CNTL);
Programme = (SetBits(pATIHW->clock, ICS2595_CLOCK) |
SetBits(N, ICS2595_FB_DIV) | SetBits(D, ICS2595_POST_DIV)) ^
ICS2595_TOGGLE;
ATIDelay(50000);
(void)xf86DisableInterrupts();
while (Programme >= CLOCK_BIT)
{
tmp = (Programme & CLOCK_BIT) | CLOCK_STROBE;
out8(CLOCK_CNTL, tmp);
ATIDelay(26);
out8(CLOCK_CNTL, tmp | CLOCK_PULSE);
ATIDelay(26);
Programme >>= 1;
}
xf86EnableInterrupts();
out8(CLOCK_CNTL, clock_cntl0 | CLOCK_STROBE);
break;
case ATI_CLOCK_STG1703:
(void)ATIGetDACCmdReg(pATI);
(void)in8(M64_DAC_MASK);
out8(M64_DAC_MASK, (pATIHW->clock << 1) + 0x20U);
out8(M64_DAC_MASK, 0);
out8(M64_DAC_MASK, SetBits(N, 0xFFU));
out8(M64_DAC_MASK, SetBits(M, 0x1FU) | SetBits(D, 0xE0U));
break;
case ATI_CLOCK_CH8398:
tmp = inr(DAC_CNTL) | (DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3);
outr(DAC_CNTL, tmp);
out8(M64_DAC_WRITE, pATIHW->clock);
out8(M64_DAC_DATA, SetBits(N, 0xFFU));
out8(M64_DAC_DATA, SetBits(M, 0x3FU) | SetBits(D, 0xC0U));
out8(M64_DAC_MASK, 0x04U);
outr(DAC_CNTL, tmp & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3));
tmp2 = in8(M64_DAC_WRITE);
out8(M64_DAC_WRITE, (tmp2 & 0x70U) | 0x80U);
outr(DAC_CNTL, tmp & ~DAC_EXT_SEL_RS2);
break;
case ATI_CLOCK_INTERNAL:
ATIMach64PutPLLReg(PLL_VCLK_CNTL, pATIHW->pll_vclk_cntl);
tmp2 = pATIHW->clock << 1;
tmp = ATIMach64GetPLLReg(PLL_VCLK_POST_DIV);
tmp &= ~(0x03U << tmp2);
tmp |= SetBits(D, 0x03U) << tmp2;
ATIMach64PutPLLReg(PLL_VCLK_POST_DIV, tmp);
tmp = ATIMach64GetPLLReg(PLL_XCLK_CNTL);
tmp &= ~(SetBits(1, PLL_VCLK0_XDIV) << pATIHW->clock);
tmp |= SetBits(D >> 2, PLL_VCLK0_XDIV) << pATIHW->clock;
ATIMach64PutPLLReg(PLL_XCLK_CNTL, tmp);
tmp = PLL_VCLK0_FB_DIV + pATIHW->clock;
ATIMach64PutPLLReg(tmp, SetBits(N, 0xFFU));
ATIMach64PutPLLReg(PLL_VCLK_CNTL,
pATIHW->pll_vclk_cntl & ~PLL_VCLK_RESET);
ATIMach64AccessPLLReg(pATI, 0, FALSE);
break;
case ATI_CLOCK_ATT20C408:
(void)ATIGetDACCmdReg(pATI);
tmp = in8(M64_DAC_MASK);
(void)ATIGetDACCmdReg(pATI);
out8(M64_DAC_MASK, tmp | 1);
out8(M64_DAC_WRITE, 1);
out8(M64_DAC_MASK, tmp | 9);
ATIDelay(400);
tmp2 = (pATIHW->clock << 2) + 0x40U;
out8(M64_DAC_WRITE, tmp2);
out8(M64_DAC_MASK, SetBits(N, 0xFFU));
out8(M64_DAC_WRITE, ++tmp2);
out8(M64_DAC_MASK, SetBits(M, 0x3FU) | SetBits(D, 0xC0U));
out8(M64_DAC_WRITE, ++tmp2);
out8(M64_DAC_MASK, 0x77U);
ATIDelay(400);
out8(M64_DAC_WRITE, 1);
out8(M64_DAC_MASK, tmp);
break;
case ATI_CLOCK_IBMRGB514:
tmp = (pATIHW->clock << 1) + 0x20U;
pATIHW->ibmrgb514[tmp] =
(SetBits(N, 0x3FU) | SetBits(D, 0xC0U)) ^ 0xC0U;
pATIHW->ibmrgb514[tmp + 1] = SetBits(M, 0x3FU);
break;
default:
break;
}
(void)in8(M64_DAC_WRITE);
if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN))
outr(CRTC_GEN_CNTL, crtc_gen_cntl);
}