summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev/sis/initextlfb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/fbdev/sis/initextlfb.c')
-rw-r--r--drivers/video/fbdev/sis/initextlfb.c231
1 files changed, 231 insertions, 0 deletions
diff --git a/drivers/video/fbdev/sis/initextlfb.c b/drivers/video/fbdev/sis/initextlfb.c
new file mode 100644
index 000000000000..3ab18f5a3759
--- /dev/null
+++ b/drivers/video/fbdev/sis/initextlfb.c
@@ -0,0 +1,231 @@
+/*
+ * SiS 300/540/630[S]/730[S]
+ * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX]
+ * XGI V3XT/V5/V8, Z7
+ * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
+ *
+ * Linux kernel specific extensions to init.c/init301.c
+ *
+ * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the named License,
+ * or any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ */
+
+#include "initdef.h"
+#include "vgatypes.h"
+#include "vstruct.h"
+
+#include <linux/types.h>
+#include <linux/fb.h>
+
+int sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr,
+ unsigned char modeno, unsigned char rateindex);
+int sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno,
+ unsigned char rateindex, struct fb_var_screeninfo *var);
+bool sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno,
+ int *htotal, int *vtotal, unsigned char rateindex);
+
+extern bool SiSInitPtr(struct SiS_Private *SiS_Pr);
+extern bool SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
+ unsigned short *ModeIdIndex);
+extern void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata,
+ int xres, int yres, struct fb_var_screeninfo *var, bool writeres);
+
+int
+sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, unsigned char modeno,
+ unsigned char rateindex)
+{
+ unsigned short ModeNo = modeno;
+ unsigned short ModeIdIndex = 0, ClockIndex = 0;
+ unsigned short RRTI = 0;
+ int Clock;
+
+ if(!SiSInitPtr(SiS_Pr)) return 65000;
+
+ if(rateindex > 0) rateindex--;
+
+#ifdef CONFIG_FB_SIS_315
+ switch(ModeNo) {
+ case 0x5a: ModeNo = 0x50; break;
+ case 0x5b: ModeNo = 0x56;
+ }
+#endif
+
+ if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) {
+ printk(KERN_ERR "Could not find mode %x\n", ModeNo);
+ return 65000;
+ }
+
+ RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
+
+ if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & HaveWideTiming) {
+ if(SiS_Pr->SiS_UseWide == 1) {
+ /* Wide screen: Ignore rateindex */
+ ClockIndex = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRTVCLK_WIDE;
+ } else {
+ RRTI += rateindex;
+ ClockIndex = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRTVCLK_NORM;
+ }
+ } else {
+ RRTI += rateindex;
+ ClockIndex = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRTVCLK;
+ }
+
+ Clock = SiS_Pr->SiS_VCLKData[ClockIndex].CLOCK * 1000;
+
+ return Clock;
+}
+
+int
+sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno,
+ unsigned char rateindex, struct fb_var_screeninfo *var)
+{
+ unsigned short ModeNo = modeno;
+ unsigned short ModeIdIndex = 0, index = 0, RRTI = 0;
+ int j;
+
+ if(!SiSInitPtr(SiS_Pr)) return 0;
+
+ if(rateindex > 0) rateindex--;
+
+#ifdef CONFIG_FB_SIS_315
+ switch(ModeNo) {
+ case 0x5a: ModeNo = 0x50; break;
+ case 0x5b: ModeNo = 0x56;
+ }
+#endif
+
+ if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return 0;
+
+ RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
+ if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & HaveWideTiming) {
+ if(SiS_Pr->SiS_UseWide == 1) {
+ /* Wide screen: Ignore rateindex */
+ index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_WIDE;
+ } else {
+ RRTI += rateindex;
+ index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_NORM;
+ }
+ } else {
+ RRTI += rateindex;
+ index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC;
+ }
+
+ SiS_Generic_ConvertCRData(SiS_Pr,
+ (unsigned char *)&SiS_Pr->SiS_CRT1Table[index].CR[0],
+ SiS_Pr->SiS_RefIndex[RRTI].XRes,
+ SiS_Pr->SiS_RefIndex[RRTI].YRes,
+ var, false);
+
+ if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & 0x8000)
+ var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
+ else
+ var->sync |= FB_SYNC_VERT_HIGH_ACT;
+
+ if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & 0x4000)
+ var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
+ else
+ var->sync |= FB_SYNC_HOR_HIGH_ACT;
+
+ var->vmode = FB_VMODE_NONINTERLACED;
+ if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & 0x0080)
+ var->vmode = FB_VMODE_INTERLACED;
+ else {
+ j = 0;
+ while(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID != 0xff) {
+ if(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID ==
+ SiS_Pr->SiS_RefIndex[RRTI].ModeID) {
+ if(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeFlag & DoubleScanMode) {
+ var->vmode = FB_VMODE_DOUBLE;
+ }
+ break;
+ }
+ j++;
+ }
+ }
+
+ if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+#if 0 /* Do this? */
+ var->upper_margin <<= 1;
+ var->lower_margin <<= 1;
+ var->vsync_len <<= 1;
+#endif
+ } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+ var->upper_margin >>= 1;
+ var->lower_margin >>= 1;
+ var->vsync_len >>= 1;
+ }
+
+ return 1;
+}
+
+bool
+sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, int *htotal,
+ int *vtotal, unsigned char rateindex)
+{
+ unsigned short ModeNo = modeno;
+ unsigned short ModeIdIndex = 0, CRT1Index = 0;
+ unsigned short RRTI = 0;
+ unsigned char sr_data, cr_data, cr_data2;
+
+ if(!SiSInitPtr(SiS_Pr)) return false;
+
+ if(rateindex > 0) rateindex--;
+
+#ifdef CONFIG_FB_SIS_315
+ switch(ModeNo) {
+ case 0x5a: ModeNo = 0x50; break;
+ case 0x5b: ModeNo = 0x56;
+ }
+#endif
+
+ if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return false;
+
+ RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
+ if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & HaveWideTiming) {
+ if(SiS_Pr->SiS_UseWide == 1) {
+ /* Wide screen: Ignore rateindex */
+ CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_WIDE;
+ } else {
+ RRTI += rateindex;
+ CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_NORM;
+ }
+ } else {
+ RRTI += rateindex;
+ CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC;
+ }
+
+ sr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14];
+ cr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[0];
+ *htotal = (((cr_data & 0xff) | ((unsigned short) (sr_data & 0x03) << 8)) + 5) * 8;
+
+ sr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13];
+ cr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[6];
+ cr_data2 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7];
+ *vtotal = ((cr_data & 0xFF) |
+ ((unsigned short)(cr_data2 & 0x01) << 8) |
+ ((unsigned short)(cr_data2 & 0x20) << 4) |
+ ((unsigned short)(sr_data & 0x01) << 10)) + 2;
+
+ if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & InterlaceMode)
+ *vtotal *= 2;
+
+ return true;
+}
+
+
+