1fe5e51b7Smrg/* 2fe5e51b7Smrg * Copyright 1994 by Robin Cutshaw <robin@XFree86.org> 3fe5e51b7Smrg * 4fe5e51b7Smrg * Permission to use, copy, modify, distribute, and sell this software and its 5fe5e51b7Smrg * documentation for any purpose is hereby granted without fee, provided that 6fe5e51b7Smrg * the above copyright notice appear in all copies and that both that 7fe5e51b7Smrg * copyright notice and this permission notice appear in supporting 8fe5e51b7Smrg * documentation, and that the name of Robin Cutshaw not be used in 9fe5e51b7Smrg * advertising or publicity pertaining to distribution of the software without 10fe5e51b7Smrg * specific, written prior permission. Robin Cutshaw makes no representations 11fe5e51b7Smrg * about the suitability of this software for any purpose. It is provided 12fe5e51b7Smrg * "as is" without express or implied warranty. 13fe5e51b7Smrg * 14fe5e51b7Smrg * ROBIN CUTSHAW DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15fe5e51b7Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16fe5e51b7Smrg * EVENT SHALL ROBIN CUTSHAW BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17fe5e51b7Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18fe5e51b7Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19fe5e51b7Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20fe5e51b7Smrg * PERFORMANCE OF THIS SOFTWARE. 21fe5e51b7Smrg * 22fe5e51b7Smrg * 23fe5e51b7Smrg * Modified for TVP3026 by Harald Koenig <koenig@tat.physik.uni-tuebingen.de> 24fe5e51b7Smrg * 25fe5e51b7Smrg * Modified for MGA Millennium by Xavier Ducoin <xavier@rd.lectra.fr> 26fe5e51b7Smrg * 27fe5e51b7Smrg * Doug Merritt <doug@netcom.com> 28fe5e51b7Smrg * 24bpp: fixed high res stripe glitches, clock glitches on all res 29fe5e51b7Smrg * 30fe5e51b7Smrg */ 31fe5e51b7Smrg 32fe5e51b7Smrg#ifdef HAVE_CONFIG_H 33fe5e51b7Smrg#include "config.h" 34fe5e51b7Smrg#endif 35fe5e51b7Smrg 36fe5e51b7Smrg/* 37fe5e51b7Smrg * This is a first cut at a non-accelerated version to work with the 38fe5e51b7Smrg * new server design (DHD). 39fe5e51b7Smrg */ 40fe5e51b7Smrg 41fe5e51b7Smrg/* All drivers should typically include these */ 42fe5e51b7Smrg#include "xf86.h" 43fe5e51b7Smrg#include "xf86_OSproc.h" 44fe5e51b7Smrg 45fe5e51b7Smrg/* Drivers that need to access the PCI config space directly need this */ 46fe5e51b7Smrg#include "xf86Pci.h" 47fe5e51b7Smrg 48fe5e51b7Smrg#include "mga_reg.h" 49fe5e51b7Smrg#include "mga.h" 50fe5e51b7Smrg#include "mga_macros.h" 51fe5e51b7Smrg 52fe5e51b7Smrg#include "xf86DDC.h" 53fe5e51b7Smrg 54fe5e51b7Smrg/* 55fe5e51b7Smrg * Only change these bits in the Option register. Make sure that the 56fe5e51b7Smrg * vgaioen bit is never in this mask because it is controlled elsewhere 57fe5e51b7Smrg */ 58fe5e51b7Smrg#define OPTION_MASK 0xFFEFFEFF /* ~(eepromwt | vgaioen) */ 59fe5e51b7Smrg 60fe5e51b7Smrgstatic void MGA3026LoadPalette(ScrnInfoPtr, int, int*, LOCO*, VisualPtr); 61fe5e51b7Smrgstatic void MGA3026SavePalette(ScrnInfoPtr, unsigned char*); 62fe5e51b7Smrgstatic void MGA3026RestorePalette(ScrnInfoPtr, unsigned char*); 63fe5e51b7Smrgstatic void MGA3026RamdacInit(ScrnInfoPtr); 64fe5e51b7Smrgstatic void MGA3026Save(ScrnInfoPtr, vgaRegPtr, MGARegPtr, Bool); 65fe5e51b7Smrgstatic void MGA3026Restore(ScrnInfoPtr, vgaRegPtr, MGARegPtr, Bool); 66fe5e51b7Smrgstatic Bool MGA3026Init(ScrnInfoPtr, DisplayModePtr); 67fe5e51b7Smrgstatic Bool MGA3026_i2cInit(ScrnInfoPtr pScrn); 68fe5e51b7Smrg 69fe5e51b7Smrg 70fe5e51b7Smrg/* 71fe5e51b7Smrg * implementation 72fe5e51b7Smrg */ 73fe5e51b7Smrg 74fe5e51b7Smrg/* 75fe5e51b7Smrg * indexes to ti3026 registers (the order is important) 76fe5e51b7Smrg */ 77fe5e51b7Smrgconst static unsigned char MGADACregs[] = { 78fe5e51b7Smrg 0x0F, 0x18, 0x19, 0x1A, 0x1C, 0x1D, 0x1E, 0x2A, 0x2B, 0x30, 79fe5e51b7Smrg 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 80fe5e51b7Smrg 0x06 81fe5e51b7Smrg}; 82fe5e51b7Smrg 83fe5e51b7Smrg/* note: to fix a cursor hw glitch, register 0x37 (blue color key) needs 84fe5e51b7Smrg to be set to magic numbers, even though they are "never" used because 85fe5e51b7Smrg blue keying disabled in 0x38. 86fe5e51b7Smrg 87fe5e51b7Smrg Matrox sez: 88fe5e51b7Smrg 89fe5e51b7Smrg ...The more precise statement of the software workaround is to insure 90fe5e51b7Smrg that bits 7-5 of register 0x37 (Blue Color Key High) and bits 7-5 of 91fe5e51b7Smrg register 0x38 (HZOOM)are the same... 92fe5e51b7Smrg*/ 93fe5e51b7Smrg 94fe5e51b7Smrg/* also note: the values of the MUX control register 0x19 (index [2]) can be 95fe5e51b7Smrg found in table 2-17 of the 3026 manual. If interlace is set, the values 96fe5e51b7Smrg listed here are incremented by one. 97fe5e51b7Smrg*/ 98fe5e51b7Smrg 99fe5e51b7Smrg#define DACREGSIZE sizeof(MGADACregs) 100fe5e51b7Smrg/* 101fe5e51b7Smrg * initial values of ti3026 registers 102fe5e51b7Smrg */ 103fe5e51b7Smrgconst static unsigned char MGADACbpp8[DACREGSIZE] = { 104fe5e51b7Smrg 0x06, 0x80, 0x4b, 0x25, 0x00, 0x00, 0x0C, 0x00, 0x1E, 0xFF, 105fe5e51b7Smrg 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0, 0x00, 106fe5e51b7Smrg 0x00 107fe5e51b7Smrg}; 108fe5e51b7Smrgconst static unsigned char MGADACbpp16[DACREGSIZE] = { 109fe5e51b7Smrg 0x07, 0x45, 0x53, 0x15, 0x00, 0x00, 0x2C, 0x00, 0x1E, 0xFF, 110fe5e51b7Smrg 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x10, 0, 0x00, 111fe5e51b7Smrg 0x00 112fe5e51b7Smrg}; 113fe5e51b7Smrg/* 114fe5e51b7Smrg * [0] value was 0x07, but changed to 0x06 by Doug Merrit to fix high res 115fe5e51b7Smrg * stripe glitches and clock glitches at 24bpp. 116fe5e51b7Smrg */ 117fe5e51b7Smrg/* [0] value is now set inside of MGA3026Init, based on the silicon revision 118fe5e51b7Smrg It is still set to 7 or 6 based on the revision, though, since setting to 119fe5e51b7Smrg 8 as in the documentation makes (some?) revB chips get the colors wrong... 120fe5e51b7Smrg maybe BGR instead of RGB? This only applies to 24bpp, since it is the only 121fe5e51b7Smrg one documented as depending on revision. 122fe5e51b7Smrg */ 123fe5e51b7Smrg 124fe5e51b7Smrgconst static unsigned char MGADACbpp24[DACREGSIZE] = { 125fe5e51b7Smrg 0x06, 0x56, 0x5b, 0x25, 0x00, 0x00, 0x2C, 0x00, 0x1E, 0xFF, 126fe5e51b7Smrg 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x10, 0, 0x00, 127fe5e51b7Smrg 0x00 128fe5e51b7Smrg}; 129fe5e51b7Smrgconst static unsigned char MGADACbpp32[DACREGSIZE] = { 130fe5e51b7Smrg 0x07, 0x46, 0x5b, 0x05, 0x00, 0x00, 0x2C, 0x00, 0x1E, 0xFF, 131fe5e51b7Smrg 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x10, 0, 0x00, 132fe5e51b7Smrg 0x00 133fe5e51b7Smrg}; 134fe5e51b7Smrg 135fe5e51b7Smrg 136fe5e51b7Smrg/* 137fe5e51b7Smrg * Read/write to the DAC via MMIO 138fe5e51b7Smrg */ 139fe5e51b7Smrg 140fe5e51b7Smrg/* 141fe5e51b7Smrg * These were functions. Use macros instead to avoid the need to 142fe5e51b7Smrg * pass pMga to them. 143fe5e51b7Smrg */ 144fe5e51b7Smrg 145fe5e51b7Smrg#define inTi3026dreg(reg) INREG8(RAMDAC_OFFSET + (reg)) 146fe5e51b7Smrg 147fe5e51b7Smrg#define outTi3026dreg(reg, val) OUTREG8(RAMDAC_OFFSET + (reg), val) 148fe5e51b7Smrg 149fe5e51b7Smrg#define inTi3026(reg) \ 150fe5e51b7Smrg (outTi3026dreg(TVP3026_INDEX, reg), inTi3026dreg(TVP3026_DATA)) 151fe5e51b7Smrg 152fe5e51b7Smrg#define outTi3026(reg, mask, val) \ 153fe5e51b7Smrg do { /* note: mask and reg may get evaluated twice */ \ 154fe5e51b7Smrg unsigned char tmp = (mask) ? (inTi3026(reg) & (mask)) : 0; \ 155fe5e51b7Smrg outTi3026dreg(TVP3026_INDEX, reg); \ 156fe5e51b7Smrg outTi3026dreg(TVP3026_DATA, tmp | (val)); \ 157fe5e51b7Smrg } while (0) 158fe5e51b7Smrg 159fe5e51b7Smrg 160fe5e51b7Smrg/* 161fe5e51b7Smrg * MGATi3026CalcClock - Calculate the PLL settings (m, n, p). 162fe5e51b7Smrg * 163fe5e51b7Smrg * DESCRIPTION 164fe5e51b7Smrg * For more information, refer to the Texas Instruments 165fe5e51b7Smrg * "TVP3026 Data Manual" (document SLAS098B). 166fe5e51b7Smrg * Section 2.4 "PLL Clock Generators" 167fe5e51b7Smrg * Appendix A "Frequency Synthesis PLL Register Settings" 168fe5e51b7Smrg * Appendix B "PLL Programming Examples" 169fe5e51b7Smrg * 170fe5e51b7Smrg * PARAMETERS 171fe5e51b7Smrg * f_out IN Desired clock frequency. 172fe5e51b7Smrg * f_max IN Maximum allowed clock frequency. 173fe5e51b7Smrg * m OUT Value of PLL 'm' register. 174fe5e51b7Smrg * n OUT Value of PLL 'n' register. 175fe5e51b7Smrg * p OUT Value of PLL 'p' register. 176fe5e51b7Smrg * 177fe5e51b7Smrg * HISTORY 178fe5e51b7Smrg * January 11, 1997 - [aem] Andrew E. Mileski 179fe5e51b7Smrg * Split off from MGATi3026SetClock. 180fe5e51b7Smrg */ 181fe5e51b7Smrg 182fe5e51b7Smrg/* The following values are in kHz */ 183fe5e51b7Smrg#define TI_MIN_VCO_FREQ 110000 184fe5e51b7Smrg#define TI_MAX_VCO_FREQ 220000 185fe5e51b7Smrg#define TI_MAX_MCLK_FREQ 100000 186fe5e51b7Smrg#define TI_REF_FREQ 14318.18 187fe5e51b7Smrg 188fe5e51b7Smrgstatic double 189fe5e51b7SmrgMGATi3026CalcClock ( 190fe5e51b7Smrg long f_out, long f_max, 191fe5e51b7Smrg int *m, int *n, int *p 192fe5e51b7Smrg){ 193fe5e51b7Smrg int best_m = 0, best_n = 0; 194fe5e51b7Smrg double f_pll, f_vco; 195fe5e51b7Smrg double m_err, inc_m, calc_m; 196fe5e51b7Smrg 197fe5e51b7Smrg /* Make sure that f_min <= f_out <= f_max */ 198fe5e51b7Smrg if ( f_out < ( TI_MIN_VCO_FREQ / 8 )) 199fe5e51b7Smrg f_out = TI_MIN_VCO_FREQ / 8; 200fe5e51b7Smrg if ( f_out > f_max ) 201fe5e51b7Smrg f_out = f_max; 202fe5e51b7Smrg 203fe5e51b7Smrg /* 204fe5e51b7Smrg * f_pll = f_vco / 2 ^ p 205fe5e51b7Smrg * Choose p so that TI_MIN_VCO_FREQ <= f_vco <= TI_MAX_VCO_FREQ 206fe5e51b7Smrg * Note that since TI_MAX_VCO_FREQ = 2 * TI_MIN_VCO_FREQ 207fe5e51b7Smrg * we don't have to bother checking for this maximum limit. 208fe5e51b7Smrg */ 209fe5e51b7Smrg f_vco = ( double ) f_out; 210fe5e51b7Smrg for ( *p = 0; *p < 3 && f_vco < TI_MIN_VCO_FREQ; ( *p )++ ) 211fe5e51b7Smrg f_vco *= 2.0; 212fe5e51b7Smrg 213fe5e51b7Smrg /* 214fe5e51b7Smrg * We avoid doing multiplications by ( 65 - n ), 215fe5e51b7Smrg * and add an increment instead - this keeps any error small. 216fe5e51b7Smrg */ 217fe5e51b7Smrg inc_m = f_vco / ( TI_REF_FREQ * 8.0 ); 218fe5e51b7Smrg 219fe5e51b7Smrg /* Initial value of calc_m for the loop */ 220fe5e51b7Smrg calc_m = inc_m + inc_m + inc_m; 221fe5e51b7Smrg 222fe5e51b7Smrg /* Initial amount of error for an integer - impossibly large */ 223fe5e51b7Smrg m_err = 2.0; 224fe5e51b7Smrg 225fe5e51b7Smrg /* Search for the closest INTEGER value of ( 65 - m ) */ 226fe5e51b7Smrg for ( *n = 3; *n <= 25; ( *n )++, calc_m += inc_m ) { 227fe5e51b7Smrg 228fe5e51b7Smrg /* Ignore values of ( 65 - m ) which we can't use */ 229fe5e51b7Smrg if ( calc_m < 3.0 || calc_m > 64.0 ) 230fe5e51b7Smrg continue; 231fe5e51b7Smrg 232fe5e51b7Smrg /* 233fe5e51b7Smrg * Pick the closest INTEGER (has smallest fractional part). 234fe5e51b7Smrg * The optimizer should clean this up for us. 235fe5e51b7Smrg */ 236fe5e51b7Smrg if (( calc_m - ( int ) calc_m ) < m_err ) { 237fe5e51b7Smrg m_err = calc_m - ( int ) calc_m; 238fe5e51b7Smrg best_m = ( int ) calc_m; 239fe5e51b7Smrg best_n = *n; 240fe5e51b7Smrg } 241fe5e51b7Smrg } 242fe5e51b7Smrg 243fe5e51b7Smrg /* 65 - ( 65 - x ) = x */ 244fe5e51b7Smrg *m = 65 - best_m; 245fe5e51b7Smrg *n = 65 - best_n; 246fe5e51b7Smrg 247fe5e51b7Smrg /* Now all the calculations can be completed */ 248fe5e51b7Smrg f_vco = 8.0 * TI_REF_FREQ * best_m / best_n; 249fe5e51b7Smrg f_pll = f_vco / ( 1 << *p ); 250fe5e51b7Smrg 251fe5e51b7Smrg#ifdef DEBUG 252fe5e51b7Smrg ErrorF( "f_out=%ld f_pll=%.1f f_vco=%.1f n=%d m=%d p=%d\n", 253fe5e51b7Smrg f_out, f_pll, f_vco, *n, *m, *p ); 254fe5e51b7Smrg#endif 255fe5e51b7Smrg 256fe5e51b7Smrg return f_pll; 257fe5e51b7Smrg} 258fe5e51b7Smrg 259fe5e51b7Smrg/* 260fe5e51b7Smrg * MGATi3026SetMCLK - Set the memory clock (MCLK) PLL. 261fe5e51b7Smrg * 262fe5e51b7Smrg * HISTORY 263fe5e51b7Smrg * January 11, 1997 - [aem] Andrew E. Mileski 264fe5e51b7Smrg * Written and tested. 265fe5e51b7Smrg */ 266fe5e51b7Smrgstatic void 267fe5e51b7SmrgMGATi3026SetMCLK( ScrnInfoPtr pScrn, long f_out ) 268fe5e51b7Smrg{ 269fe5e51b7Smrg int mclk_m, mclk_n, mclk_p; 270fe5e51b7Smrg int pclk_m, pclk_n, pclk_p; 271fe5e51b7Smrg int mclk_ctl; 272fe5e51b7Smrg MGAPtr pMga = MGAPTR(pScrn); 273fe5e51b7Smrg 274fe5e51b7Smrg MGATi3026CalcClock(f_out, TI_MAX_MCLK_FREQ, &mclk_m, &mclk_n, &mclk_p); 275fe5e51b7Smrg 276fe5e51b7Smrg /* Save PCLK settings */ 277fe5e51b7Smrg outTi3026( TVP3026_PLL_ADDR, 0, 0xfc ); 278fe5e51b7Smrg pclk_n = inTi3026( TVP3026_PIX_CLK_DATA ); 279fe5e51b7Smrg outTi3026( TVP3026_PLL_ADDR, 0, 0xfd ); 280fe5e51b7Smrg pclk_m = inTi3026( TVP3026_PIX_CLK_DATA ); 281fe5e51b7Smrg outTi3026( TVP3026_PLL_ADDR, 0, 0xfe ); 282fe5e51b7Smrg pclk_p = inTi3026( TVP3026_PIX_CLK_DATA ); 283fe5e51b7Smrg 284fe5e51b7Smrg /* Stop PCLK (PLLEN = 0, PCLKEN = 0) */ 285fe5e51b7Smrg outTi3026( TVP3026_PLL_ADDR, 0, 0xfe ); 286fe5e51b7Smrg outTi3026( TVP3026_PIX_CLK_DATA, 0, 0x00 ); 287fe5e51b7Smrg 288fe5e51b7Smrg /* Set PCLK to the new MCLK frequency (PLLEN = 1, PCLKEN = 0 ) */ 289fe5e51b7Smrg outTi3026( TVP3026_PLL_ADDR, 0, 0xfc ); 290fe5e51b7Smrg outTi3026( TVP3026_PIX_CLK_DATA, 0, ( mclk_n & 0x3f ) | 0xc0 ); 291fe5e51b7Smrg outTi3026( TVP3026_PIX_CLK_DATA, 0, mclk_m & 0x3f ); 292fe5e51b7Smrg outTi3026( TVP3026_PIX_CLK_DATA, 0, ( mclk_p & 0x03 ) | 0xb0 ); 293fe5e51b7Smrg 294fe5e51b7Smrg /* Wait for PCLK PLL to lock on frequency */ 295fe5e51b7Smrg while (( inTi3026( TVP3026_PIX_CLK_DATA ) & 0x40 ) == 0 ) { 296fe5e51b7Smrg ; 297fe5e51b7Smrg } 298fe5e51b7Smrg 299fe5e51b7Smrg /* Output PCLK on MCLK pin */ 300fe5e51b7Smrg mclk_ctl = inTi3026( TVP3026_MCLK_CTL ); 301fe5e51b7Smrg outTi3026( TVP3026_MCLK_CTL, 0, mclk_ctl & 0xe7 ); 302fe5e51b7Smrg outTi3026( TVP3026_MCLK_CTL, 0, ( mclk_ctl & 0xe7 ) | 0x08 ); 303fe5e51b7Smrg 304fe5e51b7Smrg /* Stop MCLK (PLLEN = 0 ) */ 305fe5e51b7Smrg outTi3026( TVP3026_PLL_ADDR, 0, 0xfb ); 306fe5e51b7Smrg outTi3026( TVP3026_MEM_CLK_DATA, 0, 0x00 ); 307fe5e51b7Smrg 308fe5e51b7Smrg /* Set MCLK to the new frequency (PLLEN = 1) */ 309fe5e51b7Smrg outTi3026( TVP3026_PLL_ADDR, 0, 0xf3 ); 310fe5e51b7Smrg outTi3026( TVP3026_MEM_CLK_DATA, 0, ( mclk_n & 0x3f ) | 0xc0 ); 311fe5e51b7Smrg outTi3026( TVP3026_MEM_CLK_DATA, 0, mclk_m & 0x3f ); 312fe5e51b7Smrg outTi3026( TVP3026_MEM_CLK_DATA, 0, ( mclk_p & 0x03 ) | 0xb0 ); 313fe5e51b7Smrg 314fe5e51b7Smrg /* Wait for MCLK PLL to lock on frequency */ 315fe5e51b7Smrg while (( inTi3026( TVP3026_MEM_CLK_DATA ) & 0x40 ) == 0 ) { 316fe5e51b7Smrg ; 317fe5e51b7Smrg } 318fe5e51b7Smrg 319fe5e51b7Smrg /* Output MCLK PLL on MCLK pin */ 320fe5e51b7Smrg outTi3026( TVP3026_MCLK_CTL, 0, ( mclk_ctl & 0xe7 ) | 0x10 ); 321fe5e51b7Smrg outTi3026( TVP3026_MCLK_CTL, 0, ( mclk_ctl & 0xe7 ) | 0x18 ); 322fe5e51b7Smrg 323fe5e51b7Smrg /* Stop PCLK (PLLEN = 0, PCLKEN = 0 ) */ 324fe5e51b7Smrg outTi3026( TVP3026_PLL_ADDR, 0, 0xfe ); 325fe5e51b7Smrg outTi3026( TVP3026_PIX_CLK_DATA, 0, 0x00 ); 326fe5e51b7Smrg 327fe5e51b7Smrg /* Restore PCLK (PLLEN = ?, PCLKEN = ?) */ 328fe5e51b7Smrg outTi3026( TVP3026_PLL_ADDR, 0, 0xfc ); 329fe5e51b7Smrg outTi3026( TVP3026_PIX_CLK_DATA, 0, pclk_n ); 330fe5e51b7Smrg outTi3026( TVP3026_PIX_CLK_DATA, 0, pclk_m ); 331fe5e51b7Smrg outTi3026( TVP3026_PIX_CLK_DATA, 0, pclk_p ); 332fe5e51b7Smrg 333fe5e51b7Smrg /* Wait for PCLK PLL to lock on frequency */ 334fe5e51b7Smrg while (( inTi3026( TVP3026_PIX_CLK_DATA ) & 0x40 ) == 0 ) { 335fe5e51b7Smrg ; 336fe5e51b7Smrg } 337fe5e51b7Smrg} 338fe5e51b7Smrg 339fe5e51b7Smrg/* 340fe5e51b7Smrg * MGATi3026SetPCLK - Set the pixel (PCLK) and loop (LCLK) clocks. 341fe5e51b7Smrg * 342fe5e51b7Smrg * PARAMETERS 343fe5e51b7Smrg * f_pll IN Pixel clock PLL frequencly in kHz. 344fe5e51b7Smrg * bpp IN Bytes per pixel. 345fe5e51b7Smrg * 346fe5e51b7Smrg * HISTORY 347fe5e51b7Smrg * January 11, 1997 - [aem] Andrew E. Mileski 348fe5e51b7Smrg * Split to simplify code for MCLK (=GCLK) setting. 349fe5e51b7Smrg * 350fe5e51b7Smrg * December 14, 1996 - [aem] Andrew E. Mileski 351fe5e51b7Smrg * Fixed loop clock to be based on the calculated, not requested, 352fe5e51b7Smrg * pixel clock. Added f_max = maximum f_vco frequency. 353fe5e51b7Smrg * 354fe5e51b7Smrg * October 19, 1996 - [aem] Andrew E. Mileski 355fe5e51b7Smrg * Commented the loop clock code (wow, I understand everything now), 356fe5e51b7Smrg * and simplified it a bit. This should really be two separate functions. 357fe5e51b7Smrg * 358fe5e51b7Smrg * October 1, 1996 - [aem] Andrew E. Mileski 359fe5e51b7Smrg * Optimized the m & n picking algorithm. Added maxClock detection. 360fe5e51b7Smrg * Low speed pixel clock fix (per the docs). Documented what I understand. 361fe5e51b7Smrg * 362fe5e51b7Smrg * ?????, ??, ???? - [???] ???????????? 363fe5e51b7Smrg * Based on the TVP3026 code in the S3 driver. 364fe5e51b7Smrg */ 365fe5e51b7Smrg 366fe5e51b7Smrgstatic void 367fe5e51b7SmrgMGATi3026SetPCLK( ScrnInfoPtr pScrn, long f_out, int bpp ) 368fe5e51b7Smrg{ 369fe5e51b7Smrg /* Pixel clock values */ 370fe5e51b7Smrg int m, n, p; 371fe5e51b7Smrg 372fe5e51b7Smrg /* Loop clock values */ 373fe5e51b7Smrg int lm, ln, lp, lq; 374fe5e51b7Smrg double z; 375fe5e51b7Smrg 376fe5e51b7Smrg /* The actual frequency output by the clock */ 377fe5e51b7Smrg double f_pll; 378fe5e51b7Smrg 379fe5e51b7Smrg long f_max = TI_MAX_VCO_FREQ; 380fe5e51b7Smrg 381fe5e51b7Smrg MGAPtr pMga = MGAPTR(pScrn); 382fe5e51b7Smrg MGARegPtr pReg = &pMga->ModeReg; 383fe5e51b7Smrg 384fe5e51b7Smrg /* Get the maximum pixel clock frequency */ 385fe5e51b7Smrg if ( pMga->MaxClock > TI_MAX_VCO_FREQ ) 386fe5e51b7Smrg f_max = pMga->MaxClock; 387fe5e51b7Smrg 388fe5e51b7Smrg /* Do the calculations for m, n, and p */ 389fe5e51b7Smrg f_pll = MGATi3026CalcClock( f_out, f_max, & m, & n, & p ); 390fe5e51b7Smrg 391fe5e51b7Smrg /* Values for the pixel clock PLL registers */ 392fe5e51b7Smrg pReg->DacClk[ 0 ] = ( n & 0x3f ) | 0xc0; 393fe5e51b7Smrg pReg->DacClk[ 1 ] = ( m & 0x3f ); 394fe5e51b7Smrg pReg->DacClk[ 2 ] = ( p & 0x03 ) | 0xb0; 395fe5e51b7Smrg 396fe5e51b7Smrg /* 397fe5e51b7Smrg * Now that the pixel clock PLL is setup, 398fe5e51b7Smrg * the loop clock PLL must be setup. 399fe5e51b7Smrg */ 400fe5e51b7Smrg 401fe5e51b7Smrg /* 402fe5e51b7Smrg * First we figure out lm, ln, and z. 403fe5e51b7Smrg * Things are different in packed pixel mode (24bpp) though. 404fe5e51b7Smrg */ 405fe5e51b7Smrg if ( pMga->CurrentLayout.bitsPerPixel == 24 ) { 406fe5e51b7Smrg 407fe5e51b7Smrg /* ln:lm = ln:3 */ 408fe5e51b7Smrg lm = 65 - 3; 409fe5e51b7Smrg 410fe5e51b7Smrg /* Check for interleaved mode */ 411fe5e51b7Smrg if ( bpp == 2 ) 412fe5e51b7Smrg /* ln:lm = 4:3 */ 413fe5e51b7Smrg ln = 65 - 4; 414fe5e51b7Smrg else 415fe5e51b7Smrg /* ln:lm = 8:3 */ 416fe5e51b7Smrg ln = 65 - 8; 417fe5e51b7Smrg 418fe5e51b7Smrg /* Note: this is actually 100 * z for more precision */ 419fe5e51b7Smrg z = ( 11000 * ( 65 - ln )) / (( f_pll / 1000 ) * ( 65 - lm )); 420fe5e51b7Smrg } 421fe5e51b7Smrg else { 422fe5e51b7Smrg /* ln:lm = ln:4 */ 423fe5e51b7Smrg lm = 65 - 4; 424fe5e51b7Smrg 425fe5e51b7Smrg /* Note: bpp = bytes per pixel */ 426fe5e51b7Smrg ln = 65 - 4 * ( 64 / 8 ) / bpp; 427fe5e51b7Smrg 428fe5e51b7Smrg /* Note: this is actually 100 * z for more precision */ 429fe5e51b7Smrg z = (( 11000 / 4 ) * ( 65 - ln )) / ( f_pll / 1000 ); 430fe5e51b7Smrg } 431fe5e51b7Smrg 432fe5e51b7Smrg /* 433fe5e51b7Smrg * Now we choose dividers lp and lq so that the VCO frequency 434fe5e51b7Smrg * is within the operating range of 110 MHz to 220 MHz. 435fe5e51b7Smrg */ 436fe5e51b7Smrg 437fe5e51b7Smrg /* Assume no lq divider */ 438fe5e51b7Smrg lq = 0; 439fe5e51b7Smrg 440fe5e51b7Smrg /* Note: z is actually 100 * z for more precision */ 441fe5e51b7Smrg if ( z <= 200.0 ) 442fe5e51b7Smrg lp = 0; 443fe5e51b7Smrg else if ( z <= 400.0 ) 444fe5e51b7Smrg lp = 1; 445fe5e51b7Smrg else if ( z <= 800.0 ) 446fe5e51b7Smrg lp = 2; 447fe5e51b7Smrg else if ( z <= 1600.0 ) 448fe5e51b7Smrg lp = 3; 449fe5e51b7Smrg else { 450fe5e51b7Smrg lp = 3; 451fe5e51b7Smrg lq = ( int )( z / 1600.0 ); 452fe5e51b7Smrg } 453fe5e51b7Smrg 454fe5e51b7Smrg /* Values for the loop clock PLL registers */ 455fe5e51b7Smrg if ( pMga->CurrentLayout.bitsPerPixel == 24 ) { 456fe5e51b7Smrg /* Packed pixel mode values */ 457fe5e51b7Smrg pReg->DacClk[ 3 ] = ( ln & 0x3f ) | 0x80; 458fe5e51b7Smrg pReg->DacClk[ 4 ] = ( lm & 0x3f ) | 0x80; 459fe5e51b7Smrg pReg->DacClk[ 5 ] = ( lp & 0x03 ) | 0xf8; 460fe5e51b7Smrg } else { 461fe5e51b7Smrg /* Non-packed pixel mode values */ 462fe5e51b7Smrg pReg->DacClk[ 3 ] = ( ln & 0x3f ) | 0xc0; 463fe5e51b7Smrg pReg->DacClk[ 4 ] = ( lm & 0x3f ); 464fe5e51b7Smrg pReg->DacClk[ 5 ] = ( lp & 0x03 ) | 0xf0; 465fe5e51b7Smrg } 466fe5e51b7Smrg pReg->DacRegs[ 18 ] = lq | 0x38; 467fe5e51b7Smrg 468fe5e51b7Smrg#ifdef DEBUG 469fe5e51b7Smrg ErrorF( "bpp=%d z=%.1f ln=%d lm=%d lp=%d lq=%d\n", 470fe5e51b7Smrg bpp, z, ln, lm, lp, lq ); 471fe5e51b7Smrg#endif 472fe5e51b7Smrg} 473fe5e51b7Smrg 474fe5e51b7Smrg/* 475fe5e51b7Smrg * MGA3026Init -- for mga2064 with ti3026 476fe5e51b7Smrg * 477fe5e51b7Smrg * The 'mode' parameter describes the video mode. The 'mode' structure 478fe5e51b7Smrg * as well as the 'vga256InfoRec' structure can be dereferenced for 479fe5e51b7Smrg * information that is needed to initialize the mode. The 'new' macro 480fe5e51b7Smrg * (see definition above) is used to simply fill in the structure. 481fe5e51b7Smrg */ 482fe5e51b7Smrgstatic Bool 483fe5e51b7SmrgMGA3026Init(ScrnInfoPtr pScrn, DisplayModePtr mode) 484fe5e51b7Smrg{ 485fe5e51b7Smrg int hd, hs, he, ht, vd, vs, ve, vt, wd; 486fe5e51b7Smrg int i, BppShift, index_1d = 0; 487fe5e51b7Smrg const unsigned char* initDAC; 488fe5e51b7Smrg MGAPtr pMga = MGAPTR(pScrn); 489fe5e51b7Smrg MGARamdacPtr MGAdac = &pMga->Dac; 490fe5e51b7Smrg MGAFBLayout *pLayout = &pMga->CurrentLayout; 491fe5e51b7Smrg MGARegPtr pReg = &pMga->ModeReg; 492fe5e51b7Smrg vgaRegPtr pVga = &VGAHWPTR(pScrn)->ModeReg; 493fe5e51b7Smrg 494fe5e51b7Smrg BppShift = pMga->BppShifts[(pLayout->bitsPerPixel >> 3) - 1]; 495fe5e51b7Smrg 496fe5e51b7Smrg switch(pLayout->bitsPerPixel) 497fe5e51b7Smrg { 498fe5e51b7Smrg case 8: 499fe5e51b7Smrg initDAC = MGADACbpp8; 500fe5e51b7Smrg break; 501fe5e51b7Smrg case 16: 502fe5e51b7Smrg initDAC = MGADACbpp16; 503fe5e51b7Smrg break; 504fe5e51b7Smrg case 24: 505fe5e51b7Smrg initDAC = MGADACbpp24; 506fe5e51b7Smrg break; 507fe5e51b7Smrg case 32: 508eda3803bSmrg initDAC = MGADACbpp32; 509eda3803bSmrg break; 510fe5e51b7Smrg default: 511fe5e51b7Smrg FatalError("MGA: unsupported bits per pixel\n"); 512fe5e51b7Smrg } 513fe5e51b7Smrg 514fe5e51b7Smrg /* Allocate the DacRegs space if not done already */ 515fe5e51b7Smrg if (pReg->DacRegs == NULL) { 516fe5e51b7Smrg pReg->DacRegs = xnfcalloc(DACREGSIZE, 1); 517fe5e51b7Smrg } 518fe5e51b7Smrg for (i = 0; i < DACREGSIZE; i++) { 519fe5e51b7Smrg pReg->DacRegs[i] = initDAC[i]; 520fe5e51b7Smrg if (MGADACregs[i] == 0x1D) 521fe5e51b7Smrg index_1d = i; 522fe5e51b7Smrg } 523fe5e51b7Smrg 524fe5e51b7Smrg if ( (pLayout->bitsPerPixel == 16) && (pLayout->weight.red == 5) 525fe5e51b7Smrg && (pLayout->weight.green == 5) && (pLayout->weight.blue == 5) ) { 526fe5e51b7Smrg pReg->DacRegs[1] &= ~0x01; 527fe5e51b7Smrg } 528fe5e51b7Smrg if (pMga->Interleave ) pReg->DacRegs[2] += 1; 529fe5e51b7Smrg 530fe5e51b7Smrg 531fe5e51b7Smrg if ( pLayout->bitsPerPixel == 24 ) { 532fe5e51b7Smrg int silicon_rev; 533fe5e51b7Smrg /* we need to set DacRegs[0] differently based on the silicon 534fe5e51b7Smrg * revision of the 3026 RAMDAC, as per page 2-14 of tvp3026.pdf. 535fe5e51b7Smrg * If we have rev A silicon, we want 0x07; rev B silicon wants 536fe5e51b7Smrg * 0x06. 537fe5e51b7Smrg */ 538fe5e51b7Smrg silicon_rev = inTi3026(TVP3026_SILICON_REV); 539fe5e51b7Smrg 540fe5e51b7Smrg#ifdef DEBUG 541fe5e51b7Smrg ErrorF("TVP3026 revision 0x%x (rev %s)\n", 542fe5e51b7Smrg silicon_rev, (silicon_rev <= 0x20) ? "A" : "B"); 543fe5e51b7Smrg#endif 544fe5e51b7Smrg 545fe5e51b7Smrg if(silicon_rev <= 0x20) { 546fe5e51b7Smrg /* rev A */ 547fe5e51b7Smrg pReg->DacRegs[0] = 0x07; 548fe5e51b7Smrg } else { 549fe5e51b7Smrg /* rev B */ 550fe5e51b7Smrg pReg->DacRegs[0] = 0x06; 551fe5e51b7Smrg } 552fe5e51b7Smrg } 553fe5e51b7Smrg 554fe5e51b7Smrg /* 555fe5e51b7Smrg * This will initialize all of the generic VGA registers. 556fe5e51b7Smrg */ 557fe5e51b7Smrg if (!vgaHWInit(pScrn, mode)) 558fe5e51b7Smrg return(FALSE); 559fe5e51b7Smrg 560fe5e51b7Smrg /* 561fe5e51b7Smrg * Here all of the MGA registers get filled in. 562fe5e51b7Smrg */ 563fe5e51b7Smrg hd = (mode->CrtcHDisplay >> 3) - 1; 564fe5e51b7Smrg hs = (mode->CrtcHSyncStart >> 3) - 1; 565fe5e51b7Smrg he = (mode->CrtcHSyncEnd >> 3) - 1; 566fe5e51b7Smrg ht = (mode->CrtcHTotal >> 3) - 1; 567fe5e51b7Smrg vd = mode->CrtcVDisplay - 1; 568fe5e51b7Smrg vs = mode->CrtcVSyncStart - 1; 569fe5e51b7Smrg ve = mode->CrtcVSyncEnd - 1; 570fe5e51b7Smrg vt = mode->CrtcVTotal - 2; 571fe5e51b7Smrg 572fe5e51b7Smrg /* HTOTAL & 0x7 equal to 0x6 in 8bpp or 0x4 in 24bpp causes strange 573fe5e51b7Smrg * vertical stripes 574fe5e51b7Smrg */ 575fe5e51b7Smrg if((ht & 0x07) == 0x06 || (ht & 0x07) == 0x04) 576fe5e51b7Smrg ht++; 577fe5e51b7Smrg 578fe5e51b7Smrg if (pLayout->bitsPerPixel == 24) 579fe5e51b7Smrg wd = (pLayout->displayWidth * 3) >> (4 - BppShift); 580fe5e51b7Smrg else 581fe5e51b7Smrg wd = pLayout->displayWidth >> (4 - BppShift); 582fe5e51b7Smrg 583fe5e51b7Smrg pReg->ExtVga[0] = 0; 584fe5e51b7Smrg pReg->ExtVga[5] = 0; 585fe5e51b7Smrg 586fe5e51b7Smrg if (mode->Flags & V_INTERLACE) 587fe5e51b7Smrg { 588fe5e51b7Smrg pReg->ExtVga[0] = 0x80; 589fe5e51b7Smrg pReg->ExtVga[5] = (hs + he - ht) >> 1; 590fe5e51b7Smrg wd <<= 1; 591fe5e51b7Smrg vt &= 0xFFFE; 592fe5e51b7Smrg 593fe5e51b7Smrg /* enable interlaced cursor */ 594fe5e51b7Smrg pReg->DacRegs[20] |= 0x20; 595fe5e51b7Smrg } 596fe5e51b7Smrg 597fe5e51b7Smrg pReg->ExtVga[0] |= (wd & 0x300) >> 4; 598fe5e51b7Smrg pReg->ExtVga[1] = (((ht - 4) & 0x100) >> 8) | 599fe5e51b7Smrg ((hd & 0x100) >> 7) | 600fe5e51b7Smrg ((hs & 0x100) >> 6) | 601fe5e51b7Smrg (ht & 0x40); 602fe5e51b7Smrg pReg->ExtVga[2] = ((vt & 0xc00) >> 10) | 603fe5e51b7Smrg ((vd & 0x400) >> 8) | 604fe5e51b7Smrg ((vd & 0xc00) >> 7) | 605fe5e51b7Smrg ((vs & 0xc00) >> 5); 606fe5e51b7Smrg if (pLayout->bitsPerPixel == 24) 607fe5e51b7Smrg pReg->ExtVga[3] = (((1 << BppShift) * 3) - 1) | 0x80; 608fe5e51b7Smrg else 609fe5e51b7Smrg pReg->ExtVga[3] = ((1 << BppShift) - 1) | 0x80; 610fe5e51b7Smrg 611fe5e51b7Smrg /* Set viddelay (CRTCEXT3 Bits 3-4). */ 612fe5e51b7Smrg pReg->ExtVga[3] |= (pScrn->videoRam == 8192 ? 0x10 613fe5e51b7Smrg : pScrn->videoRam == 2048 ? 0x08 : 0x00); 614fe5e51b7Smrg 615fe5e51b7Smrg pReg->ExtVga[4] = 0; 616fe5e51b7Smrg 617fe5e51b7Smrg pVga->CRTC[0] = ht - 4; 618fe5e51b7Smrg pVga->CRTC[1] = hd; 619fe5e51b7Smrg pVga->CRTC[2] = hd; 620fe5e51b7Smrg pVga->CRTC[3] = (ht & 0x1F) | 0x80; 621fe5e51b7Smrg pVga->CRTC[4] = hs; 622fe5e51b7Smrg pVga->CRTC[5] = ((ht & 0x20) << 2) | (he & 0x1F); 623fe5e51b7Smrg pVga->CRTC[6] = vt & 0xFF; 624fe5e51b7Smrg pVga->CRTC[7] = ((vt & 0x100) >> 8 ) | 625fe5e51b7Smrg ((vd & 0x100) >> 7 ) | 626fe5e51b7Smrg ((vs & 0x100) >> 6 ) | 627fe5e51b7Smrg ((vd & 0x100) >> 5 ) | 628fe5e51b7Smrg 0x10 | 629fe5e51b7Smrg ((vt & 0x200) >> 4 ) | 630fe5e51b7Smrg ((vd & 0x200) >> 3 ) | 631fe5e51b7Smrg ((vs & 0x200) >> 2 ); 632fe5e51b7Smrg pVga->CRTC[9] = ((vd & 0x200) >> 4) | 0x40; 633fe5e51b7Smrg pVga->CRTC[16] = vs & 0xFF; 634fe5e51b7Smrg pVga->CRTC[17] = (ve & 0x0F) | 0x20; 635fe5e51b7Smrg pVga->CRTC[18] = vd & 0xFF; 636fe5e51b7Smrg pVga->CRTC[19] = wd & 0xFF; 637fe5e51b7Smrg pVga->CRTC[21] = vd & 0xFF; 638fe5e51b7Smrg pVga->CRTC[22] = (vt + 1) & 0xFF; 639fe5e51b7Smrg 640fe5e51b7Smrg if (mode->Flags & V_DBLSCAN) 641fe5e51b7Smrg pVga->CRTC[9] |= 0x80; 642fe5e51b7Smrg 643fe5e51b7Smrg /* Per DDK vid.c line 75, sync polarity should be controlled 644fe5e51b7Smrg * via the TVP3026 RAMDAC register 1D and so MISC Output Register 645fe5e51b7Smrg * should always have bits 6 and 7 set. */ 646fe5e51b7Smrg 647fe5e51b7Smrg pVga->MiscOutReg |= 0xC0; 648fe5e51b7Smrg if ((mode->Flags & (V_PHSYNC | V_NHSYNC)) && 649fe5e51b7Smrg (mode->Flags & (V_PVSYNC | V_NVSYNC))) 650fe5e51b7Smrg { 651fe5e51b7Smrg if (mode->Flags & V_PHSYNC) 652fe5e51b7Smrg pReg->DacRegs[index_1d] |= 0x01; 653fe5e51b7Smrg if (mode->Flags & V_PVSYNC) 654fe5e51b7Smrg pReg->DacRegs[index_1d] |= 0x02; 655fe5e51b7Smrg } 656fe5e51b7Smrg else 657fe5e51b7Smrg { 658fe5e51b7Smrg int VDisplay = mode->VDisplay; 659fe5e51b7Smrg if (mode->Flags & V_DBLSCAN) 660fe5e51b7Smrg VDisplay *= 2; 661fe5e51b7Smrg if (VDisplay < 400) 662fe5e51b7Smrg pReg->DacRegs[index_1d] |= 0x01; /* +hsync -vsync */ 663fe5e51b7Smrg else if (VDisplay < 480) 664fe5e51b7Smrg pReg->DacRegs[index_1d] |= 0x02; /* -hsync +vsync */ 665fe5e51b7Smrg else if (VDisplay < 768) 666fe5e51b7Smrg pReg->DacRegs[index_1d] |= 0x00; /* -hsync -vsync */ 667fe5e51b7Smrg else 668fe5e51b7Smrg pReg->DacRegs[index_1d] |= 0x03; /* +hsync +vsync */ 669fe5e51b7Smrg } 670fe5e51b7Smrg 671fe5e51b7Smrg if (pMga->SyncOnGreen) 672fe5e51b7Smrg pReg->DacRegs[index_1d] |= 0x20; 673fe5e51b7Smrg 674fe5e51b7Smrg pReg->Option = 0x402C0100; /* fine for 2064 and 2164 */ 675fe5e51b7Smrg 676fe5e51b7Smrg if (pMga->Interleave) 677fe5e51b7Smrg pReg->Option |= 0x1000; 678fe5e51b7Smrg else 679fe5e51b7Smrg pReg->Option &= ~0x1000; 680fe5e51b7Smrg 681fe5e51b7Smrg /* must always have the pci retries on but rely on 682d2b10af6Smrg polling to keep them from occurring */ 683fe5e51b7Smrg pReg->Option &= ~0x20000000; 684fe5e51b7Smrg 685fe5e51b7Smrg pVga->MiscOutReg |= 0x0C; 686fe5e51b7Smrg /* XXX Need to check the first argument */ 687fe5e51b7Smrg MGATi3026SetPCLK( pScrn, mode->Clock, 1 << BppShift ); 688fe5e51b7Smrg 689fe5e51b7Smrg /* this one writes registers rather than writing to the 690fe5e51b7Smrg mgaReg->ModeReg and letting Restore write to the hardware 691fe5e51b7Smrg but that's no big deal since we will Restore right after 692fe5e51b7Smrg this function */ 693fe5e51b7Smrg 694fe5e51b7Smrg MGA_NOT_HAL(MGATi3026SetMCLK(pScrn, MGAdac->MemoryClock)); 695fe5e51b7Smrg 696fe5e51b7Smrg#ifdef DEBUG 69781f79626Smrg ErrorF("%6d: %02X %02X %02X %02X %02X %02X %08X\n", mode->Clock, 69881f79626Smrg pReg->DacClk[0], pReg->DacClk[1], pReg->DacClk[2], pReg->DacClk[3], pReg->DacClk[4], pReg->DacClk[5], (unsigned)pReg->Option); 699fe5e51b7Smrg for (i=0; i<sizeof(MGADACregs); i++) ErrorF("%02X ", pReg->DacRegs[i]); 700fe5e51b7Smrg for (i=0; i<6; i++) ErrorF(" %02X", pReg->ExtVga[i]); 701fe5e51b7Smrg ErrorF("\n"); 702fe5e51b7Smrg#endif 703fe5e51b7Smrg 704fe5e51b7Smrg /* This disables the VGA memory aperture */ 705fe5e51b7Smrg pVga->MiscOutReg &= ~0x02; 706fe5e51b7Smrg return(TRUE); 707fe5e51b7Smrg} 708fe5e51b7Smrg 709fe5e51b7Smrg/* 710fe5e51b7Smrg * MGA3026Restore -- for mga2064 with ti3026 711fe5e51b7Smrg * 712fe5e51b7Smrg * This function restores a video mode. It basically writes out all of 713fe5e51b7Smrg * the registers that have previously been saved in the vgaMGARec data 714fe5e51b7Smrg * structure. 715fe5e51b7Smrg */ 716fe5e51b7Smrgstatic void 717fe5e51b7SmrgMGA3026Restore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, MGARegPtr mgaReg, 718fe5e51b7Smrg Bool restoreFonts) 719fe5e51b7Smrg{ 720fe5e51b7Smrg int i; 721fe5e51b7Smrg MGAPtr pMga = MGAPTR(pScrn); 722fe5e51b7Smrg 723fe5e51b7Smrg /* 724fe5e51b7Smrg * Code is needed to get things back to bank zero. 725fe5e51b7Smrg */ 726fe5e51b7Smrg for (i = 0; i < 6; i++) 727fe5e51b7Smrg OUTREG16(0x1FDE, (mgaReg->ExtVga[i] << 8) | i); 728fe5e51b7Smrg 729fe5e51b7Smrg#ifdef XSERVER_LIBPCIACCESS 730cc92fc76Swiz pci_device_cfg_write_bits(pMga->PciInfo, OPTION_MASK, mgaReg->Option, 731fe5e51b7Smrg PCI_OPTION_REG); 732fe5e51b7Smrg#else 733fe5e51b7Smrg pciSetBitsLong(pMga->PciTag, PCI_OPTION_REG, OPTION_MASK, 734fe5e51b7Smrg mgaReg->Option); 735fe5e51b7Smrg#endif 736fe5e51b7Smrg 737fe5e51b7Smrg MGA_NOT_HAL( 738fe5e51b7Smrg /* select pixel clock PLL as clock source */ 739fe5e51b7Smrg outTi3026(TVP3026_CLK_SEL, 0, mgaReg->DacRegs[3]); 740fe5e51b7Smrg 741fe5e51b7Smrg /* set loop and pixel clock PLL PLLEN bits to 0 */ 742fe5e51b7Smrg outTi3026(TVP3026_PLL_ADDR, 0, 0x2A); 743fe5e51b7Smrg outTi3026(TVP3026_LOAD_CLK_DATA, 0, 0); 744fe5e51b7Smrg outTi3026(TVP3026_PIX_CLK_DATA, 0, 0); 745fe5e51b7Smrg ); /* MGA_NOT_HAL */ 746fe5e51b7Smrg 747fe5e51b7Smrg /* 748fe5e51b7Smrg * This function handles restoring the generic VGA registers. 749fe5e51b7Smrg */ 750fe5e51b7Smrg vgaHWRestore(pScrn, vgaReg, 751fe5e51b7Smrg VGA_SR_MODE | (restoreFonts ? VGA_SR_FONTS : 0)); 752fe5e51b7Smrg MGA3026RestorePalette(pScrn, vgaReg->DAC); 753fe5e51b7Smrg 754fe5e51b7Smrg /* 755fe5e51b7Smrg * Code to restore SVGA registers that have been saved/modified 756fe5e51b7Smrg * goes here. 757fe5e51b7Smrg */ 758fe5e51b7Smrg 759fe5e51b7Smrg MGA_NOT_HAL( 760fe5e51b7Smrg /* program pixel clock PLL */ 761fe5e51b7Smrg outTi3026(TVP3026_PLL_ADDR, 0, 0x00); 762fe5e51b7Smrg for (i = 0; i < 3; i++) 763fe5e51b7Smrg outTi3026(TVP3026_PIX_CLK_DATA, 0, mgaReg->DacClk[i]); 764fe5e51b7Smrg 765fe5e51b7Smrg if (vgaReg->MiscOutReg & 0x08) { 766fe5e51b7Smrg /* poll until pixel clock PLL LOCK bit is set */ 767fe5e51b7Smrg outTi3026(TVP3026_PLL_ADDR, 0, 0x3F); 768fe5e51b7Smrg while ( ! (inTi3026(TVP3026_PIX_CLK_DATA) & 0x40) ); 769fe5e51b7Smrg } 770fe5e51b7Smrg 771fe5e51b7Smrg /* set Q divider for loop clock PLL */ 772fe5e51b7Smrg outTi3026(TVP3026_MCLK_CTL, 0, mgaReg->DacRegs[18]); 773fe5e51b7Smrg ); /* MGA_NOT_HAL */ 774fe5e51b7Smrg 775fe5e51b7Smrg /* program loop PLL */ 776fe5e51b7Smrg outTi3026(TVP3026_PLL_ADDR, 0, 0x00); 777fe5e51b7Smrg for (i = 3; i < 6; i++) 778fe5e51b7Smrg outTi3026(TVP3026_LOAD_CLK_DATA, 0, mgaReg->DacClk[i]); 779fe5e51b7Smrg 780fe5e51b7Smrg MGA_NOT_HAL( 781fe5e51b7Smrg if ((vgaReg->MiscOutReg & 0x08) && ((mgaReg->DacClk[3] & 0xC0) == 0xC0) ) { 782fe5e51b7Smrg /* poll until loop PLL LOCK bit is set */ 783fe5e51b7Smrg outTi3026(TVP3026_PLL_ADDR, 0, 0x3F); 784fe5e51b7Smrg while ( ! (inTi3026(TVP3026_LOAD_CLK_DATA) & 0x40) ); 785fe5e51b7Smrg } 786fe5e51b7Smrg ); /* MGA_NOT_HAL */ 787fe5e51b7Smrg 788fe5e51b7Smrg /* 789fe5e51b7Smrg * restore other DAC registers 790fe5e51b7Smrg */ 791fe5e51b7Smrg for (i = 0; i < DACREGSIZE; i++) 792fe5e51b7Smrg outTi3026(MGADACregs[i], 0, mgaReg->DacRegs[i]); 793fe5e51b7Smrg 794fe5e51b7Smrg#ifdef DEBUG 795fe5e51b7Smrg ErrorF("PCI retry (0-enabled / 1-disabled): %d\n", 796fe5e51b7Smrg !!(mgaReg->Option & 0x20000000)); 797fe5e51b7Smrg#endif 798fe5e51b7Smrg} 799fe5e51b7Smrg 800fe5e51b7Smrg/* 801fe5e51b7Smrg * MGA3026Save -- for mga2064 with ti3026 802fe5e51b7Smrg * 803fe5e51b7Smrg * This function saves the video state. 804fe5e51b7Smrg */ 805fe5e51b7Smrgstatic void 806fe5e51b7SmrgMGA3026Save(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, MGARegPtr mgaReg, 807fe5e51b7Smrg Bool saveFonts) 808fe5e51b7Smrg{ 809fe5e51b7Smrg int i; 810fe5e51b7Smrg MGAPtr pMga = MGAPTR(pScrn); 811fe5e51b7Smrg 812fe5e51b7Smrg /* Allocate the DacRegs space if not done already */ 813fe5e51b7Smrg if (mgaReg->DacRegs == NULL) { 814fe5e51b7Smrg mgaReg->DacRegs = xnfcalloc(DACREGSIZE, 1); 815fe5e51b7Smrg } 816fe5e51b7Smrg 817fe5e51b7Smrg /* 818fe5e51b7Smrg * Code is needed to get back to bank zero. 819fe5e51b7Smrg */ 820fe5e51b7Smrg OUTREG16(0x1FDE, 0x0004); 821fe5e51b7Smrg 822fe5e51b7Smrg /* 823fe5e51b7Smrg * This function will handle creating the data structure and filling 824fe5e51b7Smrg * in the generic VGA portion. 825fe5e51b7Smrg */ 826fe5e51b7Smrg vgaHWSave(pScrn, vgaReg, VGA_SR_MODE | (saveFonts ? VGA_SR_FONTS : 0)); 827fe5e51b7Smrg MGA3026SavePalette(pScrn, vgaReg->DAC); 828fe5e51b7Smrg 829fe5e51b7Smrg /* 830fe5e51b7Smrg * The port I/O code necessary to read in the extended registers 831fe5e51b7Smrg * into the fields of the vgaMGARec structure. 832fe5e51b7Smrg */ 833fe5e51b7Smrg for (i = 0; i < 6; i++) 834fe5e51b7Smrg { 835fe5e51b7Smrg OUTREG8(0x1FDE, i); 836fe5e51b7Smrg mgaReg->ExtVga[i] = INREG8(0x1FDF); 837fe5e51b7Smrg } 838fe5e51b7Smrg 839fe5e51b7Smrg MGA_NOT_HAL( 840fe5e51b7Smrg outTi3026(TVP3026_PLL_ADDR, 0, 0x00); 841fe5e51b7Smrg for (i = 0; i < 3; i++) 842fe5e51b7Smrg outTi3026(TVP3026_PIX_CLK_DATA, 0, mgaReg->DacClk[i] = 843fe5e51b7Smrg inTi3026(TVP3026_PIX_CLK_DATA)); 844fe5e51b7Smrg 845fe5e51b7Smrg outTi3026(TVP3026_PLL_ADDR, 0, 0x00); 846fe5e51b7Smrg for (i = 3; i < 6; i++) 847fe5e51b7Smrg outTi3026(TVP3026_LOAD_CLK_DATA, 0, mgaReg->DacClk[i] = 848fe5e51b7Smrg inTi3026(TVP3026_LOAD_CLK_DATA)); 849fe5e51b7Smrg ); /* MGA_NOT_HAL */ 850fe5e51b7Smrg 851fe5e51b7Smrg for (i = 0; i < DACREGSIZE; i++) 852fe5e51b7Smrg mgaReg->DacRegs[i] = inTi3026(MGADACregs[i]); 853fe5e51b7Smrg 854fe5e51b7Smrg#ifdef XSERVER_LIBPCIACCESS 855f9071301Swiz { 856f9071301Swiz uint32_t Option; 8576f68ce78Smrg pci_device_cfg_read_u32(pMga->PciInfo, & Option, 858fe5e51b7Smrg PCI_OPTION_REG); 859f9071301Swiz mgaReg->Option = Option; 860f9071301Swiz } 861fe5e51b7Smrg#else 862fe5e51b7Smrg mgaReg->Option = pciReadLong(pMga->PciTag, PCI_OPTION_REG); 863fe5e51b7Smrg#endif 864fe5e51b7Smrg 865fe5e51b7Smrg#ifdef DEBUG 86681f79626Smrg ErrorF("read: %02X %02X %02X %02X %02X %02X %08X\n", 86781f79626Smrg mgaReg->DacClk[0], mgaReg->DacClk[1], mgaReg->DacClk[2], mgaReg->DacClk[3], mgaReg->DacClk[4], mgaReg->DacClk[5], (unsigned)mgaReg->Option); 868fe5e51b7Smrg for (i=0; i<sizeof(MGADACregs); i++) ErrorF("%02X ", mgaReg->DacRegs[i]); 869fe5e51b7Smrg for (i=0; i<6; i++) ErrorF(" %02X", mgaReg->ExtVga[i]); 870fe5e51b7Smrg ErrorF("\n"); 871fe5e51b7Smrg#endif 872fe5e51b7Smrg} 873fe5e51b7Smrg 874fe5e51b7Smrg 875fe5e51b7Smrgstatic void 876fe5e51b7SmrgMGA3026LoadCursorImage( 877fe5e51b7Smrg ScrnInfoPtr pScrn, 878fe5e51b7Smrg unsigned char *src 879fe5e51b7Smrg) 880fe5e51b7Smrg{ 881fe5e51b7Smrg MGAPtr pMga = MGAPTR(pScrn); 882fe5e51b7Smrg int i = 1024; 883fe5e51b7Smrg 884fe5e51b7Smrg outTi3026(TVP3026_CURSOR_CTL, 0xf3, 0x00); /* reset A9,A8 */ 885fe5e51b7Smrg /* reset cursor RAM load address A7..A0 */ 886fe5e51b7Smrg outTi3026dreg(TVP3026_WADR_PAL, 0x00); 887fe5e51b7Smrg 888fe5e51b7Smrg while(i--) { 889fe5e51b7Smrg while (INREG8(0x1FDA) & 0x01); 890fe5e51b7Smrg while (!(INREG8(0x1FDA) & 0x01)); 891fe5e51b7Smrg outTi3026dreg(TVP3026_CUR_RAM, *(src++)); 892fe5e51b7Smrg } 893fe5e51b7Smrg} 894fe5e51b7Smrg 895fe5e51b7Smrg 896fe5e51b7Smrgstatic void 897fe5e51b7SmrgMGA3026ShowCursor(ScrnInfoPtr pScrn) 898fe5e51b7Smrg{ 899fe5e51b7Smrg MGAPtr pMga = MGAPTR(pScrn); 900fe5e51b7Smrg /* Enable cursor - X11 mode */ 901fe5e51b7Smrg outTi3026(TVP3026_CURSOR_CTL, 0x6c, 0x13); 902fe5e51b7Smrg} 903fe5e51b7Smrg 904fe5e51b7Smrgstatic void 905fe5e51b7SmrgMGA3026HideCursor(ScrnInfoPtr pScrn) 906fe5e51b7Smrg{ 907fe5e51b7Smrg MGAPtr pMga = MGAPTR(pScrn); 908fe5e51b7Smrg /* Disable cursor */ 909fe5e51b7Smrg outTi3026(TVP3026_CURSOR_CTL, 0xfc, 0x00); 910fe5e51b7Smrg} 911fe5e51b7Smrg 912fe5e51b7Smrgstatic void 913fe5e51b7SmrgMGA3026SetCursorPosition( 914fe5e51b7Smrg ScrnInfoPtr pScrn, 915fe5e51b7Smrg int x, int y 916fe5e51b7Smrg) 917fe5e51b7Smrg{ 918fe5e51b7Smrg MGAPtr pMga = MGAPTR(pScrn); 919fe5e51b7Smrg x += 64; 920fe5e51b7Smrg y += 64; 921fe5e51b7Smrg 922fe5e51b7Smrg /* Output position - "only" 12 bits of location documented */ 923fe5e51b7Smrg 924fe5e51b7Smrg outTi3026dreg(TVP3026_CUR_XLOW, x & 0xFF); 925fe5e51b7Smrg outTi3026dreg(TVP3026_CUR_XHI, (x >> 8) & 0x0F); 926fe5e51b7Smrg outTi3026dreg(TVP3026_CUR_YLOW, y & 0xFF); 927fe5e51b7Smrg outTi3026dreg(TVP3026_CUR_YHI, (y >> 8) & 0x0F); 928fe5e51b7Smrg} 929fe5e51b7Smrg 930fe5e51b7Smrgstatic void 931fe5e51b7SmrgMGA3026SetCursorColors( 932fe5e51b7Smrg ScrnInfoPtr pScrn, 933fe5e51b7Smrg int bg, int fg 934fe5e51b7Smrg) 935fe5e51b7Smrg{ 936fe5e51b7Smrg MGAPtr pMga = MGAPTR(pScrn); 937fe5e51b7Smrg /* The TI 3026 cursor is always 8 bits so shift 8, not 10 */ 938fe5e51b7Smrg 939fe5e51b7Smrg /* Background color */ 940fe5e51b7Smrg outTi3026dreg(TVP3026_CUR_COL_ADDR, 1); 941fe5e51b7Smrg outTi3026dreg(TVP3026_CUR_COL_DATA, (bg & 0x00FF0000) >> 16); 942fe5e51b7Smrg outTi3026dreg(TVP3026_CUR_COL_DATA, (bg & 0x0000FF00) >> 8); 943fe5e51b7Smrg outTi3026dreg(TVP3026_CUR_COL_DATA, (bg & 0x000000FF)); 944fe5e51b7Smrg 945fe5e51b7Smrg /* Foreground color */ 946fe5e51b7Smrg outTi3026dreg(TVP3026_CUR_COL_ADDR, 2); 947fe5e51b7Smrg outTi3026dreg(TVP3026_CUR_COL_DATA, (fg & 0x00FF0000) >> 16); 948fe5e51b7Smrg outTi3026dreg(TVP3026_CUR_COL_DATA, (fg & 0x0000FF00) >> 8); 949fe5e51b7Smrg outTi3026dreg(TVP3026_CUR_COL_DATA, (fg & 0x000000FF)); 950fe5e51b7Smrg} 951fe5e51b7Smrg 952fe5e51b7Smrgstatic Bool 953fe5e51b7SmrgMGA3026UseHWCursor(ScreenPtr pScrn, CursorPtr pCurs) 954fe5e51b7Smrg{ 955fe5e51b7Smrg if( XF86SCRNINFO(pScrn)->currentMode->Flags & V_DBLSCAN ) 956fe5e51b7Smrg return FALSE; 957fe5e51b7Smrg return TRUE; 958fe5e51b7Smrg} 959fe5e51b7Smrg 960fe5e51b7Smrgstatic const int DDC_SDA_MASK = 1 << 2; 961fe5e51b7Smrgstatic const int DDC_SCL_MASK = 1 << 4; 962fe5e51b7Smrg 963fe5e51b7Smrgstatic unsigned int 964fe5e51b7SmrgMGA3026_ddc1Read(ScrnInfoPtr pScrn) 965fe5e51b7Smrg{ 966fe5e51b7Smrg MGAPtr pMga = MGAPTR(pScrn); 967fe5e51b7Smrg 968fe5e51b7Smrg /* Define the SDA as an input */ 969fe5e51b7Smrg outTi3026(TVP3026_GEN_IO_CTL, 0xfb, 0); 970fe5e51b7Smrg 971fe5e51b7Smrg /* wait for Vsync */ 972fe5e51b7Smrg while( INREG( MGAREG_Status ) & 0x08 ); 973fe5e51b7Smrg while( ! (INREG( MGAREG_Status ) & 0x08) ); 974fe5e51b7Smrg 975fe5e51b7Smrg /* Get the result */ 976fe5e51b7Smrg return (inTi3026(TVP3026_GEN_IO_DATA) & DDC_SDA_MASK) >> 2 ; 977fe5e51b7Smrg} 978fe5e51b7Smrg 979fe5e51b7Smrgstatic void 980fe5e51b7SmrgMGA3026_I2CGetBits(I2CBusPtr b, int *clock, int *data) 981fe5e51b7Smrg{ 982fe5e51b7Smrg ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; 983fe5e51b7Smrg MGAPtr pMga = MGAPTR(pScrn); 984fe5e51b7Smrg unsigned char val; 985fe5e51b7Smrg 986fe5e51b7Smrg /* Get the result. */ 987fe5e51b7Smrg val = inTi3026(TVP3026_GEN_IO_DATA); 988fe5e51b7Smrg *clock = (val & DDC_SCL_MASK) != 0; 989fe5e51b7Smrg *data = (val & DDC_SDA_MASK) != 0; 990fe5e51b7Smrg 991fe5e51b7Smrg#ifdef DEBUG 992fe5e51b7Smrg ErrorF("MGA3026_I2CGetBits(%p,...) val=0x%x, returns clock %d, data %d\n", b, val, *clock, *data); 993fe5e51b7Smrg#endif 994fe5e51b7Smrg} 995fe5e51b7Smrg 996fe5e51b7Smrg/* 997fe5e51b7Smrg * ATTENTION! - the DATA and CLOCK lines need to be tri-stated when 998fe5e51b7Smrg * high. Therefore turn off output driver for the line to set line 999fe5e51b7Smrg * to high. High signal is maintained by a 15k Ohm pll-up resistor. 1000fe5e51b7Smrg */ 1001fe5e51b7Smrgstatic void 1002fe5e51b7SmrgMGA3026_I2CPutBits(I2CBusPtr b, int clock, int data) 1003fe5e51b7Smrg{ 1004fe5e51b7Smrg ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; 1005fe5e51b7Smrg MGAPtr pMga = MGAPTR(pScrn); 1006fe5e51b7Smrg unsigned char val,drv; 1007fe5e51b7Smrg 1008fe5e51b7Smrg /* Write the values */ 1009fe5e51b7Smrg val = (clock ? DDC_SCL_MASK : 0) | (data ? DDC_SDA_MASK : 0); 1010fe5e51b7Smrg drv = ((!clock) ? DDC_SCL_MASK : 0) | ((!data) ? DDC_SDA_MASK : 0); 1011fe5e51b7Smrg /* Define the SDA (Data) and SCL (clock) as outputs */ 1012fe5e51b7Smrg outTi3026(TVP3026_GEN_IO_CTL, ~(DDC_SDA_MASK | DDC_SCL_MASK), drv); 1013fe5e51b7Smrg outTi3026(TVP3026_GEN_IO_DATA, ~(DDC_SDA_MASK | DDC_SCL_MASK), val); 1014fe5e51b7Smrg 1015fe5e51b7Smrg#ifdef DEBUG 1016fe5e51b7Smrg ErrorF("MGA3026_I2CPutBits(%p, %d, %d) val=0x%x\n", b, clock, data, val); 1017fe5e51b7Smrg#endif 1018fe5e51b7Smrg 1019fe5e51b7Smrg} 1020fe5e51b7Smrg 1021fe5e51b7Smrg 1022fe5e51b7SmrgBool 1023fe5e51b7SmrgMGA3026_i2cInit(ScrnInfoPtr pScrn) 1024fe5e51b7Smrg{ 1025fe5e51b7Smrg MGAPtr pMga = MGAPTR(pScrn); 1026fe5e51b7Smrg I2CBusPtr I2CPtr; 1027fe5e51b7Smrg 1028fe5e51b7Smrg I2CPtr = xf86CreateI2CBusRec(); 1029fe5e51b7Smrg if(!I2CPtr) return FALSE; 1030fe5e51b7Smrg 1031fe5e51b7Smrg pMga->DDC_Bus1 = I2CPtr; 1032fe5e51b7Smrg 1033fe5e51b7Smrg I2CPtr->BusName = "DDC"; 1034fe5e51b7Smrg I2CPtr->scrnIndex = pScrn->scrnIndex; 1035fe5e51b7Smrg I2CPtr->I2CPutBits = MGA3026_I2CPutBits; 1036fe5e51b7Smrg I2CPtr->I2CGetBits = MGA3026_I2CGetBits; 1037fe5e51b7Smrg 1038fe5e51b7Smrg /* I2CPutByte is timing out, experimenting with AcknTimeout 1039fe5e51b7Smrg * default is 2CPtr->AcknTimeout = 5; 1040fe5e51b7Smrg */ 1041fe5e51b7Smrg /* I2CPtr->AcknTimeout = 10; */ 1042fe5e51b7Smrg 1043fe5e51b7Smrg if (!xf86I2CBusInit(I2CPtr)) { 1044fe5e51b7Smrg return FALSE; 1045fe5e51b7Smrg } 1046fe5e51b7Smrg return TRUE; 1047fe5e51b7Smrg} 1048fe5e51b7Smrg 1049fe5e51b7Smrgstatic void 1050fe5e51b7SmrgMGA3026RamdacInit(ScrnInfoPtr pScrn) 1051fe5e51b7Smrg{ 1052fe5e51b7Smrg MGAPtr pMga; 1053fe5e51b7Smrg MGARamdacPtr MGAdac; 1054fe5e51b7Smrg 1055fe5e51b7Smrg pMga = MGAPTR(pScrn); 1056fe5e51b7Smrg MGAdac = &pMga->Dac; 1057fe5e51b7Smrg 1058fe5e51b7Smrg MGAdac->isHwCursor = TRUE; 1059fe5e51b7Smrg MGAdac->CursorMaxWidth = 64; 1060fe5e51b7Smrg MGAdac->CursorMaxHeight = 64; 1061fe5e51b7Smrg MGAdac->SetCursorColors = MGA3026SetCursorColors; 1062fe5e51b7Smrg MGAdac->SetCursorPosition = MGA3026SetCursorPosition; 1063fe5e51b7Smrg MGAdac->LoadCursorImage = MGA3026LoadCursorImage; 1064fe5e51b7Smrg MGAdac->HideCursor = MGA3026HideCursor; 1065fe5e51b7Smrg MGAdac->ShowCursor = MGA3026ShowCursor; 1066fe5e51b7Smrg MGAdac->UseHWCursor = MGA3026UseHWCursor; 1067fe5e51b7Smrg MGAdac->CursorFlags = 1068fe5e51b7Smrg#if X_BYTE_ORDER == X_LITTLE_ENDIAN 1069fe5e51b7Smrg HARDWARE_CURSOR_BIT_ORDER_MSBFIRST | 1070fe5e51b7Smrg#endif 1071fe5e51b7Smrg HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | 1072fe5e51b7Smrg HARDWARE_CURSOR_SOURCE_MASK_NOT_INTERLEAVED; 1073fe5e51b7Smrg 1074fe5e51b7Smrg MGAdac->LoadPalette = MGA3026LoadPalette; 1075fe5e51b7Smrg MGAdac->RestorePalette = MGA3026RestorePalette; 1076fe5e51b7Smrg 1077fe5e51b7Smrg MGAdac->maxPixelClock = pMga->bios.pixel.max_freq; 1078fe5e51b7Smrg MGAdac->ClockFrom = X_PROBED; 1079fe5e51b7Smrg 1080fe5e51b7Smrg MGAdac->MemoryClock = pMga->bios.mem_clock; 1081fe5e51b7Smrg MGAdac->MemClkFrom = X_PROBED; 1082fe5e51b7Smrg MGAdac->SetMemClk = TRUE; 1083fe5e51b7Smrg 1084fe5e51b7Smrg 1085fe5e51b7Smrg /* safety check */ 1086fe5e51b7Smrg if ( (MGAdac->MemoryClock < 40000) || 1087fe5e51b7Smrg (MGAdac->MemoryClock > 70000) ) 1088fe5e51b7Smrg MGAdac->MemoryClock = 50000; 1089fe5e51b7Smrg 1090fe5e51b7Smrg /* 1091fe5e51b7Smrg * Should initialise a sane default when the probed value is 1092fe5e51b7Smrg * obviously garbage. 1093fe5e51b7Smrg */ 1094fe5e51b7Smrg 1095fe5e51b7Smrg /* Check if interleaving can be used and set the rounding value */ 1096fe5e51b7Smrg if (pScrn->videoRam > 2048) 1097fe5e51b7Smrg pMga->Interleave = TRUE; 1098fe5e51b7Smrg else { 1099fe5e51b7Smrg pMga->Interleave = FALSE; 1100fe5e51b7Smrg pMga->BppShifts[0]++; 1101fe5e51b7Smrg pMga->BppShifts[1]++; 1102fe5e51b7Smrg pMga->BppShifts[2]++; 1103fe5e51b7Smrg pMga->BppShifts[3]++; 1104fe5e51b7Smrg } 1105fe5e51b7Smrg 1106fe5e51b7Smrg pMga->Roundings[0] = 128 >> pMga->BppShifts[0]; 1107fe5e51b7Smrg pMga->Roundings[1] = 128 >> pMga->BppShifts[1]; 1108fe5e51b7Smrg pMga->Roundings[2] = 128 >> pMga->BppShifts[2]; 1109fe5e51b7Smrg pMga->Roundings[3] = 128 >> pMga->BppShifts[3]; 1110fe5e51b7Smrg 1111fe5e51b7Smrg /* Set Fast bitblt flag */ 1112fe5e51b7Smrg pMga->HasFBitBlt = pMga->bios.fast_bitblt; 1113fe5e51b7Smrg} 1114fe5e51b7Smrg 1115fe5e51b7Smrgvoid MGA3026LoadPalette( 1116fe5e51b7Smrg ScrnInfoPtr pScrn, 1117fe5e51b7Smrg int numColors, 1118fe5e51b7Smrg int *indices, 1119fe5e51b7Smrg LOCO *colors, 1120fe5e51b7Smrg VisualPtr pVisual 1121fe5e51b7Smrg){ 1122fe5e51b7Smrg MGAPtr pMga = MGAPTR(pScrn); 1123fe5e51b7Smrg int i, index; 1124fe5e51b7Smrg 1125fe5e51b7Smrg if (pVisual->nplanes == 16) { 1126fe5e51b7Smrg for(i = 0; i < numColors; i++) { 1127fe5e51b7Smrg index = indices[i]; 1128fe5e51b7Smrg outTi3026dreg(MGA1064_WADR_PAL, index << 2); 1129fe5e51b7Smrg outTi3026dreg(MGA1064_COL_PAL, colors[index >> 1].red); 1130fe5e51b7Smrg outTi3026dreg(MGA1064_COL_PAL, colors[index].green); 1131fe5e51b7Smrg outTi3026dreg(MGA1064_COL_PAL, colors[index >> 1].blue); 1132fe5e51b7Smrg 1133fe5e51b7Smrg /* we have to write 2 indices since the pixel X on the 1134fe5e51b7Smrg TVP3026 has green colors at different locations from 1135fe5e51b7Smrg the red and blue colors */ 1136fe5e51b7Smrg if(index <= 31) { 1137fe5e51b7Smrg outTi3026dreg(MGA1064_WADR_PAL, index << 3); 1138fe5e51b7Smrg outTi3026dreg(MGA1064_COL_PAL, colors[index].red); 1139fe5e51b7Smrg outTi3026dreg(MGA1064_COL_PAL, colors[(index << 1) + 1].green); 1140fe5e51b7Smrg outTi3026dreg(MGA1064_COL_PAL, colors[index].blue); 1141fe5e51b7Smrg } 1142fe5e51b7Smrg } 1143fe5e51b7Smrg } else { 1144fe5e51b7Smrg int shift = (pVisual->nplanes == 15) ? 3 : 0; 1145fe5e51b7Smrg 1146fe5e51b7Smrg for(i = 0; i < numColors; i++) { 1147fe5e51b7Smrg index = indices[i]; 1148fe5e51b7Smrg outTi3026dreg(MGA1064_WADR_PAL, index << shift); 1149fe5e51b7Smrg outTi3026dreg(MGA1064_COL_PAL, colors[index].red); 1150fe5e51b7Smrg outTi3026dreg(MGA1064_COL_PAL, colors[index].green); 1151fe5e51b7Smrg outTi3026dreg(MGA1064_COL_PAL, colors[index].blue); 1152fe5e51b7Smrg } 1153fe5e51b7Smrg } 1154fe5e51b7Smrg} 1155fe5e51b7Smrg 1156fe5e51b7Smrg 1157fe5e51b7Smrgstatic void 1158fe5e51b7SmrgMGA3026SavePalette(ScrnInfoPtr pScrn, unsigned char* pntr) 1159fe5e51b7Smrg{ 1160fe5e51b7Smrg MGAPtr pMga = MGAPTR(pScrn); 1161fe5e51b7Smrg int i = 768; 1162fe5e51b7Smrg 1163fe5e51b7Smrg outTi3026dreg(TVP3026_RADR_PAL, 0x00); 1164fe5e51b7Smrg while(i--) 1165fe5e51b7Smrg *(pntr++) = inTi3026dreg(TVP3026_COL_PAL); 1166fe5e51b7Smrg} 1167fe5e51b7Smrg 1168fe5e51b7Smrgstatic void 1169fe5e51b7SmrgMGA3026RestorePalette(ScrnInfoPtr pScrn, unsigned char* pntr) 1170fe5e51b7Smrg{ 1171fe5e51b7Smrg MGAPtr pMga = MGAPTR(pScrn); 1172fe5e51b7Smrg int i = 768; 1173fe5e51b7Smrg 1174fe5e51b7Smrg outTi3026dreg(TVP3026_WADR_PAL, 0x00); 1175fe5e51b7Smrg while(i--) 1176fe5e51b7Smrg outTi3026dreg(TVP3026_COL_PAL, *(pntr++)); 1177fe5e51b7Smrg} 1178fe5e51b7Smrg 1179fe5e51b7Smrg 1180fe5e51b7Smrgvoid MGA2064SetupFuncs(ScrnInfoPtr pScrn) 1181fe5e51b7Smrg{ 1182fe5e51b7Smrg MGAPtr pMga = MGAPTR(pScrn); 1183fe5e51b7Smrg 1184fe5e51b7Smrg pMga->PreInit = MGA3026RamdacInit; 1185fe5e51b7Smrg pMga->Save = MGA3026Save; 1186fe5e51b7Smrg pMga->Restore = MGA3026Restore; 1187fe5e51b7Smrg pMga->ModeInit = MGA3026Init; 1188fe5e51b7Smrg pMga->ddc1Read = MGA3026_ddc1Read; 1189fe5e51b7Smrg /* vgaHWddc1SetSpeed will only work if the card is in VGA mode */ 1190fe5e51b7Smrg pMga->DDC1SetSpeed = vgaHWddc1SetSpeedWeak(); 1191fe5e51b7Smrg pMga->i2cInit = MGA3026_i2cInit; 1192fe5e51b7Smrg} 1193