17104f784Smrg/*
27104f784SmrgCopyright (C) 1994-1999 The XFree86 Project, Inc.  All Rights Reserved.
37104f784SmrgCopyright (C) 2000 Silicon Motion, Inc.  All Rights Reserved.
47104f784SmrgCopyright (C) 2008 Francisco Jerez. All Rights Reserved.
57104f784Smrg
67104f784SmrgPermission is hereby granted, free of charge, to any person obtaining a copy of
77104f784Smrgthis software and associated documentation files (the "Software"), to deal in
87104f784Smrgthe Software without restriction, including without limitation the rights to
97104f784Smrguse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
107104f784Smrgof the Software, and to permit persons to whom the Software is furnished to do
117104f784Smrgso, subject to the following conditions:
127104f784Smrg
137104f784SmrgThe above copyright notice and this permission notice shall be included in all
147104f784Smrgcopies or substantial portions of the Software.
157104f784Smrg
167104f784SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
177104f784SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
187104f784SmrgNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
197104f784SmrgXFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
207104f784SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
217104f784SmrgWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
227104f784Smrg
237104f784SmrgExcept as contained in this notice, the names of The XFree86 Project and
247104f784SmrgSilicon Motion shall not be used in advertising or otherwise to promote the
257104f784Smrgsale, use or other dealings in this Software without prior written
267104f784Smrgauthorization from The XFree86 Project or Silicon Motion.
277104f784Smrg*/
287104f784Smrg
297104f784Smrg#ifdef HAVE_CONFIG_H
307104f784Smrg#include "config.h"
317104f784Smrg#endif
327104f784Smrg
337104f784Smrg#include "smi.h"
347104f784Smrg#include "smi_crtc.h"
357104f784Smrg#include "smilynx.h"
367104f784Smrg
377104f784Smrgstatic void
387104f784SmrgSMILynx_CrtcVideoInit_crt(xf86CrtcPtr crtc)
397104f784Smrg{
407104f784Smrg    ScrnInfoPtr pScrn=crtc->scrn;
417104f784Smrg    SMIPtr pSmi = SMIPTR(pScrn);
427104f784Smrg    int pitch;
437104f784Smrg
447104f784Smrg    ENTER();
457104f784Smrg
467104f784Smrg    switch (pScrn->bitsPerPixel) {
477104f784Smrg    case 8:
487104f784Smrg	WRITE_VPR(pSmi, 0x00, 0x00000000);
497104f784Smrg	break;
507104f784Smrg    case 16:
517104f784Smrg	WRITE_VPR(pSmi, 0x00, 0x00020000);
527104f784Smrg	break;
537104f784Smrg    case 24:
547104f784Smrg	WRITE_VPR(pSmi, 0x00, 0x00040000);
557104f784Smrg	break;
567104f784Smrg    case 32:
577104f784Smrg	WRITE_VPR(pSmi, 0x00, 0x00030000);
587104f784Smrg	break;
597104f784Smrg    }
607104f784Smrg
617104f784Smrg    pitch = (crtc->rotatedData? crtc->mode.HDisplay : pScrn->displayWidth) * pSmi->Bpp;
627104f784Smrg    pitch = (pitch + 15) & ~15;
637104f784Smrg
647104f784Smrg    WRITE_VPR(pSmi, 0x10, (crtc->mode.HDisplay * pSmi->Bpp) >> 3 << 16 | pitch >> 3);
657104f784Smrg
667104f784Smrg    LEAVE();
677104f784Smrg}
687104f784Smrg
697104f784Smrgstatic void
707104f784SmrgSMILynx_CrtcVideoInit_lcd(xf86CrtcPtr crtc)
717104f784Smrg{
727104f784Smrg    ScrnInfoPtr pScrn=crtc->scrn;
737104f784Smrg    SMIPtr pSmi = SMIPTR(pScrn);
747104f784Smrg    SMIRegPtr mode = pSmi->mode;
757104f784Smrg    CARD16 fifo_readoffset,fifo_writeoffset;
767104f784Smrg
777104f784Smrg    ENTER();
787104f784Smrg
797104f784Smrg    /* Set display depth */
807104f784Smrg    if (pScrn->bitsPerPixel > 8)
817104f784Smrg	mode->SR31 |= 0x40; /* 16 bpp */
827104f784Smrg    else
837104f784Smrg	mode->SR31 &= ~0x40; /* 8 bpp */
847104f784Smrg
857104f784Smrg    /* FIFO1/2 Read Offset*/
867104f784Smrg    fifo_readoffset = (crtc->rotatedData? crtc->mode.HDisplay : pScrn->displayWidth) * pSmi->Bpp;
877104f784Smrg    fifo_readoffset = ((fifo_readoffset + 15) & ~15) >> 3;
887104f784Smrg
897104f784Smrg    /* FIFO1 Read Offset */
907104f784Smrg    mode->SR44 = fifo_readoffset & 0x000000FF;
917104f784Smrg    /* FIFO2 Read Offset */
927104f784Smrg    mode->SR4B = fifo_readoffset & 0x000000FF;
937104f784Smrg
947104f784Smrg    if(pSmi->Chipset == SMI_LYNX3DM){
957104f784Smrg	/* FIFO1/2 Read Offset overflow */
967104f784Smrg	mode->SR4C = (((fifo_readoffset & 0x00000300) >> 8) << 2) |
977104f784Smrg	    (((fifo_readoffset & 0x00000300) >> 8) << 6);
987104f784Smrg    }else{
997104f784Smrg	/* FIFO1 Read Offset overflow */
1007104f784Smrg	mode->SR45 = (mode->SR45 & 0x3F) | ((fifo_readoffset & 0x00000300) >> 8) << 6;
1017104f784Smrg	/* FIFO2 Read Offset overflow */
1027104f784Smrg	mode->SR4C = (((fifo_readoffset & 0x00000300) >> 8) << 6);
1037104f784Smrg    }
1047104f784Smrg
1057104f784Smrg    /* FIFO Write Offset */
1067104f784Smrg    fifo_writeoffset = crtc->mode.HDisplay * pSmi->Bpp >> 3;
1077104f784Smrg    mode->SR48 = fifo_writeoffset & 0x000000FF;
1087104f784Smrg    mode->SR49 = (fifo_writeoffset & 0x00000300) >> 8;
1097104f784Smrg
1107104f784Smrg    /* set FIFO levels */
1117104f784Smrg    mode->SR4A = 0x41;
1127104f784Smrg
1137104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, mode->SR31);
1147104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x44, mode->SR44);
1157104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x45, mode->SR45);
1167104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x48, mode->SR48);
1177104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x49, mode->SR49);
1187104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4A, mode->SR4A);
1197104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4B, mode->SR4B);
1207104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4C, mode->SR4C);
1217104f784Smrg
1227104f784Smrg    LEAVE();
1237104f784Smrg}
1247104f784Smrg
1257104f784Smrgstatic void
1267104f784SmrgSMI730_CrtcVideoInit(xf86CrtcPtr crtc)
1277104f784Smrg{
1287104f784Smrg    ScrnInfoPtr pScrn=crtc->scrn;
1297104f784Smrg    SMIPtr pSmi = SMIPTR(pScrn);
1307104f784Smrg    int pitch;
1317104f784Smrg
1327104f784Smrg    ENTER();
1337104f784Smrg
1347104f784Smrg    switch (pScrn->bitsPerPixel) {
1357104f784Smrg    case 8:
1367104f784Smrg	WRITE_VPR(pSmi, 0x00, 0x00000000);
1377104f784Smrg	WRITE_FPR(pSmi, FPR00, 0x00080000);
1387104f784Smrg	break;
1397104f784Smrg    case 16:
1407104f784Smrg	WRITE_VPR(pSmi, 0x00, 0x00020000);
1417104f784Smrg	WRITE_FPR(pSmi, FPR00, 0x000A0000);
1427104f784Smrg	break;
1437104f784Smrg    case 24:
1447104f784Smrg	WRITE_VPR(pSmi, 0x00, 0x00040000);
1457104f784Smrg	WRITE_FPR(pSmi, FPR00, 0x000C0000);
1467104f784Smrg	break;
1477104f784Smrg    case 32:
1487104f784Smrg	WRITE_VPR(pSmi, 0x00, 0x00030000);
1497104f784Smrg	WRITE_FPR(pSmi, FPR00, 0x000B0000);
1507104f784Smrg	break;
1517104f784Smrg    }
1527104f784Smrg
1537104f784Smrg    pitch = (crtc->rotatedData? crtc->mode.HDisplay : pScrn->displayWidth) * pSmi->Bpp;
1547104f784Smrg    pitch = (pitch + 15) & ~15;
1557104f784Smrg
1567104f784Smrg    WRITE_VPR(pSmi, 0x10, (crtc->mode.HDisplay * pSmi->Bpp) >> 3 << 16 | pitch >> 3);
1577104f784Smrg    WRITE_FPR(pSmi, FPR10, (crtc->mode.HDisplay * pSmi->Bpp) >> 3 << 16 | pitch >> 3);
1587104f784Smrg
1597104f784Smrg    LEAVE();
1607104f784Smrg}
1617104f784Smrg
1627104f784Smrgstatic void
1637104f784SmrgSMILynx_CrtcAdjustFrame(xf86CrtcPtr crtc, int x, int y)
1647104f784Smrg{
1657104f784Smrg    ScrnInfoPtr pScrn=crtc->scrn;
1667104f784Smrg    SMIPtr pSmi = SMIPTR(pScrn);
1677104f784Smrg    SMIRegPtr mode = pSmi->mode;
1687104f784Smrg    xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(pScrn);
1697104f784Smrg    CARD32 Base;
1707104f784Smrg
1717104f784Smrg    ENTER();
1727104f784Smrg
1737104f784Smrg    if(crtc->rotatedData)
1747104f784Smrg	Base = (char*)crtc->rotatedData - (char*)pSmi->FBBase;
1757104f784Smrg    else
1767104f784Smrg	Base = pSmi->FBOffset + (x + y * pScrn->displayWidth) * pSmi->Bpp;
1777104f784Smrg
1787104f784Smrg
1797104f784Smrg    if (SMI_LYNX3D_SERIES(pSmi->Chipset) ||
1807104f784Smrg	     SMI_COUGAR_SERIES(pSmi->Chipset)) {
1817104f784Smrg	Base = (Base + 15) & ~15;
1827104f784Smrg	while ((Base % pSmi->Bpp) > 0) {
1837104f784Smrg	    Base -= 16;
1847104f784Smrg	}
1857104f784Smrg    } else {
1867104f784Smrg	Base = (Base + 7) & ~7;
1877104f784Smrg	while ((Base % pSmi->Bpp) > 0)
1887104f784Smrg	    Base -= 8;
1897104f784Smrg    }
1907104f784Smrg
1917104f784Smrg    Base >>= 3;
1927104f784Smrg
1937104f784Smrg    if(SMI_COUGAR_SERIES(pSmi->Chipset)){
1947104f784Smrg	WRITE_VPR(pSmi, 0x0C, Base);
1957104f784Smrg	WRITE_FPR(pSmi, FPR0C, Base);
1967104f784Smrg    }else{
1977104f784Smrg	if(pSmi->Dualhead && crtc == crtcConf->crtc[1]){
1987104f784Smrg	    /* LCD */
1997104f784Smrg
2007104f784Smrg	    /* FIFO1 read start address */
2017104f784Smrg	    mode->SR40 = Base & 0x000000FF;
2027104f784Smrg	    mode->SR41 = (Base & 0x0000FF00) >> 8;
2037104f784Smrg
2047104f784Smrg	    /* FIFO2 read start address */
2057104f784Smrg	    mode->SR42 = Base & 0x000000FF;
2067104f784Smrg	    mode->SR43 = (Base & 0x0000FF00) >> 8;
2077104f784Smrg
2087104f784Smrg	    /* FIFO1/2 read start address overflow */
2097104f784Smrg	    if(pSmi->Chipset == SMI_LYNX3DM)
2107104f784Smrg		mode->SR45 = (Base & 0x000F0000) >> 16 | (Base & 0x000F0000) >> 16 << 4;
2117104f784Smrg	    else
2127104f784Smrg		mode->SR45 = (mode->SR45 & 0xC0) |
2137104f784Smrg		    (Base & 0x00070000) >> 16 | (Base & 0x00070000) >> 16 << 3;
2147104f784Smrg
2157104f784Smrg	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x40, mode->SR40);
2167104f784Smrg	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x41, mode->SR41);
2177104f784Smrg	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x42, mode->SR42);
2187104f784Smrg	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x43, mode->SR43);
2197104f784Smrg	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x45, mode->SR45);
2207104f784Smrg
2217104f784Smrg	}else{
2227104f784Smrg	    /* CRT or single head */
2237104f784Smrg	    WRITE_VPR(pSmi, 0x0C, Base);
2247104f784Smrg	}
2257104f784Smrg    }
2267104f784Smrg
2277104f784Smrg    LEAVE();
2287104f784Smrg}
2297104f784Smrg
2307104f784Smrgstatic Bool
2317104f784SmrgSMILynx_CrtcModeFixup(xf86CrtcPtr crtc,
2327104f784Smrg		      DisplayModePtr mode,
2337104f784Smrg		      DisplayModePtr adjusted_mode)
2347104f784Smrg{
2357104f784Smrg    ScrnInfoPtr pScrn=crtc->scrn;
2367104f784Smrg    SMIPtr pSmi = SMIPTR(pScrn);
2377104f784Smrg
2387104f784Smrg    ENTER();
2397104f784Smrg
2407104f784Smrg    if (pSmi->Chipset == SMI_LYNXEMplus) {
2417104f784Smrg	/* Adjust the pixel clock in case it is near one of the known
2427104f784Smrg	   stable frequencies (KHz) */
2437104f784Smrg	int stable_clocks[] = {46534,};
2442ec8c4b4Smrg	int epsilon = 3000;
2457104f784Smrg	int i;
2467104f784Smrg
2477104f784Smrg	for (i=0; i < sizeof(stable_clocks)/sizeof(int); i++) {
2487104f784Smrg	    if ( abs(mode->Clock - stable_clocks[i]) < epsilon) {
2497104f784Smrg		adjusted_mode->Clock = stable_clocks[i];
2507104f784Smrg		break;
2517104f784Smrg	    }
2527104f784Smrg	}
2537104f784Smrg    }
2547104f784Smrg
2557104f784Smrg    LEAVE(TRUE);
2567104f784Smrg}
2577104f784Smrg
2587104f784Smrgstatic void
2597104f784SmrgSMILynx_CrtcModeSet_vga(xf86CrtcPtr crtc,
2607104f784Smrg	    DisplayModePtr mode,
2617104f784Smrg	    DisplayModePtr adjusted_mode,
2627104f784Smrg	    int x, int y)
2637104f784Smrg{
2647104f784Smrg    ScrnInfoPtr pScrn=crtc->scrn;
2657104f784Smrg    SMIPtr pSmi = SMIPTR(pScrn);
2667104f784Smrg    SMIRegPtr reg = pSmi->mode;
2677104f784Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
2687104f784Smrg    int vgaIOBase  = hwp->IOBase;
2697104f784Smrg    int vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET;
2707104f784Smrg    int vgaCRData  = vgaIOBase + VGA_CRTC_DATA_OFFSET;
2717104f784Smrg    vgaRegPtr vganew = &hwp->ModeReg;
2727104f784Smrg
2737104f784Smrg    ENTER();
2747104f784Smrg
2757104f784Smrg    /* Initialize Video Processor Registers */
2767104f784Smrg
2777104f784Smrg    SMICRTC(crtc)->video_init(crtc);
2787104f784Smrg    SMILynx_CrtcAdjustFrame(crtc, x,y);
2797104f784Smrg
2807104f784Smrg
2817104f784Smrg    /* Program the PLL */
2827104f784Smrg
2837104f784Smrg    /* calculate vclk1 */
2847104f784Smrg    if (SMI_LYNX_SERIES(pSmi->Chipset)) {
2857104f784Smrg        SMI_CommonCalcClock(pScrn->scrnIndex, adjusted_mode->Clock,
2867104f784Smrg			1, 1, 63, 0, 3,
2877104f784Smrg                        pSmi->clockRange.minClock,
2887104f784Smrg                        pSmi->clockRange.maxClock,
2897104f784Smrg                        &reg->SR6C, &reg->SR6D);
2907104f784Smrg    } else {
2917104f784Smrg        SMI_CommonCalcClock(pScrn->scrnIndex, adjusted_mode->Clock,
2927104f784Smrg			1, 1, 63, 0, 1,
2937104f784Smrg                        pSmi->clockRange.minClock,
2947104f784Smrg                        pSmi->clockRange.maxClock,
2957104f784Smrg                        &reg->SR6C, &reg->SR6D);
2967104f784Smrg    }
2977104f784Smrg
2987104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6C, reg->SR6C);
2997104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6D, reg->SR6D);
3007104f784Smrg
3017104f784Smrg
3027104f784Smrg    /* Adjust mode timings */
3037104f784Smrg
3047104f784Smrg    if (!vgaHWInit(pScrn, mode)) {
3057104f784Smrg	LEAVE();
3067104f784Smrg    }
3077104f784Smrg
3087104f784Smrg    if ((mode->HDisplay == 640) && SMI_LYNXM_SERIES(pSmi->Chipset)) {
3097104f784Smrg	vganew->MiscOutReg &= ~0x0C;
3107104f784Smrg    } else {
3117104f784Smrg	vganew->MiscOutReg |= 0x0C;
3127104f784Smrg    }
3137104f784Smrg    vganew->MiscOutReg |= 0x20;
3147104f784Smrg
3157104f784Smrg    {
3167104f784Smrg	unsigned long HTotal=(mode->CrtcHTotal>>3)-5;
3177104f784Smrg	unsigned long HBlankEnd=(mode->CrtcHBlankEnd>>3)-1;
3187104f784Smrg	unsigned long VTotal=mode->CrtcVTotal-2;
3197104f784Smrg	unsigned long VDisplay=mode->CrtcVDisplay-1;
3207104f784Smrg	unsigned long VBlankStart=mode->CrtcVBlankStart-1;
3217104f784Smrg	unsigned long VBlankEnd=mode->CrtcVBlankEnd-1;
3227104f784Smrg	unsigned long VSyncStart=mode->CrtcVSyncStart;
3237104f784Smrg
3247104f784Smrg	/* Fix HBlankEnd/VBlankEnd */
3257104f784Smrg	if((mode->CrtcHBlankEnd >> 3) == (mode->CrtcHTotal >> 3)) HBlankEnd=0;
3267104f784Smrg	if(mode->CrtcVBlankEnd == mode->CrtcVTotal) VBlankEnd=0;
3277104f784Smrg
3287104f784Smrg	vganew->CRTC[3] = (vganew->CRTC[3] & ~0x1F) | (HBlankEnd & 0x1F);
3297104f784Smrg	vganew->CRTC[5] = (vganew->CRTC[5] & ~0x80) | (HBlankEnd & 0x20) >> 5 << 7;
3307104f784Smrg	vganew->CRTC[22] = VBlankEnd & 0xFF;
3317104f784Smrg
3327104f784Smrg	/* Write the overflow from several VGA registers */
3337104f784Smrg	reg->CR30 = (VTotal & 0x400) >> 10 << 3 |
3347104f784Smrg	    (VDisplay & 0x400) >> 10 << 2 |
3357104f784Smrg	    (VBlankStart & 0x400) >> 10 << 1 |
3367104f784Smrg	    (VSyncStart & 0x400) >> 10 << 0;
3377104f784Smrg
3387104f784Smrg	if(pSmi->Chipset == SMI_LYNX3DM)
3397104f784Smrg	    reg->CR30 |= (HTotal & 0x100) >> 8 << 6;
3407104f784Smrg
3417104f784Smrg	reg->CR33 = (HBlankEnd & 0xC0) >> 6 << 5 | (VBlankEnd & 0x300) >> 8 << 3;
3427104f784Smrg    }
3437104f784Smrg
3447104f784Smrg    vgaHWRestore(pScrn, vganew, VGA_SR_MODE);
3457104f784Smrg
3467104f784Smrg    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x30, reg->CR30);
3477104f784Smrg    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, reg->CR33);
3487104f784Smrg
3497104f784Smrg    LEAVE();
3507104f784Smrg}
3517104f784Smrg
3527104f784Smrgstatic void
3537104f784SmrgSMILynx_CrtcModeSet_crt(xf86CrtcPtr crtc,
3547104f784Smrg	    DisplayModePtr mode,
3557104f784Smrg	    DisplayModePtr adjusted_mode,
3567104f784Smrg	    int x, int y)
3577104f784Smrg{
3587104f784Smrg    ScrnInfoPtr pScrn=crtc->scrn;
3597104f784Smrg    SMIPtr pSmi = SMIPTR(pScrn);
3607104f784Smrg    SMIRegPtr reg = pSmi->mode;
3617104f784Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
3627104f784Smrg    int vgaIOBase  = hwp->IOBase;
3637104f784Smrg    int	vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET;
3647104f784Smrg    int	vgaCRData  = vgaIOBase + VGA_CRTC_DATA_OFFSET;
3657104f784Smrg    int i;
3667104f784Smrg
3677104f784Smrg    ENTER();
3687104f784Smrg
3697104f784Smrg    /* Initialize Video Processor Registers */
3707104f784Smrg
3717104f784Smrg    SMILynx_CrtcVideoInit_crt(crtc);
3727104f784Smrg    SMILynx_CrtcAdjustFrame(crtc, x,y);
3737104f784Smrg
3747104f784Smrg
3757104f784Smrg    /* Program the PLL */
3767104f784Smrg
3777104f784Smrg    /* calculate vclk1 */
3787104f784Smrg    if (SMI_LYNX_SERIES(pSmi->Chipset)) {
3797104f784Smrg        SMI_CommonCalcClock(pScrn->scrnIndex, adjusted_mode->Clock,
3807104f784Smrg			1, 1, 63, 0, 3,
3817104f784Smrg                        pSmi->clockRange.minClock,
3827104f784Smrg                        pSmi->clockRange.maxClock,
3837104f784Smrg                        &reg->SR6C, &reg->SR6D);
3847104f784Smrg    } else {
3857104f784Smrg        SMI_CommonCalcClock(pScrn->scrnIndex, adjusted_mode->Clock,
3867104f784Smrg			1, 1, 63, 0, 1,
3877104f784Smrg                        pSmi->clockRange.minClock,
3887104f784Smrg                        pSmi->clockRange.maxClock,
3897104f784Smrg                        &reg->SR6C, &reg->SR6D);
3907104f784Smrg    }
3917104f784Smrg
3927104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6C, reg->SR6C);
3937104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6D, reg->SR6D);
3947104f784Smrg
3957104f784Smrg
3967104f784Smrg    /* Adjust mode timings */
3977104f784Smrg    /* In virtual refresh mode, the CRT timings are controlled through
3987104f784Smrg       the shadow VGA registers */
3997104f784Smrg
4007104f784Smrg    {
4017104f784Smrg	unsigned long HTotal=(mode->CrtcHTotal>>3)-5;
4027104f784Smrg	unsigned long HDisplay=(mode->CrtcHDisplay>>3)-1;
4037104f784Smrg	unsigned long HBlankStart=(mode->CrtcHBlankStart>>3)-1;
4047104f784Smrg	unsigned long HBlankEnd=(mode->CrtcHBlankEnd>>3)-1;
4057104f784Smrg	unsigned long HSyncStart=mode->CrtcHSyncStart>>3;
4067104f784Smrg	unsigned long HSyncEnd=mode->CrtcHSyncEnd>>3;
4077104f784Smrg	unsigned long VTotal=mode->CrtcVTotal-2;
4087104f784Smrg	unsigned long VDisplay=mode->CrtcVDisplay-1;
4097104f784Smrg	unsigned long VBlankStart=mode->CrtcVBlankStart-1;
4107104f784Smrg	unsigned long VBlankEnd=mode->CrtcVBlankEnd-1;
4117104f784Smrg	unsigned long VSyncStart=mode->CrtcVSyncStart;
4127104f784Smrg	unsigned long VSyncEnd=mode->CrtcVSyncEnd;
4137104f784Smrg
4147104f784Smrg	/* Fix HBlankEnd/VBlankEnd */
4157104f784Smrg	if((mode->CrtcHBlankEnd >> 3) == (mode->CrtcHTotal >> 3)) HBlankEnd=0;
4167104f784Smrg	if(mode->CrtcVBlankEnd == mode->CrtcVTotal) VBlankEnd=0;
4177104f784Smrg
4187104f784Smrg	reg->CR40 [0x0] = HTotal & 0xFF;
4197104f784Smrg	reg->CR40 [0x1] = HBlankStart & 0xFF;
4207104f784Smrg	reg->CR40 [0x2] = HBlankEnd & 0x1F;
4217104f784Smrg	reg->CR40 [0x3] = HSyncStart & 0xFF;
4227104f784Smrg	reg->CR40 [0x4] = (HBlankEnd & 0x20) >> 5 << 7 |
4237104f784Smrg	    (HSyncEnd & 0x1F);
4247104f784Smrg	reg->CR40 [0x5] = VTotal & 0xFF;
4257104f784Smrg	reg->CR40 [0x6] = VBlankStart & 0xFF;
4267104f784Smrg	reg->CR40 [0x7] = VBlankEnd & 0xFF;
4277104f784Smrg	reg->CR40 [0x8] = VSyncStart & 0xFF;
4287104f784Smrg	reg->CR40 [0x9] = VSyncEnd & 0x0F;
4297104f784Smrg	reg->CR40 [0xA] = (VSyncStart & 0x200) >> 9 << 7 |
4307104f784Smrg	    (VDisplay & 0x200) >> 9 << 6 |
4317104f784Smrg	    (VTotal & 0x200) >> 9 << 5 |
4327104f784Smrg	    (VBlankStart & 0x100) >> 8 << 3 |
4337104f784Smrg	    (VSyncStart & 0x100) >> 8 << 2 |
4347104f784Smrg	    (VDisplay & 0x100) >> 8 << 1 |
4357104f784Smrg	    (VTotal & 0x100) >> 8 << 0;
4367104f784Smrg	reg->CR40 [0xB] = ((mode->Flags & V_NVSYNC)?1:0) << 7 |
4377104f784Smrg	    ((mode->Flags & V_NHSYNC)?1:0) << 6 |
4387104f784Smrg	    (VBlankStart & 0x200) >> 9 << 5;
4397104f784Smrg	reg->CR40 [0xC] = HDisplay & 0xFF;
4407104f784Smrg	reg->CR40 [0xD] = VDisplay & 0xFF;
4417104f784Smrg
4427104f784Smrg	reg->CR30 = (VTotal & 0x400) >> 10 << 3 |
4437104f784Smrg	    (VDisplay & 0x400) >> 10 << 2 |
4447104f784Smrg	    (VBlankStart & 0x400) >> 10 << 1 |
4457104f784Smrg	    (VSyncStart & 0x400) >> 10 << 0;
4467104f784Smrg
4477104f784Smrg	if(pSmi->Chipset == SMI_LYNX3DM)
4487104f784Smrg	    reg->CR30 |= (HTotal & 0x100) >> 8 << 6;
4497104f784Smrg
4507104f784Smrg	reg->CR33 = (HBlankEnd & 0xC0) >> 6 << 5 | (VBlankEnd & 0x300) >> 8 << 3;
4517104f784Smrg
4527104f784Smrg    }
4537104f784Smrg
4547104f784Smrg    /* Select primary set of shadow registers */
4557104f784Smrg    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, reg->CR90[0xE] & ~0x20);
4567104f784Smrg
4577104f784Smrg    for(i=0; i <= 0xD; i++)
4587104f784Smrg	VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i, reg->CR40[i]);
4597104f784Smrg
4607104f784Smrg    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x30, reg->CR30);
4617104f784Smrg    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, reg->CR33);
4627104f784Smrg
4637104f784Smrg    LEAVE();
4647104f784Smrg}
4657104f784Smrg
4667104f784Smrgstatic void
4677104f784SmrgSMILynx_CrtcModeSet_lcd(xf86CrtcPtr crtc,
4687104f784Smrg	    DisplayModePtr mode,
4697104f784Smrg	    DisplayModePtr adjusted_mode,
4707104f784Smrg	    int x, int y)
4717104f784Smrg{
4727104f784Smrg    ScrnInfoPtr pScrn=crtc->scrn;
4737104f784Smrg    SMIPtr pSmi = SMIPTR(pScrn);
4747104f784Smrg    SMIRegPtr reg = pSmi->mode;
4757104f784Smrg
4767104f784Smrg    ENTER();
4777104f784Smrg
4787104f784Smrg    /* Initialize the flat panel video processor */
4797104f784Smrg
4807104f784Smrg    SMILynx_CrtcVideoInit_lcd(crtc);
4817104f784Smrg    SMILynx_CrtcAdjustFrame(crtc,x,y);
4827104f784Smrg
4837104f784Smrg
4847104f784Smrg    /* Program the PLL */
4857104f784Smrg
4867104f784Smrg    /* calculate vclk2 */
4877104f784Smrg    if (SMI_LYNX_SERIES(pSmi->Chipset)) {
4887104f784Smrg        SMI_CommonCalcClock(pScrn->scrnIndex, adjusted_mode->Clock,
4897104f784Smrg			1, 1, 63, 0, 0,
4907104f784Smrg                        pSmi->clockRange.minClock,
4917104f784Smrg                        pSmi->clockRange.maxClock,
4927104f784Smrg                        &reg->SR6E, &reg->SR6F);
4937104f784Smrg    } else {
4947104f784Smrg        SMI_CommonCalcClock(pScrn->scrnIndex, adjusted_mode->Clock,
4957104f784Smrg			1, 1, 63, 0, 1,
4967104f784Smrg                        pSmi->clockRange.minClock,
4977104f784Smrg                        pSmi->clockRange.maxClock,
4987104f784Smrg                        &reg->SR6E, &reg->SR6F);
4997104f784Smrg    }
5007104f784Smrg
5017104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6E, reg->SR6E);
5027104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6F, reg->SR6F);
5037104f784Smrg
5047104f784Smrg
5057104f784Smrg    /* Adjust mode timings */
5067104f784Smrg    {
5077104f784Smrg	unsigned long HTotal=(mode->CrtcHTotal>>3)-1;
5087104f784Smrg	unsigned long HDisplay=(mode->CrtcHDisplay>>3)-1;
5097104f784Smrg	unsigned long HSyncStart=(mode->CrtcHSyncStart>>3);
5107104f784Smrg	unsigned long HSyncWidth=((mode->CrtcHSyncEnd - mode->CrtcHSyncStart) >> 3) - 1;
5117104f784Smrg	unsigned long VTotal=mode->CrtcVTotal-1;
5127104f784Smrg	unsigned long VDisplay=mode->CrtcVDisplay-1;
5137104f784Smrg	unsigned long VSyncStart=mode->CrtcVSyncStart-1;
5147104f784Smrg	unsigned long VSyncWidth=mode->CrtcVSyncEnd - mode->CrtcVSyncStart - 1;
5157104f784Smrg
5167104f784Smrg	reg->SR50 = (VTotal & 0x700) >> 8 << 1 |
5177104f784Smrg	    (HSyncStart & 0x100) >> 8 << 0;
5187104f784Smrg	reg->SR51 = (VSyncStart & 0x700) >> 8 << 5 |
5197104f784Smrg	    (VDisplay & 0x700) >> 8 << 2 |
5207104f784Smrg	    (HDisplay & 0x100) >> 8 << 1 |
5217104f784Smrg	    (HTotal & 0x100) >> 8 << 0;
5227104f784Smrg	reg->SR52 = HTotal & 0xFF;
5237104f784Smrg	reg->SR53 = HDisplay & 0xFF;
5247104f784Smrg	reg->SR54 = HSyncStart & 0xFF;
5257104f784Smrg	reg->SR55 = VTotal & 0xFF;
5267104f784Smrg	reg->SR56 = VDisplay & 0xFF;
5277104f784Smrg	reg->SR57 = VSyncStart & 0xFF;
5287104f784Smrg	reg->SR5A = (HSyncWidth & 0x1F) << 3 |
5297104f784Smrg	    (VSyncWidth & 0x07) << 0;
5307104f784Smrg
5317104f784Smrg	/* XXX - Why is the polarity hardcoded here? */
5327104f784Smrg	reg->SR32 &= ~0x18;
5337104f784Smrg	if (mode->HDisplay == 800) {
5347104f784Smrg	    reg->SR32 |= 0x18;
5357104f784Smrg	}
5367104f784Smrg	if ((mode->HDisplay == 1024) && SMI_LYNXM_SERIES(pSmi->Chipset)) {
5377104f784Smrg	    reg->SR32 |= 0x18;
5387104f784Smrg	}
5397104f784Smrg    }
5407104f784Smrg
5417104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32, reg->SR32);
5427104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x50, reg->SR50);
5437104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x51, reg->SR51);
5447104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x52, reg->SR52);
5457104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x53, reg->SR53);
5467104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x54, reg->SR54);
5477104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x55, reg->SR55);
5487104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x56, reg->SR56);
5497104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x57, reg->SR57);
5507104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x5A, reg->SR5A);
5517104f784Smrg
5527104f784Smrg    LEAVE();
5537104f784Smrg}
5547104f784Smrg
5557104f784Smrgstatic void
5567104f784SmrgSMILynx_CrtcModeSet_bios(xf86CrtcPtr crtc,
5577104f784Smrg	    DisplayModePtr mode,
5587104f784Smrg	    DisplayModePtr adjusted_mode,
5597104f784Smrg	    int x, int y)
5607104f784Smrg{
5617104f784Smrg    ScrnInfoPtr pScrn=crtc->scrn;
5627104f784Smrg    SMIPtr pSmi = SMIPTR(pScrn);
5637104f784Smrg    SMIRegPtr reg = pSmi->mode;
5647104f784Smrg    int i;
5657104f784Smrg    CARD8 tmp;
5667104f784Smrg
5677104f784Smrg    ENTER();
568eb3dced6Smacallan#ifdef USE_INT10
5697104f784Smrg    /* Find the INT 10 mode number */
5707104f784Smrg    {
5717104f784Smrg	static struct {
5727104f784Smrg	    int x, y, bpp;
5737104f784Smrg	    CARD16 mode;
5747104f784Smrg	} modeTable[] =
5757104f784Smrg	    {
5767104f784Smrg		{  640,  480,  8, 0x50 },
5777104f784Smrg		{  640,  480, 16, 0x52 },
5787104f784Smrg		{  640,  480, 24, 0x53 },
5797104f784Smrg		{  640,  480, 32, 0x54 },
5807104f784Smrg		{  800,  480,  8, 0x4A },
5817104f784Smrg		{  800,  480, 16, 0x4C },
5827104f784Smrg		{  800,  480, 24, 0x4D },
5837104f784Smrg		{  800,  600,  8, 0x55 },
5847104f784Smrg		{  800,  600, 16, 0x57 },
5857104f784Smrg		{  800,  600, 24, 0x58 },
5867104f784Smrg		{  800,  600, 32, 0x59 },
5877104f784Smrg		{ 1024,  768,  8, 0x60 },
5887104f784Smrg		{ 1024,  768, 16, 0x62 },
5897104f784Smrg		{ 1024,  768, 24, 0x63 },
5907104f784Smrg		{ 1024,  768, 32, 0x64 },
5917104f784Smrg		{ 1280, 1024,  8, 0x65 },
5927104f784Smrg		{ 1280, 1024, 16, 0x67 },
5937104f784Smrg		{ 1280, 1024, 24, 0x68 },
5947104f784Smrg		{ 1280, 1024, 32, 0x69 },
5957104f784Smrg	    };
5967104f784Smrg
5977104f784Smrg	reg->mode = 0;
5987104f784Smrg	for (i = 0; i < sizeof(modeTable) / sizeof(modeTable[0]); i++) {
5997104f784Smrg	    if ((modeTable[i].x == mode->HDisplay) &&
6007104f784Smrg		(modeTable[i].y == mode->VDisplay) &&
6017104f784Smrg		(modeTable[i].bpp == pScrn->bitsPerPixel)) {
6027104f784Smrg		reg->mode = modeTable[i].mode;
6037104f784Smrg		break;
6047104f784Smrg	    }
6057104f784Smrg	}
6067104f784Smrg    }
607eb3dced6Smacallan#endif
6087104f784Smrg    if(!reg->mode){
6097104f784Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "SMILynx_CrtcModeSet_bios: Not a known BIOS mode: "
6107104f784Smrg		   "falling back to direct modesetting.\n");
6117104f784Smrg	SMILynx_CrtcModeSet_vga(crtc,mode,adjusted_mode,x,y);
6127104f784Smrg	LEAVE();
6137104f784Smrg    }
614eb3dced6Smacallan#ifdef USE_INT10
6157104f784Smrg    pSmi->pInt10->num = 0x10;
6167104f784Smrg    pSmi->pInt10->ax = reg->mode | 0x80;
6177104f784Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting mode 0x%02X\n",
6187104f784Smrg	       reg->mode);
6197104f784Smrg    xf86ExecX86int10(pSmi->pInt10);
6207104f784Smrg
6217104f784Smrg    /* Enable linear mode. */
6227104f784Smrg    outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18);
6237104f784Smrg    tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA);
6247104f784Smrg    outb(pSmi->PIOBase + VGA_SEQ_DATA, tmp | 0x01);
6257104f784Smrg
6267104f784Smrg    /* Enable DPR/VPR registers. */
6277104f784Smrg    tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
6287104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, tmp & ~0x03);
6297104f784Smrg
6307104f784Smrg
6317104f784Smrg    /* Initialize Video Processor Registers */
6327104f784Smrg
6337104f784Smrg    SMICRTC(crtc)->video_init(crtc);
6347104f784Smrg    SMILynx_CrtcAdjustFrame(crtc, x,y);
635eb3dced6Smacallan#endif
6367104f784Smrg    LEAVE();
6377104f784Smrg}
6387104f784Smrg
6397104f784Smrgstatic void
6407104f784SmrgSMILynx_CrtcLoadLUT_crt(xf86CrtcPtr crtc)
6417104f784Smrg{
6427104f784Smrg    ScrnInfoPtr pScrn = crtc->scrn;
6437104f784Smrg    SMIPtr pSmi = SMIPTR(pScrn);
6447104f784Smrg    SMIRegPtr mode = pSmi->mode;
6457104f784Smrg    SMICrtcPrivatePtr crtcPriv = SMICRTC(crtc);
6467104f784Smrg    int i;
6477104f784Smrg
6487104f784Smrg    ENTER();
6497104f784Smrg
6507104f784Smrg    /* Write CRT RAM only */
6517104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX,VGA_SEQ_DATA,0x66,(mode->SR66 & ~0x30) | 0x20);
6527104f784Smrg
6537104f784Smrg    for(i=0;i<256;i++){
6547104f784Smrg	VGAOUT8(pSmi, VGA_DAC_WRITE_ADDR, i);
6557104f784Smrg	VGAOUT8(pSmi, VGA_DAC_DATA, crtcPriv->lut_r[i] >> 8);
6567104f784Smrg	VGAOUT8(pSmi, VGA_DAC_DATA, crtcPriv->lut_g[i] >> 8);
6577104f784Smrg	VGAOUT8(pSmi, VGA_DAC_DATA, crtcPriv->lut_b[i] >> 8);
6587104f784Smrg    }
6597104f784Smrg
6607104f784Smrg    LEAVE();
6617104f784Smrg}
6627104f784Smrg
6637104f784Smrgstatic void
6647104f784SmrgSMILynx_CrtcLoadLUT_lcd(xf86CrtcPtr crtc)
6657104f784Smrg{
6667104f784Smrg    ENTER();
6677104f784Smrg
6687104f784Smrg    /* XXX - Is it possible to load LCD LUT in Virtual Refresh mode? */
6697104f784Smrg
6707104f784Smrg    LEAVE();
6717104f784Smrg}
6727104f784Smrg
6737104f784Smrgstatic void
6747104f784SmrgSMILynx_CrtcSetCursorColors_crt (xf86CrtcPtr crtc, int bg, int fg)
6757104f784Smrg{
6767104f784Smrg    ScrnInfoPtr pScrn = crtc->scrn;
6777104f784Smrg    SMIPtr pSmi = SMIPTR(pScrn);
6787104f784Smrg    CARD8 packedFG,packedBG;
6797104f784Smrg
6807104f784Smrg    ENTER();
6817104f784Smrg
6827104f784Smrg    /* Pack the true color into 8 bit */
6837104f784Smrg    packedFG = (fg & 0xE00000) >> 16 |
6847104f784Smrg	(fg & 0x00E000) >> 11 |
6857104f784Smrg	(fg & 0x0000C0) >> 6;
6867104f784Smrg    packedBG = (bg & 0xE00000) >> 16 |
6877104f784Smrg	(bg & 0x00E000) >> 11 |
6887104f784Smrg	(bg & 0x0000C0) >> 6;
6897104f784Smrg
6907104f784Smrg    /* Program the colors */
6917104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x8C, packedFG);
6927104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x8D, packedBG);
6937104f784Smrg
6947104f784Smrg    /* Program FPR copy when on the 730 */
6957104f784Smrg    if (pSmi->Chipset == SMI_COUGAR3DR) {
6967104f784Smrg	CARD32 fpr15c;
6977104f784Smrg
6987104f784Smrg	fpr15c  = READ_FPR(pSmi, FPR15C) & FPR15C_MASK_HWCADDREN;
6997104f784Smrg	fpr15c |= packedFG;
7007104f784Smrg	fpr15c |= packedBG << 8;
7017104f784Smrg	WRITE_FPR(pSmi, FPR15C, fpr15c);
7027104f784Smrg    }
7037104f784Smrg
7047104f784Smrg    LEAVE();
7057104f784Smrg}
7067104f784Smrg
7077104f784Smrgstatic void
7087104f784SmrgSMILynx_CrtcSetCursorPosition_crt (xf86CrtcPtr crtc, int x, int y)
7097104f784Smrg{
7107104f784Smrg    ScrnInfoPtr pScrn = crtc->scrn;
7117104f784Smrg    SMIPtr pSmi = SMIPTR(pScrn);
7127104f784Smrg
7137104f784Smrg    ENTER();
7147104f784Smrg
7157104f784Smrg    if (x >= 0) {
7167104f784Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x88,
7177104f784Smrg		      x & 0xFF);
7187104f784Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x89,
7197104f784Smrg		      (x >> 8) & 0x07);
7207104f784Smrg    }
7217104f784Smrg    else {
7227104f784Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x88,
7237104f784Smrg		      (-x) & (SMILYNX_MAX_CURSOR - 1));
7247104f784Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x89,
7257104f784Smrg		      0x08);
7267104f784Smrg    }
7277104f784Smrg
7287104f784Smrg    if (y >= 0) {
7297104f784Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x8A,
7307104f784Smrg		      y & 0xFF);
7317104f784Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x8B,
7327104f784Smrg		      (y >> 8) & 0x07);
7337104f784Smrg    }
7347104f784Smrg    else {
7357104f784Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x8A,
7367104f784Smrg			  (-y) & (SMILYNX_MAX_CURSOR - 1));
7377104f784Smrg	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA,
7387104f784Smrg		      0x8B, 0x08);
7397104f784Smrg    }
7407104f784Smrg
7417104f784Smrg    /* Program FPR copy when on the 730 */
7427104f784Smrg    if (pSmi->Chipset == SMI_COUGAR3DR) {
7437104f784Smrg	CARD32 fpr158;
7447104f784Smrg
7457104f784Smrg	if (x >= 0)
7467104f784Smrg	    fpr158 = (x & FPR158_MASK_MAXBITS) << 16;
7477104f784Smrg	else
7487104f784Smrg	    fpr158 = ((-x & FPR158_MASK_MAXBITS) |
7497104f784Smrg		      FPR158_MASK_BOUNDARY) << 16;
7507104f784Smrg
7517104f784Smrg	if (y >= 0)
7527104f784Smrg	    fpr158 |= y & FPR158_MASK_MAXBITS;
7537104f784Smrg	else
7547104f784Smrg	    fpr158 |= (-y & FPR158_MASK_MAXBITS) | FPR158_MASK_BOUNDARY;
7557104f784Smrg
7567104f784Smrg	/* Program combined coordinates */
7577104f784Smrg	WRITE_FPR(pSmi, FPR158, fpr158);
7587104f784Smrg    }
7597104f784Smrg
7607104f784Smrg    LEAVE();
7617104f784Smrg}
7627104f784Smrg
7637104f784Smrgstatic void
7647104f784SmrgSMILynx_CrtcShowCursor_crt (xf86CrtcPtr crtc)
7657104f784Smrg{
7667104f784Smrg    ScrnInfoPtr pScrn = crtc->scrn;
7677104f784Smrg    SMIPtr pSmi = SMIPTR(pScrn);
7687104f784Smrg    char tmp;
7697104f784Smrg
7707104f784Smrg    ENTER();
7717104f784Smrg
7727104f784Smrg    /* Show cursor */
7737104f784Smrg    tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81);
7747104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81, tmp | 0x80);
7757104f784Smrg
7767104f784Smrg    /* Program FPR copy when on the 730 */
7777104f784Smrg    if (pSmi->Chipset == SMI_COUGAR3DR) {
7787104f784Smrg	CARD32 fpr15c;
7797104f784Smrg
7807104f784Smrg	/* turn on the top bit */
7817104f784Smrg	fpr15c  = READ_FPR(pSmi, FPR15C);
7827104f784Smrg	fpr15c |= FPR15C_MASK_HWCENABLE;
7837104f784Smrg	WRITE_FPR(pSmi, FPR15C, fpr15c);
7847104f784Smrg    }
7857104f784Smrg
7867104f784Smrg    LEAVE();
7877104f784Smrg}
7887104f784Smrg
7897104f784Smrgstatic void
7907104f784SmrgSMILynx_CrtcHideCursor_crt (xf86CrtcPtr crtc)
7917104f784Smrg{
7927104f784Smrg    ScrnInfoPtr pScrn = crtc->scrn;
7937104f784Smrg    SMIPtr pSmi = SMIPTR(pScrn);
7947104f784Smrg    char tmp;
7957104f784Smrg
7967104f784Smrg    ENTER();
7977104f784Smrg
7987104f784Smrg    /* Hide cursor */
7997104f784Smrg    tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81);
8007104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81, tmp & ~0x80);
8017104f784Smrg
8027104f784Smrg    /* Program FPR copy when on the 730 */
8037104f784Smrg    if (pSmi->Chipset == SMI_COUGAR3DR) {
8047104f784Smrg	CARD32 fpr15c;
8057104f784Smrg
8067104f784Smrg	/* turn off the top bit */
8077104f784Smrg	fpr15c  = READ_FPR(pSmi, FPR15C);
8087104f784Smrg	fpr15c &= ~FPR15C_MASK_HWCENABLE;
8097104f784Smrg	WRITE_FPR(pSmi, FPR15C, fpr15c);
8107104f784Smrg    }
8117104f784Smrg
8127104f784Smrg
8137104f784Smrg    LEAVE();
8147104f784Smrg}
8157104f784Smrg
8167104f784Smrgstatic void
8177104f784SmrgSMILynx_CrtcLoadCursorImage_crt (xf86CrtcPtr crtc, CARD8 *image)
8187104f784Smrg{
8197104f784Smrg    ScrnInfoPtr pScrn = crtc->scrn;
8207104f784Smrg    SMIPtr pSmi = SMIPTR(pScrn);
8217104f784Smrg    CARD8 tmp;
8227104f784Smrg    int i;
8237104f784Smrg    CARD8* dst;
8247104f784Smrg
8257104f784Smrg    ENTER();
8267104f784Smrg
8277104f784Smrg    /* Load storage location. */
8287104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x80,
8297104f784Smrg		  pSmi->FBCursorOffset / 2048);
8307104f784Smrg    tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81) & 0x80;
8317104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81,
8327104f784Smrg		  tmp | ((pSmi->FBCursorOffset / 2048) >> 8));
8337104f784Smrg
8347104f784Smrg    /* Program FPR copy when on the 730 */
8357104f784Smrg    if (pSmi->Chipset == SMI_COUGAR3DR) {
8367104f784Smrg	CARD32 fpr15c;
8377104f784Smrg
8387104f784Smrg	/* put address in upper word, and disable the cursor */
8397104f784Smrg	fpr15c  = READ_FPR(pSmi, FPR15C) & FPR15C_MASK_HWCCOLORS;
8407104f784Smrg	fpr15c |= (pSmi->FBCursorOffset / 2048) << 16;
8417104f784Smrg	WRITE_FPR(pSmi, FPR15C, fpr15c);
8427104f784Smrg    }
8437104f784Smrg
8447104f784Smrg    /* Copy cursor image to framebuffer storage */
8457104f784Smrg    dst = pSmi->FBBase + pSmi->FBCursorOffset;
8467104f784Smrg    for(i=0; i < (SMILYNX_MAX_CURSOR * SMILYNX_MAX_CURSOR >> 2); i++){
8477104f784Smrg	*(dst++) = image[i];
8487104f784Smrg	if((i & 0x3) == 0x3) dst+=4;
8497104f784Smrg    }
8507104f784Smrg
8517104f784Smrg    LEAVE();
8527104f784Smrg}
8537104f784Smrg
8547104f784Smrgstatic void
8557104f784SmrgSMILynx_CrtcDPMS_crt(xf86CrtcPtr crtc, int mode)
8567104f784Smrg{
8577104f784Smrg    ScrnInfoPtr pScrn = crtc->scrn;
8587104f784Smrg    SMIPtr pSmi = SMIPTR(pScrn);
8597104f784Smrg    SMIRegPtr reg = pSmi->mode;
8607104f784Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
8617104f784Smrg
8627104f784Smrg    ENTER();
8637104f784Smrg
8647104f784Smrg    if(mode == DPMSModeOff)
8657104f784Smrg	reg->SR21 |= 0x88; /* Disable DAC and color palette RAM */
8667104f784Smrg    else
8677104f784Smrg	reg->SR21 &= ~0x88; /* Enable DAC and color palette RAM */
8687104f784Smrg
8697104f784Smrg    /* Wait for vertical retrace */
8707104f784Smrg    while (hwp->readST01(hwp) & 0x8) ;
8717104f784Smrg    while (!(hwp->readST01(hwp) & 0x8)) ;
8727104f784Smrg
8737104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, reg->SR21);
8747104f784Smrg
8757104f784Smrg    if(mode == DPMSModeOn){
8767104f784Smrg	/* Reload the LUT */
8777104f784Smrg	SMILynx_CrtcLoadLUT_crt(crtc);
8787104f784Smrg    }
8797104f784Smrg
8807104f784Smrg    LEAVE();
8817104f784Smrg}
8827104f784Smrg
8837104f784Smrgstatic void
8847104f784SmrgSMILynx_CrtcDPMS_lcd(xf86CrtcPtr crtc, int mode)
8857104f784Smrg{
8867104f784Smrg    ScrnInfoPtr pScrn = crtc->scrn;
8877104f784Smrg    SMIPtr pSmi = SMIPTR(pScrn);
8887104f784Smrg    SMIRegPtr reg = pSmi->mode;
8897104f784Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
8907104f784Smrg
8917104f784Smrg    ENTER();
8927104f784Smrg
8937104f784Smrg    if(mode == DPMSModeOff)
8947104f784Smrg	reg->SR31 &= ~0x80; /* Disable Virtual Refresh */
8957104f784Smrg    else
8967104f784Smrg	reg->SR31 |= 0x80; /* Enable Virtual Refresh */
8977104f784Smrg
8987104f784Smrg    /* Wait for vertical retrace */
8997104f784Smrg    while (hwp->readST01(hwp) & 0x8) ;
9007104f784Smrg    while (!(hwp->readST01(hwp) & 0x8)) ;
9017104f784Smrg
9027104f784Smrg    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, reg->SR31);
9037104f784Smrg
9047104f784Smrg    LEAVE();
9057104f784Smrg}
9067104f784Smrg
9077104f784SmrgBool
9087104f784SmrgSMILynx_CrtcPreInit(ScrnInfoPtr pScrn)
9097104f784Smrg{
9107104f784Smrg    SMIPtr pSmi = SMIPTR(pScrn);
9117104f784Smrg    xf86CrtcPtr crtc;
9127104f784Smrg    xf86CrtcFuncsPtr crtcFuncs;
9137104f784Smrg    SMICrtcPrivatePtr crtcPriv;
9147104f784Smrg
9157104f784Smrg    ENTER();
9167104f784Smrg
9177104f784Smrg    if(pSmi->Chipset == SMI_COUGAR3DR){
9187104f784Smrg	/* XXX - Looking at the datasheet, it seems trivial to add
9197104f784Smrg	   dualhead support for this chip... Little more than
9207104f784Smrg	   splitting the WRITE_FPR/WRITE_VPR calls in separate
9217104f784Smrg	   functions. Has someone access to this hardware? */
9227104f784Smrg
9237104f784Smrg	SMI_CrtcFuncsInit_base(&crtcFuncs, &crtcPriv);
9247104f784Smrg
9257104f784Smrg	if(pSmi->useBIOS){
9267104f784Smrg	    crtcFuncs->mode_set = SMILynx_CrtcModeSet_bios;
9277104f784Smrg	}else{
9287104f784Smrg	    crtcFuncs->dpms = SMILynx_CrtcDPMS_crt;
9297104f784Smrg	    crtcFuncs->mode_set = SMILynx_CrtcModeSet_vga;
9307104f784Smrg	}
9317104f784Smrg
9327104f784Smrg	crtcFuncs->mode_fixup = SMILynx_CrtcModeFixup;
9337104f784Smrg	crtcPriv->adjust_frame = SMILynx_CrtcAdjustFrame;
9347104f784Smrg	crtcPriv->video_init = SMI730_CrtcVideoInit;
9357104f784Smrg	crtcPriv->load_lut = SMILynx_CrtcLoadLUT_crt;
9367104f784Smrg
9377104f784Smrg	if(pSmi->HwCursor){
9387104f784Smrg	    crtcFuncs->set_cursor_colors = SMILynx_CrtcSetCursorColors_crt;
9397104f784Smrg	    crtcFuncs->set_cursor_position = SMILynx_CrtcSetCursorPosition_crt;
9407104f784Smrg	    crtcFuncs->show_cursor = SMILynx_CrtcShowCursor_crt;
9417104f784Smrg	    crtcFuncs->hide_cursor = SMILynx_CrtcHideCursor_crt;
9427104f784Smrg	    crtcFuncs->load_cursor_image = SMILynx_CrtcLoadCursorImage_crt;
9437104f784Smrg	}
9447104f784Smrg
9457104f784Smrg	if(! (crtc = xf86CrtcCreate(pScrn,crtcFuncs)))
9467104f784Smrg	    LEAVE(FALSE);
9477104f784Smrg	crtc->driver_private = crtcPriv;
9487104f784Smrg    }else{
9497104f784Smrg	/* CRTC0 can drive both outputs when virtual refresh is
9507104f784Smrg	   disabled, and only the VGA output with virtual refresh
9517104f784Smrg	   enabled. */
9527104f784Smrg	SMI_CrtcFuncsInit_base(&crtcFuncs, &crtcPriv);
9537104f784Smrg
9547104f784Smrg	if(pSmi->useBIOS){
9557104f784Smrg	    crtcFuncs->mode_set = SMILynx_CrtcModeSet_bios;
9567104f784Smrg	}else{
9577104f784Smrg	    crtcFuncs->dpms = SMILynx_CrtcDPMS_crt;
9587104f784Smrg
9597104f784Smrg	    if(pSmi->Dualhead){
9607104f784Smrg		/* The standard VGA CRTC registers get locked in
9617104f784Smrg		   virtual refresh mode. */
9627104f784Smrg		crtcFuncs->mode_set = SMILynx_CrtcModeSet_crt;
9637104f784Smrg
9647104f784Smrg	    }else{
9657104f784Smrg		crtcFuncs->mode_set = SMILynx_CrtcModeSet_vga;
9667104f784Smrg	    }
9677104f784Smrg	}
9687104f784Smrg
9697104f784Smrg	crtcFuncs->mode_fixup = SMILynx_CrtcModeFixup;
9707104f784Smrg	crtcPriv->adjust_frame = SMILynx_CrtcAdjustFrame;
9717104f784Smrg	crtcPriv->video_init = SMILynx_CrtcVideoInit_crt;
9727104f784Smrg	crtcPriv->load_lut = SMILynx_CrtcLoadLUT_crt;
9737104f784Smrg
9747104f784Smrg	if(pSmi->HwCursor){
9757104f784Smrg	    crtcFuncs->set_cursor_colors = SMILynx_CrtcSetCursorColors_crt;
9767104f784Smrg	    crtcFuncs->set_cursor_position = SMILynx_CrtcSetCursorPosition_crt;
9777104f784Smrg	    crtcFuncs->show_cursor = SMILynx_CrtcShowCursor_crt;
9787104f784Smrg	    crtcFuncs->hide_cursor = SMILynx_CrtcHideCursor_crt;
9797104f784Smrg	    crtcFuncs->load_cursor_image = SMILynx_CrtcLoadCursorImage_crt;
9807104f784Smrg	}
9817104f784Smrg
9827104f784Smrg	if(! (crtc = xf86CrtcCreate(pScrn,crtcFuncs)))
9837104f784Smrg	    LEAVE(FALSE);
9847104f784Smrg	crtc->driver_private = crtcPriv;
9857104f784Smrg
9867104f784Smrg	if(pSmi->Dualhead){
9877104f784Smrg	    /* CRTC1 drives LCD when enabled. */
9887104f784Smrg	    SMI_CrtcFuncsInit_base(&crtcFuncs, &crtcPriv);
9897104f784Smrg	    crtcFuncs->mode_set = SMILynx_CrtcModeSet_lcd;
9907104f784Smrg	    crtcFuncs->mode_fixup = SMILynx_CrtcModeFixup;
9917104f784Smrg	    crtcFuncs->dpms = SMILynx_CrtcDPMS_lcd;
9927104f784Smrg	    crtcPriv->adjust_frame = SMILynx_CrtcAdjustFrame;
9937104f784Smrg	    crtcPriv->video_init = SMILynx_CrtcVideoInit_lcd;
9947104f784Smrg	    crtcPriv->load_lut = SMILynx_CrtcLoadLUT_lcd;
9957104f784Smrg
9967104f784Smrg	    if(! (crtc = xf86CrtcCreate(pScrn,crtcFuncs)))
9977104f784Smrg		LEAVE(FALSE);
9987104f784Smrg	    crtc->driver_private = crtcPriv;
9997104f784Smrg	}
10007104f784Smrg    }
10017104f784Smrg
10027104f784Smrg    LEAVE(TRUE);
10037104f784Smrg}
10047104f784Smrg
1005