1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * SiS 300/540/630[S]/730[S],
4*4882a593Smuzhiyun * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX],
5*4882a593Smuzhiyun * XGI V3XT/V5/V8, Z7
6*4882a593Smuzhiyun * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria.
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * Author: Thomas Winischhofer <thomas@winischhofer.net>
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * Author of (practically wiped) code base:
13*4882a593Smuzhiyun * SiS (www.sis.com)
14*4882a593Smuzhiyun * Copyright (C) 1999 Silicon Integrated Systems, Inc.
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * See http://www.winischhofer.net/ for more information and updates
17*4882a593Smuzhiyun *
18*4882a593Smuzhiyun * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver,
19*4882a593Smuzhiyun * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
20*4882a593Smuzhiyun */
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #include <linux/module.h>
23*4882a593Smuzhiyun #include <linux/moduleparam.h>
24*4882a593Smuzhiyun #include <linux/kernel.h>
25*4882a593Smuzhiyun #include <linux/spinlock.h>
26*4882a593Smuzhiyun #include <linux/errno.h>
27*4882a593Smuzhiyun #include <linux/string.h>
28*4882a593Smuzhiyun #include <linux/mm.h>
29*4882a593Smuzhiyun #include <linux/screen_info.h>
30*4882a593Smuzhiyun #include <linux/slab.h>
31*4882a593Smuzhiyun #include <linux/fb.h>
32*4882a593Smuzhiyun #include <linux/selection.h>
33*4882a593Smuzhiyun #include <linux/ioport.h>
34*4882a593Smuzhiyun #include <linux/init.h>
35*4882a593Smuzhiyun #include <linux/pci.h>
36*4882a593Smuzhiyun #include <linux/vmalloc.h>
37*4882a593Smuzhiyun #include <linux/capability.h>
38*4882a593Smuzhiyun #include <linux/fs.h>
39*4882a593Smuzhiyun #include <linux/types.h>
40*4882a593Smuzhiyun #include <linux/uaccess.h>
41*4882a593Smuzhiyun #include <asm/io.h>
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun #include "sis.h"
44*4882a593Smuzhiyun #include "sis_main.h"
45*4882a593Smuzhiyun #include "init301.h"
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun #if !defined(CONFIG_FB_SIS_300) && !defined(CONFIG_FB_SIS_315)
48*4882a593Smuzhiyun #warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set
49*4882a593Smuzhiyun #warning sisfb will not work!
50*4882a593Smuzhiyun #endif
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun /* ---------------------- Prototypes ------------------------- */
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun /* Interface used by the world */
55*4882a593Smuzhiyun #ifndef MODULE
56*4882a593Smuzhiyun static int sisfb_setup(char *options);
57*4882a593Smuzhiyun #endif
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun /* Interface to the low level console driver */
60*4882a593Smuzhiyun static int sisfb_init(void);
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun /* fbdev routines */
63*4882a593Smuzhiyun static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
64*4882a593Smuzhiyun struct fb_info *info);
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
67*4882a593Smuzhiyun unsigned long arg);
68*4882a593Smuzhiyun static int sisfb_set_par(struct fb_info *info);
69*4882a593Smuzhiyun static int sisfb_blank(int blank,
70*4882a593Smuzhiyun struct fb_info *info);
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun static void sisfb_handle_command(struct sis_video_info *ivideo,
73*4882a593Smuzhiyun struct sisfb_cmd *sisfb_command);
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun static void sisfb_search_mode(char *name, bool quiet);
76*4882a593Smuzhiyun static int sisfb_validate_mode(struct sis_video_info *ivideo, int modeindex, u32 vbflags);
77*4882a593Smuzhiyun static u8 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate,
78*4882a593Smuzhiyun int index);
79*4882a593Smuzhiyun static int sisfb_setcolreg(unsigned regno, unsigned red, unsigned green,
80*4882a593Smuzhiyun unsigned blue, unsigned transp,
81*4882a593Smuzhiyun struct fb_info *fb_info);
82*4882a593Smuzhiyun static int sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
83*4882a593Smuzhiyun struct fb_info *info);
84*4882a593Smuzhiyun static void sisfb_pre_setmode(struct sis_video_info *ivideo);
85*4882a593Smuzhiyun static void sisfb_post_setmode(struct sis_video_info *ivideo);
86*4882a593Smuzhiyun static bool sisfb_CheckVBRetrace(struct sis_video_info *ivideo);
87*4882a593Smuzhiyun static bool sisfbcheckvretracecrt2(struct sis_video_info *ivideo);
88*4882a593Smuzhiyun static bool sisfbcheckvretracecrt1(struct sis_video_info *ivideo);
89*4882a593Smuzhiyun static bool sisfb_bridgeisslave(struct sis_video_info *ivideo);
90*4882a593Smuzhiyun static void sisfb_detect_VB_connect(struct sis_video_info *ivideo);
91*4882a593Smuzhiyun static void sisfb_get_VB_type(struct sis_video_info *ivideo);
92*4882a593Smuzhiyun static void sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val);
93*4882a593Smuzhiyun static void sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val);
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun /* Internal heap routines */
96*4882a593Smuzhiyun static int sisfb_heap_init(struct sis_video_info *ivideo);
97*4882a593Smuzhiyun static struct SIS_OH * sisfb_poh_new_node(struct SIS_HEAP *memheap);
98*4882a593Smuzhiyun static struct SIS_OH * sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size);
99*4882a593Smuzhiyun static void sisfb_delete_node(struct SIS_OH *poh);
100*4882a593Smuzhiyun static void sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh);
101*4882a593Smuzhiyun static struct SIS_OH * sisfb_poh_free(struct SIS_HEAP *memheap, u32 base);
102*4882a593Smuzhiyun static void sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh);
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun /* ------------------ Internal helper routines ----------------- */
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun static void __init
sisfb_setdefaultparms(void)108*4882a593Smuzhiyun sisfb_setdefaultparms(void)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun sisfb_off = 0;
111*4882a593Smuzhiyun sisfb_parm_mem = 0;
112*4882a593Smuzhiyun sisfb_accel = -1;
113*4882a593Smuzhiyun sisfb_ypan = -1;
114*4882a593Smuzhiyun sisfb_max = -1;
115*4882a593Smuzhiyun sisfb_userom = -1;
116*4882a593Smuzhiyun sisfb_useoem = -1;
117*4882a593Smuzhiyun sisfb_mode_idx = -1;
118*4882a593Smuzhiyun sisfb_parm_rate = -1;
119*4882a593Smuzhiyun sisfb_crt1off = 0;
120*4882a593Smuzhiyun sisfb_forcecrt1 = -1;
121*4882a593Smuzhiyun sisfb_crt2type = -1;
122*4882a593Smuzhiyun sisfb_crt2flags = 0;
123*4882a593Smuzhiyun sisfb_pdc = 0xff;
124*4882a593Smuzhiyun sisfb_pdca = 0xff;
125*4882a593Smuzhiyun sisfb_scalelcd = -1;
126*4882a593Smuzhiyun sisfb_specialtiming = CUT_NONE;
127*4882a593Smuzhiyun sisfb_lvdshl = -1;
128*4882a593Smuzhiyun sisfb_dstn = 0;
129*4882a593Smuzhiyun sisfb_fstn = 0;
130*4882a593Smuzhiyun sisfb_tvplug = -1;
131*4882a593Smuzhiyun sisfb_tvstd = -1;
132*4882a593Smuzhiyun sisfb_tvxposoffset = 0;
133*4882a593Smuzhiyun sisfb_tvyposoffset = 0;
134*4882a593Smuzhiyun sisfb_nocrt2rate = 0;
135*4882a593Smuzhiyun #if !defined(__i386__) && !defined(__x86_64__)
136*4882a593Smuzhiyun sisfb_resetcard = 0;
137*4882a593Smuzhiyun sisfb_videoram = 0;
138*4882a593Smuzhiyun #endif
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun /* ------------- Parameter parsing -------------- */
142*4882a593Smuzhiyun
sisfb_search_vesamode(unsigned int vesamode,bool quiet)143*4882a593Smuzhiyun static void sisfb_search_vesamode(unsigned int vesamode, bool quiet)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun int i = 0, j = 0;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun /* We don't know the hardware specs yet and there is no ivideo */
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun if(vesamode == 0) {
150*4882a593Smuzhiyun if(!quiet)
151*4882a593Smuzhiyun printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun sisfb_mode_idx = DEFAULT_MODE;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun return;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun while(sisbios_mode[i++].mode_no[0] != 0) {
161*4882a593Smuzhiyun if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
162*4882a593Smuzhiyun (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
163*4882a593Smuzhiyun if(sisfb_fstn) {
164*4882a593Smuzhiyun if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
165*4882a593Smuzhiyun sisbios_mode[i-1].mode_no[1] == 0x56 ||
166*4882a593Smuzhiyun sisbios_mode[i-1].mode_no[1] == 0x53)
167*4882a593Smuzhiyun continue;
168*4882a593Smuzhiyun } else {
169*4882a593Smuzhiyun if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
170*4882a593Smuzhiyun sisbios_mode[i-1].mode_no[1] == 0x5b)
171*4882a593Smuzhiyun continue;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun sisfb_mode_idx = i - 1;
174*4882a593Smuzhiyun j = 1;
175*4882a593Smuzhiyun break;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun if((!j) && !quiet)
179*4882a593Smuzhiyun printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
sisfb_search_mode(char * name,bool quiet)182*4882a593Smuzhiyun static void sisfb_search_mode(char *name, bool quiet)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
185*4882a593Smuzhiyun int i = 0;
186*4882a593Smuzhiyun char strbuf[16], strbuf1[20];
187*4882a593Smuzhiyun char *nameptr = name;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun /* We don't know the hardware specs yet and there is no ivideo */
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun if(name == NULL) {
192*4882a593Smuzhiyun if(!quiet)
193*4882a593Smuzhiyun printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun sisfb_mode_idx = DEFAULT_MODE;
196*4882a593Smuzhiyun return;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun if(!strncasecmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
200*4882a593Smuzhiyun if(!quiet)
201*4882a593Smuzhiyun printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun sisfb_mode_idx = DEFAULT_MODE;
204*4882a593Smuzhiyun return;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun if(strlen(name) <= 19) {
208*4882a593Smuzhiyun strcpy(strbuf1, name);
209*4882a593Smuzhiyun for(i = 0; i < strlen(strbuf1); i++) {
210*4882a593Smuzhiyun if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun /* This does some fuzzy mode naming detection */
214*4882a593Smuzhiyun if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
215*4882a593Smuzhiyun if((rate <= 32) || (depth > 32)) {
216*4882a593Smuzhiyun j = rate; rate = depth; depth = j;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
219*4882a593Smuzhiyun nameptr = strbuf;
220*4882a593Smuzhiyun sisfb_parm_rate = rate;
221*4882a593Smuzhiyun } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
222*4882a593Smuzhiyun sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
223*4882a593Smuzhiyun nameptr = strbuf;
224*4882a593Smuzhiyun } else {
225*4882a593Smuzhiyun xres = 0;
226*4882a593Smuzhiyun if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
227*4882a593Smuzhiyun sprintf(strbuf, "%ux%ux8", xres, yres);
228*4882a593Smuzhiyun nameptr = strbuf;
229*4882a593Smuzhiyun } else {
230*4882a593Smuzhiyun sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
231*4882a593Smuzhiyun return;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun i = 0; j = 0;
237*4882a593Smuzhiyun while(sisbios_mode[i].mode_no[0] != 0) {
238*4882a593Smuzhiyun if(!strncasecmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
239*4882a593Smuzhiyun if(sisfb_fstn) {
240*4882a593Smuzhiyun if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
241*4882a593Smuzhiyun sisbios_mode[i-1].mode_no[1] == 0x56 ||
242*4882a593Smuzhiyun sisbios_mode[i-1].mode_no[1] == 0x53)
243*4882a593Smuzhiyun continue;
244*4882a593Smuzhiyun } else {
245*4882a593Smuzhiyun if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
246*4882a593Smuzhiyun sisbios_mode[i-1].mode_no[1] == 0x5b)
247*4882a593Smuzhiyun continue;
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun sisfb_mode_idx = i - 1;
250*4882a593Smuzhiyun j = 1;
251*4882a593Smuzhiyun break;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun if((!j) && !quiet)
256*4882a593Smuzhiyun printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun #ifndef MODULE
sisfb_get_vga_mode_from_kernel(void)260*4882a593Smuzhiyun static void sisfb_get_vga_mode_from_kernel(void)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun #ifdef CONFIG_X86
263*4882a593Smuzhiyun char mymode[32];
264*4882a593Smuzhiyun int mydepth = screen_info.lfb_depth;
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
269*4882a593Smuzhiyun (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
270*4882a593Smuzhiyun (mydepth >= 8) && (mydepth <= 32) ) {
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun if(mydepth == 24) mydepth = 32;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
275*4882a593Smuzhiyun screen_info.lfb_height,
276*4882a593Smuzhiyun mydepth);
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun printk(KERN_DEBUG
279*4882a593Smuzhiyun "sisfb: Using vga mode %s pre-set by kernel as default\n",
280*4882a593Smuzhiyun mymode);
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun sisfb_search_mode(mymode, true);
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun #endif
285*4882a593Smuzhiyun return;
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun #endif
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun static void __init
sisfb_search_crt2type(const char * name)290*4882a593Smuzhiyun sisfb_search_crt2type(const char *name)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun int i = 0;
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun /* We don't know the hardware specs yet and there is no ivideo */
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun if(name == NULL) return;
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun while(sis_crt2type[i].type_no != -1) {
299*4882a593Smuzhiyun if(!strncasecmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
300*4882a593Smuzhiyun sisfb_crt2type = sis_crt2type[i].type_no;
301*4882a593Smuzhiyun sisfb_tvplug = sis_crt2type[i].tvplug_no;
302*4882a593Smuzhiyun sisfb_crt2flags = sis_crt2type[i].flags;
303*4882a593Smuzhiyun break;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun i++;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
309*4882a593Smuzhiyun sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun if(sisfb_crt2type < 0)
312*4882a593Smuzhiyun printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun static void __init
sisfb_search_tvstd(const char * name)316*4882a593Smuzhiyun sisfb_search_tvstd(const char *name)
317*4882a593Smuzhiyun {
318*4882a593Smuzhiyun int i = 0;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun /* We don't know the hardware specs yet and there is no ivideo */
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun if(name == NULL)
323*4882a593Smuzhiyun return;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun while(sis_tvtype[i].type_no != -1) {
326*4882a593Smuzhiyun if(!strncasecmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
327*4882a593Smuzhiyun sisfb_tvstd = sis_tvtype[i].type_no;
328*4882a593Smuzhiyun break;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun i++;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun static void __init
sisfb_search_specialtiming(const char * name)335*4882a593Smuzhiyun sisfb_search_specialtiming(const char *name)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun int i = 0;
338*4882a593Smuzhiyun bool found = false;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun /* We don't know the hardware specs yet and there is no ivideo */
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun if(name == NULL)
343*4882a593Smuzhiyun return;
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun if(!strncasecmp(name, "none", 4)) {
346*4882a593Smuzhiyun sisfb_specialtiming = CUT_FORCENONE;
347*4882a593Smuzhiyun printk(KERN_DEBUG "sisfb: Special timing disabled\n");
348*4882a593Smuzhiyun } else {
349*4882a593Smuzhiyun while(mycustomttable[i].chipID != 0) {
350*4882a593Smuzhiyun if(!strncasecmp(name,mycustomttable[i].optionName,
351*4882a593Smuzhiyun strlen(mycustomttable[i].optionName))) {
352*4882a593Smuzhiyun sisfb_specialtiming = mycustomttable[i].SpecialID;
353*4882a593Smuzhiyun found = true;
354*4882a593Smuzhiyun printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
355*4882a593Smuzhiyun mycustomttable[i].vendorName,
356*4882a593Smuzhiyun mycustomttable[i].cardName,
357*4882a593Smuzhiyun mycustomttable[i].optionName);
358*4882a593Smuzhiyun break;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun i++;
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun if(!found) {
363*4882a593Smuzhiyun printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
364*4882a593Smuzhiyun printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
365*4882a593Smuzhiyun i = 0;
366*4882a593Smuzhiyun while(mycustomttable[i].chipID != 0) {
367*4882a593Smuzhiyun printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
368*4882a593Smuzhiyun mycustomttable[i].optionName,
369*4882a593Smuzhiyun mycustomttable[i].vendorName,
370*4882a593Smuzhiyun mycustomttable[i].cardName);
371*4882a593Smuzhiyun i++;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun /* ----------- Various detection routines ----------- */
378*4882a593Smuzhiyun
sisfb_detect_custom_timing(struct sis_video_info * ivideo)379*4882a593Smuzhiyun static void sisfb_detect_custom_timing(struct sis_video_info *ivideo)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun unsigned char *biosver = NULL;
382*4882a593Smuzhiyun unsigned char *biosdate = NULL;
383*4882a593Smuzhiyun bool footprint;
384*4882a593Smuzhiyun u32 chksum = 0;
385*4882a593Smuzhiyun int i, j;
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun if(ivideo->SiS_Pr.UseROM) {
388*4882a593Smuzhiyun biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
389*4882a593Smuzhiyun biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
390*4882a593Smuzhiyun for(i = 0; i < 32768; i++)
391*4882a593Smuzhiyun chksum += ivideo->SiS_Pr.VirtualRomBase[i];
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun i = 0;
395*4882a593Smuzhiyun do {
396*4882a593Smuzhiyun if( (mycustomttable[i].chipID == ivideo->chip) &&
397*4882a593Smuzhiyun ((!strlen(mycustomttable[i].biosversion)) ||
398*4882a593Smuzhiyun (ivideo->SiS_Pr.UseROM &&
399*4882a593Smuzhiyun (!strncmp(mycustomttable[i].biosversion, biosver,
400*4882a593Smuzhiyun strlen(mycustomttable[i].biosversion))))) &&
401*4882a593Smuzhiyun ((!strlen(mycustomttable[i].biosdate)) ||
402*4882a593Smuzhiyun (ivideo->SiS_Pr.UseROM &&
403*4882a593Smuzhiyun (!strncmp(mycustomttable[i].biosdate, biosdate,
404*4882a593Smuzhiyun strlen(mycustomttable[i].biosdate))))) &&
405*4882a593Smuzhiyun ((!mycustomttable[i].bioschksum) ||
406*4882a593Smuzhiyun (ivideo->SiS_Pr.UseROM &&
407*4882a593Smuzhiyun (mycustomttable[i].bioschksum == chksum))) &&
408*4882a593Smuzhiyun (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
409*4882a593Smuzhiyun (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
410*4882a593Smuzhiyun footprint = true;
411*4882a593Smuzhiyun for(j = 0; j < 5; j++) {
412*4882a593Smuzhiyun if(mycustomttable[i].biosFootprintAddr[j]) {
413*4882a593Smuzhiyun if(ivideo->SiS_Pr.UseROM) {
414*4882a593Smuzhiyun if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
415*4882a593Smuzhiyun mycustomttable[i].biosFootprintData[j]) {
416*4882a593Smuzhiyun footprint = false;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun } else
419*4882a593Smuzhiyun footprint = false;
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun if(footprint) {
423*4882a593Smuzhiyun ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
424*4882a593Smuzhiyun printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
425*4882a593Smuzhiyun mycustomttable[i].vendorName,
426*4882a593Smuzhiyun mycustomttable[i].cardName);
427*4882a593Smuzhiyun printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
428*4882a593Smuzhiyun mycustomttable[i].optionName);
429*4882a593Smuzhiyun break;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun i++;
433*4882a593Smuzhiyun } while(mycustomttable[i].chipID);
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun
sisfb_interpret_edid(struct sisfb_monitor * monitor,u8 * buffer)436*4882a593Smuzhiyun static bool sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun int i, j, xres, yres, refresh, index;
439*4882a593Smuzhiyun u32 emodes;
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun if(buffer[0] != 0x00 || buffer[1] != 0xff ||
442*4882a593Smuzhiyun buffer[2] != 0xff || buffer[3] != 0xff ||
443*4882a593Smuzhiyun buffer[4] != 0xff || buffer[5] != 0xff ||
444*4882a593Smuzhiyun buffer[6] != 0xff || buffer[7] != 0x00) {
445*4882a593Smuzhiyun printk(KERN_DEBUG "sisfb: Bad EDID header\n");
446*4882a593Smuzhiyun return false;
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun if(buffer[0x12] != 0x01) {
450*4882a593Smuzhiyun printk(KERN_INFO "sisfb: EDID version %d not supported\n",
451*4882a593Smuzhiyun buffer[0x12]);
452*4882a593Smuzhiyun return false;
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun monitor->feature = buffer[0x18];
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun if(!(buffer[0x14] & 0x80)) {
458*4882a593Smuzhiyun if(!(buffer[0x14] & 0x08)) {
459*4882a593Smuzhiyun printk(KERN_INFO
460*4882a593Smuzhiyun "sisfb: WARNING: Monitor does not support separate syncs\n");
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun if(buffer[0x13] >= 0x01) {
465*4882a593Smuzhiyun /* EDID V1 rev 1 and 2: Search for monitor descriptor
466*4882a593Smuzhiyun * to extract ranges
467*4882a593Smuzhiyun */
468*4882a593Smuzhiyun j = 0x36;
469*4882a593Smuzhiyun for(i=0; i<4; i++) {
470*4882a593Smuzhiyun if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
471*4882a593Smuzhiyun buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
472*4882a593Smuzhiyun buffer[j + 4] == 0x00) {
473*4882a593Smuzhiyun monitor->hmin = buffer[j + 7];
474*4882a593Smuzhiyun monitor->hmax = buffer[j + 8];
475*4882a593Smuzhiyun monitor->vmin = buffer[j + 5];
476*4882a593Smuzhiyun monitor->vmax = buffer[j + 6];
477*4882a593Smuzhiyun monitor->dclockmax = buffer[j + 9] * 10 * 1000;
478*4882a593Smuzhiyun monitor->datavalid = true;
479*4882a593Smuzhiyun break;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun j += 18;
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun if(!monitor->datavalid) {
486*4882a593Smuzhiyun /* Otherwise: Get a range from the list of supported
487*4882a593Smuzhiyun * Estabished Timings. This is not entirely accurate,
488*4882a593Smuzhiyun * because fixed frequency monitors are not supported
489*4882a593Smuzhiyun * that way.
490*4882a593Smuzhiyun */
491*4882a593Smuzhiyun monitor->hmin = 65535; monitor->hmax = 0;
492*4882a593Smuzhiyun monitor->vmin = 65535; monitor->vmax = 0;
493*4882a593Smuzhiyun monitor->dclockmax = 0;
494*4882a593Smuzhiyun emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
495*4882a593Smuzhiyun for(i = 0; i < 13; i++) {
496*4882a593Smuzhiyun if(emodes & sisfb_ddcsmodes[i].mask) {
497*4882a593Smuzhiyun if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
498*4882a593Smuzhiyun if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
499*4882a593Smuzhiyun if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
500*4882a593Smuzhiyun if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
501*4882a593Smuzhiyun if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun index = 0x26;
505*4882a593Smuzhiyun for(i = 0; i < 8; i++) {
506*4882a593Smuzhiyun xres = (buffer[index] + 31) * 8;
507*4882a593Smuzhiyun switch(buffer[index + 1] & 0xc0) {
508*4882a593Smuzhiyun case 0xc0: yres = (xres * 9) / 16; break;
509*4882a593Smuzhiyun case 0x80: yres = (xres * 4) / 5; break;
510*4882a593Smuzhiyun case 0x40: yres = (xres * 3) / 4; break;
511*4882a593Smuzhiyun default: yres = xres; break;
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun refresh = (buffer[index + 1] & 0x3f) + 60;
514*4882a593Smuzhiyun if((xres >= 640) && (yres >= 480)) {
515*4882a593Smuzhiyun for(j = 0; j < 8; j++) {
516*4882a593Smuzhiyun if((xres == sisfb_ddcfmodes[j].x) &&
517*4882a593Smuzhiyun (yres == sisfb_ddcfmodes[j].y) &&
518*4882a593Smuzhiyun (refresh == sisfb_ddcfmodes[j].v)) {
519*4882a593Smuzhiyun if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
520*4882a593Smuzhiyun if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
521*4882a593Smuzhiyun if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
522*4882a593Smuzhiyun if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
523*4882a593Smuzhiyun if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun index += 2;
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
530*4882a593Smuzhiyun monitor->datavalid = true;
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun return monitor->datavalid;
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun
sisfb_handle_ddc(struct sis_video_info * ivideo,struct sisfb_monitor * monitor,int crtno)537*4882a593Smuzhiyun static void sisfb_handle_ddc(struct sis_video_info *ivideo,
538*4882a593Smuzhiyun struct sisfb_monitor *monitor, int crtno)
539*4882a593Smuzhiyun {
540*4882a593Smuzhiyun unsigned short temp, i, realcrtno = crtno;
541*4882a593Smuzhiyun unsigned char buffer[256];
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun monitor->datavalid = false;
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun if(crtno) {
546*4882a593Smuzhiyun if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
547*4882a593Smuzhiyun else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
548*4882a593Smuzhiyun else return;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun if((ivideo->sisfb_crt1off) && (!crtno))
552*4882a593Smuzhiyun return;
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
555*4882a593Smuzhiyun realcrtno, 0, &buffer[0], ivideo->vbflags2);
556*4882a593Smuzhiyun if((!temp) || (temp == 0xffff)) {
557*4882a593Smuzhiyun printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
558*4882a593Smuzhiyun return;
559*4882a593Smuzhiyun } else {
560*4882a593Smuzhiyun printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
561*4882a593Smuzhiyun printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
562*4882a593Smuzhiyun crtno + 1,
563*4882a593Smuzhiyun (temp & 0x1a) ? "" : "[none of the supported]",
564*4882a593Smuzhiyun (temp & 0x02) ? "2 " : "",
565*4882a593Smuzhiyun (temp & 0x08) ? "D&P" : "",
566*4882a593Smuzhiyun (temp & 0x10) ? "FPDI-2" : "");
567*4882a593Smuzhiyun if(temp & 0x02) {
568*4882a593Smuzhiyun i = 3; /* Number of retrys */
569*4882a593Smuzhiyun do {
570*4882a593Smuzhiyun temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
571*4882a593Smuzhiyun realcrtno, 1, &buffer[0], ivideo->vbflags2);
572*4882a593Smuzhiyun } while((temp) && i--);
573*4882a593Smuzhiyun if(!temp) {
574*4882a593Smuzhiyun if(sisfb_interpret_edid(monitor, &buffer[0])) {
575*4882a593Smuzhiyun printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
576*4882a593Smuzhiyun monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
577*4882a593Smuzhiyun monitor->dclockmax / 1000);
578*4882a593Smuzhiyun } else {
579*4882a593Smuzhiyun printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun } else {
582*4882a593Smuzhiyun printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun } else {
585*4882a593Smuzhiyun printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun }
588*4882a593Smuzhiyun }
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun /* -------------- Mode validation --------------- */
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun static bool
sisfb_verify_rate(struct sis_video_info * ivideo,struct sisfb_monitor * monitor,int mode_idx,int rate_idx,int rate)593*4882a593Smuzhiyun sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
594*4882a593Smuzhiyun int mode_idx, int rate_idx, int rate)
595*4882a593Smuzhiyun {
596*4882a593Smuzhiyun int htotal, vtotal;
597*4882a593Smuzhiyun unsigned int dclock, hsync;
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun if(!monitor->datavalid)
600*4882a593Smuzhiyun return true;
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun if(mode_idx < 0)
603*4882a593Smuzhiyun return false;
604*4882a593Smuzhiyun
605*4882a593Smuzhiyun /* Skip for 320x200, 320x240, 640x400 */
606*4882a593Smuzhiyun switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
607*4882a593Smuzhiyun case 0x59:
608*4882a593Smuzhiyun case 0x41:
609*4882a593Smuzhiyun case 0x4f:
610*4882a593Smuzhiyun case 0x50:
611*4882a593Smuzhiyun case 0x56:
612*4882a593Smuzhiyun case 0x53:
613*4882a593Smuzhiyun case 0x2f:
614*4882a593Smuzhiyun case 0x5d:
615*4882a593Smuzhiyun case 0x5e:
616*4882a593Smuzhiyun return true;
617*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
618*4882a593Smuzhiyun case 0x5a:
619*4882a593Smuzhiyun case 0x5b:
620*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_315_VGA) return true;
621*4882a593Smuzhiyun #endif
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun if(rate < (monitor->vmin - 1))
625*4882a593Smuzhiyun return false;
626*4882a593Smuzhiyun if(rate > (monitor->vmax + 1))
627*4882a593Smuzhiyun return false;
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
630*4882a593Smuzhiyun sisbios_mode[mode_idx].mode_no[ivideo->mni],
631*4882a593Smuzhiyun &htotal, &vtotal, rate_idx)) {
632*4882a593Smuzhiyun dclock = (htotal * vtotal * rate) / 1000;
633*4882a593Smuzhiyun if(dclock > (monitor->dclockmax + 1000))
634*4882a593Smuzhiyun return false;
635*4882a593Smuzhiyun hsync = dclock / htotal;
636*4882a593Smuzhiyun if(hsync < (monitor->hmin - 1))
637*4882a593Smuzhiyun return false;
638*4882a593Smuzhiyun if(hsync > (monitor->hmax + 1))
639*4882a593Smuzhiyun return false;
640*4882a593Smuzhiyun } else {
641*4882a593Smuzhiyun return false;
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun return true;
644*4882a593Smuzhiyun }
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun static int
sisfb_validate_mode(struct sis_video_info * ivideo,int myindex,u32 vbflags)647*4882a593Smuzhiyun sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
648*4882a593Smuzhiyun {
649*4882a593Smuzhiyun u16 xres=0, yres, myres;
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_300
652*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_300_VGA) {
653*4882a593Smuzhiyun if(!(sisbios_mode[myindex].chipset & MD_SIS300))
654*4882a593Smuzhiyun return -1 ;
655*4882a593Smuzhiyun }
656*4882a593Smuzhiyun #endif
657*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
658*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_315_VGA) {
659*4882a593Smuzhiyun if(!(sisbios_mode[myindex].chipset & MD_SIS315))
660*4882a593Smuzhiyun return -1;
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun #endif
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun myres = sisbios_mode[myindex].yres;
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun switch(vbflags & VB_DISPTYPE_DISP2) {
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun case CRT2_LCD:
669*4882a593Smuzhiyun xres = ivideo->lcdxres; yres = ivideo->lcdyres;
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
672*4882a593Smuzhiyun (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
673*4882a593Smuzhiyun if(sisbios_mode[myindex].xres > xres)
674*4882a593Smuzhiyun return -1;
675*4882a593Smuzhiyun if(myres > yres)
676*4882a593Smuzhiyun return -1;
677*4882a593Smuzhiyun }
678*4882a593Smuzhiyun
679*4882a593Smuzhiyun if(ivideo->sisfb_fstn) {
680*4882a593Smuzhiyun if(sisbios_mode[myindex].xres == 320) {
681*4882a593Smuzhiyun if(myres == 240) {
682*4882a593Smuzhiyun switch(sisbios_mode[myindex].mode_no[1]) {
683*4882a593Smuzhiyun case 0x50: myindex = MODE_FSTN_8; break;
684*4882a593Smuzhiyun case 0x56: myindex = MODE_FSTN_16; break;
685*4882a593Smuzhiyun case 0x53: return -1;
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun }
688*4882a593Smuzhiyun }
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
692*4882a593Smuzhiyun sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
693*4882a593Smuzhiyun ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
694*4882a593Smuzhiyun return -1;
695*4882a593Smuzhiyun }
696*4882a593Smuzhiyun break;
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun case CRT2_TV:
699*4882a593Smuzhiyun if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
700*4882a593Smuzhiyun sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
701*4882a593Smuzhiyun return -1;
702*4882a593Smuzhiyun }
703*4882a593Smuzhiyun break;
704*4882a593Smuzhiyun
705*4882a593Smuzhiyun case CRT2_VGA:
706*4882a593Smuzhiyun if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
707*4882a593Smuzhiyun sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
708*4882a593Smuzhiyun return -1;
709*4882a593Smuzhiyun }
710*4882a593Smuzhiyun break;
711*4882a593Smuzhiyun }
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun return myindex;
714*4882a593Smuzhiyun }
715*4882a593Smuzhiyun
716*4882a593Smuzhiyun static u8
sisfb_search_refresh_rate(struct sis_video_info * ivideo,unsigned int rate,int mode_idx)717*4882a593Smuzhiyun sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
718*4882a593Smuzhiyun {
719*4882a593Smuzhiyun int i = 0;
720*4882a593Smuzhiyun u16 xres = sisbios_mode[mode_idx].xres;
721*4882a593Smuzhiyun u16 yres = sisbios_mode[mode_idx].yres;
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun ivideo->rate_idx = 0;
724*4882a593Smuzhiyun while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
725*4882a593Smuzhiyun if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
726*4882a593Smuzhiyun if(sisfb_vrate[i].refresh == rate) {
727*4882a593Smuzhiyun ivideo->rate_idx = sisfb_vrate[i].idx;
728*4882a593Smuzhiyun break;
729*4882a593Smuzhiyun } else if(sisfb_vrate[i].refresh > rate) {
730*4882a593Smuzhiyun if((sisfb_vrate[i].refresh - rate) <= 3) {
731*4882a593Smuzhiyun DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
732*4882a593Smuzhiyun rate, sisfb_vrate[i].refresh);
733*4882a593Smuzhiyun ivideo->rate_idx = sisfb_vrate[i].idx;
734*4882a593Smuzhiyun ivideo->refresh_rate = sisfb_vrate[i].refresh;
735*4882a593Smuzhiyun } else if((sisfb_vrate[i].idx != 1) &&
736*4882a593Smuzhiyun ((rate - sisfb_vrate[i-1].refresh) <= 2)) {
737*4882a593Smuzhiyun DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
738*4882a593Smuzhiyun rate, sisfb_vrate[i-1].refresh);
739*4882a593Smuzhiyun ivideo->rate_idx = sisfb_vrate[i-1].idx;
740*4882a593Smuzhiyun ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun break;
743*4882a593Smuzhiyun } else if((rate - sisfb_vrate[i].refresh) <= 2) {
744*4882a593Smuzhiyun DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
745*4882a593Smuzhiyun rate, sisfb_vrate[i].refresh);
746*4882a593Smuzhiyun ivideo->rate_idx = sisfb_vrate[i].idx;
747*4882a593Smuzhiyun break;
748*4882a593Smuzhiyun }
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun i++;
751*4882a593Smuzhiyun }
752*4882a593Smuzhiyun if(ivideo->rate_idx > 0) {
753*4882a593Smuzhiyun return ivideo->rate_idx;
754*4882a593Smuzhiyun } else {
755*4882a593Smuzhiyun printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
756*4882a593Smuzhiyun rate, xres, yres);
757*4882a593Smuzhiyun return 0;
758*4882a593Smuzhiyun }
759*4882a593Smuzhiyun }
760*4882a593Smuzhiyun
761*4882a593Smuzhiyun static bool
sisfb_bridgeisslave(struct sis_video_info * ivideo)762*4882a593Smuzhiyun sisfb_bridgeisslave(struct sis_video_info *ivideo)
763*4882a593Smuzhiyun {
764*4882a593Smuzhiyun unsigned char P1_00;
765*4882a593Smuzhiyun
766*4882a593Smuzhiyun if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
767*4882a593Smuzhiyun return false;
768*4882a593Smuzhiyun
769*4882a593Smuzhiyun P1_00 = SiS_GetReg(SISPART1, 0x00);
770*4882a593Smuzhiyun if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
771*4882a593Smuzhiyun ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
772*4882a593Smuzhiyun return true;
773*4882a593Smuzhiyun } else {
774*4882a593Smuzhiyun return false;
775*4882a593Smuzhiyun }
776*4882a593Smuzhiyun }
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun static bool
sisfballowretracecrt1(struct sis_video_info * ivideo)779*4882a593Smuzhiyun sisfballowretracecrt1(struct sis_video_info *ivideo)
780*4882a593Smuzhiyun {
781*4882a593Smuzhiyun u8 temp;
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun temp = SiS_GetReg(SISCR, 0x17);
784*4882a593Smuzhiyun if(!(temp & 0x80))
785*4882a593Smuzhiyun return false;
786*4882a593Smuzhiyun
787*4882a593Smuzhiyun temp = SiS_GetReg(SISSR, 0x1f);
788*4882a593Smuzhiyun if(temp & 0xc0)
789*4882a593Smuzhiyun return false;
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun return true;
792*4882a593Smuzhiyun }
793*4882a593Smuzhiyun
794*4882a593Smuzhiyun static bool
sisfbcheckvretracecrt1(struct sis_video_info * ivideo)795*4882a593Smuzhiyun sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
796*4882a593Smuzhiyun {
797*4882a593Smuzhiyun if(!sisfballowretracecrt1(ivideo))
798*4882a593Smuzhiyun return false;
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun if (SiS_GetRegByte(SISINPSTAT) & 0x08)
801*4882a593Smuzhiyun return true;
802*4882a593Smuzhiyun else
803*4882a593Smuzhiyun return false;
804*4882a593Smuzhiyun }
805*4882a593Smuzhiyun
806*4882a593Smuzhiyun static void
sisfbwaitretracecrt1(struct sis_video_info * ivideo)807*4882a593Smuzhiyun sisfbwaitretracecrt1(struct sis_video_info *ivideo)
808*4882a593Smuzhiyun {
809*4882a593Smuzhiyun int watchdog;
810*4882a593Smuzhiyun
811*4882a593Smuzhiyun if(!sisfballowretracecrt1(ivideo))
812*4882a593Smuzhiyun return;
813*4882a593Smuzhiyun
814*4882a593Smuzhiyun watchdog = 65536;
815*4882a593Smuzhiyun while ((!(SiS_GetRegByte(SISINPSTAT) & 0x08)) && --watchdog);
816*4882a593Smuzhiyun watchdog = 65536;
817*4882a593Smuzhiyun while ((SiS_GetRegByte(SISINPSTAT) & 0x08) && --watchdog);
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun static bool
sisfbcheckvretracecrt2(struct sis_video_info * ivideo)821*4882a593Smuzhiyun sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
822*4882a593Smuzhiyun {
823*4882a593Smuzhiyun unsigned char temp, reg;
824*4882a593Smuzhiyun
825*4882a593Smuzhiyun switch(ivideo->sisvga_engine) {
826*4882a593Smuzhiyun case SIS_300_VGA: reg = 0x25; break;
827*4882a593Smuzhiyun case SIS_315_VGA: reg = 0x30; break;
828*4882a593Smuzhiyun default: return false;
829*4882a593Smuzhiyun }
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun temp = SiS_GetReg(SISPART1, reg);
832*4882a593Smuzhiyun if(temp & 0x02)
833*4882a593Smuzhiyun return true;
834*4882a593Smuzhiyun else
835*4882a593Smuzhiyun return false;
836*4882a593Smuzhiyun }
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun static bool
sisfb_CheckVBRetrace(struct sis_video_info * ivideo)839*4882a593Smuzhiyun sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
840*4882a593Smuzhiyun {
841*4882a593Smuzhiyun if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
842*4882a593Smuzhiyun if(!sisfb_bridgeisslave(ivideo)) {
843*4882a593Smuzhiyun return sisfbcheckvretracecrt2(ivideo);
844*4882a593Smuzhiyun }
845*4882a593Smuzhiyun }
846*4882a593Smuzhiyun return sisfbcheckvretracecrt1(ivideo);
847*4882a593Smuzhiyun }
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun static u32
sisfb_setupvbblankflags(struct sis_video_info * ivideo,u32 * vcount,u32 * hcount)850*4882a593Smuzhiyun sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
851*4882a593Smuzhiyun {
852*4882a593Smuzhiyun u8 idx, reg1, reg2, reg3, reg4;
853*4882a593Smuzhiyun u32 ret = 0;
854*4882a593Smuzhiyun
855*4882a593Smuzhiyun (*vcount) = (*hcount) = 0;
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
858*4882a593Smuzhiyun
859*4882a593Smuzhiyun ret |= (FB_VBLANK_HAVE_VSYNC |
860*4882a593Smuzhiyun FB_VBLANK_HAVE_HBLANK |
861*4882a593Smuzhiyun FB_VBLANK_HAVE_VBLANK |
862*4882a593Smuzhiyun FB_VBLANK_HAVE_VCOUNT |
863*4882a593Smuzhiyun FB_VBLANK_HAVE_HCOUNT);
864*4882a593Smuzhiyun switch(ivideo->sisvga_engine) {
865*4882a593Smuzhiyun case SIS_300_VGA: idx = 0x25; break;
866*4882a593Smuzhiyun default:
867*4882a593Smuzhiyun case SIS_315_VGA: idx = 0x30; break;
868*4882a593Smuzhiyun }
869*4882a593Smuzhiyun reg1 = SiS_GetReg(SISPART1, (idx+0)); /* 30 */
870*4882a593Smuzhiyun reg2 = SiS_GetReg(SISPART1, (idx+1)); /* 31 */
871*4882a593Smuzhiyun reg3 = SiS_GetReg(SISPART1, (idx+2)); /* 32 */
872*4882a593Smuzhiyun reg4 = SiS_GetReg(SISPART1, (idx+3)); /* 33 */
873*4882a593Smuzhiyun if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
874*4882a593Smuzhiyun if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
875*4882a593Smuzhiyun if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
876*4882a593Smuzhiyun (*vcount) = reg3 | ((reg4 & 0x70) << 4);
877*4882a593Smuzhiyun (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun } else if(sisfballowretracecrt1(ivideo)) {
880*4882a593Smuzhiyun
881*4882a593Smuzhiyun ret |= (FB_VBLANK_HAVE_VSYNC |
882*4882a593Smuzhiyun FB_VBLANK_HAVE_VBLANK |
883*4882a593Smuzhiyun FB_VBLANK_HAVE_VCOUNT |
884*4882a593Smuzhiyun FB_VBLANK_HAVE_HCOUNT);
885*4882a593Smuzhiyun reg1 = SiS_GetRegByte(SISINPSTAT);
886*4882a593Smuzhiyun if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
887*4882a593Smuzhiyun if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
888*4882a593Smuzhiyun reg1 = SiS_GetReg(SISCR, 0x20);
889*4882a593Smuzhiyun reg1 = SiS_GetReg(SISCR, 0x1b);
890*4882a593Smuzhiyun reg2 = SiS_GetReg(SISCR, 0x1c);
891*4882a593Smuzhiyun reg3 = SiS_GetReg(SISCR, 0x1d);
892*4882a593Smuzhiyun (*vcount) = reg2 | ((reg3 & 0x07) << 8);
893*4882a593Smuzhiyun (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
894*4882a593Smuzhiyun }
895*4882a593Smuzhiyun
896*4882a593Smuzhiyun return ret;
897*4882a593Smuzhiyun }
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun static int
sisfb_myblank(struct sis_video_info * ivideo,int blank)900*4882a593Smuzhiyun sisfb_myblank(struct sis_video_info *ivideo, int blank)
901*4882a593Smuzhiyun {
902*4882a593Smuzhiyun u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
903*4882a593Smuzhiyun bool backlight = true;
904*4882a593Smuzhiyun
905*4882a593Smuzhiyun switch(blank) {
906*4882a593Smuzhiyun case FB_BLANK_UNBLANK: /* on */
907*4882a593Smuzhiyun sr01 = 0x00;
908*4882a593Smuzhiyun sr11 = 0x00;
909*4882a593Smuzhiyun sr1f = 0x00;
910*4882a593Smuzhiyun cr63 = 0x00;
911*4882a593Smuzhiyun p2_0 = 0x20;
912*4882a593Smuzhiyun p1_13 = 0x00;
913*4882a593Smuzhiyun backlight = true;
914*4882a593Smuzhiyun break;
915*4882a593Smuzhiyun case FB_BLANK_NORMAL: /* blank */
916*4882a593Smuzhiyun sr01 = 0x20;
917*4882a593Smuzhiyun sr11 = 0x00;
918*4882a593Smuzhiyun sr1f = 0x00;
919*4882a593Smuzhiyun cr63 = 0x00;
920*4882a593Smuzhiyun p2_0 = 0x20;
921*4882a593Smuzhiyun p1_13 = 0x00;
922*4882a593Smuzhiyun backlight = true;
923*4882a593Smuzhiyun break;
924*4882a593Smuzhiyun case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
925*4882a593Smuzhiyun sr01 = 0x20;
926*4882a593Smuzhiyun sr11 = 0x08;
927*4882a593Smuzhiyun sr1f = 0x80;
928*4882a593Smuzhiyun cr63 = 0x40;
929*4882a593Smuzhiyun p2_0 = 0x40;
930*4882a593Smuzhiyun p1_13 = 0x80;
931*4882a593Smuzhiyun backlight = false;
932*4882a593Smuzhiyun break;
933*4882a593Smuzhiyun case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
934*4882a593Smuzhiyun sr01 = 0x20;
935*4882a593Smuzhiyun sr11 = 0x08;
936*4882a593Smuzhiyun sr1f = 0x40;
937*4882a593Smuzhiyun cr63 = 0x40;
938*4882a593Smuzhiyun p2_0 = 0x80;
939*4882a593Smuzhiyun p1_13 = 0x40;
940*4882a593Smuzhiyun backlight = false;
941*4882a593Smuzhiyun break;
942*4882a593Smuzhiyun case FB_BLANK_POWERDOWN: /* off */
943*4882a593Smuzhiyun sr01 = 0x20;
944*4882a593Smuzhiyun sr11 = 0x08;
945*4882a593Smuzhiyun sr1f = 0xc0;
946*4882a593Smuzhiyun cr63 = 0x40;
947*4882a593Smuzhiyun p2_0 = 0xc0;
948*4882a593Smuzhiyun p1_13 = 0xc0;
949*4882a593Smuzhiyun backlight = false;
950*4882a593Smuzhiyun break;
951*4882a593Smuzhiyun default:
952*4882a593Smuzhiyun return 1;
953*4882a593Smuzhiyun }
954*4882a593Smuzhiyun
955*4882a593Smuzhiyun if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
956*4882a593Smuzhiyun
957*4882a593Smuzhiyun if( (!ivideo->sisfb_thismonitor.datavalid) ||
958*4882a593Smuzhiyun ((ivideo->sisfb_thismonitor.datavalid) &&
959*4882a593Smuzhiyun (ivideo->sisfb_thismonitor.feature & 0xe0))) {
960*4882a593Smuzhiyun
961*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_315_VGA) {
962*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
963*4882a593Smuzhiyun }
964*4882a593Smuzhiyun
965*4882a593Smuzhiyun if(!(sisfb_bridgeisslave(ivideo))) {
966*4882a593Smuzhiyun SiS_SetRegANDOR(SISSR, 0x01, ~0x20, sr01);
967*4882a593Smuzhiyun SiS_SetRegANDOR(SISSR, 0x1f, 0x3f, sr1f);
968*4882a593Smuzhiyun }
969*4882a593Smuzhiyun }
970*4882a593Smuzhiyun
971*4882a593Smuzhiyun }
972*4882a593Smuzhiyun
973*4882a593Smuzhiyun if(ivideo->currentvbflags & CRT2_LCD) {
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
976*4882a593Smuzhiyun if(backlight) {
977*4882a593Smuzhiyun SiS_SiS30xBLOn(&ivideo->SiS_Pr);
978*4882a593Smuzhiyun } else {
979*4882a593Smuzhiyun SiS_SiS30xBLOff(&ivideo->SiS_Pr);
980*4882a593Smuzhiyun }
981*4882a593Smuzhiyun } else if(ivideo->sisvga_engine == SIS_315_VGA) {
982*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
983*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_CHRONTEL) {
984*4882a593Smuzhiyun if(backlight) {
985*4882a593Smuzhiyun SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
986*4882a593Smuzhiyun } else {
987*4882a593Smuzhiyun SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
988*4882a593Smuzhiyun }
989*4882a593Smuzhiyun }
990*4882a593Smuzhiyun #endif
991*4882a593Smuzhiyun }
992*4882a593Smuzhiyun
993*4882a593Smuzhiyun if(((ivideo->sisvga_engine == SIS_300_VGA) &&
994*4882a593Smuzhiyun (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
995*4882a593Smuzhiyun ((ivideo->sisvga_engine == SIS_315_VGA) &&
996*4882a593Smuzhiyun ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
997*4882a593Smuzhiyun SiS_SetRegANDOR(SISSR, 0x11, ~0x0c, sr11);
998*4882a593Smuzhiyun }
999*4882a593Smuzhiyun
1000*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_300_VGA) {
1001*4882a593Smuzhiyun if((ivideo->vbflags2 & VB2_30xB) &&
1002*4882a593Smuzhiyun (!(ivideo->vbflags2 & VB2_30xBDH))) {
1003*4882a593Smuzhiyun SiS_SetRegANDOR(SISPART1, 0x13, 0x3f, p1_13);
1004*4882a593Smuzhiyun }
1005*4882a593Smuzhiyun } else if(ivideo->sisvga_engine == SIS_315_VGA) {
1006*4882a593Smuzhiyun if((ivideo->vbflags2 & VB2_30xB) &&
1007*4882a593Smuzhiyun (!(ivideo->vbflags2 & VB2_30xBDH))) {
1008*4882a593Smuzhiyun SiS_SetRegANDOR(SISPART2, 0x00, 0x1f, p2_0);
1009*4882a593Smuzhiyun }
1010*4882a593Smuzhiyun }
1011*4882a593Smuzhiyun
1012*4882a593Smuzhiyun } else if(ivideo->currentvbflags & CRT2_VGA) {
1013*4882a593Smuzhiyun
1014*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_30xB) {
1015*4882a593Smuzhiyun SiS_SetRegANDOR(SISPART2, 0x00, 0x1f, p2_0);
1016*4882a593Smuzhiyun }
1017*4882a593Smuzhiyun
1018*4882a593Smuzhiyun }
1019*4882a593Smuzhiyun
1020*4882a593Smuzhiyun return 0;
1021*4882a593Smuzhiyun }
1022*4882a593Smuzhiyun
1023*4882a593Smuzhiyun /* ------------- Callbacks from init.c/init301.c -------------- */
1024*4882a593Smuzhiyun
1025*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_300
1026*4882a593Smuzhiyun unsigned int
sisfb_read_nbridge_pci_dword(struct SiS_Private * SiS_Pr,int reg)1027*4882a593Smuzhiyun sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1028*4882a593Smuzhiyun {
1029*4882a593Smuzhiyun struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1030*4882a593Smuzhiyun u32 val = 0;
1031*4882a593Smuzhiyun
1032*4882a593Smuzhiyun pci_read_config_dword(ivideo->nbridge, reg, &val);
1033*4882a593Smuzhiyun return (unsigned int)val;
1034*4882a593Smuzhiyun }
1035*4882a593Smuzhiyun
1036*4882a593Smuzhiyun void
sisfb_write_nbridge_pci_dword(struct SiS_Private * SiS_Pr,int reg,unsigned int val)1037*4882a593Smuzhiyun sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
1038*4882a593Smuzhiyun {
1039*4882a593Smuzhiyun struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1040*4882a593Smuzhiyun
1041*4882a593Smuzhiyun pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
1042*4882a593Smuzhiyun }
1043*4882a593Smuzhiyun
1044*4882a593Smuzhiyun unsigned int
sisfb_read_lpc_pci_dword(struct SiS_Private * SiS_Pr,int reg)1045*4882a593Smuzhiyun sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1046*4882a593Smuzhiyun {
1047*4882a593Smuzhiyun struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1048*4882a593Smuzhiyun u32 val = 0;
1049*4882a593Smuzhiyun
1050*4882a593Smuzhiyun if(!ivideo->lpcdev) return 0;
1051*4882a593Smuzhiyun
1052*4882a593Smuzhiyun pci_read_config_dword(ivideo->lpcdev, reg, &val);
1053*4882a593Smuzhiyun return (unsigned int)val;
1054*4882a593Smuzhiyun }
1055*4882a593Smuzhiyun #endif
1056*4882a593Smuzhiyun
1057*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
1058*4882a593Smuzhiyun void
sisfb_write_nbridge_pci_byte(struct SiS_Private * SiS_Pr,int reg,unsigned char val)1059*4882a593Smuzhiyun sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
1060*4882a593Smuzhiyun {
1061*4882a593Smuzhiyun struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1062*4882a593Smuzhiyun
1063*4882a593Smuzhiyun pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
1064*4882a593Smuzhiyun }
1065*4882a593Smuzhiyun
1066*4882a593Smuzhiyun unsigned int
sisfb_read_mio_pci_word(struct SiS_Private * SiS_Pr,int reg)1067*4882a593Smuzhiyun sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
1068*4882a593Smuzhiyun {
1069*4882a593Smuzhiyun struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1070*4882a593Smuzhiyun u16 val = 0;
1071*4882a593Smuzhiyun
1072*4882a593Smuzhiyun if(!ivideo->lpcdev) return 0;
1073*4882a593Smuzhiyun
1074*4882a593Smuzhiyun pci_read_config_word(ivideo->lpcdev, reg, &val);
1075*4882a593Smuzhiyun return (unsigned int)val;
1076*4882a593Smuzhiyun }
1077*4882a593Smuzhiyun #endif
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun /* ----------- FBDev related routines for all series ----------- */
1080*4882a593Smuzhiyun
1081*4882a593Smuzhiyun static int
sisfb_get_cmap_len(const struct fb_var_screeninfo * var)1082*4882a593Smuzhiyun sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
1083*4882a593Smuzhiyun {
1084*4882a593Smuzhiyun return (var->bits_per_pixel == 8) ? 256 : 16;
1085*4882a593Smuzhiyun }
1086*4882a593Smuzhiyun
1087*4882a593Smuzhiyun static void
sisfb_set_vparms(struct sis_video_info * ivideo)1088*4882a593Smuzhiyun sisfb_set_vparms(struct sis_video_info *ivideo)
1089*4882a593Smuzhiyun {
1090*4882a593Smuzhiyun switch(ivideo->video_bpp) {
1091*4882a593Smuzhiyun case 8:
1092*4882a593Smuzhiyun ivideo->DstColor = 0x0000;
1093*4882a593Smuzhiyun ivideo->SiS310_AccelDepth = 0x00000000;
1094*4882a593Smuzhiyun ivideo->video_cmap_len = 256;
1095*4882a593Smuzhiyun break;
1096*4882a593Smuzhiyun case 16:
1097*4882a593Smuzhiyun ivideo->DstColor = 0x8000;
1098*4882a593Smuzhiyun ivideo->SiS310_AccelDepth = 0x00010000;
1099*4882a593Smuzhiyun ivideo->video_cmap_len = 16;
1100*4882a593Smuzhiyun break;
1101*4882a593Smuzhiyun case 32:
1102*4882a593Smuzhiyun ivideo->DstColor = 0xC000;
1103*4882a593Smuzhiyun ivideo->SiS310_AccelDepth = 0x00020000;
1104*4882a593Smuzhiyun ivideo->video_cmap_len = 16;
1105*4882a593Smuzhiyun break;
1106*4882a593Smuzhiyun default:
1107*4882a593Smuzhiyun ivideo->video_cmap_len = 16;
1108*4882a593Smuzhiyun printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
1109*4882a593Smuzhiyun ivideo->accel = 0;
1110*4882a593Smuzhiyun }
1111*4882a593Smuzhiyun }
1112*4882a593Smuzhiyun
1113*4882a593Smuzhiyun static int
sisfb_calc_maxyres(struct sis_video_info * ivideo,struct fb_var_screeninfo * var)1114*4882a593Smuzhiyun sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1115*4882a593Smuzhiyun {
1116*4882a593Smuzhiyun int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
1117*4882a593Smuzhiyun
1118*4882a593Smuzhiyun if(maxyres > 32767) maxyres = 32767;
1119*4882a593Smuzhiyun
1120*4882a593Smuzhiyun return maxyres;
1121*4882a593Smuzhiyun }
1122*4882a593Smuzhiyun
1123*4882a593Smuzhiyun static void
sisfb_calc_pitch(struct sis_video_info * ivideo,struct fb_var_screeninfo * var)1124*4882a593Smuzhiyun sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1125*4882a593Smuzhiyun {
1126*4882a593Smuzhiyun ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
1127*4882a593Smuzhiyun ivideo->scrnpitchCRT1 = ivideo->video_linelength;
1128*4882a593Smuzhiyun if(!(ivideo->currentvbflags & CRT1_LCDA)) {
1129*4882a593Smuzhiyun if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1130*4882a593Smuzhiyun ivideo->scrnpitchCRT1 <<= 1;
1131*4882a593Smuzhiyun }
1132*4882a593Smuzhiyun }
1133*4882a593Smuzhiyun }
1134*4882a593Smuzhiyun
1135*4882a593Smuzhiyun static void
sisfb_set_pitch(struct sis_video_info * ivideo)1136*4882a593Smuzhiyun sisfb_set_pitch(struct sis_video_info *ivideo)
1137*4882a593Smuzhiyun {
1138*4882a593Smuzhiyun bool isslavemode = false;
1139*4882a593Smuzhiyun unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1140*4882a593Smuzhiyun unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1141*4882a593Smuzhiyun
1142*4882a593Smuzhiyun if(sisfb_bridgeisslave(ivideo)) isslavemode = true;
1143*4882a593Smuzhiyun
1144*4882a593Smuzhiyun /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1145*4882a593Smuzhiyun if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1146*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x13, (HDisplay1 & 0xFF));
1147*4882a593Smuzhiyun SiS_SetRegANDOR(SISSR, 0x0E, 0xF0, (HDisplay1 >> 8));
1148*4882a593Smuzhiyun }
1149*4882a593Smuzhiyun
1150*4882a593Smuzhiyun /* We must not set the pitch for CRT2 if bridge is in slave mode */
1151*4882a593Smuzhiyun if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
1152*4882a593Smuzhiyun SiS_SetRegOR(SISPART1, ivideo->CRT2_write_enable, 0x01);
1153*4882a593Smuzhiyun SiS_SetReg(SISPART1, 0x07, (HDisplay2 & 0xFF));
1154*4882a593Smuzhiyun SiS_SetRegANDOR(SISPART1, 0x09, 0xF0, (HDisplay2 >> 8));
1155*4882a593Smuzhiyun }
1156*4882a593Smuzhiyun }
1157*4882a593Smuzhiyun
1158*4882a593Smuzhiyun static void
sisfb_bpp_to_var(struct sis_video_info * ivideo,struct fb_var_screeninfo * var)1159*4882a593Smuzhiyun sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1160*4882a593Smuzhiyun {
1161*4882a593Smuzhiyun ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1162*4882a593Smuzhiyun
1163*4882a593Smuzhiyun switch(var->bits_per_pixel) {
1164*4882a593Smuzhiyun case 8:
1165*4882a593Smuzhiyun var->red.offset = var->green.offset = var->blue.offset = 0;
1166*4882a593Smuzhiyun var->red.length = var->green.length = var->blue.length = 8;
1167*4882a593Smuzhiyun break;
1168*4882a593Smuzhiyun case 16:
1169*4882a593Smuzhiyun var->red.offset = 11;
1170*4882a593Smuzhiyun var->red.length = 5;
1171*4882a593Smuzhiyun var->green.offset = 5;
1172*4882a593Smuzhiyun var->green.length = 6;
1173*4882a593Smuzhiyun var->blue.offset = 0;
1174*4882a593Smuzhiyun var->blue.length = 5;
1175*4882a593Smuzhiyun var->transp.offset = 0;
1176*4882a593Smuzhiyun var->transp.length = 0;
1177*4882a593Smuzhiyun break;
1178*4882a593Smuzhiyun case 32:
1179*4882a593Smuzhiyun var->red.offset = 16;
1180*4882a593Smuzhiyun var->red.length = 8;
1181*4882a593Smuzhiyun var->green.offset = 8;
1182*4882a593Smuzhiyun var->green.length = 8;
1183*4882a593Smuzhiyun var->blue.offset = 0;
1184*4882a593Smuzhiyun var->blue.length = 8;
1185*4882a593Smuzhiyun var->transp.offset = 24;
1186*4882a593Smuzhiyun var->transp.length = 8;
1187*4882a593Smuzhiyun break;
1188*4882a593Smuzhiyun }
1189*4882a593Smuzhiyun }
1190*4882a593Smuzhiyun
1191*4882a593Smuzhiyun static int
sisfb_set_mode(struct sis_video_info * ivideo,int clrscrn)1192*4882a593Smuzhiyun sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
1193*4882a593Smuzhiyun {
1194*4882a593Smuzhiyun unsigned short modeno = ivideo->mode_no;
1195*4882a593Smuzhiyun
1196*4882a593Smuzhiyun /* >=2.6.12's fbcon clears the screen anyway */
1197*4882a593Smuzhiyun modeno |= 0x80;
1198*4882a593Smuzhiyun
1199*4882a593Smuzhiyun SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1200*4882a593Smuzhiyun
1201*4882a593Smuzhiyun sisfb_pre_setmode(ivideo);
1202*4882a593Smuzhiyun
1203*4882a593Smuzhiyun if(!SiSSetMode(&ivideo->SiS_Pr, modeno)) {
1204*4882a593Smuzhiyun printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1205*4882a593Smuzhiyun return -EINVAL;
1206*4882a593Smuzhiyun }
1207*4882a593Smuzhiyun
1208*4882a593Smuzhiyun SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1209*4882a593Smuzhiyun
1210*4882a593Smuzhiyun sisfb_post_setmode(ivideo);
1211*4882a593Smuzhiyun
1212*4882a593Smuzhiyun return 0;
1213*4882a593Smuzhiyun }
1214*4882a593Smuzhiyun
1215*4882a593Smuzhiyun
1216*4882a593Smuzhiyun static int
sisfb_do_set_var(struct fb_var_screeninfo * var,int isactive,struct fb_info * info)1217*4882a593Smuzhiyun sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1218*4882a593Smuzhiyun {
1219*4882a593Smuzhiyun struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1220*4882a593Smuzhiyun unsigned int htotal = 0, vtotal = 0;
1221*4882a593Smuzhiyun unsigned int drate = 0, hrate = 0;
1222*4882a593Smuzhiyun int found_mode = 0, ret;
1223*4882a593Smuzhiyun int old_mode;
1224*4882a593Smuzhiyun u32 pixclock;
1225*4882a593Smuzhiyun
1226*4882a593Smuzhiyun htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1227*4882a593Smuzhiyun
1228*4882a593Smuzhiyun vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1229*4882a593Smuzhiyun
1230*4882a593Smuzhiyun pixclock = var->pixclock;
1231*4882a593Smuzhiyun
1232*4882a593Smuzhiyun if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1233*4882a593Smuzhiyun vtotal += var->yres;
1234*4882a593Smuzhiyun vtotal <<= 1;
1235*4882a593Smuzhiyun } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1236*4882a593Smuzhiyun vtotal += var->yres;
1237*4882a593Smuzhiyun vtotal <<= 2;
1238*4882a593Smuzhiyun } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1239*4882a593Smuzhiyun vtotal += var->yres;
1240*4882a593Smuzhiyun vtotal <<= 1;
1241*4882a593Smuzhiyun } else vtotal += var->yres;
1242*4882a593Smuzhiyun
1243*4882a593Smuzhiyun if(!(htotal) || !(vtotal)) {
1244*4882a593Smuzhiyun DPRINTK("sisfb: Invalid 'var' information\n");
1245*4882a593Smuzhiyun return -EINVAL;
1246*4882a593Smuzhiyun }
1247*4882a593Smuzhiyun
1248*4882a593Smuzhiyun if(pixclock && htotal && vtotal) {
1249*4882a593Smuzhiyun drate = 1000000000 / pixclock;
1250*4882a593Smuzhiyun hrate = (drate * 1000) / htotal;
1251*4882a593Smuzhiyun ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1252*4882a593Smuzhiyun } else {
1253*4882a593Smuzhiyun ivideo->refresh_rate = 60;
1254*4882a593Smuzhiyun }
1255*4882a593Smuzhiyun
1256*4882a593Smuzhiyun old_mode = ivideo->sisfb_mode_idx;
1257*4882a593Smuzhiyun ivideo->sisfb_mode_idx = 0;
1258*4882a593Smuzhiyun
1259*4882a593Smuzhiyun while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1260*4882a593Smuzhiyun (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1261*4882a593Smuzhiyun if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1262*4882a593Smuzhiyun (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1263*4882a593Smuzhiyun (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1264*4882a593Smuzhiyun ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1265*4882a593Smuzhiyun found_mode = 1;
1266*4882a593Smuzhiyun break;
1267*4882a593Smuzhiyun }
1268*4882a593Smuzhiyun ivideo->sisfb_mode_idx++;
1269*4882a593Smuzhiyun }
1270*4882a593Smuzhiyun
1271*4882a593Smuzhiyun if(found_mode) {
1272*4882a593Smuzhiyun ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1273*4882a593Smuzhiyun ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1274*4882a593Smuzhiyun } else {
1275*4882a593Smuzhiyun ivideo->sisfb_mode_idx = -1;
1276*4882a593Smuzhiyun }
1277*4882a593Smuzhiyun
1278*4882a593Smuzhiyun if(ivideo->sisfb_mode_idx < 0) {
1279*4882a593Smuzhiyun printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1280*4882a593Smuzhiyun var->yres, var->bits_per_pixel);
1281*4882a593Smuzhiyun ivideo->sisfb_mode_idx = old_mode;
1282*4882a593Smuzhiyun return -EINVAL;
1283*4882a593Smuzhiyun }
1284*4882a593Smuzhiyun
1285*4882a593Smuzhiyun ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1286*4882a593Smuzhiyun
1287*4882a593Smuzhiyun if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1288*4882a593Smuzhiyun ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1289*4882a593Smuzhiyun ivideo->refresh_rate = 60;
1290*4882a593Smuzhiyun }
1291*4882a593Smuzhiyun
1292*4882a593Smuzhiyun if(isactive) {
1293*4882a593Smuzhiyun /* If acceleration to be used? Need to know
1294*4882a593Smuzhiyun * before pre/post_set_mode()
1295*4882a593Smuzhiyun */
1296*4882a593Smuzhiyun ivideo->accel = 0;
1297*4882a593Smuzhiyun #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1298*4882a593Smuzhiyun #ifdef STUPID_ACCELF_TEXT_SHIT
1299*4882a593Smuzhiyun if(var->accel_flags & FB_ACCELF_TEXT) {
1300*4882a593Smuzhiyun info->flags &= ~FBINFO_HWACCEL_DISABLED;
1301*4882a593Smuzhiyun } else {
1302*4882a593Smuzhiyun info->flags |= FBINFO_HWACCEL_DISABLED;
1303*4882a593Smuzhiyun }
1304*4882a593Smuzhiyun #endif
1305*4882a593Smuzhiyun if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1306*4882a593Smuzhiyun #else
1307*4882a593Smuzhiyun if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1308*4882a593Smuzhiyun #endif
1309*4882a593Smuzhiyun
1310*4882a593Smuzhiyun if((ret = sisfb_set_mode(ivideo, 1))) {
1311*4882a593Smuzhiyun return ret;
1312*4882a593Smuzhiyun }
1313*4882a593Smuzhiyun
1314*4882a593Smuzhiyun ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1315*4882a593Smuzhiyun ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1316*4882a593Smuzhiyun ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1317*4882a593Smuzhiyun
1318*4882a593Smuzhiyun sisfb_calc_pitch(ivideo, var);
1319*4882a593Smuzhiyun sisfb_set_pitch(ivideo);
1320*4882a593Smuzhiyun
1321*4882a593Smuzhiyun sisfb_set_vparms(ivideo);
1322*4882a593Smuzhiyun
1323*4882a593Smuzhiyun ivideo->current_width = ivideo->video_width;
1324*4882a593Smuzhiyun ivideo->current_height = ivideo->video_height;
1325*4882a593Smuzhiyun ivideo->current_bpp = ivideo->video_bpp;
1326*4882a593Smuzhiyun ivideo->current_htotal = htotal;
1327*4882a593Smuzhiyun ivideo->current_vtotal = vtotal;
1328*4882a593Smuzhiyun ivideo->current_linelength = ivideo->video_linelength;
1329*4882a593Smuzhiyun ivideo->current_pixclock = var->pixclock;
1330*4882a593Smuzhiyun ivideo->current_refresh_rate = ivideo->refresh_rate;
1331*4882a593Smuzhiyun ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
1332*4882a593Smuzhiyun }
1333*4882a593Smuzhiyun
1334*4882a593Smuzhiyun return 0;
1335*4882a593Smuzhiyun }
1336*4882a593Smuzhiyun
1337*4882a593Smuzhiyun static void
sisfb_set_base_CRT1(struct sis_video_info * ivideo,unsigned int base)1338*4882a593Smuzhiyun sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
1339*4882a593Smuzhiyun {
1340*4882a593Smuzhiyun SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1341*4882a593Smuzhiyun
1342*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x0D, base & 0xFF);
1343*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x0C, (base >> 8) & 0xFF);
1344*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x0D, (base >> 16) & 0xFF);
1345*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_315_VGA) {
1346*4882a593Smuzhiyun SiS_SetRegANDOR(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1347*4882a593Smuzhiyun }
1348*4882a593Smuzhiyun }
1349*4882a593Smuzhiyun
1350*4882a593Smuzhiyun static void
sisfb_set_base_CRT2(struct sis_video_info * ivideo,unsigned int base)1351*4882a593Smuzhiyun sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
1352*4882a593Smuzhiyun {
1353*4882a593Smuzhiyun if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1354*4882a593Smuzhiyun SiS_SetRegOR(SISPART1, ivideo->CRT2_write_enable, 0x01);
1355*4882a593Smuzhiyun SiS_SetReg(SISPART1, 0x06, (base & 0xFF));
1356*4882a593Smuzhiyun SiS_SetReg(SISPART1, 0x05, ((base >> 8) & 0xFF));
1357*4882a593Smuzhiyun SiS_SetReg(SISPART1, 0x04, ((base >> 16) & 0xFF));
1358*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_315_VGA) {
1359*4882a593Smuzhiyun SiS_SetRegANDOR(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1360*4882a593Smuzhiyun }
1361*4882a593Smuzhiyun }
1362*4882a593Smuzhiyun }
1363*4882a593Smuzhiyun
1364*4882a593Smuzhiyun static int
sisfb_pan_var(struct sis_video_info * ivideo,struct fb_info * info,struct fb_var_screeninfo * var)1365*4882a593Smuzhiyun sisfb_pan_var(struct sis_video_info *ivideo, struct fb_info *info,
1366*4882a593Smuzhiyun struct fb_var_screeninfo *var)
1367*4882a593Smuzhiyun {
1368*4882a593Smuzhiyun ivideo->current_base = var->yoffset * info->var.xres_virtual
1369*4882a593Smuzhiyun + var->xoffset;
1370*4882a593Smuzhiyun
1371*4882a593Smuzhiyun /* calculate base bpp dep. */
1372*4882a593Smuzhiyun switch (info->var.bits_per_pixel) {
1373*4882a593Smuzhiyun case 32:
1374*4882a593Smuzhiyun break;
1375*4882a593Smuzhiyun case 16:
1376*4882a593Smuzhiyun ivideo->current_base >>= 1;
1377*4882a593Smuzhiyun break;
1378*4882a593Smuzhiyun case 8:
1379*4882a593Smuzhiyun default:
1380*4882a593Smuzhiyun ivideo->current_base >>= 2;
1381*4882a593Smuzhiyun break;
1382*4882a593Smuzhiyun }
1383*4882a593Smuzhiyun
1384*4882a593Smuzhiyun ivideo->current_base += (ivideo->video_offset >> 2);
1385*4882a593Smuzhiyun
1386*4882a593Smuzhiyun sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1387*4882a593Smuzhiyun sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1388*4882a593Smuzhiyun
1389*4882a593Smuzhiyun return 0;
1390*4882a593Smuzhiyun }
1391*4882a593Smuzhiyun
1392*4882a593Smuzhiyun static int
sisfb_open(struct fb_info * info,int user)1393*4882a593Smuzhiyun sisfb_open(struct fb_info *info, int user)
1394*4882a593Smuzhiyun {
1395*4882a593Smuzhiyun return 0;
1396*4882a593Smuzhiyun }
1397*4882a593Smuzhiyun
1398*4882a593Smuzhiyun static int
sisfb_release(struct fb_info * info,int user)1399*4882a593Smuzhiyun sisfb_release(struct fb_info *info, int user)
1400*4882a593Smuzhiyun {
1401*4882a593Smuzhiyun return 0;
1402*4882a593Smuzhiyun }
1403*4882a593Smuzhiyun
1404*4882a593Smuzhiyun static int
sisfb_setcolreg(unsigned regno,unsigned red,unsigned green,unsigned blue,unsigned transp,struct fb_info * info)1405*4882a593Smuzhiyun sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1406*4882a593Smuzhiyun unsigned transp, struct fb_info *info)
1407*4882a593Smuzhiyun {
1408*4882a593Smuzhiyun struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1409*4882a593Smuzhiyun
1410*4882a593Smuzhiyun if(regno >= sisfb_get_cmap_len(&info->var))
1411*4882a593Smuzhiyun return 1;
1412*4882a593Smuzhiyun
1413*4882a593Smuzhiyun switch(info->var.bits_per_pixel) {
1414*4882a593Smuzhiyun case 8:
1415*4882a593Smuzhiyun SiS_SetRegByte(SISDACA, regno);
1416*4882a593Smuzhiyun SiS_SetRegByte(SISDACD, (red >> 10));
1417*4882a593Smuzhiyun SiS_SetRegByte(SISDACD, (green >> 10));
1418*4882a593Smuzhiyun SiS_SetRegByte(SISDACD, (blue >> 10));
1419*4882a593Smuzhiyun if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1420*4882a593Smuzhiyun SiS_SetRegByte(SISDAC2A, regno);
1421*4882a593Smuzhiyun SiS_SetRegByte(SISDAC2D, (red >> 8));
1422*4882a593Smuzhiyun SiS_SetRegByte(SISDAC2D, (green >> 8));
1423*4882a593Smuzhiyun SiS_SetRegByte(SISDAC2D, (blue >> 8));
1424*4882a593Smuzhiyun }
1425*4882a593Smuzhiyun break;
1426*4882a593Smuzhiyun case 16:
1427*4882a593Smuzhiyun if (regno >= 16)
1428*4882a593Smuzhiyun break;
1429*4882a593Smuzhiyun
1430*4882a593Smuzhiyun ((u32 *)(info->pseudo_palette))[regno] =
1431*4882a593Smuzhiyun (red & 0xf800) |
1432*4882a593Smuzhiyun ((green & 0xfc00) >> 5) |
1433*4882a593Smuzhiyun ((blue & 0xf800) >> 11);
1434*4882a593Smuzhiyun break;
1435*4882a593Smuzhiyun case 32:
1436*4882a593Smuzhiyun if (regno >= 16)
1437*4882a593Smuzhiyun break;
1438*4882a593Smuzhiyun
1439*4882a593Smuzhiyun red >>= 8;
1440*4882a593Smuzhiyun green >>= 8;
1441*4882a593Smuzhiyun blue >>= 8;
1442*4882a593Smuzhiyun ((u32 *)(info->pseudo_palette))[regno] =
1443*4882a593Smuzhiyun (red << 16) | (green << 8) | (blue);
1444*4882a593Smuzhiyun break;
1445*4882a593Smuzhiyun }
1446*4882a593Smuzhiyun return 0;
1447*4882a593Smuzhiyun }
1448*4882a593Smuzhiyun
1449*4882a593Smuzhiyun static int
sisfb_set_par(struct fb_info * info)1450*4882a593Smuzhiyun sisfb_set_par(struct fb_info *info)
1451*4882a593Smuzhiyun {
1452*4882a593Smuzhiyun int err;
1453*4882a593Smuzhiyun
1454*4882a593Smuzhiyun if((err = sisfb_do_set_var(&info->var, 1, info)))
1455*4882a593Smuzhiyun return err;
1456*4882a593Smuzhiyun
1457*4882a593Smuzhiyun sisfb_get_fix(&info->fix, -1, info);
1458*4882a593Smuzhiyun
1459*4882a593Smuzhiyun return 0;
1460*4882a593Smuzhiyun }
1461*4882a593Smuzhiyun
1462*4882a593Smuzhiyun static int
sisfb_check_var(struct fb_var_screeninfo * var,struct fb_info * info)1463*4882a593Smuzhiyun sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1464*4882a593Smuzhiyun {
1465*4882a593Smuzhiyun struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1466*4882a593Smuzhiyun unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1467*4882a593Smuzhiyun unsigned int drate = 0, hrate = 0, maxyres;
1468*4882a593Smuzhiyun int found_mode = 0;
1469*4882a593Smuzhiyun int refresh_rate, search_idx, tidx;
1470*4882a593Smuzhiyun bool recalc_clock = false;
1471*4882a593Smuzhiyun u32 pixclock;
1472*4882a593Smuzhiyun
1473*4882a593Smuzhiyun htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1474*4882a593Smuzhiyun
1475*4882a593Smuzhiyun vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1476*4882a593Smuzhiyun
1477*4882a593Smuzhiyun pixclock = var->pixclock;
1478*4882a593Smuzhiyun
1479*4882a593Smuzhiyun if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1480*4882a593Smuzhiyun vtotal += var->yres;
1481*4882a593Smuzhiyun vtotal <<= 1;
1482*4882a593Smuzhiyun } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1483*4882a593Smuzhiyun vtotal += var->yres;
1484*4882a593Smuzhiyun vtotal <<= 2;
1485*4882a593Smuzhiyun } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1486*4882a593Smuzhiyun vtotal += var->yres;
1487*4882a593Smuzhiyun vtotal <<= 1;
1488*4882a593Smuzhiyun } else
1489*4882a593Smuzhiyun vtotal += var->yres;
1490*4882a593Smuzhiyun
1491*4882a593Smuzhiyun if(!(htotal) || !(vtotal)) {
1492*4882a593Smuzhiyun SISFAIL("sisfb: no valid timing data");
1493*4882a593Smuzhiyun }
1494*4882a593Smuzhiyun
1495*4882a593Smuzhiyun search_idx = 0;
1496*4882a593Smuzhiyun while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1497*4882a593Smuzhiyun (sisbios_mode[search_idx].xres <= var->xres) ) {
1498*4882a593Smuzhiyun if( (sisbios_mode[search_idx].xres == var->xres) &&
1499*4882a593Smuzhiyun (sisbios_mode[search_idx].yres == var->yres) &&
1500*4882a593Smuzhiyun (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1501*4882a593Smuzhiyun if((tidx = sisfb_validate_mode(ivideo, search_idx,
1502*4882a593Smuzhiyun ivideo->currentvbflags)) > 0) {
1503*4882a593Smuzhiyun found_mode = 1;
1504*4882a593Smuzhiyun search_idx = tidx;
1505*4882a593Smuzhiyun break;
1506*4882a593Smuzhiyun }
1507*4882a593Smuzhiyun }
1508*4882a593Smuzhiyun search_idx++;
1509*4882a593Smuzhiyun }
1510*4882a593Smuzhiyun
1511*4882a593Smuzhiyun if(!found_mode) {
1512*4882a593Smuzhiyun search_idx = 0;
1513*4882a593Smuzhiyun while(sisbios_mode[search_idx].mode_no[0] != 0) {
1514*4882a593Smuzhiyun if( (var->xres <= sisbios_mode[search_idx].xres) &&
1515*4882a593Smuzhiyun (var->yres <= sisbios_mode[search_idx].yres) &&
1516*4882a593Smuzhiyun (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1517*4882a593Smuzhiyun if((tidx = sisfb_validate_mode(ivideo,search_idx,
1518*4882a593Smuzhiyun ivideo->currentvbflags)) > 0) {
1519*4882a593Smuzhiyun found_mode = 1;
1520*4882a593Smuzhiyun search_idx = tidx;
1521*4882a593Smuzhiyun break;
1522*4882a593Smuzhiyun }
1523*4882a593Smuzhiyun }
1524*4882a593Smuzhiyun search_idx++;
1525*4882a593Smuzhiyun }
1526*4882a593Smuzhiyun if(found_mode) {
1527*4882a593Smuzhiyun printk(KERN_DEBUG
1528*4882a593Smuzhiyun "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1529*4882a593Smuzhiyun var->xres, var->yres, var->bits_per_pixel,
1530*4882a593Smuzhiyun sisbios_mode[search_idx].xres,
1531*4882a593Smuzhiyun sisbios_mode[search_idx].yres,
1532*4882a593Smuzhiyun var->bits_per_pixel);
1533*4882a593Smuzhiyun var->xres = sisbios_mode[search_idx].xres;
1534*4882a593Smuzhiyun var->yres = sisbios_mode[search_idx].yres;
1535*4882a593Smuzhiyun } else {
1536*4882a593Smuzhiyun printk(KERN_ERR
1537*4882a593Smuzhiyun "sisfb: Failed to find supported mode near %dx%dx%d\n",
1538*4882a593Smuzhiyun var->xres, var->yres, var->bits_per_pixel);
1539*4882a593Smuzhiyun return -EINVAL;
1540*4882a593Smuzhiyun }
1541*4882a593Smuzhiyun }
1542*4882a593Smuzhiyun
1543*4882a593Smuzhiyun if( ((ivideo->vbflags2 & VB2_LVDS) ||
1544*4882a593Smuzhiyun ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1545*4882a593Smuzhiyun (var->bits_per_pixel == 8) ) {
1546*4882a593Smuzhiyun /* Slave modes on LVDS and 301B-DH */
1547*4882a593Smuzhiyun refresh_rate = 60;
1548*4882a593Smuzhiyun recalc_clock = true;
1549*4882a593Smuzhiyun } else if( (ivideo->current_htotal == htotal) &&
1550*4882a593Smuzhiyun (ivideo->current_vtotal == vtotal) &&
1551*4882a593Smuzhiyun (ivideo->current_pixclock == pixclock) ) {
1552*4882a593Smuzhiyun /* x=x & y=y & c=c -> assume depth change */
1553*4882a593Smuzhiyun drate = 1000000000 / pixclock;
1554*4882a593Smuzhiyun hrate = (drate * 1000) / htotal;
1555*4882a593Smuzhiyun refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1556*4882a593Smuzhiyun } else if( ( (ivideo->current_htotal != htotal) ||
1557*4882a593Smuzhiyun (ivideo->current_vtotal != vtotal) ) &&
1558*4882a593Smuzhiyun (ivideo->current_pixclock == var->pixclock) ) {
1559*4882a593Smuzhiyun /* x!=x | y!=y & c=c -> invalid pixclock */
1560*4882a593Smuzhiyun if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1561*4882a593Smuzhiyun refresh_rate =
1562*4882a593Smuzhiyun ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1563*4882a593Smuzhiyun } else if(ivideo->sisfb_parm_rate != -1) {
1564*4882a593Smuzhiyun /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1565*4882a593Smuzhiyun refresh_rate = ivideo->sisfb_parm_rate;
1566*4882a593Smuzhiyun } else {
1567*4882a593Smuzhiyun refresh_rate = 60;
1568*4882a593Smuzhiyun }
1569*4882a593Smuzhiyun recalc_clock = true;
1570*4882a593Smuzhiyun } else if((pixclock) && (htotal) && (vtotal)) {
1571*4882a593Smuzhiyun drate = 1000000000 / pixclock;
1572*4882a593Smuzhiyun hrate = (drate * 1000) / htotal;
1573*4882a593Smuzhiyun refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1574*4882a593Smuzhiyun } else if(ivideo->current_refresh_rate) {
1575*4882a593Smuzhiyun refresh_rate = ivideo->current_refresh_rate;
1576*4882a593Smuzhiyun recalc_clock = true;
1577*4882a593Smuzhiyun } else {
1578*4882a593Smuzhiyun refresh_rate = 60;
1579*4882a593Smuzhiyun recalc_clock = true;
1580*4882a593Smuzhiyun }
1581*4882a593Smuzhiyun
1582*4882a593Smuzhiyun myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1583*4882a593Smuzhiyun
1584*4882a593Smuzhiyun /* Eventually recalculate timing and clock */
1585*4882a593Smuzhiyun if(recalc_clock) {
1586*4882a593Smuzhiyun if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1587*4882a593Smuzhiyun var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1588*4882a593Smuzhiyun sisbios_mode[search_idx].mode_no[ivideo->mni],
1589*4882a593Smuzhiyun myrateindex));
1590*4882a593Smuzhiyun sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1591*4882a593Smuzhiyun sisbios_mode[search_idx].mode_no[ivideo->mni],
1592*4882a593Smuzhiyun myrateindex, var);
1593*4882a593Smuzhiyun if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1594*4882a593Smuzhiyun var->pixclock <<= 1;
1595*4882a593Smuzhiyun }
1596*4882a593Smuzhiyun }
1597*4882a593Smuzhiyun
1598*4882a593Smuzhiyun if(ivideo->sisfb_thismonitor.datavalid) {
1599*4882a593Smuzhiyun if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1600*4882a593Smuzhiyun myrateindex, refresh_rate)) {
1601*4882a593Smuzhiyun printk(KERN_INFO
1602*4882a593Smuzhiyun "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1603*4882a593Smuzhiyun }
1604*4882a593Smuzhiyun }
1605*4882a593Smuzhiyun
1606*4882a593Smuzhiyun /* Adapt RGB settings */
1607*4882a593Smuzhiyun sisfb_bpp_to_var(ivideo, var);
1608*4882a593Smuzhiyun
1609*4882a593Smuzhiyun if(var->xres > var->xres_virtual)
1610*4882a593Smuzhiyun var->xres_virtual = var->xres;
1611*4882a593Smuzhiyun
1612*4882a593Smuzhiyun if(ivideo->sisfb_ypan) {
1613*4882a593Smuzhiyun maxyres = sisfb_calc_maxyres(ivideo, var);
1614*4882a593Smuzhiyun if(ivideo->sisfb_max) {
1615*4882a593Smuzhiyun var->yres_virtual = maxyres;
1616*4882a593Smuzhiyun } else {
1617*4882a593Smuzhiyun if(var->yres_virtual > maxyres) {
1618*4882a593Smuzhiyun var->yres_virtual = maxyres;
1619*4882a593Smuzhiyun }
1620*4882a593Smuzhiyun }
1621*4882a593Smuzhiyun if(var->yres_virtual <= var->yres) {
1622*4882a593Smuzhiyun var->yres_virtual = var->yres;
1623*4882a593Smuzhiyun }
1624*4882a593Smuzhiyun } else {
1625*4882a593Smuzhiyun if(var->yres != var->yres_virtual) {
1626*4882a593Smuzhiyun var->yres_virtual = var->yres;
1627*4882a593Smuzhiyun }
1628*4882a593Smuzhiyun var->xoffset = 0;
1629*4882a593Smuzhiyun var->yoffset = 0;
1630*4882a593Smuzhiyun }
1631*4882a593Smuzhiyun
1632*4882a593Smuzhiyun /* Truncate offsets to maximum if too high */
1633*4882a593Smuzhiyun if(var->xoffset > var->xres_virtual - var->xres) {
1634*4882a593Smuzhiyun var->xoffset = var->xres_virtual - var->xres - 1;
1635*4882a593Smuzhiyun }
1636*4882a593Smuzhiyun
1637*4882a593Smuzhiyun if(var->yoffset > var->yres_virtual - var->yres) {
1638*4882a593Smuzhiyun var->yoffset = var->yres_virtual - var->yres - 1;
1639*4882a593Smuzhiyun }
1640*4882a593Smuzhiyun
1641*4882a593Smuzhiyun /* Set everything else to 0 */
1642*4882a593Smuzhiyun var->red.msb_right =
1643*4882a593Smuzhiyun var->green.msb_right =
1644*4882a593Smuzhiyun var->blue.msb_right =
1645*4882a593Smuzhiyun var->transp.offset =
1646*4882a593Smuzhiyun var->transp.length =
1647*4882a593Smuzhiyun var->transp.msb_right = 0;
1648*4882a593Smuzhiyun
1649*4882a593Smuzhiyun return 0;
1650*4882a593Smuzhiyun }
1651*4882a593Smuzhiyun
1652*4882a593Smuzhiyun static int
sisfb_pan_display(struct fb_var_screeninfo * var,struct fb_info * info)1653*4882a593Smuzhiyun sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1654*4882a593Smuzhiyun {
1655*4882a593Smuzhiyun struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1656*4882a593Smuzhiyun int err;
1657*4882a593Smuzhiyun
1658*4882a593Smuzhiyun if (var->vmode & FB_VMODE_YWRAP)
1659*4882a593Smuzhiyun return -EINVAL;
1660*4882a593Smuzhiyun
1661*4882a593Smuzhiyun if (var->xoffset + info->var.xres > info->var.xres_virtual ||
1662*4882a593Smuzhiyun var->yoffset + info->var.yres > info->var.yres_virtual)
1663*4882a593Smuzhiyun return -EINVAL;
1664*4882a593Smuzhiyun
1665*4882a593Smuzhiyun err = sisfb_pan_var(ivideo, info, var);
1666*4882a593Smuzhiyun if (err < 0)
1667*4882a593Smuzhiyun return err;
1668*4882a593Smuzhiyun
1669*4882a593Smuzhiyun info->var.xoffset = var->xoffset;
1670*4882a593Smuzhiyun info->var.yoffset = var->yoffset;
1671*4882a593Smuzhiyun
1672*4882a593Smuzhiyun return 0;
1673*4882a593Smuzhiyun }
1674*4882a593Smuzhiyun
1675*4882a593Smuzhiyun static int
sisfb_blank(int blank,struct fb_info * info)1676*4882a593Smuzhiyun sisfb_blank(int blank, struct fb_info *info)
1677*4882a593Smuzhiyun {
1678*4882a593Smuzhiyun struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1679*4882a593Smuzhiyun
1680*4882a593Smuzhiyun return sisfb_myblank(ivideo, blank);
1681*4882a593Smuzhiyun }
1682*4882a593Smuzhiyun
1683*4882a593Smuzhiyun /* ----------- FBDev related routines for all series ---------- */
1684*4882a593Smuzhiyun
sisfb_ioctl(struct fb_info * info,unsigned int cmd,unsigned long arg)1685*4882a593Smuzhiyun static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1686*4882a593Smuzhiyun unsigned long arg)
1687*4882a593Smuzhiyun {
1688*4882a593Smuzhiyun struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1689*4882a593Smuzhiyun struct sis_memreq sismemreq;
1690*4882a593Smuzhiyun struct fb_vblank sisvbblank;
1691*4882a593Smuzhiyun u32 gpu32 = 0;
1692*4882a593Smuzhiyun #ifndef __user
1693*4882a593Smuzhiyun #define __user
1694*4882a593Smuzhiyun #endif
1695*4882a593Smuzhiyun u32 __user *argp = (u32 __user *)arg;
1696*4882a593Smuzhiyun
1697*4882a593Smuzhiyun switch(cmd) {
1698*4882a593Smuzhiyun case FBIO_ALLOC:
1699*4882a593Smuzhiyun if(!capable(CAP_SYS_RAWIO))
1700*4882a593Smuzhiyun return -EPERM;
1701*4882a593Smuzhiyun
1702*4882a593Smuzhiyun if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1703*4882a593Smuzhiyun return -EFAULT;
1704*4882a593Smuzhiyun
1705*4882a593Smuzhiyun sis_malloc(&sismemreq);
1706*4882a593Smuzhiyun
1707*4882a593Smuzhiyun if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1708*4882a593Smuzhiyun sis_free((u32)sismemreq.offset);
1709*4882a593Smuzhiyun return -EFAULT;
1710*4882a593Smuzhiyun }
1711*4882a593Smuzhiyun break;
1712*4882a593Smuzhiyun
1713*4882a593Smuzhiyun case FBIO_FREE:
1714*4882a593Smuzhiyun if(!capable(CAP_SYS_RAWIO))
1715*4882a593Smuzhiyun return -EPERM;
1716*4882a593Smuzhiyun
1717*4882a593Smuzhiyun if(get_user(gpu32, argp))
1718*4882a593Smuzhiyun return -EFAULT;
1719*4882a593Smuzhiyun
1720*4882a593Smuzhiyun sis_free(gpu32);
1721*4882a593Smuzhiyun break;
1722*4882a593Smuzhiyun
1723*4882a593Smuzhiyun case FBIOGET_VBLANK:
1724*4882a593Smuzhiyun
1725*4882a593Smuzhiyun memset(&sisvbblank, 0, sizeof(struct fb_vblank));
1726*4882a593Smuzhiyun
1727*4882a593Smuzhiyun sisvbblank.count = 0;
1728*4882a593Smuzhiyun sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
1729*4882a593Smuzhiyun
1730*4882a593Smuzhiyun if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
1731*4882a593Smuzhiyun return -EFAULT;
1732*4882a593Smuzhiyun
1733*4882a593Smuzhiyun break;
1734*4882a593Smuzhiyun
1735*4882a593Smuzhiyun case SISFB_GET_INFO_SIZE:
1736*4882a593Smuzhiyun return put_user(sizeof(struct sisfb_info), argp);
1737*4882a593Smuzhiyun
1738*4882a593Smuzhiyun case SISFB_GET_INFO_OLD:
1739*4882a593Smuzhiyun if(ivideo->warncount++ < 10)
1740*4882a593Smuzhiyun printk(KERN_INFO
1741*4882a593Smuzhiyun "sisfb: Deprecated ioctl call received - update your application!\n");
1742*4882a593Smuzhiyun fallthrough;
1743*4882a593Smuzhiyun case SISFB_GET_INFO: /* For communication with X driver */
1744*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1745*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1746*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1747*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1748*4882a593Smuzhiyun ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1749*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1750*4882a593Smuzhiyun ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1751*4882a593Smuzhiyun ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
1752*4882a593Smuzhiyun if(ivideo->modechanged) {
1753*4882a593Smuzhiyun ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
1754*4882a593Smuzhiyun } else {
1755*4882a593Smuzhiyun ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
1756*4882a593Smuzhiyun }
1757*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1758*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1759*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1760*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1761*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1762*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1763*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1764*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1765*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1766*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1767*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1768*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1769*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1770*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1771*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1772*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1773*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1774*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1775*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1776*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1777*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1778*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1779*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1780*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1781*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1782*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1783*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1784*4882a593Smuzhiyun ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
1785*4882a593Smuzhiyun
1786*4882a593Smuzhiyun if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1787*4882a593Smuzhiyun sizeof(ivideo->sisfb_infoblock)))
1788*4882a593Smuzhiyun return -EFAULT;
1789*4882a593Smuzhiyun
1790*4882a593Smuzhiyun break;
1791*4882a593Smuzhiyun
1792*4882a593Smuzhiyun case SISFB_GET_VBRSTATUS_OLD:
1793*4882a593Smuzhiyun if(ivideo->warncount++ < 10)
1794*4882a593Smuzhiyun printk(KERN_INFO
1795*4882a593Smuzhiyun "sisfb: Deprecated ioctl call received - update your application!\n");
1796*4882a593Smuzhiyun fallthrough;
1797*4882a593Smuzhiyun case SISFB_GET_VBRSTATUS:
1798*4882a593Smuzhiyun if(sisfb_CheckVBRetrace(ivideo))
1799*4882a593Smuzhiyun return put_user((u32)1, argp);
1800*4882a593Smuzhiyun else
1801*4882a593Smuzhiyun return put_user((u32)0, argp);
1802*4882a593Smuzhiyun
1803*4882a593Smuzhiyun case SISFB_GET_AUTOMAXIMIZE_OLD:
1804*4882a593Smuzhiyun if(ivideo->warncount++ < 10)
1805*4882a593Smuzhiyun printk(KERN_INFO
1806*4882a593Smuzhiyun "sisfb: Deprecated ioctl call received - update your application!\n");
1807*4882a593Smuzhiyun fallthrough;
1808*4882a593Smuzhiyun case SISFB_GET_AUTOMAXIMIZE:
1809*4882a593Smuzhiyun if(ivideo->sisfb_max)
1810*4882a593Smuzhiyun return put_user((u32)1, argp);
1811*4882a593Smuzhiyun else
1812*4882a593Smuzhiyun return put_user((u32)0, argp);
1813*4882a593Smuzhiyun
1814*4882a593Smuzhiyun case SISFB_SET_AUTOMAXIMIZE_OLD:
1815*4882a593Smuzhiyun if(ivideo->warncount++ < 10)
1816*4882a593Smuzhiyun printk(KERN_INFO
1817*4882a593Smuzhiyun "sisfb: Deprecated ioctl call received - update your application!\n");
1818*4882a593Smuzhiyun fallthrough;
1819*4882a593Smuzhiyun case SISFB_SET_AUTOMAXIMIZE:
1820*4882a593Smuzhiyun if(get_user(gpu32, argp))
1821*4882a593Smuzhiyun return -EFAULT;
1822*4882a593Smuzhiyun
1823*4882a593Smuzhiyun ivideo->sisfb_max = (gpu32) ? 1 : 0;
1824*4882a593Smuzhiyun break;
1825*4882a593Smuzhiyun
1826*4882a593Smuzhiyun case SISFB_SET_TVPOSOFFSET:
1827*4882a593Smuzhiyun if(get_user(gpu32, argp))
1828*4882a593Smuzhiyun return -EFAULT;
1829*4882a593Smuzhiyun
1830*4882a593Smuzhiyun sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1831*4882a593Smuzhiyun sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1832*4882a593Smuzhiyun break;
1833*4882a593Smuzhiyun
1834*4882a593Smuzhiyun case SISFB_GET_TVPOSOFFSET:
1835*4882a593Smuzhiyun return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1836*4882a593Smuzhiyun argp);
1837*4882a593Smuzhiyun
1838*4882a593Smuzhiyun case SISFB_COMMAND:
1839*4882a593Smuzhiyun if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1840*4882a593Smuzhiyun sizeof(struct sisfb_cmd)))
1841*4882a593Smuzhiyun return -EFAULT;
1842*4882a593Smuzhiyun
1843*4882a593Smuzhiyun sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1844*4882a593Smuzhiyun
1845*4882a593Smuzhiyun if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1846*4882a593Smuzhiyun sizeof(struct sisfb_cmd)))
1847*4882a593Smuzhiyun return -EFAULT;
1848*4882a593Smuzhiyun
1849*4882a593Smuzhiyun break;
1850*4882a593Smuzhiyun
1851*4882a593Smuzhiyun case SISFB_SET_LOCK:
1852*4882a593Smuzhiyun if(get_user(gpu32, argp))
1853*4882a593Smuzhiyun return -EFAULT;
1854*4882a593Smuzhiyun
1855*4882a593Smuzhiyun ivideo->sisfblocked = (gpu32) ? 1 : 0;
1856*4882a593Smuzhiyun break;
1857*4882a593Smuzhiyun
1858*4882a593Smuzhiyun default:
1859*4882a593Smuzhiyun #ifdef SIS_NEW_CONFIG_COMPAT
1860*4882a593Smuzhiyun return -ENOIOCTLCMD;
1861*4882a593Smuzhiyun #else
1862*4882a593Smuzhiyun return -EINVAL;
1863*4882a593Smuzhiyun #endif
1864*4882a593Smuzhiyun }
1865*4882a593Smuzhiyun return 0;
1866*4882a593Smuzhiyun }
1867*4882a593Smuzhiyun
1868*4882a593Smuzhiyun static int
sisfb_get_fix(struct fb_fix_screeninfo * fix,int con,struct fb_info * info)1869*4882a593Smuzhiyun sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1870*4882a593Smuzhiyun {
1871*4882a593Smuzhiyun struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1872*4882a593Smuzhiyun
1873*4882a593Smuzhiyun memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1874*4882a593Smuzhiyun
1875*4882a593Smuzhiyun strlcpy(fix->id, ivideo->myid, sizeof(fix->id));
1876*4882a593Smuzhiyun
1877*4882a593Smuzhiyun mutex_lock(&info->mm_lock);
1878*4882a593Smuzhiyun fix->smem_start = ivideo->video_base + ivideo->video_offset;
1879*4882a593Smuzhiyun fix->smem_len = ivideo->sisfb_mem;
1880*4882a593Smuzhiyun mutex_unlock(&info->mm_lock);
1881*4882a593Smuzhiyun fix->type = FB_TYPE_PACKED_PIXELS;
1882*4882a593Smuzhiyun fix->type_aux = 0;
1883*4882a593Smuzhiyun fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1884*4882a593Smuzhiyun fix->xpanstep = 1;
1885*4882a593Smuzhiyun fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1886*4882a593Smuzhiyun fix->ywrapstep = 0;
1887*4882a593Smuzhiyun fix->line_length = ivideo->video_linelength;
1888*4882a593Smuzhiyun fix->mmio_start = ivideo->mmio_base;
1889*4882a593Smuzhiyun fix->mmio_len = ivideo->mmio_size;
1890*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_300_VGA) {
1891*4882a593Smuzhiyun fix->accel = FB_ACCEL_SIS_GLAMOUR;
1892*4882a593Smuzhiyun } else if((ivideo->chip == SIS_330) ||
1893*4882a593Smuzhiyun (ivideo->chip == SIS_760) ||
1894*4882a593Smuzhiyun (ivideo->chip == SIS_761)) {
1895*4882a593Smuzhiyun fix->accel = FB_ACCEL_SIS_XABRE;
1896*4882a593Smuzhiyun } else if(ivideo->chip == XGI_20) {
1897*4882a593Smuzhiyun fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1898*4882a593Smuzhiyun } else if(ivideo->chip >= XGI_40) {
1899*4882a593Smuzhiyun fix->accel = FB_ACCEL_XGI_VOLARI_V;
1900*4882a593Smuzhiyun } else {
1901*4882a593Smuzhiyun fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
1902*4882a593Smuzhiyun }
1903*4882a593Smuzhiyun
1904*4882a593Smuzhiyun return 0;
1905*4882a593Smuzhiyun }
1906*4882a593Smuzhiyun
1907*4882a593Smuzhiyun /* ---------------- fb_ops structures ----------------- */
1908*4882a593Smuzhiyun
1909*4882a593Smuzhiyun static const struct fb_ops sisfb_ops = {
1910*4882a593Smuzhiyun .owner = THIS_MODULE,
1911*4882a593Smuzhiyun .fb_open = sisfb_open,
1912*4882a593Smuzhiyun .fb_release = sisfb_release,
1913*4882a593Smuzhiyun .fb_check_var = sisfb_check_var,
1914*4882a593Smuzhiyun .fb_set_par = sisfb_set_par,
1915*4882a593Smuzhiyun .fb_setcolreg = sisfb_setcolreg,
1916*4882a593Smuzhiyun .fb_pan_display = sisfb_pan_display,
1917*4882a593Smuzhiyun .fb_blank = sisfb_blank,
1918*4882a593Smuzhiyun .fb_fillrect = fbcon_sis_fillrect,
1919*4882a593Smuzhiyun .fb_copyarea = fbcon_sis_copyarea,
1920*4882a593Smuzhiyun .fb_imageblit = cfb_imageblit,
1921*4882a593Smuzhiyun .fb_sync = fbcon_sis_sync,
1922*4882a593Smuzhiyun #ifdef SIS_NEW_CONFIG_COMPAT
1923*4882a593Smuzhiyun .fb_compat_ioctl= sisfb_ioctl,
1924*4882a593Smuzhiyun #endif
1925*4882a593Smuzhiyun .fb_ioctl = sisfb_ioctl
1926*4882a593Smuzhiyun };
1927*4882a593Smuzhiyun
1928*4882a593Smuzhiyun /* ---------------- Chip generation dependent routines ---------------- */
1929*4882a593Smuzhiyun
sisfb_get_northbridge(int basechipid)1930*4882a593Smuzhiyun static struct pci_dev *sisfb_get_northbridge(int basechipid)
1931*4882a593Smuzhiyun {
1932*4882a593Smuzhiyun struct pci_dev *pdev = NULL;
1933*4882a593Smuzhiyun int nbridgenum, nbridgeidx, i;
1934*4882a593Smuzhiyun static const unsigned short nbridgeids[] = {
1935*4882a593Smuzhiyun PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
1936*4882a593Smuzhiyun PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
1937*4882a593Smuzhiyun PCI_DEVICE_ID_SI_730,
1938*4882a593Smuzhiyun PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
1939*4882a593Smuzhiyun PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
1940*4882a593Smuzhiyun PCI_DEVICE_ID_SI_651,
1941*4882a593Smuzhiyun PCI_DEVICE_ID_SI_740,
1942*4882a593Smuzhiyun PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
1943*4882a593Smuzhiyun PCI_DEVICE_ID_SI_741,
1944*4882a593Smuzhiyun PCI_DEVICE_ID_SI_660,
1945*4882a593Smuzhiyun PCI_DEVICE_ID_SI_760,
1946*4882a593Smuzhiyun PCI_DEVICE_ID_SI_761
1947*4882a593Smuzhiyun };
1948*4882a593Smuzhiyun
1949*4882a593Smuzhiyun switch(basechipid) {
1950*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_300
1951*4882a593Smuzhiyun case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
1952*4882a593Smuzhiyun case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
1953*4882a593Smuzhiyun #endif
1954*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
1955*4882a593Smuzhiyun case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
1956*4882a593Smuzhiyun case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
1957*4882a593Smuzhiyun case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
1958*4882a593Smuzhiyun #endif
1959*4882a593Smuzhiyun default: return NULL;
1960*4882a593Smuzhiyun }
1961*4882a593Smuzhiyun for(i = 0; i < nbridgenum; i++) {
1962*4882a593Smuzhiyun if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
1963*4882a593Smuzhiyun nbridgeids[nbridgeidx+i], NULL)))
1964*4882a593Smuzhiyun break;
1965*4882a593Smuzhiyun }
1966*4882a593Smuzhiyun return pdev;
1967*4882a593Smuzhiyun }
1968*4882a593Smuzhiyun
sisfb_get_dram_size(struct sis_video_info * ivideo)1969*4882a593Smuzhiyun static int sisfb_get_dram_size(struct sis_video_info *ivideo)
1970*4882a593Smuzhiyun {
1971*4882a593Smuzhiyun #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1972*4882a593Smuzhiyun u8 reg;
1973*4882a593Smuzhiyun #endif
1974*4882a593Smuzhiyun
1975*4882a593Smuzhiyun ivideo->video_size = 0;
1976*4882a593Smuzhiyun ivideo->UMAsize = ivideo->LFBsize = 0;
1977*4882a593Smuzhiyun
1978*4882a593Smuzhiyun switch(ivideo->chip) {
1979*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_300
1980*4882a593Smuzhiyun case SIS_300:
1981*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x14);
1982*4882a593Smuzhiyun ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1983*4882a593Smuzhiyun break;
1984*4882a593Smuzhiyun case SIS_540:
1985*4882a593Smuzhiyun case SIS_630:
1986*4882a593Smuzhiyun case SIS_730:
1987*4882a593Smuzhiyun if(!ivideo->nbridge)
1988*4882a593Smuzhiyun return -1;
1989*4882a593Smuzhiyun pci_read_config_byte(ivideo->nbridge, 0x63, ®);
1990*4882a593Smuzhiyun ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1991*4882a593Smuzhiyun break;
1992*4882a593Smuzhiyun #endif
1993*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
1994*4882a593Smuzhiyun case SIS_315H:
1995*4882a593Smuzhiyun case SIS_315PRO:
1996*4882a593Smuzhiyun case SIS_315:
1997*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x14);
1998*4882a593Smuzhiyun ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1999*4882a593Smuzhiyun switch((reg >> 2) & 0x03) {
2000*4882a593Smuzhiyun case 0x01:
2001*4882a593Smuzhiyun case 0x03:
2002*4882a593Smuzhiyun ivideo->video_size <<= 1;
2003*4882a593Smuzhiyun break;
2004*4882a593Smuzhiyun case 0x02:
2005*4882a593Smuzhiyun ivideo->video_size += (ivideo->video_size/2);
2006*4882a593Smuzhiyun }
2007*4882a593Smuzhiyun break;
2008*4882a593Smuzhiyun case SIS_330:
2009*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x14);
2010*4882a593Smuzhiyun ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2011*4882a593Smuzhiyun if(reg & 0x0c) ivideo->video_size <<= 1;
2012*4882a593Smuzhiyun break;
2013*4882a593Smuzhiyun case SIS_550:
2014*4882a593Smuzhiyun case SIS_650:
2015*4882a593Smuzhiyun case SIS_740:
2016*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x14);
2017*4882a593Smuzhiyun ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2018*4882a593Smuzhiyun break;
2019*4882a593Smuzhiyun case SIS_661:
2020*4882a593Smuzhiyun case SIS_741:
2021*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x79);
2022*4882a593Smuzhiyun ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2023*4882a593Smuzhiyun break;
2024*4882a593Smuzhiyun case SIS_660:
2025*4882a593Smuzhiyun case SIS_760:
2026*4882a593Smuzhiyun case SIS_761:
2027*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x79);
2028*4882a593Smuzhiyun reg = (reg & 0xf0) >> 4;
2029*4882a593Smuzhiyun if(reg) {
2030*4882a593Smuzhiyun ivideo->video_size = (1 << reg) << 20;
2031*4882a593Smuzhiyun ivideo->UMAsize = ivideo->video_size;
2032*4882a593Smuzhiyun }
2033*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x78);
2034*4882a593Smuzhiyun reg &= 0x30;
2035*4882a593Smuzhiyun if(reg) {
2036*4882a593Smuzhiyun if(reg == 0x10) {
2037*4882a593Smuzhiyun ivideo->LFBsize = (32 << 20);
2038*4882a593Smuzhiyun } else {
2039*4882a593Smuzhiyun ivideo->LFBsize = (64 << 20);
2040*4882a593Smuzhiyun }
2041*4882a593Smuzhiyun ivideo->video_size += ivideo->LFBsize;
2042*4882a593Smuzhiyun }
2043*4882a593Smuzhiyun break;
2044*4882a593Smuzhiyun case SIS_340:
2045*4882a593Smuzhiyun case XGI_20:
2046*4882a593Smuzhiyun case XGI_40:
2047*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x14);
2048*4882a593Smuzhiyun ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2049*4882a593Smuzhiyun if(ivideo->chip != XGI_20) {
2050*4882a593Smuzhiyun reg = (reg & 0x0c) >> 2;
2051*4882a593Smuzhiyun if(ivideo->revision_id == 2) {
2052*4882a593Smuzhiyun if(reg & 0x01) reg = 0x02;
2053*4882a593Smuzhiyun else reg = 0x00;
2054*4882a593Smuzhiyun }
2055*4882a593Smuzhiyun if(reg == 0x02) ivideo->video_size <<= 1;
2056*4882a593Smuzhiyun else if(reg == 0x03) ivideo->video_size <<= 2;
2057*4882a593Smuzhiyun }
2058*4882a593Smuzhiyun break;
2059*4882a593Smuzhiyun #endif
2060*4882a593Smuzhiyun default:
2061*4882a593Smuzhiyun return -1;
2062*4882a593Smuzhiyun }
2063*4882a593Smuzhiyun return 0;
2064*4882a593Smuzhiyun }
2065*4882a593Smuzhiyun
2066*4882a593Smuzhiyun /* -------------- video bridge device detection --------------- */
2067*4882a593Smuzhiyun
sisfb_detect_VB_connect(struct sis_video_info * ivideo)2068*4882a593Smuzhiyun static void sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2069*4882a593Smuzhiyun {
2070*4882a593Smuzhiyun u8 cr32, temp;
2071*4882a593Smuzhiyun
2072*4882a593Smuzhiyun /* No CRT2 on XGI Z7 */
2073*4882a593Smuzhiyun if(ivideo->chip == XGI_20) {
2074*4882a593Smuzhiyun ivideo->sisfb_crt1off = 0;
2075*4882a593Smuzhiyun return;
2076*4882a593Smuzhiyun }
2077*4882a593Smuzhiyun
2078*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_300
2079*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_300_VGA) {
2080*4882a593Smuzhiyun temp = SiS_GetReg(SISSR, 0x17);
2081*4882a593Smuzhiyun if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2082*4882a593Smuzhiyun /* PAL/NTSC is stored on SR16 on such machines */
2083*4882a593Smuzhiyun if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2084*4882a593Smuzhiyun temp = SiS_GetReg(SISSR, 0x16);
2085*4882a593Smuzhiyun if(temp & 0x20)
2086*4882a593Smuzhiyun ivideo->vbflags |= TV_PAL;
2087*4882a593Smuzhiyun else
2088*4882a593Smuzhiyun ivideo->vbflags |= TV_NTSC;
2089*4882a593Smuzhiyun }
2090*4882a593Smuzhiyun }
2091*4882a593Smuzhiyun }
2092*4882a593Smuzhiyun #endif
2093*4882a593Smuzhiyun
2094*4882a593Smuzhiyun cr32 = SiS_GetReg(SISCR, 0x32);
2095*4882a593Smuzhiyun
2096*4882a593Smuzhiyun if(cr32 & SIS_CRT1) {
2097*4882a593Smuzhiyun ivideo->sisfb_crt1off = 0;
2098*4882a593Smuzhiyun } else {
2099*4882a593Smuzhiyun ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2100*4882a593Smuzhiyun }
2101*4882a593Smuzhiyun
2102*4882a593Smuzhiyun ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2103*4882a593Smuzhiyun
2104*4882a593Smuzhiyun if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2105*4882a593Smuzhiyun if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2106*4882a593Smuzhiyun if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2107*4882a593Smuzhiyun
2108*4882a593Smuzhiyun /* Check given parms for hardware compatibility.
2109*4882a593Smuzhiyun * (Cannot do this in the search_xx routines since we don't
2110*4882a593Smuzhiyun * know what hardware we are running on then)
2111*4882a593Smuzhiyun */
2112*4882a593Smuzhiyun
2113*4882a593Smuzhiyun if(ivideo->chip != SIS_550) {
2114*4882a593Smuzhiyun ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2115*4882a593Smuzhiyun }
2116*4882a593Smuzhiyun
2117*4882a593Smuzhiyun if(ivideo->sisfb_tvplug != -1) {
2118*4882a593Smuzhiyun if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2119*4882a593Smuzhiyun (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
2120*4882a593Smuzhiyun if(ivideo->sisfb_tvplug & TV_YPBPR) {
2121*4882a593Smuzhiyun ivideo->sisfb_tvplug = -1;
2122*4882a593Smuzhiyun printk(KERN_ERR "sisfb: YPbPr not supported\n");
2123*4882a593Smuzhiyun }
2124*4882a593Smuzhiyun }
2125*4882a593Smuzhiyun }
2126*4882a593Smuzhiyun if(ivideo->sisfb_tvplug != -1) {
2127*4882a593Smuzhiyun if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2128*4882a593Smuzhiyun (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
2129*4882a593Smuzhiyun if(ivideo->sisfb_tvplug & TV_HIVISION) {
2130*4882a593Smuzhiyun ivideo->sisfb_tvplug = -1;
2131*4882a593Smuzhiyun printk(KERN_ERR "sisfb: HiVision not supported\n");
2132*4882a593Smuzhiyun }
2133*4882a593Smuzhiyun }
2134*4882a593Smuzhiyun }
2135*4882a593Smuzhiyun if(ivideo->sisfb_tvstd != -1) {
2136*4882a593Smuzhiyun if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2137*4882a593Smuzhiyun (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2138*4882a593Smuzhiyun (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
2139*4882a593Smuzhiyun if(ivideo->sisfb_tvstd & (TV_PALM | TV_PALN | TV_NTSCJ)) {
2140*4882a593Smuzhiyun ivideo->sisfb_tvstd = -1;
2141*4882a593Smuzhiyun printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2142*4882a593Smuzhiyun }
2143*4882a593Smuzhiyun }
2144*4882a593Smuzhiyun }
2145*4882a593Smuzhiyun
2146*4882a593Smuzhiyun /* Detect/set TV plug & type */
2147*4882a593Smuzhiyun if(ivideo->sisfb_tvplug != -1) {
2148*4882a593Smuzhiyun ivideo->vbflags |= ivideo->sisfb_tvplug;
2149*4882a593Smuzhiyun } else {
2150*4882a593Smuzhiyun if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2151*4882a593Smuzhiyun else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2152*4882a593Smuzhiyun else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
2153*4882a593Smuzhiyun else {
2154*4882a593Smuzhiyun if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2155*4882a593Smuzhiyun if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2156*4882a593Smuzhiyun }
2157*4882a593Smuzhiyun }
2158*4882a593Smuzhiyun
2159*4882a593Smuzhiyun if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2160*4882a593Smuzhiyun if(ivideo->sisfb_tvstd != -1) {
2161*4882a593Smuzhiyun ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2162*4882a593Smuzhiyun ivideo->vbflags |= ivideo->sisfb_tvstd;
2163*4882a593Smuzhiyun }
2164*4882a593Smuzhiyun if(ivideo->vbflags & TV_SCART) {
2165*4882a593Smuzhiyun ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2166*4882a593Smuzhiyun ivideo->vbflags |= TV_PAL;
2167*4882a593Smuzhiyun }
2168*4882a593Smuzhiyun if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2169*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_300_VGA) {
2170*4882a593Smuzhiyun temp = SiS_GetReg(SISSR, 0x38);
2171*4882a593Smuzhiyun if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2172*4882a593Smuzhiyun else ivideo->vbflags |= TV_NTSC;
2173*4882a593Smuzhiyun } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2174*4882a593Smuzhiyun temp = SiS_GetReg(SISSR, 0x38);
2175*4882a593Smuzhiyun if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2176*4882a593Smuzhiyun else ivideo->vbflags |= TV_NTSC;
2177*4882a593Smuzhiyun } else {
2178*4882a593Smuzhiyun temp = SiS_GetReg(SISCR, 0x79);
2179*4882a593Smuzhiyun if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2180*4882a593Smuzhiyun else ivideo->vbflags |= TV_NTSC;
2181*4882a593Smuzhiyun }
2182*4882a593Smuzhiyun }
2183*4882a593Smuzhiyun }
2184*4882a593Smuzhiyun
2185*4882a593Smuzhiyun /* Copy forceCRT1 option to CRT1off if option is given */
2186*4882a593Smuzhiyun if(ivideo->sisfb_forcecrt1 != -1) {
2187*4882a593Smuzhiyun ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2188*4882a593Smuzhiyun }
2189*4882a593Smuzhiyun }
2190*4882a593Smuzhiyun
2191*4882a593Smuzhiyun /* ------------------ Sensing routines ------------------ */
2192*4882a593Smuzhiyun
sisfb_test_DDC1(struct sis_video_info * ivideo)2193*4882a593Smuzhiyun static bool sisfb_test_DDC1(struct sis_video_info *ivideo)
2194*4882a593Smuzhiyun {
2195*4882a593Smuzhiyun unsigned short old;
2196*4882a593Smuzhiyun int count = 48;
2197*4882a593Smuzhiyun
2198*4882a593Smuzhiyun old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2199*4882a593Smuzhiyun do {
2200*4882a593Smuzhiyun if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2201*4882a593Smuzhiyun } while(count--);
2202*4882a593Smuzhiyun return (count != -1);
2203*4882a593Smuzhiyun }
2204*4882a593Smuzhiyun
sisfb_sense_crt1(struct sis_video_info * ivideo)2205*4882a593Smuzhiyun static void sisfb_sense_crt1(struct sis_video_info *ivideo)
2206*4882a593Smuzhiyun {
2207*4882a593Smuzhiyun bool mustwait = false;
2208*4882a593Smuzhiyun u8 sr1F, cr17;
2209*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
2210*4882a593Smuzhiyun u8 cr63=0;
2211*4882a593Smuzhiyun #endif
2212*4882a593Smuzhiyun u16 temp = 0xffff;
2213*4882a593Smuzhiyun int i;
2214*4882a593Smuzhiyun
2215*4882a593Smuzhiyun sr1F = SiS_GetReg(SISSR, 0x1F);
2216*4882a593Smuzhiyun SiS_SetRegOR(SISSR, 0x1F, 0x04);
2217*4882a593Smuzhiyun SiS_SetRegAND(SISSR, 0x1F, 0x3F);
2218*4882a593Smuzhiyun if(sr1F & 0xc0) mustwait = true;
2219*4882a593Smuzhiyun
2220*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
2221*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_315_VGA) {
2222*4882a593Smuzhiyun cr63 = SiS_GetReg(SISCR, ivideo->SiS_Pr.SiS_MyCR63);
2223*4882a593Smuzhiyun cr63 &= 0x40;
2224*4882a593Smuzhiyun SiS_SetRegAND(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF);
2225*4882a593Smuzhiyun }
2226*4882a593Smuzhiyun #endif
2227*4882a593Smuzhiyun
2228*4882a593Smuzhiyun cr17 = SiS_GetReg(SISCR, 0x17);
2229*4882a593Smuzhiyun cr17 &= 0x80;
2230*4882a593Smuzhiyun if(!cr17) {
2231*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0x17, 0x80);
2232*4882a593Smuzhiyun mustwait = true;
2233*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x00, 0x01);
2234*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x00, 0x03);
2235*4882a593Smuzhiyun }
2236*4882a593Smuzhiyun
2237*4882a593Smuzhiyun if(mustwait) {
2238*4882a593Smuzhiyun for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2239*4882a593Smuzhiyun }
2240*4882a593Smuzhiyun
2241*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
2242*4882a593Smuzhiyun if(ivideo->chip >= SIS_330) {
2243*4882a593Smuzhiyun SiS_SetRegAND(SISCR, 0x32, ~0x20);
2244*4882a593Smuzhiyun if(ivideo->chip >= SIS_340) {
2245*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x57, 0x4a);
2246*4882a593Smuzhiyun } else {
2247*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x57, 0x5f);
2248*4882a593Smuzhiyun }
2249*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0x53, 0x02);
2250*4882a593Smuzhiyun while ((SiS_GetRegByte(SISINPSTAT)) & 0x01) break;
2251*4882a593Smuzhiyun while (!((SiS_GetRegByte(SISINPSTAT)) & 0x01)) break;
2252*4882a593Smuzhiyun if ((SiS_GetRegByte(SISMISCW)) & 0x10) temp = 1;
2253*4882a593Smuzhiyun SiS_SetRegAND(SISCR, 0x53, 0xfd);
2254*4882a593Smuzhiyun SiS_SetRegAND(SISCR, 0x57, 0x00);
2255*4882a593Smuzhiyun }
2256*4882a593Smuzhiyun #endif
2257*4882a593Smuzhiyun
2258*4882a593Smuzhiyun if(temp == 0xffff) {
2259*4882a593Smuzhiyun i = 3;
2260*4882a593Smuzhiyun do {
2261*4882a593Smuzhiyun temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2262*4882a593Smuzhiyun ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
2263*4882a593Smuzhiyun } while(((temp == 0) || (temp == 0xffff)) && i--);
2264*4882a593Smuzhiyun
2265*4882a593Smuzhiyun if((temp == 0) || (temp == 0xffff)) {
2266*4882a593Smuzhiyun if(sisfb_test_DDC1(ivideo)) temp = 1;
2267*4882a593Smuzhiyun }
2268*4882a593Smuzhiyun }
2269*4882a593Smuzhiyun
2270*4882a593Smuzhiyun if((temp) && (temp != 0xffff)) {
2271*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0x32, 0x20);
2272*4882a593Smuzhiyun }
2273*4882a593Smuzhiyun
2274*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
2275*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_315_VGA) {
2276*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF, cr63);
2277*4882a593Smuzhiyun }
2278*4882a593Smuzhiyun #endif
2279*4882a593Smuzhiyun
2280*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x17, 0x7F, cr17);
2281*4882a593Smuzhiyun
2282*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x1F, sr1F);
2283*4882a593Smuzhiyun }
2284*4882a593Smuzhiyun
2285*4882a593Smuzhiyun /* Determine and detect attached devices on SiS30x */
SiS_SenseLCD(struct sis_video_info * ivideo)2286*4882a593Smuzhiyun static void SiS_SenseLCD(struct sis_video_info *ivideo)
2287*4882a593Smuzhiyun {
2288*4882a593Smuzhiyun unsigned char buffer[256];
2289*4882a593Smuzhiyun unsigned short temp, realcrtno, i;
2290*4882a593Smuzhiyun u8 reg, cr37 = 0, paneltype = 0;
2291*4882a593Smuzhiyun u16 xres, yres;
2292*4882a593Smuzhiyun
2293*4882a593Smuzhiyun ivideo->SiS_Pr.PanelSelfDetected = false;
2294*4882a593Smuzhiyun
2295*4882a593Smuzhiyun /* LCD detection only for TMDS bridges */
2296*4882a593Smuzhiyun if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2297*4882a593Smuzhiyun return;
2298*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_30xBDH)
2299*4882a593Smuzhiyun return;
2300*4882a593Smuzhiyun
2301*4882a593Smuzhiyun /* If LCD already set up by BIOS, skip it */
2302*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x32);
2303*4882a593Smuzhiyun if(reg & 0x08)
2304*4882a593Smuzhiyun return;
2305*4882a593Smuzhiyun
2306*4882a593Smuzhiyun realcrtno = 1;
2307*4882a593Smuzhiyun if(ivideo->SiS_Pr.DDCPortMixup)
2308*4882a593Smuzhiyun realcrtno = 0;
2309*4882a593Smuzhiyun
2310*4882a593Smuzhiyun /* Check DDC capabilities */
2311*4882a593Smuzhiyun temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2312*4882a593Smuzhiyun realcrtno, 0, &buffer[0], ivideo->vbflags2);
2313*4882a593Smuzhiyun
2314*4882a593Smuzhiyun if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2315*4882a593Smuzhiyun return;
2316*4882a593Smuzhiyun
2317*4882a593Smuzhiyun /* Read DDC data */
2318*4882a593Smuzhiyun i = 3; /* Number of retrys */
2319*4882a593Smuzhiyun do {
2320*4882a593Smuzhiyun temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2321*4882a593Smuzhiyun ivideo->sisvga_engine, realcrtno, 1,
2322*4882a593Smuzhiyun &buffer[0], ivideo->vbflags2);
2323*4882a593Smuzhiyun } while((temp) && i--);
2324*4882a593Smuzhiyun
2325*4882a593Smuzhiyun if(temp)
2326*4882a593Smuzhiyun return;
2327*4882a593Smuzhiyun
2328*4882a593Smuzhiyun /* No digital device */
2329*4882a593Smuzhiyun if(!(buffer[0x14] & 0x80))
2330*4882a593Smuzhiyun return;
2331*4882a593Smuzhiyun
2332*4882a593Smuzhiyun /* First detailed timing preferred timing? */
2333*4882a593Smuzhiyun if(!(buffer[0x18] & 0x02))
2334*4882a593Smuzhiyun return;
2335*4882a593Smuzhiyun
2336*4882a593Smuzhiyun xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2337*4882a593Smuzhiyun yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2338*4882a593Smuzhiyun
2339*4882a593Smuzhiyun switch(xres) {
2340*4882a593Smuzhiyun case 1024:
2341*4882a593Smuzhiyun if(yres == 768)
2342*4882a593Smuzhiyun paneltype = 0x02;
2343*4882a593Smuzhiyun break;
2344*4882a593Smuzhiyun case 1280:
2345*4882a593Smuzhiyun if(yres == 1024)
2346*4882a593Smuzhiyun paneltype = 0x03;
2347*4882a593Smuzhiyun break;
2348*4882a593Smuzhiyun case 1600:
2349*4882a593Smuzhiyun if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2350*4882a593Smuzhiyun paneltype = 0x0b;
2351*4882a593Smuzhiyun break;
2352*4882a593Smuzhiyun }
2353*4882a593Smuzhiyun
2354*4882a593Smuzhiyun if(!paneltype)
2355*4882a593Smuzhiyun return;
2356*4882a593Smuzhiyun
2357*4882a593Smuzhiyun if(buffer[0x23])
2358*4882a593Smuzhiyun cr37 |= 0x10;
2359*4882a593Smuzhiyun
2360*4882a593Smuzhiyun if((buffer[0x47] & 0x18) == 0x18)
2361*4882a593Smuzhiyun cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2362*4882a593Smuzhiyun else
2363*4882a593Smuzhiyun cr37 |= 0xc0;
2364*4882a593Smuzhiyun
2365*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x36, paneltype);
2366*4882a593Smuzhiyun cr37 &= 0xf1;
2367*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x37, 0x0c, cr37);
2368*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0x32, 0x08);
2369*4882a593Smuzhiyun
2370*4882a593Smuzhiyun ivideo->SiS_Pr.PanelSelfDetected = true;
2371*4882a593Smuzhiyun }
2372*4882a593Smuzhiyun
SISDoSense(struct sis_video_info * ivideo,u16 type,u16 test)2373*4882a593Smuzhiyun static int SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2374*4882a593Smuzhiyun {
2375*4882a593Smuzhiyun int temp, mytest, result, i, j;
2376*4882a593Smuzhiyun
2377*4882a593Smuzhiyun for(j = 0; j < 10; j++) {
2378*4882a593Smuzhiyun result = 0;
2379*4882a593Smuzhiyun for(i = 0; i < 3; i++) {
2380*4882a593Smuzhiyun mytest = test;
2381*4882a593Smuzhiyun SiS_SetReg(SISPART4, 0x11, (type & 0x00ff));
2382*4882a593Smuzhiyun temp = (type >> 8) | (mytest & 0x00ff);
2383*4882a593Smuzhiyun SiS_SetRegANDOR(SISPART4, 0x10, 0xe0, temp);
2384*4882a593Smuzhiyun SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2385*4882a593Smuzhiyun mytest >>= 8;
2386*4882a593Smuzhiyun mytest &= 0x7f;
2387*4882a593Smuzhiyun temp = SiS_GetReg(SISPART4, 0x03);
2388*4882a593Smuzhiyun temp ^= 0x0e;
2389*4882a593Smuzhiyun temp &= mytest;
2390*4882a593Smuzhiyun if(temp == mytest) result++;
2391*4882a593Smuzhiyun #if 1
2392*4882a593Smuzhiyun SiS_SetReg(SISPART4, 0x11, 0x00);
2393*4882a593Smuzhiyun SiS_SetRegAND(SISPART4, 0x10, 0xe0);
2394*4882a593Smuzhiyun SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2395*4882a593Smuzhiyun #endif
2396*4882a593Smuzhiyun }
2397*4882a593Smuzhiyun if((result == 0) || (result >= 2)) break;
2398*4882a593Smuzhiyun }
2399*4882a593Smuzhiyun return result;
2400*4882a593Smuzhiyun }
2401*4882a593Smuzhiyun
SiS_Sense30x(struct sis_video_info * ivideo)2402*4882a593Smuzhiyun static void SiS_Sense30x(struct sis_video_info *ivideo)
2403*4882a593Smuzhiyun {
2404*4882a593Smuzhiyun u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2405*4882a593Smuzhiyun u16 svhs=0, svhs_c=0;
2406*4882a593Smuzhiyun u16 cvbs=0, cvbs_c=0;
2407*4882a593Smuzhiyun u16 vga2=0, vga2_c=0;
2408*4882a593Smuzhiyun int myflag, result;
2409*4882a593Smuzhiyun char stdstr[] = "sisfb: Detected";
2410*4882a593Smuzhiyun char tvstr[] = "TV connected to";
2411*4882a593Smuzhiyun
2412*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_301) {
2413*4882a593Smuzhiyun svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2414*4882a593Smuzhiyun myflag = SiS_GetReg(SISPART4, 0x01);
2415*4882a593Smuzhiyun if(myflag & 0x04) {
2416*4882a593Smuzhiyun svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2417*4882a593Smuzhiyun }
2418*4882a593Smuzhiyun } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
2419*4882a593Smuzhiyun svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2420*4882a593Smuzhiyun } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
2421*4882a593Smuzhiyun svhs = 0x0200; cvbs = 0x0100;
2422*4882a593Smuzhiyun } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
2423*4882a593Smuzhiyun svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2424*4882a593Smuzhiyun } else
2425*4882a593Smuzhiyun return;
2426*4882a593Smuzhiyun
2427*4882a593Smuzhiyun vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2428*4882a593Smuzhiyun if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
2429*4882a593Smuzhiyun svhs_c = 0x0408; cvbs_c = 0x0808;
2430*4882a593Smuzhiyun }
2431*4882a593Smuzhiyun
2432*4882a593Smuzhiyun biosflag = 2;
2433*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
2434*4882a593Smuzhiyun biosflag = ivideo->bios_abase[0x58] & 0x03;
2435*4882a593Smuzhiyun } else if(ivideo->newrom) {
2436*4882a593Smuzhiyun if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2437*4882a593Smuzhiyun } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2438*4882a593Smuzhiyun if(ivideo->bios_abase) {
2439*4882a593Smuzhiyun biosflag = ivideo->bios_abase[0xfe] & 0x03;
2440*4882a593Smuzhiyun }
2441*4882a593Smuzhiyun }
2442*4882a593Smuzhiyun
2443*4882a593Smuzhiyun if(ivideo->chip == SIS_300) {
2444*4882a593Smuzhiyun myflag = SiS_GetReg(SISSR, 0x3b);
2445*4882a593Smuzhiyun if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2446*4882a593Smuzhiyun }
2447*4882a593Smuzhiyun
2448*4882a593Smuzhiyun if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2449*4882a593Smuzhiyun vga2 = vga2_c = 0;
2450*4882a593Smuzhiyun }
2451*4882a593Smuzhiyun
2452*4882a593Smuzhiyun backupSR_1e = SiS_GetReg(SISSR, 0x1e);
2453*4882a593Smuzhiyun SiS_SetRegOR(SISSR, 0x1e, 0x20);
2454*4882a593Smuzhiyun
2455*4882a593Smuzhiyun backupP4_0d = SiS_GetReg(SISPART4, 0x0d);
2456*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_30xC) {
2457*4882a593Smuzhiyun SiS_SetRegANDOR(SISPART4, 0x0d, ~0x07, 0x01);
2458*4882a593Smuzhiyun } else {
2459*4882a593Smuzhiyun SiS_SetRegOR(SISPART4, 0x0d, 0x04);
2460*4882a593Smuzhiyun }
2461*4882a593Smuzhiyun SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2462*4882a593Smuzhiyun
2463*4882a593Smuzhiyun backupP2_00 = SiS_GetReg(SISPART2, 0x00);
2464*4882a593Smuzhiyun SiS_SetReg(SISPART2, 0x00, ((backupP2_00 | 0x1c) & 0xfc));
2465*4882a593Smuzhiyun
2466*4882a593Smuzhiyun backupP2_4d = SiS_GetReg(SISPART2, 0x4d);
2467*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
2468*4882a593Smuzhiyun SiS_SetReg(SISPART2, 0x4d, (backupP2_4d & ~0x10));
2469*4882a593Smuzhiyun }
2470*4882a593Smuzhiyun
2471*4882a593Smuzhiyun if(!(ivideo->vbflags2 & VB2_30xCLV)) {
2472*4882a593Smuzhiyun SISDoSense(ivideo, 0, 0);
2473*4882a593Smuzhiyun }
2474*4882a593Smuzhiyun
2475*4882a593Smuzhiyun SiS_SetRegAND(SISCR, 0x32, ~0x14);
2476*4882a593Smuzhiyun
2477*4882a593Smuzhiyun if(vga2_c || vga2) {
2478*4882a593Smuzhiyun if(SISDoSense(ivideo, vga2, vga2_c)) {
2479*4882a593Smuzhiyun if(biosflag & 0x01) {
2480*4882a593Smuzhiyun printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2481*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0x32, 0x04);
2482*4882a593Smuzhiyun } else {
2483*4882a593Smuzhiyun printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2484*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0x32, 0x10);
2485*4882a593Smuzhiyun }
2486*4882a593Smuzhiyun }
2487*4882a593Smuzhiyun }
2488*4882a593Smuzhiyun
2489*4882a593Smuzhiyun SiS_SetRegAND(SISCR, 0x32, 0x3f);
2490*4882a593Smuzhiyun
2491*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_30xCLV) {
2492*4882a593Smuzhiyun SiS_SetRegOR(SISPART4, 0x0d, 0x04);
2493*4882a593Smuzhiyun }
2494*4882a593Smuzhiyun
2495*4882a593Smuzhiyun if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
2496*4882a593Smuzhiyun SiS_SetReg(SISPART2, 0x4d, (backupP2_4d | 0x10));
2497*4882a593Smuzhiyun SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2498*4882a593Smuzhiyun if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2499*4882a593Smuzhiyun if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2500*4882a593Smuzhiyun printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2501*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0x32, 0x80);
2502*4882a593Smuzhiyun }
2503*4882a593Smuzhiyun }
2504*4882a593Smuzhiyun SiS_SetReg(SISPART2, 0x4d, backupP2_4d);
2505*4882a593Smuzhiyun }
2506*4882a593Smuzhiyun
2507*4882a593Smuzhiyun SiS_SetRegAND(SISCR, 0x32, ~0x03);
2508*4882a593Smuzhiyun
2509*4882a593Smuzhiyun if(!(ivideo->vbflags & TV_YPBPR)) {
2510*4882a593Smuzhiyun if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2511*4882a593Smuzhiyun printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2512*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0x32, 0x02);
2513*4882a593Smuzhiyun }
2514*4882a593Smuzhiyun if((biosflag & 0x02) || (!result)) {
2515*4882a593Smuzhiyun if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2516*4882a593Smuzhiyun printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2517*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0x32, 0x01);
2518*4882a593Smuzhiyun }
2519*4882a593Smuzhiyun }
2520*4882a593Smuzhiyun }
2521*4882a593Smuzhiyun
2522*4882a593Smuzhiyun SISDoSense(ivideo, 0, 0);
2523*4882a593Smuzhiyun
2524*4882a593Smuzhiyun SiS_SetReg(SISPART2, 0x00, backupP2_00);
2525*4882a593Smuzhiyun SiS_SetReg(SISPART4, 0x0d, backupP4_0d);
2526*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x1e, backupSR_1e);
2527*4882a593Smuzhiyun
2528*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_30xCLV) {
2529*4882a593Smuzhiyun biosflag = SiS_GetReg(SISPART2, 0x00);
2530*4882a593Smuzhiyun if(biosflag & 0x20) {
2531*4882a593Smuzhiyun for(myflag = 2; myflag > 0; myflag--) {
2532*4882a593Smuzhiyun biosflag ^= 0x20;
2533*4882a593Smuzhiyun SiS_SetReg(SISPART2, 0x00, biosflag);
2534*4882a593Smuzhiyun }
2535*4882a593Smuzhiyun }
2536*4882a593Smuzhiyun }
2537*4882a593Smuzhiyun
2538*4882a593Smuzhiyun SiS_SetReg(SISPART2, 0x00, backupP2_00);
2539*4882a593Smuzhiyun }
2540*4882a593Smuzhiyun
2541*4882a593Smuzhiyun /* Determine and detect attached TV's on Chrontel */
SiS_SenseCh(struct sis_video_info * ivideo)2542*4882a593Smuzhiyun static void SiS_SenseCh(struct sis_video_info *ivideo)
2543*4882a593Smuzhiyun {
2544*4882a593Smuzhiyun #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2545*4882a593Smuzhiyun u8 temp1, temp2;
2546*4882a593Smuzhiyun char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2547*4882a593Smuzhiyun #endif
2548*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_300
2549*4882a593Smuzhiyun unsigned char test[3];
2550*4882a593Smuzhiyun int i;
2551*4882a593Smuzhiyun #endif
2552*4882a593Smuzhiyun
2553*4882a593Smuzhiyun if(ivideo->chip < SIS_315H) {
2554*4882a593Smuzhiyun
2555*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_300
2556*4882a593Smuzhiyun ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2557*4882a593Smuzhiyun SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2558*4882a593Smuzhiyun SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2559*4882a593Smuzhiyun temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2560*4882a593Smuzhiyun /* See Chrontel TB31 for explanation */
2561*4882a593Smuzhiyun temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2562*4882a593Smuzhiyun if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2563*4882a593Smuzhiyun SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
2564*4882a593Smuzhiyun SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2565*4882a593Smuzhiyun }
2566*4882a593Smuzhiyun temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2567*4882a593Smuzhiyun if(temp2 != temp1) temp1 = temp2;
2568*4882a593Smuzhiyun
2569*4882a593Smuzhiyun if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2570*4882a593Smuzhiyun /* Read power status */
2571*4882a593Smuzhiyun temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2572*4882a593Smuzhiyun if((temp1 & 0x03) != 0x03) {
2573*4882a593Smuzhiyun /* Power all outputs */
2574*4882a593Smuzhiyun SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
2575*4882a593Smuzhiyun SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2576*4882a593Smuzhiyun }
2577*4882a593Smuzhiyun /* Sense connected TV devices */
2578*4882a593Smuzhiyun for(i = 0; i < 3; i++) {
2579*4882a593Smuzhiyun SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
2580*4882a593Smuzhiyun SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2581*4882a593Smuzhiyun SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
2582*4882a593Smuzhiyun SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2583*4882a593Smuzhiyun temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2584*4882a593Smuzhiyun if(!(temp1 & 0x08)) test[i] = 0x02;
2585*4882a593Smuzhiyun else if(!(temp1 & 0x02)) test[i] = 0x01;
2586*4882a593Smuzhiyun else test[i] = 0;
2587*4882a593Smuzhiyun SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2588*4882a593Smuzhiyun }
2589*4882a593Smuzhiyun
2590*4882a593Smuzhiyun if(test[0] == test[1]) temp1 = test[0];
2591*4882a593Smuzhiyun else if(test[0] == test[2]) temp1 = test[0];
2592*4882a593Smuzhiyun else if(test[1] == test[2]) temp1 = test[1];
2593*4882a593Smuzhiyun else {
2594*4882a593Smuzhiyun printk(KERN_INFO
2595*4882a593Smuzhiyun "sisfb: TV detection unreliable - test results varied\n");
2596*4882a593Smuzhiyun temp1 = test[2];
2597*4882a593Smuzhiyun }
2598*4882a593Smuzhiyun if(temp1 == 0x02) {
2599*4882a593Smuzhiyun printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2600*4882a593Smuzhiyun ivideo->vbflags |= TV_SVIDEO;
2601*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0x32, 0x02);
2602*4882a593Smuzhiyun SiS_SetRegAND(SISCR, 0x32, ~0x05);
2603*4882a593Smuzhiyun } else if (temp1 == 0x01) {
2604*4882a593Smuzhiyun printk(KERN_INFO "%s CVBS output\n", stdstr);
2605*4882a593Smuzhiyun ivideo->vbflags |= TV_AVIDEO;
2606*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0x32, 0x01);
2607*4882a593Smuzhiyun SiS_SetRegAND(SISCR, 0x32, ~0x06);
2608*4882a593Smuzhiyun } else {
2609*4882a593Smuzhiyun SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2610*4882a593Smuzhiyun SiS_SetRegAND(SISCR, 0x32, ~0x07);
2611*4882a593Smuzhiyun }
2612*4882a593Smuzhiyun } else if(temp1 == 0) {
2613*4882a593Smuzhiyun SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2614*4882a593Smuzhiyun SiS_SetRegAND(SISCR, 0x32, ~0x07);
2615*4882a593Smuzhiyun }
2616*4882a593Smuzhiyun /* Set general purpose IO for Chrontel communication */
2617*4882a593Smuzhiyun SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2618*4882a593Smuzhiyun #endif
2619*4882a593Smuzhiyun
2620*4882a593Smuzhiyun } else {
2621*4882a593Smuzhiyun
2622*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
2623*4882a593Smuzhiyun ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
2624*4882a593Smuzhiyun temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2625*4882a593Smuzhiyun SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
2626*4882a593Smuzhiyun SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2627*4882a593Smuzhiyun temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2628*4882a593Smuzhiyun temp2 |= 0x01;
2629*4882a593Smuzhiyun SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2630*4882a593Smuzhiyun SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2631*4882a593Smuzhiyun temp2 ^= 0x01;
2632*4882a593Smuzhiyun SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2633*4882a593Smuzhiyun SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2634*4882a593Smuzhiyun temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2635*4882a593Smuzhiyun SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2636*4882a593Smuzhiyun temp1 = 0;
2637*4882a593Smuzhiyun if(temp2 & 0x02) temp1 |= 0x01;
2638*4882a593Smuzhiyun if(temp2 & 0x10) temp1 |= 0x01;
2639*4882a593Smuzhiyun if(temp2 & 0x04) temp1 |= 0x02;
2640*4882a593Smuzhiyun if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2641*4882a593Smuzhiyun switch(temp1) {
2642*4882a593Smuzhiyun case 0x01:
2643*4882a593Smuzhiyun printk(KERN_INFO "%s CVBS output\n", stdstr);
2644*4882a593Smuzhiyun ivideo->vbflags |= TV_AVIDEO;
2645*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0x32, 0x01);
2646*4882a593Smuzhiyun SiS_SetRegAND(SISCR, 0x32, ~0x06);
2647*4882a593Smuzhiyun break;
2648*4882a593Smuzhiyun case 0x02:
2649*4882a593Smuzhiyun printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2650*4882a593Smuzhiyun ivideo->vbflags |= TV_SVIDEO;
2651*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0x32, 0x02);
2652*4882a593Smuzhiyun SiS_SetRegAND(SISCR, 0x32, ~0x05);
2653*4882a593Smuzhiyun break;
2654*4882a593Smuzhiyun case 0x04:
2655*4882a593Smuzhiyun printk(KERN_INFO "%s SCART output\n", stdstr);
2656*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0x32, 0x04);
2657*4882a593Smuzhiyun SiS_SetRegAND(SISCR, 0x32, ~0x03);
2658*4882a593Smuzhiyun break;
2659*4882a593Smuzhiyun default:
2660*4882a593Smuzhiyun SiS_SetRegAND(SISCR, 0x32, ~0x07);
2661*4882a593Smuzhiyun }
2662*4882a593Smuzhiyun #endif
2663*4882a593Smuzhiyun }
2664*4882a593Smuzhiyun }
2665*4882a593Smuzhiyun
sisfb_get_VB_type(struct sis_video_info * ivideo)2666*4882a593Smuzhiyun static void sisfb_get_VB_type(struct sis_video_info *ivideo)
2667*4882a593Smuzhiyun {
2668*4882a593Smuzhiyun char stdstr[] = "sisfb: Detected";
2669*4882a593Smuzhiyun char bridgestr[] = "video bridge";
2670*4882a593Smuzhiyun u8 vb_chipid;
2671*4882a593Smuzhiyun u8 reg;
2672*4882a593Smuzhiyun
2673*4882a593Smuzhiyun /* No CRT2 on XGI Z7 */
2674*4882a593Smuzhiyun if(ivideo->chip == XGI_20)
2675*4882a593Smuzhiyun return;
2676*4882a593Smuzhiyun
2677*4882a593Smuzhiyun vb_chipid = SiS_GetReg(SISPART4, 0x00);
2678*4882a593Smuzhiyun switch(vb_chipid) {
2679*4882a593Smuzhiyun case 0x01:
2680*4882a593Smuzhiyun reg = SiS_GetReg(SISPART4, 0x01);
2681*4882a593Smuzhiyun if(reg < 0xb0) {
2682*4882a593Smuzhiyun ivideo->vbflags |= VB_301; /* Deprecated */
2683*4882a593Smuzhiyun ivideo->vbflags2 |= VB2_301;
2684*4882a593Smuzhiyun printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2685*4882a593Smuzhiyun } else if(reg < 0xc0) {
2686*4882a593Smuzhiyun ivideo->vbflags |= VB_301B; /* Deprecated */
2687*4882a593Smuzhiyun ivideo->vbflags2 |= VB2_301B;
2688*4882a593Smuzhiyun reg = SiS_GetReg(SISPART4, 0x23);
2689*4882a593Smuzhiyun if(!(reg & 0x02)) {
2690*4882a593Smuzhiyun ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2691*4882a593Smuzhiyun ivideo->vbflags2 |= VB2_30xBDH;
2692*4882a593Smuzhiyun printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2693*4882a593Smuzhiyun } else {
2694*4882a593Smuzhiyun printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2695*4882a593Smuzhiyun }
2696*4882a593Smuzhiyun } else if(reg < 0xd0) {
2697*4882a593Smuzhiyun ivideo->vbflags |= VB_301C; /* Deprecated */
2698*4882a593Smuzhiyun ivideo->vbflags2 |= VB2_301C;
2699*4882a593Smuzhiyun printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2700*4882a593Smuzhiyun } else if(reg < 0xe0) {
2701*4882a593Smuzhiyun ivideo->vbflags |= VB_301LV; /* Deprecated */
2702*4882a593Smuzhiyun ivideo->vbflags2 |= VB2_301LV;
2703*4882a593Smuzhiyun printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2704*4882a593Smuzhiyun } else if(reg <= 0xe1) {
2705*4882a593Smuzhiyun reg = SiS_GetReg(SISPART4, 0x39);
2706*4882a593Smuzhiyun if(reg == 0xff) {
2707*4882a593Smuzhiyun ivideo->vbflags |= VB_302LV; /* Deprecated */
2708*4882a593Smuzhiyun ivideo->vbflags2 |= VB2_302LV;
2709*4882a593Smuzhiyun printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2710*4882a593Smuzhiyun } else {
2711*4882a593Smuzhiyun ivideo->vbflags |= VB_301C; /* Deprecated */
2712*4882a593Smuzhiyun ivideo->vbflags2 |= VB2_301C;
2713*4882a593Smuzhiyun printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2714*4882a593Smuzhiyun #if 0
2715*4882a593Smuzhiyun ivideo->vbflags |= VB_302ELV; /* Deprecated */
2716*4882a593Smuzhiyun ivideo->vbflags2 |= VB2_302ELV;
2717*4882a593Smuzhiyun printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2718*4882a593Smuzhiyun #endif
2719*4882a593Smuzhiyun }
2720*4882a593Smuzhiyun }
2721*4882a593Smuzhiyun break;
2722*4882a593Smuzhiyun case 0x02:
2723*4882a593Smuzhiyun ivideo->vbflags |= VB_302B; /* Deprecated */
2724*4882a593Smuzhiyun ivideo->vbflags2 |= VB2_302B;
2725*4882a593Smuzhiyun printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2726*4882a593Smuzhiyun break;
2727*4882a593Smuzhiyun }
2728*4882a593Smuzhiyun
2729*4882a593Smuzhiyun if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2730*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x37);
2731*4882a593Smuzhiyun reg &= SIS_EXTERNAL_CHIP_MASK;
2732*4882a593Smuzhiyun reg >>= 1;
2733*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_300_VGA) {
2734*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_300
2735*4882a593Smuzhiyun switch(reg) {
2736*4882a593Smuzhiyun case SIS_EXTERNAL_CHIP_LVDS:
2737*4882a593Smuzhiyun ivideo->vbflags |= VB_LVDS; /* Deprecated */
2738*4882a593Smuzhiyun ivideo->vbflags2 |= VB2_LVDS;
2739*4882a593Smuzhiyun break;
2740*4882a593Smuzhiyun case SIS_EXTERNAL_CHIP_TRUMPION:
2741*4882a593Smuzhiyun ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2742*4882a593Smuzhiyun ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2743*4882a593Smuzhiyun break;
2744*4882a593Smuzhiyun case SIS_EXTERNAL_CHIP_CHRONTEL:
2745*4882a593Smuzhiyun ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2746*4882a593Smuzhiyun ivideo->vbflags2 |= VB2_CHRONTEL;
2747*4882a593Smuzhiyun break;
2748*4882a593Smuzhiyun case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2749*4882a593Smuzhiyun ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2750*4882a593Smuzhiyun ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2751*4882a593Smuzhiyun break;
2752*4882a593Smuzhiyun }
2753*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2754*4882a593Smuzhiyun #endif
2755*4882a593Smuzhiyun } else if(ivideo->chip < SIS_661) {
2756*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
2757*4882a593Smuzhiyun switch (reg) {
2758*4882a593Smuzhiyun case SIS310_EXTERNAL_CHIP_LVDS:
2759*4882a593Smuzhiyun ivideo->vbflags |= VB_LVDS; /* Deprecated */
2760*4882a593Smuzhiyun ivideo->vbflags2 |= VB2_LVDS;
2761*4882a593Smuzhiyun break;
2762*4882a593Smuzhiyun case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2763*4882a593Smuzhiyun ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2764*4882a593Smuzhiyun ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2765*4882a593Smuzhiyun break;
2766*4882a593Smuzhiyun }
2767*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2768*4882a593Smuzhiyun #endif
2769*4882a593Smuzhiyun } else if(ivideo->chip >= SIS_661) {
2770*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
2771*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x38);
2772*4882a593Smuzhiyun reg >>= 5;
2773*4882a593Smuzhiyun switch(reg) {
2774*4882a593Smuzhiyun case 0x02:
2775*4882a593Smuzhiyun ivideo->vbflags |= VB_LVDS; /* Deprecated */
2776*4882a593Smuzhiyun ivideo->vbflags2 |= VB2_LVDS;
2777*4882a593Smuzhiyun break;
2778*4882a593Smuzhiyun case 0x03:
2779*4882a593Smuzhiyun ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2780*4882a593Smuzhiyun ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2781*4882a593Smuzhiyun break;
2782*4882a593Smuzhiyun case 0x04:
2783*4882a593Smuzhiyun ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2784*4882a593Smuzhiyun ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2785*4882a593Smuzhiyun break;
2786*4882a593Smuzhiyun }
2787*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2788*4882a593Smuzhiyun #endif
2789*4882a593Smuzhiyun }
2790*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_LVDS) {
2791*4882a593Smuzhiyun printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2792*4882a593Smuzhiyun }
2793*4882a593Smuzhiyun if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2794*4882a593Smuzhiyun printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2795*4882a593Smuzhiyun }
2796*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_CHRONTEL) {
2797*4882a593Smuzhiyun printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2798*4882a593Smuzhiyun }
2799*4882a593Smuzhiyun if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2800*4882a593Smuzhiyun printk(KERN_INFO "%s Conexant external device\n", stdstr);
2801*4882a593Smuzhiyun }
2802*4882a593Smuzhiyun }
2803*4882a593Smuzhiyun
2804*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2805*4882a593Smuzhiyun SiS_SenseLCD(ivideo);
2806*4882a593Smuzhiyun SiS_Sense30x(ivideo);
2807*4882a593Smuzhiyun } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2808*4882a593Smuzhiyun SiS_SenseCh(ivideo);
2809*4882a593Smuzhiyun }
2810*4882a593Smuzhiyun }
2811*4882a593Smuzhiyun
2812*4882a593Smuzhiyun /* ---------- Engine initialization routines ------------ */
2813*4882a593Smuzhiyun
2814*4882a593Smuzhiyun static void
sisfb_engine_init(struct sis_video_info * ivideo)2815*4882a593Smuzhiyun sisfb_engine_init(struct sis_video_info *ivideo)
2816*4882a593Smuzhiyun {
2817*4882a593Smuzhiyun
2818*4882a593Smuzhiyun /* Initialize command queue (we use MMIO only) */
2819*4882a593Smuzhiyun
2820*4882a593Smuzhiyun /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2821*4882a593Smuzhiyun
2822*4882a593Smuzhiyun ivideo->caps &= ~(TURBO_QUEUE_CAP |
2823*4882a593Smuzhiyun MMIO_CMD_QUEUE_CAP |
2824*4882a593Smuzhiyun VM_CMD_QUEUE_CAP |
2825*4882a593Smuzhiyun AGP_CMD_QUEUE_CAP);
2826*4882a593Smuzhiyun
2827*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_300
2828*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_300_VGA) {
2829*4882a593Smuzhiyun u32 tqueue_pos;
2830*4882a593Smuzhiyun u8 tq_state;
2831*4882a593Smuzhiyun
2832*4882a593Smuzhiyun tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2833*4882a593Smuzhiyun
2834*4882a593Smuzhiyun tq_state = SiS_GetReg(SISSR, IND_SIS_TURBOQUEUE_SET);
2835*4882a593Smuzhiyun tq_state |= 0xf0;
2836*4882a593Smuzhiyun tq_state &= 0xfc;
2837*4882a593Smuzhiyun tq_state |= (u8)(tqueue_pos >> 8);
2838*4882a593Smuzhiyun SiS_SetReg(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2839*4882a593Smuzhiyun
2840*4882a593Smuzhiyun SiS_SetReg(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2841*4882a593Smuzhiyun
2842*4882a593Smuzhiyun ivideo->caps |= TURBO_QUEUE_CAP;
2843*4882a593Smuzhiyun }
2844*4882a593Smuzhiyun #endif
2845*4882a593Smuzhiyun
2846*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
2847*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_315_VGA) {
2848*4882a593Smuzhiyun u32 tempq = 0, templ;
2849*4882a593Smuzhiyun u8 temp;
2850*4882a593Smuzhiyun
2851*4882a593Smuzhiyun if(ivideo->chip == XGI_20) {
2852*4882a593Smuzhiyun switch(ivideo->cmdQueueSize) {
2853*4882a593Smuzhiyun case (64 * 1024):
2854*4882a593Smuzhiyun temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2855*4882a593Smuzhiyun break;
2856*4882a593Smuzhiyun case (128 * 1024):
2857*4882a593Smuzhiyun default:
2858*4882a593Smuzhiyun temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2859*4882a593Smuzhiyun }
2860*4882a593Smuzhiyun } else {
2861*4882a593Smuzhiyun switch(ivideo->cmdQueueSize) {
2862*4882a593Smuzhiyun case (4 * 1024 * 1024):
2863*4882a593Smuzhiyun temp = SIS_CMD_QUEUE_SIZE_4M;
2864*4882a593Smuzhiyun break;
2865*4882a593Smuzhiyun case (2 * 1024 * 1024):
2866*4882a593Smuzhiyun temp = SIS_CMD_QUEUE_SIZE_2M;
2867*4882a593Smuzhiyun break;
2868*4882a593Smuzhiyun case (1 * 1024 * 1024):
2869*4882a593Smuzhiyun temp = SIS_CMD_QUEUE_SIZE_1M;
2870*4882a593Smuzhiyun break;
2871*4882a593Smuzhiyun default:
2872*4882a593Smuzhiyun case (512 * 1024):
2873*4882a593Smuzhiyun temp = SIS_CMD_QUEUE_SIZE_512k;
2874*4882a593Smuzhiyun }
2875*4882a593Smuzhiyun }
2876*4882a593Smuzhiyun
2877*4882a593Smuzhiyun SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2878*4882a593Smuzhiyun SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2879*4882a593Smuzhiyun
2880*4882a593Smuzhiyun if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2881*4882a593Smuzhiyun /* Must disable dual pipe on XGI_40. Can't do
2882*4882a593Smuzhiyun * this in MMIO mode, because it requires
2883*4882a593Smuzhiyun * setting/clearing a bit in the MMIO fire trigger
2884*4882a593Smuzhiyun * register.
2885*4882a593Smuzhiyun */
2886*4882a593Smuzhiyun if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2887*4882a593Smuzhiyun
2888*4882a593Smuzhiyun MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2889*4882a593Smuzhiyun
2890*4882a593Smuzhiyun SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2891*4882a593Smuzhiyun
2892*4882a593Smuzhiyun tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2893*4882a593Smuzhiyun MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2894*4882a593Smuzhiyun
2895*4882a593Smuzhiyun tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2896*4882a593Smuzhiyun MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2897*4882a593Smuzhiyun
2898*4882a593Smuzhiyun writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2899*4882a593Smuzhiyun writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2900*4882a593Smuzhiyun writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2901*4882a593Smuzhiyun writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2902*4882a593Smuzhiyun
2903*4882a593Smuzhiyun MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2904*4882a593Smuzhiyun
2905*4882a593Smuzhiyun sisfb_syncaccel(ivideo);
2906*4882a593Smuzhiyun
2907*4882a593Smuzhiyun SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2908*4882a593Smuzhiyun
2909*4882a593Smuzhiyun }
2910*4882a593Smuzhiyun }
2911*4882a593Smuzhiyun
2912*4882a593Smuzhiyun tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2913*4882a593Smuzhiyun MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2914*4882a593Smuzhiyun
2915*4882a593Smuzhiyun temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
2916*4882a593Smuzhiyun SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, temp);
2917*4882a593Smuzhiyun
2918*4882a593Smuzhiyun tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2919*4882a593Smuzhiyun MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2920*4882a593Smuzhiyun
2921*4882a593Smuzhiyun ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2922*4882a593Smuzhiyun }
2923*4882a593Smuzhiyun #endif
2924*4882a593Smuzhiyun
2925*4882a593Smuzhiyun ivideo->engineok = 1;
2926*4882a593Smuzhiyun }
2927*4882a593Smuzhiyun
sisfb_detect_lcd_type(struct sis_video_info * ivideo)2928*4882a593Smuzhiyun static void sisfb_detect_lcd_type(struct sis_video_info *ivideo)
2929*4882a593Smuzhiyun {
2930*4882a593Smuzhiyun u8 reg;
2931*4882a593Smuzhiyun int i;
2932*4882a593Smuzhiyun
2933*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x36);
2934*4882a593Smuzhiyun reg &= 0x0f;
2935*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_300_VGA) {
2936*4882a593Smuzhiyun ivideo->CRT2LCDType = sis300paneltype[reg];
2937*4882a593Smuzhiyun } else if(ivideo->chip >= SIS_661) {
2938*4882a593Smuzhiyun ivideo->CRT2LCDType = sis661paneltype[reg];
2939*4882a593Smuzhiyun } else {
2940*4882a593Smuzhiyun ivideo->CRT2LCDType = sis310paneltype[reg];
2941*4882a593Smuzhiyun if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2942*4882a593Smuzhiyun if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2943*4882a593Smuzhiyun (ivideo->CRT2LCDType != LCD_320x240_3)) {
2944*4882a593Smuzhiyun ivideo->CRT2LCDType = LCD_320x240;
2945*4882a593Smuzhiyun }
2946*4882a593Smuzhiyun }
2947*4882a593Smuzhiyun }
2948*4882a593Smuzhiyun
2949*4882a593Smuzhiyun if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2950*4882a593Smuzhiyun /* For broken BIOSes: Assume 1024x768, RGB18 */
2951*4882a593Smuzhiyun ivideo->CRT2LCDType = LCD_1024x768;
2952*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x36, 0xf0, 0x02);
2953*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x37, 0xee, 0x01);
2954*4882a593Smuzhiyun printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2955*4882a593Smuzhiyun }
2956*4882a593Smuzhiyun
2957*4882a593Smuzhiyun for(i = 0; i < SIS_LCD_NUMBER; i++) {
2958*4882a593Smuzhiyun if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2959*4882a593Smuzhiyun ivideo->lcdxres = sis_lcd_data[i].xres;
2960*4882a593Smuzhiyun ivideo->lcdyres = sis_lcd_data[i].yres;
2961*4882a593Smuzhiyun ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2962*4882a593Smuzhiyun break;
2963*4882a593Smuzhiyun }
2964*4882a593Smuzhiyun }
2965*4882a593Smuzhiyun
2966*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_300
2967*4882a593Smuzhiyun if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2968*4882a593Smuzhiyun ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2969*4882a593Smuzhiyun ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2970*4882a593Smuzhiyun } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2971*4882a593Smuzhiyun ivideo->lcdxres = 848; ivideo->lcdyres = 480;
2972*4882a593Smuzhiyun ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2973*4882a593Smuzhiyun } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2974*4882a593Smuzhiyun ivideo->lcdxres = 856; ivideo->lcdyres = 480;
2975*4882a593Smuzhiyun ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2976*4882a593Smuzhiyun }
2977*4882a593Smuzhiyun #endif
2978*4882a593Smuzhiyun
2979*4882a593Smuzhiyun printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2980*4882a593Smuzhiyun ivideo->lcdxres, ivideo->lcdyres);
2981*4882a593Smuzhiyun }
2982*4882a593Smuzhiyun
sisfb_save_pdc_emi(struct sis_video_info * ivideo)2983*4882a593Smuzhiyun static void sisfb_save_pdc_emi(struct sis_video_info *ivideo)
2984*4882a593Smuzhiyun {
2985*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_300
2986*4882a593Smuzhiyun /* Save the current PanelDelayCompensation if the LCD is currently used */
2987*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_300_VGA) {
2988*4882a593Smuzhiyun if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2989*4882a593Smuzhiyun int tmp;
2990*4882a593Smuzhiyun tmp = SiS_GetReg(SISCR, 0x30);
2991*4882a593Smuzhiyun if(tmp & 0x20) {
2992*4882a593Smuzhiyun /* Currently on LCD? If yes, read current pdc */
2993*4882a593Smuzhiyun ivideo->detectedpdc = SiS_GetReg(SISPART1, 0x13);
2994*4882a593Smuzhiyun ivideo->detectedpdc &= 0x3c;
2995*4882a593Smuzhiyun if(ivideo->SiS_Pr.PDC == -1) {
2996*4882a593Smuzhiyun /* Let option override detection */
2997*4882a593Smuzhiyun ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
2998*4882a593Smuzhiyun }
2999*4882a593Smuzhiyun printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
3000*4882a593Smuzhiyun ivideo->detectedpdc);
3001*4882a593Smuzhiyun }
3002*4882a593Smuzhiyun if((ivideo->SiS_Pr.PDC != -1) &&
3003*4882a593Smuzhiyun (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3004*4882a593Smuzhiyun printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
3005*4882a593Smuzhiyun ivideo->SiS_Pr.PDC);
3006*4882a593Smuzhiyun }
3007*4882a593Smuzhiyun }
3008*4882a593Smuzhiyun }
3009*4882a593Smuzhiyun #endif
3010*4882a593Smuzhiyun
3011*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
3012*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_315_VGA) {
3013*4882a593Smuzhiyun
3014*4882a593Smuzhiyun /* Try to find about LCDA */
3015*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3016*4882a593Smuzhiyun int tmp;
3017*4882a593Smuzhiyun tmp = SiS_GetReg(SISPART1, 0x13);
3018*4882a593Smuzhiyun if(tmp & 0x04) {
3019*4882a593Smuzhiyun ivideo->SiS_Pr.SiS_UseLCDA = true;
3020*4882a593Smuzhiyun ivideo->detectedlcda = 0x03;
3021*4882a593Smuzhiyun }
3022*4882a593Smuzhiyun }
3023*4882a593Smuzhiyun
3024*4882a593Smuzhiyun /* Save PDC */
3025*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3026*4882a593Smuzhiyun int tmp;
3027*4882a593Smuzhiyun tmp = SiS_GetReg(SISCR, 0x30);
3028*4882a593Smuzhiyun if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3029*4882a593Smuzhiyun /* Currently on LCD? If yes, read current pdc */
3030*4882a593Smuzhiyun u8 pdc;
3031*4882a593Smuzhiyun pdc = SiS_GetReg(SISPART1, 0x2D);
3032*4882a593Smuzhiyun ivideo->detectedpdc = (pdc & 0x0f) << 1;
3033*4882a593Smuzhiyun ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3034*4882a593Smuzhiyun pdc = SiS_GetReg(SISPART1, 0x35);
3035*4882a593Smuzhiyun ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3036*4882a593Smuzhiyun pdc = SiS_GetReg(SISPART1, 0x20);
3037*4882a593Smuzhiyun ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3038*4882a593Smuzhiyun if(ivideo->newrom) {
3039*4882a593Smuzhiyun /* New ROM invalidates other PDC resp. */
3040*4882a593Smuzhiyun if(ivideo->detectedlcda != 0xff) {
3041*4882a593Smuzhiyun ivideo->detectedpdc = 0xff;
3042*4882a593Smuzhiyun } else {
3043*4882a593Smuzhiyun ivideo->detectedpdca = 0xff;
3044*4882a593Smuzhiyun }
3045*4882a593Smuzhiyun }
3046*4882a593Smuzhiyun if(ivideo->SiS_Pr.PDC == -1) {
3047*4882a593Smuzhiyun if(ivideo->detectedpdc != 0xff) {
3048*4882a593Smuzhiyun ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3049*4882a593Smuzhiyun }
3050*4882a593Smuzhiyun }
3051*4882a593Smuzhiyun if(ivideo->SiS_Pr.PDCA == -1) {
3052*4882a593Smuzhiyun if(ivideo->detectedpdca != 0xff) {
3053*4882a593Smuzhiyun ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3054*4882a593Smuzhiyun }
3055*4882a593Smuzhiyun }
3056*4882a593Smuzhiyun if(ivideo->detectedpdc != 0xff) {
3057*4882a593Smuzhiyun printk(KERN_INFO
3058*4882a593Smuzhiyun "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3059*4882a593Smuzhiyun ivideo->detectedpdc);
3060*4882a593Smuzhiyun }
3061*4882a593Smuzhiyun if(ivideo->detectedpdca != 0xff) {
3062*4882a593Smuzhiyun printk(KERN_INFO
3063*4882a593Smuzhiyun "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3064*4882a593Smuzhiyun ivideo->detectedpdca);
3065*4882a593Smuzhiyun }
3066*4882a593Smuzhiyun }
3067*4882a593Smuzhiyun
3068*4882a593Smuzhiyun /* Save EMI */
3069*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3070*4882a593Smuzhiyun ivideo->SiS_Pr.EMI_30 = SiS_GetReg(SISPART4, 0x30);
3071*4882a593Smuzhiyun ivideo->SiS_Pr.EMI_31 = SiS_GetReg(SISPART4, 0x31);
3072*4882a593Smuzhiyun ivideo->SiS_Pr.EMI_32 = SiS_GetReg(SISPART4, 0x32);
3073*4882a593Smuzhiyun ivideo->SiS_Pr.EMI_33 = SiS_GetReg(SISPART4, 0x33);
3074*4882a593Smuzhiyun ivideo->SiS_Pr.HaveEMI = true;
3075*4882a593Smuzhiyun if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3076*4882a593Smuzhiyun ivideo->SiS_Pr.HaveEMILCD = true;
3077*4882a593Smuzhiyun }
3078*4882a593Smuzhiyun }
3079*4882a593Smuzhiyun }
3080*4882a593Smuzhiyun
3081*4882a593Smuzhiyun /* Let user override detected PDCs (all bridges) */
3082*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_30xBLV) {
3083*4882a593Smuzhiyun if((ivideo->SiS_Pr.PDC != -1) &&
3084*4882a593Smuzhiyun (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3085*4882a593Smuzhiyun printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3086*4882a593Smuzhiyun ivideo->SiS_Pr.PDC);
3087*4882a593Smuzhiyun }
3088*4882a593Smuzhiyun if((ivideo->SiS_Pr.PDCA != -1) &&
3089*4882a593Smuzhiyun (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3090*4882a593Smuzhiyun printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3091*4882a593Smuzhiyun ivideo->SiS_Pr.PDCA);
3092*4882a593Smuzhiyun }
3093*4882a593Smuzhiyun }
3094*4882a593Smuzhiyun
3095*4882a593Smuzhiyun }
3096*4882a593Smuzhiyun #endif
3097*4882a593Smuzhiyun }
3098*4882a593Smuzhiyun
3099*4882a593Smuzhiyun /* -------------------- Memory manager routines ---------------------- */
3100*4882a593Smuzhiyun
sisfb_getheapstart(struct sis_video_info * ivideo)3101*4882a593Smuzhiyun static u32 sisfb_getheapstart(struct sis_video_info *ivideo)
3102*4882a593Smuzhiyun {
3103*4882a593Smuzhiyun u32 ret = ivideo->sisfb_parm_mem * 1024;
3104*4882a593Smuzhiyun u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3105*4882a593Smuzhiyun u32 def;
3106*4882a593Smuzhiyun
3107*4882a593Smuzhiyun /* Calculate heap start = end of memory for console
3108*4882a593Smuzhiyun *
3109*4882a593Smuzhiyun * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3110*4882a593Smuzhiyun * C = console, D = heap, H = HWCursor, Q = cmd-queue
3111*4882a593Smuzhiyun *
3112*4882a593Smuzhiyun * On 76x in UMA+LFB mode, the layout is as follows:
3113*4882a593Smuzhiyun * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3114*4882a593Smuzhiyun * where the heap is the entire UMA area, eventually
3115*4882a593Smuzhiyun * into the LFB area if the given mem parameter is
3116*4882a593Smuzhiyun * higher than the size of the UMA memory.
3117*4882a593Smuzhiyun *
3118*4882a593Smuzhiyun * Basically given by "mem" parameter
3119*4882a593Smuzhiyun *
3120*4882a593Smuzhiyun * maximum = videosize - cmd_queue - hwcursor
3121*4882a593Smuzhiyun * (results in a heap of size 0)
3122*4882a593Smuzhiyun * default = SiS 300: depends on videosize
3123*4882a593Smuzhiyun * SiS 315/330/340/XGI: 32k below max
3124*4882a593Smuzhiyun */
3125*4882a593Smuzhiyun
3126*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_300_VGA) {
3127*4882a593Smuzhiyun if(ivideo->video_size > 0x1000000) {
3128*4882a593Smuzhiyun def = 0xc00000;
3129*4882a593Smuzhiyun } else if(ivideo->video_size > 0x800000) {
3130*4882a593Smuzhiyun def = 0x800000;
3131*4882a593Smuzhiyun } else {
3132*4882a593Smuzhiyun def = 0x400000;
3133*4882a593Smuzhiyun }
3134*4882a593Smuzhiyun } else if(ivideo->UMAsize && ivideo->LFBsize) {
3135*4882a593Smuzhiyun ret = def = 0;
3136*4882a593Smuzhiyun } else {
3137*4882a593Smuzhiyun def = maxoffs - 0x8000;
3138*4882a593Smuzhiyun }
3139*4882a593Smuzhiyun
3140*4882a593Smuzhiyun /* Use default for secondary card for now (FIXME) */
3141*4882a593Smuzhiyun if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3142*4882a593Smuzhiyun ret = def;
3143*4882a593Smuzhiyun
3144*4882a593Smuzhiyun return ret;
3145*4882a593Smuzhiyun }
3146*4882a593Smuzhiyun
sisfb_getheapsize(struct sis_video_info * ivideo)3147*4882a593Smuzhiyun static u32 sisfb_getheapsize(struct sis_video_info *ivideo)
3148*4882a593Smuzhiyun {
3149*4882a593Smuzhiyun u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3150*4882a593Smuzhiyun u32 ret = 0;
3151*4882a593Smuzhiyun
3152*4882a593Smuzhiyun if(ivideo->UMAsize && ivideo->LFBsize) {
3153*4882a593Smuzhiyun if( (!ivideo->sisfb_parm_mem) ||
3154*4882a593Smuzhiyun ((ivideo->sisfb_parm_mem * 1024) > max) ||
3155*4882a593Smuzhiyun ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3156*4882a593Smuzhiyun ret = ivideo->UMAsize;
3157*4882a593Smuzhiyun max -= ivideo->UMAsize;
3158*4882a593Smuzhiyun } else {
3159*4882a593Smuzhiyun ret = max - (ivideo->sisfb_parm_mem * 1024);
3160*4882a593Smuzhiyun max = ivideo->sisfb_parm_mem * 1024;
3161*4882a593Smuzhiyun }
3162*4882a593Smuzhiyun ivideo->video_offset = ret;
3163*4882a593Smuzhiyun ivideo->sisfb_mem = max;
3164*4882a593Smuzhiyun } else {
3165*4882a593Smuzhiyun ret = max - ivideo->heapstart;
3166*4882a593Smuzhiyun ivideo->sisfb_mem = ivideo->heapstart;
3167*4882a593Smuzhiyun }
3168*4882a593Smuzhiyun
3169*4882a593Smuzhiyun return ret;
3170*4882a593Smuzhiyun }
3171*4882a593Smuzhiyun
sisfb_heap_init(struct sis_video_info * ivideo)3172*4882a593Smuzhiyun static int sisfb_heap_init(struct sis_video_info *ivideo)
3173*4882a593Smuzhiyun {
3174*4882a593Smuzhiyun struct SIS_OH *poh;
3175*4882a593Smuzhiyun
3176*4882a593Smuzhiyun ivideo->video_offset = 0;
3177*4882a593Smuzhiyun if(ivideo->sisfb_parm_mem) {
3178*4882a593Smuzhiyun if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3179*4882a593Smuzhiyun (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3180*4882a593Smuzhiyun ivideo->sisfb_parm_mem = 0;
3181*4882a593Smuzhiyun }
3182*4882a593Smuzhiyun }
3183*4882a593Smuzhiyun
3184*4882a593Smuzhiyun ivideo->heapstart = sisfb_getheapstart(ivideo);
3185*4882a593Smuzhiyun ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
3186*4882a593Smuzhiyun
3187*4882a593Smuzhiyun ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3188*4882a593Smuzhiyun ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
3189*4882a593Smuzhiyun
3190*4882a593Smuzhiyun printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3191*4882a593Smuzhiyun (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3192*4882a593Smuzhiyun
3193*4882a593Smuzhiyun ivideo->sisfb_heap.vinfo = ivideo;
3194*4882a593Smuzhiyun
3195*4882a593Smuzhiyun ivideo->sisfb_heap.poha_chain = NULL;
3196*4882a593Smuzhiyun ivideo->sisfb_heap.poh_freelist = NULL;
3197*4882a593Smuzhiyun
3198*4882a593Smuzhiyun poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3199*4882a593Smuzhiyun if(poh == NULL)
3200*4882a593Smuzhiyun return 1;
3201*4882a593Smuzhiyun
3202*4882a593Smuzhiyun poh->poh_next = &ivideo->sisfb_heap.oh_free;
3203*4882a593Smuzhiyun poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3204*4882a593Smuzhiyun poh->size = ivideo->sisfb_heap_size;
3205*4882a593Smuzhiyun poh->offset = ivideo->heapstart;
3206*4882a593Smuzhiyun
3207*4882a593Smuzhiyun ivideo->sisfb_heap.oh_free.poh_next = poh;
3208*4882a593Smuzhiyun ivideo->sisfb_heap.oh_free.poh_prev = poh;
3209*4882a593Smuzhiyun ivideo->sisfb_heap.oh_free.size = 0;
3210*4882a593Smuzhiyun ivideo->sisfb_heap.max_freesize = poh->size;
3211*4882a593Smuzhiyun
3212*4882a593Smuzhiyun ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3213*4882a593Smuzhiyun ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3214*4882a593Smuzhiyun ivideo->sisfb_heap.oh_used.size = SENTINEL;
3215*4882a593Smuzhiyun
3216*4882a593Smuzhiyun if(ivideo->cardnumber == 0) {
3217*4882a593Smuzhiyun /* For the first card, make this heap the "global" one
3218*4882a593Smuzhiyun * for old DRM (which could handle only one card)
3219*4882a593Smuzhiyun */
3220*4882a593Smuzhiyun sisfb_heap = &ivideo->sisfb_heap;
3221*4882a593Smuzhiyun }
3222*4882a593Smuzhiyun
3223*4882a593Smuzhiyun return 0;
3224*4882a593Smuzhiyun }
3225*4882a593Smuzhiyun
3226*4882a593Smuzhiyun static struct SIS_OH *
sisfb_poh_new_node(struct SIS_HEAP * memheap)3227*4882a593Smuzhiyun sisfb_poh_new_node(struct SIS_HEAP *memheap)
3228*4882a593Smuzhiyun {
3229*4882a593Smuzhiyun struct SIS_OHALLOC *poha;
3230*4882a593Smuzhiyun struct SIS_OH *poh;
3231*4882a593Smuzhiyun unsigned long cOhs;
3232*4882a593Smuzhiyun int i;
3233*4882a593Smuzhiyun
3234*4882a593Smuzhiyun if(memheap->poh_freelist == NULL) {
3235*4882a593Smuzhiyun poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3236*4882a593Smuzhiyun if(!poha)
3237*4882a593Smuzhiyun return NULL;
3238*4882a593Smuzhiyun
3239*4882a593Smuzhiyun poha->poha_next = memheap->poha_chain;
3240*4882a593Smuzhiyun memheap->poha_chain = poha;
3241*4882a593Smuzhiyun
3242*4882a593Smuzhiyun cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
3243*4882a593Smuzhiyun
3244*4882a593Smuzhiyun poh = &poha->aoh[0];
3245*4882a593Smuzhiyun for(i = cOhs - 1; i != 0; i--) {
3246*4882a593Smuzhiyun poh->poh_next = poh + 1;
3247*4882a593Smuzhiyun poh = poh + 1;
3248*4882a593Smuzhiyun }
3249*4882a593Smuzhiyun
3250*4882a593Smuzhiyun poh->poh_next = NULL;
3251*4882a593Smuzhiyun memheap->poh_freelist = &poha->aoh[0];
3252*4882a593Smuzhiyun }
3253*4882a593Smuzhiyun
3254*4882a593Smuzhiyun poh = memheap->poh_freelist;
3255*4882a593Smuzhiyun memheap->poh_freelist = poh->poh_next;
3256*4882a593Smuzhiyun
3257*4882a593Smuzhiyun return poh;
3258*4882a593Smuzhiyun }
3259*4882a593Smuzhiyun
3260*4882a593Smuzhiyun static struct SIS_OH *
sisfb_poh_allocate(struct SIS_HEAP * memheap,u32 size)3261*4882a593Smuzhiyun sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
3262*4882a593Smuzhiyun {
3263*4882a593Smuzhiyun struct SIS_OH *pohThis;
3264*4882a593Smuzhiyun struct SIS_OH *pohRoot;
3265*4882a593Smuzhiyun int bAllocated = 0;
3266*4882a593Smuzhiyun
3267*4882a593Smuzhiyun if(size > memheap->max_freesize) {
3268*4882a593Smuzhiyun DPRINTK("sisfb: Can't allocate %dk video memory\n",
3269*4882a593Smuzhiyun (unsigned int) size / 1024);
3270*4882a593Smuzhiyun return NULL;
3271*4882a593Smuzhiyun }
3272*4882a593Smuzhiyun
3273*4882a593Smuzhiyun pohThis = memheap->oh_free.poh_next;
3274*4882a593Smuzhiyun
3275*4882a593Smuzhiyun while(pohThis != &memheap->oh_free) {
3276*4882a593Smuzhiyun if(size <= pohThis->size) {
3277*4882a593Smuzhiyun bAllocated = 1;
3278*4882a593Smuzhiyun break;
3279*4882a593Smuzhiyun }
3280*4882a593Smuzhiyun pohThis = pohThis->poh_next;
3281*4882a593Smuzhiyun }
3282*4882a593Smuzhiyun
3283*4882a593Smuzhiyun if(!bAllocated) {
3284*4882a593Smuzhiyun DPRINTK("sisfb: Can't allocate %dk video memory\n",
3285*4882a593Smuzhiyun (unsigned int) size / 1024);
3286*4882a593Smuzhiyun return NULL;
3287*4882a593Smuzhiyun }
3288*4882a593Smuzhiyun
3289*4882a593Smuzhiyun if(size == pohThis->size) {
3290*4882a593Smuzhiyun pohRoot = pohThis;
3291*4882a593Smuzhiyun sisfb_delete_node(pohThis);
3292*4882a593Smuzhiyun } else {
3293*4882a593Smuzhiyun pohRoot = sisfb_poh_new_node(memheap);
3294*4882a593Smuzhiyun if(pohRoot == NULL)
3295*4882a593Smuzhiyun return NULL;
3296*4882a593Smuzhiyun
3297*4882a593Smuzhiyun pohRoot->offset = pohThis->offset;
3298*4882a593Smuzhiyun pohRoot->size = size;
3299*4882a593Smuzhiyun
3300*4882a593Smuzhiyun pohThis->offset += size;
3301*4882a593Smuzhiyun pohThis->size -= size;
3302*4882a593Smuzhiyun }
3303*4882a593Smuzhiyun
3304*4882a593Smuzhiyun memheap->max_freesize -= size;
3305*4882a593Smuzhiyun
3306*4882a593Smuzhiyun pohThis = &memheap->oh_used;
3307*4882a593Smuzhiyun sisfb_insert_node(pohThis, pohRoot);
3308*4882a593Smuzhiyun
3309*4882a593Smuzhiyun return pohRoot;
3310*4882a593Smuzhiyun }
3311*4882a593Smuzhiyun
3312*4882a593Smuzhiyun static void
sisfb_delete_node(struct SIS_OH * poh)3313*4882a593Smuzhiyun sisfb_delete_node(struct SIS_OH *poh)
3314*4882a593Smuzhiyun {
3315*4882a593Smuzhiyun poh->poh_prev->poh_next = poh->poh_next;
3316*4882a593Smuzhiyun poh->poh_next->poh_prev = poh->poh_prev;
3317*4882a593Smuzhiyun }
3318*4882a593Smuzhiyun
3319*4882a593Smuzhiyun static void
sisfb_insert_node(struct SIS_OH * pohList,struct SIS_OH * poh)3320*4882a593Smuzhiyun sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
3321*4882a593Smuzhiyun {
3322*4882a593Smuzhiyun struct SIS_OH *pohTemp = pohList->poh_next;
3323*4882a593Smuzhiyun
3324*4882a593Smuzhiyun pohList->poh_next = poh;
3325*4882a593Smuzhiyun pohTemp->poh_prev = poh;
3326*4882a593Smuzhiyun
3327*4882a593Smuzhiyun poh->poh_prev = pohList;
3328*4882a593Smuzhiyun poh->poh_next = pohTemp;
3329*4882a593Smuzhiyun }
3330*4882a593Smuzhiyun
3331*4882a593Smuzhiyun static struct SIS_OH *
sisfb_poh_free(struct SIS_HEAP * memheap,u32 base)3332*4882a593Smuzhiyun sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
3333*4882a593Smuzhiyun {
3334*4882a593Smuzhiyun struct SIS_OH *pohThis;
3335*4882a593Smuzhiyun struct SIS_OH *poh_freed;
3336*4882a593Smuzhiyun struct SIS_OH *poh_prev;
3337*4882a593Smuzhiyun struct SIS_OH *poh_next;
3338*4882a593Smuzhiyun u32 ulUpper;
3339*4882a593Smuzhiyun u32 ulLower;
3340*4882a593Smuzhiyun int foundNode = 0;
3341*4882a593Smuzhiyun
3342*4882a593Smuzhiyun poh_freed = memheap->oh_used.poh_next;
3343*4882a593Smuzhiyun
3344*4882a593Smuzhiyun while(poh_freed != &memheap->oh_used) {
3345*4882a593Smuzhiyun if(poh_freed->offset == base) {
3346*4882a593Smuzhiyun foundNode = 1;
3347*4882a593Smuzhiyun break;
3348*4882a593Smuzhiyun }
3349*4882a593Smuzhiyun
3350*4882a593Smuzhiyun poh_freed = poh_freed->poh_next;
3351*4882a593Smuzhiyun }
3352*4882a593Smuzhiyun
3353*4882a593Smuzhiyun if(!foundNode)
3354*4882a593Smuzhiyun return NULL;
3355*4882a593Smuzhiyun
3356*4882a593Smuzhiyun memheap->max_freesize += poh_freed->size;
3357*4882a593Smuzhiyun
3358*4882a593Smuzhiyun poh_prev = poh_next = NULL;
3359*4882a593Smuzhiyun ulUpper = poh_freed->offset + poh_freed->size;
3360*4882a593Smuzhiyun ulLower = poh_freed->offset;
3361*4882a593Smuzhiyun
3362*4882a593Smuzhiyun pohThis = memheap->oh_free.poh_next;
3363*4882a593Smuzhiyun
3364*4882a593Smuzhiyun while(pohThis != &memheap->oh_free) {
3365*4882a593Smuzhiyun if(pohThis->offset == ulUpper) {
3366*4882a593Smuzhiyun poh_next = pohThis;
3367*4882a593Smuzhiyun } else if((pohThis->offset + pohThis->size) == ulLower) {
3368*4882a593Smuzhiyun poh_prev = pohThis;
3369*4882a593Smuzhiyun }
3370*4882a593Smuzhiyun pohThis = pohThis->poh_next;
3371*4882a593Smuzhiyun }
3372*4882a593Smuzhiyun
3373*4882a593Smuzhiyun sisfb_delete_node(poh_freed);
3374*4882a593Smuzhiyun
3375*4882a593Smuzhiyun if(poh_prev && poh_next) {
3376*4882a593Smuzhiyun poh_prev->size += (poh_freed->size + poh_next->size);
3377*4882a593Smuzhiyun sisfb_delete_node(poh_next);
3378*4882a593Smuzhiyun sisfb_free_node(memheap, poh_freed);
3379*4882a593Smuzhiyun sisfb_free_node(memheap, poh_next);
3380*4882a593Smuzhiyun return poh_prev;
3381*4882a593Smuzhiyun }
3382*4882a593Smuzhiyun
3383*4882a593Smuzhiyun if(poh_prev) {
3384*4882a593Smuzhiyun poh_prev->size += poh_freed->size;
3385*4882a593Smuzhiyun sisfb_free_node(memheap, poh_freed);
3386*4882a593Smuzhiyun return poh_prev;
3387*4882a593Smuzhiyun }
3388*4882a593Smuzhiyun
3389*4882a593Smuzhiyun if(poh_next) {
3390*4882a593Smuzhiyun poh_next->size += poh_freed->size;
3391*4882a593Smuzhiyun poh_next->offset = poh_freed->offset;
3392*4882a593Smuzhiyun sisfb_free_node(memheap, poh_freed);
3393*4882a593Smuzhiyun return poh_next;
3394*4882a593Smuzhiyun }
3395*4882a593Smuzhiyun
3396*4882a593Smuzhiyun sisfb_insert_node(&memheap->oh_free, poh_freed);
3397*4882a593Smuzhiyun
3398*4882a593Smuzhiyun return poh_freed;
3399*4882a593Smuzhiyun }
3400*4882a593Smuzhiyun
3401*4882a593Smuzhiyun static void
sisfb_free_node(struct SIS_HEAP * memheap,struct SIS_OH * poh)3402*4882a593Smuzhiyun sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
3403*4882a593Smuzhiyun {
3404*4882a593Smuzhiyun if(poh == NULL)
3405*4882a593Smuzhiyun return;
3406*4882a593Smuzhiyun
3407*4882a593Smuzhiyun poh->poh_next = memheap->poh_freelist;
3408*4882a593Smuzhiyun memheap->poh_freelist = poh;
3409*4882a593Smuzhiyun }
3410*4882a593Smuzhiyun
3411*4882a593Smuzhiyun static void
sis_int_malloc(struct sis_video_info * ivideo,struct sis_memreq * req)3412*4882a593Smuzhiyun sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3413*4882a593Smuzhiyun {
3414*4882a593Smuzhiyun struct SIS_OH *poh = NULL;
3415*4882a593Smuzhiyun
3416*4882a593Smuzhiyun if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3417*4882a593Smuzhiyun poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3418*4882a593Smuzhiyun
3419*4882a593Smuzhiyun if(poh == NULL) {
3420*4882a593Smuzhiyun req->offset = req->size = 0;
3421*4882a593Smuzhiyun DPRINTK("sisfb: Video RAM allocation failed\n");
3422*4882a593Smuzhiyun } else {
3423*4882a593Smuzhiyun req->offset = poh->offset;
3424*4882a593Smuzhiyun req->size = poh->size;
3425*4882a593Smuzhiyun DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3426*4882a593Smuzhiyun (poh->offset + ivideo->video_vbase));
3427*4882a593Smuzhiyun }
3428*4882a593Smuzhiyun }
3429*4882a593Smuzhiyun
3430*4882a593Smuzhiyun void
sis_malloc(struct sis_memreq * req)3431*4882a593Smuzhiyun sis_malloc(struct sis_memreq *req)
3432*4882a593Smuzhiyun {
3433*4882a593Smuzhiyun struct sis_video_info *ivideo = sisfb_heap->vinfo;
3434*4882a593Smuzhiyun
3435*4882a593Smuzhiyun if(&ivideo->sisfb_heap == sisfb_heap)
3436*4882a593Smuzhiyun sis_int_malloc(ivideo, req);
3437*4882a593Smuzhiyun else
3438*4882a593Smuzhiyun req->offset = req->size = 0;
3439*4882a593Smuzhiyun }
3440*4882a593Smuzhiyun
3441*4882a593Smuzhiyun void
sis_malloc_new(struct pci_dev * pdev,struct sis_memreq * req)3442*4882a593Smuzhiyun sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3443*4882a593Smuzhiyun {
3444*4882a593Smuzhiyun struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3445*4882a593Smuzhiyun
3446*4882a593Smuzhiyun sis_int_malloc(ivideo, req);
3447*4882a593Smuzhiyun }
3448*4882a593Smuzhiyun
3449*4882a593Smuzhiyun /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3450*4882a593Smuzhiyun
3451*4882a593Smuzhiyun static void
sis_int_free(struct sis_video_info * ivideo,u32 base)3452*4882a593Smuzhiyun sis_int_free(struct sis_video_info *ivideo, u32 base)
3453*4882a593Smuzhiyun {
3454*4882a593Smuzhiyun struct SIS_OH *poh;
3455*4882a593Smuzhiyun
3456*4882a593Smuzhiyun if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3457*4882a593Smuzhiyun return;
3458*4882a593Smuzhiyun
3459*4882a593Smuzhiyun poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
3460*4882a593Smuzhiyun
3461*4882a593Smuzhiyun if(poh == NULL) {
3462*4882a593Smuzhiyun DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3463*4882a593Smuzhiyun (unsigned int) base);
3464*4882a593Smuzhiyun }
3465*4882a593Smuzhiyun }
3466*4882a593Smuzhiyun
3467*4882a593Smuzhiyun void
sis_free(u32 base)3468*4882a593Smuzhiyun sis_free(u32 base)
3469*4882a593Smuzhiyun {
3470*4882a593Smuzhiyun struct sis_video_info *ivideo = sisfb_heap->vinfo;
3471*4882a593Smuzhiyun
3472*4882a593Smuzhiyun sis_int_free(ivideo, base);
3473*4882a593Smuzhiyun }
3474*4882a593Smuzhiyun
3475*4882a593Smuzhiyun void
sis_free_new(struct pci_dev * pdev,u32 base)3476*4882a593Smuzhiyun sis_free_new(struct pci_dev *pdev, u32 base)
3477*4882a593Smuzhiyun {
3478*4882a593Smuzhiyun struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3479*4882a593Smuzhiyun
3480*4882a593Smuzhiyun sis_int_free(ivideo, base);
3481*4882a593Smuzhiyun }
3482*4882a593Smuzhiyun
3483*4882a593Smuzhiyun /* --------------------- SetMode routines ------------------------- */
3484*4882a593Smuzhiyun
3485*4882a593Smuzhiyun static void
sisfb_check_engine_and_sync(struct sis_video_info * ivideo)3486*4882a593Smuzhiyun sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3487*4882a593Smuzhiyun {
3488*4882a593Smuzhiyun u8 cr30, cr31;
3489*4882a593Smuzhiyun
3490*4882a593Smuzhiyun /* Check if MMIO and engines are enabled,
3491*4882a593Smuzhiyun * and sync in case they are. Can't use
3492*4882a593Smuzhiyun * ivideo->accel here, as this might have
3493*4882a593Smuzhiyun * been changed before this is called.
3494*4882a593Smuzhiyun */
3495*4882a593Smuzhiyun cr30 = SiS_GetReg(SISSR, IND_SIS_PCI_ADDRESS_SET);
3496*4882a593Smuzhiyun cr31 = SiS_GetReg(SISSR, IND_SIS_MODULE_ENABLE);
3497*4882a593Smuzhiyun /* MMIO and 2D/3D engine enabled? */
3498*4882a593Smuzhiyun if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3499*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_300
3500*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_300_VGA) {
3501*4882a593Smuzhiyun /* Don't care about TurboQueue. It's
3502*4882a593Smuzhiyun * enough to know that the engines
3503*4882a593Smuzhiyun * are enabled
3504*4882a593Smuzhiyun */
3505*4882a593Smuzhiyun sisfb_syncaccel(ivideo);
3506*4882a593Smuzhiyun }
3507*4882a593Smuzhiyun #endif
3508*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
3509*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_315_VGA) {
3510*4882a593Smuzhiyun /* Check that any queue mode is
3511*4882a593Smuzhiyun * enabled, and that the queue
3512*4882a593Smuzhiyun * is not in the state of "reset"
3513*4882a593Smuzhiyun */
3514*4882a593Smuzhiyun cr30 = SiS_GetReg(SISSR, 0x26);
3515*4882a593Smuzhiyun if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3516*4882a593Smuzhiyun sisfb_syncaccel(ivideo);
3517*4882a593Smuzhiyun }
3518*4882a593Smuzhiyun }
3519*4882a593Smuzhiyun #endif
3520*4882a593Smuzhiyun }
3521*4882a593Smuzhiyun }
3522*4882a593Smuzhiyun
3523*4882a593Smuzhiyun static void
sisfb_pre_setmode(struct sis_video_info * ivideo)3524*4882a593Smuzhiyun sisfb_pre_setmode(struct sis_video_info *ivideo)
3525*4882a593Smuzhiyun {
3526*4882a593Smuzhiyun u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3527*4882a593Smuzhiyun int tvregnum = 0;
3528*4882a593Smuzhiyun
3529*4882a593Smuzhiyun ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3530*4882a593Smuzhiyun
3531*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x05, 0x86);
3532*4882a593Smuzhiyun
3533*4882a593Smuzhiyun cr31 = SiS_GetReg(SISCR, 0x31);
3534*4882a593Smuzhiyun cr31 &= ~0x60;
3535*4882a593Smuzhiyun cr31 |= 0x04;
3536*4882a593Smuzhiyun
3537*4882a593Smuzhiyun cr33 = ivideo->rate_idx & 0x0F;
3538*4882a593Smuzhiyun
3539*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
3540*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_315_VGA) {
3541*4882a593Smuzhiyun if(ivideo->chip >= SIS_661) {
3542*4882a593Smuzhiyun cr38 = SiS_GetReg(SISCR, 0x38);
3543*4882a593Smuzhiyun cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3544*4882a593Smuzhiyun } else {
3545*4882a593Smuzhiyun tvregnum = 0x38;
3546*4882a593Smuzhiyun cr38 = SiS_GetReg(SISCR, tvregnum);
3547*4882a593Smuzhiyun cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3548*4882a593Smuzhiyun }
3549*4882a593Smuzhiyun }
3550*4882a593Smuzhiyun #endif
3551*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_300
3552*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_300_VGA) {
3553*4882a593Smuzhiyun tvregnum = 0x35;
3554*4882a593Smuzhiyun cr38 = SiS_GetReg(SISCR, tvregnum);
3555*4882a593Smuzhiyun }
3556*4882a593Smuzhiyun #endif
3557*4882a593Smuzhiyun
3558*4882a593Smuzhiyun SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
3559*4882a593Smuzhiyun SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
3560*4882a593Smuzhiyun ivideo->curFSTN = ivideo->curDSTN = 0;
3561*4882a593Smuzhiyun
3562*4882a593Smuzhiyun switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3563*4882a593Smuzhiyun
3564*4882a593Smuzhiyun case CRT2_TV:
3565*4882a593Smuzhiyun cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
3566*4882a593Smuzhiyun if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
3567*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
3568*4882a593Smuzhiyun if(ivideo->chip >= SIS_661) {
3569*4882a593Smuzhiyun cr38 |= 0x04;
3570*4882a593Smuzhiyun if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
3571*4882a593Smuzhiyun else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3572*4882a593Smuzhiyun else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3573*4882a593Smuzhiyun cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3574*4882a593Smuzhiyun cr35 &= ~0x01;
3575*4882a593Smuzhiyun ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3576*4882a593Smuzhiyun } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3577*4882a593Smuzhiyun cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3578*4882a593Smuzhiyun cr38 |= 0x08;
3579*4882a593Smuzhiyun if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
3580*4882a593Smuzhiyun else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3581*4882a593Smuzhiyun else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3582*4882a593Smuzhiyun cr31 &= ~0x01;
3583*4882a593Smuzhiyun ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3584*4882a593Smuzhiyun }
3585*4882a593Smuzhiyun #endif
3586*4882a593Smuzhiyun } else if((ivideo->vbflags & TV_HIVISION) &&
3587*4882a593Smuzhiyun (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3588*4882a593Smuzhiyun if(ivideo->chip >= SIS_661) {
3589*4882a593Smuzhiyun cr38 |= 0x04;
3590*4882a593Smuzhiyun cr35 |= 0x60;
3591*4882a593Smuzhiyun } else {
3592*4882a593Smuzhiyun cr30 |= 0x80;
3593*4882a593Smuzhiyun }
3594*4882a593Smuzhiyun cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3595*4882a593Smuzhiyun cr31 |= 0x01;
3596*4882a593Smuzhiyun cr35 |= 0x01;
3597*4882a593Smuzhiyun ivideo->currentvbflags |= TV_HIVISION;
3598*4882a593Smuzhiyun } else if(ivideo->vbflags & TV_SCART) {
3599*4882a593Smuzhiyun cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3600*4882a593Smuzhiyun cr31 |= 0x01;
3601*4882a593Smuzhiyun cr35 |= 0x01;
3602*4882a593Smuzhiyun ivideo->currentvbflags |= TV_SCART;
3603*4882a593Smuzhiyun } else {
3604*4882a593Smuzhiyun if(ivideo->vbflags & TV_SVIDEO) {
3605*4882a593Smuzhiyun cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3606*4882a593Smuzhiyun ivideo->currentvbflags |= TV_SVIDEO;
3607*4882a593Smuzhiyun }
3608*4882a593Smuzhiyun if(ivideo->vbflags & TV_AVIDEO) {
3609*4882a593Smuzhiyun cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3610*4882a593Smuzhiyun ivideo->currentvbflags |= TV_AVIDEO;
3611*4882a593Smuzhiyun }
3612*4882a593Smuzhiyun }
3613*4882a593Smuzhiyun cr31 |= SIS_DRIVER_MODE;
3614*4882a593Smuzhiyun
3615*4882a593Smuzhiyun if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3616*4882a593Smuzhiyun if(ivideo->vbflags & TV_PAL) {
3617*4882a593Smuzhiyun cr31 |= 0x01; cr35 |= 0x01;
3618*4882a593Smuzhiyun ivideo->currentvbflags |= TV_PAL;
3619*4882a593Smuzhiyun if(ivideo->vbflags & TV_PALM) {
3620*4882a593Smuzhiyun cr38 |= 0x40; cr35 |= 0x04;
3621*4882a593Smuzhiyun ivideo->currentvbflags |= TV_PALM;
3622*4882a593Smuzhiyun } else if(ivideo->vbflags & TV_PALN) {
3623*4882a593Smuzhiyun cr38 |= 0x80; cr35 |= 0x08;
3624*4882a593Smuzhiyun ivideo->currentvbflags |= TV_PALN;
3625*4882a593Smuzhiyun }
3626*4882a593Smuzhiyun } else {
3627*4882a593Smuzhiyun cr31 &= ~0x01; cr35 &= ~0x01;
3628*4882a593Smuzhiyun ivideo->currentvbflags |= TV_NTSC;
3629*4882a593Smuzhiyun if(ivideo->vbflags & TV_NTSCJ) {
3630*4882a593Smuzhiyun cr38 |= 0x40; cr35 |= 0x02;
3631*4882a593Smuzhiyun ivideo->currentvbflags |= TV_NTSCJ;
3632*4882a593Smuzhiyun }
3633*4882a593Smuzhiyun }
3634*4882a593Smuzhiyun }
3635*4882a593Smuzhiyun break;
3636*4882a593Smuzhiyun
3637*4882a593Smuzhiyun case CRT2_LCD:
3638*4882a593Smuzhiyun cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3639*4882a593Smuzhiyun cr31 |= SIS_DRIVER_MODE;
3640*4882a593Smuzhiyun SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3641*4882a593Smuzhiyun SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3642*4882a593Smuzhiyun ivideo->curFSTN = ivideo->sisfb_fstn;
3643*4882a593Smuzhiyun ivideo->curDSTN = ivideo->sisfb_dstn;
3644*4882a593Smuzhiyun break;
3645*4882a593Smuzhiyun
3646*4882a593Smuzhiyun case CRT2_VGA:
3647*4882a593Smuzhiyun cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3648*4882a593Smuzhiyun cr31 |= SIS_DRIVER_MODE;
3649*4882a593Smuzhiyun if(ivideo->sisfb_nocrt2rate) {
3650*4882a593Smuzhiyun cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3651*4882a593Smuzhiyun } else {
3652*4882a593Smuzhiyun cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3653*4882a593Smuzhiyun }
3654*4882a593Smuzhiyun break;
3655*4882a593Smuzhiyun
3656*4882a593Smuzhiyun default: /* disable CRT2 */
3657*4882a593Smuzhiyun cr30 = 0x00;
3658*4882a593Smuzhiyun cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3659*4882a593Smuzhiyun }
3660*4882a593Smuzhiyun
3661*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x30, cr30);
3662*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x33, cr33);
3663*4882a593Smuzhiyun
3664*4882a593Smuzhiyun if(ivideo->chip >= SIS_661) {
3665*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
3666*4882a593Smuzhiyun cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3667*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3668*4882a593Smuzhiyun cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3669*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x38, 0xf8, cr38);
3670*4882a593Smuzhiyun #endif
3671*4882a593Smuzhiyun } else if(ivideo->chip != SIS_300) {
3672*4882a593Smuzhiyun SiS_SetReg(SISCR, tvregnum, cr38);
3673*4882a593Smuzhiyun }
3674*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x31, cr31);
3675*4882a593Smuzhiyun
3676*4882a593Smuzhiyun ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3677*4882a593Smuzhiyun
3678*4882a593Smuzhiyun sisfb_check_engine_and_sync(ivideo);
3679*4882a593Smuzhiyun }
3680*4882a593Smuzhiyun
3681*4882a593Smuzhiyun /* Fix SR11 for 661 and later */
3682*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
3683*4882a593Smuzhiyun static void
sisfb_fixup_SR11(struct sis_video_info * ivideo)3684*4882a593Smuzhiyun sisfb_fixup_SR11(struct sis_video_info *ivideo)
3685*4882a593Smuzhiyun {
3686*4882a593Smuzhiyun u8 tmpreg;
3687*4882a593Smuzhiyun
3688*4882a593Smuzhiyun if(ivideo->chip >= SIS_661) {
3689*4882a593Smuzhiyun tmpreg = SiS_GetReg(SISSR, 0x11);
3690*4882a593Smuzhiyun if(tmpreg & 0x20) {
3691*4882a593Smuzhiyun tmpreg = SiS_GetReg(SISSR, 0x3e);
3692*4882a593Smuzhiyun tmpreg = (tmpreg + 1) & 0xff;
3693*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x3e, tmpreg);
3694*4882a593Smuzhiyun tmpreg = SiS_GetReg(SISSR, 0x11);
3695*4882a593Smuzhiyun }
3696*4882a593Smuzhiyun if(tmpreg & 0xf0) {
3697*4882a593Smuzhiyun SiS_SetRegAND(SISSR, 0x11, 0x0f);
3698*4882a593Smuzhiyun }
3699*4882a593Smuzhiyun }
3700*4882a593Smuzhiyun }
3701*4882a593Smuzhiyun #endif
3702*4882a593Smuzhiyun
3703*4882a593Smuzhiyun static void
sisfb_set_TVxposoffset(struct sis_video_info * ivideo,int val)3704*4882a593Smuzhiyun sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3705*4882a593Smuzhiyun {
3706*4882a593Smuzhiyun if(val > 32) val = 32;
3707*4882a593Smuzhiyun if(val < -32) val = -32;
3708*4882a593Smuzhiyun ivideo->tvxpos = val;
3709*4882a593Smuzhiyun
3710*4882a593Smuzhiyun if(ivideo->sisfblocked) return;
3711*4882a593Smuzhiyun if(!ivideo->modechanged) return;
3712*4882a593Smuzhiyun
3713*4882a593Smuzhiyun if(ivideo->currentvbflags & CRT2_TV) {
3714*4882a593Smuzhiyun
3715*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_CHRONTEL) {
3716*4882a593Smuzhiyun
3717*4882a593Smuzhiyun int x = ivideo->tvx;
3718*4882a593Smuzhiyun
3719*4882a593Smuzhiyun switch(ivideo->chronteltype) {
3720*4882a593Smuzhiyun case 1:
3721*4882a593Smuzhiyun x += val;
3722*4882a593Smuzhiyun if(x < 0) x = 0;
3723*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x05, 0x86);
3724*4882a593Smuzhiyun SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3725*4882a593Smuzhiyun SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3726*4882a593Smuzhiyun break;
3727*4882a593Smuzhiyun case 2:
3728*4882a593Smuzhiyun /* Not supported by hardware */
3729*4882a593Smuzhiyun break;
3730*4882a593Smuzhiyun }
3731*4882a593Smuzhiyun
3732*4882a593Smuzhiyun } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3733*4882a593Smuzhiyun
3734*4882a593Smuzhiyun u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3735*4882a593Smuzhiyun unsigned short temp;
3736*4882a593Smuzhiyun
3737*4882a593Smuzhiyun p2_1f = ivideo->p2_1f;
3738*4882a593Smuzhiyun p2_20 = ivideo->p2_20;
3739*4882a593Smuzhiyun p2_2b = ivideo->p2_2b;
3740*4882a593Smuzhiyun p2_42 = ivideo->p2_42;
3741*4882a593Smuzhiyun p2_43 = ivideo->p2_43;
3742*4882a593Smuzhiyun
3743*4882a593Smuzhiyun temp = p2_1f | ((p2_20 & 0xf0) << 4);
3744*4882a593Smuzhiyun temp += (val * 2);
3745*4882a593Smuzhiyun p2_1f = temp & 0xff;
3746*4882a593Smuzhiyun p2_20 = (temp & 0xf00) >> 4;
3747*4882a593Smuzhiyun p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3748*4882a593Smuzhiyun temp = p2_43 | ((p2_42 & 0xf0) << 4);
3749*4882a593Smuzhiyun temp += (val * 2);
3750*4882a593Smuzhiyun p2_43 = temp & 0xff;
3751*4882a593Smuzhiyun p2_42 = (temp & 0xf00) >> 4;
3752*4882a593Smuzhiyun SiS_SetReg(SISPART2, 0x1f, p2_1f);
3753*4882a593Smuzhiyun SiS_SetRegANDOR(SISPART2, 0x20, 0x0F, p2_20);
3754*4882a593Smuzhiyun SiS_SetRegANDOR(SISPART2, 0x2b, 0xF0, p2_2b);
3755*4882a593Smuzhiyun SiS_SetRegANDOR(SISPART2, 0x42, 0x0F, p2_42);
3756*4882a593Smuzhiyun SiS_SetReg(SISPART2, 0x43, p2_43);
3757*4882a593Smuzhiyun }
3758*4882a593Smuzhiyun }
3759*4882a593Smuzhiyun }
3760*4882a593Smuzhiyun
3761*4882a593Smuzhiyun static void
sisfb_set_TVyposoffset(struct sis_video_info * ivideo,int val)3762*4882a593Smuzhiyun sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3763*4882a593Smuzhiyun {
3764*4882a593Smuzhiyun if(val > 32) val = 32;
3765*4882a593Smuzhiyun if(val < -32) val = -32;
3766*4882a593Smuzhiyun ivideo->tvypos = val;
3767*4882a593Smuzhiyun
3768*4882a593Smuzhiyun if(ivideo->sisfblocked) return;
3769*4882a593Smuzhiyun if(!ivideo->modechanged) return;
3770*4882a593Smuzhiyun
3771*4882a593Smuzhiyun if(ivideo->currentvbflags & CRT2_TV) {
3772*4882a593Smuzhiyun
3773*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_CHRONTEL) {
3774*4882a593Smuzhiyun
3775*4882a593Smuzhiyun int y = ivideo->tvy;
3776*4882a593Smuzhiyun
3777*4882a593Smuzhiyun switch(ivideo->chronteltype) {
3778*4882a593Smuzhiyun case 1:
3779*4882a593Smuzhiyun y -= val;
3780*4882a593Smuzhiyun if(y < 0) y = 0;
3781*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x05, 0x86);
3782*4882a593Smuzhiyun SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3783*4882a593Smuzhiyun SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3784*4882a593Smuzhiyun break;
3785*4882a593Smuzhiyun case 2:
3786*4882a593Smuzhiyun /* Not supported by hardware */
3787*4882a593Smuzhiyun break;
3788*4882a593Smuzhiyun }
3789*4882a593Smuzhiyun
3790*4882a593Smuzhiyun } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3791*4882a593Smuzhiyun
3792*4882a593Smuzhiyun char p2_01, p2_02;
3793*4882a593Smuzhiyun val /= 2;
3794*4882a593Smuzhiyun p2_01 = ivideo->p2_01;
3795*4882a593Smuzhiyun p2_02 = ivideo->p2_02;
3796*4882a593Smuzhiyun
3797*4882a593Smuzhiyun p2_01 += val;
3798*4882a593Smuzhiyun p2_02 += val;
3799*4882a593Smuzhiyun if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3800*4882a593Smuzhiyun while((p2_01 <= 0) || (p2_02 <= 0)) {
3801*4882a593Smuzhiyun p2_01 += 2;
3802*4882a593Smuzhiyun p2_02 += 2;
3803*4882a593Smuzhiyun }
3804*4882a593Smuzhiyun }
3805*4882a593Smuzhiyun SiS_SetReg(SISPART2, 0x01, p2_01);
3806*4882a593Smuzhiyun SiS_SetReg(SISPART2, 0x02, p2_02);
3807*4882a593Smuzhiyun }
3808*4882a593Smuzhiyun }
3809*4882a593Smuzhiyun }
3810*4882a593Smuzhiyun
3811*4882a593Smuzhiyun static void
sisfb_post_setmode(struct sis_video_info * ivideo)3812*4882a593Smuzhiyun sisfb_post_setmode(struct sis_video_info *ivideo)
3813*4882a593Smuzhiyun {
3814*4882a593Smuzhiyun bool crt1isoff = false;
3815*4882a593Smuzhiyun bool doit = true;
3816*4882a593Smuzhiyun #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3817*4882a593Smuzhiyun u8 reg;
3818*4882a593Smuzhiyun #endif
3819*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
3820*4882a593Smuzhiyun u8 reg1;
3821*4882a593Smuzhiyun #endif
3822*4882a593Smuzhiyun
3823*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x05, 0x86);
3824*4882a593Smuzhiyun
3825*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
3826*4882a593Smuzhiyun sisfb_fixup_SR11(ivideo);
3827*4882a593Smuzhiyun #endif
3828*4882a593Smuzhiyun
3829*4882a593Smuzhiyun /* Now we actually HAVE changed the display mode */
3830*4882a593Smuzhiyun ivideo->modechanged = 1;
3831*4882a593Smuzhiyun
3832*4882a593Smuzhiyun /* We can't switch off CRT1 if bridge is in slave mode */
3833*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
3834*4882a593Smuzhiyun if(sisfb_bridgeisslave(ivideo)) doit = false;
3835*4882a593Smuzhiyun } else
3836*4882a593Smuzhiyun ivideo->sisfb_crt1off = 0;
3837*4882a593Smuzhiyun
3838*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_300
3839*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_300_VGA) {
3840*4882a593Smuzhiyun if((ivideo->sisfb_crt1off) && (doit)) {
3841*4882a593Smuzhiyun crt1isoff = true;
3842*4882a593Smuzhiyun reg = 0x00;
3843*4882a593Smuzhiyun } else {
3844*4882a593Smuzhiyun crt1isoff = false;
3845*4882a593Smuzhiyun reg = 0x80;
3846*4882a593Smuzhiyun }
3847*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x17, 0x7f, reg);
3848*4882a593Smuzhiyun }
3849*4882a593Smuzhiyun #endif
3850*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
3851*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_315_VGA) {
3852*4882a593Smuzhiyun if((ivideo->sisfb_crt1off) && (doit)) {
3853*4882a593Smuzhiyun crt1isoff = true;
3854*4882a593Smuzhiyun reg = 0x40;
3855*4882a593Smuzhiyun reg1 = 0xc0;
3856*4882a593Smuzhiyun } else {
3857*4882a593Smuzhiyun crt1isoff = false;
3858*4882a593Smuzhiyun reg = 0x00;
3859*4882a593Smuzhiyun reg1 = 0x00;
3860*4882a593Smuzhiyun }
3861*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3862*4882a593Smuzhiyun SiS_SetRegANDOR(SISSR, 0x1f, 0x3f, reg1);
3863*4882a593Smuzhiyun }
3864*4882a593Smuzhiyun #endif
3865*4882a593Smuzhiyun
3866*4882a593Smuzhiyun if(crt1isoff) {
3867*4882a593Smuzhiyun ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3868*4882a593Smuzhiyun ivideo->currentvbflags |= VB_SINGLE_MODE;
3869*4882a593Smuzhiyun } else {
3870*4882a593Smuzhiyun ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3871*4882a593Smuzhiyun if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3872*4882a593Smuzhiyun ivideo->currentvbflags |= VB_MIRROR_MODE;
3873*4882a593Smuzhiyun } else {
3874*4882a593Smuzhiyun ivideo->currentvbflags |= VB_SINGLE_MODE;
3875*4882a593Smuzhiyun }
3876*4882a593Smuzhiyun }
3877*4882a593Smuzhiyun
3878*4882a593Smuzhiyun SiS_SetRegAND(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3879*4882a593Smuzhiyun
3880*4882a593Smuzhiyun if(ivideo->currentvbflags & CRT2_TV) {
3881*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3882*4882a593Smuzhiyun ivideo->p2_1f = SiS_GetReg(SISPART2, 0x1f);
3883*4882a593Smuzhiyun ivideo->p2_20 = SiS_GetReg(SISPART2, 0x20);
3884*4882a593Smuzhiyun ivideo->p2_2b = SiS_GetReg(SISPART2, 0x2b);
3885*4882a593Smuzhiyun ivideo->p2_42 = SiS_GetReg(SISPART2, 0x42);
3886*4882a593Smuzhiyun ivideo->p2_43 = SiS_GetReg(SISPART2, 0x43);
3887*4882a593Smuzhiyun ivideo->p2_01 = SiS_GetReg(SISPART2, 0x01);
3888*4882a593Smuzhiyun ivideo->p2_02 = SiS_GetReg(SISPART2, 0x02);
3889*4882a593Smuzhiyun } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3890*4882a593Smuzhiyun if(ivideo->chronteltype == 1) {
3891*4882a593Smuzhiyun ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3892*4882a593Smuzhiyun ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3893*4882a593Smuzhiyun ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3894*4882a593Smuzhiyun ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3895*4882a593Smuzhiyun }
3896*4882a593Smuzhiyun }
3897*4882a593Smuzhiyun }
3898*4882a593Smuzhiyun
3899*4882a593Smuzhiyun if(ivideo->tvxpos) {
3900*4882a593Smuzhiyun sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
3901*4882a593Smuzhiyun }
3902*4882a593Smuzhiyun if(ivideo->tvypos) {
3903*4882a593Smuzhiyun sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
3904*4882a593Smuzhiyun }
3905*4882a593Smuzhiyun
3906*4882a593Smuzhiyun /* Eventually sync engines */
3907*4882a593Smuzhiyun sisfb_check_engine_and_sync(ivideo);
3908*4882a593Smuzhiyun
3909*4882a593Smuzhiyun /* (Re-)Initialize chip engines */
3910*4882a593Smuzhiyun if(ivideo->accel) {
3911*4882a593Smuzhiyun sisfb_engine_init(ivideo);
3912*4882a593Smuzhiyun } else {
3913*4882a593Smuzhiyun ivideo->engineok = 0;
3914*4882a593Smuzhiyun }
3915*4882a593Smuzhiyun }
3916*4882a593Smuzhiyun
3917*4882a593Smuzhiyun static int
sisfb_reset_mode(struct sis_video_info * ivideo)3918*4882a593Smuzhiyun sisfb_reset_mode(struct sis_video_info *ivideo)
3919*4882a593Smuzhiyun {
3920*4882a593Smuzhiyun if(sisfb_set_mode(ivideo, 0))
3921*4882a593Smuzhiyun return 1;
3922*4882a593Smuzhiyun
3923*4882a593Smuzhiyun sisfb_set_pitch(ivideo);
3924*4882a593Smuzhiyun sisfb_set_base_CRT1(ivideo, ivideo->current_base);
3925*4882a593Smuzhiyun sisfb_set_base_CRT2(ivideo, ivideo->current_base);
3926*4882a593Smuzhiyun
3927*4882a593Smuzhiyun return 0;
3928*4882a593Smuzhiyun }
3929*4882a593Smuzhiyun
3930*4882a593Smuzhiyun static void
sisfb_handle_command(struct sis_video_info * ivideo,struct sisfb_cmd * sisfb_command)3931*4882a593Smuzhiyun sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
3932*4882a593Smuzhiyun {
3933*4882a593Smuzhiyun int mycrt1off;
3934*4882a593Smuzhiyun
3935*4882a593Smuzhiyun switch(sisfb_command->sisfb_cmd) {
3936*4882a593Smuzhiyun case SISFB_CMD_GETVBFLAGS:
3937*4882a593Smuzhiyun if(!ivideo->modechanged) {
3938*4882a593Smuzhiyun sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3939*4882a593Smuzhiyun } else {
3940*4882a593Smuzhiyun sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3941*4882a593Smuzhiyun sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
3942*4882a593Smuzhiyun sisfb_command->sisfb_result[2] = ivideo->vbflags2;
3943*4882a593Smuzhiyun }
3944*4882a593Smuzhiyun break;
3945*4882a593Smuzhiyun case SISFB_CMD_SWITCHCRT1:
3946*4882a593Smuzhiyun /* arg[0]: 0 = off, 1 = on, 99 = query */
3947*4882a593Smuzhiyun if(!ivideo->modechanged) {
3948*4882a593Smuzhiyun sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3949*4882a593Smuzhiyun } else if(sisfb_command->sisfb_arg[0] == 99) {
3950*4882a593Smuzhiyun /* Query */
3951*4882a593Smuzhiyun sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3952*4882a593Smuzhiyun sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3953*4882a593Smuzhiyun } else if(ivideo->sisfblocked) {
3954*4882a593Smuzhiyun sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
3955*4882a593Smuzhiyun } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
3956*4882a593Smuzhiyun (sisfb_command->sisfb_arg[0] == 0)) {
3957*4882a593Smuzhiyun sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
3958*4882a593Smuzhiyun } else {
3959*4882a593Smuzhiyun sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3960*4882a593Smuzhiyun mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
3961*4882a593Smuzhiyun if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
3962*4882a593Smuzhiyun ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
3963*4882a593Smuzhiyun ivideo->sisfb_crt1off = mycrt1off;
3964*4882a593Smuzhiyun if(sisfb_reset_mode(ivideo)) {
3965*4882a593Smuzhiyun sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
3966*4882a593Smuzhiyun }
3967*4882a593Smuzhiyun }
3968*4882a593Smuzhiyun sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3969*4882a593Smuzhiyun }
3970*4882a593Smuzhiyun break;
3971*4882a593Smuzhiyun /* more to come */
3972*4882a593Smuzhiyun default:
3973*4882a593Smuzhiyun sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
3974*4882a593Smuzhiyun printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
3975*4882a593Smuzhiyun sisfb_command->sisfb_cmd);
3976*4882a593Smuzhiyun }
3977*4882a593Smuzhiyun }
3978*4882a593Smuzhiyun
3979*4882a593Smuzhiyun #ifndef MODULE
sisfb_setup(char * options)3980*4882a593Smuzhiyun static int __init sisfb_setup(char *options)
3981*4882a593Smuzhiyun {
3982*4882a593Smuzhiyun char *this_opt;
3983*4882a593Smuzhiyun
3984*4882a593Smuzhiyun sisfb_setdefaultparms();
3985*4882a593Smuzhiyun
3986*4882a593Smuzhiyun if(!options || !(*options))
3987*4882a593Smuzhiyun return 0;
3988*4882a593Smuzhiyun
3989*4882a593Smuzhiyun while((this_opt = strsep(&options, ",")) != NULL) {
3990*4882a593Smuzhiyun
3991*4882a593Smuzhiyun if(!(*this_opt)) continue;
3992*4882a593Smuzhiyun
3993*4882a593Smuzhiyun if(!strncasecmp(this_opt, "off", 3)) {
3994*4882a593Smuzhiyun sisfb_off = 1;
3995*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "forcecrt2type:", 14)) {
3996*4882a593Smuzhiyun /* Need to check crt2 type first for fstn/dstn */
3997*4882a593Smuzhiyun sisfb_search_crt2type(this_opt + 14);
3998*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "tvmode:",7)) {
3999*4882a593Smuzhiyun sisfb_search_tvstd(this_opt + 7);
4000*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "tvstandard:",11)) {
4001*4882a593Smuzhiyun sisfb_search_tvstd(this_opt + 11);
4002*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "mode:", 5)) {
4003*4882a593Smuzhiyun sisfb_search_mode(this_opt + 5, false);
4004*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "vesa:", 5)) {
4005*4882a593Smuzhiyun sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
4006*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "rate:", 5)) {
4007*4882a593Smuzhiyun sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
4008*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "forcecrt1:", 10)) {
4009*4882a593Smuzhiyun sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
4010*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "mem:",4)) {
4011*4882a593Smuzhiyun sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
4012*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "pdc:", 4)) {
4013*4882a593Smuzhiyun sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
4014*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "pdc1:", 5)) {
4015*4882a593Smuzhiyun sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
4016*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "noaccel", 7)) {
4017*4882a593Smuzhiyun sisfb_accel = 0;
4018*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "accel", 5)) {
4019*4882a593Smuzhiyun sisfb_accel = -1;
4020*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "noypan", 6)) {
4021*4882a593Smuzhiyun sisfb_ypan = 0;
4022*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "ypan", 4)) {
4023*4882a593Smuzhiyun sisfb_ypan = -1;
4024*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "nomax", 5)) {
4025*4882a593Smuzhiyun sisfb_max = 0;
4026*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "max", 3)) {
4027*4882a593Smuzhiyun sisfb_max = -1;
4028*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "userom:", 7)) {
4029*4882a593Smuzhiyun sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4030*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "useoem:", 7)) {
4031*4882a593Smuzhiyun sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4032*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "nocrt2rate", 10)) {
4033*4882a593Smuzhiyun sisfb_nocrt2rate = 1;
4034*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "scalelcd:", 9)) {
4035*4882a593Smuzhiyun unsigned long temp = 2;
4036*4882a593Smuzhiyun temp = simple_strtoul(this_opt + 9, NULL, 0);
4037*4882a593Smuzhiyun if((temp == 0) || (temp == 1)) {
4038*4882a593Smuzhiyun sisfb_scalelcd = temp ^ 1;
4039*4882a593Smuzhiyun }
4040*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "tvxposoffset:", 13)) {
4041*4882a593Smuzhiyun int temp = 0;
4042*4882a593Smuzhiyun temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4043*4882a593Smuzhiyun if((temp >= -32) && (temp <= 32)) {
4044*4882a593Smuzhiyun sisfb_tvxposoffset = temp;
4045*4882a593Smuzhiyun }
4046*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "tvyposoffset:", 13)) {
4047*4882a593Smuzhiyun int temp = 0;
4048*4882a593Smuzhiyun temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4049*4882a593Smuzhiyun if((temp >= -32) && (temp <= 32)) {
4050*4882a593Smuzhiyun sisfb_tvyposoffset = temp;
4051*4882a593Smuzhiyun }
4052*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "specialtiming:", 14)) {
4053*4882a593Smuzhiyun sisfb_search_specialtiming(this_opt + 14);
4054*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "lvdshl:", 7)) {
4055*4882a593Smuzhiyun int temp = 4;
4056*4882a593Smuzhiyun temp = simple_strtoul(this_opt + 7, NULL, 0);
4057*4882a593Smuzhiyun if((temp >= 0) && (temp <= 3)) {
4058*4882a593Smuzhiyun sisfb_lvdshl = temp;
4059*4882a593Smuzhiyun }
4060*4882a593Smuzhiyun } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4061*4882a593Smuzhiyun sisfb_search_mode(this_opt, true);
4062*4882a593Smuzhiyun #if !defined(__i386__) && !defined(__x86_64__)
4063*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "resetcard", 9)) {
4064*4882a593Smuzhiyun sisfb_resetcard = 1;
4065*4882a593Smuzhiyun } else if(!strncasecmp(this_opt, "videoram:", 9)) {
4066*4882a593Smuzhiyun sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
4067*4882a593Smuzhiyun #endif
4068*4882a593Smuzhiyun } else {
4069*4882a593Smuzhiyun printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4070*4882a593Smuzhiyun }
4071*4882a593Smuzhiyun
4072*4882a593Smuzhiyun }
4073*4882a593Smuzhiyun
4074*4882a593Smuzhiyun return 0;
4075*4882a593Smuzhiyun }
4076*4882a593Smuzhiyun #endif
4077*4882a593Smuzhiyun
sisfb_check_rom(void __iomem * rom_base,struct sis_video_info * ivideo)4078*4882a593Smuzhiyun static int sisfb_check_rom(void __iomem *rom_base,
4079*4882a593Smuzhiyun struct sis_video_info *ivideo)
4080*4882a593Smuzhiyun {
4081*4882a593Smuzhiyun void __iomem *rom;
4082*4882a593Smuzhiyun int romptr;
4083*4882a593Smuzhiyun
4084*4882a593Smuzhiyun if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4085*4882a593Smuzhiyun return 0;
4086*4882a593Smuzhiyun
4087*4882a593Smuzhiyun romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4088*4882a593Smuzhiyun if(romptr > (0x10000 - 8))
4089*4882a593Smuzhiyun return 0;
4090*4882a593Smuzhiyun
4091*4882a593Smuzhiyun rom = rom_base + romptr;
4092*4882a593Smuzhiyun
4093*4882a593Smuzhiyun if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4094*4882a593Smuzhiyun (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4095*4882a593Smuzhiyun return 0;
4096*4882a593Smuzhiyun
4097*4882a593Smuzhiyun if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4098*4882a593Smuzhiyun return 0;
4099*4882a593Smuzhiyun
4100*4882a593Smuzhiyun if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4101*4882a593Smuzhiyun return 0;
4102*4882a593Smuzhiyun
4103*4882a593Smuzhiyun return 1;
4104*4882a593Smuzhiyun }
4105*4882a593Smuzhiyun
sisfb_find_rom(struct pci_dev * pdev)4106*4882a593Smuzhiyun static unsigned char *sisfb_find_rom(struct pci_dev *pdev)
4107*4882a593Smuzhiyun {
4108*4882a593Smuzhiyun struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4109*4882a593Smuzhiyun void __iomem *rom_base;
4110*4882a593Smuzhiyun unsigned char *myrombase = NULL;
4111*4882a593Smuzhiyun size_t romsize;
4112*4882a593Smuzhiyun
4113*4882a593Smuzhiyun /* First, try the official pci ROM functions (except
4114*4882a593Smuzhiyun * on integrated chipsets which have no ROM).
4115*4882a593Smuzhiyun */
4116*4882a593Smuzhiyun
4117*4882a593Smuzhiyun if(!ivideo->nbridge) {
4118*4882a593Smuzhiyun
4119*4882a593Smuzhiyun if((rom_base = pci_map_rom(pdev, &romsize))) {
4120*4882a593Smuzhiyun
4121*4882a593Smuzhiyun if(sisfb_check_rom(rom_base, ivideo)) {
4122*4882a593Smuzhiyun
4123*4882a593Smuzhiyun if((myrombase = vmalloc(65536))) {
4124*4882a593Smuzhiyun memcpy_fromio(myrombase, rom_base,
4125*4882a593Smuzhiyun (romsize > 65536) ? 65536 : romsize);
4126*4882a593Smuzhiyun }
4127*4882a593Smuzhiyun }
4128*4882a593Smuzhiyun pci_unmap_rom(pdev, rom_base);
4129*4882a593Smuzhiyun }
4130*4882a593Smuzhiyun }
4131*4882a593Smuzhiyun
4132*4882a593Smuzhiyun if(myrombase) return myrombase;
4133*4882a593Smuzhiyun
4134*4882a593Smuzhiyun /* Otherwise do it the conventional way. */
4135*4882a593Smuzhiyun
4136*4882a593Smuzhiyun #if defined(__i386__) || defined(__x86_64__)
4137*4882a593Smuzhiyun {
4138*4882a593Smuzhiyun u32 temp;
4139*4882a593Smuzhiyun
4140*4882a593Smuzhiyun for (temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
4141*4882a593Smuzhiyun
4142*4882a593Smuzhiyun rom_base = ioremap(temp, 65536);
4143*4882a593Smuzhiyun if (!rom_base)
4144*4882a593Smuzhiyun continue;
4145*4882a593Smuzhiyun
4146*4882a593Smuzhiyun if (!sisfb_check_rom(rom_base, ivideo)) {
4147*4882a593Smuzhiyun iounmap(rom_base);
4148*4882a593Smuzhiyun continue;
4149*4882a593Smuzhiyun }
4150*4882a593Smuzhiyun
4151*4882a593Smuzhiyun if ((myrombase = vmalloc(65536)))
4152*4882a593Smuzhiyun memcpy_fromio(myrombase, rom_base, 65536);
4153*4882a593Smuzhiyun
4154*4882a593Smuzhiyun iounmap(rom_base);
4155*4882a593Smuzhiyun break;
4156*4882a593Smuzhiyun
4157*4882a593Smuzhiyun }
4158*4882a593Smuzhiyun
4159*4882a593Smuzhiyun }
4160*4882a593Smuzhiyun #endif
4161*4882a593Smuzhiyun
4162*4882a593Smuzhiyun return myrombase;
4163*4882a593Smuzhiyun }
4164*4882a593Smuzhiyun
sisfb_post_map_vram(struct sis_video_info * ivideo,unsigned int * mapsize,unsigned int min)4165*4882a593Smuzhiyun static void sisfb_post_map_vram(struct sis_video_info *ivideo,
4166*4882a593Smuzhiyun unsigned int *mapsize, unsigned int min)
4167*4882a593Smuzhiyun {
4168*4882a593Smuzhiyun if (*mapsize < (min << 20))
4169*4882a593Smuzhiyun return;
4170*4882a593Smuzhiyun
4171*4882a593Smuzhiyun ivideo->video_vbase = ioremap_wc(ivideo->video_base, (*mapsize));
4172*4882a593Smuzhiyun
4173*4882a593Smuzhiyun if(!ivideo->video_vbase) {
4174*4882a593Smuzhiyun printk(KERN_ERR
4175*4882a593Smuzhiyun "sisfb: Unable to map maximum video RAM for size detection\n");
4176*4882a593Smuzhiyun (*mapsize) >>= 1;
4177*4882a593Smuzhiyun while((!(ivideo->video_vbase = ioremap_wc(ivideo->video_base, (*mapsize))))) {
4178*4882a593Smuzhiyun (*mapsize) >>= 1;
4179*4882a593Smuzhiyun if((*mapsize) < (min << 20))
4180*4882a593Smuzhiyun break;
4181*4882a593Smuzhiyun }
4182*4882a593Smuzhiyun if(ivideo->video_vbase) {
4183*4882a593Smuzhiyun printk(KERN_ERR
4184*4882a593Smuzhiyun "sisfb: Video RAM size detection limited to %dMB\n",
4185*4882a593Smuzhiyun (int)((*mapsize) >> 20));
4186*4882a593Smuzhiyun }
4187*4882a593Smuzhiyun }
4188*4882a593Smuzhiyun }
4189*4882a593Smuzhiyun
4190*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_300
sisfb_post_300_buswidth(struct sis_video_info * ivideo)4191*4882a593Smuzhiyun static int sisfb_post_300_buswidth(struct sis_video_info *ivideo)
4192*4882a593Smuzhiyun {
4193*4882a593Smuzhiyun void __iomem *FBAddress = ivideo->video_vbase;
4194*4882a593Smuzhiyun unsigned short temp;
4195*4882a593Smuzhiyun unsigned char reg;
4196*4882a593Smuzhiyun int i, j;
4197*4882a593Smuzhiyun
4198*4882a593Smuzhiyun SiS_SetRegAND(SISSR, 0x15, 0xFB);
4199*4882a593Smuzhiyun SiS_SetRegOR(SISSR, 0x15, 0x04);
4200*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0x00);
4201*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0xBF);
4202*4882a593Smuzhiyun
4203*4882a593Smuzhiyun for(i = 0; i < 2; i++) {
4204*4882a593Smuzhiyun temp = 0x1234;
4205*4882a593Smuzhiyun for(j = 0; j < 4; j++) {
4206*4882a593Smuzhiyun writew(temp, FBAddress);
4207*4882a593Smuzhiyun if(readw(FBAddress) == temp)
4208*4882a593Smuzhiyun break;
4209*4882a593Smuzhiyun SiS_SetRegOR(SISSR, 0x3c, 0x01);
4210*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x05);
4211*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x05);
4212*4882a593Smuzhiyun SiS_SetRegAND(SISSR, 0x3c, 0xfe);
4213*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x05);
4214*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x05);
4215*4882a593Smuzhiyun temp++;
4216*4882a593Smuzhiyun }
4217*4882a593Smuzhiyun }
4218*4882a593Smuzhiyun
4219*4882a593Smuzhiyun writel(0x01234567L, FBAddress);
4220*4882a593Smuzhiyun writel(0x456789ABL, (FBAddress + 4));
4221*4882a593Smuzhiyun writel(0x89ABCDEFL, (FBAddress + 8));
4222*4882a593Smuzhiyun writel(0xCDEF0123L, (FBAddress + 12));
4223*4882a593Smuzhiyun
4224*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x3b);
4225*4882a593Smuzhiyun if(reg & 0x01) {
4226*4882a593Smuzhiyun if(readl((FBAddress + 12)) == 0xCDEF0123L)
4227*4882a593Smuzhiyun return 4; /* Channel A 128bit */
4228*4882a593Smuzhiyun }
4229*4882a593Smuzhiyun
4230*4882a593Smuzhiyun if(readl((FBAddress + 4)) == 0x456789ABL)
4231*4882a593Smuzhiyun return 2; /* Channel B 64bit */
4232*4882a593Smuzhiyun
4233*4882a593Smuzhiyun return 1; /* 32bit */
4234*4882a593Smuzhiyun }
4235*4882a593Smuzhiyun
4236*4882a593Smuzhiyun static const unsigned short SiS_DRAMType[17][5] = {
4237*4882a593Smuzhiyun {0x0C,0x0A,0x02,0x40,0x39},
4238*4882a593Smuzhiyun {0x0D,0x0A,0x01,0x40,0x48},
4239*4882a593Smuzhiyun {0x0C,0x09,0x02,0x20,0x35},
4240*4882a593Smuzhiyun {0x0D,0x09,0x01,0x20,0x44},
4241*4882a593Smuzhiyun {0x0C,0x08,0x02,0x10,0x31},
4242*4882a593Smuzhiyun {0x0D,0x08,0x01,0x10,0x40},
4243*4882a593Smuzhiyun {0x0C,0x0A,0x01,0x20,0x34},
4244*4882a593Smuzhiyun {0x0C,0x09,0x01,0x08,0x32},
4245*4882a593Smuzhiyun {0x0B,0x08,0x02,0x08,0x21},
4246*4882a593Smuzhiyun {0x0C,0x08,0x01,0x08,0x30},
4247*4882a593Smuzhiyun {0x0A,0x08,0x02,0x04,0x11},
4248*4882a593Smuzhiyun {0x0B,0x0A,0x01,0x10,0x28},
4249*4882a593Smuzhiyun {0x09,0x08,0x02,0x02,0x01},
4250*4882a593Smuzhiyun {0x0B,0x09,0x01,0x08,0x24},
4251*4882a593Smuzhiyun {0x0B,0x08,0x01,0x04,0x20},
4252*4882a593Smuzhiyun {0x0A,0x08,0x01,0x02,0x10},
4253*4882a593Smuzhiyun {0x09,0x08,0x01,0x01,0x00}
4254*4882a593Smuzhiyun };
4255*4882a593Smuzhiyun
sisfb_post_300_rwtest(struct sis_video_info * ivideo,int iteration,int buswidth,int PseudoRankCapacity,int PseudoAdrPinCount,unsigned int mapsize)4256*4882a593Smuzhiyun static int sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration,
4257*4882a593Smuzhiyun int buswidth, int PseudoRankCapacity,
4258*4882a593Smuzhiyun int PseudoAdrPinCount, unsigned int mapsize)
4259*4882a593Smuzhiyun {
4260*4882a593Smuzhiyun void __iomem *FBAddr = ivideo->video_vbase;
4261*4882a593Smuzhiyun unsigned short sr14;
4262*4882a593Smuzhiyun unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4263*4882a593Smuzhiyun unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4264*4882a593Smuzhiyun
4265*4882a593Smuzhiyun for(k = 0; k < ARRAY_SIZE(SiS_DRAMType); k++) {
4266*4882a593Smuzhiyun
4267*4882a593Smuzhiyun RankCapacity = buswidth * SiS_DRAMType[k][3];
4268*4882a593Smuzhiyun
4269*4882a593Smuzhiyun if(RankCapacity != PseudoRankCapacity)
4270*4882a593Smuzhiyun continue;
4271*4882a593Smuzhiyun
4272*4882a593Smuzhiyun if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4273*4882a593Smuzhiyun continue;
4274*4882a593Smuzhiyun
4275*4882a593Smuzhiyun BankNumHigh = RankCapacity * 16 * iteration - 1;
4276*4882a593Smuzhiyun if(iteration == 3) { /* Rank No */
4277*4882a593Smuzhiyun BankNumMid = RankCapacity * 16 - 1;
4278*4882a593Smuzhiyun } else {
4279*4882a593Smuzhiyun BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4280*4882a593Smuzhiyun }
4281*4882a593Smuzhiyun
4282*4882a593Smuzhiyun PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4283*4882a593Smuzhiyun PhysicalAdrHigh = BankNumHigh;
4284*4882a593Smuzhiyun PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4285*4882a593Smuzhiyun PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4286*4882a593Smuzhiyun
4287*4882a593Smuzhiyun SiS_SetRegAND(SISSR, 0x15, 0xFB); /* Test */
4288*4882a593Smuzhiyun SiS_SetRegOR(SISSR, 0x15, 0x04); /* Test */
4289*4882a593Smuzhiyun sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4290*4882a593Smuzhiyun if(buswidth == 4) sr14 |= 0x80;
4291*4882a593Smuzhiyun else if(buswidth == 2) sr14 |= 0x40;
4292*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, SiS_DRAMType[k][4]);
4293*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, sr14);
4294*4882a593Smuzhiyun
4295*4882a593Smuzhiyun BankNumHigh <<= 16;
4296*4882a593Smuzhiyun BankNumMid <<= 16;
4297*4882a593Smuzhiyun
4298*4882a593Smuzhiyun if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4299*4882a593Smuzhiyun (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4300*4882a593Smuzhiyun (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4301*4882a593Smuzhiyun (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4302*4882a593Smuzhiyun continue;
4303*4882a593Smuzhiyun
4304*4882a593Smuzhiyun /* Write data */
4305*4882a593Smuzhiyun writew(((unsigned short)PhysicalAdrHigh),
4306*4882a593Smuzhiyun (FBAddr + BankNumHigh + PhysicalAdrHigh));
4307*4882a593Smuzhiyun writew(((unsigned short)BankNumMid),
4308*4882a593Smuzhiyun (FBAddr + BankNumMid + PhysicalAdrHigh));
4309*4882a593Smuzhiyun writew(((unsigned short)PhysicalAdrHalfPage),
4310*4882a593Smuzhiyun (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4311*4882a593Smuzhiyun writew(((unsigned short)PhysicalAdrOtherPage),
4312*4882a593Smuzhiyun (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4313*4882a593Smuzhiyun
4314*4882a593Smuzhiyun /* Read data */
4315*4882a593Smuzhiyun if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4316*4882a593Smuzhiyun return 1;
4317*4882a593Smuzhiyun }
4318*4882a593Smuzhiyun
4319*4882a593Smuzhiyun return 0;
4320*4882a593Smuzhiyun }
4321*4882a593Smuzhiyun
sisfb_post_300_ramsize(struct pci_dev * pdev,unsigned int mapsize)4322*4882a593Smuzhiyun static void sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
4323*4882a593Smuzhiyun {
4324*4882a593Smuzhiyun struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4325*4882a593Smuzhiyun int i, j, buswidth;
4326*4882a593Smuzhiyun int PseudoRankCapacity, PseudoAdrPinCount;
4327*4882a593Smuzhiyun
4328*4882a593Smuzhiyun buswidth = sisfb_post_300_buswidth(ivideo);
4329*4882a593Smuzhiyun
4330*4882a593Smuzhiyun for(i = 6; i >= 0; i--) {
4331*4882a593Smuzhiyun PseudoRankCapacity = 1 << i;
4332*4882a593Smuzhiyun for(j = 4; j >= 1; j--) {
4333*4882a593Smuzhiyun PseudoAdrPinCount = 15 - j;
4334*4882a593Smuzhiyun if((PseudoRankCapacity * j) <= 64) {
4335*4882a593Smuzhiyun if(sisfb_post_300_rwtest(ivideo,
4336*4882a593Smuzhiyun j,
4337*4882a593Smuzhiyun buswidth,
4338*4882a593Smuzhiyun PseudoRankCapacity,
4339*4882a593Smuzhiyun PseudoAdrPinCount,
4340*4882a593Smuzhiyun mapsize))
4341*4882a593Smuzhiyun return;
4342*4882a593Smuzhiyun }
4343*4882a593Smuzhiyun }
4344*4882a593Smuzhiyun }
4345*4882a593Smuzhiyun }
4346*4882a593Smuzhiyun
sisfb_post_sis300(struct pci_dev * pdev)4347*4882a593Smuzhiyun static void sisfb_post_sis300(struct pci_dev *pdev)
4348*4882a593Smuzhiyun {
4349*4882a593Smuzhiyun struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4350*4882a593Smuzhiyun unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
4351*4882a593Smuzhiyun u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4352*4882a593Smuzhiyun u16 index, rindex, memtype = 0;
4353*4882a593Smuzhiyun unsigned int mapsize;
4354*4882a593Smuzhiyun
4355*4882a593Smuzhiyun if(!ivideo->SiS_Pr.UseROM)
4356*4882a593Smuzhiyun bios = NULL;
4357*4882a593Smuzhiyun
4358*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x05, 0x86);
4359*4882a593Smuzhiyun
4360*4882a593Smuzhiyun if(bios) {
4361*4882a593Smuzhiyun if(bios[0x52] & 0x80) {
4362*4882a593Smuzhiyun memtype = bios[0x52];
4363*4882a593Smuzhiyun } else {
4364*4882a593Smuzhiyun memtype = SiS_GetReg(SISSR, 0x3a);
4365*4882a593Smuzhiyun }
4366*4882a593Smuzhiyun memtype &= 0x07;
4367*4882a593Smuzhiyun }
4368*4882a593Smuzhiyun
4369*4882a593Smuzhiyun v3 = 0x80; v6 = 0x80;
4370*4882a593Smuzhiyun if(ivideo->revision_id <= 0x13) {
4371*4882a593Smuzhiyun v1 = 0x44; v2 = 0x42;
4372*4882a593Smuzhiyun v4 = 0x44; v5 = 0x42;
4373*4882a593Smuzhiyun } else {
4374*4882a593Smuzhiyun v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4375*4882a593Smuzhiyun v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4376*4882a593Smuzhiyun if(bios) {
4377*4882a593Smuzhiyun index = memtype * 5;
4378*4882a593Smuzhiyun rindex = index + 0x54;
4379*4882a593Smuzhiyun v1 = bios[rindex++];
4380*4882a593Smuzhiyun v2 = bios[rindex++];
4381*4882a593Smuzhiyun v3 = bios[rindex++];
4382*4882a593Smuzhiyun rindex = index + 0x7c;
4383*4882a593Smuzhiyun v4 = bios[rindex++];
4384*4882a593Smuzhiyun v5 = bios[rindex++];
4385*4882a593Smuzhiyun v6 = bios[rindex++];
4386*4882a593Smuzhiyun }
4387*4882a593Smuzhiyun }
4388*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x28, v1);
4389*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x29, v2);
4390*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x2a, v3);
4391*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x2e, v4);
4392*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x2f, v5);
4393*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x30, v6);
4394*4882a593Smuzhiyun
4395*4882a593Smuzhiyun v1 = 0x10;
4396*4882a593Smuzhiyun if(bios)
4397*4882a593Smuzhiyun v1 = bios[0xa4];
4398*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x07, v1); /* DAC speed */
4399*4882a593Smuzhiyun
4400*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x11, 0x0f); /* DDC, power save */
4401*4882a593Smuzhiyun
4402*4882a593Smuzhiyun v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4403*4882a593Smuzhiyun v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4404*4882a593Smuzhiyun if(bios) {
4405*4882a593Smuzhiyun memtype += 0xa5;
4406*4882a593Smuzhiyun v1 = bios[memtype];
4407*4882a593Smuzhiyun v2 = bios[memtype + 8];
4408*4882a593Smuzhiyun v3 = bios[memtype + 16];
4409*4882a593Smuzhiyun v4 = bios[memtype + 24];
4410*4882a593Smuzhiyun v5 = bios[memtype + 32];
4411*4882a593Smuzhiyun v6 = bios[memtype + 40];
4412*4882a593Smuzhiyun v7 = bios[memtype + 48];
4413*4882a593Smuzhiyun v8 = bios[memtype + 56];
4414*4882a593Smuzhiyun }
4415*4882a593Smuzhiyun if(ivideo->revision_id >= 0x80)
4416*4882a593Smuzhiyun v3 &= 0xfd;
4417*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4418*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, v2);
4419*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x17, v3);
4420*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x18, v4);
4421*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x19, v5);
4422*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x1a, v6);
4423*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x1b, v7);
4424*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x1c, v8); /* ---- */
4425*4882a593Smuzhiyun SiS_SetRegAND(SISSR, 0x15, 0xfb);
4426*4882a593Smuzhiyun SiS_SetRegOR(SISSR, 0x15, 0x04);
4427*4882a593Smuzhiyun if(bios) {
4428*4882a593Smuzhiyun if(bios[0x53] & 0x02) {
4429*4882a593Smuzhiyun SiS_SetRegOR(SISSR, 0x19, 0x20);
4430*4882a593Smuzhiyun }
4431*4882a593Smuzhiyun }
4432*4882a593Smuzhiyun v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
4433*4882a593Smuzhiyun if(ivideo->revision_id >= 0x80)
4434*4882a593Smuzhiyun v1 |= 0x01;
4435*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x1f, v1);
4436*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
4437*4882a593Smuzhiyun v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4438*4882a593Smuzhiyun if(bios) {
4439*4882a593Smuzhiyun v1 = bios[0xe8];
4440*4882a593Smuzhiyun v2 = bios[0xe9];
4441*4882a593Smuzhiyun v3 = bios[0xea];
4442*4882a593Smuzhiyun }
4443*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x23, v1);
4444*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x24, v2);
4445*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x25, v3);
4446*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x21, 0x84);
4447*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x22, 0x00);
4448*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x37, 0x00);
4449*4882a593Smuzhiyun SiS_SetRegOR(SISPART1, 0x24, 0x01); /* unlock crt2 */
4450*4882a593Smuzhiyun SiS_SetReg(SISPART1, 0x00, 0x00);
4451*4882a593Smuzhiyun v1 = 0x40; v2 = 0x11;
4452*4882a593Smuzhiyun if(bios) {
4453*4882a593Smuzhiyun v1 = bios[0xec];
4454*4882a593Smuzhiyun v2 = bios[0xeb];
4455*4882a593Smuzhiyun }
4456*4882a593Smuzhiyun SiS_SetReg(SISPART1, 0x02, v1);
4457*4882a593Smuzhiyun
4458*4882a593Smuzhiyun if(ivideo->revision_id >= 0x80)
4459*4882a593Smuzhiyun v2 &= ~0x01;
4460*4882a593Smuzhiyun
4461*4882a593Smuzhiyun reg = SiS_GetReg(SISPART4, 0x00);
4462*4882a593Smuzhiyun if((reg == 1) || (reg == 2)) {
4463*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x37, 0x02);
4464*4882a593Smuzhiyun SiS_SetReg(SISPART2, 0x00, 0x1c);
4465*4882a593Smuzhiyun v4 = 0x00; v5 = 0x00; v6 = 0x10;
4466*4882a593Smuzhiyun if(ivideo->SiS_Pr.UseROM) {
4467*4882a593Smuzhiyun v4 = bios[0xf5];
4468*4882a593Smuzhiyun v5 = bios[0xf6];
4469*4882a593Smuzhiyun v6 = bios[0xf7];
4470*4882a593Smuzhiyun }
4471*4882a593Smuzhiyun SiS_SetReg(SISPART4, 0x0d, v4);
4472*4882a593Smuzhiyun SiS_SetReg(SISPART4, 0x0e, v5);
4473*4882a593Smuzhiyun SiS_SetReg(SISPART4, 0x10, v6);
4474*4882a593Smuzhiyun SiS_SetReg(SISPART4, 0x0f, 0x3f);
4475*4882a593Smuzhiyun reg = SiS_GetReg(SISPART4, 0x01);
4476*4882a593Smuzhiyun if(reg >= 0xb0) {
4477*4882a593Smuzhiyun reg = SiS_GetReg(SISPART4, 0x23);
4478*4882a593Smuzhiyun reg &= 0x20;
4479*4882a593Smuzhiyun reg <<= 1;
4480*4882a593Smuzhiyun SiS_SetReg(SISPART4, 0x23, reg);
4481*4882a593Smuzhiyun }
4482*4882a593Smuzhiyun } else {
4483*4882a593Smuzhiyun v2 &= ~0x10;
4484*4882a593Smuzhiyun }
4485*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x32, v2);
4486*4882a593Smuzhiyun
4487*4882a593Smuzhiyun SiS_SetRegAND(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4488*4882a593Smuzhiyun
4489*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x16);
4490*4882a593Smuzhiyun reg &= 0xc3;
4491*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x35, reg);
4492*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x83, 0x00);
4493*4882a593Smuzhiyun #if !defined(__i386__) && !defined(__x86_64__)
4494*4882a593Smuzhiyun if(sisfb_videoram) {
4495*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0x28); /* ? */
4496*4882a593Smuzhiyun reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4497*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, reg);
4498*4882a593Smuzhiyun } else {
4499*4882a593Smuzhiyun #endif
4500*4882a593Smuzhiyun /* Need to map max FB size for finding out about RAM size */
4501*4882a593Smuzhiyun mapsize = ivideo->video_size;
4502*4882a593Smuzhiyun sisfb_post_map_vram(ivideo, &mapsize, 4);
4503*4882a593Smuzhiyun
4504*4882a593Smuzhiyun if(ivideo->video_vbase) {
4505*4882a593Smuzhiyun sisfb_post_300_ramsize(pdev, mapsize);
4506*4882a593Smuzhiyun iounmap(ivideo->video_vbase);
4507*4882a593Smuzhiyun } else {
4508*4882a593Smuzhiyun printk(KERN_DEBUG
4509*4882a593Smuzhiyun "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4510*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0x28); /* ? */
4511*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4512*4882a593Smuzhiyun }
4513*4882a593Smuzhiyun #if !defined(__i386__) && !defined(__x86_64__)
4514*4882a593Smuzhiyun }
4515*4882a593Smuzhiyun #endif
4516*4882a593Smuzhiyun if(bios) {
4517*4882a593Smuzhiyun v1 = bios[0xe6];
4518*4882a593Smuzhiyun v2 = bios[0xe7];
4519*4882a593Smuzhiyun } else {
4520*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x3a);
4521*4882a593Smuzhiyun if((reg & 0x30) == 0x30) {
4522*4882a593Smuzhiyun v1 = 0x04; /* PCI */
4523*4882a593Smuzhiyun v2 = 0x92;
4524*4882a593Smuzhiyun } else {
4525*4882a593Smuzhiyun v1 = 0x14; /* AGP */
4526*4882a593Smuzhiyun v2 = 0xb2;
4527*4882a593Smuzhiyun }
4528*4882a593Smuzhiyun }
4529*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x21, v1);
4530*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x22, v2);
4531*4882a593Smuzhiyun
4532*4882a593Smuzhiyun /* Sense CRT1 */
4533*4882a593Smuzhiyun sisfb_sense_crt1(ivideo);
4534*4882a593Smuzhiyun
4535*4882a593Smuzhiyun /* Set default mode, don't clear screen */
4536*4882a593Smuzhiyun ivideo->SiS_Pr.SiS_UseOEM = false;
4537*4882a593Smuzhiyun SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
4538*4882a593Smuzhiyun SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
4539*4882a593Smuzhiyun ivideo->curFSTN = ivideo->curDSTN = 0;
4540*4882a593Smuzhiyun ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4541*4882a593Smuzhiyun SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4542*4882a593Smuzhiyun
4543*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x05, 0x86);
4544*4882a593Smuzhiyun
4545*4882a593Smuzhiyun /* Display off */
4546*4882a593Smuzhiyun SiS_SetRegOR(SISSR, 0x01, 0x20);
4547*4882a593Smuzhiyun
4548*4882a593Smuzhiyun /* Save mode number in CR34 */
4549*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x34, 0x2e);
4550*4882a593Smuzhiyun
4551*4882a593Smuzhiyun /* Let everyone know what the current mode is */
4552*4882a593Smuzhiyun ivideo->modeprechange = 0x2e;
4553*4882a593Smuzhiyun }
4554*4882a593Smuzhiyun #endif
4555*4882a593Smuzhiyun
4556*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
4557*4882a593Smuzhiyun #if 0
4558*4882a593Smuzhiyun static void sisfb_post_sis315330(struct pci_dev *pdev)
4559*4882a593Smuzhiyun {
4560*4882a593Smuzhiyun /* TODO */
4561*4882a593Smuzhiyun }
4562*4882a593Smuzhiyun #endif
4563*4882a593Smuzhiyun
sisfb_xgi_is21(struct sis_video_info * ivideo)4564*4882a593Smuzhiyun static inline int sisfb_xgi_is21(struct sis_video_info *ivideo)
4565*4882a593Smuzhiyun {
4566*4882a593Smuzhiyun return ivideo->chip_real_id == XGI_21;
4567*4882a593Smuzhiyun }
4568*4882a593Smuzhiyun
sisfb_post_xgi_delay(struct sis_video_info * ivideo,int delay)4569*4882a593Smuzhiyun static void sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
4570*4882a593Smuzhiyun {
4571*4882a593Smuzhiyun unsigned int i;
4572*4882a593Smuzhiyun u8 reg;
4573*4882a593Smuzhiyun
4574*4882a593Smuzhiyun for(i = 0; i <= (delay * 10 * 36); i++) {
4575*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x05);
4576*4882a593Smuzhiyun reg++;
4577*4882a593Smuzhiyun }
4578*4882a593Smuzhiyun }
4579*4882a593Smuzhiyun
sisfb_find_host_bridge(struct sis_video_info * ivideo,struct pci_dev * mypdev,unsigned short pcivendor)4580*4882a593Smuzhiyun static int sisfb_find_host_bridge(struct sis_video_info *ivideo,
4581*4882a593Smuzhiyun struct pci_dev *mypdev,
4582*4882a593Smuzhiyun unsigned short pcivendor)
4583*4882a593Smuzhiyun {
4584*4882a593Smuzhiyun struct pci_dev *pdev = NULL;
4585*4882a593Smuzhiyun unsigned short temp;
4586*4882a593Smuzhiyun int ret = 0;
4587*4882a593Smuzhiyun
4588*4882a593Smuzhiyun while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
4589*4882a593Smuzhiyun temp = pdev->vendor;
4590*4882a593Smuzhiyun if(temp == pcivendor) {
4591*4882a593Smuzhiyun ret = 1;
4592*4882a593Smuzhiyun pci_dev_put(pdev);
4593*4882a593Smuzhiyun break;
4594*4882a593Smuzhiyun }
4595*4882a593Smuzhiyun }
4596*4882a593Smuzhiyun
4597*4882a593Smuzhiyun return ret;
4598*4882a593Smuzhiyun }
4599*4882a593Smuzhiyun
sisfb_post_xgi_rwtest(struct sis_video_info * ivideo,int starta,unsigned int enda,unsigned int mapsize)4600*4882a593Smuzhiyun static int sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4601*4882a593Smuzhiyun unsigned int enda, unsigned int mapsize)
4602*4882a593Smuzhiyun {
4603*4882a593Smuzhiyun unsigned int pos;
4604*4882a593Smuzhiyun int i;
4605*4882a593Smuzhiyun
4606*4882a593Smuzhiyun writel(0, ivideo->video_vbase);
4607*4882a593Smuzhiyun
4608*4882a593Smuzhiyun for(i = starta; i <= enda; i++) {
4609*4882a593Smuzhiyun pos = 1 << i;
4610*4882a593Smuzhiyun if(pos < mapsize)
4611*4882a593Smuzhiyun writel(pos, ivideo->video_vbase + pos);
4612*4882a593Smuzhiyun }
4613*4882a593Smuzhiyun
4614*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 150);
4615*4882a593Smuzhiyun
4616*4882a593Smuzhiyun if(readl(ivideo->video_vbase) != 0)
4617*4882a593Smuzhiyun return 0;
4618*4882a593Smuzhiyun
4619*4882a593Smuzhiyun for(i = starta; i <= enda; i++) {
4620*4882a593Smuzhiyun pos = 1 << i;
4621*4882a593Smuzhiyun if(pos < mapsize) {
4622*4882a593Smuzhiyun if(readl(ivideo->video_vbase + pos) != pos)
4623*4882a593Smuzhiyun return 0;
4624*4882a593Smuzhiyun } else
4625*4882a593Smuzhiyun return 0;
4626*4882a593Smuzhiyun }
4627*4882a593Smuzhiyun
4628*4882a593Smuzhiyun return 1;
4629*4882a593Smuzhiyun }
4630*4882a593Smuzhiyun
sisfb_post_xgi_ramsize(struct sis_video_info * ivideo)4631*4882a593Smuzhiyun static int sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4632*4882a593Smuzhiyun {
4633*4882a593Smuzhiyun unsigned int buswidth, ranksize, channelab, mapsize;
4634*4882a593Smuzhiyun int i, j, k, l, status;
4635*4882a593Smuzhiyun u8 reg, sr14;
4636*4882a593Smuzhiyun static const u8 dramsr13[12 * 5] = {
4637*4882a593Smuzhiyun 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4638*4882a593Smuzhiyun 0x02, 0x0e, 0x0a, 0x40, 0x59,
4639*4882a593Smuzhiyun 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4640*4882a593Smuzhiyun 0x02, 0x0e, 0x09, 0x20, 0x55,
4641*4882a593Smuzhiyun 0x02, 0x0d, 0x0a, 0x20, 0x49,
4642*4882a593Smuzhiyun 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4643*4882a593Smuzhiyun 0x02, 0x0e, 0x08, 0x10, 0x51,
4644*4882a593Smuzhiyun 0x02, 0x0d, 0x09, 0x10, 0x45,
4645*4882a593Smuzhiyun 0x02, 0x0c, 0x0a, 0x10, 0x39,
4646*4882a593Smuzhiyun 0x02, 0x0d, 0x08, 0x08, 0x41,
4647*4882a593Smuzhiyun 0x02, 0x0c, 0x09, 0x08, 0x35,
4648*4882a593Smuzhiyun 0x02, 0x0c, 0x08, 0x04, 0x31
4649*4882a593Smuzhiyun };
4650*4882a593Smuzhiyun static const u8 dramsr13_4[4 * 5] = {
4651*4882a593Smuzhiyun 0x02, 0x0d, 0x09, 0x40, 0x45,
4652*4882a593Smuzhiyun 0x02, 0x0c, 0x09, 0x20, 0x35,
4653*4882a593Smuzhiyun 0x02, 0x0c, 0x08, 0x10, 0x31,
4654*4882a593Smuzhiyun 0x02, 0x0b, 0x08, 0x08, 0x21
4655*4882a593Smuzhiyun };
4656*4882a593Smuzhiyun
4657*4882a593Smuzhiyun /* Enable linear mode, disable 0xa0000 address decoding */
4658*4882a593Smuzhiyun /* We disable a0000 address decoding, because
4659*4882a593Smuzhiyun * - if running on x86, if the card is disabled, it means
4660*4882a593Smuzhiyun * that another card is in the system. We don't want
4661*4882a593Smuzhiyun * to interphere with that primary card's textmode.
4662*4882a593Smuzhiyun * - if running on non-x86, there usually is no VGA window
4663*4882a593Smuzhiyun * at a0000.
4664*4882a593Smuzhiyun */
4665*4882a593Smuzhiyun SiS_SetRegOR(SISSR, 0x20, (0x80 | 0x04));
4666*4882a593Smuzhiyun
4667*4882a593Smuzhiyun /* Need to map max FB size for finding out about RAM size */
4668*4882a593Smuzhiyun mapsize = ivideo->video_size;
4669*4882a593Smuzhiyun sisfb_post_map_vram(ivideo, &mapsize, 32);
4670*4882a593Smuzhiyun
4671*4882a593Smuzhiyun if(!ivideo->video_vbase) {
4672*4882a593Smuzhiyun printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4673*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0x35);
4674*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0x41);
4675*4882a593Smuzhiyun /* TODO */
4676*4882a593Smuzhiyun return -ENOMEM;
4677*4882a593Smuzhiyun }
4678*4882a593Smuzhiyun
4679*4882a593Smuzhiyun /* Non-interleaving */
4680*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x15, 0x00);
4681*4882a593Smuzhiyun /* No tiling */
4682*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x1c, 0x00);
4683*4882a593Smuzhiyun
4684*4882a593Smuzhiyun if(ivideo->chip == XGI_20) {
4685*4882a593Smuzhiyun
4686*4882a593Smuzhiyun channelab = 1;
4687*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x97);
4688*4882a593Smuzhiyun if(!(reg & 0x01)) { /* Single 32/16 */
4689*4882a593Smuzhiyun buswidth = 32;
4690*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0xb1);
4691*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0x52);
4692*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
4693*4882a593Smuzhiyun sr14 = 0x02;
4694*4882a593Smuzhiyun if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4695*4882a593Smuzhiyun goto bail_out;
4696*4882a593Smuzhiyun
4697*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0x31);
4698*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0x42);
4699*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
4700*4882a593Smuzhiyun if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4701*4882a593Smuzhiyun goto bail_out;
4702*4882a593Smuzhiyun
4703*4882a593Smuzhiyun buswidth = 16;
4704*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0xb1);
4705*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0x41);
4706*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
4707*4882a593Smuzhiyun sr14 = 0x01;
4708*4882a593Smuzhiyun if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4709*4882a593Smuzhiyun goto bail_out;
4710*4882a593Smuzhiyun else
4711*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0x31);
4712*4882a593Smuzhiyun } else { /* Dual 16/8 */
4713*4882a593Smuzhiyun buswidth = 16;
4714*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0xb1);
4715*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0x41);
4716*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
4717*4882a593Smuzhiyun sr14 = 0x01;
4718*4882a593Smuzhiyun if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4719*4882a593Smuzhiyun goto bail_out;
4720*4882a593Smuzhiyun
4721*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0x31);
4722*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0x31);
4723*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
4724*4882a593Smuzhiyun if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4725*4882a593Smuzhiyun goto bail_out;
4726*4882a593Smuzhiyun
4727*4882a593Smuzhiyun buswidth = 8;
4728*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0xb1);
4729*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0x30);
4730*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
4731*4882a593Smuzhiyun sr14 = 0x00;
4732*4882a593Smuzhiyun if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4733*4882a593Smuzhiyun goto bail_out;
4734*4882a593Smuzhiyun else
4735*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0x31);
4736*4882a593Smuzhiyun }
4737*4882a593Smuzhiyun
4738*4882a593Smuzhiyun } else { /* XGI_40 */
4739*4882a593Smuzhiyun
4740*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x97);
4741*4882a593Smuzhiyun if(!(reg & 0x10)) {
4742*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x39);
4743*4882a593Smuzhiyun reg >>= 1;
4744*4882a593Smuzhiyun }
4745*4882a593Smuzhiyun
4746*4882a593Smuzhiyun if(reg & 0x01) { /* DDRII */
4747*4882a593Smuzhiyun buswidth = 32;
4748*4882a593Smuzhiyun if(ivideo->revision_id == 2) {
4749*4882a593Smuzhiyun channelab = 2;
4750*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0xa1);
4751*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0x44);
4752*4882a593Smuzhiyun sr14 = 0x04;
4753*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
4754*4882a593Smuzhiyun if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4755*4882a593Smuzhiyun goto bail_out;
4756*4882a593Smuzhiyun
4757*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0x21);
4758*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0x34);
4759*4882a593Smuzhiyun if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4760*4882a593Smuzhiyun goto bail_out;
4761*4882a593Smuzhiyun
4762*4882a593Smuzhiyun channelab = 1;
4763*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0xa1);
4764*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0x40);
4765*4882a593Smuzhiyun sr14 = 0x00;
4766*4882a593Smuzhiyun if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4767*4882a593Smuzhiyun goto bail_out;
4768*4882a593Smuzhiyun
4769*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0x21);
4770*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0x30);
4771*4882a593Smuzhiyun } else {
4772*4882a593Smuzhiyun channelab = 3;
4773*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0xa1);
4774*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0x4c);
4775*4882a593Smuzhiyun sr14 = 0x0c;
4776*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
4777*4882a593Smuzhiyun if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4778*4882a593Smuzhiyun goto bail_out;
4779*4882a593Smuzhiyun
4780*4882a593Smuzhiyun channelab = 2;
4781*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0x48);
4782*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
4783*4882a593Smuzhiyun sr14 = 0x08;
4784*4882a593Smuzhiyun if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4785*4882a593Smuzhiyun goto bail_out;
4786*4882a593Smuzhiyun
4787*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0x21);
4788*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0x3c);
4789*4882a593Smuzhiyun sr14 = 0x0c;
4790*4882a593Smuzhiyun
4791*4882a593Smuzhiyun if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4792*4882a593Smuzhiyun channelab = 3;
4793*4882a593Smuzhiyun } else {
4794*4882a593Smuzhiyun channelab = 2;
4795*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0x38);
4796*4882a593Smuzhiyun sr14 = 0x08;
4797*4882a593Smuzhiyun }
4798*4882a593Smuzhiyun }
4799*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
4800*4882a593Smuzhiyun
4801*4882a593Smuzhiyun } else { /* DDR */
4802*4882a593Smuzhiyun
4803*4882a593Smuzhiyun buswidth = 64;
4804*4882a593Smuzhiyun if(ivideo->revision_id == 2) {
4805*4882a593Smuzhiyun channelab = 1;
4806*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0xa1);
4807*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0x52);
4808*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
4809*4882a593Smuzhiyun sr14 = 0x02;
4810*4882a593Smuzhiyun if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4811*4882a593Smuzhiyun goto bail_out;
4812*4882a593Smuzhiyun
4813*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0x21);
4814*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0x42);
4815*4882a593Smuzhiyun } else {
4816*4882a593Smuzhiyun channelab = 2;
4817*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0xa1);
4818*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0x5a);
4819*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
4820*4882a593Smuzhiyun sr14 = 0x0a;
4821*4882a593Smuzhiyun if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4822*4882a593Smuzhiyun goto bail_out;
4823*4882a593Smuzhiyun
4824*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, 0x21);
4825*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, 0x4a);
4826*4882a593Smuzhiyun }
4827*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
4828*4882a593Smuzhiyun
4829*4882a593Smuzhiyun }
4830*4882a593Smuzhiyun }
4831*4882a593Smuzhiyun
4832*4882a593Smuzhiyun bail_out:
4833*4882a593Smuzhiyun SiS_SetRegANDOR(SISSR, 0x14, 0xf0, sr14);
4834*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
4835*4882a593Smuzhiyun
4836*4882a593Smuzhiyun j = (ivideo->chip == XGI_20) ? 5 : 9;
4837*4882a593Smuzhiyun k = (ivideo->chip == XGI_20) ? 12 : 4;
4838*4882a593Smuzhiyun status = -EIO;
4839*4882a593Smuzhiyun
4840*4882a593Smuzhiyun for(i = 0; i < k; i++) {
4841*4882a593Smuzhiyun
4842*4882a593Smuzhiyun reg = (ivideo->chip == XGI_20) ?
4843*4882a593Smuzhiyun dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4844*4882a593Smuzhiyun SiS_SetRegANDOR(SISSR, 0x13, 0x80, reg);
4845*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 50);
4846*4882a593Smuzhiyun
4847*4882a593Smuzhiyun ranksize = (ivideo->chip == XGI_20) ?
4848*4882a593Smuzhiyun dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4849*4882a593Smuzhiyun
4850*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x13);
4851*4882a593Smuzhiyun if(reg & 0x80) ranksize <<= 1;
4852*4882a593Smuzhiyun
4853*4882a593Smuzhiyun if(ivideo->chip == XGI_20) {
4854*4882a593Smuzhiyun if(buswidth == 16) ranksize <<= 1;
4855*4882a593Smuzhiyun else if(buswidth == 32) ranksize <<= 2;
4856*4882a593Smuzhiyun } else {
4857*4882a593Smuzhiyun if(buswidth == 64) ranksize <<= 1;
4858*4882a593Smuzhiyun }
4859*4882a593Smuzhiyun
4860*4882a593Smuzhiyun reg = 0;
4861*4882a593Smuzhiyun l = channelab;
4862*4882a593Smuzhiyun if(l == 3) l = 4;
4863*4882a593Smuzhiyun if((ranksize * l) <= 256) {
4864*4882a593Smuzhiyun while((ranksize >>= 1)) reg += 0x10;
4865*4882a593Smuzhiyun }
4866*4882a593Smuzhiyun
4867*4882a593Smuzhiyun if(!reg) continue;
4868*4882a593Smuzhiyun
4869*4882a593Smuzhiyun SiS_SetRegANDOR(SISSR, 0x14, 0x0f, (reg & 0xf0));
4870*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
4871*4882a593Smuzhiyun
4872*4882a593Smuzhiyun if (sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize)) {
4873*4882a593Smuzhiyun status = 0;
4874*4882a593Smuzhiyun break;
4875*4882a593Smuzhiyun }
4876*4882a593Smuzhiyun }
4877*4882a593Smuzhiyun
4878*4882a593Smuzhiyun iounmap(ivideo->video_vbase);
4879*4882a593Smuzhiyun
4880*4882a593Smuzhiyun return status;
4881*4882a593Smuzhiyun }
4882*4882a593Smuzhiyun
sisfb_post_xgi_setclocks(struct sis_video_info * ivideo,u8 regb)4883*4882a593Smuzhiyun static void sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
4884*4882a593Smuzhiyun {
4885*4882a593Smuzhiyun u8 v1, v2, v3;
4886*4882a593Smuzhiyun int index;
4887*4882a593Smuzhiyun static const u8 cs90[8 * 3] = {
4888*4882a593Smuzhiyun 0x16, 0x01, 0x01,
4889*4882a593Smuzhiyun 0x3e, 0x03, 0x01,
4890*4882a593Smuzhiyun 0x7c, 0x08, 0x01,
4891*4882a593Smuzhiyun 0x79, 0x06, 0x01,
4892*4882a593Smuzhiyun 0x29, 0x01, 0x81,
4893*4882a593Smuzhiyun 0x5c, 0x23, 0x01,
4894*4882a593Smuzhiyun 0x5c, 0x23, 0x01,
4895*4882a593Smuzhiyun 0x5c, 0x23, 0x01
4896*4882a593Smuzhiyun };
4897*4882a593Smuzhiyun static const u8 csb8[8 * 3] = {
4898*4882a593Smuzhiyun 0x5c, 0x23, 0x01,
4899*4882a593Smuzhiyun 0x29, 0x01, 0x01,
4900*4882a593Smuzhiyun 0x7c, 0x08, 0x01,
4901*4882a593Smuzhiyun 0x79, 0x06, 0x01,
4902*4882a593Smuzhiyun 0x29, 0x01, 0x81,
4903*4882a593Smuzhiyun 0x5c, 0x23, 0x01,
4904*4882a593Smuzhiyun 0x5c, 0x23, 0x01,
4905*4882a593Smuzhiyun 0x5c, 0x23, 0x01
4906*4882a593Smuzhiyun };
4907*4882a593Smuzhiyun
4908*4882a593Smuzhiyun regb = 0; /* ! */
4909*4882a593Smuzhiyun
4910*4882a593Smuzhiyun index = regb * 3;
4911*4882a593Smuzhiyun v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
4912*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
4913*4882a593Smuzhiyun v1 = ivideo->bios_abase[0x90 + index];
4914*4882a593Smuzhiyun v2 = ivideo->bios_abase[0x90 + index + 1];
4915*4882a593Smuzhiyun v3 = ivideo->bios_abase[0x90 + index + 2];
4916*4882a593Smuzhiyun }
4917*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x28, v1);
4918*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x29, v2);
4919*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x2a, v3);
4920*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 0x43);
4921*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 0x43);
4922*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 0x43);
4923*4882a593Smuzhiyun index = regb * 3;
4924*4882a593Smuzhiyun v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
4925*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
4926*4882a593Smuzhiyun v1 = ivideo->bios_abase[0xb8 + index];
4927*4882a593Smuzhiyun v2 = ivideo->bios_abase[0xb8 + index + 1];
4928*4882a593Smuzhiyun v3 = ivideo->bios_abase[0xb8 + index + 2];
4929*4882a593Smuzhiyun }
4930*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x2e, v1);
4931*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x2f, v2);
4932*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x30, v3);
4933*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 0x43);
4934*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 0x43);
4935*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 0x43);
4936*4882a593Smuzhiyun }
4937*4882a593Smuzhiyun
sisfb_post_xgi_ddr2_mrs_default(struct sis_video_info * ivideo,u8 regb)4938*4882a593Smuzhiyun static void sisfb_post_xgi_ddr2_mrs_default(struct sis_video_info *ivideo,
4939*4882a593Smuzhiyun u8 regb)
4940*4882a593Smuzhiyun {
4941*4882a593Smuzhiyun unsigned char *bios = ivideo->bios_abase;
4942*4882a593Smuzhiyun u8 v1;
4943*4882a593Smuzhiyun
4944*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x28, 0x64);
4945*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x29, 0x63);
4946*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 15);
4947*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x18, 0x00);
4948*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x19, 0x20);
4949*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x00);
4950*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x80);
4951*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x18, 0xc5);
4952*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x19, 0x23);
4953*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x00);
4954*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x80);
4955*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
4956*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x97, 0x11);
4957*4882a593Smuzhiyun sisfb_post_xgi_setclocks(ivideo, regb);
4958*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 0x46);
4959*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x18, 0xc5);
4960*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x19, 0x23);
4961*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x00);
4962*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x80);
4963*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
4964*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x1b, 0x04);
4965*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
4966*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x1b, 0x00);
4967*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
4968*4882a593Smuzhiyun v1 = 0x31;
4969*4882a593Smuzhiyun if (ivideo->haveXGIROM) {
4970*4882a593Smuzhiyun v1 = bios[0xf0];
4971*4882a593Smuzhiyun }
4972*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x18, v1);
4973*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x19, 0x06);
4974*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x04);
4975*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x84);
4976*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
4977*4882a593Smuzhiyun }
4978*4882a593Smuzhiyun
sisfb_post_xgi_ddr2_mrs_xg21(struct sis_video_info * ivideo)4979*4882a593Smuzhiyun static void sisfb_post_xgi_ddr2_mrs_xg21(struct sis_video_info *ivideo)
4980*4882a593Smuzhiyun {
4981*4882a593Smuzhiyun sisfb_post_xgi_setclocks(ivideo, 1);
4982*4882a593Smuzhiyun
4983*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x97, 0x11);
4984*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 0x46);
4985*4882a593Smuzhiyun
4986*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS2 */
4987*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x19, 0x80);
4988*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x05);
4989*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x85);
4990*4882a593Smuzhiyun
4991*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS3 */
4992*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x19, 0xc0);
4993*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x05);
4994*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x85);
4995*4882a593Smuzhiyun
4996*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS1 */
4997*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x19, 0x40);
4998*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x05);
4999*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x85);
5000*4882a593Smuzhiyun
5001*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x18, 0x42); /* MRS1 */
5002*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x19, 0x02);
5003*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x05);
5004*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x85);
5005*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
5006*4882a593Smuzhiyun
5007*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x1b, 0x04);
5008*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
5009*4882a593Smuzhiyun
5010*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x1b, 0x00);
5011*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
5012*4882a593Smuzhiyun
5013*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x18, 0x42); /* MRS1 */
5014*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x19, 0x00);
5015*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x05);
5016*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x85);
5017*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 1);
5018*4882a593Smuzhiyun }
5019*4882a593Smuzhiyun
sisfb_post_xgi_ddr2(struct sis_video_info * ivideo,u8 regb)5020*4882a593Smuzhiyun static void sisfb_post_xgi_ddr2(struct sis_video_info *ivideo, u8 regb)
5021*4882a593Smuzhiyun {
5022*4882a593Smuzhiyun unsigned char *bios = ivideo->bios_abase;
5023*4882a593Smuzhiyun static const u8 cs158[8] = {
5024*4882a593Smuzhiyun 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5025*4882a593Smuzhiyun };
5026*4882a593Smuzhiyun static const u8 cs160[8] = {
5027*4882a593Smuzhiyun 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5028*4882a593Smuzhiyun };
5029*4882a593Smuzhiyun static const u8 cs168[8] = {
5030*4882a593Smuzhiyun 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5031*4882a593Smuzhiyun };
5032*4882a593Smuzhiyun u8 reg;
5033*4882a593Smuzhiyun u8 v1;
5034*4882a593Smuzhiyun u8 v2;
5035*4882a593Smuzhiyun u8 v3;
5036*4882a593Smuzhiyun
5037*4882a593Smuzhiyun SiS_SetReg(SISCR, 0xb0, 0x80); /* DDR2 dual frequency mode */
5038*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x82, 0x77);
5039*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x86, 0x00);
5040*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x86);
5041*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x86, 0x88);
5042*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x86);
5043*4882a593Smuzhiyun v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5044*4882a593Smuzhiyun if (ivideo->haveXGIROM) {
5045*4882a593Smuzhiyun v1 = bios[regb + 0x168];
5046*4882a593Smuzhiyun v2 = bios[regb + 0x160];
5047*4882a593Smuzhiyun v3 = bios[regb + 0x158];
5048*4882a593Smuzhiyun }
5049*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x86, v1);
5050*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x82, 0x77);
5051*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x85, 0x00);
5052*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x85);
5053*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x85, 0x88);
5054*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x85);
5055*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x85, v2);
5056*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x82, v3);
5057*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x98, 0x01);
5058*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x9a, 0x02);
5059*4882a593Smuzhiyun if (sisfb_xgi_is21(ivideo))
5060*4882a593Smuzhiyun sisfb_post_xgi_ddr2_mrs_xg21(ivideo);
5061*4882a593Smuzhiyun else
5062*4882a593Smuzhiyun sisfb_post_xgi_ddr2_mrs_default(ivideo, regb);
5063*4882a593Smuzhiyun }
5064*4882a593Smuzhiyun
sisfb_post_xgi_ramtype(struct sis_video_info * ivideo)5065*4882a593Smuzhiyun static u8 sisfb_post_xgi_ramtype(struct sis_video_info *ivideo)
5066*4882a593Smuzhiyun {
5067*4882a593Smuzhiyun unsigned char *bios = ivideo->bios_abase;
5068*4882a593Smuzhiyun u8 ramtype;
5069*4882a593Smuzhiyun u8 reg;
5070*4882a593Smuzhiyun u8 v1;
5071*4882a593Smuzhiyun
5072*4882a593Smuzhiyun ramtype = 0x00; v1 = 0x10;
5073*4882a593Smuzhiyun if (ivideo->haveXGIROM) {
5074*4882a593Smuzhiyun ramtype = bios[0x62];
5075*4882a593Smuzhiyun v1 = bios[0x1d2];
5076*4882a593Smuzhiyun }
5077*4882a593Smuzhiyun if (!(ramtype & 0x80)) {
5078*4882a593Smuzhiyun if (sisfb_xgi_is21(ivideo)) {
5079*4882a593Smuzhiyun SiS_SetRegAND(SISCR, 0xb4, 0xfd); /* GPIO control */
5080*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0x4a, 0x80); /* GPIOH EN */
5081*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x48);
5082*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0xb4, 0x02);
5083*4882a593Smuzhiyun ramtype = reg & 0x01; /* GPIOH */
5084*4882a593Smuzhiyun } else if (ivideo->chip == XGI_20) {
5085*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x97, v1);
5086*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x97);
5087*4882a593Smuzhiyun if (reg & 0x10) {
5088*4882a593Smuzhiyun ramtype = (reg & 0x01) << 1;
5089*4882a593Smuzhiyun }
5090*4882a593Smuzhiyun } else {
5091*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x39);
5092*4882a593Smuzhiyun ramtype = reg & 0x02;
5093*4882a593Smuzhiyun if (!(ramtype)) {
5094*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x3a);
5095*4882a593Smuzhiyun ramtype = (reg >> 1) & 0x01;
5096*4882a593Smuzhiyun }
5097*4882a593Smuzhiyun }
5098*4882a593Smuzhiyun }
5099*4882a593Smuzhiyun ramtype &= 0x07;
5100*4882a593Smuzhiyun
5101*4882a593Smuzhiyun return ramtype;
5102*4882a593Smuzhiyun }
5103*4882a593Smuzhiyun
sisfb_post_xgi(struct pci_dev * pdev)5104*4882a593Smuzhiyun static int sisfb_post_xgi(struct pci_dev *pdev)
5105*4882a593Smuzhiyun {
5106*4882a593Smuzhiyun struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5107*4882a593Smuzhiyun unsigned char *bios = ivideo->bios_abase;
5108*4882a593Smuzhiyun struct pci_dev *mypdev = NULL;
5109*4882a593Smuzhiyun const u8 *ptr, *ptr2;
5110*4882a593Smuzhiyun u8 v1, v2, v3, v4, v5, reg, ramtype;
5111*4882a593Smuzhiyun u32 rega, regb, regd;
5112*4882a593Smuzhiyun int i, j, k, index;
5113*4882a593Smuzhiyun static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
5114*4882a593Smuzhiyun static const u8 cs76[2] = { 0xa3, 0xfb };
5115*4882a593Smuzhiyun static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
5116*4882a593Smuzhiyun static const u8 cs158[8] = {
5117*4882a593Smuzhiyun 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5118*4882a593Smuzhiyun };
5119*4882a593Smuzhiyun static const u8 cs160[8] = {
5120*4882a593Smuzhiyun 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5121*4882a593Smuzhiyun };
5122*4882a593Smuzhiyun static const u8 cs168[8] = {
5123*4882a593Smuzhiyun 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5124*4882a593Smuzhiyun };
5125*4882a593Smuzhiyun static const u8 cs128[3 * 8] = {
5126*4882a593Smuzhiyun 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
5127*4882a593Smuzhiyun 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5128*4882a593Smuzhiyun 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
5129*4882a593Smuzhiyun };
5130*4882a593Smuzhiyun static const u8 cs148[2 * 8] = {
5131*4882a593Smuzhiyun 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
5132*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5133*4882a593Smuzhiyun };
5134*4882a593Smuzhiyun static const u8 cs31a[8 * 4] = {
5135*4882a593Smuzhiyun 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
5136*4882a593Smuzhiyun 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
5137*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5138*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5139*4882a593Smuzhiyun };
5140*4882a593Smuzhiyun static const u8 cs33a[8 * 4] = {
5141*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5142*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5143*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5144*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5145*4882a593Smuzhiyun };
5146*4882a593Smuzhiyun static const u8 cs45a[8 * 2] = {
5147*4882a593Smuzhiyun 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5148*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5149*4882a593Smuzhiyun };
5150*4882a593Smuzhiyun static const u8 cs170[7 * 8] = {
5151*4882a593Smuzhiyun 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5152*4882a593Smuzhiyun 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5153*4882a593Smuzhiyun 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5154*4882a593Smuzhiyun 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5155*4882a593Smuzhiyun 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5156*4882a593Smuzhiyun 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5157*4882a593Smuzhiyun 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5158*4882a593Smuzhiyun };
5159*4882a593Smuzhiyun static const u8 cs1a8[3 * 8] = {
5160*4882a593Smuzhiyun 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5161*4882a593Smuzhiyun 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5162*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5163*4882a593Smuzhiyun };
5164*4882a593Smuzhiyun static const u8 cs100[2 * 8] = {
5165*4882a593Smuzhiyun 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5166*4882a593Smuzhiyun 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5167*4882a593Smuzhiyun };
5168*4882a593Smuzhiyun
5169*4882a593Smuzhiyun /* VGA enable */
5170*4882a593Smuzhiyun reg = SiS_GetRegByte(SISVGAENABLE) | 0x01;
5171*4882a593Smuzhiyun SiS_SetRegByte(SISVGAENABLE, reg);
5172*4882a593Smuzhiyun
5173*4882a593Smuzhiyun /* Misc */
5174*4882a593Smuzhiyun reg = SiS_GetRegByte(SISMISCR) | 0x01;
5175*4882a593Smuzhiyun SiS_SetRegByte(SISMISCW, reg);
5176*4882a593Smuzhiyun
5177*4882a593Smuzhiyun /* Unlock SR */
5178*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x05, 0x86);
5179*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x05);
5180*4882a593Smuzhiyun if(reg != 0xa1)
5181*4882a593Smuzhiyun return 0;
5182*4882a593Smuzhiyun
5183*4882a593Smuzhiyun /* Clear some regs */
5184*4882a593Smuzhiyun for(i = 0; i < 0x22; i++) {
5185*4882a593Smuzhiyun if(0x06 + i == 0x20) continue;
5186*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x06 + i, 0x00);
5187*4882a593Smuzhiyun }
5188*4882a593Smuzhiyun for(i = 0; i < 0x0b; i++) {
5189*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x31 + i, 0x00);
5190*4882a593Smuzhiyun }
5191*4882a593Smuzhiyun for(i = 0; i < 0x10; i++) {
5192*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x30 + i, 0x00);
5193*4882a593Smuzhiyun }
5194*4882a593Smuzhiyun
5195*4882a593Smuzhiyun ptr = cs78;
5196*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
5197*4882a593Smuzhiyun ptr = (const u8 *)&bios[0x78];
5198*4882a593Smuzhiyun }
5199*4882a593Smuzhiyun for(i = 0; i < 3; i++) {
5200*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x23 + i, ptr[i]);
5201*4882a593Smuzhiyun }
5202*4882a593Smuzhiyun
5203*4882a593Smuzhiyun ptr = cs76;
5204*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
5205*4882a593Smuzhiyun ptr = (const u8 *)&bios[0x76];
5206*4882a593Smuzhiyun }
5207*4882a593Smuzhiyun for(i = 0; i < 2; i++) {
5208*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x21 + i, ptr[i]);
5209*4882a593Smuzhiyun }
5210*4882a593Smuzhiyun
5211*4882a593Smuzhiyun v1 = 0x18; v2 = 0x00;
5212*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
5213*4882a593Smuzhiyun v1 = bios[0x74];
5214*4882a593Smuzhiyun v2 = bios[0x75];
5215*4882a593Smuzhiyun }
5216*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x07, v1);
5217*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x11, 0x0f);
5218*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x1f, v2);
5219*4882a593Smuzhiyun /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5220*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5221*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x27, 0x74);
5222*4882a593Smuzhiyun
5223*4882a593Smuzhiyun ptr = cs7b;
5224*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
5225*4882a593Smuzhiyun ptr = (const u8 *)&bios[0x7b];
5226*4882a593Smuzhiyun }
5227*4882a593Smuzhiyun for(i = 0; i < 3; i++) {
5228*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x31 + i, ptr[i]);
5229*4882a593Smuzhiyun }
5230*4882a593Smuzhiyun
5231*4882a593Smuzhiyun if(ivideo->chip == XGI_40) {
5232*4882a593Smuzhiyun if(ivideo->revision_id == 2) {
5233*4882a593Smuzhiyun SiS_SetRegANDOR(SISSR, 0x3b, 0x3f, 0xc0);
5234*4882a593Smuzhiyun }
5235*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x7d, 0xfe);
5236*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x7e, 0x0f);
5237*4882a593Smuzhiyun }
5238*4882a593Smuzhiyun if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5239*4882a593Smuzhiyun SiS_SetRegAND(SISCR, 0x58, 0xd7);
5240*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0xcb);
5241*4882a593Smuzhiyun if(reg & 0x20) {
5242*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5243*4882a593Smuzhiyun }
5244*4882a593Smuzhiyun }
5245*4882a593Smuzhiyun
5246*4882a593Smuzhiyun reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5247*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x38, 0x1f, reg);
5248*4882a593Smuzhiyun
5249*4882a593Smuzhiyun if(ivideo->chip == XGI_20) {
5250*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x36, 0x70);
5251*4882a593Smuzhiyun } else {
5252*4882a593Smuzhiyun SiS_SetReg(SISVID, 0x00, 0x86);
5253*4882a593Smuzhiyun SiS_SetReg(SISVID, 0x32, 0x00);
5254*4882a593Smuzhiyun SiS_SetReg(SISVID, 0x30, 0x00);
5255*4882a593Smuzhiyun SiS_SetReg(SISVID, 0x32, 0x01);
5256*4882a593Smuzhiyun SiS_SetReg(SISVID, 0x30, 0x00);
5257*4882a593Smuzhiyun SiS_SetRegAND(SISVID, 0x2f, 0xdf);
5258*4882a593Smuzhiyun SiS_SetRegAND(SISCAP, 0x00, 0x3f);
5259*4882a593Smuzhiyun
5260*4882a593Smuzhiyun SiS_SetReg(SISPART1, 0x2f, 0x01);
5261*4882a593Smuzhiyun SiS_SetReg(SISPART1, 0x00, 0x00);
5262*4882a593Smuzhiyun SiS_SetReg(SISPART1, 0x02, bios[0x7e]);
5263*4882a593Smuzhiyun SiS_SetReg(SISPART1, 0x2e, 0x08);
5264*4882a593Smuzhiyun SiS_SetRegAND(SISPART1, 0x35, 0x7f);
5265*4882a593Smuzhiyun SiS_SetRegAND(SISPART1, 0x50, 0xfe);
5266*4882a593Smuzhiyun
5267*4882a593Smuzhiyun reg = SiS_GetReg(SISPART4, 0x00);
5268*4882a593Smuzhiyun if(reg == 1 || reg == 2) {
5269*4882a593Smuzhiyun SiS_SetReg(SISPART2, 0x00, 0x1c);
5270*4882a593Smuzhiyun SiS_SetReg(SISPART4, 0x0d, bios[0x7f]);
5271*4882a593Smuzhiyun SiS_SetReg(SISPART4, 0x0e, bios[0x80]);
5272*4882a593Smuzhiyun SiS_SetReg(SISPART4, 0x10, bios[0x81]);
5273*4882a593Smuzhiyun SiS_SetRegAND(SISPART4, 0x0f, 0x3f);
5274*4882a593Smuzhiyun
5275*4882a593Smuzhiyun reg = SiS_GetReg(SISPART4, 0x01);
5276*4882a593Smuzhiyun if((reg & 0xf0) >= 0xb0) {
5277*4882a593Smuzhiyun reg = SiS_GetReg(SISPART4, 0x23);
5278*4882a593Smuzhiyun if(reg & 0x20) reg |= 0x40;
5279*4882a593Smuzhiyun SiS_SetReg(SISPART4, 0x23, reg);
5280*4882a593Smuzhiyun reg = (reg & 0x20) ? 0x02 : 0x00;
5281*4882a593Smuzhiyun SiS_SetRegANDOR(SISPART1, 0x1e, 0xfd, reg);
5282*4882a593Smuzhiyun }
5283*4882a593Smuzhiyun }
5284*4882a593Smuzhiyun
5285*4882a593Smuzhiyun v1 = bios[0x77];
5286*4882a593Smuzhiyun
5287*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x3b);
5288*4882a593Smuzhiyun if(reg & 0x02) {
5289*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x3a);
5290*4882a593Smuzhiyun v2 = (reg & 0x30) >> 3;
5291*4882a593Smuzhiyun if(!(v2 & 0x04)) v2 ^= 0x02;
5292*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x39);
5293*4882a593Smuzhiyun if(reg & 0x80) v2 |= 0x80;
5294*4882a593Smuzhiyun v2 |= 0x01;
5295*4882a593Smuzhiyun
5296*4882a593Smuzhiyun if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5297*4882a593Smuzhiyun pci_dev_put(mypdev);
5298*4882a593Smuzhiyun if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5299*4882a593Smuzhiyun v2 &= 0xf9;
5300*4882a593Smuzhiyun v2 |= 0x08;
5301*4882a593Smuzhiyun v1 &= 0xfe;
5302*4882a593Smuzhiyun } else {
5303*4882a593Smuzhiyun mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL);
5304*4882a593Smuzhiyun if(!mypdev)
5305*4882a593Smuzhiyun mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL);
5306*4882a593Smuzhiyun if(!mypdev)
5307*4882a593Smuzhiyun mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
5308*4882a593Smuzhiyun if(mypdev) {
5309*4882a593Smuzhiyun pci_read_config_dword(mypdev, 0x94, ®d);
5310*4882a593Smuzhiyun regd &= 0xfffffeff;
5311*4882a593Smuzhiyun pci_write_config_dword(mypdev, 0x94, regd);
5312*4882a593Smuzhiyun v1 &= 0xfe;
5313*4882a593Smuzhiyun pci_dev_put(mypdev);
5314*4882a593Smuzhiyun } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5315*4882a593Smuzhiyun v1 &= 0xfe;
5316*4882a593Smuzhiyun } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5317*4882a593Smuzhiyun sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5318*4882a593Smuzhiyun sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5319*4882a593Smuzhiyun sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5320*4882a593Smuzhiyun if((v2 & 0x06) == 4)
5321*4882a593Smuzhiyun v2 ^= 0x06;
5322*4882a593Smuzhiyun v2 |= 0x08;
5323*4882a593Smuzhiyun }
5324*4882a593Smuzhiyun }
5325*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x5f, 0xf0, v2);
5326*4882a593Smuzhiyun }
5327*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x22, v1);
5328*4882a593Smuzhiyun
5329*4882a593Smuzhiyun if(ivideo->revision_id == 2) {
5330*4882a593Smuzhiyun v1 = SiS_GetReg(SISSR, 0x3b);
5331*4882a593Smuzhiyun v2 = SiS_GetReg(SISSR, 0x3a);
5332*4882a593Smuzhiyun regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5333*4882a593Smuzhiyun if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5334*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x5f, 0xf1, 0x01);
5335*4882a593Smuzhiyun
5336*4882a593Smuzhiyun if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
5337*4882a593Smuzhiyun /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5338*4882a593Smuzhiyun * of nforce 2 ROM
5339*4882a593Smuzhiyun */
5340*4882a593Smuzhiyun if(0)
5341*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x5f, 0xf1, 0x01);
5342*4882a593Smuzhiyun pci_dev_put(mypdev);
5343*4882a593Smuzhiyun }
5344*4882a593Smuzhiyun }
5345*4882a593Smuzhiyun
5346*4882a593Smuzhiyun v1 = 0x30;
5347*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, 0x3b);
5348*4882a593Smuzhiyun v2 = SiS_GetReg(SISCR, 0x5f);
5349*4882a593Smuzhiyun if((!(reg & 0x02)) && (v2 & 0x0e))
5350*4882a593Smuzhiyun v1 |= 0x08;
5351*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x27, v1);
5352*4882a593Smuzhiyun
5353*4882a593Smuzhiyun if(bios[0x64] & 0x01) {
5354*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x5f, 0xf0, bios[0x64]);
5355*4882a593Smuzhiyun }
5356*4882a593Smuzhiyun
5357*4882a593Smuzhiyun v1 = bios[0x4f7];
5358*4882a593Smuzhiyun pci_read_config_dword(pdev, 0x50, ®d);
5359*4882a593Smuzhiyun regd = (regd >> 20) & 0x0f;
5360*4882a593Smuzhiyun if(regd == 1) {
5361*4882a593Smuzhiyun v1 &= 0xfc;
5362*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0x5f, 0x08);
5363*4882a593Smuzhiyun }
5364*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x48, v1);
5365*4882a593Smuzhiyun
5366*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5367*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5368*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5369*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5370*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5371*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x70, bios[0x4fc]);
5372*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5373*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x74, 0xd0);
5374*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5375*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5376*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5377*4882a593Smuzhiyun v1 = bios[0x501];
5378*4882a593Smuzhiyun if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
5379*4882a593Smuzhiyun v1 = 0xf0;
5380*4882a593Smuzhiyun pci_dev_put(mypdev);
5381*4882a593Smuzhiyun }
5382*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x77, v1);
5383*4882a593Smuzhiyun }
5384*4882a593Smuzhiyun
5385*4882a593Smuzhiyun /* RAM type:
5386*4882a593Smuzhiyun *
5387*4882a593Smuzhiyun * 0 == DDR1, 1 == DDR2, 2..7 == reserved?
5388*4882a593Smuzhiyun *
5389*4882a593Smuzhiyun * The code seems to written so that regb should equal ramtype,
5390*4882a593Smuzhiyun * however, so far it has been hardcoded to 0. Enable other values only
5391*4882a593Smuzhiyun * on XGI Z9, as it passes the POST, and add a warning for others.
5392*4882a593Smuzhiyun */
5393*4882a593Smuzhiyun ramtype = sisfb_post_xgi_ramtype(ivideo);
5394*4882a593Smuzhiyun if (!sisfb_xgi_is21(ivideo) && ramtype) {
5395*4882a593Smuzhiyun dev_warn(&pdev->dev,
5396*4882a593Smuzhiyun "RAM type something else than expected: %d\n",
5397*4882a593Smuzhiyun ramtype);
5398*4882a593Smuzhiyun regb = 0;
5399*4882a593Smuzhiyun } else {
5400*4882a593Smuzhiyun regb = ramtype;
5401*4882a593Smuzhiyun }
5402*4882a593Smuzhiyun
5403*4882a593Smuzhiyun v1 = 0xff;
5404*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
5405*4882a593Smuzhiyun v1 = bios[0x140 + regb];
5406*4882a593Smuzhiyun }
5407*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x6d, v1);
5408*4882a593Smuzhiyun
5409*4882a593Smuzhiyun ptr = cs128;
5410*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
5411*4882a593Smuzhiyun ptr = (const u8 *)&bios[0x128];
5412*4882a593Smuzhiyun }
5413*4882a593Smuzhiyun for(i = 0, j = 0; i < 3; i++, j += 8) {
5414*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x68 + i, ptr[j + regb]);
5415*4882a593Smuzhiyun }
5416*4882a593Smuzhiyun
5417*4882a593Smuzhiyun ptr = cs31a;
5418*4882a593Smuzhiyun ptr2 = cs33a;
5419*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
5420*4882a593Smuzhiyun index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5421*4882a593Smuzhiyun ptr = (const u8 *)&bios[index];
5422*4882a593Smuzhiyun ptr2 = (const u8 *)&bios[index + 0x20];
5423*4882a593Smuzhiyun }
5424*4882a593Smuzhiyun for(i = 0; i < 2; i++) {
5425*4882a593Smuzhiyun if(i == 0) {
5426*4882a593Smuzhiyun regd = le32_to_cpu(((u32 *)ptr)[regb]);
5427*4882a593Smuzhiyun rega = 0x6b;
5428*4882a593Smuzhiyun } else {
5429*4882a593Smuzhiyun regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5430*4882a593Smuzhiyun rega = 0x6e;
5431*4882a593Smuzhiyun }
5432*4882a593Smuzhiyun reg = 0x00;
5433*4882a593Smuzhiyun for(j = 0; j < 16; j++) {
5434*4882a593Smuzhiyun reg &= 0xf3;
5435*4882a593Smuzhiyun if(regd & 0x01) reg |= 0x04;
5436*4882a593Smuzhiyun if(regd & 0x02) reg |= 0x08;
5437*4882a593Smuzhiyun regd >>= 2;
5438*4882a593Smuzhiyun SiS_SetReg(SISCR, rega, reg);
5439*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, rega);
5440*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, rega);
5441*4882a593Smuzhiyun reg += 0x10;
5442*4882a593Smuzhiyun }
5443*4882a593Smuzhiyun }
5444*4882a593Smuzhiyun
5445*4882a593Smuzhiyun SiS_SetRegAND(SISCR, 0x6e, 0xfc);
5446*4882a593Smuzhiyun
5447*4882a593Smuzhiyun ptr = NULL;
5448*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
5449*4882a593Smuzhiyun index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5450*4882a593Smuzhiyun ptr = (const u8 *)&bios[index];
5451*4882a593Smuzhiyun }
5452*4882a593Smuzhiyun for(i = 0; i < 4; i++) {
5453*4882a593Smuzhiyun SiS_SetRegANDOR(SISCR, 0x6e, 0xfc, i);
5454*4882a593Smuzhiyun reg = 0x00;
5455*4882a593Smuzhiyun for(j = 0; j < 2; j++) {
5456*4882a593Smuzhiyun regd = 0;
5457*4882a593Smuzhiyun if(ptr) {
5458*4882a593Smuzhiyun regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5459*4882a593Smuzhiyun ptr += 4;
5460*4882a593Smuzhiyun }
5461*4882a593Smuzhiyun /* reg = 0x00; */
5462*4882a593Smuzhiyun for(k = 0; k < 16; k++) {
5463*4882a593Smuzhiyun reg &= 0xfc;
5464*4882a593Smuzhiyun if(regd & 0x01) reg |= 0x01;
5465*4882a593Smuzhiyun if(regd & 0x02) reg |= 0x02;
5466*4882a593Smuzhiyun regd >>= 2;
5467*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x6f, reg);
5468*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x6f);
5469*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x6f);
5470*4882a593Smuzhiyun reg += 0x08;
5471*4882a593Smuzhiyun }
5472*4882a593Smuzhiyun }
5473*4882a593Smuzhiyun }
5474*4882a593Smuzhiyun
5475*4882a593Smuzhiyun ptr = cs148;
5476*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
5477*4882a593Smuzhiyun ptr = (const u8 *)&bios[0x148];
5478*4882a593Smuzhiyun }
5479*4882a593Smuzhiyun for(i = 0, j = 0; i < 2; i++, j += 8) {
5480*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x80 + i, ptr[j + regb]);
5481*4882a593Smuzhiyun }
5482*4882a593Smuzhiyun
5483*4882a593Smuzhiyun SiS_SetRegAND(SISCR, 0x89, 0x8f);
5484*4882a593Smuzhiyun
5485*4882a593Smuzhiyun ptr = cs45a;
5486*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
5487*4882a593Smuzhiyun index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5488*4882a593Smuzhiyun ptr = (const u8 *)&bios[index];
5489*4882a593Smuzhiyun }
5490*4882a593Smuzhiyun regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5491*4882a593Smuzhiyun reg = 0x80;
5492*4882a593Smuzhiyun for(i = 0; i < 5; i++) {
5493*4882a593Smuzhiyun reg &= 0xfc;
5494*4882a593Smuzhiyun if(regd & 0x01) reg |= 0x01;
5495*4882a593Smuzhiyun if(regd & 0x02) reg |= 0x02;
5496*4882a593Smuzhiyun regd >>= 2;
5497*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x89, reg);
5498*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x89);
5499*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x89);
5500*4882a593Smuzhiyun reg += 0x10;
5501*4882a593Smuzhiyun }
5502*4882a593Smuzhiyun
5503*4882a593Smuzhiyun v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5504*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
5505*4882a593Smuzhiyun v1 = bios[0x118 + regb];
5506*4882a593Smuzhiyun v2 = bios[0xf8 + regb];
5507*4882a593Smuzhiyun v3 = bios[0x120 + regb];
5508*4882a593Smuzhiyun v4 = bios[0x1ca];
5509*4882a593Smuzhiyun }
5510*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x45, v1 & 0x0f);
5511*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x99, (v1 >> 4) & 0x07);
5512*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0x40, v1 & 0x80);
5513*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x41, v2);
5514*4882a593Smuzhiyun
5515*4882a593Smuzhiyun ptr = cs170;
5516*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
5517*4882a593Smuzhiyun ptr = (const u8 *)&bios[0x170];
5518*4882a593Smuzhiyun }
5519*4882a593Smuzhiyun for(i = 0, j = 0; i < 7; i++, j += 8) {
5520*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x90 + i, ptr[j + regb]);
5521*4882a593Smuzhiyun }
5522*4882a593Smuzhiyun
5523*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x59, v3);
5524*4882a593Smuzhiyun
5525*4882a593Smuzhiyun ptr = cs1a8;
5526*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
5527*4882a593Smuzhiyun ptr = (const u8 *)&bios[0x1a8];
5528*4882a593Smuzhiyun }
5529*4882a593Smuzhiyun for(i = 0, j = 0; i < 3; i++, j += 8) {
5530*4882a593Smuzhiyun SiS_SetReg(SISCR, 0xc3 + i, ptr[j + regb]);
5531*4882a593Smuzhiyun }
5532*4882a593Smuzhiyun
5533*4882a593Smuzhiyun ptr = cs100;
5534*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
5535*4882a593Smuzhiyun ptr = (const u8 *)&bios[0x100];
5536*4882a593Smuzhiyun }
5537*4882a593Smuzhiyun for(i = 0, j = 0; i < 2; i++, j += 8) {
5538*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x8a + i, ptr[j + regb]);
5539*4882a593Smuzhiyun }
5540*4882a593Smuzhiyun
5541*4882a593Smuzhiyun SiS_SetReg(SISCR, 0xcf, v4);
5542*4882a593Smuzhiyun
5543*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x83, 0x09);
5544*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x87, 0x00);
5545*4882a593Smuzhiyun
5546*4882a593Smuzhiyun if(ivideo->chip == XGI_40) {
5547*4882a593Smuzhiyun if( (ivideo->revision_id == 1) ||
5548*4882a593Smuzhiyun (ivideo->revision_id == 2) ) {
5549*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x8c, 0x87);
5550*4882a593Smuzhiyun }
5551*4882a593Smuzhiyun }
5552*4882a593Smuzhiyun
5553*4882a593Smuzhiyun if (regb == 1)
5554*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x17, 0x80); /* DDR2 */
5555*4882a593Smuzhiyun else
5556*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x17, 0x00); /* DDR1 */
5557*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x1a, 0x87);
5558*4882a593Smuzhiyun
5559*4882a593Smuzhiyun if(ivideo->chip == XGI_20) {
5560*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x15, 0x00);
5561*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x1c, 0x00);
5562*4882a593Smuzhiyun }
5563*4882a593Smuzhiyun
5564*4882a593Smuzhiyun switch(ramtype) {
5565*4882a593Smuzhiyun case 0:
5566*4882a593Smuzhiyun sisfb_post_xgi_setclocks(ivideo, regb);
5567*4882a593Smuzhiyun if((ivideo->chip == XGI_20) ||
5568*4882a593Smuzhiyun (ivideo->revision_id == 1) ||
5569*4882a593Smuzhiyun (ivideo->revision_id == 2)) {
5570*4882a593Smuzhiyun v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5571*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
5572*4882a593Smuzhiyun v1 = bios[regb + 0x158];
5573*4882a593Smuzhiyun v2 = bios[regb + 0x160];
5574*4882a593Smuzhiyun v3 = bios[regb + 0x168];
5575*4882a593Smuzhiyun }
5576*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x82, v1);
5577*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x85, v2);
5578*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x86, v3);
5579*4882a593Smuzhiyun } else {
5580*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x82, 0x88);
5581*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x86, 0x00);
5582*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x86);
5583*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x86, 0x88);
5584*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x86);
5585*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x86, bios[regb + 0x168]);
5586*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x82, 0x77);
5587*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x85, 0x00);
5588*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x85);
5589*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x85, 0x88);
5590*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x85);
5591*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x85, bios[regb + 0x160]);
5592*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x82, bios[regb + 0x158]);
5593*4882a593Smuzhiyun }
5594*4882a593Smuzhiyun if(ivideo->chip == XGI_40) {
5595*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x97, 0x00);
5596*4882a593Smuzhiyun }
5597*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x98, 0x01);
5598*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x9a, 0x02);
5599*4882a593Smuzhiyun
5600*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x18, 0x01);
5601*4882a593Smuzhiyun if((ivideo->chip == XGI_20) ||
5602*4882a593Smuzhiyun (ivideo->revision_id == 2)) {
5603*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x19, 0x40);
5604*4882a593Smuzhiyun } else {
5605*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x19, 0x20);
5606*4882a593Smuzhiyun }
5607*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x00);
5608*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x80);
5609*4882a593Smuzhiyun if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5610*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 0x43);
5611*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 0x43);
5612*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 0x43);
5613*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x18, 0x00);
5614*4882a593Smuzhiyun if((ivideo->chip == XGI_20) ||
5615*4882a593Smuzhiyun (ivideo->revision_id == 2)) {
5616*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x19, 0x40);
5617*4882a593Smuzhiyun } else {
5618*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x19, 0x20);
5619*4882a593Smuzhiyun }
5620*4882a593Smuzhiyun } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5621*4882a593Smuzhiyun /* SiS_SetReg(SISSR, 0x16, 0x0c); */ /* ? */
5622*4882a593Smuzhiyun }
5623*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x00);
5624*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x80);
5625*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 4);
5626*4882a593Smuzhiyun v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5627*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
5628*4882a593Smuzhiyun v1 = bios[0xf0];
5629*4882a593Smuzhiyun index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5630*4882a593Smuzhiyun v2 = bios[index];
5631*4882a593Smuzhiyun v3 = bios[index + 1];
5632*4882a593Smuzhiyun v4 = bios[index + 2];
5633*4882a593Smuzhiyun v5 = bios[index + 3];
5634*4882a593Smuzhiyun }
5635*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x18, v1);
5636*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5637*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, v2);
5638*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, v3);
5639*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 0x43);
5640*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x1b, 0x03);
5641*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 0x22);
5642*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x18, v1);
5643*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x19, 0x00);
5644*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, v4);
5645*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, v5);
5646*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x1b, 0x00);
5647*4882a593Smuzhiyun break;
5648*4882a593Smuzhiyun case 1:
5649*4882a593Smuzhiyun sisfb_post_xgi_ddr2(ivideo, regb);
5650*4882a593Smuzhiyun break;
5651*4882a593Smuzhiyun default:
5652*4882a593Smuzhiyun sisfb_post_xgi_setclocks(ivideo, regb);
5653*4882a593Smuzhiyun if((ivideo->chip == XGI_40) &&
5654*4882a593Smuzhiyun ((ivideo->revision_id == 1) ||
5655*4882a593Smuzhiyun (ivideo->revision_id == 2))) {
5656*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x82, bios[regb + 0x158]);
5657*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x85, bios[regb + 0x160]);
5658*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x86, bios[regb + 0x168]);
5659*4882a593Smuzhiyun } else {
5660*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x82, 0x88);
5661*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x86, 0x00);
5662*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x86);
5663*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x86, 0x88);
5664*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x82, 0x77);
5665*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x85, 0x00);
5666*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x85);
5667*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x85, 0x88);
5668*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x85);
5669*4882a593Smuzhiyun v1 = cs160[regb]; v2 = cs158[regb];
5670*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
5671*4882a593Smuzhiyun v1 = bios[regb + 0x160];
5672*4882a593Smuzhiyun v2 = bios[regb + 0x158];
5673*4882a593Smuzhiyun }
5674*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x85, v1);
5675*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x82, v2);
5676*4882a593Smuzhiyun }
5677*4882a593Smuzhiyun if(ivideo->chip == XGI_40) {
5678*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x97, 0x11);
5679*4882a593Smuzhiyun }
5680*4882a593Smuzhiyun if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5681*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x98, 0x01);
5682*4882a593Smuzhiyun } else {
5683*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x98, 0x03);
5684*4882a593Smuzhiyun }
5685*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x9a, 0x02);
5686*4882a593Smuzhiyun
5687*4882a593Smuzhiyun if(ivideo->chip == XGI_40) {
5688*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x18, 0x01);
5689*4882a593Smuzhiyun } else {
5690*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x18, 0x00);
5691*4882a593Smuzhiyun }
5692*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x19, 0x40);
5693*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x00);
5694*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x80);
5695*4882a593Smuzhiyun if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5696*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 0x43);
5697*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 0x43);
5698*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 0x43);
5699*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x18, 0x00);
5700*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x19, 0x40);
5701*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x00);
5702*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x80);
5703*4882a593Smuzhiyun }
5704*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 4);
5705*4882a593Smuzhiyun v1 = 0x31;
5706*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
5707*4882a593Smuzhiyun v1 = bios[0xf0];
5708*4882a593Smuzhiyun }
5709*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x18, v1);
5710*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x19, 0x01);
5711*4882a593Smuzhiyun if(ivideo->chip == XGI_40) {
5712*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, bios[0x53e]);
5713*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, bios[0x53f]);
5714*4882a593Smuzhiyun } else {
5715*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x05);
5716*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x85);
5717*4882a593Smuzhiyun }
5718*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 0x43);
5719*4882a593Smuzhiyun if(ivideo->chip == XGI_40) {
5720*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x1b, 0x01);
5721*4882a593Smuzhiyun } else {
5722*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x1b, 0x03);
5723*4882a593Smuzhiyun }
5724*4882a593Smuzhiyun sisfb_post_xgi_delay(ivideo, 0x22);
5725*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x18, v1);
5726*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x19, 0x00);
5727*4882a593Smuzhiyun if(ivideo->chip == XGI_40) {
5728*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, bios[0x540]);
5729*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, bios[0x541]);
5730*4882a593Smuzhiyun } else {
5731*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x05);
5732*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x16, 0x85);
5733*4882a593Smuzhiyun }
5734*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x1b, 0x00);
5735*4882a593Smuzhiyun }
5736*4882a593Smuzhiyun
5737*4882a593Smuzhiyun regb = 0; /* ! */
5738*4882a593Smuzhiyun v1 = 0x03;
5739*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
5740*4882a593Smuzhiyun v1 = bios[0x110 + regb];
5741*4882a593Smuzhiyun }
5742*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x1b, v1);
5743*4882a593Smuzhiyun
5744*4882a593Smuzhiyun /* RAM size */
5745*4882a593Smuzhiyun v1 = 0x00; v2 = 0x00;
5746*4882a593Smuzhiyun if(ivideo->haveXGIROM) {
5747*4882a593Smuzhiyun v1 = bios[0x62];
5748*4882a593Smuzhiyun v2 = bios[0x63];
5749*4882a593Smuzhiyun }
5750*4882a593Smuzhiyun regb = 0; /* ! */
5751*4882a593Smuzhiyun regd = 1 << regb;
5752*4882a593Smuzhiyun if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5753*4882a593Smuzhiyun
5754*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x13, bios[regb + 0xe0]);
5755*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5756*4882a593Smuzhiyun
5757*4882a593Smuzhiyun } else {
5758*4882a593Smuzhiyun int err;
5759*4882a593Smuzhiyun
5760*4882a593Smuzhiyun /* Set default mode, don't clear screen */
5761*4882a593Smuzhiyun ivideo->SiS_Pr.SiS_UseOEM = false;
5762*4882a593Smuzhiyun SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5763*4882a593Smuzhiyun SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
5764*4882a593Smuzhiyun ivideo->curFSTN = ivideo->curDSTN = 0;
5765*4882a593Smuzhiyun ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5766*4882a593Smuzhiyun SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5767*4882a593Smuzhiyun
5768*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x05, 0x86);
5769*4882a593Smuzhiyun
5770*4882a593Smuzhiyun /* Disable read-cache */
5771*4882a593Smuzhiyun SiS_SetRegAND(SISSR, 0x21, 0xdf);
5772*4882a593Smuzhiyun err = sisfb_post_xgi_ramsize(ivideo);
5773*4882a593Smuzhiyun /* Enable read-cache */
5774*4882a593Smuzhiyun SiS_SetRegOR(SISSR, 0x21, 0x20);
5775*4882a593Smuzhiyun
5776*4882a593Smuzhiyun if (err) {
5777*4882a593Smuzhiyun dev_err(&pdev->dev,
5778*4882a593Smuzhiyun "%s: RAM size detection failed: %d\n",
5779*4882a593Smuzhiyun __func__, err);
5780*4882a593Smuzhiyun return 0;
5781*4882a593Smuzhiyun }
5782*4882a593Smuzhiyun }
5783*4882a593Smuzhiyun
5784*4882a593Smuzhiyun #if 0
5785*4882a593Smuzhiyun printk(KERN_DEBUG "-----------------\n");
5786*4882a593Smuzhiyun for(i = 0; i < 0xff; i++) {
5787*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, i);
5788*4882a593Smuzhiyun printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5789*4882a593Smuzhiyun }
5790*4882a593Smuzhiyun for(i = 0; i < 0x40; i++) {
5791*4882a593Smuzhiyun reg = SiS_GetReg(SISSR, i);
5792*4882a593Smuzhiyun printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5793*4882a593Smuzhiyun }
5794*4882a593Smuzhiyun printk(KERN_DEBUG "-----------------\n");
5795*4882a593Smuzhiyun #endif
5796*4882a593Smuzhiyun
5797*4882a593Smuzhiyun /* Sense CRT1 */
5798*4882a593Smuzhiyun if(ivideo->chip == XGI_20) {
5799*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0x32, 0x20);
5800*4882a593Smuzhiyun } else {
5801*4882a593Smuzhiyun reg = SiS_GetReg(SISPART4, 0x00);
5802*4882a593Smuzhiyun if((reg == 1) || (reg == 2)) {
5803*4882a593Smuzhiyun sisfb_sense_crt1(ivideo);
5804*4882a593Smuzhiyun } else {
5805*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0x32, 0x20);
5806*4882a593Smuzhiyun }
5807*4882a593Smuzhiyun }
5808*4882a593Smuzhiyun
5809*4882a593Smuzhiyun /* Set default mode, don't clear screen */
5810*4882a593Smuzhiyun ivideo->SiS_Pr.SiS_UseOEM = false;
5811*4882a593Smuzhiyun SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5812*4882a593Smuzhiyun SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
5813*4882a593Smuzhiyun ivideo->curFSTN = ivideo->curDSTN = 0;
5814*4882a593Smuzhiyun SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5815*4882a593Smuzhiyun
5816*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x05, 0x86);
5817*4882a593Smuzhiyun
5818*4882a593Smuzhiyun /* Display off */
5819*4882a593Smuzhiyun SiS_SetRegOR(SISSR, 0x01, 0x20);
5820*4882a593Smuzhiyun
5821*4882a593Smuzhiyun /* Save mode number in CR34 */
5822*4882a593Smuzhiyun SiS_SetReg(SISCR, 0x34, 0x2e);
5823*4882a593Smuzhiyun
5824*4882a593Smuzhiyun /* Let everyone know what the current mode is */
5825*4882a593Smuzhiyun ivideo->modeprechange = 0x2e;
5826*4882a593Smuzhiyun
5827*4882a593Smuzhiyun if(ivideo->chip == XGI_40) {
5828*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0xca);
5829*4882a593Smuzhiyun v1 = SiS_GetReg(SISCR, 0xcc);
5830*4882a593Smuzhiyun if((reg & 0x10) && (!(v1 & 0x04))) {
5831*4882a593Smuzhiyun printk(KERN_ERR
5832*4882a593Smuzhiyun "sisfb: Please connect power to the card.\n");
5833*4882a593Smuzhiyun return 0;
5834*4882a593Smuzhiyun }
5835*4882a593Smuzhiyun }
5836*4882a593Smuzhiyun
5837*4882a593Smuzhiyun return 1;
5838*4882a593Smuzhiyun }
5839*4882a593Smuzhiyun #endif
5840*4882a593Smuzhiyun
sisfb_probe(struct pci_dev * pdev,const struct pci_device_id * ent)5841*4882a593Smuzhiyun static int sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5842*4882a593Smuzhiyun {
5843*4882a593Smuzhiyun struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5844*4882a593Smuzhiyun struct sis_video_info *ivideo = NULL;
5845*4882a593Smuzhiyun struct fb_info *sis_fb_info = NULL;
5846*4882a593Smuzhiyun u16 reg16;
5847*4882a593Smuzhiyun u8 reg;
5848*4882a593Smuzhiyun int i, ret;
5849*4882a593Smuzhiyun
5850*4882a593Smuzhiyun if(sisfb_off)
5851*4882a593Smuzhiyun return -ENXIO;
5852*4882a593Smuzhiyun
5853*4882a593Smuzhiyun sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
5854*4882a593Smuzhiyun if(!sis_fb_info)
5855*4882a593Smuzhiyun return -ENOMEM;
5856*4882a593Smuzhiyun
5857*4882a593Smuzhiyun ivideo = (struct sis_video_info *)sis_fb_info->par;
5858*4882a593Smuzhiyun ivideo->memyselfandi = sis_fb_info;
5859*4882a593Smuzhiyun
5860*4882a593Smuzhiyun ivideo->sisfb_id = SISFB_ID;
5861*4882a593Smuzhiyun
5862*4882a593Smuzhiyun if(card_list == NULL) {
5863*4882a593Smuzhiyun ivideo->cardnumber = 0;
5864*4882a593Smuzhiyun } else {
5865*4882a593Smuzhiyun struct sis_video_info *countvideo = card_list;
5866*4882a593Smuzhiyun ivideo->cardnumber = 1;
5867*4882a593Smuzhiyun while((countvideo = countvideo->next) != NULL)
5868*4882a593Smuzhiyun ivideo->cardnumber++;
5869*4882a593Smuzhiyun }
5870*4882a593Smuzhiyun
5871*4882a593Smuzhiyun strlcpy(ivideo->myid, chipinfo->chip_name, sizeof(ivideo->myid));
5872*4882a593Smuzhiyun
5873*4882a593Smuzhiyun ivideo->warncount = 0;
5874*4882a593Smuzhiyun ivideo->chip_id = pdev->device;
5875*4882a593Smuzhiyun ivideo->chip_vendor = pdev->vendor;
5876*4882a593Smuzhiyun ivideo->revision_id = pdev->revision;
5877*4882a593Smuzhiyun ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
5878*4882a593Smuzhiyun pci_read_config_word(pdev, PCI_COMMAND, ®16);
5879*4882a593Smuzhiyun ivideo->sisvga_enabled = reg16 & 0x01;
5880*4882a593Smuzhiyun ivideo->pcibus = pdev->bus->number;
5881*4882a593Smuzhiyun ivideo->pcislot = PCI_SLOT(pdev->devfn);
5882*4882a593Smuzhiyun ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5883*4882a593Smuzhiyun ivideo->subsysvendor = pdev->subsystem_vendor;
5884*4882a593Smuzhiyun ivideo->subsysdevice = pdev->subsystem_device;
5885*4882a593Smuzhiyun
5886*4882a593Smuzhiyun #ifndef MODULE
5887*4882a593Smuzhiyun if(sisfb_mode_idx == -1) {
5888*4882a593Smuzhiyun sisfb_get_vga_mode_from_kernel();
5889*4882a593Smuzhiyun }
5890*4882a593Smuzhiyun #endif
5891*4882a593Smuzhiyun
5892*4882a593Smuzhiyun ivideo->chip = chipinfo->chip;
5893*4882a593Smuzhiyun ivideo->chip_real_id = chipinfo->chip;
5894*4882a593Smuzhiyun ivideo->sisvga_engine = chipinfo->vgaengine;
5895*4882a593Smuzhiyun ivideo->hwcursor_size = chipinfo->hwcursor_size;
5896*4882a593Smuzhiyun ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5897*4882a593Smuzhiyun ivideo->mni = chipinfo->mni;
5898*4882a593Smuzhiyun
5899*4882a593Smuzhiyun ivideo->detectedpdc = 0xff;
5900*4882a593Smuzhiyun ivideo->detectedpdca = 0xff;
5901*4882a593Smuzhiyun ivideo->detectedlcda = 0xff;
5902*4882a593Smuzhiyun
5903*4882a593Smuzhiyun ivideo->sisfb_thismonitor.datavalid = false;
5904*4882a593Smuzhiyun
5905*4882a593Smuzhiyun ivideo->current_base = 0;
5906*4882a593Smuzhiyun
5907*4882a593Smuzhiyun ivideo->engineok = 0;
5908*4882a593Smuzhiyun
5909*4882a593Smuzhiyun ivideo->sisfb_was_boot_device = 0;
5910*4882a593Smuzhiyun
5911*4882a593Smuzhiyun if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5912*4882a593Smuzhiyun if(ivideo->sisvga_enabled)
5913*4882a593Smuzhiyun ivideo->sisfb_was_boot_device = 1;
5914*4882a593Smuzhiyun else {
5915*4882a593Smuzhiyun printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5916*4882a593Smuzhiyun "but marked as boot video device ???\n");
5917*4882a593Smuzhiyun printk(KERN_DEBUG "sisfb: I will not accept this "
5918*4882a593Smuzhiyun "as the primary VGA device\n");
5919*4882a593Smuzhiyun }
5920*4882a593Smuzhiyun }
5921*4882a593Smuzhiyun
5922*4882a593Smuzhiyun ivideo->sisfb_parm_mem = sisfb_parm_mem;
5923*4882a593Smuzhiyun ivideo->sisfb_accel = sisfb_accel;
5924*4882a593Smuzhiyun ivideo->sisfb_ypan = sisfb_ypan;
5925*4882a593Smuzhiyun ivideo->sisfb_max = sisfb_max;
5926*4882a593Smuzhiyun ivideo->sisfb_userom = sisfb_userom;
5927*4882a593Smuzhiyun ivideo->sisfb_useoem = sisfb_useoem;
5928*4882a593Smuzhiyun ivideo->sisfb_mode_idx = sisfb_mode_idx;
5929*4882a593Smuzhiyun ivideo->sisfb_parm_rate = sisfb_parm_rate;
5930*4882a593Smuzhiyun ivideo->sisfb_crt1off = sisfb_crt1off;
5931*4882a593Smuzhiyun ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5932*4882a593Smuzhiyun ivideo->sisfb_crt2type = sisfb_crt2type;
5933*4882a593Smuzhiyun ivideo->sisfb_crt2flags = sisfb_crt2flags;
5934*4882a593Smuzhiyun /* pdc(a), scalelcd, special timing, lvdshl handled below */
5935*4882a593Smuzhiyun ivideo->sisfb_dstn = sisfb_dstn;
5936*4882a593Smuzhiyun ivideo->sisfb_fstn = sisfb_fstn;
5937*4882a593Smuzhiyun ivideo->sisfb_tvplug = sisfb_tvplug;
5938*4882a593Smuzhiyun ivideo->sisfb_tvstd = sisfb_tvstd;
5939*4882a593Smuzhiyun ivideo->tvxpos = sisfb_tvxposoffset;
5940*4882a593Smuzhiyun ivideo->tvypos = sisfb_tvyposoffset;
5941*4882a593Smuzhiyun ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5942*4882a593Smuzhiyun ivideo->refresh_rate = 0;
5943*4882a593Smuzhiyun if(ivideo->sisfb_parm_rate != -1) {
5944*4882a593Smuzhiyun ivideo->refresh_rate = ivideo->sisfb_parm_rate;
5945*4882a593Smuzhiyun }
5946*4882a593Smuzhiyun
5947*4882a593Smuzhiyun ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5948*4882a593Smuzhiyun ivideo->SiS_Pr.CenterScreen = -1;
5949*4882a593Smuzhiyun ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5950*4882a593Smuzhiyun ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5951*4882a593Smuzhiyun
5952*4882a593Smuzhiyun ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
5953*4882a593Smuzhiyun ivideo->SiS_Pr.SiS_CHOverScan = -1;
5954*4882a593Smuzhiyun ivideo->SiS_Pr.SiS_ChSW = false;
5955*4882a593Smuzhiyun ivideo->SiS_Pr.SiS_UseLCDA = false;
5956*4882a593Smuzhiyun ivideo->SiS_Pr.HaveEMI = false;
5957*4882a593Smuzhiyun ivideo->SiS_Pr.HaveEMILCD = false;
5958*4882a593Smuzhiyun ivideo->SiS_Pr.OverruleEMI = false;
5959*4882a593Smuzhiyun ivideo->SiS_Pr.SiS_SensibleSR11 = false;
5960*4882a593Smuzhiyun ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5961*4882a593Smuzhiyun ivideo->SiS_Pr.PDC = -1;
5962*4882a593Smuzhiyun ivideo->SiS_Pr.PDCA = -1;
5963*4882a593Smuzhiyun ivideo->SiS_Pr.DDCPortMixup = false;
5964*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
5965*4882a593Smuzhiyun if(ivideo->chip >= SIS_330) {
5966*4882a593Smuzhiyun ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5967*4882a593Smuzhiyun if(ivideo->chip >= SIS_661) {
5968*4882a593Smuzhiyun ivideo->SiS_Pr.SiS_SensibleSR11 = true;
5969*4882a593Smuzhiyun }
5970*4882a593Smuzhiyun }
5971*4882a593Smuzhiyun #endif
5972*4882a593Smuzhiyun
5973*4882a593Smuzhiyun memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
5974*4882a593Smuzhiyun
5975*4882a593Smuzhiyun pci_set_drvdata(pdev, ivideo);
5976*4882a593Smuzhiyun
5977*4882a593Smuzhiyun /* Patch special cases */
5978*4882a593Smuzhiyun if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
5979*4882a593Smuzhiyun switch(ivideo->nbridge->device) {
5980*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_300
5981*4882a593Smuzhiyun case PCI_DEVICE_ID_SI_730:
5982*4882a593Smuzhiyun ivideo->chip = SIS_730;
5983*4882a593Smuzhiyun strcpy(ivideo->myid, "SiS 730");
5984*4882a593Smuzhiyun break;
5985*4882a593Smuzhiyun #endif
5986*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
5987*4882a593Smuzhiyun case PCI_DEVICE_ID_SI_651:
5988*4882a593Smuzhiyun /* ivideo->chip is ok */
5989*4882a593Smuzhiyun strcpy(ivideo->myid, "SiS 651");
5990*4882a593Smuzhiyun break;
5991*4882a593Smuzhiyun case PCI_DEVICE_ID_SI_740:
5992*4882a593Smuzhiyun ivideo->chip = SIS_740;
5993*4882a593Smuzhiyun strcpy(ivideo->myid, "SiS 740");
5994*4882a593Smuzhiyun break;
5995*4882a593Smuzhiyun case PCI_DEVICE_ID_SI_661:
5996*4882a593Smuzhiyun ivideo->chip = SIS_661;
5997*4882a593Smuzhiyun strcpy(ivideo->myid, "SiS 661");
5998*4882a593Smuzhiyun break;
5999*4882a593Smuzhiyun case PCI_DEVICE_ID_SI_741:
6000*4882a593Smuzhiyun ivideo->chip = SIS_741;
6001*4882a593Smuzhiyun strcpy(ivideo->myid, "SiS 741");
6002*4882a593Smuzhiyun break;
6003*4882a593Smuzhiyun case PCI_DEVICE_ID_SI_760:
6004*4882a593Smuzhiyun ivideo->chip = SIS_760;
6005*4882a593Smuzhiyun strcpy(ivideo->myid, "SiS 760");
6006*4882a593Smuzhiyun break;
6007*4882a593Smuzhiyun case PCI_DEVICE_ID_SI_761:
6008*4882a593Smuzhiyun ivideo->chip = SIS_761;
6009*4882a593Smuzhiyun strcpy(ivideo->myid, "SiS 761");
6010*4882a593Smuzhiyun break;
6011*4882a593Smuzhiyun #endif
6012*4882a593Smuzhiyun default:
6013*4882a593Smuzhiyun break;
6014*4882a593Smuzhiyun }
6015*4882a593Smuzhiyun }
6016*4882a593Smuzhiyun
6017*4882a593Smuzhiyun ivideo->SiS_Pr.ChipType = ivideo->chip;
6018*4882a593Smuzhiyun
6019*4882a593Smuzhiyun ivideo->SiS_Pr.ivideo = (void *)ivideo;
6020*4882a593Smuzhiyun
6021*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
6022*4882a593Smuzhiyun if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
6023*4882a593Smuzhiyun (ivideo->SiS_Pr.ChipType == SIS_315)) {
6024*4882a593Smuzhiyun ivideo->SiS_Pr.ChipType = SIS_315H;
6025*4882a593Smuzhiyun }
6026*4882a593Smuzhiyun #endif
6027*4882a593Smuzhiyun
6028*4882a593Smuzhiyun if(!ivideo->sisvga_enabled) {
6029*4882a593Smuzhiyun if(pci_enable_device(pdev)) {
6030*4882a593Smuzhiyun pci_dev_put(ivideo->nbridge);
6031*4882a593Smuzhiyun framebuffer_release(sis_fb_info);
6032*4882a593Smuzhiyun return -EIO;
6033*4882a593Smuzhiyun }
6034*4882a593Smuzhiyun }
6035*4882a593Smuzhiyun
6036*4882a593Smuzhiyun ivideo->video_base = pci_resource_start(pdev, 0);
6037*4882a593Smuzhiyun ivideo->video_size = pci_resource_len(pdev, 0);
6038*4882a593Smuzhiyun ivideo->mmio_base = pci_resource_start(pdev, 1);
6039*4882a593Smuzhiyun ivideo->mmio_size = pci_resource_len(pdev, 1);
6040*4882a593Smuzhiyun ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
6041*4882a593Smuzhiyun ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
6042*4882a593Smuzhiyun
6043*4882a593Smuzhiyun SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
6044*4882a593Smuzhiyun
6045*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_300
6046*4882a593Smuzhiyun /* Find PCI systems for Chrontel/GPIO communication setup */
6047*4882a593Smuzhiyun if(ivideo->chip == SIS_630) {
6048*4882a593Smuzhiyun i = 0;
6049*4882a593Smuzhiyun do {
6050*4882a593Smuzhiyun if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
6051*4882a593Smuzhiyun mychswtable[i].subsysCard == ivideo->subsysdevice) {
6052*4882a593Smuzhiyun ivideo->SiS_Pr.SiS_ChSW = true;
6053*4882a593Smuzhiyun printk(KERN_DEBUG "sisfb: Identified [%s %s] "
6054*4882a593Smuzhiyun "requiring Chrontel/GPIO setup\n",
6055*4882a593Smuzhiyun mychswtable[i].vendorName,
6056*4882a593Smuzhiyun mychswtable[i].cardName);
6057*4882a593Smuzhiyun ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
6058*4882a593Smuzhiyun break;
6059*4882a593Smuzhiyun }
6060*4882a593Smuzhiyun i++;
6061*4882a593Smuzhiyun } while(mychswtable[i].subsysVendor != 0);
6062*4882a593Smuzhiyun }
6063*4882a593Smuzhiyun #endif
6064*4882a593Smuzhiyun
6065*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
6066*4882a593Smuzhiyun if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
6067*4882a593Smuzhiyun ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
6068*4882a593Smuzhiyun }
6069*4882a593Smuzhiyun #endif
6070*4882a593Smuzhiyun
6071*4882a593Smuzhiyun SiS_SetReg(SISSR, 0x05, 0x86);
6072*4882a593Smuzhiyun
6073*4882a593Smuzhiyun if( (!ivideo->sisvga_enabled)
6074*4882a593Smuzhiyun #if !defined(__i386__) && !defined(__x86_64__)
6075*4882a593Smuzhiyun || (sisfb_resetcard)
6076*4882a593Smuzhiyun #endif
6077*4882a593Smuzhiyun ) {
6078*4882a593Smuzhiyun for(i = 0x30; i <= 0x3f; i++) {
6079*4882a593Smuzhiyun SiS_SetReg(SISCR, i, 0x00);
6080*4882a593Smuzhiyun }
6081*4882a593Smuzhiyun }
6082*4882a593Smuzhiyun
6083*4882a593Smuzhiyun /* Find out about current video mode */
6084*4882a593Smuzhiyun ivideo->modeprechange = 0x03;
6085*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x34);
6086*4882a593Smuzhiyun if(reg & 0x7f) {
6087*4882a593Smuzhiyun ivideo->modeprechange = reg & 0x7f;
6088*4882a593Smuzhiyun } else if(ivideo->sisvga_enabled) {
6089*4882a593Smuzhiyun #if defined(__i386__) || defined(__x86_64__)
6090*4882a593Smuzhiyun unsigned char __iomem *tt = ioremap(0x400, 0x100);
6091*4882a593Smuzhiyun if(tt) {
6092*4882a593Smuzhiyun ivideo->modeprechange = readb(tt + 0x49);
6093*4882a593Smuzhiyun iounmap(tt);
6094*4882a593Smuzhiyun }
6095*4882a593Smuzhiyun #endif
6096*4882a593Smuzhiyun }
6097*4882a593Smuzhiyun
6098*4882a593Smuzhiyun /* Search and copy ROM image */
6099*4882a593Smuzhiyun ivideo->bios_abase = NULL;
6100*4882a593Smuzhiyun ivideo->SiS_Pr.VirtualRomBase = NULL;
6101*4882a593Smuzhiyun ivideo->SiS_Pr.UseROM = false;
6102*4882a593Smuzhiyun ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
6103*4882a593Smuzhiyun if(ivideo->sisfb_userom) {
6104*4882a593Smuzhiyun ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6105*4882a593Smuzhiyun ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6106*4882a593Smuzhiyun ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
6107*4882a593Smuzhiyun printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6108*4882a593Smuzhiyun ivideo->SiS_Pr.UseROM ? "" : "not ");
6109*4882a593Smuzhiyun if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6110*4882a593Smuzhiyun ivideo->SiS_Pr.UseROM = false;
6111*4882a593Smuzhiyun ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
6112*4882a593Smuzhiyun if( (ivideo->revision_id == 2) &&
6113*4882a593Smuzhiyun (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6114*4882a593Smuzhiyun ivideo->SiS_Pr.DDCPortMixup = true;
6115*4882a593Smuzhiyun }
6116*4882a593Smuzhiyun }
6117*4882a593Smuzhiyun } else {
6118*4882a593Smuzhiyun printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6119*4882a593Smuzhiyun }
6120*4882a593Smuzhiyun
6121*4882a593Smuzhiyun /* Find systems for special custom timing */
6122*4882a593Smuzhiyun if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6123*4882a593Smuzhiyun sisfb_detect_custom_timing(ivideo);
6124*4882a593Smuzhiyun }
6125*4882a593Smuzhiyun
6126*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
6127*4882a593Smuzhiyun if (ivideo->chip == XGI_20) {
6128*4882a593Smuzhiyun /* Check if our Z7 chip is actually Z9 */
6129*4882a593Smuzhiyun SiS_SetRegOR(SISCR, 0x4a, 0x40); /* GPIOG EN */
6130*4882a593Smuzhiyun reg = SiS_GetReg(SISCR, 0x48);
6131*4882a593Smuzhiyun if (reg & 0x02) { /* GPIOG */
6132*4882a593Smuzhiyun ivideo->chip_real_id = XGI_21;
6133*4882a593Smuzhiyun dev_info(&pdev->dev, "Z9 detected\n");
6134*4882a593Smuzhiyun }
6135*4882a593Smuzhiyun }
6136*4882a593Smuzhiyun #endif
6137*4882a593Smuzhiyun
6138*4882a593Smuzhiyun /* POST card in case this has not been done by the BIOS */
6139*4882a593Smuzhiyun if( (!ivideo->sisvga_enabled)
6140*4882a593Smuzhiyun #if !defined(__i386__) && !defined(__x86_64__)
6141*4882a593Smuzhiyun || (sisfb_resetcard)
6142*4882a593Smuzhiyun #endif
6143*4882a593Smuzhiyun ) {
6144*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_300
6145*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_300_VGA) {
6146*4882a593Smuzhiyun if(ivideo->chip == SIS_300) {
6147*4882a593Smuzhiyun sisfb_post_sis300(pdev);
6148*4882a593Smuzhiyun ivideo->sisfb_can_post = 1;
6149*4882a593Smuzhiyun }
6150*4882a593Smuzhiyun }
6151*4882a593Smuzhiyun #endif
6152*4882a593Smuzhiyun
6153*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
6154*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_315_VGA) {
6155*4882a593Smuzhiyun int result = 1;
6156*4882a593Smuzhiyun /* if((ivideo->chip == SIS_315H) ||
6157*4882a593Smuzhiyun (ivideo->chip == SIS_315) ||
6158*4882a593Smuzhiyun (ivideo->chip == SIS_315PRO) ||
6159*4882a593Smuzhiyun (ivideo->chip == SIS_330)) {
6160*4882a593Smuzhiyun sisfb_post_sis315330(pdev);
6161*4882a593Smuzhiyun } else */ if(ivideo->chip == XGI_20) {
6162*4882a593Smuzhiyun result = sisfb_post_xgi(pdev);
6163*4882a593Smuzhiyun ivideo->sisfb_can_post = 1;
6164*4882a593Smuzhiyun } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6165*4882a593Smuzhiyun result = sisfb_post_xgi(pdev);
6166*4882a593Smuzhiyun ivideo->sisfb_can_post = 1;
6167*4882a593Smuzhiyun } else {
6168*4882a593Smuzhiyun printk(KERN_INFO "sisfb: Card is not "
6169*4882a593Smuzhiyun "POSTed and sisfb can't do this either.\n");
6170*4882a593Smuzhiyun }
6171*4882a593Smuzhiyun if(!result) {
6172*4882a593Smuzhiyun printk(KERN_ERR "sisfb: Failed to POST card\n");
6173*4882a593Smuzhiyun ret = -ENODEV;
6174*4882a593Smuzhiyun goto error_3;
6175*4882a593Smuzhiyun }
6176*4882a593Smuzhiyun }
6177*4882a593Smuzhiyun #endif
6178*4882a593Smuzhiyun }
6179*4882a593Smuzhiyun
6180*4882a593Smuzhiyun ivideo->sisfb_card_posted = 1;
6181*4882a593Smuzhiyun
6182*4882a593Smuzhiyun /* Find out about RAM size */
6183*4882a593Smuzhiyun if(sisfb_get_dram_size(ivideo)) {
6184*4882a593Smuzhiyun printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6185*4882a593Smuzhiyun ret = -ENODEV;
6186*4882a593Smuzhiyun goto error_3;
6187*4882a593Smuzhiyun }
6188*4882a593Smuzhiyun
6189*4882a593Smuzhiyun
6190*4882a593Smuzhiyun /* Enable PCI addressing and MMIO */
6191*4882a593Smuzhiyun if((ivideo->sisfb_mode_idx < 0) ||
6192*4882a593Smuzhiyun ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6193*4882a593Smuzhiyun /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6194*4882a593Smuzhiyun SiS_SetRegOR(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6195*4882a593Smuzhiyun /* Enable 2D accelerator engine */
6196*4882a593Smuzhiyun SiS_SetRegOR(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
6197*4882a593Smuzhiyun }
6198*4882a593Smuzhiyun
6199*4882a593Smuzhiyun if(sisfb_pdc != 0xff) {
6200*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_300_VGA)
6201*4882a593Smuzhiyun sisfb_pdc &= 0x3c;
6202*4882a593Smuzhiyun else
6203*4882a593Smuzhiyun sisfb_pdc &= 0x1f;
6204*4882a593Smuzhiyun ivideo->SiS_Pr.PDC = sisfb_pdc;
6205*4882a593Smuzhiyun }
6206*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
6207*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_315_VGA) {
6208*4882a593Smuzhiyun if(sisfb_pdca != 0xff)
6209*4882a593Smuzhiyun ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
6210*4882a593Smuzhiyun }
6211*4882a593Smuzhiyun #endif
6212*4882a593Smuzhiyun
6213*4882a593Smuzhiyun if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
6214*4882a593Smuzhiyun printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6215*4882a593Smuzhiyun (int)(ivideo->video_size >> 20));
6216*4882a593Smuzhiyun printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
6217*4882a593Smuzhiyun ret = -ENODEV;
6218*4882a593Smuzhiyun goto error_3;
6219*4882a593Smuzhiyun }
6220*4882a593Smuzhiyun
6221*4882a593Smuzhiyun if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6222*4882a593Smuzhiyun printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
6223*4882a593Smuzhiyun ret = -ENODEV;
6224*4882a593Smuzhiyun goto error_2;
6225*4882a593Smuzhiyun }
6226*4882a593Smuzhiyun
6227*4882a593Smuzhiyun ivideo->video_vbase = ioremap_wc(ivideo->video_base, ivideo->video_size);
6228*4882a593Smuzhiyun ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
6229*4882a593Smuzhiyun if(!ivideo->video_vbase) {
6230*4882a593Smuzhiyun printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6231*4882a593Smuzhiyun ret = -ENODEV;
6232*4882a593Smuzhiyun goto error_1;
6233*4882a593Smuzhiyun }
6234*4882a593Smuzhiyun
6235*4882a593Smuzhiyun ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6236*4882a593Smuzhiyun if(!ivideo->mmio_vbase) {
6237*4882a593Smuzhiyun printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6238*4882a593Smuzhiyun ret = -ENODEV;
6239*4882a593Smuzhiyun error_0: iounmap(ivideo->video_vbase);
6240*4882a593Smuzhiyun error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6241*4882a593Smuzhiyun error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6242*4882a593Smuzhiyun error_3: vfree(ivideo->bios_abase);
6243*4882a593Smuzhiyun pci_dev_put(ivideo->lpcdev);
6244*4882a593Smuzhiyun pci_dev_put(ivideo->nbridge);
6245*4882a593Smuzhiyun if(!ivideo->sisvga_enabled)
6246*4882a593Smuzhiyun pci_disable_device(pdev);
6247*4882a593Smuzhiyun framebuffer_release(sis_fb_info);
6248*4882a593Smuzhiyun return ret;
6249*4882a593Smuzhiyun }
6250*4882a593Smuzhiyun
6251*4882a593Smuzhiyun printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6252*4882a593Smuzhiyun ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6253*4882a593Smuzhiyun
6254*4882a593Smuzhiyun if(ivideo->video_offset) {
6255*4882a593Smuzhiyun printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6256*4882a593Smuzhiyun ivideo->video_offset / 1024);
6257*4882a593Smuzhiyun }
6258*4882a593Smuzhiyun
6259*4882a593Smuzhiyun printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
6260*4882a593Smuzhiyun ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
6261*4882a593Smuzhiyun
6262*4882a593Smuzhiyun
6263*4882a593Smuzhiyun /* Determine the size of the command queue */
6264*4882a593Smuzhiyun if(ivideo->sisvga_engine == SIS_300_VGA) {
6265*4882a593Smuzhiyun ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6266*4882a593Smuzhiyun } else {
6267*4882a593Smuzhiyun if(ivideo->chip == XGI_20) {
6268*4882a593Smuzhiyun ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6269*4882a593Smuzhiyun } else {
6270*4882a593Smuzhiyun ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6271*4882a593Smuzhiyun }
6272*4882a593Smuzhiyun }
6273*4882a593Smuzhiyun
6274*4882a593Smuzhiyun /* Engines are no longer initialized here; this is
6275*4882a593Smuzhiyun * now done after the first mode-switch (if the
6276*4882a593Smuzhiyun * submitted var has its acceleration flags set).
6277*4882a593Smuzhiyun */
6278*4882a593Smuzhiyun
6279*4882a593Smuzhiyun /* Calculate the base of the (unused) hw cursor */
6280*4882a593Smuzhiyun ivideo->hwcursor_vbase = ivideo->video_vbase
6281*4882a593Smuzhiyun + ivideo->video_size
6282*4882a593Smuzhiyun - ivideo->cmdQueueSize
6283*4882a593Smuzhiyun - ivideo->hwcursor_size;
6284*4882a593Smuzhiyun ivideo->caps |= HW_CURSOR_CAP;
6285*4882a593Smuzhiyun
6286*4882a593Smuzhiyun /* Initialize offscreen memory manager */
6287*4882a593Smuzhiyun if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6288*4882a593Smuzhiyun printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6289*4882a593Smuzhiyun }
6290*4882a593Smuzhiyun
6291*4882a593Smuzhiyun /* Used for clearing the screen only, therefore respect our mem limit */
6292*4882a593Smuzhiyun ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6293*4882a593Smuzhiyun ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
6294*4882a593Smuzhiyun
6295*4882a593Smuzhiyun ivideo->vbflags = 0;
6296*4882a593Smuzhiyun ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6297*4882a593Smuzhiyun ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6298*4882a593Smuzhiyun ivideo->defmodeidx = DEFAULT_MODE;
6299*4882a593Smuzhiyun
6300*4882a593Smuzhiyun ivideo->newrom = 0;
6301*4882a593Smuzhiyun if(ivideo->chip < XGI_20) {
6302*4882a593Smuzhiyun if(ivideo->bios_abase) {
6303*4882a593Smuzhiyun ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6304*4882a593Smuzhiyun }
6305*4882a593Smuzhiyun }
6306*4882a593Smuzhiyun
6307*4882a593Smuzhiyun if((ivideo->sisfb_mode_idx < 0) ||
6308*4882a593Smuzhiyun ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6309*4882a593Smuzhiyun
6310*4882a593Smuzhiyun sisfb_sense_crt1(ivideo);
6311*4882a593Smuzhiyun
6312*4882a593Smuzhiyun sisfb_get_VB_type(ivideo);
6313*4882a593Smuzhiyun
6314*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6315*4882a593Smuzhiyun sisfb_detect_VB_connect(ivideo);
6316*4882a593Smuzhiyun }
6317*4882a593Smuzhiyun
6318*4882a593Smuzhiyun ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6319*4882a593Smuzhiyun
6320*4882a593Smuzhiyun /* Decide on which CRT2 device to use */
6321*4882a593Smuzhiyun if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6322*4882a593Smuzhiyun if(ivideo->sisfb_crt2type != -1) {
6323*4882a593Smuzhiyun if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6324*4882a593Smuzhiyun (ivideo->vbflags & CRT2_LCD)) {
6325*4882a593Smuzhiyun ivideo->currentvbflags |= CRT2_LCD;
6326*4882a593Smuzhiyun } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6327*4882a593Smuzhiyun ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6328*4882a593Smuzhiyun }
6329*4882a593Smuzhiyun } else {
6330*4882a593Smuzhiyun /* Chrontel 700x TV detection often unreliable, therefore
6331*4882a593Smuzhiyun * use a different default order on such machines
6332*4882a593Smuzhiyun */
6333*4882a593Smuzhiyun if((ivideo->sisvga_engine == SIS_300_VGA) &&
6334*4882a593Smuzhiyun (ivideo->vbflags2 & VB2_CHRONTEL)) {
6335*4882a593Smuzhiyun if(ivideo->vbflags & CRT2_LCD)
6336*4882a593Smuzhiyun ivideo->currentvbflags |= CRT2_LCD;
6337*4882a593Smuzhiyun else if(ivideo->vbflags & CRT2_TV)
6338*4882a593Smuzhiyun ivideo->currentvbflags |= CRT2_TV;
6339*4882a593Smuzhiyun else if(ivideo->vbflags & CRT2_VGA)
6340*4882a593Smuzhiyun ivideo->currentvbflags |= CRT2_VGA;
6341*4882a593Smuzhiyun } else {
6342*4882a593Smuzhiyun if(ivideo->vbflags & CRT2_TV)
6343*4882a593Smuzhiyun ivideo->currentvbflags |= CRT2_TV;
6344*4882a593Smuzhiyun else if(ivideo->vbflags & CRT2_LCD)
6345*4882a593Smuzhiyun ivideo->currentvbflags |= CRT2_LCD;
6346*4882a593Smuzhiyun else if(ivideo->vbflags & CRT2_VGA)
6347*4882a593Smuzhiyun ivideo->currentvbflags |= CRT2_VGA;
6348*4882a593Smuzhiyun }
6349*4882a593Smuzhiyun }
6350*4882a593Smuzhiyun }
6351*4882a593Smuzhiyun
6352*4882a593Smuzhiyun if(ivideo->vbflags & CRT2_LCD) {
6353*4882a593Smuzhiyun sisfb_detect_lcd_type(ivideo);
6354*4882a593Smuzhiyun }
6355*4882a593Smuzhiyun
6356*4882a593Smuzhiyun sisfb_save_pdc_emi(ivideo);
6357*4882a593Smuzhiyun
6358*4882a593Smuzhiyun if(!ivideo->sisfb_crt1off) {
6359*4882a593Smuzhiyun sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
6360*4882a593Smuzhiyun } else {
6361*4882a593Smuzhiyun if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6362*4882a593Smuzhiyun (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6363*4882a593Smuzhiyun sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6364*4882a593Smuzhiyun }
6365*4882a593Smuzhiyun }
6366*4882a593Smuzhiyun
6367*4882a593Smuzhiyun if(ivideo->sisfb_mode_idx >= 0) {
6368*4882a593Smuzhiyun int bu = ivideo->sisfb_mode_idx;
6369*4882a593Smuzhiyun ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6370*4882a593Smuzhiyun ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6371*4882a593Smuzhiyun if(bu != ivideo->sisfb_mode_idx) {
6372*4882a593Smuzhiyun printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6373*4882a593Smuzhiyun sisbios_mode[bu].xres,
6374*4882a593Smuzhiyun sisbios_mode[bu].yres,
6375*4882a593Smuzhiyun sisbios_mode[bu].bpp);
6376*4882a593Smuzhiyun }
6377*4882a593Smuzhiyun }
6378*4882a593Smuzhiyun
6379*4882a593Smuzhiyun if(ivideo->sisfb_mode_idx < 0) {
6380*4882a593Smuzhiyun switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6381*4882a593Smuzhiyun case CRT2_LCD:
6382*4882a593Smuzhiyun ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6383*4882a593Smuzhiyun break;
6384*4882a593Smuzhiyun case CRT2_TV:
6385*4882a593Smuzhiyun ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6386*4882a593Smuzhiyun break;
6387*4882a593Smuzhiyun default:
6388*4882a593Smuzhiyun ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6389*4882a593Smuzhiyun break;
6390*4882a593Smuzhiyun }
6391*4882a593Smuzhiyun }
6392*4882a593Smuzhiyun
6393*4882a593Smuzhiyun ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6394*4882a593Smuzhiyun
6395*4882a593Smuzhiyun if(ivideo->refresh_rate != 0) {
6396*4882a593Smuzhiyun sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6397*4882a593Smuzhiyun ivideo->sisfb_mode_idx);
6398*4882a593Smuzhiyun }
6399*4882a593Smuzhiyun
6400*4882a593Smuzhiyun if(ivideo->rate_idx == 0) {
6401*4882a593Smuzhiyun ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6402*4882a593Smuzhiyun ivideo->refresh_rate = 60;
6403*4882a593Smuzhiyun }
6404*4882a593Smuzhiyun
6405*4882a593Smuzhiyun if(ivideo->sisfb_thismonitor.datavalid) {
6406*4882a593Smuzhiyun if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6407*4882a593Smuzhiyun ivideo->sisfb_mode_idx,
6408*4882a593Smuzhiyun ivideo->rate_idx,
6409*4882a593Smuzhiyun ivideo->refresh_rate)) {
6410*4882a593Smuzhiyun printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6411*4882a593Smuzhiyun "exceeds monitor specs!\n");
6412*4882a593Smuzhiyun }
6413*4882a593Smuzhiyun }
6414*4882a593Smuzhiyun
6415*4882a593Smuzhiyun ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6416*4882a593Smuzhiyun ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6417*4882a593Smuzhiyun ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6418*4882a593Smuzhiyun
6419*4882a593Smuzhiyun sisfb_set_vparms(ivideo);
6420*4882a593Smuzhiyun
6421*4882a593Smuzhiyun printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
6422*4882a593Smuzhiyun ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6423*4882a593Smuzhiyun ivideo->refresh_rate);
6424*4882a593Smuzhiyun
6425*4882a593Smuzhiyun /* Set up the default var according to chosen default display mode */
6426*4882a593Smuzhiyun ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6427*4882a593Smuzhiyun ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6428*4882a593Smuzhiyun ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6429*4882a593Smuzhiyun
6430*4882a593Smuzhiyun sisfb_bpp_to_var(ivideo, &ivideo->default_var);
6431*4882a593Smuzhiyun
6432*4882a593Smuzhiyun ivideo->default_var.pixclock = (u32) (1000000000 /
6433*4882a593Smuzhiyun sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6434*4882a593Smuzhiyun
6435*4882a593Smuzhiyun if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6436*4882a593Smuzhiyun ivideo->rate_idx, &ivideo->default_var)) {
6437*4882a593Smuzhiyun if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6438*4882a593Smuzhiyun ivideo->default_var.pixclock <<= 1;
6439*4882a593Smuzhiyun }
6440*4882a593Smuzhiyun }
6441*4882a593Smuzhiyun
6442*4882a593Smuzhiyun if(ivideo->sisfb_ypan) {
6443*4882a593Smuzhiyun /* Maximize regardless of sisfb_max at startup */
6444*4882a593Smuzhiyun ivideo->default_var.yres_virtual =
6445*4882a593Smuzhiyun sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6446*4882a593Smuzhiyun if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6447*4882a593Smuzhiyun ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6448*4882a593Smuzhiyun }
6449*4882a593Smuzhiyun }
6450*4882a593Smuzhiyun
6451*4882a593Smuzhiyun sisfb_calc_pitch(ivideo, &ivideo->default_var);
6452*4882a593Smuzhiyun
6453*4882a593Smuzhiyun ivideo->accel = 0;
6454*4882a593Smuzhiyun if(ivideo->sisfb_accel) {
6455*4882a593Smuzhiyun ivideo->accel = -1;
6456*4882a593Smuzhiyun #ifdef STUPID_ACCELF_TEXT_SHIT
6457*4882a593Smuzhiyun ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6458*4882a593Smuzhiyun #endif
6459*4882a593Smuzhiyun }
6460*4882a593Smuzhiyun sisfb_initaccel(ivideo);
6461*4882a593Smuzhiyun
6462*4882a593Smuzhiyun #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6463*4882a593Smuzhiyun sis_fb_info->flags = FBINFO_DEFAULT |
6464*4882a593Smuzhiyun FBINFO_HWACCEL_YPAN |
6465*4882a593Smuzhiyun FBINFO_HWACCEL_XPAN |
6466*4882a593Smuzhiyun FBINFO_HWACCEL_COPYAREA |
6467*4882a593Smuzhiyun FBINFO_HWACCEL_FILLRECT |
6468*4882a593Smuzhiyun ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6469*4882a593Smuzhiyun #else
6470*4882a593Smuzhiyun sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6471*4882a593Smuzhiyun #endif
6472*4882a593Smuzhiyun sis_fb_info->var = ivideo->default_var;
6473*4882a593Smuzhiyun sis_fb_info->fix = ivideo->sisfb_fix;
6474*4882a593Smuzhiyun sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
6475*4882a593Smuzhiyun sis_fb_info->fbops = &sisfb_ops;
6476*4882a593Smuzhiyun sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
6477*4882a593Smuzhiyun
6478*4882a593Smuzhiyun fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6479*4882a593Smuzhiyun
6480*4882a593Smuzhiyun printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
6481*4882a593Smuzhiyun
6482*4882a593Smuzhiyun ivideo->wc_cookie = arch_phys_wc_add(ivideo->video_base,
6483*4882a593Smuzhiyun ivideo->video_size);
6484*4882a593Smuzhiyun if(register_framebuffer(sis_fb_info) < 0) {
6485*4882a593Smuzhiyun printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
6486*4882a593Smuzhiyun ret = -EINVAL;
6487*4882a593Smuzhiyun iounmap(ivideo->mmio_vbase);
6488*4882a593Smuzhiyun goto error_0;
6489*4882a593Smuzhiyun }
6490*4882a593Smuzhiyun
6491*4882a593Smuzhiyun ivideo->registered = 1;
6492*4882a593Smuzhiyun
6493*4882a593Smuzhiyun /* Enlist us */
6494*4882a593Smuzhiyun ivideo->next = card_list;
6495*4882a593Smuzhiyun card_list = ivideo;
6496*4882a593Smuzhiyun
6497*4882a593Smuzhiyun printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
6498*4882a593Smuzhiyun ivideo->sisfb_accel ? "enabled" : "disabled",
6499*4882a593Smuzhiyun ivideo->sisfb_ypan ?
6500*4882a593Smuzhiyun (ivideo->sisfb_max ? "enabled (auto-max)" :
6501*4882a593Smuzhiyun "enabled (no auto-max)") :
6502*4882a593Smuzhiyun "disabled");
6503*4882a593Smuzhiyun
6504*4882a593Smuzhiyun
6505*4882a593Smuzhiyun fb_info(sis_fb_info, "%s frame buffer device version %d.%d.%d\n",
6506*4882a593Smuzhiyun ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6507*4882a593Smuzhiyun
6508*4882a593Smuzhiyun printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
6509*4882a593Smuzhiyun
6510*4882a593Smuzhiyun } /* if mode = "none" */
6511*4882a593Smuzhiyun
6512*4882a593Smuzhiyun return 0;
6513*4882a593Smuzhiyun }
6514*4882a593Smuzhiyun
6515*4882a593Smuzhiyun /*****************************************************/
6516*4882a593Smuzhiyun /* PCI DEVICE HANDLING */
6517*4882a593Smuzhiyun /*****************************************************/
6518*4882a593Smuzhiyun
sisfb_remove(struct pci_dev * pdev)6519*4882a593Smuzhiyun static void sisfb_remove(struct pci_dev *pdev)
6520*4882a593Smuzhiyun {
6521*4882a593Smuzhiyun struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6522*4882a593Smuzhiyun struct fb_info *sis_fb_info = ivideo->memyselfandi;
6523*4882a593Smuzhiyun int registered = ivideo->registered;
6524*4882a593Smuzhiyun int modechanged = ivideo->modechanged;
6525*4882a593Smuzhiyun
6526*4882a593Smuzhiyun /* Unmap */
6527*4882a593Smuzhiyun iounmap(ivideo->mmio_vbase);
6528*4882a593Smuzhiyun iounmap(ivideo->video_vbase);
6529*4882a593Smuzhiyun
6530*4882a593Smuzhiyun /* Release mem regions */
6531*4882a593Smuzhiyun release_mem_region(ivideo->video_base, ivideo->video_size);
6532*4882a593Smuzhiyun release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6533*4882a593Smuzhiyun
6534*4882a593Smuzhiyun vfree(ivideo->bios_abase);
6535*4882a593Smuzhiyun
6536*4882a593Smuzhiyun pci_dev_put(ivideo->lpcdev);
6537*4882a593Smuzhiyun
6538*4882a593Smuzhiyun pci_dev_put(ivideo->nbridge);
6539*4882a593Smuzhiyun
6540*4882a593Smuzhiyun arch_phys_wc_del(ivideo->wc_cookie);
6541*4882a593Smuzhiyun
6542*4882a593Smuzhiyun /* If device was disabled when starting, disable
6543*4882a593Smuzhiyun * it when quitting.
6544*4882a593Smuzhiyun */
6545*4882a593Smuzhiyun if(!ivideo->sisvga_enabled)
6546*4882a593Smuzhiyun pci_disable_device(pdev);
6547*4882a593Smuzhiyun
6548*4882a593Smuzhiyun /* Unregister the framebuffer */
6549*4882a593Smuzhiyun if(ivideo->registered) {
6550*4882a593Smuzhiyun unregister_framebuffer(sis_fb_info);
6551*4882a593Smuzhiyun framebuffer_release(sis_fb_info);
6552*4882a593Smuzhiyun }
6553*4882a593Smuzhiyun
6554*4882a593Smuzhiyun /* OK, our ivideo is gone for good from here. */
6555*4882a593Smuzhiyun
6556*4882a593Smuzhiyun /* TODO: Restore the initial mode
6557*4882a593Smuzhiyun * This sounds easy but is as good as impossible
6558*4882a593Smuzhiyun * on many machines with SiS chip and video bridge
6559*4882a593Smuzhiyun * since text modes are always set up differently
6560*4882a593Smuzhiyun * from machine to machine. Depends on the type
6561*4882a593Smuzhiyun * of integration between chipset and bridge.
6562*4882a593Smuzhiyun */
6563*4882a593Smuzhiyun if(registered && modechanged)
6564*4882a593Smuzhiyun printk(KERN_INFO
6565*4882a593Smuzhiyun "sisfb: Restoring of text mode not supported yet\n");
6566*4882a593Smuzhiyun };
6567*4882a593Smuzhiyun
6568*4882a593Smuzhiyun static struct pci_driver sisfb_driver = {
6569*4882a593Smuzhiyun .name = "sisfb",
6570*4882a593Smuzhiyun .id_table = sisfb_pci_table,
6571*4882a593Smuzhiyun .probe = sisfb_probe,
6572*4882a593Smuzhiyun .remove = sisfb_remove,
6573*4882a593Smuzhiyun };
6574*4882a593Smuzhiyun
sisfb_init(void)6575*4882a593Smuzhiyun static int __init sisfb_init(void)
6576*4882a593Smuzhiyun {
6577*4882a593Smuzhiyun #ifndef MODULE
6578*4882a593Smuzhiyun char *options = NULL;
6579*4882a593Smuzhiyun
6580*4882a593Smuzhiyun if(fb_get_options("sisfb", &options))
6581*4882a593Smuzhiyun return -ENODEV;
6582*4882a593Smuzhiyun
6583*4882a593Smuzhiyun sisfb_setup(options);
6584*4882a593Smuzhiyun #endif
6585*4882a593Smuzhiyun return pci_register_driver(&sisfb_driver);
6586*4882a593Smuzhiyun }
6587*4882a593Smuzhiyun
6588*4882a593Smuzhiyun #ifndef MODULE
6589*4882a593Smuzhiyun module_init(sisfb_init);
6590*4882a593Smuzhiyun #endif
6591*4882a593Smuzhiyun
6592*4882a593Smuzhiyun /*****************************************************/
6593*4882a593Smuzhiyun /* MODULE */
6594*4882a593Smuzhiyun /*****************************************************/
6595*4882a593Smuzhiyun
6596*4882a593Smuzhiyun #ifdef MODULE
6597*4882a593Smuzhiyun
6598*4882a593Smuzhiyun static char *mode = NULL;
6599*4882a593Smuzhiyun static int vesa = -1;
6600*4882a593Smuzhiyun static unsigned int rate = 0;
6601*4882a593Smuzhiyun static unsigned int crt1off = 1;
6602*4882a593Smuzhiyun static unsigned int mem = 0;
6603*4882a593Smuzhiyun static char *forcecrt2type = NULL;
6604*4882a593Smuzhiyun static int forcecrt1 = -1;
6605*4882a593Smuzhiyun static int pdc = -1;
6606*4882a593Smuzhiyun static int pdc1 = -1;
6607*4882a593Smuzhiyun static int noaccel = -1;
6608*4882a593Smuzhiyun static int noypan = -1;
6609*4882a593Smuzhiyun static int nomax = -1;
6610*4882a593Smuzhiyun static int userom = -1;
6611*4882a593Smuzhiyun static int useoem = -1;
6612*4882a593Smuzhiyun static char *tvstandard = NULL;
6613*4882a593Smuzhiyun static int nocrt2rate = 0;
6614*4882a593Smuzhiyun static int scalelcd = -1;
6615*4882a593Smuzhiyun static char *specialtiming = NULL;
6616*4882a593Smuzhiyun static int lvdshl = -1;
6617*4882a593Smuzhiyun static int tvxposoffset = 0, tvyposoffset = 0;
6618*4882a593Smuzhiyun #if !defined(__i386__) && !defined(__x86_64__)
6619*4882a593Smuzhiyun static int resetcard = 0;
6620*4882a593Smuzhiyun static int videoram = 0;
6621*4882a593Smuzhiyun #endif
6622*4882a593Smuzhiyun
sisfb_init_module(void)6623*4882a593Smuzhiyun static int __init sisfb_init_module(void)
6624*4882a593Smuzhiyun {
6625*4882a593Smuzhiyun sisfb_setdefaultparms();
6626*4882a593Smuzhiyun
6627*4882a593Smuzhiyun if(rate)
6628*4882a593Smuzhiyun sisfb_parm_rate = rate;
6629*4882a593Smuzhiyun
6630*4882a593Smuzhiyun if((scalelcd == 0) || (scalelcd == 1))
6631*4882a593Smuzhiyun sisfb_scalelcd = scalelcd ^ 1;
6632*4882a593Smuzhiyun
6633*4882a593Smuzhiyun /* Need to check crt2 type first for fstn/dstn */
6634*4882a593Smuzhiyun
6635*4882a593Smuzhiyun if(forcecrt2type)
6636*4882a593Smuzhiyun sisfb_search_crt2type(forcecrt2type);
6637*4882a593Smuzhiyun
6638*4882a593Smuzhiyun if(tvstandard)
6639*4882a593Smuzhiyun sisfb_search_tvstd(tvstandard);
6640*4882a593Smuzhiyun
6641*4882a593Smuzhiyun if(mode)
6642*4882a593Smuzhiyun sisfb_search_mode(mode, false);
6643*4882a593Smuzhiyun else if(vesa != -1)
6644*4882a593Smuzhiyun sisfb_search_vesamode(vesa, false);
6645*4882a593Smuzhiyun
6646*4882a593Smuzhiyun sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6647*4882a593Smuzhiyun
6648*4882a593Smuzhiyun sisfb_forcecrt1 = forcecrt1;
6649*4882a593Smuzhiyun if(forcecrt1 == 1)
6650*4882a593Smuzhiyun sisfb_crt1off = 0;
6651*4882a593Smuzhiyun else if(forcecrt1 == 0)
6652*4882a593Smuzhiyun sisfb_crt1off = 1;
6653*4882a593Smuzhiyun
6654*4882a593Smuzhiyun if(noaccel == 1)
6655*4882a593Smuzhiyun sisfb_accel = 0;
6656*4882a593Smuzhiyun else if(noaccel == 0)
6657*4882a593Smuzhiyun sisfb_accel = 1;
6658*4882a593Smuzhiyun
6659*4882a593Smuzhiyun if(noypan == 1)
6660*4882a593Smuzhiyun sisfb_ypan = 0;
6661*4882a593Smuzhiyun else if(noypan == 0)
6662*4882a593Smuzhiyun sisfb_ypan = 1;
6663*4882a593Smuzhiyun
6664*4882a593Smuzhiyun if(nomax == 1)
6665*4882a593Smuzhiyun sisfb_max = 0;
6666*4882a593Smuzhiyun else if(nomax == 0)
6667*4882a593Smuzhiyun sisfb_max = 1;
6668*4882a593Smuzhiyun
6669*4882a593Smuzhiyun if(mem)
6670*4882a593Smuzhiyun sisfb_parm_mem = mem;
6671*4882a593Smuzhiyun
6672*4882a593Smuzhiyun if(userom != -1)
6673*4882a593Smuzhiyun sisfb_userom = userom;
6674*4882a593Smuzhiyun
6675*4882a593Smuzhiyun if(useoem != -1)
6676*4882a593Smuzhiyun sisfb_useoem = useoem;
6677*4882a593Smuzhiyun
6678*4882a593Smuzhiyun if(pdc != -1)
6679*4882a593Smuzhiyun sisfb_pdc = (pdc & 0x7f);
6680*4882a593Smuzhiyun
6681*4882a593Smuzhiyun if(pdc1 != -1)
6682*4882a593Smuzhiyun sisfb_pdca = (pdc1 & 0x1f);
6683*4882a593Smuzhiyun
6684*4882a593Smuzhiyun sisfb_nocrt2rate = nocrt2rate;
6685*4882a593Smuzhiyun
6686*4882a593Smuzhiyun if(specialtiming)
6687*4882a593Smuzhiyun sisfb_search_specialtiming(specialtiming);
6688*4882a593Smuzhiyun
6689*4882a593Smuzhiyun if((lvdshl >= 0) && (lvdshl <= 3))
6690*4882a593Smuzhiyun sisfb_lvdshl = lvdshl;
6691*4882a593Smuzhiyun
6692*4882a593Smuzhiyun sisfb_tvxposoffset = tvxposoffset;
6693*4882a593Smuzhiyun sisfb_tvyposoffset = tvyposoffset;
6694*4882a593Smuzhiyun
6695*4882a593Smuzhiyun #if !defined(__i386__) && !defined(__x86_64__)
6696*4882a593Smuzhiyun sisfb_resetcard = (resetcard) ? 1 : 0;
6697*4882a593Smuzhiyun if(videoram)
6698*4882a593Smuzhiyun sisfb_videoram = videoram;
6699*4882a593Smuzhiyun #endif
6700*4882a593Smuzhiyun
6701*4882a593Smuzhiyun return sisfb_init();
6702*4882a593Smuzhiyun }
6703*4882a593Smuzhiyun
sisfb_remove_module(void)6704*4882a593Smuzhiyun static void __exit sisfb_remove_module(void)
6705*4882a593Smuzhiyun {
6706*4882a593Smuzhiyun pci_unregister_driver(&sisfb_driver);
6707*4882a593Smuzhiyun printk(KERN_DEBUG "sisfb: Module unloaded\n");
6708*4882a593Smuzhiyun }
6709*4882a593Smuzhiyun
6710*4882a593Smuzhiyun module_init(sisfb_init_module);
6711*4882a593Smuzhiyun module_exit(sisfb_remove_module);
6712*4882a593Smuzhiyun
6713*4882a593Smuzhiyun MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
6714*4882a593Smuzhiyun MODULE_LICENSE("GPL");
6715*4882a593Smuzhiyun MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6716*4882a593Smuzhiyun
6717*4882a593Smuzhiyun module_param(mem, int, 0);
6718*4882a593Smuzhiyun module_param(noaccel, int, 0);
6719*4882a593Smuzhiyun module_param(noypan, int, 0);
6720*4882a593Smuzhiyun module_param(nomax, int, 0);
6721*4882a593Smuzhiyun module_param(userom, int, 0);
6722*4882a593Smuzhiyun module_param(useoem, int, 0);
6723*4882a593Smuzhiyun module_param(mode, charp, 0);
6724*4882a593Smuzhiyun module_param(vesa, int, 0);
6725*4882a593Smuzhiyun module_param(rate, int, 0);
6726*4882a593Smuzhiyun module_param(forcecrt1, int, 0);
6727*4882a593Smuzhiyun module_param(forcecrt2type, charp, 0);
6728*4882a593Smuzhiyun module_param(scalelcd, int, 0);
6729*4882a593Smuzhiyun module_param(pdc, int, 0);
6730*4882a593Smuzhiyun module_param(pdc1, int, 0);
6731*4882a593Smuzhiyun module_param(specialtiming, charp, 0);
6732*4882a593Smuzhiyun module_param(lvdshl, int, 0);
6733*4882a593Smuzhiyun module_param(tvstandard, charp, 0);
6734*4882a593Smuzhiyun module_param(tvxposoffset, int, 0);
6735*4882a593Smuzhiyun module_param(tvyposoffset, int, 0);
6736*4882a593Smuzhiyun module_param(nocrt2rate, int, 0);
6737*4882a593Smuzhiyun #if !defined(__i386__) && !defined(__x86_64__)
6738*4882a593Smuzhiyun module_param(resetcard, int, 0);
6739*4882a593Smuzhiyun module_param(videoram, int, 0);
6740*4882a593Smuzhiyun #endif
6741*4882a593Smuzhiyun
6742*4882a593Smuzhiyun MODULE_PARM_DESC(mem,
6743*4882a593Smuzhiyun "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6744*4882a593Smuzhiyun "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6745*4882a593Smuzhiyun "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6746*4882a593Smuzhiyun "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6747*4882a593Smuzhiyun "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6748*4882a593Smuzhiyun "The value is to be specified without 'KB'.\n");
6749*4882a593Smuzhiyun
6750*4882a593Smuzhiyun MODULE_PARM_DESC(noaccel,
6751*4882a593Smuzhiyun "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
6752*4882a593Smuzhiyun "(default: 0)\n");
6753*4882a593Smuzhiyun
6754*4882a593Smuzhiyun MODULE_PARM_DESC(noypan,
6755*4882a593Smuzhiyun "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6756*4882a593Smuzhiyun "will be performed by redrawing the screen. (default: 0)\n");
6757*4882a593Smuzhiyun
6758*4882a593Smuzhiyun MODULE_PARM_DESC(nomax,
6759*4882a593Smuzhiyun "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
6760*4882a593Smuzhiyun "memory for the virtual screen in order to optimize scrolling performance. If\n"
6761*4882a593Smuzhiyun "this is set to anything other than 0, sisfb will not do this and thereby \n"
6762*4882a593Smuzhiyun "enable the user to positively specify a virtual Y size of the screen using\n"
6763*4882a593Smuzhiyun "fbset. (default: 0)\n");
6764*4882a593Smuzhiyun
6765*4882a593Smuzhiyun MODULE_PARM_DESC(mode,
6766*4882a593Smuzhiyun "\nSelects the desired default display mode in the format XxYxDepth,\n"
6767*4882a593Smuzhiyun "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
6768*4882a593Smuzhiyun "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
6769*4882a593Smuzhiyun "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
6770*4882a593Smuzhiyun
6771*4882a593Smuzhiyun MODULE_PARM_DESC(vesa,
6772*4882a593Smuzhiyun "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
6773*4882a593Smuzhiyun "0x117 (default: 0x0103)\n");
6774*4882a593Smuzhiyun
6775*4882a593Smuzhiyun MODULE_PARM_DESC(rate,
6776*4882a593Smuzhiyun "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
6777*4882a593Smuzhiyun "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
6778*4882a593Smuzhiyun "will be ignored (default: 60)\n");
6779*4882a593Smuzhiyun
6780*4882a593Smuzhiyun MODULE_PARM_DESC(forcecrt1,
6781*4882a593Smuzhiyun "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
6782*4882a593Smuzhiyun "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
6783*4882a593Smuzhiyun "0=CRT1 OFF) (default: [autodetected])\n");
6784*4882a593Smuzhiyun
6785*4882a593Smuzhiyun MODULE_PARM_DESC(forcecrt2type,
6786*4882a593Smuzhiyun "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
6787*4882a593Smuzhiyun "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
6788*4882a593Smuzhiyun "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
6789*4882a593Smuzhiyun "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
6790*4882a593Smuzhiyun "be used instead of TV to override the TV detection. Furthermore, on systems\n"
6791*4882a593Smuzhiyun "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
6792*4882a593Smuzhiyun "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
6793*4882a593Smuzhiyun "depends on the very hardware in use. (default: [autodetected])\n");
6794*4882a593Smuzhiyun
6795*4882a593Smuzhiyun MODULE_PARM_DESC(scalelcd,
6796*4882a593Smuzhiyun "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
6797*4882a593Smuzhiyun "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
6798*4882a593Smuzhiyun "show black bars around the image, TMDS panels will probably do the scaling\n"
6799*4882a593Smuzhiyun "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
6800*4882a593Smuzhiyun
6801*4882a593Smuzhiyun MODULE_PARM_DESC(pdc,
6802*4882a593Smuzhiyun "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
6803*4882a593Smuzhiyun "should detect this correctly in most cases; however, sometimes this is not\n"
6804*4882a593Smuzhiyun "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
6805*4882a593Smuzhiyun "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
6806*4882a593Smuzhiyun "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
6807*4882a593Smuzhiyun "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
6808*4882a593Smuzhiyun
6809*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_315
6810*4882a593Smuzhiyun MODULE_PARM_DESC(pdc1,
6811*4882a593Smuzhiyun "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
6812*4882a593Smuzhiyun "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
6813*4882a593Smuzhiyun "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
6814*4882a593Smuzhiyun "implemented yet.\n");
6815*4882a593Smuzhiyun #endif
6816*4882a593Smuzhiyun
6817*4882a593Smuzhiyun MODULE_PARM_DESC(specialtiming,
6818*4882a593Smuzhiyun "\nPlease refer to documentation for more information on this option.\n");
6819*4882a593Smuzhiyun
6820*4882a593Smuzhiyun MODULE_PARM_DESC(lvdshl,
6821*4882a593Smuzhiyun "\nPlease refer to documentation for more information on this option.\n");
6822*4882a593Smuzhiyun
6823*4882a593Smuzhiyun MODULE_PARM_DESC(tvstandard,
6824*4882a593Smuzhiyun "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
6825*4882a593Smuzhiyun "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
6826*4882a593Smuzhiyun
6827*4882a593Smuzhiyun MODULE_PARM_DESC(tvxposoffset,
6828*4882a593Smuzhiyun "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
6829*4882a593Smuzhiyun "Default: 0\n");
6830*4882a593Smuzhiyun
6831*4882a593Smuzhiyun MODULE_PARM_DESC(tvyposoffset,
6832*4882a593Smuzhiyun "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
6833*4882a593Smuzhiyun "Default: 0\n");
6834*4882a593Smuzhiyun
6835*4882a593Smuzhiyun MODULE_PARM_DESC(nocrt2rate,
6836*4882a593Smuzhiyun "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
6837*4882a593Smuzhiyun "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
6838*4882a593Smuzhiyun
6839*4882a593Smuzhiyun #if !defined(__i386__) && !defined(__x86_64__)
6840*4882a593Smuzhiyun #ifdef CONFIG_FB_SIS_300
6841*4882a593Smuzhiyun MODULE_PARM_DESC(resetcard,
6842*4882a593Smuzhiyun "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
6843*4882a593Smuzhiyun "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
6844*4882a593Smuzhiyun "currently). Default: 0\n");
6845*4882a593Smuzhiyun
6846*4882a593Smuzhiyun MODULE_PARM_DESC(videoram,
6847*4882a593Smuzhiyun "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
6848*4882a593Smuzhiyun "some non-x86 architectures where the memory auto detection fails. Only\n"
6849*4882a593Smuzhiyun "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
6850*4882a593Smuzhiyun #endif
6851*4882a593Smuzhiyun #endif
6852*4882a593Smuzhiyun
6853*4882a593Smuzhiyun #endif /* /MODULE */
6854*4882a593Smuzhiyun
6855*4882a593Smuzhiyun /* _GPL only for new symbols. */
6856*4882a593Smuzhiyun EXPORT_SYMBOL(sis_malloc);
6857*4882a593Smuzhiyun EXPORT_SYMBOL(sis_free);
6858*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(sis_malloc_new);
6859*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(sis_free_new);
6860*4882a593Smuzhiyun
6861*4882a593Smuzhiyun
6862*4882a593Smuzhiyun
6863