/* $XFree86: xc/programs/Xserver/hw/xfree86/common_hw/ATTDac.c,v 3.5 1996/12/23 06:44:00 dawes Exp $ */ /* * Copyright 1994 by David Wexelblat * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of David Wexelblat not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. David Wexelblat makes no representations * about the suitability of this software for any purpose. It is provided * "as is" without express or implied warranty. * * DAVID WEXELBLAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL DAVID WEXELBLAT BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * */ /* $XConsortium: ATTDac.c /main/9 1996/05/07 17:12:54 kaleb $ */ #include "Xfuncproto.h" #include "compiler.h" #define NO_OSLIB_PROTOTYPES #include "xf86_OSlib.h" #include "misc.h" /* #include "xf86_HWlib.h" */ #define ATT409_CC 0x06 #define ATT409_CR0 0x01 void xf86dactopel() { outb(0x3C8,0); return; } unsigned char xf86dactocomm() { (void)inb(0x3C6); (void)inb(0x3C6); (void)inb(0x3C6); return(inb(0x3C6)); } unsigned char xf86getdaccomm() { unsigned char ret; xf86dactopel(); (void)xf86dactocomm(); ret = inb(0x3C6); xf86dactopel(); #ifdef EXTENDED_DEBUG ErrorF("Old CR0 0x%x\n",ret); #endif return(ret); } void xf86setdaccomm(comm) unsigned char comm; { xf86dactopel(); (void)xf86dactocomm(); outb(0x3C6, comm); xf86dactopel(); #ifdef EXTENDED_DEBUG ErrorF("New CR0 0x%x\n",comm); #endif return; } void xf86setdaccommbit(bits) unsigned char bits; { unsigned char tmp; tmp = xf86getdaccomm() | bits; xf86setdaccomm(tmp); return; } void xf86clrdaccommbit(bits) unsigned char bits; { unsigned char tmp; tmp = xf86getdaccomm() & ~bits; xf86setdaccomm(tmp); return; } unsigned char xf86getdacregindexed(idx) unsigned char idx; { unsigned char ret; /* * first check if we are in indexed mode */ if( !xf86testdacindexed() ) { ret = xf86getdaccomm(); ErrorF("Yieck! CR0 = 0x%x which is not indexed mode\n",ret); } outb(0x3C8,idx); ret = inb(0x3C6); #ifdef EXTENDED_DEBUG ErrorF("Index 0x%x is 0x%x\n",idx,ret); #endif return(ret); } void xf86setdacregindexed(idx,val) unsigned char idx; unsigned char val; { unsigned char tmp; /* * first check if we are in indexed mode */ if( !xf86testdacindexed() ) { tmp = xf86getdaccomm(); ErrorF("Yieck! CR0 = 0x%x which is not indexed mode\n",tmp); } #ifdef EXTENDED_DEBUG outb(0x3C8,idx); tmp = inb(0x3C6); #endif outb(0x3C8,idx); outb(0x3C6,val); #ifdef EXTENDED_DEBUG ErrorF("Index 0x%x set to 0x%x (was 0x%x)\n",idx,val,tmp); #endif return; } int xf86testdacindexed() { /* * figure out whether we are in indexed addressing mode */ outb(0x3C8,0); /* reset state machine, if we are non-index */ (void) inb(0x3C6); (void) inb(0x3C6); (void) inb(0x3C6); (void) inb(0x3C6); (void) inb(0x3C6); if( (inb(0x3C6) != 0x84) || ((inb(0x3C6) & 0xf) != 9) ) return TRUE; else return FALSE; } static void Att409UseClock(clk) int clk; { unsigned char tmp; /* * this function should only be called when the chip is in indexed * addressing mode (CR0[0] = 1) !! */ tmp = xf86getdacregindexed(ATT409_CC); if( clk <= 3 ) { /* * this sets the PCLK (Clock A) by setting CC[5:4] */ xf86setdacregindexed(ATT409_CC, (tmp & 0xCF) | 0x80 | clk << 4); } else { /* * this sets the MCLK (Clock B) by setting CC[1:0] */ xf86setdacregindexed(ATT409_CC, (tmp & 0xFC) | 0x08 | (clk & 3)); } #ifdef EXTENDED_DEBUG ErrorF("CC set to 0x%x (was 0x%x)\n", xf86getdacregindexed(ATT409_CC),tmp); #endif return; } #define BASE_FREQ 14.31818 #define FREQ_MIN (120000.0 / 8.0) /* p = 3 */ #define FREQ_MAX (240000.0 / 1.0) /* p = 0 */ static void Att409CalcMNP(freq,m,n,p) long freq; unsigned char *m,*n,*p; { double ffreq, ffreq_min, ffreq_max; double div, diff, best_diff; unsigned int mm,nn; int pp; /* let's make that signed so the loop is easier to phrase */ unsigned char best_n=5+2, best_p=2, best_m=125+2; ffreq = freq / 1000.0 / BASE_FREQ; ffreq_min = FREQ_MIN / 1000.0 / BASE_FREQ; ffreq_max = FREQ_MAX / 1000.0 / BASE_FREQ; best_diff = ffreq; for (pp=3; pp >= 0; pp--) { for (nn = 0+2; nn <= 63+2; nn++) { mm = (int)(ffreq * nn * (1< 255+2) continue; div = (double)(mm) / (double)(nn); if ((div >= ffreq_min) && (div <= ffreq_max)) { diff = ffreq - div / (1<= 4) ? 0x10 : 0x0); reg_n = 0x41 + 4*clk + ((clk >= 4) ? 0x10 : 0x0); Att409CalcMNP(freq,&m,&n,&p); n = (n & 0x3f) | ((p & 0x3) << 6); /* combine n and p into 8 bit */ #ifdef EXTENDED_DEBUG ErrorF("setting Clk %d to %1.6f MHz (m %d, n %d, p %d)\n", clk, ((double)(m+2)/(double)((n&0x3f)+2)/(1<