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/types.h> 34#include <linux/fb.h> 35 36int sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, 37 unsigned char modeno, unsigned char rateindex); 38int sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno, 39 unsigned char rateindex, struct fb_var_screeninfo *var); 40bool sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, 41 int *htotal, int *vtotal, unsigned char rateindex); 42 43extern bool SiSInitPtr(struct SiS_Private *SiS_Pr); 44extern bool SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, 45 unsigned short *ModeIdIndex); 46extern void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, 47 int xres, int yres, struct fb_var_screeninfo *var, bool writeres); 48 49int 50sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, unsigned char modeno, 51 unsigned char rateindex) 52{ 53 unsigned short ModeNo = modeno; 54 unsigned short ModeIdIndex = 0, ClockIndex = 0; 55 unsigned short RRTI = 0; 56 int Clock; 57 58 if(!SiSInitPtr(SiS_Pr)) return 65000; 59 60 if(rateindex > 0) rateindex--; 61 62#ifdef SIS315H 63 switch(ModeNo) { 64 case 0x5a: ModeNo = 0x50; break; 65 case 0x5b: ModeNo = 0x56; 66 } 67#endif 68 69 if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) {; 70 printk(KERN_ERR "Could not find mode %x\n", ModeNo); 71 return 65000; 72 } 73 74 RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; 75 76 if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & HaveWideTiming) { 77 if(SiS_Pr->SiS_UseWide == 1) { 78 /* Wide screen: Ignore rateindex */ 79 ClockIndex = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRTVCLK_WIDE; 80 } else { 81 RRTI += rateindex; 82 ClockIndex = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRTVCLK_NORM; 83 } 84 } else { 85 RRTI += rateindex; 86 ClockIndex = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRTVCLK; 87 } 88 89 Clock = SiS_Pr->SiS_VCLKData[ClockIndex].CLOCK * 1000; 90 91 return Clock; 92} 93 94int 95sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno, 96 unsigned char rateindex, struct fb_var_screeninfo *var) 97{ 98 unsigned short ModeNo = modeno; 99 unsigned short ModeIdIndex = 0, index = 0, RRTI = 0; 100 int j; 101 102 if(!SiSInitPtr(SiS_Pr)) return 0; 103 104 if(rateindex > 0) rateindex--; 105 106#ifdef SIS315H 107 switch(ModeNo) { 108 case 0x5a: ModeNo = 0x50; break; 109 case 0x5b: ModeNo = 0x56; 110 } 111#endif 112 113 if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return 0; 114 115 RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; 116 if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & HaveWideTiming) { 117 if(SiS_Pr->SiS_UseWide == 1) { 118 /* Wide screen: Ignore rateindex */ 119 index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_WIDE; 120 } else { 121 RRTI += rateindex; 122 index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_NORM; 123 } 124 } else { 125 RRTI += rateindex; 126 index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC; 127 } 128 129 SiS_Generic_ConvertCRData(SiS_Pr, 130 (unsigned char *)&SiS_Pr->SiS_CRT1Table[index].CR[0], 131 SiS_Pr->SiS_RefIndex[RRTI].XRes, 132 SiS_Pr->SiS_RefIndex[RRTI].YRes, 133 var, false); 134 135 if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & 0x8000) 136 var->sync &= ~FB_SYNC_VERT_HIGH_ACT; 137 else 138 var->sync |= FB_SYNC_VERT_HIGH_ACT; 139 140 if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & 0x4000) 141 var->sync &= ~FB_SYNC_HOR_HIGH_ACT; 142 else 143 var->sync |= FB_SYNC_HOR_HIGH_ACT; 144 145 var->vmode = FB_VMODE_NONINTERLACED; 146 if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & 0x0080) 147 var->vmode = FB_VMODE_INTERLACED; 148 else { 149 j = 0; 150 while(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID != 0xff) { 151 if(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID == 152 SiS_Pr->SiS_RefIndex[RRTI].ModeID) { 153 if(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeFlag & DoubleScanMode) { 154 var->vmode = FB_VMODE_DOUBLE; 155 } 156 break; 157 } 158 j++; 159 } 160 } 161 162 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { 163 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { 164 var->upper_margin >>= 1; 165 var->lower_margin >>= 1; 166 var->vsync_len >>= 1; 167 } 168 169 return 1; 170} 171 172bool 173sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, int *htotal, 174 int *vtotal, unsigned char rateindex) 175{ 176 unsigned short ModeNo = modeno; 177 unsigned short ModeIdIndex = 0, CRT1Index = 0; 178 unsigned short RRTI = 0; 179 unsigned char sr_data, cr_data, cr_data2; 180 181 if(!SiSInitPtr(SiS_Pr)) return false; 182 183 if(rateindex > 0) rateindex--; 184 185#ifdef SIS315H 186 switch(ModeNo) { 187 case 0x5a: ModeNo = 0x50; break; 188 case 0x5b: ModeNo = 0x56; 189 } 190#endif 191 192 if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return false; 193 194 RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; 195 if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & HaveWideTiming) { 196 if(SiS_Pr->SiS_UseWide == 1) { 197 /* Wide screen: Ignore rateindex */ 198 CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_WIDE; 199 } else { 200 RRTI += rateindex; 201 CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_NORM; 202 } 203 } else { 204 RRTI += rateindex; 205 CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC; 206 } 207 208 sr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14]; 209 cr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[0]; 210 *htotal = (((cr_data & 0xff) | ((unsigned short) (sr_data & 0x03) << 8)) + 5) * 8; 211 212 sr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13]; 213 cr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[6]; 214 cr_data2 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7]; 215 *vtotal = ((cr_data & 0xFF) | 216 ((unsigned short)(cr_data2 & 0x01) << 8) | 217 ((unsigned short)(cr_data2 & 0x20) << 4) | 218 ((unsigned short)(sr_data & 0x01) << 10)) + 2; 219 220 if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & InterlaceMode) 221 *vtotal *= 2; 222 223 return true; 224} 225