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