1/* 2 * SiS 300/540/630[S]/730[S] 3 * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX] 4 * XGI V3XT/V5/V8, Z7 5 * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3 6 * 7 * Linux kernel specific extensions to init.c/init301.c 8 * 9 * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria. 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the named License, 14 * or any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA 24 * 25 * Author: Thomas Winischhofer <thomas@winischhofer.net> 26 */ 27 28#include "osdef.h" 29#include "initdef.h" 30#include "vgatypes.h" 31#include "vstruct.h" 32 33#include <linux/version.h> 34#include <linux/types.h> 35#include <linux/fb.h> 36 37int sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, 38 unsigned char modeno, unsigned char rateindex); 39int sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno, 40 unsigned char rateindex, struct fb_var_screeninfo *var); 41bool sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, 42 int *htotal, int *vtotal, unsigned char rateindex); 43 44extern bool SiSInitPtr(struct SiS_Private *SiS_Pr); 45extern bool SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, 46 unsigned short *ModeIdIndex); 47extern void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, 48 int xres, int yres, struct fb_var_screeninfo *var, bool writeres); 49 50int 51sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, unsigned char modeno, 52 unsigned char rateindex) 53{ 54 unsigned short ModeNo = modeno; 55 unsigned short ModeIdIndex = 0, ClockIndex = 0; 56 unsigned short RRTI = 0; 57 int Clock; 58 59 if(!SiSInitPtr(SiS_Pr)) return 65000; 60 61 if(rateindex > 0) rateindex--; 62 63#ifdef SIS315H 64 switch(ModeNo) { 65 case 0x5a: ModeNo = 0x50; break; 66 case 0x5b: ModeNo = 0x56; 67 } 68#endif 69 70 if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) {; 71 printk(KERN_ERR "Could not find mode %x\n", ModeNo); 72 return 65000; 73 } 74 75 RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; 76 77 if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & HaveWideTiming) { 78 if(SiS_Pr->SiS_UseWide == 1) { 79 /* Wide screen: Ignore rateindex */ 80 ClockIndex = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRTVCLK_WIDE; 81 } else { 82 RRTI += rateindex; 83 ClockIndex = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRTVCLK_NORM; 84 } 85 } else { 86 RRTI += rateindex; 87 ClockIndex = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRTVCLK; 88 } 89 90 Clock = SiS_Pr->SiS_VCLKData[ClockIndex].CLOCK * 1000; 91 92 return Clock; 93} 94 95int 96sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno, 97 unsigned char rateindex, struct fb_var_screeninfo *var) 98{ 99 unsigned short ModeNo = modeno; 100 unsigned short ModeIdIndex = 0, index = 0, RRTI = 0; 101 int j; 102 103 if(!SiSInitPtr(SiS_Pr)) return 0; 104 105 if(rateindex > 0) rateindex--; 106 107#ifdef SIS315H 108 switch(ModeNo) { 109 case 0x5a: ModeNo = 0x50; break; 110 case 0x5b: ModeNo = 0x56; 111 } 112#endif 113 114 if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return 0; 115 116 RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; 117 if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & HaveWideTiming) { 118 if(SiS_Pr->SiS_UseWide == 1) { 119 /* Wide screen: Ignore rateindex */ 120 index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_WIDE; 121 } else { 122 RRTI += rateindex; 123 index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_NORM; 124 } 125 } else { 126 RRTI += rateindex; 127 index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC; 128 } 129 130 SiS_Generic_ConvertCRData(SiS_Pr, 131 (unsigned char *)&SiS_Pr->SiS_CRT1Table[index].CR[0], 132 SiS_Pr->SiS_RefIndex[RRTI].XRes, 133 SiS_Pr->SiS_RefIndex[RRTI].YRes, 134 var, false); 135 136 if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & 0x8000) 137 var->sync &= ~FB_SYNC_VERT_HIGH_ACT; 138 else 139 var->sync |= FB_SYNC_VERT_HIGH_ACT; 140 141 if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & 0x4000) 142 var->sync &= ~FB_SYNC_HOR_HIGH_ACT; 143 else 144 var->sync |= FB_SYNC_HOR_HIGH_ACT; 145 146 var->vmode = FB_VMODE_NONINTERLACED; 147 if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & 0x0080) 148 var->vmode = FB_VMODE_INTERLACED; 149 else { 150 j = 0; 151 while(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID != 0xff) { 152 if(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID == 153 SiS_Pr->SiS_RefIndex[RRTI].ModeID) { 154 if(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeFlag & DoubleScanMode) { 155 var->vmode = FB_VMODE_DOUBLE; 156 } 157 break; 158 } 159 j++; 160 } 161 } 162 163 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { 164 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { 165 var->upper_margin >>= 1; 166 var->lower_margin >>= 1; 167 var->vsync_len >>= 1; 168 } 169 170 return 1; 171} 172 173bool 174sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, int *htotal, 175 int *vtotal, unsigned char rateindex) 176{ 177 unsigned short ModeNo = modeno; 178 unsigned short ModeIdIndex = 0, CRT1Index = 0; 179 unsigned short RRTI = 0; 180 unsigned char sr_data, cr_data, cr_data2; 181 182 if(!SiSInitPtr(SiS_Pr)) return false; 183 184 if(rateindex > 0) rateindex--; 185 186#ifdef SIS315H 187 switch(ModeNo) { 188 case 0x5a: ModeNo = 0x50; break; 189 case 0x5b: ModeNo = 0x56; 190 } 191#endif 192 193 if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return false; 194 195 RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; 196 if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & HaveWideTiming) { 197 if(SiS_Pr->SiS_UseWide == 1) { 198 /* Wide screen: Ignore rateindex */ 199 CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_WIDE; 200 } else { 201 RRTI += rateindex; 202 CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_NORM; 203 } 204 } else { 205 RRTI += rateindex; 206 CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC; 207 } 208 209 sr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14]; 210 cr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[0]; 211 *htotal = (((cr_data & 0xff) | ((unsigned short) (sr_data & 0x03) << 8)) + 5) * 8; 212 213 sr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13]; 214 cr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[6]; 215 cr_data2 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7]; 216 *vtotal = ((cr_data & 0xFF) | 217 ((unsigned short)(cr_data2 & 0x01) << 8) | 218 ((unsigned short)(cr_data2 & 0x20) << 4) | 219 ((unsigned short)(sr_data & 0x01) << 10)) + 2; 220 221 if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & InterlaceMode) 222 *vtotal *= 2; 223 224 return true; 225} 226