1/*
2 * Copyright 1997-2001 by Alan Hourihane <alanh@fairlite.demon.co.uk>
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 Alan Hourihane not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Alan Hourihane 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 * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL ALAN HOURIHANE 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:  Alan Hourihane, <alanh@fairlite.demon.co.uk>
23 *           Dirk Hohndel,   <hohndel@suse.de>
24 *	     Stefan Dirsch,  <sndirsch@suse.de>
25 *	     Helmut Fahrion, <hf@suse.de>
26 *	     Michel Dänzer,  <michdaen@iiic.ethz.ch>
27 *
28 * this work is sponsored by S.u.S.E. GmbH, Fuerth, Elsa GmbH, Aachen and
29 * Siemens Nixdorf Informationssysteme
30 */
31
32#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
36#include <X11/Xarch.h>
37#include "xf86.h"
38#include "xf86_OSproc.h"
39
40#include "xf86Pci.h"
41
42#include "glint_regs.h"
43#include "glint.h"
44
45#define INITIALFREQERR 100000
46#define MINCLK 110000		/* VCO frequency range */
47#define MAXCLK 250000
48
49static unsigned long
50PM2DAC_CalculateMNPCForClock
51(
52 unsigned long reqclock,		/* In kHz units */
53 unsigned long refclock,		/* In kHz units */
54 unsigned char *rm, 			/* M Out */
55 unsigned char *rn, 			/* N Out */
56 unsigned char *rp			/* P Out */
57 )
58{
59    unsigned char	m, n, p;
60    unsigned long	f;
61    long		freqerr, lowestfreqerr = INITIALFREQERR;
62    unsigned long  	clock,actualclock = 0;
63
64    for (n = 2; n <= 14; n++) {
65        for (m = 2; m != 0; m++) { /* this is a char, so this counts to 255 */
66	    f = refclock * m / n;
67	    if ( (f < MINCLK) || (f > MAXCLK) )
68	    	continue;
69	    for (p = 0; p <= 4; p++) {
70	    	clock = f >> p;
71		freqerr = reqclock - clock;
72		if (freqerr < 0)
73		    freqerr = -freqerr;
74		if (freqerr < lowestfreqerr) {
75		    *rn = n;
76		    *rm = m;
77		    *rp = p;
78		    lowestfreqerr = freqerr;
79		    actualclock = clock;
80#ifdef DEBUG
81	ErrorF("Best %ld diff %ld\n",actualclock,freqerr);
82#endif
83		}
84	    }
85	}
86    }
87
88    return(actualclock);
89}
90
91Bool
92Permedia2Init(ScrnInfoPtr pScrn, DisplayModePtr mode)
93{
94    GLINTPtr pGlint = GLINTPTR(pScrn);
95    GLINTRegPtr pReg = &pGlint->ModeReg[0];
96    CARD32 temp1, temp2, temp3, temp4;
97
98#if X_BYTE_ORDER == X_BIG_ENDIAN
99    switch (pGlint->HwBpp) {
100    case 8:
101    case 24:
102	    temp1 = 0x00;
103	    break;
104
105    case 15:
106    case 16:
107	    temp1 = 0x02;
108	    break;
109
110    case 32:
111	    temp1 = 0x01;
112	    break;
113    default:
114	    break;
115    };
116#endif /* BIG_ENDIAN */
117    pReg->glintRegs[Aperture0 >> 3] = temp1;
118    pReg->glintRegs[Aperture1 >> 3] = temp1;
119    pReg->glintRegs[PMFramebufferWriteMask >> 3] = 0xFFFFFFFF;
120    pReg->glintRegs[PMBypassWriteMask >> 3] = 0xFFFFFFFF;
121
122    pReg->glintRegs[DFIFODis >> 3] = 0;
123    pReg->glintRegs[FIFODis >> 3] = 1;
124
125    if (pGlint->UseBlockWrite)
126	pReg->glintRegs[PMMemConfig >> 3] = GLINT_READ_REG(PMMemConfig) | 1<<21;
127
128
129    temp1 = mode->CrtcHSyncStart - mode->CrtcHDisplay;
130    temp2 = mode->CrtcVSyncStart - mode->CrtcVDisplay;
131    temp3 = mode->CrtcHSyncEnd - mode->CrtcHSyncStart;
132    temp4 = mode->CrtcVSyncEnd - mode->CrtcVSyncStart;
133
134    pReg->glintRegs[PMHTotal >> 3] = Shiftbpp(pScrn,mode->CrtcHTotal);
135    pReg->glintRegs[PMHsEnd >> 3] = Shiftbpp(pScrn, temp1 + temp3);
136    pReg->glintRegs[PMHsStart >> 3] = Shiftbpp(pScrn, temp1);
137    pReg->glintRegs[PMHbEnd >> 3] =
138			Shiftbpp(pScrn,mode->CrtcHTotal-mode->CrtcHDisplay);
139    pReg->glintRegs[PMScreenStride >> 3] =
140			Shiftbpp(pScrn,pScrn->displayWidth>>1);
141
142    pReg->glintRegs[PMVTotal >> 3] = mode->CrtcVTotal - 1;
143    pReg->glintRegs[PMVsEnd >> 3] = temp2 + temp4 - 1;
144    pReg->glintRegs[PMVsStart >> 3] = temp2 - 1;
145    pReg->glintRegs[PMVbEnd >> 3] = mode->CrtcVTotal - mode->CrtcVDisplay;
146
147    /* The hw cursor needs /VSYNC to recognize vert retrace. We'll stick
148       both sync lines to active high here and if needed invert them
149       using the RAMDAC's MCR below. */
150    pReg->glintRegs[PMVideoControl >> 3] =
151	(1 << 5) | (1 << 3) | 1;
152
153    if (pScrn->bitsPerPixel > 8) {
154	/* When != 8bpp then we stick the RAMDAC into 64bit mode */
155	/* And reduce the horizontal timings by half */
156	pReg->glintRegs[PMVideoControl >> 3] |= 1<<16;
157    	pReg->glintRegs[PMHTotal >> 3] >>= 1;
158	pReg->glintRegs[PMHsEnd >> 3] >>= 1;
159	pReg->glintRegs[PMHsStart >> 3] >>= 1;
160	pReg->glintRegs[PMHbEnd >> 3] >>= 1;
161    }
162
163    pReg->glintRegs[VClkCtl >> 3] = (GLINT_READ_REG(VClkCtl) & 0xFFFFFFFC);
164    pReg->glintRegs[PMScreenBase >> 3] = 0;
165    pReg->glintRegs[PMHTotal >> 3] -= 1;
166
167    pReg->glintRegs[ChipConfig >> 3] = GLINT_READ_REG(ChipConfig) & 0xFFFFFFDD;
168
169    pReg->DacRegs[PM2DACIndexMDCR] = 0x00; /* Disable Overlay */
170
171    {
172	/* Get the programmable clock values */
173    	unsigned char m,n,p;
174
175	(void) PM2DAC_CalculateMNPCForClock(mode->Clock,pGlint->RefClock,
176								&m,&n,&p);
177	pReg->DacRegs[PM2DACIndexClockAM] = m;
178	pReg->DacRegs[PM2DACIndexClockAN] = n;
179	pReg->DacRegs[PM2DACIndexClockAP] = p|0x08;
180    }
181
182    if (pScrn->rgbBits == 8)
183	pReg->DacRegs[PM2DACIndexMCR] = 0x02; /* 8bit DAC */
184    else
185        pReg->DacRegs[PM2DACIndexMCR] = 0x00; /* 6bit DAC */
186
187    if (!(mode->Flags & V_PHSYNC))
188        pReg->DacRegs[PM2DACIndexMCR] |= 0x04; /* invert hsync */
189    if (!(mode->Flags & V_PVSYNC))
190        pReg->DacRegs[PM2DACIndexMCR] |= 0x08; /* invert vsync */
191
192    switch (pScrn->bitsPerPixel)
193    {
194    case 8:
195	pReg->DacRegs[PM2DACIndexCMR] = PM2DAC_RGB | PM2DAC_GRAPHICS |
196					PM2DAC_CI8;
197    	break;
198    case 16:
199	if (pScrn->depth == 15) {
200	      pReg->DacRegs[PM2DACIndexCMR] = PM2DAC_RGB | PM2DAC_TRUECOLOR|
201				        PM2DAC_GRAPHICS | PM2DAC_5551;
202	} else {
203	    pReg->DacRegs[PM2DACIndexCMR] = PM2DAC_RGB | PM2DAC_TRUECOLOR|
204				 	PM2DAC_GRAPHICS | PM2DAC_565;
205	}
206    	break;
207    case 24:
208	pReg->DacRegs[PM2DACIndexCMR] = PM2DAC_RGB | PM2DAC_TRUECOLOR|
209				 	PM2DAC_GRAPHICS | PM2DAC_PACKED;
210    	break;
211    case 32:
212	pReg->DacRegs[PM2DACIndexCMR] = PM2DAC_RGB |
213				 	PM2DAC_GRAPHICS | PM2DAC_8888;
214	if (pScrn->overlayFlags & OVERLAY_8_32_PLANAR) {
215	    pReg->DacRegs[PM2DACIndexColorKeyControl] = 0x11;
216	    pReg->DacRegs[PM2DACIndexColorKeyOverlay] = pScrn->colorKey;
217	} else
218	    pReg->DacRegs[PM2DACIndexCMR] |= PM2DAC_TRUECOLOR;
219    	break;
220    }
221
222    return(TRUE);
223}
224
225void
226Permedia2Save(ScrnInfoPtr pScrn, GLINTRegPtr glintReg)
227{
228    GLINTPtr pGlint = GLINTPTR(pScrn);
229    int i;
230
231    /* We can't rely on the vgahw layer copying the font information
232     * back properly, due to problems with MMIO access to VGA space
233     * so we memcpy the information using the slow routines */
234    xf86SlowBcopy((CARD8*)pGlint->FbBase, (CARD8*)pGlint->VGAdata, 65536);
235
236    glintReg->glintRegs[Aperture0 >> 3] = GLINT_READ_REG(Aperture0);
237    glintReg->glintRegs[Aperture1 >> 3] = GLINT_READ_REG(Aperture1);
238    glintReg->glintRegs[PMFramebufferWriteMask >> 3] =
239					GLINT_READ_REG(PMFramebufferWriteMask);
240    glintReg->glintRegs[PMBypassWriteMask >> 3]  = GLINT_READ_REG(PMBypassWriteMask);
241    glintReg->glintRegs[DFIFODis >> 3]  = GLINT_READ_REG(DFIFODis);
242    glintReg->glintRegs[FIFODis >> 3]  = GLINT_READ_REG(FIFODis);
243    /* We only muck about with PMMemConfig, if user wants to */
244    if (pGlint->UseBlockWrite)
245	glintReg->glintRegs[PMMemConfig >> 3] = GLINT_READ_REG(PMMemConfig);
246    glintReg->glintRegs[PMHTotal >> 3] = GLINT_READ_REG(PMHTotal);
247    glintReg->glintRegs[PMHbEnd >> 3] = GLINT_READ_REG(PMHbEnd);
248    glintReg->glintRegs[PMHbEnd >> 3] = GLINT_READ_REG(PMHgEnd);
249    glintReg->glintRegs[PMScreenStride >> 3] = GLINT_READ_REG(PMScreenStride);
250    glintReg->glintRegs[PMHsStart >> 3] = GLINT_READ_REG(PMHsStart);
251    glintReg->glintRegs[PMHsEnd >> 3] = GLINT_READ_REG(PMHsEnd);
252    glintReg->glintRegs[PMVTotal >> 3] = GLINT_READ_REG(PMVTotal);
253    glintReg->glintRegs[PMVbEnd >> 3] = GLINT_READ_REG(PMVbEnd);
254    glintReg->glintRegs[PMVsStart >> 3] = GLINT_READ_REG(PMVsStart);
255    glintReg->glintRegs[PMVsEnd >> 3] = GLINT_READ_REG(PMVsEnd);
256    glintReg->glintRegs[PMScreenBase >> 3] = GLINT_READ_REG(PMScreenBase);
257    glintReg->glintRegs[PMVideoControl >> 3] = GLINT_READ_REG(PMVideoControl);
258    glintReg->glintRegs[VClkCtl >> 3] = GLINT_READ_REG(VClkCtl);
259    glintReg->glintRegs[ChipConfig >> 3] = GLINT_READ_REG(ChipConfig);
260
261    for (i=0;i<768;i++) {
262    	Permedia2ReadAddress(pScrn, i);
263	glintReg->cmap[i] = Permedia2ReadData(pScrn);
264    }
265
266    glintReg->DacRegs[PM2DACIndexColorKeyOverlay] =
267				Permedia2InIndReg(pScrn, PM2DACIndexColorKeyOverlay);
268    glintReg->DacRegs[PM2DACIndexColorKeyControl] =
269				Permedia2InIndReg(pScrn, PM2DACIndexColorKeyControl);
270    glintReg->DacRegs[PM2DACIndexMCR] =
271				Permedia2InIndReg(pScrn, PM2DACIndexMCR);
272    glintReg->DacRegs[PM2DACIndexMDCR] =
273				Permedia2InIndReg(pScrn, PM2DACIndexMDCR);
274    glintReg->DacRegs[PM2DACIndexCMR] =
275				Permedia2InIndReg(pScrn, PM2DACIndexCMR);
276
277    glintReg->DacRegs[PM2DACIndexClockAM] =
278				Permedia2InIndReg(pScrn, PM2DACIndexClockAM);
279    glintReg->DacRegs[PM2DACIndexClockAN] =
280				Permedia2InIndReg(pScrn, PM2DACIndexClockAN);
281    glintReg->DacRegs[PM2DACIndexClockAP] =
282				Permedia2InIndReg(pScrn, PM2DACIndexClockAP);
283}
284
285void
286Permedia2Restore(ScrnInfoPtr pScrn, GLINTRegPtr glintReg)
287{
288    GLINTPtr pGlint = GLINTPTR(pScrn);
289    int i;
290
291    /* We can't rely on the vgahw layer copying the font information
292     * back properly, due to problems with MMIO access to VGA space
293     * so we memcpy the information using the slow routines */
294    if (pGlint->STATE)
295	xf86SlowBcopy((CARD8*)pGlint->VGAdata, (CARD8*)pGlint->FbBase, 65536);
296
297#if 0
298    GLINT_SLOW_WRITE_REG(0, ResetStatus);
299    while(GLINT_READ_REG(ResetStatus) != 0) {
300	xf86MsgVerb(X_INFO, 2, "Resetting Engine - Please Wait.\n");
301    };
302#endif
303
304    GLINT_SLOW_WRITE_REG(0xFF, PM2DACReadMask);
305
306    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[Aperture0 >> 3], Aperture0);
307    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[Aperture1 >> 3], Aperture1);
308    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMFramebufferWriteMask >> 3],
309							PMFramebufferWriteMask);
310    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMBypassWriteMask >> 3],
311							PMBypassWriteMask);
312    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[DFIFODis >> 3], DFIFODis);
313    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[FIFODis >> 3], FIFODis);
314    /* We only muck about with PMMemConfig, if user wants to */
315    if (pGlint->UseBlockWrite)
316    	GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMMemConfig >> 3],PMMemConfig);
317    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMVideoControl >> 3],
318								PMVideoControl);
319    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMHbEnd >> 3], PMHgEnd);
320    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMScreenBase >> 3], PMScreenBase);
321    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[VClkCtl >> 3], VClkCtl);
322    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMScreenStride >> 3],
323								PMScreenStride);
324    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMHTotal >> 3], PMHTotal);
325    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMHbEnd >> 3], PMHbEnd);
326    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMHsStart >> 3], PMHsStart);
327    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMHsEnd >> 3], PMHsEnd);
328    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMVTotal >> 3], PMVTotal);
329    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMVbEnd >> 3], PMVbEnd);
330    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMVsStart >> 3], PMVsStart);
331    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[PMVsEnd >> 3], PMVsEnd);
332    GLINT_SLOW_WRITE_REG(glintReg->glintRegs[ChipConfig >> 3], ChipConfig);
333
334    Permedia2OutIndReg(pScrn, PM2DACIndexColorKeyOverlay, 0x00,
335					glintReg->DacRegs[PM2DACIndexColorKeyOverlay]);
336    Permedia2OutIndReg(pScrn, PM2DACIndexColorKeyControl, 0x00,
337					glintReg->DacRegs[PM2DACIndexColorKeyControl]);
338    Permedia2OutIndReg(pScrn, PM2DACIndexMCR, 0x00,
339					glintReg->DacRegs[PM2DACIndexMCR]);
340    Permedia2OutIndReg(pScrn, PM2DACIndexMDCR, 0x00,
341					glintReg->DacRegs[PM2DACIndexMDCR]);
342    Permedia2OutIndReg(pScrn, PM2DACIndexCMR, 0x00,
343					glintReg->DacRegs[PM2DACIndexCMR]);
344
345    Permedia2OutIndReg(pScrn, PM2DACIndexClockAM, 0x00,
346					glintReg->DacRegs[PM2DACIndexClockAM]);
347    Permedia2OutIndReg(pScrn, PM2DACIndexClockAN, 0x00,
348					glintReg->DacRegs[PM2DACIndexClockAN]);
349    Permedia2OutIndReg(pScrn, PM2DACIndexClockAP, 0x00,
350					glintReg->DacRegs[PM2DACIndexClockAP]);
351
352    for (i=0;i<768;i++) {
353    	Permedia2WriteAddress(pScrn, i);
354        Permedia2WriteData(pScrn, glintReg->cmap[i]);
355    }
356}
357
358static void
359Permedia2ShowCursor(ScrnInfoPtr pScrn)
360{
361    /* Enable cursor - X11 mode */
362    Permedia2OutIndReg(pScrn, PM2DACCursorControl, 0x00, 0x43);
363}
364
365static void
366Permedia2HideCursor(ScrnInfoPtr pScrn)
367{
368    /* Disable cursor */
369    Permedia2OutIndReg(pScrn, PM2DACCursorControl, 0x00, 0x00);
370}
371
372static void
373Permedia2LoadCursorImage(
374    ScrnInfoPtr pScrn,
375    unsigned char *src
376)
377{
378    GLINTPtr pGlint = GLINTPTR(pScrn);
379    int i;
380
381    GLINT_SLOW_WRITE_REG(0x00, PM2DACWriteAddress);
382    for (i=0; i<1024; i++) {
383	GLINT_SLOW_WRITE_REG(*(src++), PM2DACCursorData);
384    }
385}
386
387static void
388Permedia2SetCursorPosition(
389   ScrnInfoPtr pScrn,
390   int x, int y
391)
392{
393    GLINTPtr pGlint = GLINTPTR(pScrn);
394
395    x += 64;
396    y += 64;
397
398    /* Output position - "only" 11 bits of location documented */
399
400    GLINT_WRITE_REG(x & 0xFF,	   PM2DACCursorXLsb);
401    GLINT_WRITE_REG((x>>8) & 0x07, PM2DACCursorXMsb);
402    GLINT_WRITE_REG(y & 0xFF,	   PM2DACCursorYLsb);
403    GLINT_WRITE_REG((y>>8) & 0x07, PM2DACCursorYMsb);
404}
405
406static void
407Permedia2SetCursorColors(
408   ScrnInfoPtr pScrn,
409   int bg, int fg
410)
411{
412    GLINTPtr pGlint = GLINTPTR(pScrn);
413    /* The Permedia2 cursor is always 8 bits so shift 8, not 10 */
414
415    GLINT_SLOW_WRITE_REG(1, PM2DACCursorColorAddress);
416    /* Background color */
417    GLINT_SLOW_WRITE_REG(bg >> 0, PM2DACCursorColorData);
418    GLINT_SLOW_WRITE_REG(bg >> 8, PM2DACCursorColorData);
419    GLINT_SLOW_WRITE_REG(bg >> 16, PM2DACCursorColorData);
420
421    /* Foreground color */
422    GLINT_SLOW_WRITE_REG(fg >> 0, PM2DACCursorColorData);
423    GLINT_SLOW_WRITE_REG(fg >> 8, PM2DACCursorColorData);
424    GLINT_SLOW_WRITE_REG(fg >> 16, PM2DACCursorColorData);
425}
426
427static Bool
428Permedia2UseHWCursor(ScreenPtr pScr, CursorPtr pCurs)
429{
430    return TRUE;
431}
432
433Bool
434Permedia2HWCursorInit(ScreenPtr pScreen)
435{
436    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
437    GLINTPtr pGlint = GLINTPTR(pScrn);
438    xf86CursorInfoPtr infoPtr;
439
440    infoPtr = xf86CreateCursorInfoRec();
441    if(!infoPtr) return FALSE;
442
443    pGlint->CursorInfoRec = infoPtr;
444
445    infoPtr->MaxWidth = 64;
446    infoPtr->MaxHeight = 64;
447    infoPtr->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
448#if X_BYTE_ORDER == X_LITTLE_ENDIAN
449		HARDWARE_CURSOR_BIT_ORDER_MSBFIRST |
450#endif
451		HARDWARE_CURSOR_SOURCE_MASK_NOT_INTERLEAVED;
452    infoPtr->SetCursorColors = Permedia2SetCursorColors;
453    infoPtr->SetCursorPosition = Permedia2SetCursorPosition;
454    infoPtr->LoadCursorImage = Permedia2LoadCursorImage;
455    infoPtr->HideCursor = Permedia2HideCursor;
456    infoPtr->ShowCursor = Permedia2ShowCursor;
457    infoPtr->UseHWCursor = Permedia2UseHWCursor;
458
459    return(xf86InitCursor(pScreen, infoPtr));
460}
461
462/* I2C Functions */
463
464void
465Permedia2I2CUDelay(I2CBusPtr b, int usec)
466{
467    GLINTPtr pGlint = (GLINTPtr) b->DriverPrivate.ptr;
468    CARD32 ct1 = GLINT_READ_REG(PMCount);
469    CARD32 ct2 = usec * 100;
470
471    if (GLINT_READ_REG(PMCount) != ct1)
472	while ((GLINT_READ_REG(PMCount) - ct1) < ct2);
473}
474
475void
476Permedia2I2CPutBits(I2CBusPtr b, int scl, int sda)
477{
478    GLINTPtr pGlint = (GLINTPtr) b->DriverPrivate.ptr;
479    int r = (pGlint->DDCBus == b) ? PMDDCData : VSSerialBusControl;
480
481    CARD32 v = 0;
482
483    if (scl > 0) v |= ClkOut;
484    if (sda > 0) v |= DataOut;
485
486    GLINT_WRITE_REG(v, r);
487}
488
489void
490Permedia2I2CGetBits(I2CBusPtr b, int *scl, int *sda)
491{
492    GLINTPtr pGlint = (GLINTPtr) b->DriverPrivate.ptr;
493    CARD32 v = GLINT_READ_REG((pGlint->DDCBus == b) ?
494	    PMDDCData : VSSerialBusControl);
495
496    *scl = (v & ClkIn) > 0;
497    *sda = (v & DataIn) > 0;
498}
499
500void
501Permedia2PreInit(ScrnInfoPtr pScrn)
502{
503#if defined(__alpha__)
504    GLINTPtr pGlint = GLINTPTR(pScrn);
505
506    /*
507     * On Alpha, we have to init secondary PM2 cards, since
508     * int10 cannot be run on the OEMed cards with VGA disable
509     * jumpers.
510     */
511    if (!xf86IsPrimaryPci(pGlint->PciInfo)) {
512	if ( IS_GLORIASYNERGY ) {
513
514	    /* PM2DAC_CalculateMNPCForClock(80000, 14318, &m, &n, &p); */
515	    Permedia2OutIndReg(pScrn, PM2DACIndexMemClockM, 0x00, 0x7b);
516	    Permedia2OutIndReg(pScrn, PM2DACIndexMemClockN, 0x00, 0x0b);
517	    Permedia2OutIndReg(pScrn, PM2DACIndexMemClockP, 0x00, 0x09);
518
519	    GLINT_SLOW_WRITE_REG( 0x20, PMBootAddress);
520	    GLINT_SLOW_WRITE_REG( 0xe6002021, PMMemConfig);
521	}
522    }
523#endif /* __alpha__ */
524}
525