pm3_dac.c revision c35d236e
1/*
2 * Copyright 2000,2001 by Sven Luther <luther@dpt-info.u-strasbg.fr>.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Sven Luther not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission. Sven Luther makes no representations
11 * about the suitability of this software for any purpose.  It is provided
12 * "as is" without express or implied warranty.
13 *
14 * SVEN LUTHER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL SVEN LUTHER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 *
22 * Authors: Sven Luther, <luther@dpt-info.u-strasbg.fr>
23 *          Thomas Witzel, <twitzel@nmr.mgh.harvard.edu>
24 *          Alan Hourihane, <alanh@fairlite.demon.co.uk>
25 *
26 * this work is sponsored by Appian Graphics.
27 *
28 */
29/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/glint/pm3_dac.c,v 1.33tsi Exp $ */
30
31#ifdef HAVE_CONFIG_H
32#include "config.h"
33#endif
34
35#include "xf86.h"
36#include "xf86_OSproc.h"
37
38#include "xf86PciInfo.h"
39#include "xf86Pci.h"
40#include "xf86int10.h"
41
42#include "glint_regs.h"
43#include "pm3_regs.h"
44#include "glint.h"
45
46#define DEBUG 0
47
48#if DEBUG
49# define TRACE_ENTER(str)       ErrorF("glint: " str " %d\n",pScrn->scrnIndex)
50# define TRACE_EXIT(str)        ErrorF("glint: " str " done\n")
51# define TRACE(str)             ErrorF("glint trace: " str "\n")
52#else
53# define TRACE_ENTER(str)
54# define TRACE_EXIT(str)
55# define TRACE(str)
56#endif
57
58int
59Permedia3MemorySizeDetect(ScrnInfoPtr pScrn)
60{
61    GLINTPtr pGlint = GLINTPTR (pScrn);
62    CARD32 size = 0, temp, temp1, temp2, i;
63
64    /* We can map 64MB, as that's the size of the Permedia3 aperture
65     * regardless of memory configuration */
66    pGlint->FbMapSize = 64*1024*1024;
67
68    /* Mark as VIDMEM_MMIO to avoid write-combining while detecting memory */
69    pGlint->FbBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
70			pGlint->PciTag, pGlint->FbAddress, pGlint->FbMapSize);
71
72    if (pGlint->FbBase == NULL)
73	return 0;
74
75    temp = GLINT_READ_REG(PM3MemBypassWriteMask);
76    GLINT_SLOW_WRITE_REG(0xffffffff, PM3MemBypassWriteMask);
77
78    /* The Permedia3 splits up memory, and even replicates it. Grrr.
79     * So that each 32MB appears at offset 0, and offset 32, unless
80     * there's really 64MB attached to the chip.
81     * So, 16MB appears at offset 0, nothing between 16-32, then it re-appears
82     * at offset 32.
83     * This below is to detect the cases of memory combinations
84     */
85
86    /* Test first 32MB */
87    for(i=0;i<32;i++) {
88    	/* write test pattern */
89	MMIO_OUT32(pGlint->FbBase, i*1024*1024, i*0x00345678);
90	mem_barrier();
91	temp1 = MMIO_IN32(pGlint->FbBase, i*1024*1024);
92    	/* Let's check for wrapover, write will fail at 16MB boundary */
93	if (temp1 == (i*0x00345678))
94	    size = i;
95	else
96	    break;
97    }
98
99    /* Ok, we're satisfied we've got 32MB, let's test the second lot */
100    if ((size + 1) == i) {
101	for(i=0;i<32;i++) {
102	    /* Clear first 32MB */
103	    MMIO_OUT32(pGlint->FbBase, i*1024*1024, 0);
104	    mem_barrier();
105	}
106        for(i=32;i<64;i++) {
107    	    /* write test pattern */
108	    MMIO_OUT32(pGlint->FbBase, i*1024*1024, i*0x00345678);
109	    mem_barrier();
110	    temp1 = MMIO_IN32(pGlint->FbBase, i*1024*1024);
111	    temp2 = MMIO_IN32(pGlint->FbBase, (i-32)*1024*1024);
112    	    /* Let's check for wrapover */
113	    if ( (temp1 == (i*0x00345678)) && (temp2 == 0) )
114	        size = i;
115	    else
116	        break;
117	}
118    }
119
120    GLINT_SLOW_WRITE_REG(temp, PM3MemBypassWriteMask);
121
122    xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pGlint->FbBase,
123							pGlint->FbMapSize);
124
125    pGlint->FbBase = NULL;
126    pGlint->FbMapSize = 0;
127
128    return ( (size+1) * 1024 );
129}
130
131static unsigned long
132PM3DAC_CalculateClock
133(
134 unsigned long ReqClock,		/* In kHz units */
135 unsigned long RefClock,		/* In kHz units */
136 unsigned char *prescale,		/* ClkPreScale */
137 unsigned char *feedback,		/* ClkFeedBackScale */
138 unsigned char *postscale		/* ClkPostScale */
139 )
140{
141  unsigned long fMinVCO = 2000000; /* min fVCO is 200MHz (in 100Hz units) */
142  unsigned long fMaxVCO = 6220000; /* max fVCO is 622MHz (in 100Hz units) */
143  unsigned long fMinINTREF = 10000;/* min fINTREF is 1MHz (in 100Hz units) */
144  unsigned long fMaxINTREF = 20000;/* max fINTREF is 2MHz (in 100Hz units) */
145  unsigned long	M, N, P; /* M=feedback, N=prescale, P=postscale */
146  unsigned long	fINTREF;
147  unsigned long	fVCO;
148  unsigned long	ActualClock;
149  long		Error;
150  unsigned long LowestError = 1000000;
151  unsigned int	bFoundFreq = FALSE;
152  int		cInnerLoopIterations = 0;
153  int		LoopCount;
154  unsigned long	ClosestClock = 0;
155
156  ReqClock*=10; /* convert into 100Hz units */
157  RefClock*=10; /* convert into 100Hz units */
158
159  for(P = 0; P <= 5; ++P)
160    {
161      unsigned long fVCOLowest, fVCOHighest;
162
163      /* it is pointless going through the main loop if all values of
164         N produce an fVCO outside the acceptable range */
165      N = 1;
166      M = (N * (1UL << P) * ReqClock) / (2 * RefClock);
167      fVCOLowest = (2 * RefClock * M) / N;
168      N = 255;
169      M = (N * (1UL << P) * ReqClock) / (2 * RefClock);
170      fVCOHighest = (2 * RefClock * M) / N;
171
172      if(fVCOHighest < fMinVCO || fVCOLowest > fMaxVCO)
173	{
174	  continue;
175	}
176
177      for(N = 1; N <= 255; ++N, ++cInnerLoopIterations)
178	{
179	  fINTREF = RefClock / N;
180	  if(fINTREF < fMinINTREF || fINTREF > fMaxINTREF)
181	    {
182	      if(fINTREF > fMaxINTREF)
183		{
184		  /* hopefully we will get into range as the prescale
185		     value increases */
186		  continue;
187		}
188	      else
189		{
190		  /* already below minimum and it will only get worse:
191		     move to the next postscale value */
192		  break;
193		}
194	    }
195
196	  M = (N * (1UL << P) * ReqClock) / (2 * RefClock);
197	  if(M > 255)
198	    {
199	      /* M, N & P registers are only 8 bits wide */
200	      break;
201	    }
202
203	  /* we can expect rounding errors in calculating M, which
204	     will always be rounded down. So we will checkout our
205	     calculated value of M along with (M+1) */
206	  for(LoopCount = (M == 255) ? 1 : 2; --LoopCount >= 0; ++M)
207	    {
208	      fVCO = (2 * RefClock * M) / N;
209	      if(fVCO >= fMinVCO && fVCO <= fMaxVCO)
210		{
211		  ActualClock = fVCO / (1UL << P);
212		  Error = ActualClock - ReqClock;
213		  if(Error < 0)
214		    Error = -Error;
215		  if(Error < LowestError)
216		    {
217		      bFoundFreq = TRUE;
218		      LowestError = Error;
219		      ClosestClock = ActualClock;
220		      *prescale = N;
221		      *feedback = M;
222		      *postscale = P;
223		      if(Error == 0)
224			goto Done;
225		    }
226		}
227	    }
228	}
229    }
230
231Done:
232
233  if(bFoundFreq)
234    ActualClock = ClosestClock;
235  else
236    ActualClock = 0;
237
238#if 0
239  ErrorF("PM3DAC_CalculateClock: Got prescale=%d, feedback=%d, postscale=%d, WantedClock = %d00 ActualClock = %d00 (Error %d00)\n",
240	 *prescale, *feedback, *postscale, ReqClock, ActualClock, LowestError);
241#endif
242
243    return(ActualClock);
244}
245
246static unsigned long
247PM4DAC_CalculateClock
248(
249 unsigned long req_clock,		/* In kHz units */
250 unsigned long ref_clock,		/* In kHz units */
251 unsigned char *param_m,		/* ClkPreScale */
252 unsigned char *param_n, 		/* ClkFeedBackScale */
253 unsigned char *param_p			/* ClkPostScale */
254 )
255{
256#define INITIALFREQERR 10000
257
258  long fMinVCO = 200000;	/* min fVCO is 200MHz (in 10000Hz units) */
259  long fMaxVCO = 400000;	/* max fVCO is 400MHz (in 10000Hz units) */
260  unsigned long int	M, N, P;
261  unsigned long int	fVCO;
262  unsigned long int	ActualClock;
263  int		Error;
264  int		LowestError = INITIALFREQERR;
265  short		bFoundFreq = FALSE;
266  int		cInnerLoopIterations = 0;
267  int		LoopCount;
268
269  /*
270   * Actual Equations:
271   *		fVCO = (ref_clock * M)/(N+1)
272   *		PIXELCLOCK = fVCO/(1<<p)
273   *		200 <= fVCO <= 400
274   *		24 <= N <= 80
275   *		1 <= M <= 15
276   *		0 <= P <= 3
277   *		1Mhz < ref_clock/(N+1) <= 2Mhz - not used
278   * For refclk == 14.318 we have the tighter equations:
279   *		32 <= N <= 80
280   *		3 <= M <= 12
281   * Notes:
282   *		The spec says that the PLLs will only do 260Mhz, but I have assumed 300Mhz 'cos
283   *		260Mhz is a crap limit.
284   */
285
286#define	P4RD_PLL_MIN_P	0
287#define	P4RD_PLL_MAX_P	3
288#define	P4RD_PLL_MIN_M	1
289#define	P4RD_PLL_MAX_M	12
290#define	P4RD_PLL_MIN_N	24
291#define	P4RD_PLL_MAX_N	80
292
293  for(P = P4RD_PLL_MIN_P; P <= P4RD_PLL_MAX_P; ++P) {
294      unsigned long int fVCOLowest, fVCOHighest;
295
296      /* it's pointless going through the main loop if all values of
297       * N produce an fVCO outside the acceptable range */
298
299      M = P4RD_PLL_MIN_M;
300      N = ((M + 1) * (1 << P) * req_clock) / ref_clock;
301
302      fVCOLowest = (ref_clock * N) / (M + 1);
303
304      M = P4RD_PLL_MAX_M;
305      N = ((M + 1) * (1 << P) * req_clock) / ref_clock;
306
307      fVCOHighest = (ref_clock * N) / (M + 1);
308
309      if(fVCOHighest < fMinVCO || fVCOLowest > fMaxVCO)
310	  continue;
311
312      for(M = P4RD_PLL_MIN_M; M <= P4RD_PLL_MAX_M; ++M, ++cInnerLoopIterations)
313	{
314	  N = ((M + 1) * (1 << P) * req_clock) / ref_clock;
315
316	  if(N > P4RD_PLL_MAX_N || N < P4RD_PLL_MIN_N)
317	      continue;
318
319	  /*  we can expect rounding errors in calculating M, which will always be rounded down. */
320	  /*  So we'll checkout our calculated value of M along with (M+1) */
321
322	  for(LoopCount = (N == P4RD_PLL_MAX_N) ? 1 : 2; --LoopCount >= 0; ++N)
323	    {
324	      fVCO = (ref_clock * N) / (M + 1);
325
326	      if( (fVCO >= fMinVCO) && (fVCO <= fMaxVCO) )
327		{
328		  ActualClock = (fVCO / (1 << P));
329
330		  Error = ActualClock - req_clock;
331
332		  if(Error < 0)
333		      Error = -Error;
334
335		  /*  It is desirable that we use the lowest value of M if the*/
336		  /*  frequencies are the same.*/
337		  if(Error < LowestError || (Error == LowestError && M < *param_m))
338		    {
339		      bFoundFreq = TRUE;
340		      LowestError = Error;
341		      *param_m = M;
342		      *param_n = N;
343		      *param_p = P;
344		      if(Error == 0)
345			goto Done;
346		    }
347		}
348	    }
349	}
350    }
351
352Done:
353  if(bFoundFreq)
354    ActualClock = (ref_clock * (*param_n)) / (((*param_m) + 1) * (1 << (*param_p)));
355  else
356    ActualClock = 0;
357
358  return(ActualClock);
359}
360
361void
362Permedia3PreInit(ScrnInfoPtr pScrn)
363{
364    GLINTPtr pGlint = GLINTPTR(pScrn);
365    CARD32 LocalMemCaps;
366
367    TRACE_ENTER("Permedia3PreInit");
368
369    if (IS_J2000) {
370    	unsigned char m,n,p;
371
372	if (pGlint->Chipset == PCI_VENDOR_3DLABS_CHIP_GAMMA)
373	    GLINT_SLOW_WRITE_REG(GCSRSecondaryGLINTMapEn, GCSRAperture);
374
375	/* Memory timings for the Appian J2000 board.
376	 * This is needed for the second head which is left un-initialized
377	 * by the bios, thus freezing the machine. */
378	GLINT_SLOW_WRITE_REG(0x02e311B8, PM3LocalMemCaps);
379	GLINT_SLOW_WRITE_REG(0x07424905, PM3LocalMemTimings);
380	GLINT_SLOW_WRITE_REG(0x0c000003, PM3LocalMemControl);
381	GLINT_SLOW_WRITE_REG(0x00000061, PM3LocalMemRefresh);
382	GLINT_SLOW_WRITE_REG(0x00000000, PM3LocalMemPowerDown);
383
384	/* Let's program the K, M and S Clocks to the same values as the bios
385	 * does for first head :
386	 *   - KClk and MClk are 105Mhz.
387	 *   - S Clock is set to PClk.
388	 * Note 1 : pGlint->RefClock is not set yet, so use 14318 instead.
389	 * Note 2 : KClk gets internally halved, so we need to double it.
390	 */
391	(void) PM3DAC_CalculateClock(2*105000, 14318, &m,&n,&p);
392        Permedia2vOutIndReg(pScrn, PM3RD_KClkPreScale, 0x00, m);
393        Permedia2vOutIndReg(pScrn, PM3RD_KClkFeedbackScale, 0x00, n);
394        Permedia2vOutIndReg(pScrn, PM3RD_KClkPostScale, 0x00, p);
395        Permedia2vOutIndReg(pScrn, PM3RD_KClkControl, 0x00,
396	    PM3RD_KClkControl_STATE_RUN |
397	    PM3RD_KClkControl_SOURCE_PLL |
398	    PM3RD_KClkControl_ENABLE);
399        Permedia2vOutIndReg(pScrn, PM3RD_MClkControl, 0x00,
400	    PM3RD_MClkControl_STATE_RUN |
401	    PM3RD_MClkControl_SOURCE_KCLK |
402	    PM3RD_MClkControl_ENABLE);
403        Permedia2vOutIndReg(pScrn, PM3RD_SClkControl, 0x00,
404	    PM3RD_SClkControl_STATE_RUN |
405	    PM3RD_SClkControl_SOURCE_PCLK |
406	    PM3RD_SClkControl_ENABLE);
407    }
408
409#if defined(__alpha__)
410    /*
411     * On Alpha, we have to "int10" secondary VX1 cards early;
412     * otherwise, some information taken from registers, like
413     * memory size, is incorrect.
414     */
415    if (!xf86IsPrimaryPci(pGlint->PciInfo)) {
416        if ( IS_QVX1 ) {
417
418	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
419		       "VX1 secondary enabling VGA before int10\n");
420
421	    /* Enable VGA on the current card. */
422	    pciWriteByte( pGlint->PciTag, 0xf8, 0 );
423	    pciWriteByte( pGlint->PciTag, 0xf4, 0 );
424	    pciWriteByte( pGlint->PciTag, 0xfc, 0 );
425
426	    /* The card we are on should be VGA-enabled now, so run int10. */
427	    if (xf86LoadSubModule(pScrn, "int10")) {
428	        xf86Int10InfoPtr pInt;
429
430	        xf86LoaderReqSymLists(GLINTint10Symbols, NULL);
431		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Initializing int10\n");
432		pInt = xf86InitInt10(pGlint->pEnt->index);
433		xf86FreeInt10(pInt);
434	    }
435
436	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
437		       "VX1 secondary disabling VGA after int10\n");
438
439	    /* Finally, disable VGA on the current card. */
440	    pciWriteByte( pGlint->PciTag, 0xf8, 0x70 );
441	    pciWriteByte( pGlint->PciTag, 0xf4, 0x01 );
442	    pciWriteByte( pGlint->PciTag, 0xfc, 0x00 );
443	}
444    }
445#endif /* __alpha__ */
446
447    /* If we have SDRAM instead of SGRAM, we have to do some things
448       differently in the FillRectSolid code. */
449    LocalMemCaps = GLINT_READ_REG(PM3LocalMemCaps);
450    pGlint->PM3_UsingSGRAM = !(LocalMemCaps & PM3LocalMemCaps_NoWriteMask);
451    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using %s memory\n",
452	       pGlint->PM3_UsingSGRAM ? "SGRAM" : "SDRAM");
453
454    TRACE_EXIT("Permedia3PreInit");
455}
456
457Bool
458Permedia3Init(ScrnInfoPtr pScrn, DisplayModePtr mode, GLINTRegPtr pReg)
459{
460    GLINTPtr pGlint = GLINTPTR(pScrn);
461    CARD32 temp1, temp2, temp3, temp4;
462
463    if ((pGlint->numMultiDevices == 2) || (IS_J2000)) {
464	STOREREG(GCSRAperture, GCSRSecondaryGLINTMapEn);
465    }
466
467    if (pGlint->MultiAperture) {
468	STOREREG(GMultGLINTAperture, pGlint->realWidth);
469	STOREREG(GMultGLINT1,
470			pGlint->MultiPciInfo[0]->memBase[2] & 0xFF800000);
471	STOREREG(GMultGLINT2,
472			pGlint->MultiPciInfo[1]->memBase[2] & 0xFF800000);
473    }
474
475    STOREREG(PM3MemBypassWriteMask, 	0xffffffff);
476    STOREREG(Aperture0,		 	0x00000000);
477    STOREREG(Aperture1,		 	0x00000000);
478
479    if (pGlint->Chipset == PCI_VENDOR_3DLABS_CHIP_GAMMA)
480    	STOREREG(DFIFODis,			0x00000001);
481
482    STOREREG(FIFODis,			0x00000007);
483
484    temp1 = mode->CrtcHSyncStart - mode->CrtcHDisplay;
485    temp2 = mode->CrtcVSyncStart - mode->CrtcVDisplay;
486    temp3 = mode->CrtcHSyncEnd - mode->CrtcHSyncStart;
487    temp4 = mode->CrtcVSyncEnd - mode->CrtcVSyncStart;
488
489    STOREREG(PMHTotal,	Shiftbpp(pScrn, mode->CrtcHTotal - 1));
490    STOREREG(PMHsEnd,	Shiftbpp(pScrn, temp1 + temp3));
491    STOREREG(PMHsStart,	Shiftbpp(pScrn, temp1));
492    STOREREG(PMHbEnd,	Shiftbpp(pScrn, mode->CrtcHTotal - mode->CrtcHDisplay));
493    STOREREG(PMHgEnd,	Shiftbpp(pScrn, mode->CrtcHTotal - mode->CrtcHDisplay));
494    STOREREG(PMScreenStride, Shiftbpp(pScrn, pScrn->displayWidth));
495
496    STOREREG(PMVTotal,	mode->CrtcVTotal - 1);
497    STOREREG(PMVsEnd,	temp2 + temp4 - 1);
498    STOREREG(PMVsStart,	temp2 - 1);
499    STOREREG(PMVbEnd,	mode->CrtcVTotal - mode->CrtcVDisplay);
500
501    switch (pScrn->bitsPerPixel)
502    {
503	case 8:
504	    STOREREG(PM3ByAperture1Mode, PM3ByApertureMode_PIXELSIZE_8BIT);
505	    STOREREG(PM3ByAperture2Mode, PM3ByApertureMode_PIXELSIZE_8BIT);
506	    STOREREG(PMVideoControl,	 1 | (1 << 3) | (1 << 5) | (0 << 19));
507	    break;
508	case 16:
509#if X_BYTE_ORDER != X_BIG_ENDIAN
510	    STOREREG(PM3ByAperture1Mode, PM3ByApertureMode_PIXELSIZE_16BIT);
511	    STOREREG(PM3ByAperture2Mode, PM3ByApertureMode_PIXELSIZE_16BIT);
512#else
513	    STOREREG(PM3ByAperture1Mode, PM3ByApertureMode_PIXELSIZE_16BIT |
514					 PM3ByApertureMode_BYTESWAP_BADC);
515	    STOREREG(PM3ByAperture2Mode, PM3ByApertureMode_PIXELSIZE_16BIT |
516					 PM3ByApertureMode_BYTESWAP_BADC);
517#endif
518	    STOREREG(PMVideoControl,	 1 | (1 << 3) | (1 << 5) | (1 << 19));
519	    break;
520	case 32:
521#if X_BYTE_ORDER != X_BIG_ENDIAN
522	    STOREREG(PM3ByAperture1Mode, PM3ByApertureMode_PIXELSIZE_32BIT);
523	    STOREREG(PM3ByAperture2Mode, PM3ByApertureMode_PIXELSIZE_32BIT);
524#else
525	    STOREREG(PM3ByAperture1Mode, PM3ByApertureMode_PIXELSIZE_32BIT |
526					 PM3ByApertureMode_BYTESWAP_DCBA);
527	    STOREREG(PM3ByAperture2Mode, PM3ByApertureMode_PIXELSIZE_32BIT |
528					 PM3ByApertureMode_BYTESWAP_DCBA);
529#endif
530	    STOREREG(PMVideoControl,	 1 | (1 << 3) | (1 << 5) | (2 << 19));
531	    break;
532    }
533
534    STOREREG(VClkCtl, GLINT_READ_REG(VClkCtl) & 0xFFFFFFFC);
535    STOREREG(PMScreenBase, 0x00000000);
536    STOREREG(ChipConfig, GLINT_READ_REG(ChipConfig) & 0xFFFFFFFD);
537
538    {
539	/* Get the programmable clock values */
540    	unsigned char m,n,p;
541
542	/* Let's program the dot clock */
543	switch (pGlint->Chipset) {
544	case PCI_VENDOR_3DLABS_CHIP_PERMEDIA4:
545	case PCI_VENDOR_3DLABS_CHIP_R4:
546	  (void) PM4DAC_CalculateClock(mode->Clock, pGlint->RefClock, &m,&n,&p);
547	  break;
548	case PCI_VENDOR_3DLABS_CHIP_PERMEDIA3:
549	  (void) PM3DAC_CalculateClock(mode->Clock, pGlint->RefClock, &m,&n,&p);
550	  break;
551	case PCI_VENDOR_3DLABS_CHIP_GAMMA:
552	  switch (pGlint->MultiChip) {
553	    case PCI_CHIP_PERMEDIA3:
554		(void) PM3DAC_CalculateClock(mode->Clock,
555					    pGlint->RefClock, &m,&n,&p);
556		break;
557	    case PCI_CHIP_R4:
558		(void) PM4DAC_CalculateClock(mode->Clock,
559					    pGlint->RefClock, &m,&n,&p);
560		break;
561	  }
562	  break;
563	}
564	STOREDAC(PM3RD_DClk0PreScale, m);
565	STOREDAC(PM3RD_DClk0FeedbackScale, n);
566	STOREDAC(PM3RD_DClk0PostScale, p);
567    }
568
569    temp1 = 0;
570    temp2 = 0;
571    temp3 = 0;
572
573    if (pGlint->UseFlatPanel) {
574    	temp2 |= PM3RD_DACControl_BLANK_PEDESTAL_ENABLE;
575    	temp3 |= PM3RD_MiscControl_VSB_OUTPUT_ENABLE;
576    	STOREREG(VSConfiguration, 0x06);
577    	STOREREG(VSBBase, 1<<14);
578    }
579
580    if (mode->Flags & V_PHSYNC) temp1 |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH;
581    if (mode->Flags & V_PVSYNC) temp1 |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH;
582
583    STOREREG(PM2VDACRDIndexControl, 0x00);
584    STOREDAC(PM2VDACRDSyncControl, temp1);
585    STOREDAC(PM2VDACRDDACControl, temp2);
586
587    if (pScrn->rgbBits == 8)
588	temp3 |= 0x01; /* 8bit DAC */
589
590    switch (pScrn->bitsPerPixel)
591    {
592    case 8:
593	STOREDAC(PM2VDACRDPixelSize, 0x00);
594	STOREDAC(PM2VDACRDColorFormat, 0x2E);
595    	break;
596    case 16:
597    	temp3 |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE;
598	STOREDAC(PM2VDACRDPixelSize, 0x01);
599	if (pScrn->depth == 15) {
600	    STOREDAC(PM2VDACRDColorFormat, 0x61);
601	} else {
602	    STOREDAC(PM2VDACRDColorFormat, 0x70);
603	}
604    	break;
605    case 24:
606    	temp3 |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE;
607	STOREDAC(PM2VDACRDPixelSize, 0x04);
608	STOREDAC(PM2VDACRDColorFormat, 0x20);
609    	break;
610    case 32:
611    	temp3 |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE;
612	if (pScrn->overlayFlags & OVERLAY_8_32_PLANAR) {
613	    temp3 |= 0x18;
614	    STOREDAC(PM2VDACRDOverlayKey, pScrn->colorKey);
615	}
616	STOREDAC(PM2VDACRDPixelSize, 0x02);
617	STOREDAC(PM2VDACRDColorFormat, 0x20);
618    	break;
619    }
620    STOREDAC(PM2VDACRDMiscControl, temp3);
621
622    STOREREG(PM3FifoControl, 0x905); /* Lower the default fifo threshold */
623
624    return(TRUE);
625}
626
627void
628Permedia3Save(ScrnInfoPtr pScrn, GLINTRegPtr pReg)
629{
630    GLINTPtr pGlint = GLINTPTR(pScrn);
631    int i;
632
633    /* We can't rely on the vgahw layer copying the font information
634     * back properly, due to problems with MMIO access to VGA space
635     * so we memcpy the information using the slow routines */
636    xf86SlowBcopy((CARD8*)pGlint->FbBase, (CARD8*)pGlint->VGAdata, 65536);
637
638    if ((pGlint->numMultiDevices == 2) || (IS_J2000)) {
639	SAVEREG(GCSRAperture);
640    }
641
642    if (pGlint->MultiAperture) {
643	SAVEREG(GMultGLINTAperture);
644	SAVEREG(GMultGLINT1);
645	SAVEREG(GMultGLINT2);
646    }
647
648    /* Permedia 3 memory Timings */
649    SAVEREG(PM3MemBypassWriteMask);
650    SAVEREG(PM3ByAperture1Mode);
651    SAVEREG(PM3ByAperture2Mode);
652    SAVEREG(ChipConfig);
653    SAVEREG(Aperture0);
654    SAVEREG(Aperture1);
655    SAVEREG(PM3FifoControl);
656
657    if (pGlint->Chipset == PCI_VENDOR_3DLABS_CHIP_GAMMA)
658   	SAVEREG(DFIFODis);
659    SAVEREG(FIFODis);
660    SAVEREG(PMHTotal);
661    SAVEREG(PMHbEnd);
662    SAVEREG(PMHgEnd);
663    SAVEREG(PMScreenStride);
664    SAVEREG(PMHsStart);
665    SAVEREG(PMHsEnd);
666    SAVEREG(PMVTotal);
667    SAVEREG(PMVbEnd);
668    SAVEREG(PMVsStart);
669    SAVEREG(PMVsEnd);
670    SAVEREG(PMScreenBase);
671    SAVEREG(PMVideoControl);
672    SAVEREG(VClkCtl);
673    if (pGlint->UseFlatPanel) {
674    	SAVEREG(VSConfiguration);
675    	SAVEREG(VSBBase);
676    }
677
678    for (i=0;i<768;i++) {
679    	Permedia2ReadAddress(pScrn, i);
680	pReg->cmap[i] = Permedia2ReadData(pScrn);
681    }
682
683    SAVEREG(PM2VDACRDIndexControl);
684    P2VIN(PM2VDACRDOverlayKey);
685    P2VIN(PM2VDACRDSyncControl);
686    P2VIN(PM2VDACRDMiscControl);
687    P2VIN(PM2VDACRDDACControl);
688    P2VIN(PM2VDACRDPixelSize);
689    P2VIN(PM2VDACRDColorFormat);
690    P2VIN(PM2VDACRDDClk0PreScale);
691    P2VIN(PM2VDACRDDClk0FeedbackScale);
692    P2VIN(PM2VDACRDDClk0PostScale);
693}
694
695void
696Permedia3Restore(ScrnInfoPtr pScrn, GLINTRegPtr pReg)
697{
698    GLINTPtr pGlint = GLINTPTR(pScrn);
699    CARD32 temp;
700    int i;
701
702    /* We can't rely on the vgahw layer copying the font information
703     * back properly, due to problems with MMIO access to VGA space
704     * so we memcpy the information using the slow routines */
705    if (pGlint->STATE)
706	xf86SlowBcopy((CARD8*)pGlint->VGAdata, (CARD8*)pGlint->FbBase, 65536);
707
708    if ((pGlint->numMultiDevices == 2) || (IS_J2000)) {
709	RESTOREREG(GCSRAperture);
710    }
711
712    if (pGlint->MultiAperture) {
713	RESTOREREG(GMultGLINTAperture);
714	RESTOREREG(GMultGLINT1);
715	RESTOREREG(GMultGLINT2);
716    }
717
718    /* Permedia 3 memory Timings */
719    RESTOREREG(PM3MemBypassWriteMask);
720    RESTOREREG(PM3ByAperture1Mode);
721    RESTOREREG(PM3ByAperture2Mode);
722    RESTOREREG(ChipConfig);
723    RESTOREREG(Aperture0);
724    RESTOREREG(Aperture1);
725    RESTOREREG(PM3FifoControl);
726    if (pGlint->Chipset == PCI_VENDOR_3DLABS_CHIP_GAMMA)
727    	RESTOREREG(DFIFODis);
728    RESTOREREG(FIFODis);
729    RESTOREREG(PMVideoControl);
730    RESTOREREG(PMHbEnd);
731    RESTOREREG(PMHgEnd);
732    RESTOREREG(PMScreenBase);
733    RESTOREREG(VClkCtl);
734    RESTOREREG(PMScreenStride);
735    RESTOREREG(PMHTotal);
736    RESTOREREG(PMHsStart);
737    RESTOREREG(PMHsEnd);
738    RESTOREREG(PMVTotal);
739    RESTOREREG(PMVbEnd);
740    RESTOREREG(PMVsStart);
741    RESTOREREG(PMVsEnd);
742
743    if (pGlint->UseFlatPanel) {
744    	RESTOREREG(VSConfiguration);
745    	RESTOREREG(VSBBase);
746    }
747
748    RESTOREREG(PM2VDACRDIndexControl);
749    P2VOUT(PM2VDACRDOverlayKey);
750    P2VOUT(PM2VDACRDSyncControl);
751    P2VOUT(PM2VDACRDMiscControl);
752    P2VOUT(PM2VDACRDDACControl);
753    P2VOUT(PM2VDACRDPixelSize);
754    P2VOUT(PM2VDACRDColorFormat);
755
756    for (i=0;i<768;i++) {
757    	Permedia2WriteAddress(pScrn, i);
758	Permedia2WriteData(pScrn, pReg->cmap[i]);
759    }
760
761    temp = Permedia2vInIndReg(pScrn, PM2VDACIndexClockControl) & 0xFC;
762    P2VOUT(PM2VDACRDDClk0PreScale);
763    P2VOUT(PM2VDACRDDClk0FeedbackScale);
764    P2VOUT(PM2VDACRDDClk0PostScale);
765    Permedia2vOutIndReg(pScrn, PM2VDACIndexClockControl, 0x00, temp|0x03);
766}
767
768void Permedia3LoadPalette(
769    ScrnInfoPtr pScrn,
770    int numColors,
771    int *indices,
772    LOCO *colors,
773    VisualPtr pVisual
774){
775#if 0
776    GLINTPtr pGlint = GLINTPTR(pScrn);
777#endif
778    int i, index, shift = 0, j, repeat = 1;
779
780    if (pScrn->depth == 15) {
781	repeat = 8;
782	shift = 3;
783    }
784
785    for(i = 0; i < numColors; i++) {
786	index = indices[i];
787	for (j = 0; j < repeat; j++) {
788	    Permedia2WriteAddress(pScrn, (index << shift)+j);
789	    Permedia2WriteData(pScrn, colors[index].red);
790	    Permedia2WriteData(pScrn, colors[index].green);
791	    Permedia2WriteData(pScrn, colors[index].blue);
792	}
793#if 0
794        GLINT_SLOW_WRITE_REG(index, PM3LUTIndex);
795	GLINT_SLOW_WRITE_REG((colors[index].red & 0xFF) |
796			     ((colors[index].green & 0xFF) << 8) |
797			     ((colors[index].blue & 0xFF) << 16),
798			     PM3LUTData);
799#endif
800    }
801}
802
803/* special one for 565 mode */
804void Permedia3LoadPalette16(
805    ScrnInfoPtr pScrn,
806    int numColors,
807    int *indices,
808    LOCO *colors,
809    VisualPtr pVisual
810){
811#if 0
812    GLINTPtr pGlint = GLINTPTR(pScrn);
813#endif
814    int i, index, j;
815
816    for(i = 0; i < numColors; i++) {
817	index = indices[i];
818	for (j = 0; j < 4; j++) {
819	    Permedia2WriteAddress(pScrn, (index << 2)+j);
820	    Permedia2WriteData(pScrn, colors[index >> 1].red);
821	    Permedia2WriteData(pScrn, colors[index].green);
822	    Permedia2WriteData(pScrn, colors[index >> 1].blue);
823	}
824#if 0
825        GLINT_SLOW_WRITE_REG(index, PM3LUTIndex);
826	GLINT_SLOW_WRITE_REG((colors[index].red & 0xFF) |
827			     ((colors[index].green & 0xFF) << 8) |
828			     ((colors[index].blue & 0xFF) << 16),
829			     PM3LUTData);
830#endif
831
832	if(index <= 31) {
833	    for (j = 0; j < 4; j++) {
834	    	Permedia2WriteAddress(pScrn, (index << 3)+j);
835	    	Permedia2WriteData(pScrn, colors[index].red);
836	    	Permedia2WriteData(pScrn, colors[(index << 1) + 1].green);
837	    	Permedia2WriteData(pScrn, colors[index].blue);
838	    }
839	}
840    }
841}
842