smi_dac.c revision 09885543
109885543Smrg/* Header: //Mercury/Projects/archives/XFree86/4.0/smi_dac.c-arc 1.8 27 Nov 2000 15:47:08 Frido $ */ 209885543Smrg 309885543Smrg/* 409885543SmrgCopyright (C) 1994-1998 The XFree86 Project, Inc. All Rights Reserved. 509885543SmrgCopyright (C) 2000 Silicon Motion, Inc. All Rights Reserved. 609885543Smrg 709885543SmrgPermission is hereby granted, free of charge, to any person obtaining a copy of 809885543Smrgthis software and associated documentation files (the "Software"), to deal in 909885543Smrgthe Software without restriction, including without limitation the rights to 1009885543Smrguse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 1109885543Smrgof the Software, and to permit persons to whom the Software is furnished to do 1209885543Smrgso, subject to the following conditions: 1309885543Smrg 1409885543SmrgThe above copyright notice and this permission notice shall be included in all 1509885543Smrgcopies or substantial portions of the Software. 1609885543Smrg 1709885543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1809885543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- 1909885543SmrgNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2009885543SmrgXFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 2109885543SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 2209885543SmrgWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2309885543Smrg 2409885543SmrgExcept as contained in this notice, the names of the XFree86 Project and 2509885543SmrgSilicon Motion shall not be used in advertising or otherwise to promote the 2609885543Smrgsale, use or other dealings in this Software without prior written 2709885543Smrgauthorization from the XFree86 Project and Silicon Motion. 2809885543Smrg*/ 2909885543Smrg/* $XFree86$ */ 3009885543Smrg 3109885543Smrg#ifdef HAVE_CONFIG_H 3209885543Smrg#include "config.h" 3309885543Smrg#endif 3409885543Smrg 3509885543Smrg#include "smi.h" 3609885543Smrg 3709885543Smrg#define BASE_FREQ 14.31818 /* MHz */ 3809885543Smrg 3909885543Smrgvoid 4009885543SmrgSMI_CommonCalcClock(int scrnIndex, long freq, int min_m, int min_n1, 4109885543Smrg int max_n1, int min_n2, int max_n2, long freq_min, 4209885543Smrg long freq_max, unsigned char *mdiv, unsigned char *ndiv) 4309885543Smrg{ 4409885543Smrg ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 4509885543Smrg SMIPtr pSmi = SMIPTR(pScrn); 4609885543Smrg double div, diff, best_diff; 4709885543Smrg unsigned int m; 4809885543Smrg unsigned char n1, n2; 4909885543Smrg unsigned char best_n1 = 63, best_n2 = 3, best_m = 255; 5009885543Smrg 5109885543Smrg double ffreq = freq / 1000.0 / BASE_FREQ; 5209885543Smrg double ffreq_min = freq_min / 1000.0 / BASE_FREQ; 5309885543Smrg double ffreq_max = freq_max / 1000.0 / BASE_FREQ; 5409885543Smrg 5509885543Smrg if (ffreq < ffreq_min / (1 << max_n2)) { 5609885543Smrg xf86DrvMsg(scrnIndex,X_WARNING,"invalid frequency %1.3f MHz [freq >= %1.3f MHz]\n", 5709885543Smrg ffreq * BASE_FREQ, ffreq_min * BASE_FREQ / (1 << max_n2)); 5809885543Smrg ffreq = ffreq_min / (1 << max_n2); 5909885543Smrg } 6009885543Smrg if (ffreq > ffreq_max / (1 << min_n2)) { 6109885543Smrg xf86DrvMsg(scrnIndex,X_WARNING,"invalid frequency %1.3f MHz [freq <= %1.3f MHz]\n", 6209885543Smrg ffreq * BASE_FREQ, ffreq_max * BASE_FREQ / (1 << min_n2)); 6309885543Smrg ffreq = ffreq_max / (1 << min_n2); 6409885543Smrg } 6509885543Smrg 6609885543Smrg /* work out suitable timings */ 6709885543Smrg best_diff = ffreq; 6809885543Smrg 6909885543Smrg for (n2 = min_n2; n2 <= max_n2; n2++) { 7009885543Smrg for (n1 = min_n1; n1 <= max_n1; n1++) { 7109885543Smrg m = (int)(ffreq * n1 * (1 << n2) + 0.5); 7209885543Smrg if ( (m < min_m) || (m > 255) ) { 7309885543Smrg continue; 7409885543Smrg } 7509885543Smrg div = (double)(m) / (double)(n1); 7609885543Smrg if ( (div >= ffreq_min) && (div <= ffreq_max) ) { 7709885543Smrg diff = ffreq - div / (1 << n2); 7809885543Smrg if (diff < 0.0) { 7909885543Smrg diff = -diff; 8009885543Smrg } 8109885543Smrg if (diff < best_diff) { 8209885543Smrg best_diff = diff; 8309885543Smrg best_m = m; 8409885543Smrg best_n1 = n1; 8509885543Smrg best_n2 = n2; 8609885543Smrg } 8709885543Smrg } 8809885543Smrg } 8909885543Smrg } 9009885543Smrg 9109885543Smrg DEBUG((VERBLEV, "Clock parameters for %1.6f MHz: m=%d, n1=%d, n2=%d\n", 9209885543Smrg ((double)(best_m) / (double)(best_n1) / (1 << best_n2)) * BASE_FREQ, 9309885543Smrg best_m, best_n1, best_n2)); 9409885543Smrg 9509885543Smrg if (SMI_LYNX_SERIES(pSmi->Chipset)) { 9609885543Smrg *ndiv = best_n1 | (best_n2 << 6); 9709885543Smrg } else { 9809885543Smrg *ndiv = best_n1 | (best_n2 << 7); 9909885543Smrg if (freq > 120000) 10009885543Smrg *ndiv |= 1 << 6; 10109885543Smrg } 10209885543Smrg 10309885543Smrg *mdiv = best_m; 10409885543Smrg} 10509885543Smrg 106