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