1d87a3195Smrg/* 2d87a3195Smrg * Copyright 1992-2003 by Alan Hourihane, North Wales, UK. 3d87a3195Smrg * 4d87a3195Smrg * Permission to use, copy, modify, distribute, and sell this software 5d87a3195Smrg * and its documentation for any purpose is hereby granted without 6d87a3195Smrg * fee, provided that the above copyright notice appear in all copies 7d87a3195Smrg * and that both that copyright notice and this permission notice 8d87a3195Smrg * appear in supporting documentation, and that the name of Alan 9d87a3195Smrg * Hourihane not be used in advertising or publicity pertaining to 10d87a3195Smrg * distribution of the software without specific, written prior 11d87a3195Smrg * permission. Alan Hourihane makes no representations about the 12d87a3195Smrg * suitability of this software for any purpose. It is provided 13d87a3195Smrg * "as is" without express or implied warranty. 14d87a3195Smrg * 15d87a3195Smrg * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 16d87a3195Smrg * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 17d87a3195Smrg * FITNESS, IN NO EVENT SHALL ALAN HOURIHANE BE LIABLE FOR ANY 18d87a3195Smrg * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19d87a3195Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 20d87a3195Smrg * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 21d87a3195Smrg * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 22d87a3195Smrg * SOFTWARE. 23d87a3195Smrg * 24d87a3195Smrg * Author: Alan Hourihane, alanh@fairlite.demon.co.uk 25d87a3195Smrg */ 26d87a3195Smrg 27d87a3195Smrg#ifdef HAVE_CONFIG_H 28d87a3195Smrg#include "config.h" 29d87a3195Smrg#endif 30d87a3195Smrg 31d87a3195Smrg#include "xf86.h" 32d87a3195Smrg#include "xf86_OSproc.h" 33d87a3195Smrg#include "xf86Pci.h" 34d87a3195Smrg 35d87a3195Smrg#include "vgaHW.h" 36d87a3195Smrg 37d87a3195Smrg#include "trident.h" 38d87a3195Smrg#include "trident_regs.h" 39d87a3195Smrg 40d87a3195Smrg 41d87a3195Smrgstatic void 42d87a3195SmrgIsClearTV(ScrnInfoPtr pScrn) 43d87a3195Smrg{ 44d87a3195Smrg int vgaIOBase = VGAHWPTR(pScrn)->IOBase; 45d87a3195Smrg TRIDENTPtr pTrident = TRIDENTPTR(pScrn); 46d87a3195Smrg CARD8 temp; 47d87a3195Smrg 48d87a3195Smrg if (pTrident->frequency != 0) return; 49d87a3195Smrg 50d87a3195Smrg OUTB(vgaIOBase + 4, 0xC0); 51d87a3195Smrg temp = INB(vgaIOBase + 5); 52d87a3195Smrg if (temp & 0x80) 53d87a3195Smrg pTrident->frequency = PAL; 54d87a3195Smrg else 55d87a3195Smrg pTrident->frequency = NTSC; 56d87a3195Smrg} 57d87a3195Smrg 58d87a3195Smrgvoid 59d87a3195SmrgTGUISetClock(ScrnInfoPtr pScrn, int clock, CARD8 *a, CARD8 *b) 60d87a3195Smrg{ 61d87a3195Smrg TRIDENTPtr pTrident = TRIDENTPTR(pScrn); 62d87a3195Smrg int powerup[4] = { 1, 2, 4, 8 }; 63d87a3195Smrg int clock_diff = 750; 64d87a3195Smrg int freq, ffreq; 65d87a3195Smrg int m, n, k; 66d87a3195Smrg int p, q, r, s; 67d87a3195Smrg int endn, endm, endk, startk; 68d87a3195Smrg 69d87a3195Smrg p = q = r = s = 0; 70d87a3195Smrg 71d87a3195Smrg IsClearTV(pScrn); 72d87a3195Smrg 73d87a3195Smrg if (pTrident->NewClockCode) { 74d87a3195Smrg endn = 255; 75d87a3195Smrg endm = 63; 76d87a3195Smrg endk = 2; 77d87a3195Smrg if (clock >= 100000) startk = 0; else 78d87a3195Smrg if (clock >= 50000) startk = 1; else 79d87a3195Smrg startk = 2; 80d87a3195Smrg } else { 81d87a3195Smrg endn = 121; 82d87a3195Smrg endm = 31; 83d87a3195Smrg endk = 1; 84d87a3195Smrg if (clock > 50000) startk = 1; else 85d87a3195Smrg startk = 0; 86d87a3195Smrg } 87d87a3195Smrg 88d87a3195Smrg freq = clock; 89d87a3195Smrg 90d87a3195Smrg for (k = startk; k <= endk; k++) { 91d87a3195Smrg for (n = 0; n <= endn; n++) { 92d87a3195Smrg for (m = 1; m <= endm; m++) { 93d87a3195Smrg ffreq = ((((n + 8) * pTrident->frequency) / 94d87a3195Smrg ((m + 2) * powerup[k])) * 1000); 95d87a3195Smrg if ((ffreq > freq - clock_diff) && 96d87a3195Smrg (ffreq < freq + clock_diff)) { 97d87a3195Smrg /* 98d87a3195Smrg * It seems that the 9440 docs have this STRICT 99d87a3195Smrg * limitation, although most 9440 boards seem to 100d87a3195Smrg * cope. 96xx/Cyber chips don't need this limit 101d87a3195Smrg * so, I'm gonna remove it and it allows lower 102d87a3195Smrg * clocks < 25.175 too! 103d87a3195Smrg */ 104d87a3195Smrg#ifdef STRICT 105d87a3195Smrg if ((n + 8) * 100 / (m + 2) < 978 && 106d87a3195Smrg (n + 8) * 100 / (m + 2) > 349) { 107d87a3195Smrg#endif 108d87a3195Smrg clock_diff = (freq > ffreq) ? 109d87a3195Smrg freq - ffreq : ffreq - freq; 110d87a3195Smrg p = n; q = m; r = k; s = ffreq; 111d87a3195Smrg#ifdef STRICT 112d87a3195Smrg } 113d87a3195Smrg#endif 114d87a3195Smrg } 115d87a3195Smrg } 116d87a3195Smrg } 117d87a3195Smrg } 118d87a3195Smrg 119d87a3195Smrg if (s == 0) { 120d87a3195Smrg FatalError("Unable to set programmable clock.\n" 121d87a3195Smrg "Frequency %d is not a valid clock.\n" 122d87a3195Smrg "Please modify XF86Config for a new clock.\n", 123d87a3195Smrg freq); 124d87a3195Smrg } 125d87a3195Smrg 126d87a3195Smrg if (pTrident->NewClockCode) { 127d87a3195Smrg /* N is all 8bits */ 128d87a3195Smrg *a = p; 129d87a3195Smrg /* M is first 6bits, with K last 2bits */ 130d87a3195Smrg *b = (q & 0x3F) | (r << 6); 131d87a3195Smrg } else { 132d87a3195Smrg /* N is first 7bits, first M bit is 8th bit */ 133d87a3195Smrg *a = ((1 & q) << 7) | p; 134d87a3195Smrg /* first 4bits are rest of M, 1bit for K value */ 135d87a3195Smrg *b = (((q & 0xFE) >> 1) | (r << 4)); 136d87a3195Smrg } 137d87a3195Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, 138d87a3195Smrg "Found Clock %6.2f n=%i m=%i k=%i\n", 139d87a3195Smrg clock/1000., p, q, r); 140d87a3195Smrg} 141d87a3195Smrg 142d87a3195Smrgvoid 143d87a3195SmrgTridentFindClock(ScrnInfoPtr pScrn, int clock) 144d87a3195Smrg{ 145d87a3195Smrg TRIDENTPtr pTrident = TRIDENTPTR(pScrn); 146d87a3195Smrg 147d87a3195Smrg pTrident->MUX = FALSE; 148d87a3195Smrg#ifdef READOUT 149d87a3195Smrg pTrident->DontSetClock = FALSE; 150d87a3195Smrg#endif 151d87a3195Smrg pTrident->currentClock = clock; 152d87a3195Smrg 153d87a3195Smrg if (pTrident->IsCyber) { 154d87a3195Smrg Bool LCDActive; 155d87a3195Smrg#ifdef READOUT 156d87a3195Smrg Bool ShadowModeActive; 157d87a3195Smrg Bool HStretch; 158d87a3195Smrg Bool VStretch; 159d87a3195Smrg#endif 160d87a3195Smrg OUTB(0x3CE, FPConfig); 161d87a3195Smrg LCDActive = (INB(0x3CF) & 0x10); 162d87a3195Smrg#ifdef READOUT 163d87a3195Smrg OUTB(0x3CE, HorStretch); 164d87a3195Smrg HStretch = (INB(0x3CF) & 0x01); 165d87a3195Smrg OUTB(0x3CE, VertStretch); 166d87a3195Smrg VStretch = (INB(0x3CF) & 0x01); 167d87a3195Smrg 168d87a3195Smrg if (!(VStretch || HStretch) && LCDActive) { 169d87a3195Smrg CARD8 temp; 170d87a3195Smrg temp = INB(0x3C8); 171d87a3195Smrg temp = INB(0x3C6); 172d87a3195Smrg temp = INB(0x3C6); 173d87a3195Smrg temp = INB(0x3C6); 174d87a3195Smrg temp = INB(0x3C6); 175d87a3195Smrg pTrident->MUX = ((INB(0x3C6) & 0x20) == 0x20); 176d87a3195Smrg temp = INB(0x3C8); 177d87a3195Smrg pTrident->DontSetClock = TRUE; 178d87a3195Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 179d87a3195Smrg "Keeping Clock for LCD Mode\n"); 180d87a3195Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 181d87a3195Smrg "MUX is %s\n", 182d87a3195Smrg pTrident->MUX ? "on" : "off"); 183d87a3195Smrg return; 184d87a3195Smrg } else 185d87a3195Smrg#endif 186d87a3195Smrg { 187d87a3195Smrg if (pTrident->lcdMode != 0xff && LCDActive) 188d87a3195Smrg pTrident->currentClock = clock = 189d87a3195Smrg LCD[pTrident->lcdMode].clock; 190d87a3195Smrg } 191d87a3195Smrg 192d87a3195Smrg } 193d87a3195Smrg#ifndef READOUT 194d87a3195Smrg if (pTrident->Chipset != BLADEXP && 195d87a3195Smrg clock > pTrident->MUXThreshold) 196d87a3195Smrg pTrident->MUX = TRUE; 197d87a3195Smrg else 198d87a3195Smrg pTrident->MUX = FALSE; 199d87a3195Smrg#endif 200d87a3195Smrg} 201d87a3195Smrg 202d87a3195Smrgfloat 203d87a3195SmrgCalculateMCLK(ScrnInfoPtr pScrn) 204d87a3195Smrg{ 205d87a3195Smrg int vgaIOBase = VGAHWPTR(pScrn)->IOBase; 206d87a3195Smrg TRIDENTPtr pTrident = TRIDENTPTR(pScrn); 207d87a3195Smrg int a, b; 208d87a3195Smrg int m, n, k; 209d87a3195Smrg float freq = 0.0; 210d87a3195Smrg int powerup[4] = { 1, 2, 4, 8 }; 211d87a3195Smrg CARD8 temp; 212d87a3195Smrg 213d87a3195Smrg if (pTrident->HasSGRAM) { 214d87a3195Smrg OUTB(vgaIOBase + 4, 0x28); 215d87a3195Smrg switch(INB(vgaIOBase + 5) & 0x07) { 216d87a3195Smrg case 0: 217d87a3195Smrg freq = 60; 218d87a3195Smrg break; 219d87a3195Smrg case 1: 220d87a3195Smrg freq = 78; 221d87a3195Smrg break; 222d87a3195Smrg case 2: 223d87a3195Smrg freq = 90; 224d87a3195Smrg break; 225d87a3195Smrg case 3: 226d87a3195Smrg freq = 120; 227d87a3195Smrg break; 228d87a3195Smrg case 4: 229d87a3195Smrg freq = 66; 230d87a3195Smrg break; 231d87a3195Smrg case 5: 232d87a3195Smrg freq = 83; 233d87a3195Smrg break; 234d87a3195Smrg case 6: 235d87a3195Smrg freq = 100; 236d87a3195Smrg break; 237d87a3195Smrg case 7: 238d87a3195Smrg freq = 132; 239d87a3195Smrg break; 240d87a3195Smrg } 241d87a3195Smrg } else { 242d87a3195Smrg OUTB(0x3C4, NewMode1); 243d87a3195Smrg temp = INB(0x3C5); 244d87a3195Smrg 245d87a3195Smrg OUTB(0x3C5, 0xC2); 246d87a3195Smrg if (!Is3Dchip) { 247d87a3195Smrg a = INB(0x43C6); 248d87a3195Smrg b = INB(0x43C7); 249d87a3195Smrg } else { 250d87a3195Smrg OUTB(0x3C4, 0x16); 251d87a3195Smrg a = INB(0x3C5); 252d87a3195Smrg OUTB(0x3C4, 0x17); 253d87a3195Smrg b = INB(0x3C5); 254d87a3195Smrg } 255d87a3195Smrg 256d87a3195Smrg OUTB(0x3C4, NewMode1); 257d87a3195Smrg OUTB(0x3C5, temp); 258d87a3195Smrg 259d87a3195Smrg IsClearTV(pScrn); 260d87a3195Smrg 261d87a3195Smrg if (pTrident->NewClockCode) { 262d87a3195Smrg m = b & 0x3F; 263d87a3195Smrg n = a; 264d87a3195Smrg k = (b & 0xC0) >> 6; 265d87a3195Smrg } else { 266d87a3195Smrg m = (a & 0x07); 267d87a3195Smrg k = (b & 0x02) >> 1; 268d87a3195Smrg n = ((a & 0xF8) >> 3) | ((b&0x01) << 5); 269d87a3195Smrg } 270d87a3195Smrg 271d87a3195Smrg freq = ((n + 8) * pTrident->frequency) / 272d87a3195Smrg ((m + 2) * powerup[k]); 273d87a3195Smrg } 274d87a3195Smrg 275d87a3195Smrg return (freq); 276d87a3195Smrg} 277d87a3195Smrg 278d87a3195Smrgvoid 279d87a3195SmrgTGUISetMCLK(ScrnInfoPtr pScrn, int clock, CARD8 *a, CARD8 *b) 280d87a3195Smrg{ 281d87a3195Smrg TRIDENTPtr pTrident = TRIDENTPTR(pScrn); 282d87a3195Smrg int powerup[4] = { 1,2,4,8 }; 283d87a3195Smrg int clock_diff = 750; 284d87a3195Smrg int freq, ffreq; 285d87a3195Smrg int m,n,k; 286d87a3195Smrg int p, q, r, s; 287d87a3195Smrg int startn, endn; 288d87a3195Smrg int endm, endk; 289d87a3195Smrg 290d87a3195Smrg p = q = r = s = 0; 291d87a3195Smrg 292d87a3195Smrg IsClearTV(pScrn); 293d87a3195Smrg 294d87a3195Smrg if (pTrident->NewClockCode) { 295d87a3195Smrg startn = 64; 296d87a3195Smrg endn = 255; 297d87a3195Smrg endm = 63; 298d87a3195Smrg endk = 3; 299d87a3195Smrg } else { 300d87a3195Smrg startn = 0; 301d87a3195Smrg endn = 121; 302d87a3195Smrg endm = 31; 303d87a3195Smrg endk = 1; 304d87a3195Smrg } 305d87a3195Smrg 306d87a3195Smrg freq = clock; 307d87a3195Smrg 308d87a3195Smrg if (!pTrident->HasSGRAM) { 309d87a3195Smrg for (k = 0; k <= endk; k++) { 310d87a3195Smrg for (n = startn; n <= endn; n++) { 311d87a3195Smrg for (m = 1;m <= endm; m++) { 312d87a3195Smrg ffreq = ((((n + 8) * pTrident->frequency) / 313d87a3195Smrg ((m + 2) * powerup[k])) * 1000); 314d87a3195Smrg if ((ffreq > freq - clock_diff) && 315d87a3195Smrg (ffreq < freq + clock_diff)) { 316d87a3195Smrg clock_diff = (freq > ffreq) ? 317d87a3195Smrg freq - ffreq : ffreq - freq; 318d87a3195Smrg p = n; q = m; r = k; s = ffreq; 319d87a3195Smrg } 320d87a3195Smrg } 321d87a3195Smrg } 322d87a3195Smrg } 323d87a3195Smrg 324d87a3195Smrg if (s == 0) { 325d87a3195Smrg FatalError("Unable to set memory clock.\n" 326d87a3195Smrg "Frequency %d is not a valid clock.\n" 327d87a3195Smrg "Please modify XF86Config for a new clock.\n", 328d87a3195Smrg freq); 329d87a3195Smrg } 330d87a3195Smrg 331d87a3195Smrg if (pTrident->NewClockCode) { 332d87a3195Smrg /* N is all 8bits */ 333d87a3195Smrg *a = p; 334d87a3195Smrg /* M is first 6bits, with K last 2bits */ 335d87a3195Smrg *b = (q & 0x3F) | (r << 6); 336d87a3195Smrg } 337d87a3195Smrg else { 338d87a3195Smrg /* N is first 7bits, first M bit is 8th bit */ 339d87a3195Smrg *a = ((1 & q) << 7) | p; 340d87a3195Smrg /* first 4bits are rest of M, 1bit for K value */ 341d87a3195Smrg *b = (((q & 0xFE) >> 1) | (r << 4)); 342d87a3195Smrg } 343d87a3195Smrg } 344d87a3195Smrg} 345