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: &ModeNo, ModeIdIndex: &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: &ModeNo, ModeIdIndex: &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 | crdata: (unsigned char *)&SiS_Pr->SiS_CRT1Table[index].CR[0], |
117 | xres: SiS_Pr->SiS_RefIndex[RRTI].XRes, |
118 | yres: SiS_Pr->SiS_RefIndex[RRTI].YRes, |
119 | var, writeres: 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: &ModeNo, ModeIdIndex: &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 | |