summaryrefslogtreecommitdiff
path: root/src/smilynx_crtc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/smilynx_crtc.c')
-rw-r--r--src/smilynx_crtc.c557
1 files changed, 557 insertions, 0 deletions
diff --git a/src/smilynx_crtc.c b/src/smilynx_crtc.c
new file mode 100644
index 0000000..5166ea1
--- /dev/null
+++ b/src/smilynx_crtc.c
@@ -0,0 +1,557 @@
+/*
+Copyright (C) 1994-1999 The XFree86 Project, Inc. All Rights Reserved.
+Copyright (C) 2000 Silicon Motion, Inc. All Rights Reserved.
+Copyright (C) 2008 Francisco Jerez. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
+NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the names of The XFree86 Project and
+Silicon Motion shall not be used in advertising or otherwise to promote the
+sale, use or other dealings in this Software without prior written
+authorization from The XFree86 Project or Silicon Motion.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "smi.h"
+#include "smi_crtc.h"
+#include "smilynx.h"
+
+static void
+SMILynx_CrtcVideoInit_crt(xf86CrtcPtr crtc)
+{
+ ScrnInfoPtr pScrn=crtc->scrn;
+ SMIPtr pSmi = SMIPTR(pScrn);
+
+ ENTER();
+
+ switch (pScrn->bitsPerPixel) {
+ case 8:
+ WRITE_VPR(pSmi, 0x00, 0x00000000);
+ break;
+ case 16:
+ WRITE_VPR(pSmi, 0x00, 0x00020000);
+ break;
+ case 24:
+ WRITE_VPR(pSmi, 0x00, 0x00040000);
+ break;
+ case 32:
+ WRITE_VPR(pSmi, 0x00, 0x00030000);
+ break;
+ }
+
+ int pitch = (crtc->rotatedData? crtc->mode.HDisplay : pScrn->displayWidth) * pSmi->Bpp;
+ pitch = (pitch + 15) & ~15;
+
+ WRITE_VPR(pSmi, 0x10, (crtc->mode.HDisplay * pSmi->Bpp) >> 3 << 16 | pitch >> 3);
+
+ LEAVE();
+}
+
+static void
+SMILynx_CrtcVideoInit_lcd(xf86CrtcPtr crtc)
+{
+ ScrnInfoPtr pScrn=crtc->scrn;
+ SMIPtr pSmi = SMIPTR(pScrn);
+
+ ENTER();
+
+ /* Set display depth */
+ CARD8 SR31=VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX,VGA_SEQ_DATA,0x31);
+ if (pScrn->bitsPerPixel > 8)
+ SR31 |= 0x40; /* 16 bpp */
+ else
+ SR31 &= ~0x40; /* 8 bpp */
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX,VGA_SEQ_DATA,0x31,SR31);
+
+ CARD16 fifo_readoffset = (crtc->rotatedData? crtc->mode.HDisplay : pScrn->displayWidth) * pSmi->Bpp;
+ fifo_readoffset = ((fifo_readoffset + 15) & ~15) >> 3;
+
+ /* FIFO1 Read Offset */
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x44, fifo_readoffset & 0x000000FF);
+ /* FIFO2 Read Offset */
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4B, fifo_readoffset & 0x000000FF);
+ /* FIFO1/2 Read Offset overflow */
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4C, (((fifo_readoffset & 0x00000300) >> 8) << 2) |
+ (((fifo_readoffset & 0x00000300) >> 8) << 6));
+
+ /* FIFO Write Offset */
+ CARD16 fifo_writeoffset = crtc->mode.HDisplay * pSmi->Bpp >> 3;
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x48, fifo_writeoffset & 0x000000FF);
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x49, (fifo_writeoffset & 0x00000300) >> 8);
+
+ /* set FIFO levels */
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4A, 0x41);
+
+ LEAVE();
+}
+
+static void
+SMI730_CrtcVideoInit(xf86CrtcPtr crtc)
+{
+ ScrnInfoPtr pScrn=crtc->scrn;
+ SMIPtr pSmi = SMIPTR(pScrn);
+
+ ENTER();
+
+ switch (pScrn->bitsPerPixel) {
+ case 8:
+ WRITE_VPR(pSmi, 0x00, 0x00000000);
+ WRITE_FPR(pSmi, FPR00, 0x00080000);
+ break;
+ case 16:
+ WRITE_VPR(pSmi, 0x00, 0x00020000);
+ WRITE_FPR(pSmi, FPR00, 0x000A0000);
+ break;
+ case 24:
+ WRITE_VPR(pSmi, 0x00, 0x00040000);
+ WRITE_FPR(pSmi, FPR00, 0x000C0000);
+ break;
+ case 32:
+ WRITE_VPR(pSmi, 0x00, 0x00030000);
+ WRITE_FPR(pSmi, FPR00, 0x000B0000);
+ break;
+ }
+
+ int pitch = (crtc->rotatedData? crtc->mode.HDisplay : pScrn->displayWidth) * pSmi->Bpp;
+ pitch = (pitch + 15) & ~15;
+
+ WRITE_VPR(pSmi, 0x10, (crtc->mode.HDisplay * pSmi->Bpp) >> 3 << 16 | pitch >> 3);
+ WRITE_FPR(pSmi, FPR10, (crtc->mode.HDisplay * pSmi->Bpp) >> 3 << 16 | pitch >> 3);
+
+ LEAVE();
+}
+
+static void
+SMILynx_CrtcAdjustFrame(xf86CrtcPtr crtc, int x, int y)
+{
+ ScrnInfoPtr pScrn=crtc->scrn;
+ SMIPtr pSmi = SMIPTR(pScrn);
+ xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(pScrn);
+ CARD32 Base;
+
+ ENTER();
+
+ if(crtc->rotatedData)
+ Base = (char*)crtc->rotatedData - (char*)pSmi->FBBase;
+ else
+ Base = pSmi->FBOffset + (x + y * pScrn->displayWidth) * pSmi->Bpp;
+
+
+ if (SMI_LYNX3D_SERIES(pSmi->Chipset) ||
+ SMI_COUGAR_SERIES(pSmi->Chipset)) {
+ Base = (Base + 15) & ~15;
+ while ((Base % pSmi->Bpp) > 0) {
+ Base -= 16;
+ }
+ } else {
+ Base = (Base + 7) & ~7;
+ while ((Base % pSmi->Bpp) > 0)
+ Base -= 8;
+ }
+
+ Base >>= 3;
+
+ if(SMI_COUGAR_SERIES(pSmi->Chipset)){
+ WRITE_VPR(pSmi, 0x0C, Base);
+ WRITE_FPR(pSmi, FPR0C, Base);
+ }else{
+ if(pSmi->Dualhead && crtc == crtcConf->crtc[0]){
+ /* LCD */
+
+ /* FIFO1 read start address */
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x40,
+ (Base & 0x000000FF));
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x41,
+ ((Base & 0x0000FF00) >> 8));
+
+ /* FIFO2 read start address */
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x42,
+ (Base & 0x000000FF));
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x43,
+ ((Base & 0x0000FF00) >> 8));
+
+ /* FIFO1/2 read start address overflow */
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x45,
+ ((Base & 0x000F0000) >> 16) | (((Base & 0x000F0000) >> 16) << 4));
+ }else{
+ /* CRT or single head */
+ WRITE_VPR(pSmi, 0x0C, Base);
+ }
+ }
+
+ LEAVE();
+}
+
+static void
+SMILynx_CrtcModeSet_vga(xf86CrtcPtr crtc,
+ DisplayModePtr mode,
+ DisplayModePtr adjusted_mode,
+ int x, int y)
+{
+ ScrnInfoPtr pScrn=crtc->scrn;
+ SMIPtr pSmi = SMIPTR(pScrn);
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ vgaRegPtr vganew = &hwp->ModeReg;
+ CARD8 SR6C, SR6D;
+
+ ENTER();
+
+ /* Initialize Video Processor Registers */
+
+ SMICRTC(crtc)->video_init(crtc);
+ SMILynx_CrtcAdjustFrame(crtc, x,y);
+
+
+ /* Program the PLL */
+
+ /* calculate vclk1 */
+ if (SMI_LYNX_SERIES(pSmi->Chipset)) {
+ SMI_CommonCalcClock(pScrn->scrnIndex, mode->Clock,
+ 1, 1, 63, 0, 3,
+ pSmi->clockRange.minClock,
+ pSmi->clockRange.maxClock,
+ &SR6C, &SR6D);
+ } else {
+ SMI_CommonCalcClock(pScrn->scrnIndex, mode->Clock,
+ 1, 1, 63, 0, 1,
+ pSmi->clockRange.minClock,
+ pSmi->clockRange.maxClock,
+ &SR6C, &SR6D);
+ }
+
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6C, SR6C);
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6D, SR6D);
+
+
+ /* Adjust mode timings */
+
+ if (!vgaHWInit(pScrn, mode)) {
+ LEAVE();
+ return;
+ }
+
+ if ((mode->HDisplay == 640) && SMI_LYNXM_SERIES(pSmi->Chipset)) {
+ vganew->MiscOutReg &= ~0x0C;
+ } else {
+ vganew->MiscOutReg |= 0x0C;
+ }
+ vganew->MiscOutReg |= 0x20;
+
+ if(pSmi->Chipset != SMI_COUGAR3DR){
+ /* Enable LCD */
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31,
+ VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX,VGA_SEQ_DATA,0x31) | 0x01);
+ }
+
+ vgaHWRestore(pScrn, vganew, VGA_SR_MODE);
+
+ LEAVE();
+}
+
+static void
+SMILynx_CrtcModeSet_crt(xf86CrtcPtr crtc,
+ DisplayModePtr mode,
+ DisplayModePtr adjusted_mode,
+ int x, int y)
+{
+ ScrnInfoPtr pScrn=crtc->scrn;
+ SMIPtr pSmi = SMIPTR(pScrn);
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ int vgaIOBase = hwp->IOBase;
+ int vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET;
+ int vgaCRData = vgaIOBase + VGA_CRTC_DATA_OFFSET;
+ CARD8 SR6C, SR6D;
+
+ ENTER();
+
+ /* Initialize Video Processor Registers */
+
+ SMILynx_CrtcVideoInit_crt(crtc);
+ SMILynx_CrtcAdjustFrame(crtc, x,y);
+
+
+ /* Program the PLL */
+
+ /* calculate vclk1 */
+ if (SMI_LYNX_SERIES(pSmi->Chipset)) {
+ SMI_CommonCalcClock(pScrn->scrnIndex, mode->Clock,
+ 1, 1, 63, 0, 3,
+ pSmi->clockRange.minClock,
+ pSmi->clockRange.maxClock,
+ &SR6C, &SR6D);
+ } else {
+ SMI_CommonCalcClock(pScrn->scrnIndex, mode->Clock,
+ 1, 1, 63, 0, 1,
+ pSmi->clockRange.minClock,
+ pSmi->clockRange.maxClock,
+ &SR6C, &SR6D);
+ }
+
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6C, SR6C);
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6D, SR6D);
+
+
+ /* Adjust mode timings */
+ /* In virtual refresh mode, the CRT timings are controlled through
+ the shadow VGA registers */
+
+ /* Select primary set of shadow registers */
+ VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E,
+ VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E) & ~0x20);
+
+ unsigned long HTotal=(mode->CrtcHTotal>>3)-5;
+ unsigned long HDisplay=(mode->CrtcHDisplay>>3)-1;
+ unsigned long HBlankStart=(mode->CrtcHBlankStart>>3)-1;
+ unsigned long HBlankEnd=(mode->CrtcHBlankEnd>>3)-1;
+ unsigned long HSyncStart=mode->CrtcHSyncStart>>3;
+ unsigned long HSyncEnd=mode->CrtcHSyncEnd>>3;
+ unsigned long VTotal=mode->CrtcVTotal-2;
+ unsigned long VDisplay=mode->CrtcVDisplay-1;
+ unsigned long VBlankStart=mode->CrtcVBlankStart-1;
+ unsigned long VBlankEnd=mode->CrtcVBlankEnd-1;
+ unsigned long VSyncStart=mode->CrtcVSyncStart;
+ unsigned long VSyncEnd=mode->CrtcVSyncEnd;
+
+ if((mode->CrtcHBlankEnd >> 3) == (mode->CrtcHTotal >> 3)) HBlankEnd=0;
+ if(mode->CrtcVBlankEnd == mode->CrtcVTotal) VBlankEnd=0;
+
+ VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40, HTotal & 0xFF );
+ VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x41, HBlankStart & 0xFF);
+ VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x42, HBlankEnd & 0x1F);
+ VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x43, HSyncStart & 0xFF);
+ VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x44,
+ (HBlankEnd & 0x20) >> 5 << 7 |
+ (HSyncEnd & 0x1F) );
+ VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x45, VTotal & 0xFF );
+ VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x46, VBlankStart & 0xFF );
+ VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x47, VBlankEnd & 0xFF );
+ VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x48, VSyncStart & 0xFF );
+ VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x49, VSyncEnd & 0x0F );
+ VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x4A,
+ (VSyncStart & 0x200) >> 9 << 7 |
+ (VDisplay & 0x200) >> 9 << 6 |
+ (VTotal & 0x200) >> 9 << 5 |
+ (VBlankStart & 0x100) >> 8 << 3 |
+ (VSyncStart & 0x100) >> 8 << 2 |
+ (VDisplay & 0x100) >> 8 << 1 |
+ (VTotal & 0x100) >> 8 << 0 );
+ VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x4B,
+ ((mode->Flags & V_NVSYNC)?1:0) << 7 |
+ ((mode->Flags & V_NHSYNC)?1:0) << 6 |
+ (VBlankStart & 0x200) >> 9 << 5 );
+ VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x4C, HDisplay & 0xFF );
+ VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x4D, VDisplay & 0xFF );
+ VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33,
+ (HBlankEnd & 0xC0) >> 6 << 5 |
+ (VBlankEnd & 0x300) >> 8 << 3);
+
+ LEAVE();
+}
+
+static void
+SMILynx_CrtcModeSet_lcd(xf86CrtcPtr crtc,
+ DisplayModePtr mode,
+ DisplayModePtr adjusted_mode,
+ int x, int y)
+{
+ ScrnInfoPtr pScrn=crtc->scrn;
+ SMIPtr pSmi = SMIPTR(pScrn);
+ CARD8 SR6E, SR6F;
+
+ ENTER();
+
+ /* Initialize the flat panel video processor */
+
+ SMILynx_CrtcVideoInit_lcd(crtc);
+ SMILynx_CrtcAdjustFrame(crtc,x,y);
+
+
+ /* Program the PLL */
+
+ /* calculate vclk2 */
+ if (SMI_LYNX_SERIES(pSmi->Chipset)) {
+ SMI_CommonCalcClock(pScrn->scrnIndex, mode->Clock,
+ 1, 1, 63, 0, 3,
+ pSmi->clockRange.minClock,
+ pSmi->clockRange.maxClock,
+ &SR6E, &SR6F);
+ } else {
+ SMI_CommonCalcClock(pScrn->scrnIndex, mode->Clock,
+ 1, 1, 63, 0, 1,
+ pSmi->clockRange.minClock,
+ pSmi->clockRange.maxClock,
+ &SR6E, &SR6F);
+ }
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6E, SR6E);
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6F, SR6F);
+
+
+ /* Adjust mode timings */
+
+ unsigned long HTotal=(mode->CrtcHTotal>>3)-1;
+ unsigned long HDisplay=(mode->CrtcHDisplay>>3)-1;
+ unsigned long HSyncStart=(mode->CrtcHSyncStart>>3);
+ unsigned long VTotal=mode->CrtcVTotal-1;
+ unsigned long VDisplay=mode->CrtcVDisplay-1;
+ unsigned long VSyncStart=mode->CrtcVSyncStart-1;
+
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x50,
+ (VTotal & 0x700) >> 8 << 1 |
+ (HSyncStart & 0x100) >> 8 << 0);
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x51,
+ (VSyncStart & 0x700) >> 8 << 5 |
+ (VDisplay & 0x700) >> 8 << 2 |
+ (HDisplay & 0x100) >> 8 << 1 |
+ (HTotal & 0x100) >> 8 << 0);
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x52, HTotal & 0xFF);
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x53, HDisplay & 0xFF);
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x54, HSyncStart & 0xFF);
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x55, VTotal & 0xFF);
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x56, VDisplay & 0xFF);
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x57, VSyncStart & 0xFF);
+
+ /* XXX - Why is the polarity hardcoded here? */
+ CARD8 SR32=VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX,VGA_SEQ_DATA,0x32);
+ SR32 &= ~0x18;
+ if (mode->HDisplay == 800) {
+ SR32 |= 0x18;
+ }
+ if ((mode->HDisplay == 1024) && SMI_LYNXM_SERIES(pSmi->Chipset)) {
+ SR32 |= 0x18;
+ }
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX,VGA_SEQ_DATA,0x32,SR32);
+
+ /* XXX - sync pulse width? FPR5A */
+
+ LEAVE();
+}
+
+static void
+SMILynx_CrtcLoadLUT_crt(xf86CrtcPtr crtc)
+{
+ ScrnInfoPtr pScrn = crtc->scrn;
+ SMIPtr pSmi = SMIPTR(pScrn);
+ SMICrtcPrivatePtr crtcPriv = SMICRTC(crtc);
+ int i;
+
+ ENTER();
+
+ CARD8 SR66 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX,VGA_SEQ_DATA,0x66);
+
+ /* Write CRT RAM only */
+ VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX,VGA_SEQ_DATA,0x66,(SR66 & ~0x30) | 0x20);
+
+ for(i=0;i<256;i++){
+ VGAOUT8(pSmi, VGA_DAC_WRITE_ADDR, i);
+ VGAOUT8(pSmi, VGA_DAC_DATA, crtcPriv->lut_r[i] >> 8);
+ VGAOUT8(pSmi, VGA_DAC_DATA, crtcPriv->lut_g[i] >> 8);
+ VGAOUT8(pSmi, VGA_DAC_DATA, crtcPriv->lut_b[i] >> 8);
+ }
+
+
+ LEAVE();
+}
+
+static void
+SMILynx_CrtcLoadLUT_lcd(xf86CrtcPtr crtc)
+{
+ ENTER();
+
+ /* XXX - Is it possible to load LCD LUT in Virtual Refresh mode? */
+
+ LEAVE();
+}
+
+static xf86CrtcFuncsRec SMILynx_Crtc0Funcs;
+static SMICrtcPrivateRec SMILynx_Crtc0Priv;
+static xf86CrtcFuncsRec SMILynx_Crtc1Funcs;
+static SMICrtcPrivateRec SMILynx_Crtc1Priv;
+
+Bool
+SMILynx_CrtcPreInit(ScrnInfoPtr pScrn)
+{
+ SMIPtr pSmi = SMIPTR(pScrn);
+ xf86CrtcPtr crtc0=NULL;
+ xf86CrtcPtr crtc1=NULL;
+
+ ENTER();
+
+ if(pSmi->Chipset == SMI_COUGAR3DR){
+ /* XXX - Looking at the datasheet, it seems trivial to add
+ dualhead support for this chip... Little more than
+ splitting the WRITE_FPR/WRITE_VPR calls in separate
+ functions. Has someone access to this hardware? */
+
+ SMI_CrtcFuncsInit_base(&SMILynx_Crtc0Funcs, &SMILynx_Crtc0Priv);
+ SMILynx_Crtc0Funcs.mode_set = SMILynx_CrtcModeSet_vga;
+ SMILynx_Crtc0Priv.adjust_frame = SMILynx_CrtcAdjustFrame;
+ SMILynx_Crtc0Priv.video_init = SMI730_CrtcVideoInit;
+ SMILynx_Crtc0Priv.load_lut = SMILynx_CrtcLoadLUT_crt;
+
+ crtc0=xf86CrtcCreate(pScrn,&SMILynx_Crtc0Funcs);
+ if(!crtc0)
+ RETURN(FALSE);
+ crtc0->driver_private = &SMILynx_Crtc0Priv;
+ }else{
+ if(pSmi->Dualhead){
+ /* CRTC0 is LCD*/
+ SMI_CrtcFuncsInit_base(&SMILynx_Crtc0Funcs, &SMILynx_Crtc0Priv);
+ SMILynx_Crtc0Funcs.mode_set = SMILynx_CrtcModeSet_lcd;
+ SMILynx_Crtc0Priv.adjust_frame = SMILynx_CrtcAdjustFrame;
+ SMILynx_Crtc0Priv.video_init = SMILynx_CrtcVideoInit_lcd;
+ SMILynx_Crtc0Priv.load_lut = SMILynx_CrtcLoadLUT_lcd;
+
+ crtc0=xf86CrtcCreate(pScrn,&SMILynx_Crtc0Funcs);
+ if(!crtc0)
+ RETURN(FALSE);
+ crtc0->driver_private = &SMILynx_Crtc0Priv;
+
+ /* CRTC1 is CRT */
+ SMI_CrtcFuncsInit_base(&SMILynx_Crtc1Funcs, &SMILynx_Crtc1Priv);
+ SMILynx_Crtc1Funcs.mode_set = SMILynx_CrtcModeSet_crt;
+ SMILynx_Crtc1Priv.adjust_frame = SMILynx_CrtcAdjustFrame;
+ SMILynx_Crtc1Priv.video_init = SMILynx_CrtcVideoInit_crt;
+ SMILynx_Crtc1Priv.load_lut = SMILynx_CrtcLoadLUT_crt;
+
+ crtc1=xf86CrtcCreate(pScrn,&SMILynx_Crtc1Funcs);
+ if(!crtc1)
+ RETURN(FALSE);
+ crtc1->driver_private = &SMILynx_Crtc1Priv;
+
+ }else{
+ /* CRTC0 is LCD, but in standard refresh mode
+ it is controlled through the primary VGA registers */
+ SMI_CrtcFuncsInit_base(&SMILynx_Crtc0Funcs, &SMILynx_Crtc0Priv);
+ SMILynx_Crtc0Funcs.mode_set = SMILynx_CrtcModeSet_vga;
+ SMILynx_Crtc0Priv.adjust_frame = SMILynx_CrtcAdjustFrame;
+ SMILynx_Crtc0Priv.video_init = SMILynx_CrtcVideoInit_crt;
+ SMILynx_Crtc0Priv.load_lut = SMILynx_CrtcLoadLUT_crt;
+
+ crtc0=xf86CrtcCreate(pScrn,&SMILynx_Crtc0Funcs);
+ if(!crtc0)
+ RETURN(FALSE);
+ crtc0->driver_private = &SMILynx_Crtc0Priv;
+ }
+ }
+
+ RETURN(TRUE);
+}
+