Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-backlight
[linux-2.6] / drivers / video / sis / initextlfb.c
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
36 int             sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr,
37                         unsigned char modeno, unsigned char rateindex);
38 int             sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno,
39                         unsigned char rateindex, struct fb_var_screeninfo *var);
40 bool            sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno,
41                         int *htotal, int *vtotal, unsigned char rateindex);
42
43 extern bool     SiSInitPtr(struct SiS_Private *SiS_Pr);
44 extern bool     SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
45                         unsigned short *ModeIdIndex);
46 extern 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
49 int
50 sisfb_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
94 int
95 sisfb_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 #if 0  /* Do this? */
164        var->upper_margin <<= 1;
165        var->lower_margin <<= 1;
166        var->vsync_len <<= 1;
167 #endif
168     } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
169        var->upper_margin >>= 1;
170        var->lower_margin >>= 1;
171        var->vsync_len >>= 1;
172     }
173
174     return 1;
175 }
176
177 bool
178 sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, int *htotal,
179                         int *vtotal, unsigned char rateindex)
180 {
181     unsigned short ModeNo = modeno;
182     unsigned short ModeIdIndex = 0, CRT1Index = 0;
183     unsigned short RRTI = 0;
184     unsigned char  sr_data, cr_data, cr_data2;
185
186     if(!SiSInitPtr(SiS_Pr)) return false;
187
188     if(rateindex > 0) rateindex--;
189
190 #ifdef SIS315H
191     switch(ModeNo) {
192        case 0x5a: ModeNo = 0x50; break;
193        case 0x5b: ModeNo = 0x56;
194     }
195 #endif
196
197     if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return false;
198
199     RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
200     if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & HaveWideTiming) {
201        if(SiS_Pr->SiS_UseWide == 1) {
202           /* Wide screen: Ignore rateindex */
203           CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_WIDE;
204        } else {
205           RRTI += rateindex;
206           CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_NORM;
207        }
208     } else {
209        RRTI += rateindex;
210        CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC;
211     }
212
213     sr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14];
214     cr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[0];
215     *htotal = (((cr_data & 0xff) | ((unsigned short) (sr_data & 0x03) << 8)) + 5) * 8;
216
217     sr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13];
218     cr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[6];
219     cr_data2 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7];
220     *vtotal = ((cr_data & 0xFF) |
221                ((unsigned short)(cr_data2 & 0x01) <<  8) |
222                ((unsigned short)(cr_data2 & 0x20) <<  4) |
223                ((unsigned short)(sr_data  & 0x01) << 10)) + 2;
224
225     if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & InterlaceMode)
226        *vtotal *= 2;
227
228     return true;
229 }
230
231
232