aticlock.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/* 2432b578d3Smrg * For all supported programmable clock generators, the driver will ignore any 2532b578d3Smrg * XF86Config clock line and programme, as needed, the clock number reserved by 2632b578d3Smrg * the BIOS for accelerated drivers. The driver's mode initialisation routine 2732b578d3Smrg * finds integers N, M and D such that 2832b578d3Smrg * 2932b578d3Smrg * N 3032b578d3Smrg * R * ------- MHz 3132b578d3Smrg * M * D 3232b578d3Smrg * 3332b578d3Smrg * best approximates the mode's clock frequency, where R is the crystal- 3432b578d3Smrg * generated reference frequency (usually 14.318 MHz). D is a power of 2 3532b578d3Smrg * except for those integrated controllers that also offer odd dividers. 3632b578d3Smrg * Different clock generators have different restrictions on the value N, M and 3732b578d3Smrg * D can assume. The driver contains an internal table to record these 3832b578d3Smrg * restrictions (among other things). The resulting values of N, M and D are 3932b578d3Smrg * then encoded in a generator-specific way and used to programme the clock. 4032b578d3Smrg * The Mach64's clock divider is not used in this case. 4132b578d3Smrg */ 4232b578d3Smrg 4332b578d3Smrg#ifdef HAVE_CONFIG_H 4432b578d3Smrg#include "config.h" 4532b578d3Smrg#endif 4632b578d3Smrg 4732b578d3Smrg#include <stdlib.h> 4832b578d3Smrg#include "ati.h" 4932b578d3Smrg#include "atichip.h" 5032b578d3Smrg#include "atidac.h" 5132b578d3Smrg#include "atidsp.h" 5232b578d3Smrg#include "atimach64io.h" 5332b578d3Smrg#include "atimode.h" 5432b578d3Smrg#include "atiwonderio.h" 5532b578d3Smrg 5632b578d3Smrg/* 5732b578d3Smrg * Definitions related to programmable clock generators. 5832b578d3Smrg */ 5932b578d3Smrgstatic CARD16 ATIPostDividers[] = {1, 2, 4, 8, 16, 32, 64, 128}, 6032b578d3Smrg ATI264xTPostDividers[] = {1, 2, 4, 8, 3, 0, 6, 12}; 6132b578d3SmrgClockRec ATIClockDescriptors[] = 6232b578d3Smrg{ 6332b578d3Smrg { 6432b578d3Smrg 0, 0, 0, 1, 1, 6532b578d3Smrg 1, 1, 0, 6632b578d3Smrg 0, NULL, 6732b578d3Smrg "Non-programmable" 6832b578d3Smrg }, 6932b578d3Smrg { 7032b578d3Smrg 257, 512, 257, 1, 1, 7132b578d3Smrg 46, 46, 0, 7232b578d3Smrg 4, ATIPostDividers, 7332b578d3Smrg "ATI 18818 or ICS 2595 or similar" 7432b578d3Smrg }, 7532b578d3Smrg { 7632b578d3Smrg 2, 129, 2, 1, 1, 7732b578d3Smrg 8, 14, 2, 7832b578d3Smrg 8, ATIPostDividers, 7932b578d3Smrg "SGS-Thompson 1703 or similar" 8032b578d3Smrg }, 8132b578d3Smrg { 8232b578d3Smrg 16, 263, 8, 8, 9, 8332b578d3Smrg 4, 12, 2, 8432b578d3Smrg 4, ATIPostDividers, 8532b578d3Smrg "Chrontel 8398 or similar" 8632b578d3Smrg }, 8732b578d3Smrg { 8832b578d3Smrg 2, 255, 0, 1, 1, 8932b578d3Smrg 45, 45, 0, 9032b578d3Smrg 4, ATI264xTPostDividers, 9132b578d3Smrg "Internal" 9232b578d3Smrg }, 9332b578d3Smrg { 9432b578d3Smrg 2, 257, 2, 1, 1, 9532b578d3Smrg 2, 32, 2, 9632b578d3Smrg 4, ATIPostDividers, 9732b578d3Smrg "AT&T 20C408 or similar" 9832b578d3Smrg }, 9932b578d3Smrg { 10032b578d3Smrg 65, 128, 65, 1, 1, 10132b578d3Smrg 2, 14, 0, 10232b578d3Smrg 4, ATIPostDividers, 10332b578d3Smrg "IBM RGB 514 or similar" 10432b578d3Smrg } 10532b578d3Smrg}; 10632b578d3Smrg 10732b578d3Smrg/* 10832b578d3Smrg * ATIClockPreInit -- 10932b578d3Smrg * 11032b578d3Smrg * This function is called by ATIPreInit() and handles the XF86Config clocks 11132b578d3Smrg * line (or lack thereof). 11232b578d3Smrg */ 11332b578d3Smrgvoid 11432b578d3SmrgATIClockPreInit 11532b578d3Smrg( 11632b578d3Smrg ScrnInfoPtr pScreenInfo, 11732b578d3Smrg ATIPtr pATI 11832b578d3Smrg) 11932b578d3Smrg{ 12032b578d3Smrg /* 12132b578d3Smrg * Recognise supported clock generators. This involves telling the 12232b578d3Smrg * rest of the server about it and (re-)initializing the XF86Config 12332b578d3Smrg * clocks line. 12432b578d3Smrg */ 12532b578d3Smrg pScreenInfo->progClock = TRUE; 12632b578d3Smrg 12732b578d3Smrg xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, 12832b578d3Smrg "%s programmable clock generator detected.\n", 12932b578d3Smrg pATI->ClockDescriptor.ClockName); 13032b578d3Smrg if (pATI->ReferenceDenominator == 1) 13132b578d3Smrg xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, 13232b578d3Smrg "Reference clock %.3f MHz.\n", 13332b578d3Smrg (double)pATI->ReferenceNumerator / 1000.0); 13432b578d3Smrg else 13532b578d3Smrg xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, 13632b578d3Smrg "Reference clock %.6g/%d (%.3f) MHz.\n", 13732b578d3Smrg (double)pATI->ReferenceNumerator / 1000.0, 13832b578d3Smrg pATI->ReferenceDenominator, 13932b578d3Smrg (double)pATI->ReferenceNumerator / 14032b578d3Smrg ((double)pATI->ReferenceDenominator * 1000.0)); 14132b578d3Smrg 14232b578d3Smrg#if defined(__sparc__) 14332b578d3Smrg if ((pATI->refclk / 100000) != 286 && 14432b578d3Smrg (pATI->refclk / 100000) != 295) 14532b578d3Smrg { 14632b578d3Smrg xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 14732b578d3Smrg "If modes do not work on Ultra 5/10 or Blade 100/150,\n" 14832b578d3Smrg "\tset option \"reference_clock\" to \"28.636 MHz\"" 14932b578d3Smrg " or \"29.5 MHz\"\n"); 15032b578d3Smrg } 15132b578d3Smrg#endif 15232b578d3Smrg 15332b578d3Smrg if (pATI->ProgrammableClock == ATI_CLOCK_CH8398) 15432b578d3Smrg { /* First two are fixed */ 15532b578d3Smrg pScreenInfo->numClocks = 2; 15632b578d3Smrg pScreenInfo->clock[0] = 25175; 15732b578d3Smrg pScreenInfo->clock[1] = 28322; 15832b578d3Smrg } 15932b578d3Smrg else if (pATI->ProgrammableClock == ATI_CLOCK_INTERNAL) 16032b578d3Smrg { 16132b578d3Smrg /* 16232b578d3Smrg * The integrated PLL generates clocks as if the reference 16332b578d3Smrg * frequency were doubled. 16432b578d3Smrg */ 16532b578d3Smrg pATI->ReferenceNumerator <<= 1; 16632b578d3Smrg } 16732b578d3Smrg} 16832b578d3Smrg 16932b578d3Smrg/* 17032b578d3Smrg * ATIClockCalculate -- 17132b578d3Smrg * 17232b578d3Smrg * This function is called to generate, if necessary, the data needed for clock 17332b578d3Smrg * programming, and set clock select bits in various register values. 17432b578d3Smrg */ 17532b578d3SmrgBool 17632b578d3SmrgATIClockCalculate 17732b578d3Smrg( 17832b578d3Smrg int iScreen, 17932b578d3Smrg ATIPtr pATI, 18032b578d3Smrg ATIHWPtr pATIHW, 18132b578d3Smrg DisplayModePtr pMode 18232b578d3Smrg) 18332b578d3Smrg{ 18432b578d3Smrg int N, M, D; 18532b578d3Smrg int ClockSelect, N1, MinimumGap; 18632b578d3Smrg int Frequency, Multiple; /* Used as temporaries */ 18732b578d3Smrg 18832b578d3Smrg /* Set default values */ 18932b578d3Smrg pATIHW->FeedbackDivider = pATIHW->ReferenceDivider = pATIHW->PostDivider = 0; 19032b578d3Smrg 19132b578d3Smrg if (((pATI->ProgrammableClock == ATI_CLOCK_CH8398) && 19232b578d3Smrg (pMode->ClockIndex < 2))) 19332b578d3Smrg { 19432b578d3Smrg xf86DrvMsg(iScreen, X_ERROR, 19532b578d3Smrg "First two clocks of Chrontel 8398 clock generator are fixed\n"); 19632b578d3Smrg return FALSE; 19732b578d3Smrg } 19832b578d3Smrg 19932b578d3Smrg { 20032b578d3Smrg /* Generate clock programme word, using units of kHz */ 20132b578d3Smrg MinimumGap = ((unsigned int)(-1)) >> 1; 20232b578d3Smrg 20332b578d3Smrg /* Loop through reference dividers */ 20432b578d3Smrg for (M = pATI->ClockDescriptor.MinM; 20532b578d3Smrg M <= pATI->ClockDescriptor.MaxM; 20632b578d3Smrg M++) 20732b578d3Smrg { 20832b578d3Smrg /* Loop through post-dividers */ 20932b578d3Smrg for (D = 0; D < pATI->ClockDescriptor.NumD; D++) 21032b578d3Smrg { 21132b578d3Smrg if (!pATI->ClockDescriptor.PostDividers[D]) 21232b578d3Smrg continue; 21332b578d3Smrg 21432b578d3Smrg /* Limit undivided VCO to maxClock */ 21532b578d3Smrg if (pATI->maxClock && 21632b578d3Smrg ((pATI->maxClock / pATI->ClockDescriptor.PostDividers[D]) < 21732b578d3Smrg pMode->Clock)) 21832b578d3Smrg continue; 21932b578d3Smrg 22032b578d3Smrg /* 22132b578d3Smrg * Calculate closest feedback divider and apply its 22232b578d3Smrg * restrictions. 22332b578d3Smrg */ 22432b578d3Smrg Multiple = M * pATI->ReferenceDenominator * 22532b578d3Smrg pATI->ClockDescriptor.PostDividers[D]; 22632b578d3Smrg N = ATIDivide(pMode->Clock * Multiple, 22732b578d3Smrg pATI->ReferenceNumerator, 0, 0); 22832b578d3Smrg if (N < pATI->ClockDescriptor.MinN) 22932b578d3Smrg N = pATI->ClockDescriptor.MinN; 23032b578d3Smrg else if (N > pATI->ClockDescriptor.MaxN) 23132b578d3Smrg N = pATI->ClockDescriptor.MaxN; 23232b578d3Smrg N -= pATI->ClockDescriptor.NAdjust; 23332b578d3Smrg N1 = (N / pATI->ClockDescriptor.N1) * pATI->ClockDescriptor.N2; 23432b578d3Smrg if (N > N1) 23532b578d3Smrg N = ATIDivide(N1 + 1, pATI->ClockDescriptor.N1, 0, 1); 23632b578d3Smrg N += pATI->ClockDescriptor.NAdjust; 23732b578d3Smrg N1 += pATI->ClockDescriptor.NAdjust; 23832b578d3Smrg 23932b578d3Smrg for (; ; N = N1) 24032b578d3Smrg { 24132b578d3Smrg /* Pick the closest setting */ 24232b578d3Smrg Frequency = abs(ATIDivide(N * pATI->ReferenceNumerator, 24332b578d3Smrg Multiple, 0, 0) - pMode->Clock); 24432b578d3Smrg if ((Frequency < MinimumGap) || 24532b578d3Smrg ((Frequency == MinimumGap) && 24632b578d3Smrg (pATIHW->FeedbackDivider < N))) 24732b578d3Smrg { 24832b578d3Smrg /* Save settings */ 24932b578d3Smrg pATIHW->FeedbackDivider = N; 25032b578d3Smrg pATIHW->ReferenceDivider = M; 25132b578d3Smrg pATIHW->PostDivider = D; 25232b578d3Smrg MinimumGap = Frequency; 25332b578d3Smrg } 25432b578d3Smrg 25532b578d3Smrg if (N <= N1) 25632b578d3Smrg break; 25732b578d3Smrg } 25832b578d3Smrg } 25932b578d3Smrg } 26032b578d3Smrg 26132b578d3Smrg Multiple = pATIHW->ReferenceDivider * pATI->ReferenceDenominator * 26232b578d3Smrg pATI->ClockDescriptor.PostDividers[pATIHW->PostDivider]; 26332b578d3Smrg Frequency = pATIHW->FeedbackDivider * pATI->ReferenceNumerator; 26432b578d3Smrg Frequency = ATIDivide(Frequency, Multiple, 0, 0); 26532b578d3Smrg if (abs(Frequency - pMode->Clock) > CLOCK_TOLERANCE) 26632b578d3Smrg { 26732b578d3Smrg xf86DrvMsg(iScreen, X_ERROR, 26832b578d3Smrg "Unable to programme clock %.3fMHz for mode %s.\n", 26932b578d3Smrg (double)(pMode->Clock) / 1000.0, pMode->name); 27032b578d3Smrg return FALSE; 27132b578d3Smrg } 27232b578d3Smrg pMode->SynthClock = Frequency; 27332b578d3Smrg ClockSelect = pATI->ClockNumberToProgramme; 27432b578d3Smrg 27532b578d3Smrg xf86ErrorFVerb(4, 27632b578d3Smrg "\n Programming clock %d to %.3fMHz for mode %s." 27732b578d3Smrg " N=%d, M=%d, D=%d.\n", 27832b578d3Smrg ClockSelect, (double)Frequency / 1000.0, pMode->name, 27932b578d3Smrg pATIHW->FeedbackDivider, pATIHW->ReferenceDivider, 28032b578d3Smrg pATIHW->PostDivider); 28132b578d3Smrg 28232b578d3Smrg if (pATI->Chip >= ATI_CHIP_264VTB) 28332b578d3Smrg ATIDSPCalculate(pATI, pATIHW, pMode); 28432b578d3Smrg } 28532b578d3Smrg 28632b578d3Smrg /* Set clock select bits */ 28732b578d3Smrg pATIHW->clock = ClockSelect; 28832b578d3Smrg 28932b578d3Smrg { 29032b578d3Smrg pATIHW->clock_cntl = CLOCK_STROBE | 29132b578d3Smrg SetBits(ClockSelect, CLOCK_SELECT | CLOCK_DIVIDER); 29232b578d3Smrg } 29332b578d3Smrg 29432b578d3Smrg return TRUE; 29532b578d3Smrg} 29632b578d3Smrg 29732b578d3Smrg/* 29832b578d3Smrg * ATIClockSet -- 29932b578d3Smrg * 30032b578d3Smrg * This function is called to programme a clock for the mode being set. 30132b578d3Smrg */ 30232b578d3Smrgvoid 30332b578d3SmrgATIClockSet 30432b578d3Smrg( 30532b578d3Smrg ATIPtr pATI, 30632b578d3Smrg ATIHWPtr pATIHW 30732b578d3Smrg) 30832b578d3Smrg{ 30932b578d3Smrg CARD32 crtc_gen_cntl, tmp; 31032b578d3Smrg CARD8 clock_cntl0; 31132b578d3Smrg CARD8 tmp2; 31232b578d3Smrg unsigned int Programme; 31332b578d3Smrg int N = pATIHW->FeedbackDivider - pATI->ClockDescriptor.NAdjust; 31432b578d3Smrg int M = pATIHW->ReferenceDivider - pATI->ClockDescriptor.MAdjust; 31532b578d3Smrg int D = pATIHW->PostDivider; 31632b578d3Smrg 31732b578d3Smrg /* Temporarily switch to accelerator mode */ 31832b578d3Smrg crtc_gen_cntl = inr(CRTC_GEN_CNTL); 31932b578d3Smrg if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN)) 32032b578d3Smrg outr(CRTC_GEN_CNTL, crtc_gen_cntl | CRTC_EXT_DISP_EN); 32132b578d3Smrg 32232b578d3Smrg switch (pATI->ProgrammableClock) 32332b578d3Smrg { 32432b578d3Smrg case ATI_CLOCK_ICS2595: 32532b578d3Smrg clock_cntl0 = in8(CLOCK_CNTL); 32632b578d3Smrg 32732b578d3Smrg Programme = (SetBits(pATIHW->clock, ICS2595_CLOCK) | 32832b578d3Smrg SetBits(N, ICS2595_FB_DIV) | SetBits(D, ICS2595_POST_DIV)) ^ 32932b578d3Smrg ICS2595_TOGGLE; 33032b578d3Smrg 33132b578d3Smrg ATIDelay(50000); /* 50 milliseconds */ 33232b578d3Smrg 33332b578d3Smrg (void)xf86DisableInterrupts(); 33432b578d3Smrg 33532b578d3Smrg /* Send all 20 bits of programme word */ 33632b578d3Smrg while (Programme >= CLOCK_BIT) 33732b578d3Smrg { 33832b578d3Smrg tmp = (Programme & CLOCK_BIT) | CLOCK_STROBE; 33932b578d3Smrg out8(CLOCK_CNTL, tmp); 34032b578d3Smrg ATIDelay(26); /* 26 microseconds */ 34132b578d3Smrg out8(CLOCK_CNTL, tmp | CLOCK_PULSE); 34232b578d3Smrg ATIDelay(26); /* 26 microseconds */ 34332b578d3Smrg Programme >>= 1; 34432b578d3Smrg } 34532b578d3Smrg 34632b578d3Smrg xf86EnableInterrupts(); 34732b578d3Smrg 34832b578d3Smrg /* Restore register */ 34932b578d3Smrg out8(CLOCK_CNTL, clock_cntl0 | CLOCK_STROBE); 35032b578d3Smrg break; 35132b578d3Smrg 35232b578d3Smrg case ATI_CLOCK_STG1703: 35332b578d3Smrg (void)ATIGetDACCmdReg(pATI); 35432b578d3Smrg (void)in8(M64_DAC_MASK); 35532b578d3Smrg out8(M64_DAC_MASK, (pATIHW->clock << 1) + 0x20U); 35632b578d3Smrg out8(M64_DAC_MASK, 0); 35732b578d3Smrg out8(M64_DAC_MASK, SetBits(N, 0xFFU)); 35832b578d3Smrg out8(M64_DAC_MASK, SetBits(M, 0x1FU) | SetBits(D, 0xE0U)); 35932b578d3Smrg break; 36032b578d3Smrg 36132b578d3Smrg case ATI_CLOCK_CH8398: 36232b578d3Smrg tmp = inr(DAC_CNTL) | (DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3); 36332b578d3Smrg outr(DAC_CNTL, tmp); 36432b578d3Smrg out8(M64_DAC_WRITE, pATIHW->clock); 36532b578d3Smrg out8(M64_DAC_DATA, SetBits(N, 0xFFU)); 36632b578d3Smrg out8(M64_DAC_DATA, SetBits(M, 0x3FU) | SetBits(D, 0xC0U)); 36732b578d3Smrg out8(M64_DAC_MASK, 0x04U); 36832b578d3Smrg outr(DAC_CNTL, tmp & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3)); 36932b578d3Smrg tmp2 = in8(M64_DAC_WRITE); 37032b578d3Smrg out8(M64_DAC_WRITE, (tmp2 & 0x70U) | 0x80U); 37132b578d3Smrg outr(DAC_CNTL, tmp & ~DAC_EXT_SEL_RS2); 37232b578d3Smrg break; 37332b578d3Smrg 37432b578d3Smrg case ATI_CLOCK_INTERNAL: 37532b578d3Smrg /* Reset VCLK generator */ 37632b578d3Smrg ATIMach64PutPLLReg(PLL_VCLK_CNTL, pATIHW->pll_vclk_cntl); 37732b578d3Smrg 37832b578d3Smrg /* Set post-divider */ 37932b578d3Smrg tmp2 = pATIHW->clock << 1; 38032b578d3Smrg tmp = ATIMach64GetPLLReg(PLL_VCLK_POST_DIV); 38132b578d3Smrg tmp &= ~(0x03U << tmp2); 38232b578d3Smrg tmp |= SetBits(D, 0x03U) << tmp2; 38332b578d3Smrg ATIMach64PutPLLReg(PLL_VCLK_POST_DIV, tmp); 38432b578d3Smrg 38532b578d3Smrg /* Set extended post-divider */ 38632b578d3Smrg tmp = ATIMach64GetPLLReg(PLL_XCLK_CNTL); 38732b578d3Smrg tmp &= ~(SetBits(1, PLL_VCLK0_XDIV) << pATIHW->clock); 38832b578d3Smrg tmp |= SetBits(D >> 2, PLL_VCLK0_XDIV) << pATIHW->clock; 38932b578d3Smrg ATIMach64PutPLLReg(PLL_XCLK_CNTL, tmp); 39032b578d3Smrg 39132b578d3Smrg /* Set feedback divider */ 39232b578d3Smrg tmp = PLL_VCLK0_FB_DIV + pATIHW->clock; 39332b578d3Smrg ATIMach64PutPLLReg(tmp, SetBits(N, 0xFFU)); 39432b578d3Smrg 39532b578d3Smrg /* End VCLK generator reset */ 39632b578d3Smrg ATIMach64PutPLLReg(PLL_VCLK_CNTL, 39732b578d3Smrg pATIHW->pll_vclk_cntl & ~PLL_VCLK_RESET); 39832b578d3Smrg 39932b578d3Smrg /* Reset write bit */ 40032b578d3Smrg ATIMach64AccessPLLReg(pATI, 0, FALSE); 40132b578d3Smrg break; 40232b578d3Smrg 40332b578d3Smrg case ATI_CLOCK_ATT20C408: 40432b578d3Smrg (void)ATIGetDACCmdReg(pATI); 40532b578d3Smrg tmp = in8(M64_DAC_MASK); 40632b578d3Smrg (void)ATIGetDACCmdReg(pATI); 40732b578d3Smrg out8(M64_DAC_MASK, tmp | 1); 40832b578d3Smrg out8(M64_DAC_WRITE, 1); 40932b578d3Smrg out8(M64_DAC_MASK, tmp | 9); 41032b578d3Smrg ATIDelay(400); /* 400 microseconds */ 41132b578d3Smrg tmp2 = (pATIHW->clock << 2) + 0x40U; 41232b578d3Smrg out8(M64_DAC_WRITE, tmp2); 41332b578d3Smrg out8(M64_DAC_MASK, SetBits(N, 0xFFU)); 41432b578d3Smrg out8(M64_DAC_WRITE, ++tmp2); 41532b578d3Smrg out8(M64_DAC_MASK, SetBits(M, 0x3FU) | SetBits(D, 0xC0U)); 41632b578d3Smrg out8(M64_DAC_WRITE, ++tmp2); 41732b578d3Smrg out8(M64_DAC_MASK, 0x77U); 41832b578d3Smrg ATIDelay(400); /* 400 microseconds */ 41932b578d3Smrg out8(M64_DAC_WRITE, 1); 42032b578d3Smrg out8(M64_DAC_MASK, tmp); 42132b578d3Smrg break; 42232b578d3Smrg 42332b578d3Smrg case ATI_CLOCK_IBMRGB514: 42432b578d3Smrg /* 42532b578d3Smrg * Here, only update in-core data. It will be written out later by 42632b578d3Smrg * ATIRGB514Set(). 42732b578d3Smrg */ 42832b578d3Smrg tmp = (pATIHW->clock << 1) + 0x20U; 42932b578d3Smrg pATIHW->ibmrgb514[tmp] = 43032b578d3Smrg (SetBits(N, 0x3FU) | SetBits(D, 0xC0U)) ^ 0xC0U; 43132b578d3Smrg pATIHW->ibmrgb514[tmp + 1] = SetBits(M, 0x3FU); 43232b578d3Smrg break; 43332b578d3Smrg 43432b578d3Smrg default: 43532b578d3Smrg break; 43632b578d3Smrg } 43732b578d3Smrg 43832b578d3Smrg (void)in8(M64_DAC_WRITE); /* Clear DAC counter */ 43932b578d3Smrg 44032b578d3Smrg /* Restore register */ 44132b578d3Smrg if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN)) 44232b578d3Smrg outr(CRTC_GEN_CNTL, crtc_gen_cntl); 44332b578d3Smrg} 444