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