CirrusClk.c revision 76888252
176888252Smrg/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cirrus/CirrusClk.c,v 1.8 1998/12/06 06:08:28 dawes Exp $ */ 276888252Smrg 376888252Smrg#ifdef HAVE_CONFIG_H 476888252Smrg#include "config.h" 576888252Smrg#endif 676888252Smrg 776888252Smrg/* 876888252Smrg * Programming of the built-in Cirrus clock generator. 976888252Smrg * Harm Hanemaayer <hhanemaa@cs.ruu.nl> 1076888252Smrg * 1176888252Smrg * VCO stability criterion code added by Koen Gadeyne (koen.gadeyne@barco.com) 1276888252Smrg * Max clock specification added by Harm Hanemaayer (H.Hanemaayer@inter.nl.net) 1376888252Smrg * 1476888252Smrg * Minor changes and cleanup Itai Nahshon. 1576888252Smrg * 1676888252Smrg * Made this completly chipset independent, and moved chipset dependent parts 1776888252Smrg * into the specific sub-drivers. Derek Fawcus <derek@spider.com> 1876888252Smrg */ 1976888252Smrg 2076888252Smrg#include "xf86.h" 2176888252Smrg#include "xf86_OSproc.h" 2276888252Smrg#include "xf86PciInfo.h" 2376888252Smrg#include "xf86Pci.h" 2476888252Smrg 2576888252Smrg#include "cir.h" 2676888252Smrg 2776888252Smrg/* CLOCK_FACTOR is double the osc freq in kHz (osc = 14.31818 MHz) */ 2876888252Smrg#define CLOCK_FACTOR 28636 2976888252Smrg 3076888252Smrg/* Stability constraints for internal VCO -- MAX_VCO also determines 3176888252Smrg * the maximum Video pixel clock 3276888252Smrg */ 3376888252Smrg#define MIN_VCO CLOCK_FACTOR 3476888252Smrg#define MAX_VCO 111000 3576888252Smrg 3676888252Smrg/* clock in kHz is (numer * CLOCK_FACTOR / (denom & 0x3E)) >> (denom & 1) */ 3776888252Smrg#define VCOVAL(n, d) \ 3876888252Smrg ((((n) & 0x7F) * CLOCK_FACTOR / ((d) & 0x3E)) ) 3976888252Smrg 4076888252Smrg#define CLOCKVAL(n, d) \ 4176888252Smrg (VCOVAL(n, d) >> ((d) & 1)) 4276888252Smrg 4376888252Smrgtypedef struct { 4476888252Smrg unsigned char numer; 4576888252Smrg unsigned char denom; 4676888252Smrg} cirrusClockRec; 4776888252Smrg 4876888252Smrgstatic cirrusClockRec cirrusClockTab[] = { 4976888252Smrg { 0x2C, 0x33 }, /* 12.599 */ 5076888252Smrg { 0x4A, 0x2B }, /* 25.227 */ 5176888252Smrg { 0x5B, 0x2F }, /* 28.325 */ 5276888252Smrg { 0x45, 0x30 }, /* 41.164 */ 5376888252Smrg { 0x7E, 0x33 }, /* 36.082 */ 5476888252Smrg { 0x42, 0x1F }, /* 31.500 */ 5576888252Smrg { 0x51, 0x3A }, /* 39.992 */ 5676888252Smrg { 0x55, 0x36 }, /* 45.076 */ 5776888252Smrg { 0x65, 0x3A }, /* 49.867 */ 5876888252Smrg { 0x76, 0x34 }, /* 64.983 */ 5976888252Smrg { 0x7E, 0x32 }, /* 72.163 */ 6076888252Smrg { 0x6E, 0x2A }, /* 75.000 */ 6176888252Smrg { 0x5F, 0x22 }, /* 80.013 */ 6276888252Smrg { 0x7D, 0x2A }, /* 85.226 */ 6376888252Smrg { 0x58, 0x1C }, /* 89.998 */ 6476888252Smrg { 0x49, 0x16 }, /* 95.019 */ 6576888252Smrg { 0x46, 0x14 }, /* 100.226 */ 6676888252Smrg { 0x53, 0x16 }, /* 108.035 */ 6776888252Smrg { 0x5C, 0x18 }, /* 110.248 */ 6876888252Smrg 6976888252Smrg { 0x6D, 0x1A }, /* 120.050 */ 7076888252Smrg { 0x58, 0x14 }, /* 125.998 */ 7176888252Smrg { 0x6D, 0x18 }, /* 130.055 */ 7276888252Smrg { 0x42, 0x0E }, /* 134.998 */ 7376888252Smrg 7476888252Smrg { 0x69, 0x14 }, /* 150.341 */ 7576888252Smrg { 0x5E, 0x10 }, /* 168.239 */ 7676888252Smrg { 0x5C, 0x0E }, /* 188.182 */ 7776888252Smrg { 0x67, 0x0E }, /* 210.682 */ 7876888252Smrg { 0x60, 0x0C }, /* 229.091 */ 7976888252Smrg}; 8076888252Smrg 8176888252Smrg#define NU_FIXED_CLOCKS (sizeof(cirrusClockTab)/sizeof(cirrusClockTab[0])) 8276888252Smrg 8376888252Smrg 8476888252Smrg/* 8576888252Smrg * This function returns the 7-bit numerator and 6-bit denominator/post-scalar 8676888252Smrg * value that corresponds to the closest clock found. 8776888252Smrg * If a frequency close to one of the tested clock values is found, 8876888252Smrg * use the tested clock since others can be unstable. 8976888252Smrg */ 9076888252Smrg 9176888252SmrgBool 9276888252SmrgCirrusFindClock(int *rfreq, int max_clock, int *num_out, int *den_out) 9376888252Smrg{ 9476888252Smrg int n, i; 9576888252Smrg int num = 0, den = 0; 9676888252Smrg int freq, ffreq = 0, mindiff = 0; 9776888252Smrg 9876888252Smrg freq = *rfreq; 9976888252Smrg /* Prefer a tested value if it matches within 0.1%. */ 10076888252Smrg for (i = 0; i < NU_FIXED_CLOCKS; i++) { 10176888252Smrg int diff; 10276888252Smrg diff = abs(CLOCKVAL(cirrusClockTab[i].numer, 10376888252Smrg cirrusClockTab[i].denom) - freq); 10476888252Smrg if (diff < freq / 1000) { 10576888252Smrg num = cirrusClockTab[i].numer; 10676888252Smrg den = cirrusClockTab[i].denom; 10776888252Smrg ffreq = CLOCKVAL(num, den); 10876888252Smrg goto foundclock; 10976888252Smrg } 11076888252Smrg } 11176888252Smrg 11276888252Smrg /* 11376888252Smrg * If max_clock is greater than the MAX_VCO default, ignore 11476888252Smrg * MAX_VCO. On the other hand, if MAX_VCO is higher than max_clock, 11576888252Smrg * make use of the higher MAX_VCO value. 11676888252Smrg */ 11776888252Smrg if (MAX_VCO > max_clock) 11876888252Smrg max_clock = MAX_VCO; 11976888252Smrg 12076888252Smrg mindiff = freq; 12176888252Smrg for (n = 0x10; n < 0x7f; n++) { 12276888252Smrg int d; 12376888252Smrg for (d = 0x14; d < 0x3f; d++) { 12476888252Smrg int c, diff; 12576888252Smrg 12676888252Smrg /* Avoid combinations that can be unstable. */ 12776888252Smrg if ((VCOVAL(n, d) < MIN_VCO) || (VCOVAL(n, d) > max_clock)) 12876888252Smrg continue; 12976888252Smrg c = CLOCKVAL(n, d); 13076888252Smrg diff = abs(c - freq); 13176888252Smrg if (diff < mindiff) { 13276888252Smrg mindiff = diff; 13376888252Smrg num = n; 13476888252Smrg den = d; 13576888252Smrg ffreq = c; 13676888252Smrg } 13776888252Smrg } 13876888252Smrg } 13976888252Smrg 14076888252Smrg if (0 == num || 0 == den) 14176888252Smrg return FALSE; 14276888252Smrg 14376888252Smrgfoundclock: 14476888252Smrg *num_out = num; 14576888252Smrg *den_out = den; 14676888252Smrg *rfreq = ffreq; 14776888252Smrg 14876888252Smrg return TRUE; 14976888252Smrg} 150