/* ======================================================================= */ /* /* 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 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 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 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; } }