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