|
|
/* ======================================================================= */ /*
/* Filename : CLOCK.C
/* Creation : Dominique Leblanc 92/10/26
/*
/*
/* This file contains the different routines to program the ICD2061
/* oscillator for the MGA family.
/*
/* Modifications List:
/* D.L. 92/11/30: modification for a limited condition of
/* searching for an exact frequency.
/*
/* Bart Simpson: Adaptation for CADDI
/*
/* ======================================================================= */
#include "switches.h"
#include "g3dstd.h"
#include "caddi.h"
#include "def.h"
#include "mga.h"
#include "global.h"
#include "proto.h"
#include "mgai_c.h"
#include "mgai.h"
#ifdef WINDOWS_NT
#if defined(ALLOC_PRAGMA)
#pragma alloc_text(PAGE,setFrequence)
#pragma alloc_text(PAGE,programme_clock)
#pragma alloc_text(PAGE,dummyCallDelai)
#pragma alloc_text(PAGE,programme_reg_icd)
#pragma alloc_text(PAGE,send_unlock)
#pragma alloc_text(PAGE,send_data)
#pragma alloc_text(PAGE,send_full_clock)
#pragma alloc_text(PAGE,send_start)
#pragma alloc_text(PAGE,send_0)
#pragma alloc_text(PAGE,send_1)
#pragma alloc_text(PAGE,send_stop)
#pragma alloc_text(PAGE,setTVP3026Freq)
#endif
#if defined(ALLOC_PRAGMA)
#pragma data_seg("PAGE")
#endif
#include "video.h"
#endif /* #ifdef WINDOWS_NT */
static volatile BYTE _Far * pDevice;
typedef unsigned char byte; typedef unsigned short word; typedef unsigned long dword;
/* this keep mclk f(vco) value to use with jitter VCLK=MCLK output value. */ /* updated by function <ProgrammeClock> in module mtxinit.c */ extern void delay_us(dword delai);
extern long presentMclk[]; /* MCLK currently in use (module mtxinit.c) */ extern byte iBoard; /* index of current selected board (module mtxinit.c)*/
typedef struct { short p; short q; short m; short i; long trueFout; long fvco; /* for jitter problem, keep osc. value */ long ppmError; } ST_RESULTAT;
static ST_RESULTAT result; static byte init_misc;
typedef union { byte var8; byte byte; byte octet;
struct { byte enable_color : 1; /* 1=COLOR:0x3D?, 0=MONO:0x3B? */ byte enable_RAM : 1; byte cs0 : 1; byte cs1 : 1; byte reserved : 1; byte page_select : 1; byte h_pol : 1; byte v_pol : 1;
} bit;
struct { byte unused : 2; byte pgmclk : 1; byte pgmdata : 1; byte reserved : 4;
} clock_bit;
struct { byte unused : 2; byte select : 2; byte reserved : 4;
} sel_reg_output;
} ST_MISC_OUTPUT;
#define MISC_OUTPUT_WRITE 0x03C2
#define MISC_OUTPUT_READ 0x03CC
#define NBRE_M_POSSIBLE 7
static ST_MISC_OUTPUT misc;
typedef union { dword var32; dword dmot; dword ulong;
struct { dword q_prime : 7; dword m_diviseur : 3; dword p_prime : 7; dword index_field : 4; dword unused : 11;
} bit;
} ST_REG_PROGRAM_DATA;
ST_REG_PROGRAM_DATA reg_clock[4] = { { 0x5A8BCL }, /* REG0 video 1 */ { 0x960ACL }, /* REG1 video 2 */ { 0x960ACL }, /* REG2 video 3 */ { 0xD44A3L }, /* MREG memory */ };
static long diviseur_m [ NBRE_M_POSSIBLE ] = { 1, /* 0 */ 2, /* 1 */ 4, /* 2 */ 8, /* 3 */ 16, /* 4 */ 32, /* 5 */ 64, /* 6 */ /* 64, /* 7 */ /* we don't use this case in our calculations */ };
/* static long limites_i [ NBRE_I_POSSIBLE ] = old see below */ static long limites_i [] = {/* min, max, I */ 50000L, /* 47500000 0 */ 51000L, /* 47500000 1 */ 53200L, /* 52200000 2 */ 58500L, /* 56300000 3 */ 60700L, /* 61900000 4 */ 64400L, /* 65000000 5 */ 66800L, /* 68100000 6 */ 73500L, /* 82300000 7 */ 75600L, /* 86000000 8 */ 80900L, /* 88000000 9 */ 83200L, /* 90500000 10 */ 91500L, /* 95000000 11 */ 100000L, /* 1.0E+08 12 */ 120000L, /* 1.2E+08 13 */ /* 120000000L, /* 14 */ }; #define NBRE_I_POSSIBLE ( (sizeof(limites_i)) / (sizeof(long)) )
/* old frequency & keep default value (power up)
* there is output frequency value f(o) */
long old_fr_reg[4] = { { 25175L }, /* REG0 video 1 */ { 28322L }, /* REG1 video 2 */ { 28322L }, /* REG2 video 3 */ { 32500L }, /* MREG memory */ };
/**************** LIST OF REGISTERS OF ICD2061 ************************/
#define NBRE_REG_ICD2061 6
#define VIDEO_CLOCK_1 0
#define VIDEO_CLOCK_2 1
#define VIDEO_CLOCK_3 2
#define MEMORY_CLOCK 3
#define POWERDWN_REG 4
#define CONTROL_ICD2061 6
static long fref;
/**************************** list of routines in this file *************/
dword programme_clock ( short reg, short p, short q, short m, short i ); void programme_reg_icd ( volatile BYTE _Far * pDeviceParam, short reg, dword data ); static void send_unlock ( void ); static void send_data ( short reg, dword data ); static void send_full_clock ( void ); static void send_start ( void ); static void send_0 ( void ); static void send_1 ( void ); static void send_stop ( void ); static byte selectIcdOutputReg ( long reg ); static void LowerVCO(long Fout, byte pll, byte pwidth, dword fvcomax, byte dac_rev1);
/*** Temporary delay to be put after each acces to programable register ***/ void dummyCallDelai() { byte TmpByte;
mgaReadBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), TmpByte); }
/***************************************************************************/ /*/ setFrequence ( volatile BYTE _Far *pDeviceParam, long fout, long reg )
* * For a given frequency, determines the best values to put for the * programming of the ICD2061. * Programs the register. * If outgoing frequency is 0, this function only chooses the output register. * * Problemes : * Concu : Dominique Leblanc:92/10/29 * * Parametres: [0]-frequency output. * [1]-register (0, 1, 2 ou 3) which will be used * (the register 3 MCLK cannot be used as output * * Returns : programmed frequency (or 0) * */
long setFrequence ( volatile BYTE _Far *pDeviceParam, long fout, long reg ) { short i;
long p, q, m; short index; short i_find;
long old_frequency; long fvco, trueFout, desiredFout; long fdivise; long ppmError; long bestError; long ftmp;
fref = 1431818; /* frequence XTAL */
pDevice = pDeviceParam;
mgaReadBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_R), init_misc); misc.var8 = init_misc;
/* special condition: if VCLK is a multiple of MCLK,
* use special programming multiple VCLK=MCLK */
if ( reg != MEMORY_CLOCK ) {
/*
* 4&3rd case include in same one "for(i=0;... * at place of check1(), and for(i=1;...)" * * 4rd case: MCLK is soo far as VCLK (.5%) * look for jither problems if both oscillator clock are same or * closer one from the other, change video frequency to * use MCLK redirection. * 3rd case: MCLK is multiple of VCLK * if mclk is multiple of mclk, divide vclk * ex. mclk=50MHz, vclk=25MHz, * vclk(fvco)=mclk(fvco) * mclk==> 50mhz, * vclk==> 50mhz/2 */ i_find = NO; for ( i = 0 ; ( i < NBRE_M_POSSIBLE && i_find == NO ) ; i++ ) { ftmp = ( fout * 1000L ) * diviseur_m[i];
if ( ( ftmp >= ( presentMclk[iBoard] - (presentMclk[iBoard]/200) ) ) && ( ftmp <= ( presentMclk[iBoard] + (presentMclk[iBoard]/200) ) ) ) { i_find = YES; /* MCLK is multiple of VCLK */ index = i; /* keep divisor value */ } }
if ( i_find == YES ) { old_frequency = old_fr_reg[reg]; old_fr_reg[reg] = fout / 1000L;
/*
* We program VCLK since it use same MCLK fvco origin. * We reprogram only I value in register to use MCLK on * VCLCK, and m divisor (see ICD2061A for more details). */ /***** putMclkOnVclk ( reg, index ); *****/ reg_clock[reg].bit.m_diviseur = index; reg_clock[reg].bit.index_field = 0xF; /* MCLK fvco value */
programme_reg_icd (pDevice, (short)reg, reg_clock[reg].var32);
dummyCallDelai();
selectIcdOutputReg ( reg ); return ( old_frequency ); /* QUIT */ } }
/***************************************************/ /*
/* MUST ONLY PROGRAM THE REGISTER
/*
/***************************************************/
if ( fout == 0L ) {
switch ( reg ) { case VIDEO_CLOCK_1: case VIDEO_CLOCK_2: misc.sel_reg_output.select = (byte)reg; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8); break;
case VIDEO_CLOCK_3: misc.sel_reg_output.select = 3; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8); break;
default: /* par defaut, (si on a modifie MCLK), on restore VCLK
* initial */ mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), init_misc); break; }
return ( NO ); }
/***************************************************/ /*
/* MUST CALCULATE A FREQUENCY
/*
/***************************************************/
desiredFout = fout;
index = 0; bestError = 99999999; /* dummy start number */
for ( m = 0 ; m < NBRE_M_POSSIBLE ; m++ ) /* for all possible divisors */ {
fdivise = diviseur_m[m];
fvco = fdivise * desiredFout;
if ((fvco < 40000) || (fvco > 120000)) continue;
for ( q = 3 ; q <= 129 ; q++ ) {
if ( ((fref/q) < 20000) || ((fref/q) > 100000)) continue;
p = ((q * fvco * 100) / (2 * fref)) + 1;
if (p < 4 || p > 130) continue;
/**************************************************
* now that we have all our values * we determine the true f(output), and its error. */
trueFout = (2 * fref * p) / (q * fdivise * 100) ;
if (trueFout > desiredFout) ppmError = trueFout - desiredFout; else ppmError = desiredFout - trueFout;
if ( ppmError < bestError ) { /***************************************************
* * HO!!! this result is better than the preceding one * */
i_find = -1; for ( i = 0 ; i < NBRE_I_POSSIBLE ; i++ ) {
if ( ( fvco >= limites_i[i] ) && ( fvco <= limites_i[i+1] ) ) i_find = i; }
if ( i_find != -1 ) { index = 0; /* reset result table */
result.p = (short)p; result.q = (short)q; result.m = (short)m; result.i = i_find; result.trueFout = trueFout; result.fvco = fout; /* keep real value */ result.ppmError = ppmError;
index++; /* find a good value */
bestError = ppmError; /* reset reference erreur */ } } } }
if ( index == 0 ) { /* restore valeur de depart */
/* outb ( MISC_OUTPUT_WRITE , init_misc ); */
mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), init_misc);
} else {
programme_clock ( (short)reg, result.p, result.q, result.m, result.i );
selectIcdOutputReg ( reg );
/* SAVE PRESENT FREQUENCY in kHz */ old_frequency = old_fr_reg[reg]; /* RETURN VALUE */ old_fr_reg[reg] = fout / 1000L; }
dummyCallDelai();
return (old_frequency); }
/* ======================================================================= */
/*/
* NAME: selectIcdOutputReg ( long reg ) * * Select desired output register. * */
static byte selectIcdOutputReg ( long reg ) {
/********************************************/ /*
/* PROGRAMME CS : clock output select
/*
/********************************************/
switch ( reg ) { case VIDEO_CLOCK_1: case VIDEO_CLOCK_2: misc.sel_reg_output.select = (byte)reg; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8); break;
case VIDEO_CLOCK_3: misc.sel_reg_output.select = 3; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8); break;
default: /*** MEMORY CLOCK ***/ /*
* if we modify MCLK, restore VCLK initial value */ mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), init_misc); presentMclk[iBoard] = result.fvco; break; }
dummyCallDelai();
return ( misc.var8 ); }
/* ======================================================================= */ /*/
* NAME: programme_clock ( short p, short q, short m, short reg ) * * Program the clock of the programmable oscillator for the desired * frequency. * */
dword programme_clock ( short reg, short p, short q, short m, short i ) { reg_clock [ reg ].var32 = 0; reg_clock [ reg ].bit.q_prime = q - 2; reg_clock [ reg ].bit.m_diviseur = m; reg_clock [ reg ].bit.p_prime = p - 3; reg_clock [ reg ].bit.index_field = i;
programme_reg_icd ( pDevice, reg, reg_clock [ reg ].var32 );
dummyCallDelai();
return ( reg_clock [ reg ] .var32 ); }
/* ======================================================================= */ /*/
* NAME: programme_reg_icd ( volatile BYTE _Far *pDeviceParam, short reg, dword data ) * * This routine permits the serial programming of the programmable oscillator * (ICD2061). It uses the following communication protocol * (from HARDWARE SPECs): * * * ^ . . . . . . * | . . . . . . * | . _ _ _ _ _ ___ ____ ____ ___ _._ * CLK |_____| |_| |_| |_| |_| |___| . |___| . |___| . |___| . |___| . * | . . . . . . * | . . . . . . * | . _____________________ . . ___ . ___________._ * DATA |___| |____________| |________| . . * +-----------------------------------------------------------------> * | . unlock sequence . start . send 0 . send 1 . stop . * | . . bit . . . bit . * | * * * * Parameters: [0] - reg: address of internal register of the ICD2061 (3 bits). * [1] - data: data to write in reg (21 bits). * */
void programme_reg_icd ( volatile BYTE _Far *pDeviceParam, short reg, dword data ) { pDevice = pDeviceParam;
send_unlock (); send_start (); send_data ( reg, data ); send_stop (); }
/* ======================================================================= */ /*/
* NAME: send_unlock ( void ) * * Send unlock sequence * */
static void send_unlock ( void ) { misc.clock_bit.pgmdata = 1; misc.clock_bit.pgmclk = 0; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8);
dummyCallDelai();
send_full_clock (); send_full_clock (); send_full_clock (); send_full_clock (); send_full_clock (); }
/* ======================================================================= */ /*/
* NAME: send_data ( void ) * * Sends 21 bits of data + 3 bits for the register. * */
static void send_data ( short reg, dword data ) { short i;
for ( i = 0 ; i < 21 ; i++ ) { if ( ( data & 1 ) == 1 ) send_1 (); else send_0 ();
data >>= 1; }
for ( i = 0 ; i < 3 ; i++ ) { if ( ( reg & 1 ) == 1 ) send_1 (); else send_0 ();
reg >>= 1; } }
/* ======================================================================= */ /*/
* NAME: send_full_clock ( void ) * * Toggle one full clock (used only by send_unlock()"). * */
static void send_full_clock ( void ) { misc.clock_bit.pgmclk = 1; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8);
/*** delay to be sure to respect the programming setup time of the ICD2061 */ dummyCallDelai();
misc.clock_bit.pgmclk = 0; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8);
/*** delay to be sure to respect the programming setup time of the ICD2061 */ dummyCallDelai(); }
/* ======================================================================= */ /*/
* NAME: send_start ( void ) * * Send start sequence * */
static void send_start ( void ) { misc.clock_bit.pgmdata = 0; misc.clock_bit.pgmclk = 0; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8);
dummyCallDelai();
send_full_clock ();
misc.clock_bit.pgmdata = 0; misc.clock_bit.pgmclk = 1; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8);
dummyCallDelai(); }
/* ======================================================================= */ /*/
* NAME: send_0 ( void ) * * Send data bit 0 (protocol "MANCHESTER"). * */
static void send_0 ( void ) { misc.clock_bit.pgmdata = 0; misc.clock_bit.pgmclk = 1; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8);
dummyCallDelai();
misc.clock_bit.pgmdata = 1; misc.clock_bit.pgmclk = 1; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8);
dummyCallDelai();
misc.clock_bit.pgmdata = 1; misc.clock_bit.pgmclk = 0; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8);
dummyCallDelai();
misc.clock_bit.pgmdata = 0; misc.clock_bit.pgmclk = 0; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8);
dummyCallDelai();
misc.clock_bit.pgmdata = 0; misc.clock_bit.pgmclk = 1; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8);
dummyCallDelai(); }
/* ======================================================================= */ /*/
* NAME: send_1 ( void ) * * Send data bit 1 (protocol "MANCHESTER"). * */
static void send_1 ( void ) { misc.clock_bit.pgmdata = 0; misc.clock_bit.pgmclk = 1; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8);
dummyCallDelai();
misc.clock_bit.pgmdata = 0; misc.clock_bit.pgmclk = 0; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8);
dummyCallDelai();
misc.clock_bit.pgmdata = 1; misc.clock_bit.pgmclk = 0; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8);
dummyCallDelai();
misc.clock_bit.pgmdata = 1; misc.clock_bit.pgmclk = 1; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8);
dummyCallDelai(); }
/* ======================================================================= */ /*/
* NAME: send_stop ( void ) * * Send stop sequence * */
static void send_stop ( void ) { misc.clock_bit.pgmdata = 1; misc.clock_bit.pgmclk = 1; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8);
dummyCallDelai();
misc.clock_bit.pgmdata = 1; misc.clock_bit.pgmclk = 0; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8);
dummyCallDelai();
misc.clock_bit.pgmdata = 1; misc.clock_bit.pgmclk = 1; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8);
dummyCallDelai();
misc.clock_bit.pgmdata = 0; misc.clock_bit.pgmclk = 1; mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8);
dummyCallDelai(); }
/* ======================================================================= */
/***************************************************************************/
/*/ setTVP3026Freq ( volatile byte _Far *pDeviceParam, long desiredFout, long reg, word pWidth )
* * Calculate best value to obtain a frequency output. * This routine program and select the register. * If fout is 0, just toggle to the desired * output register. * * Problems : * Designed : Patrick Servais:94/04/08 * * Parameters: [0]-desired output frequency (in kHz). * (0 -> select desired register) * [1]-register (0, 1, 2 ou 3) to prgram and select. * (the MCLOCK register (3) can be reprogrammable, but * is always available for output - no selection is permit). * * Call : * * Used : * Modify : Benoit Leblanc * * Return : old frequency value * * List of modifications : * */
long setTVP3026Freq ( volatile byte _Far *pDeviceParam, long fout, long reg, byte pWidth ) { word i; short p, pixel_p, pixel_n, q, n, bestN; int m, pixel_m, bestM, tmp; short index; short val; long old_frequency, z; long fvco, fTemp, trueFout, desiredFout; long ppmError; long bestError; byte init_misc, dac_rev1; byte tmpByte, saveByte; word pixelWidth; dword power; dword config200Mhz, fvcoMax;
switch(pWidth) { case 0: pixelWidth = 8; break; case 1: pixelWidth = 16; break; case 2: pixelWidth = 32; break; } /* Hard to 16*/
pDevice = pDeviceParam;
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), 0x01); /* Silicon revision */ mgaReadBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), tmpByte); if (tmpByte >= 0x10) dac_rev1 = 1; else dac_rev1 = 0;
/* Read 200Mhz straps saved in config register */ mgaReadDWORD(*(pDevice+TITAN_OFFSET + TITAN_CONFIG), config200Mhz); if (config200Mhz & 0x00000004) { fvcoMax = (dword)220000000; /* 200Mhz support */ } else { fvcoMax = (dword)175000000; /* 200Mhz not support */ }
mgaReadBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_R), init_misc); misc.var8 = init_misc;
/***************************************************/ /*
/* CALCULATE FREQUENCY
/*
/***************************************************/
bestError = 99999999; /* dummy start number */
fref = 14318180; /* frequence clock ref */
index = 0; bestError = 5000000;
desiredFout = fout * 1000; /* Scale it from KHz to Hz */
if ((dword) desiredFout>= (fvcoMax >> 1)) p = 0; else if ((dword) desiredFout>=(fvcoMax >> 2)) p = 1; else if ((dword) desiredFout>=(fvcoMax >> 3)) p = 2; else p = 3;
power = 1; for(i=0; i<p; i++) power = power * 2;
for ( n=1;n<=63;n++ ) {
m = (650 - (((((dword)desiredFout*10)/fref) * ((65-n) * power)) / 8)) / 10;
fTemp = fref / (65-n); fvco = fTemp * 8 * (65-m); trueFout = fvco / power;
if (trueFout < desiredFout) ppmError = desiredFout - trueFout; else ppmError = trueFout - desiredFout;
if ((ppmError < bestError) && (m > 0) && (m <= 63) && (fTemp > 500000) && ((dword)fvco >= (fvcoMax >> 1) ) && (fvco <= (dword)220000000)) { index = 1;
bestError = ppmError; bestM = m; bestN = n; } }
m = bestM; n = bestN; fTemp = fref / (65-n); fvco = fTemp * 8 * (65-m);
{ dword num;
num = ((65 - m)*10) / (65-n); num = num * 8 * fref;
trueFout = (num / power) / 10; }
if ( index == 0 ) /* no solution find */ { /* ***ERROR: setFrequence() NONE RESULT (IMPOSSIBLE?!?) */ /* restore valeur de depart */
old_frequency = 0L; /* ERREUR RETURN */
mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), init_misc); } else {
/**********************************************************************
* * SET THE DESIRED FREQUENCY OUTPUT REGISTER * */ switch ( reg ) {
case VIDEO_CLOCK_3: /* NOTE 1: header */
misc.sel_reg_output.select = 3; /* NOTE 1: header */ mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), misc.var8);
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PLL_ADDR); mgaReadBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), tmpByte); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), tmpByte & 0xfc);
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PIX_CLK_DATA ); if (dac_rev1) mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), ((n&0x3f)|0xc0) ); else mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), ((n&0x3f)|0x80) ); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), (m&0x3f) ); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), ((p&0x03)|0xf0) );
tmp = 0; do { tmp += 1; delay_us(10); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PIX_CLK_DATA); mgaReadBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), tmpByte); tmpByte &= 0x40; } while((tmpByte != 0x40) && (tmp < 5000));
if((tmp == 5000) && (fout < 1100000) && (fvcoMax == 220000000)) LowerVCO(fout, 0, pWidth, fvcoMax, dac_rev1);
/* searching for loop clock parameters */
n = 65 - ((4*64)/pixelWidth); /* 64 is the Pixel bus Width */ m = 0x3d; z = ((65L-n)*2750L)/(fout/1000);
q = 0; p = 3; if (z <= 200) p = 0; else if (z <= 400) p = 1; else if (z <= 800) p = 2; else if (z <=1600) p = 3; else q = (short)(z/1600);
if (dac_rev1) n |= 0xc0; else n |= 0x80;
if ((dac_rev1 == 0) && (fout <= 175000)) p |= 0xb0; else p |= 0xf0;
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_MCLK_CTL); mgaReadBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), tmpByte); val = tmpByte; mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), ((val&0xf8)|q) | 0x20);
if ((pWidth == TITAN_PWIDTH_PW24) && (dac_rev1)) { if (desiredFout >= 50000000) {n = 0xf9; p = 0xf9; m=0x3e;} else {n = 0xf9; p = 0xfb; m=0x3e;} } else if ((pWidth == TITAN_PWIDTH_PW24) && (dac_rev1 == 0)) { if (desiredFout >= 50000000) {n = 0xb9; p = 0xf9; m=0x3e;} else {n = 0xb9; p = 0xfb; m=0x3e;} }
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PLL_ADDR); mgaReadBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), tmpByte); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), tmpByte & 0xcf);
/* DAT Patrick Servais, on ajoute ce qui suis */ mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_LOAD_CLK_DATA); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), 0); delay_us(100L); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), 0); delay_us(100L); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), 0); delay_us(100L);
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PLL_ADDR); mgaReadBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), tmpByte); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), tmpByte & 0xcf);
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_LOAD_CLK_DATA); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), (byte)n); delay_us(100L); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), (byte)m); delay_us(100L); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), (byte)p); delay_us(100L);
tmp = 0; do { tmp += 1; delay_us(10); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_LOAD_CLK_DATA); mgaReadBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), tmpByte); tmpByte &= 0x40; } while((tmpByte != 0x40) && (tmp < 5000));
if(tmp == 5000) LowerVCO(fout, 1, pWidth, fvcoMax, dac_rev1);
old_frequency = old_fr_reg[reg]; /* RETURN VALUE */ old_fr_reg[reg] = trueFout / 1000L; /* SAVE PRESENT FREQUENCY in kHz */ break;
/*******************************************************************
* * the programmation line is used to modify register internal value * of TVP3026, and to select output video register (with internal * muxer) at the end of programmation. For the system clock * MCLOCK programmation, at the end, we put on programmation line * the initial value of the video register. * */ case MEMORY_CLOCK: /* par defaut, (si on a modifie MCLK), on restore VCLK
* initial */ mgaReadBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_R), saveByte);
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PLL_ADDR); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), 0xfc);
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PIX_CLK_DATA); mgaReadBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), pixel_n);
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PLL_ADDR); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), 0xfd);
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PIX_CLK_DATA); mgaReadBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), pixel_m);
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PLL_ADDR); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), 0xfe);
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PIX_CLK_DATA); mgaReadBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), pixel_p);
/*------------*/ /* 1st step */ /*------------*/
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PLL_ADDR); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), 0xfc);
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PIX_CLK_DATA); if (dac_rev1) mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), ((n&0x3f)|0xc0)); else mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), ((n&0x3f)|0x80)); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), (m&0x3f)); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), ((p&0x03)|0xb0));
do { delay_us(1); mgaReadBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), tmpByte); tmpByte &= 0x40; } while(tmpByte != 0x40);
/*------------*/ /* 2d step */ /*------------*/
/* Select programmable clock */ mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), 0x0f);
delay_us(2000); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PLL_ADDR); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), 0xff); do { delay_us(1); mgaReadBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), tmpByte); tmpByte &= 0x40; } while(tmpByte != 0x40);
/* Select internal pclk instead of external pclk0 */ mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_CLK_SEL); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), 5);
/*------------*/ /* 3rd step */ /*------------*/
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_MCLK_CTL); mgaReadBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), val); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), (val&0xe7)); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), (val&0xe7)|0x08);
/*------------*/ /* 4th step */ /*------------*/
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PLL_ADDR); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), 0xf3);
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_MEM_CLK_DATA); if (dac_rev1) mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), ((n&0x3f)|0xc0)); else mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), ((n&0x3f)|0x80)); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), (m&0x3f)); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), ((p&0x03)|0xb0));
delay_us(3500); do { delay_us(1); mgaReadBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), tmpByte); tmpByte &= 0x40; } while(tmpByte != 0x40);
/*------------*/ /* 5th step */ /*------------*/
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_MCLK_CTL); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), (val&0xe7)|0x10); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), (val&0xe7)|0x18);
/*------------*/ /* 6th step */ /*------------*/
/* Restore clock select */ mgaWriteBYTE(*(pDevice + TITAN_OFFSET + TITAN_MISC_OUT_W), saveByte);
/* Reselect external pclk0 */ mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_CLK_SEL); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), 7);
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PLL_ADDR); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), 0xfc);
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PIX_CLK_DATA); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), (byte)pixel_n); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), (byte)pixel_m); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), (byte)pixel_p);
do { delay_us(1); mgaReadBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), tmpByte); tmpByte &= 0x40; } while(tmpByte != 0x40);
old_fr_reg[reg] = trueFout / 1000L; /* SAVE PRESENT FREQUENCY */
break;
default:
/***ERROR: REGISTER ICD UNKNOWN: */ old_frequency = 0L; /* ERROR RETURN */ break; }
}
/* wait 10ms before quit....this is not suppose
* to necessary outside of the programmation * register, but, well, we are not too secure */ dummyCallDelai(); /* delay ( 10 ); */
return ( old_frequency );
}
void LowerVCO(long Fout, byte pll, byte pwidth, dword vcomax, byte dacrev1) { word i; short p, q, n, bestN; int m, bestM; short val; long z; long fvco, fvco_l, fTemp, trueFout, desiredFout; long ppmError; long bestError; byte tmpByte; word pixelwidth, div_ratio; dword power; dword fvcomax;
switch(pwidth) { case 0: pixelwidth = 8; div_ratio = 8; break; case 1: pixelwidth = 16; div_ratio = 4; break; case 2: pixelwidth = 32; div_ratio = 2; break; }
desiredFout = Fout * 1000; /* Scale it from KHz to Hz */
switch(pll) { case 0:
fvcomax = (dword)175000000; /* Patch pour eviter la Deadzone */
bestError = 99999999; /* dummy start number */
fref = 14318180; /* frequence clock ref */
if ((dword)desiredFout>= (fvcomax >> 1)) p = 0; else if ((dword)desiredFout>=(fvcomax >> 2)) p = 1; else if ((dword)desiredFout>=(fvcomax >> 3)) p = 2; else p = 3;
power = 1; for(i=0; i<p; i++) power = power * 2;
for ( n=40;n<=62;n++ ) {
m = (650 - (((((dword)desiredFout*10)/fref) * ((65-n) * power)) / 8)) / 10;
fTemp = fref / (65 - n); fvco = fTemp * 8 * (65 - m); trueFout = fvco / power;
if (trueFout < desiredFout) ppmError = desiredFout - trueFout; else ppmError = trueFout - desiredFout;
if ((ppmError < bestError) && (m > 0) && (m <= 63) && (fTemp > 500000) && ((dword)fvco >= (fvcomax >> 1) ) && (fvco <= (dword)220000000)) { bestError = ppmError; bestM = m; bestN = n; } }
m = bestM; n = bestN;
{ dword num;
num = ((65 - m)*10) / (65-n); num = num * 8 * fref;
trueFout = (num / power) / 10; }
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PLL_ADDR); mgaReadBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), tmpByte); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), tmpByte & 0xfc);
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PIX_CLK_DATA ); if (dacrev1) mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), ((n&0x3f)|0xc0) ); else mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), ((n&0x3f)|0x80) ); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), (m&0x3f) ); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), ((p&0x03)|0xf0) );
do { delay_us(10); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PIX_CLK_DATA); mgaReadBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), tmpByte); tmpByte &= 0x40; } while(tmpByte != 0x40);
break;
case 1:
/* searching for loop clock parameters */
n = 65 - ((4*64)/pixelwidth); /* 64 is the Pixel bus Width */ m = 0x3d; z = ((65L-(long)n)*2750L)/(Fout/1000);
q = 0; p = 3; if (z <= 200) p = 0; else if (z <= 400) p = 1; else if (z <= 800) p = 2; else if (z <=1600) p = 3; else q = (short)(z/1600);
/* Patch: si vco du loop clock pll est > 180 MHz, on le divise par deux */ /* pour ne plus qu'il soit dans la dead zone */
div_ratio = div_ratio * 10; if (pwidth == TITAN_PWIDTH_PW24) div_ratio = 80/3; /* meilleurs precision */
fvco_l = ((Fout/div_ratio) << p) * (2*(q+1)) * 10;
if ((p > 0) && (fvco_l > 180000)) p = p-1;
if (dacrev1) n |= 0xc0; else n |= 0x80;
if ((dacrev1 == 0) && (Fout <= 175000)) p |= 0xb0; else p |= 0xf0;
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_MCLK_CTL); mgaReadBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), tmpByte); val = tmpByte; mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), ((val&0xf8)|q) | 0x20);
if ((pwidth == TITAN_PWIDTH_PW24) && (dacrev1)) { if (desiredFout >= 50000000) {n = 0xf9; p = 0xf9; m=0x3e;} else {n = 0xf9; p = 0xfb; m=0x3e;} } else if ((pwidth == TITAN_PWIDTH_PW24) && (dacrev1 == 0)) { if (desiredFout >= 50000000) {n = 0xb9; p = 0xf9; m=0x3e;} else {n = 0xb9; p = 0xfb; m=0x3e;} }
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_PLL_ADDR); mgaReadBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), tmpByte); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), tmpByte & 0xcf);
mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_INDEX), TVP3026_LOAD_CLK_DATA); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), (byte)n); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), (byte)m); mgaWriteBYTE(*(pDevice + RAMDAC_OFFSET + TVP3026_DATA), (byte)p);
break; } }
|