162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * SiS 300/540/630[S]/730[S],
462306a36Sopenharmony_ci * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX],
562306a36Sopenharmony_ci * XGI V3XT/V5/V8, Z7
662306a36Sopenharmony_ci * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Author:	Thomas Winischhofer <thomas@winischhofer.net>
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Author of (practically wiped) code base:
1362306a36Sopenharmony_ci *		SiS (www.sis.com)
1462306a36Sopenharmony_ci *		Copyright (C) 1999 Silicon Integrated Systems, Inc.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * See http://www.winischhofer.net/ for more information and updates
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver,
1962306a36Sopenharmony_ci * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include <linux/aperture.h>
2362306a36Sopenharmony_ci#include <linux/module.h>
2462306a36Sopenharmony_ci#include <linux/moduleparam.h>
2562306a36Sopenharmony_ci#include <linux/kernel.h>
2662306a36Sopenharmony_ci#include <linux/spinlock.h>
2762306a36Sopenharmony_ci#include <linux/errno.h>
2862306a36Sopenharmony_ci#include <linux/string.h>
2962306a36Sopenharmony_ci#include <linux/mm.h>
3062306a36Sopenharmony_ci#include <linux/screen_info.h>
3162306a36Sopenharmony_ci#include <linux/slab.h>
3262306a36Sopenharmony_ci#include <linux/fb.h>
3362306a36Sopenharmony_ci#include <linux/selection.h>
3462306a36Sopenharmony_ci#include <linux/ioport.h>
3562306a36Sopenharmony_ci#include <linux/init.h>
3662306a36Sopenharmony_ci#include <linux/pci.h>
3762306a36Sopenharmony_ci#include <linux/vmalloc.h>
3862306a36Sopenharmony_ci#include <linux/capability.h>
3962306a36Sopenharmony_ci#include <linux/fs.h>
4062306a36Sopenharmony_ci#include <linux/types.h>
4162306a36Sopenharmony_ci#include <linux/uaccess.h>
4262306a36Sopenharmony_ci#include <asm/io.h>
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#include "sis.h"
4562306a36Sopenharmony_ci#include "sis_main.h"
4662306a36Sopenharmony_ci#include "init301.h"
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#if !defined(CONFIG_FB_SIS_300) && !defined(CONFIG_FB_SIS_315)
4962306a36Sopenharmony_ci#warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set
5062306a36Sopenharmony_ci#warning sisfb will not work!
5162306a36Sopenharmony_ci#endif
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* ---------------------- Prototypes ------------------------- */
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/* Interface used by the world */
5662306a36Sopenharmony_ci#ifndef MODULE
5762306a36Sopenharmony_cistatic int sisfb_setup(char *options);
5862306a36Sopenharmony_ci#endif
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/* Interface to the low level console driver */
6162306a36Sopenharmony_cistatic int sisfb_init(void);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/* fbdev routines */
6462306a36Sopenharmony_cistatic int	sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
6562306a36Sopenharmony_ci				struct fb_info *info);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic int	sisfb_ioctl(struct fb_info *info, unsigned int cmd,
6862306a36Sopenharmony_ci			    unsigned long arg);
6962306a36Sopenharmony_cistatic int	sisfb_set_par(struct fb_info *info);
7062306a36Sopenharmony_cistatic int	sisfb_blank(int blank,
7162306a36Sopenharmony_ci				struct fb_info *info);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic void sisfb_handle_command(struct sis_video_info *ivideo,
7462306a36Sopenharmony_ci				 struct sisfb_cmd *sisfb_command);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic void	sisfb_search_mode(char *name, bool quiet);
7762306a36Sopenharmony_cistatic int	sisfb_validate_mode(struct sis_video_info *ivideo, int modeindex, u32 vbflags);
7862306a36Sopenharmony_cistatic u8	sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate,
7962306a36Sopenharmony_ci				int index);
8062306a36Sopenharmony_cistatic int	sisfb_setcolreg(unsigned regno, unsigned red, unsigned green,
8162306a36Sopenharmony_ci				unsigned blue, unsigned transp,
8262306a36Sopenharmony_ci				struct fb_info *fb_info);
8362306a36Sopenharmony_cistatic int	sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
8462306a36Sopenharmony_ci				struct fb_info *info);
8562306a36Sopenharmony_cistatic void	sisfb_pre_setmode(struct sis_video_info *ivideo);
8662306a36Sopenharmony_cistatic void	sisfb_post_setmode(struct sis_video_info *ivideo);
8762306a36Sopenharmony_cistatic bool	sisfb_CheckVBRetrace(struct sis_video_info *ivideo);
8862306a36Sopenharmony_cistatic bool	sisfbcheckvretracecrt2(struct sis_video_info *ivideo);
8962306a36Sopenharmony_cistatic bool	sisfbcheckvretracecrt1(struct sis_video_info *ivideo);
9062306a36Sopenharmony_cistatic bool	sisfb_bridgeisslave(struct sis_video_info *ivideo);
9162306a36Sopenharmony_cistatic void	sisfb_detect_VB_connect(struct sis_video_info *ivideo);
9262306a36Sopenharmony_cistatic void	sisfb_get_VB_type(struct sis_video_info *ivideo);
9362306a36Sopenharmony_cistatic void	sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val);
9462306a36Sopenharmony_cistatic void	sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/* Internal heap routines */
9762306a36Sopenharmony_cistatic int		sisfb_heap_init(struct sis_video_info *ivideo);
9862306a36Sopenharmony_cistatic struct SIS_OH *	sisfb_poh_new_node(struct SIS_HEAP *memheap);
9962306a36Sopenharmony_cistatic struct SIS_OH *	sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size);
10062306a36Sopenharmony_cistatic void		sisfb_delete_node(struct SIS_OH *poh);
10162306a36Sopenharmony_cistatic void		sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh);
10262306a36Sopenharmony_cistatic struct SIS_OH *	sisfb_poh_free(struct SIS_HEAP *memheap, u32 base);
10362306a36Sopenharmony_cistatic void		sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/* ------------------ Internal helper routines ----------------- */
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic void __init
10962306a36Sopenharmony_cisisfb_setdefaultparms(void)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	sisfb_off		= 0;
11262306a36Sopenharmony_ci	sisfb_parm_mem		= 0;
11362306a36Sopenharmony_ci	sisfb_accel		= -1;
11462306a36Sopenharmony_ci	sisfb_ypan		= -1;
11562306a36Sopenharmony_ci	sisfb_max		= -1;
11662306a36Sopenharmony_ci	sisfb_userom		= -1;
11762306a36Sopenharmony_ci	sisfb_useoem		= -1;
11862306a36Sopenharmony_ci	sisfb_mode_idx		= -1;
11962306a36Sopenharmony_ci	sisfb_parm_rate		= -1;
12062306a36Sopenharmony_ci	sisfb_crt1off		= 0;
12162306a36Sopenharmony_ci	sisfb_forcecrt1		= -1;
12262306a36Sopenharmony_ci	sisfb_crt2type		= -1;
12362306a36Sopenharmony_ci	sisfb_crt2flags		= 0;
12462306a36Sopenharmony_ci	sisfb_pdc		= 0xff;
12562306a36Sopenharmony_ci	sisfb_pdca		= 0xff;
12662306a36Sopenharmony_ci	sisfb_scalelcd		= -1;
12762306a36Sopenharmony_ci	sisfb_specialtiming 	= CUT_NONE;
12862306a36Sopenharmony_ci	sisfb_lvdshl		= -1;
12962306a36Sopenharmony_ci	sisfb_dstn		= 0;
13062306a36Sopenharmony_ci	sisfb_fstn		= 0;
13162306a36Sopenharmony_ci	sisfb_tvplug		= -1;
13262306a36Sopenharmony_ci	sisfb_tvstd		= -1;
13362306a36Sopenharmony_ci	sisfb_tvxposoffset	= 0;
13462306a36Sopenharmony_ci	sisfb_tvyposoffset	= 0;
13562306a36Sopenharmony_ci	sisfb_nocrt2rate	= 0;
13662306a36Sopenharmony_ci#if !defined(__i386__) && !defined(__x86_64__)
13762306a36Sopenharmony_ci	sisfb_resetcard		= 0;
13862306a36Sopenharmony_ci	sisfb_videoram		= 0;
13962306a36Sopenharmony_ci#endif
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/* ------------- Parameter parsing -------------- */
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic void sisfb_search_vesamode(unsigned int vesamode, bool quiet)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	int i = 0, j = 0;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	/* We don't know the hardware specs yet and there is no ivideo */
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if(vesamode == 0) {
15162306a36Sopenharmony_ci		if(!quiet)
15262306a36Sopenharmony_ci			printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci		sisfb_mode_idx = DEFAULT_MODE;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci		return;
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	vesamode &= 0x1dff;  /* Clean VESA mode number from other flags */
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	while(sisbios_mode[i++].mode_no[0] != 0) {
16262306a36Sopenharmony_ci		if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
16362306a36Sopenharmony_ci		    (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
16462306a36Sopenharmony_ci			if(sisfb_fstn) {
16562306a36Sopenharmony_ci				if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
16662306a36Sopenharmony_ci				   sisbios_mode[i-1].mode_no[1] == 0x56 ||
16762306a36Sopenharmony_ci				   sisbios_mode[i-1].mode_no[1] == 0x53)
16862306a36Sopenharmony_ci					continue;
16962306a36Sopenharmony_ci			} else {
17062306a36Sopenharmony_ci				if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
17162306a36Sopenharmony_ci				   sisbios_mode[i-1].mode_no[1] == 0x5b)
17262306a36Sopenharmony_ci					continue;
17362306a36Sopenharmony_ci			}
17462306a36Sopenharmony_ci			sisfb_mode_idx = i - 1;
17562306a36Sopenharmony_ci			j = 1;
17662306a36Sopenharmony_ci			break;
17762306a36Sopenharmony_ci		}
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci	if((!j) && !quiet)
18062306a36Sopenharmony_ci		printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic void sisfb_search_mode(char *name, bool quiet)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
18662306a36Sopenharmony_ci	int i = 0;
18762306a36Sopenharmony_ci	char strbuf[16], strbuf1[20];
18862306a36Sopenharmony_ci	char *nameptr = name;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	/* We don't know the hardware specs yet and there is no ivideo */
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	if(name == NULL) {
19362306a36Sopenharmony_ci		if(!quiet)
19462306a36Sopenharmony_ci			printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci		sisfb_mode_idx = DEFAULT_MODE;
19762306a36Sopenharmony_ci		return;
19862306a36Sopenharmony_ci	}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	if(!strncasecmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
20162306a36Sopenharmony_ci		if(!quiet)
20262306a36Sopenharmony_ci			printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci		sisfb_mode_idx = DEFAULT_MODE;
20562306a36Sopenharmony_ci		return;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	if(strlen(name) <= 19) {
20962306a36Sopenharmony_ci		strcpy(strbuf1, name);
21062306a36Sopenharmony_ci		for(i = 0; i < strlen(strbuf1); i++) {
21162306a36Sopenharmony_ci			if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
21262306a36Sopenharmony_ci		}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci		/* This does some fuzzy mode naming detection */
21562306a36Sopenharmony_ci		if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
21662306a36Sopenharmony_ci			if((rate <= 32) || (depth > 32)) {
21762306a36Sopenharmony_ci				swap(rate, depth);
21862306a36Sopenharmony_ci			}
21962306a36Sopenharmony_ci			sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
22062306a36Sopenharmony_ci			nameptr = strbuf;
22162306a36Sopenharmony_ci			sisfb_parm_rate = rate;
22262306a36Sopenharmony_ci		} else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
22362306a36Sopenharmony_ci			sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
22462306a36Sopenharmony_ci			nameptr = strbuf;
22562306a36Sopenharmony_ci		} else {
22662306a36Sopenharmony_ci			xres = 0;
22762306a36Sopenharmony_ci			if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
22862306a36Sopenharmony_ci				sprintf(strbuf, "%ux%ux8", xres, yres);
22962306a36Sopenharmony_ci				nameptr = strbuf;
23062306a36Sopenharmony_ci			} else {
23162306a36Sopenharmony_ci				sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
23262306a36Sopenharmony_ci				return;
23362306a36Sopenharmony_ci			}
23462306a36Sopenharmony_ci		}
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	i = 0; j = 0;
23862306a36Sopenharmony_ci	while(sisbios_mode[i].mode_no[0] != 0) {
23962306a36Sopenharmony_ci		if(!strncasecmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
24062306a36Sopenharmony_ci			if(sisfb_fstn) {
24162306a36Sopenharmony_ci				if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
24262306a36Sopenharmony_ci				   sisbios_mode[i-1].mode_no[1] == 0x56 ||
24362306a36Sopenharmony_ci				   sisbios_mode[i-1].mode_no[1] == 0x53)
24462306a36Sopenharmony_ci					continue;
24562306a36Sopenharmony_ci			} else {
24662306a36Sopenharmony_ci				if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
24762306a36Sopenharmony_ci				   sisbios_mode[i-1].mode_no[1] == 0x5b)
24862306a36Sopenharmony_ci					continue;
24962306a36Sopenharmony_ci			}
25062306a36Sopenharmony_ci			sisfb_mode_idx = i - 1;
25162306a36Sopenharmony_ci			j = 1;
25262306a36Sopenharmony_ci			break;
25362306a36Sopenharmony_ci		}
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	if((!j) && !quiet)
25762306a36Sopenharmony_ci		printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci#ifndef MODULE
26162306a36Sopenharmony_cistatic void sisfb_get_vga_mode_from_kernel(void)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci#ifdef CONFIG_X86
26462306a36Sopenharmony_ci	char mymode[32];
26562306a36Sopenharmony_ci	int  mydepth = screen_info.lfb_depth;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
27062306a36Sopenharmony_ci	    (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
27162306a36Sopenharmony_ci	    (mydepth >= 8) && (mydepth <= 32) ) {
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci		if(mydepth == 24) mydepth = 32;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci		sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
27662306a36Sopenharmony_ci					screen_info.lfb_height,
27762306a36Sopenharmony_ci					mydepth);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci		printk(KERN_DEBUG
28062306a36Sopenharmony_ci			"sisfb: Using vga mode %s pre-set by kernel as default\n",
28162306a36Sopenharmony_ci			mymode);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci		sisfb_search_mode(mymode, true);
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci#endif
28662306a36Sopenharmony_ci	return;
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci#endif
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic void __init
29162306a36Sopenharmony_cisisfb_search_crt2type(const char *name)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	int i = 0;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	/* We don't know the hardware specs yet and there is no ivideo */
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	if(name == NULL) return;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	while(sis_crt2type[i].type_no != -1) {
30062306a36Sopenharmony_ci		if(!strncasecmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
30162306a36Sopenharmony_ci			sisfb_crt2type = sis_crt2type[i].type_no;
30262306a36Sopenharmony_ci			sisfb_tvplug = sis_crt2type[i].tvplug_no;
30362306a36Sopenharmony_ci			sisfb_crt2flags = sis_crt2type[i].flags;
30462306a36Sopenharmony_ci			break;
30562306a36Sopenharmony_ci		}
30662306a36Sopenharmony_ci		i++;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
31062306a36Sopenharmony_ci	sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	if(sisfb_crt2type < 0)
31362306a36Sopenharmony_ci		printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic void __init
31762306a36Sopenharmony_cisisfb_search_tvstd(const char *name)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	int i = 0;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	/* We don't know the hardware specs yet and there is no ivideo */
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	if(name == NULL)
32462306a36Sopenharmony_ci		return;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	while(sis_tvtype[i].type_no != -1) {
32762306a36Sopenharmony_ci		if(!strncasecmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
32862306a36Sopenharmony_ci			sisfb_tvstd = sis_tvtype[i].type_no;
32962306a36Sopenharmony_ci			break;
33062306a36Sopenharmony_ci		}
33162306a36Sopenharmony_ci		i++;
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic void __init
33662306a36Sopenharmony_cisisfb_search_specialtiming(const char *name)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	int i = 0;
33962306a36Sopenharmony_ci	bool found = false;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	/* We don't know the hardware specs yet and there is no ivideo */
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	if(name == NULL)
34462306a36Sopenharmony_ci		return;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if(!strncasecmp(name, "none", 4)) {
34762306a36Sopenharmony_ci		sisfb_specialtiming = CUT_FORCENONE;
34862306a36Sopenharmony_ci		printk(KERN_DEBUG "sisfb: Special timing disabled\n");
34962306a36Sopenharmony_ci	} else {
35062306a36Sopenharmony_ci		while(mycustomttable[i].chipID != 0) {
35162306a36Sopenharmony_ci			if(!strncasecmp(name,mycustomttable[i].optionName,
35262306a36Sopenharmony_ci			   strlen(mycustomttable[i].optionName))) {
35362306a36Sopenharmony_ci				sisfb_specialtiming = mycustomttable[i].SpecialID;
35462306a36Sopenharmony_ci				found = true;
35562306a36Sopenharmony_ci				printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
35662306a36Sopenharmony_ci					mycustomttable[i].vendorName,
35762306a36Sopenharmony_ci					mycustomttable[i].cardName,
35862306a36Sopenharmony_ci					mycustomttable[i].optionName);
35962306a36Sopenharmony_ci				break;
36062306a36Sopenharmony_ci			}
36162306a36Sopenharmony_ci			i++;
36262306a36Sopenharmony_ci		}
36362306a36Sopenharmony_ci		if(!found) {
36462306a36Sopenharmony_ci			printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
36562306a36Sopenharmony_ci			printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
36662306a36Sopenharmony_ci			i = 0;
36762306a36Sopenharmony_ci			while(mycustomttable[i].chipID != 0) {
36862306a36Sopenharmony_ci				printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
36962306a36Sopenharmony_ci					mycustomttable[i].optionName,
37062306a36Sopenharmony_ci					mycustomttable[i].vendorName,
37162306a36Sopenharmony_ci					mycustomttable[i].cardName);
37262306a36Sopenharmony_ci				i++;
37362306a36Sopenharmony_ci			}
37462306a36Sopenharmony_ci		}
37562306a36Sopenharmony_ci	}
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci/* ----------- Various detection routines ----------- */
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic void sisfb_detect_custom_timing(struct sis_video_info *ivideo)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	unsigned char *biosver = NULL;
38362306a36Sopenharmony_ci	unsigned char *biosdate = NULL;
38462306a36Sopenharmony_ci	bool footprint;
38562306a36Sopenharmony_ci	u32 chksum = 0;
38662306a36Sopenharmony_ci	int i, j;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	if(ivideo->SiS_Pr.UseROM) {
38962306a36Sopenharmony_ci		biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
39062306a36Sopenharmony_ci		biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
39162306a36Sopenharmony_ci		for(i = 0; i < 32768; i++)
39262306a36Sopenharmony_ci			chksum += ivideo->SiS_Pr.VirtualRomBase[i];
39362306a36Sopenharmony_ci	}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	i = 0;
39662306a36Sopenharmony_ci	do {
39762306a36Sopenharmony_ci		if( (mycustomttable[i].chipID == ivideo->chip)			&&
39862306a36Sopenharmony_ci		    ((!strlen(mycustomttable[i].biosversion)) ||
39962306a36Sopenharmony_ci		     (ivideo->SiS_Pr.UseROM &&
40062306a36Sopenharmony_ci		      (!strncmp(mycustomttable[i].biosversion, biosver,
40162306a36Sopenharmony_ci				strlen(mycustomttable[i].biosversion)))))	&&
40262306a36Sopenharmony_ci		    ((!strlen(mycustomttable[i].biosdate)) ||
40362306a36Sopenharmony_ci		     (ivideo->SiS_Pr.UseROM &&
40462306a36Sopenharmony_ci		      (!strncmp(mycustomttable[i].biosdate, biosdate,
40562306a36Sopenharmony_ci				strlen(mycustomttable[i].biosdate)))))		&&
40662306a36Sopenharmony_ci		    ((!mycustomttable[i].bioschksum) ||
40762306a36Sopenharmony_ci		     (ivideo->SiS_Pr.UseROM &&
40862306a36Sopenharmony_ci		      (mycustomttable[i].bioschksum == chksum)))		&&
40962306a36Sopenharmony_ci		    (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
41062306a36Sopenharmony_ci		    (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
41162306a36Sopenharmony_ci			footprint = true;
41262306a36Sopenharmony_ci			for(j = 0; j < 5; j++) {
41362306a36Sopenharmony_ci				if(mycustomttable[i].biosFootprintAddr[j]) {
41462306a36Sopenharmony_ci					if(ivideo->SiS_Pr.UseROM) {
41562306a36Sopenharmony_ci						if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
41662306a36Sopenharmony_ci							mycustomttable[i].biosFootprintData[j]) {
41762306a36Sopenharmony_ci							footprint = false;
41862306a36Sopenharmony_ci						}
41962306a36Sopenharmony_ci					} else
42062306a36Sopenharmony_ci						footprint = false;
42162306a36Sopenharmony_ci				}
42262306a36Sopenharmony_ci			}
42362306a36Sopenharmony_ci			if(footprint) {
42462306a36Sopenharmony_ci				ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
42562306a36Sopenharmony_ci				printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
42662306a36Sopenharmony_ci					mycustomttable[i].vendorName,
42762306a36Sopenharmony_ci				mycustomttable[i].cardName);
42862306a36Sopenharmony_ci				printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
42962306a36Sopenharmony_ci					mycustomttable[i].optionName);
43062306a36Sopenharmony_ci				break;
43162306a36Sopenharmony_ci			}
43262306a36Sopenharmony_ci		}
43362306a36Sopenharmony_ci		i++;
43462306a36Sopenharmony_ci	} while(mycustomttable[i].chipID);
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic bool sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	int i, j, xres, yres, refresh, index;
44062306a36Sopenharmony_ci	u32 emodes;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	if(buffer[0] != 0x00 || buffer[1] != 0xff ||
44362306a36Sopenharmony_ci	   buffer[2] != 0xff || buffer[3] != 0xff ||
44462306a36Sopenharmony_ci	   buffer[4] != 0xff || buffer[5] != 0xff ||
44562306a36Sopenharmony_ci	   buffer[6] != 0xff || buffer[7] != 0x00) {
44662306a36Sopenharmony_ci		printk(KERN_DEBUG "sisfb: Bad EDID header\n");
44762306a36Sopenharmony_ci		return false;
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	if(buffer[0x12] != 0x01) {
45162306a36Sopenharmony_ci		printk(KERN_INFO "sisfb: EDID version %d not supported\n",
45262306a36Sopenharmony_ci			buffer[0x12]);
45362306a36Sopenharmony_ci		return false;
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	monitor->feature = buffer[0x18];
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	if(!(buffer[0x14] & 0x80)) {
45962306a36Sopenharmony_ci		if(!(buffer[0x14] & 0x08)) {
46062306a36Sopenharmony_ci			printk(KERN_INFO
46162306a36Sopenharmony_ci				"sisfb: WARNING: Monitor does not support separate syncs\n");
46262306a36Sopenharmony_ci		}
46362306a36Sopenharmony_ci	}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	if(buffer[0x13] >= 0x01) {
46662306a36Sopenharmony_ci	   /* EDID V1 rev 1 and 2: Search for monitor descriptor
46762306a36Sopenharmony_ci	    * to extract ranges
46862306a36Sopenharmony_ci	    */
46962306a36Sopenharmony_ci	    j = 0x36;
47062306a36Sopenharmony_ci	    for(i=0; i<4; i++) {
47162306a36Sopenharmony_ci	       if(buffer[j]     == 0x00 && buffer[j + 1] == 0x00 &&
47262306a36Sopenharmony_ci		  buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
47362306a36Sopenharmony_ci		  buffer[j + 4] == 0x00) {
47462306a36Sopenharmony_ci		  monitor->hmin = buffer[j + 7];
47562306a36Sopenharmony_ci		  monitor->hmax = buffer[j + 8];
47662306a36Sopenharmony_ci		  monitor->vmin = buffer[j + 5];
47762306a36Sopenharmony_ci		  monitor->vmax = buffer[j + 6];
47862306a36Sopenharmony_ci		  monitor->dclockmax = buffer[j + 9] * 10 * 1000;
47962306a36Sopenharmony_ci		  monitor->datavalid = true;
48062306a36Sopenharmony_ci		  break;
48162306a36Sopenharmony_ci	       }
48262306a36Sopenharmony_ci	       j += 18;
48362306a36Sopenharmony_ci	    }
48462306a36Sopenharmony_ci	}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	if(!monitor->datavalid) {
48762306a36Sopenharmony_ci	   /* Otherwise: Get a range from the list of supported
48862306a36Sopenharmony_ci	    * Estabished Timings. This is not entirely accurate,
48962306a36Sopenharmony_ci	    * because fixed frequency monitors are not supported
49062306a36Sopenharmony_ci	    * that way.
49162306a36Sopenharmony_ci	    */
49262306a36Sopenharmony_ci	   monitor->hmin = 65535; monitor->hmax = 0;
49362306a36Sopenharmony_ci	   monitor->vmin = 65535; monitor->vmax = 0;
49462306a36Sopenharmony_ci	   monitor->dclockmax = 0;
49562306a36Sopenharmony_ci	   emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
49662306a36Sopenharmony_ci	   for(i = 0; i < 13; i++) {
49762306a36Sopenharmony_ci	      if(emodes & sisfb_ddcsmodes[i].mask) {
49862306a36Sopenharmony_ci		 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
49962306a36Sopenharmony_ci		 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
50062306a36Sopenharmony_ci		 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
50162306a36Sopenharmony_ci		 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
50262306a36Sopenharmony_ci		 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
50362306a36Sopenharmony_ci	      }
50462306a36Sopenharmony_ci	   }
50562306a36Sopenharmony_ci	   index = 0x26;
50662306a36Sopenharmony_ci	   for(i = 0; i < 8; i++) {
50762306a36Sopenharmony_ci	      xres = (buffer[index] + 31) * 8;
50862306a36Sopenharmony_ci	      switch(buffer[index + 1] & 0xc0) {
50962306a36Sopenharmony_ci		 case 0xc0: yres = (xres * 9) / 16; break;
51062306a36Sopenharmony_ci		 case 0x80: yres = (xres * 4) /  5; break;
51162306a36Sopenharmony_ci		 case 0x40: yres = (xres * 3) /  4; break;
51262306a36Sopenharmony_ci		 default:   yres = xres;	    break;
51362306a36Sopenharmony_ci	      }
51462306a36Sopenharmony_ci	      refresh = (buffer[index + 1] & 0x3f) + 60;
51562306a36Sopenharmony_ci	      if((xres >= 640) && (yres >= 480)) {
51662306a36Sopenharmony_ci		 for(j = 0; j < 8; j++) {
51762306a36Sopenharmony_ci		    if((xres == sisfb_ddcfmodes[j].x) &&
51862306a36Sopenharmony_ci		       (yres == sisfb_ddcfmodes[j].y) &&
51962306a36Sopenharmony_ci		       (refresh == sisfb_ddcfmodes[j].v)) {
52062306a36Sopenharmony_ci		      if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
52162306a36Sopenharmony_ci		      if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
52262306a36Sopenharmony_ci		      if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
52362306a36Sopenharmony_ci		      if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
52462306a36Sopenharmony_ci		      if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
52562306a36Sopenharmony_ci		    }
52662306a36Sopenharmony_ci		 }
52762306a36Sopenharmony_ci	      }
52862306a36Sopenharmony_ci	      index += 2;
52962306a36Sopenharmony_ci	   }
53062306a36Sopenharmony_ci	   if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
53162306a36Sopenharmony_ci	      monitor->datavalid = true;
53262306a36Sopenharmony_ci	   }
53362306a36Sopenharmony_ci	}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	return monitor->datavalid;
53662306a36Sopenharmony_ci}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_cistatic void sisfb_handle_ddc(struct sis_video_info *ivideo,
53962306a36Sopenharmony_ci			     struct sisfb_monitor *monitor, int crtno)
54062306a36Sopenharmony_ci{
54162306a36Sopenharmony_ci	unsigned short temp, i, realcrtno = crtno;
54262306a36Sopenharmony_ci	unsigned char  buffer[256];
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	monitor->datavalid = false;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	if(crtno) {
54762306a36Sopenharmony_ci	   if(ivideo->vbflags & CRT2_LCD)      realcrtno = 1;
54862306a36Sopenharmony_ci	   else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
54962306a36Sopenharmony_ci	   else return;
55062306a36Sopenharmony_ci	}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	if((ivideo->sisfb_crt1off) && (!crtno))
55362306a36Sopenharmony_ci		return;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
55662306a36Sopenharmony_ci				realcrtno, 0, &buffer[0], ivideo->vbflags2);
55762306a36Sopenharmony_ci	if((!temp) || (temp == 0xffff)) {
55862306a36Sopenharmony_ci	   printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
55962306a36Sopenharmony_ci	   return;
56062306a36Sopenharmony_ci	} else {
56162306a36Sopenharmony_ci	   printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
56262306a36Sopenharmony_ci	   printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
56362306a36Sopenharmony_ci		crtno + 1,
56462306a36Sopenharmony_ci		(temp & 0x1a) ? "" : "[none of the supported]",
56562306a36Sopenharmony_ci		(temp & 0x02) ? "2 " : "",
56662306a36Sopenharmony_ci		(temp & 0x08) ? "D&P" : "",
56762306a36Sopenharmony_ci		(temp & 0x10) ? "FPDI-2" : "");
56862306a36Sopenharmony_ci	   if(temp & 0x02) {
56962306a36Sopenharmony_ci	      i = 3;  /* Number of retrys */
57062306a36Sopenharmony_ci	      do {
57162306a36Sopenharmony_ci		 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
57262306a36Sopenharmony_ci				     realcrtno, 1, &buffer[0], ivideo->vbflags2);
57362306a36Sopenharmony_ci	      } while((temp) && i--);
57462306a36Sopenharmony_ci	      if(!temp) {
57562306a36Sopenharmony_ci		 if(sisfb_interpret_edid(monitor, &buffer[0])) {
57662306a36Sopenharmony_ci		    printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
57762306a36Sopenharmony_ci			monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
57862306a36Sopenharmony_ci			monitor->dclockmax / 1000);
57962306a36Sopenharmony_ci		 } else {
58062306a36Sopenharmony_ci		    printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
58162306a36Sopenharmony_ci		 }
58262306a36Sopenharmony_ci	      } else {
58362306a36Sopenharmony_ci		 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
58462306a36Sopenharmony_ci	      }
58562306a36Sopenharmony_ci	   } else {
58662306a36Sopenharmony_ci	      printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
58762306a36Sopenharmony_ci	   }
58862306a36Sopenharmony_ci	}
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci/* -------------- Mode validation --------------- */
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_cistatic bool
59462306a36Sopenharmony_cisisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
59562306a36Sopenharmony_ci		int mode_idx, int rate_idx, int rate)
59662306a36Sopenharmony_ci{
59762306a36Sopenharmony_ci	int htotal, vtotal;
59862306a36Sopenharmony_ci	unsigned int dclock, hsync;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	if(!monitor->datavalid)
60162306a36Sopenharmony_ci		return true;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	if(mode_idx < 0)
60462306a36Sopenharmony_ci		return false;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	/* Skip for 320x200, 320x240, 640x400 */
60762306a36Sopenharmony_ci	switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
60862306a36Sopenharmony_ci	case 0x59:
60962306a36Sopenharmony_ci	case 0x41:
61062306a36Sopenharmony_ci	case 0x4f:
61162306a36Sopenharmony_ci	case 0x50:
61262306a36Sopenharmony_ci	case 0x56:
61362306a36Sopenharmony_ci	case 0x53:
61462306a36Sopenharmony_ci	case 0x2f:
61562306a36Sopenharmony_ci	case 0x5d:
61662306a36Sopenharmony_ci	case 0x5e:
61762306a36Sopenharmony_ci		return true;
61862306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
61962306a36Sopenharmony_ci	case 0x5a:
62062306a36Sopenharmony_ci	case 0x5b:
62162306a36Sopenharmony_ci		if(ivideo->sisvga_engine == SIS_315_VGA) return true;
62262306a36Sopenharmony_ci#endif
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	if(rate < (monitor->vmin - 1))
62662306a36Sopenharmony_ci		return false;
62762306a36Sopenharmony_ci	if(rate > (monitor->vmax + 1))
62862306a36Sopenharmony_ci		return false;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
63162306a36Sopenharmony_ci				  sisbios_mode[mode_idx].mode_no[ivideo->mni],
63262306a36Sopenharmony_ci				  &htotal, &vtotal, rate_idx)) {
63362306a36Sopenharmony_ci		dclock = (htotal * vtotal * rate) / 1000;
63462306a36Sopenharmony_ci		if(dclock > (monitor->dclockmax + 1000))
63562306a36Sopenharmony_ci			return false;
63662306a36Sopenharmony_ci		hsync = dclock / htotal;
63762306a36Sopenharmony_ci		if(hsync < (monitor->hmin - 1))
63862306a36Sopenharmony_ci			return false;
63962306a36Sopenharmony_ci		if(hsync > (monitor->hmax + 1))
64062306a36Sopenharmony_ci			return false;
64162306a36Sopenharmony_ci        } else {
64262306a36Sopenharmony_ci		return false;
64362306a36Sopenharmony_ci	}
64462306a36Sopenharmony_ci	return true;
64562306a36Sopenharmony_ci}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_cistatic int
64862306a36Sopenharmony_cisisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	u16 xres=0, yres, myres;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
65362306a36Sopenharmony_ci	if (ivideo->sisvga_engine == SIS_300_VGA) {
65462306a36Sopenharmony_ci		if (!(sisbios_mode[myindex].chipset & MD_SIS300))
65562306a36Sopenharmony_ci			return -1 ;
65662306a36Sopenharmony_ci	}
65762306a36Sopenharmony_ci#endif
65862306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
65962306a36Sopenharmony_ci	if (ivideo->sisvga_engine == SIS_315_VGA) {
66062306a36Sopenharmony_ci		if (!(sisbios_mode[myindex].chipset & MD_SIS315))
66162306a36Sopenharmony_ci			return -1;
66262306a36Sopenharmony_ci	}
66362306a36Sopenharmony_ci#endif
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	myres = sisbios_mode[myindex].yres;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	switch (vbflags & VB_DISPTYPE_DISP2) {
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	case CRT2_LCD:
67062306a36Sopenharmony_ci		xres = ivideo->lcdxres; yres = ivideo->lcdyres;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci		if ((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
67362306a36Sopenharmony_ci		    (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
67462306a36Sopenharmony_ci			if (sisbios_mode[myindex].xres > xres)
67562306a36Sopenharmony_ci				return -1;
67662306a36Sopenharmony_ci			if (myres > yres)
67762306a36Sopenharmony_ci				return -1;
67862306a36Sopenharmony_ci		}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci		if (ivideo->sisfb_fstn) {
68162306a36Sopenharmony_ci			if (sisbios_mode[myindex].xres == 320) {
68262306a36Sopenharmony_ci				if (myres == 240) {
68362306a36Sopenharmony_ci					switch (sisbios_mode[myindex].mode_no[1]) {
68462306a36Sopenharmony_ci						case 0x50: myindex = MODE_FSTN_8;  break;
68562306a36Sopenharmony_ci						case 0x56: myindex = MODE_FSTN_16; break;
68662306a36Sopenharmony_ci						case 0x53: return -1;
68762306a36Sopenharmony_ci					}
68862306a36Sopenharmony_ci				}
68962306a36Sopenharmony_ci			}
69062306a36Sopenharmony_ci		}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci		if (SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
69362306a36Sopenharmony_ci			 	sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
69462306a36Sopenharmony_ci			 	ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
69562306a36Sopenharmony_ci			return -1;
69662306a36Sopenharmony_ci		}
69762306a36Sopenharmony_ci		break;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	case CRT2_TV:
70062306a36Sopenharmony_ci		if (SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
70162306a36Sopenharmony_ci				sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
70262306a36Sopenharmony_ci			return -1;
70362306a36Sopenharmony_ci		}
70462306a36Sopenharmony_ci		break;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	case CRT2_VGA:
70762306a36Sopenharmony_ci		if (SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
70862306a36Sopenharmony_ci				sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
70962306a36Sopenharmony_ci			return -1;
71062306a36Sopenharmony_ci		}
71162306a36Sopenharmony_ci		break;
71262306a36Sopenharmony_ci	}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	return myindex;
71562306a36Sopenharmony_ci}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_cistatic u8
71862306a36Sopenharmony_cisisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
71962306a36Sopenharmony_ci{
72062306a36Sopenharmony_ci	int i = 0;
72162306a36Sopenharmony_ci	u16 xres = sisbios_mode[mode_idx].xres;
72262306a36Sopenharmony_ci	u16 yres = sisbios_mode[mode_idx].yres;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	ivideo->rate_idx = 0;
72562306a36Sopenharmony_ci	while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
72662306a36Sopenharmony_ci		if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
72762306a36Sopenharmony_ci			if(sisfb_vrate[i].refresh == rate) {
72862306a36Sopenharmony_ci				ivideo->rate_idx = sisfb_vrate[i].idx;
72962306a36Sopenharmony_ci				break;
73062306a36Sopenharmony_ci			} else if(sisfb_vrate[i].refresh > rate) {
73162306a36Sopenharmony_ci				if((sisfb_vrate[i].refresh - rate) <= 3) {
73262306a36Sopenharmony_ci					DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
73362306a36Sopenharmony_ci						rate, sisfb_vrate[i].refresh);
73462306a36Sopenharmony_ci					ivideo->rate_idx = sisfb_vrate[i].idx;
73562306a36Sopenharmony_ci					ivideo->refresh_rate = sisfb_vrate[i].refresh;
73662306a36Sopenharmony_ci				} else if((sisfb_vrate[i].idx != 1) &&
73762306a36Sopenharmony_ci						((rate - sisfb_vrate[i-1].refresh) <= 2)) {
73862306a36Sopenharmony_ci					DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
73962306a36Sopenharmony_ci						rate, sisfb_vrate[i-1].refresh);
74062306a36Sopenharmony_ci					ivideo->rate_idx = sisfb_vrate[i-1].idx;
74162306a36Sopenharmony_ci					ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
74262306a36Sopenharmony_ci				}
74362306a36Sopenharmony_ci				break;
74462306a36Sopenharmony_ci			} else if((rate - sisfb_vrate[i].refresh) <= 2) {
74562306a36Sopenharmony_ci				DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
74662306a36Sopenharmony_ci						rate, sisfb_vrate[i].refresh);
74762306a36Sopenharmony_ci				ivideo->rate_idx = sisfb_vrate[i].idx;
74862306a36Sopenharmony_ci				break;
74962306a36Sopenharmony_ci			}
75062306a36Sopenharmony_ci		}
75162306a36Sopenharmony_ci		i++;
75262306a36Sopenharmony_ci	}
75362306a36Sopenharmony_ci	if(ivideo->rate_idx > 0) {
75462306a36Sopenharmony_ci		return ivideo->rate_idx;
75562306a36Sopenharmony_ci	} else {
75662306a36Sopenharmony_ci		printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
75762306a36Sopenharmony_ci				rate, xres, yres);
75862306a36Sopenharmony_ci		return 0;
75962306a36Sopenharmony_ci	}
76062306a36Sopenharmony_ci}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_cistatic bool
76362306a36Sopenharmony_cisisfb_bridgeisslave(struct sis_video_info *ivideo)
76462306a36Sopenharmony_ci{
76562306a36Sopenharmony_ci	unsigned char P1_00;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
76862306a36Sopenharmony_ci		return false;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	P1_00 = SiS_GetReg(SISPART1, 0x00);
77162306a36Sopenharmony_ci	if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
77262306a36Sopenharmony_ci	    ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
77362306a36Sopenharmony_ci		return true;
77462306a36Sopenharmony_ci	} else {
77562306a36Sopenharmony_ci		return false;
77662306a36Sopenharmony_ci	}
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_cistatic bool
78062306a36Sopenharmony_cisisfballowretracecrt1(struct sis_video_info *ivideo)
78162306a36Sopenharmony_ci{
78262306a36Sopenharmony_ci	u8 temp;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	temp = SiS_GetReg(SISCR, 0x17);
78562306a36Sopenharmony_ci	if(!(temp & 0x80))
78662306a36Sopenharmony_ci		return false;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	temp = SiS_GetReg(SISSR, 0x1f);
78962306a36Sopenharmony_ci	if(temp & 0xc0)
79062306a36Sopenharmony_ci		return false;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	return true;
79362306a36Sopenharmony_ci}
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_cistatic bool
79662306a36Sopenharmony_cisisfbcheckvretracecrt1(struct sis_video_info *ivideo)
79762306a36Sopenharmony_ci{
79862306a36Sopenharmony_ci	if(!sisfballowretracecrt1(ivideo))
79962306a36Sopenharmony_ci		return false;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	if (SiS_GetRegByte(SISINPSTAT) & 0x08)
80262306a36Sopenharmony_ci		return true;
80362306a36Sopenharmony_ci	else
80462306a36Sopenharmony_ci		return false;
80562306a36Sopenharmony_ci}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_cistatic void
80862306a36Sopenharmony_cisisfbwaitretracecrt1(struct sis_video_info *ivideo)
80962306a36Sopenharmony_ci{
81062306a36Sopenharmony_ci	int watchdog;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	if(!sisfballowretracecrt1(ivideo))
81362306a36Sopenharmony_ci		return;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	watchdog = 65536;
81662306a36Sopenharmony_ci	while ((!(SiS_GetRegByte(SISINPSTAT) & 0x08)) && --watchdog);
81762306a36Sopenharmony_ci	watchdog = 65536;
81862306a36Sopenharmony_ci	while ((SiS_GetRegByte(SISINPSTAT) & 0x08) && --watchdog);
81962306a36Sopenharmony_ci}
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_cistatic bool
82262306a36Sopenharmony_cisisfbcheckvretracecrt2(struct sis_video_info *ivideo)
82362306a36Sopenharmony_ci{
82462306a36Sopenharmony_ci	unsigned char temp, reg;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	switch(ivideo->sisvga_engine) {
82762306a36Sopenharmony_ci	case SIS_300_VGA: reg = 0x25; break;
82862306a36Sopenharmony_ci	case SIS_315_VGA: reg = 0x30; break;
82962306a36Sopenharmony_ci	default:	  return false;
83062306a36Sopenharmony_ci	}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	temp = SiS_GetReg(SISPART1, reg);
83362306a36Sopenharmony_ci	if(temp & 0x02)
83462306a36Sopenharmony_ci		return true;
83562306a36Sopenharmony_ci	else
83662306a36Sopenharmony_ci		return false;
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_cistatic bool
84062306a36Sopenharmony_cisisfb_CheckVBRetrace(struct sis_video_info *ivideo)
84162306a36Sopenharmony_ci{
84262306a36Sopenharmony_ci	if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
84362306a36Sopenharmony_ci		if(!sisfb_bridgeisslave(ivideo)) {
84462306a36Sopenharmony_ci			return sisfbcheckvretracecrt2(ivideo);
84562306a36Sopenharmony_ci		}
84662306a36Sopenharmony_ci	}
84762306a36Sopenharmony_ci	return sisfbcheckvretracecrt1(ivideo);
84862306a36Sopenharmony_ci}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_cistatic u32
85162306a36Sopenharmony_cisisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
85262306a36Sopenharmony_ci{
85362306a36Sopenharmony_ci	u8 idx, reg1, reg2, reg3, reg4;
85462306a36Sopenharmony_ci	u32 ret = 0;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	(*vcount) = (*hcount) = 0;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci		ret |= (FB_VBLANK_HAVE_VSYNC  |
86162306a36Sopenharmony_ci			FB_VBLANK_HAVE_HBLANK |
86262306a36Sopenharmony_ci			FB_VBLANK_HAVE_VBLANK |
86362306a36Sopenharmony_ci			FB_VBLANK_HAVE_VCOUNT |
86462306a36Sopenharmony_ci			FB_VBLANK_HAVE_HCOUNT);
86562306a36Sopenharmony_ci		switch(ivideo->sisvga_engine) {
86662306a36Sopenharmony_ci			case SIS_300_VGA: idx = 0x25; break;
86762306a36Sopenharmony_ci			default:
86862306a36Sopenharmony_ci			case SIS_315_VGA: idx = 0x30; break;
86962306a36Sopenharmony_ci		}
87062306a36Sopenharmony_ci		reg1 = SiS_GetReg(SISPART1, (idx+0)); /* 30 */
87162306a36Sopenharmony_ci		reg2 = SiS_GetReg(SISPART1, (idx+1)); /* 31 */
87262306a36Sopenharmony_ci		reg3 = SiS_GetReg(SISPART1, (idx+2)); /* 32 */
87362306a36Sopenharmony_ci		reg4 = SiS_GetReg(SISPART1, (idx+3)); /* 33 */
87462306a36Sopenharmony_ci		if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
87562306a36Sopenharmony_ci		if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
87662306a36Sopenharmony_ci		if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
87762306a36Sopenharmony_ci		(*vcount) = reg3 | ((reg4 & 0x70) << 4);
87862306a36Sopenharmony_ci		(*hcount) = reg2 | ((reg4 & 0x0f) << 8);
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	} else if(sisfballowretracecrt1(ivideo)) {
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci		ret |= (FB_VBLANK_HAVE_VSYNC  |
88362306a36Sopenharmony_ci			FB_VBLANK_HAVE_VBLANK |
88462306a36Sopenharmony_ci			FB_VBLANK_HAVE_VCOUNT |
88562306a36Sopenharmony_ci			FB_VBLANK_HAVE_HCOUNT);
88662306a36Sopenharmony_ci		reg1 = SiS_GetRegByte(SISINPSTAT);
88762306a36Sopenharmony_ci		if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
88862306a36Sopenharmony_ci		if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
88962306a36Sopenharmony_ci		reg1 = SiS_GetReg(SISCR, 0x20);
89062306a36Sopenharmony_ci		reg1 = SiS_GetReg(SISCR, 0x1b);
89162306a36Sopenharmony_ci		reg2 = SiS_GetReg(SISCR, 0x1c);
89262306a36Sopenharmony_ci		reg3 = SiS_GetReg(SISCR, 0x1d);
89362306a36Sopenharmony_ci		(*vcount) = reg2 | ((reg3 & 0x07) << 8);
89462306a36Sopenharmony_ci		(*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
89562306a36Sopenharmony_ci	}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	return ret;
89862306a36Sopenharmony_ci}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_cistatic int
90162306a36Sopenharmony_cisisfb_myblank(struct sis_video_info *ivideo, int blank)
90262306a36Sopenharmony_ci{
90362306a36Sopenharmony_ci	u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
90462306a36Sopenharmony_ci	bool backlight = true;
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	switch(blank) {
90762306a36Sopenharmony_ci		case FB_BLANK_UNBLANK:	/* on */
90862306a36Sopenharmony_ci			sr01  = 0x00;
90962306a36Sopenharmony_ci			sr11  = 0x00;
91062306a36Sopenharmony_ci			sr1f  = 0x00;
91162306a36Sopenharmony_ci			cr63  = 0x00;
91262306a36Sopenharmony_ci			p2_0  = 0x20;
91362306a36Sopenharmony_ci			p1_13 = 0x00;
91462306a36Sopenharmony_ci			backlight = true;
91562306a36Sopenharmony_ci			break;
91662306a36Sopenharmony_ci		case FB_BLANK_NORMAL:	/* blank */
91762306a36Sopenharmony_ci			sr01  = 0x20;
91862306a36Sopenharmony_ci			sr11  = 0x00;
91962306a36Sopenharmony_ci			sr1f  = 0x00;
92062306a36Sopenharmony_ci			cr63  = 0x00;
92162306a36Sopenharmony_ci			p2_0  = 0x20;
92262306a36Sopenharmony_ci			p1_13 = 0x00;
92362306a36Sopenharmony_ci			backlight = true;
92462306a36Sopenharmony_ci			break;
92562306a36Sopenharmony_ci		case FB_BLANK_VSYNC_SUSPEND:	/* no vsync */
92662306a36Sopenharmony_ci			sr01  = 0x20;
92762306a36Sopenharmony_ci			sr11  = 0x08;
92862306a36Sopenharmony_ci			sr1f  = 0x80;
92962306a36Sopenharmony_ci			cr63  = 0x40;
93062306a36Sopenharmony_ci			p2_0  = 0x40;
93162306a36Sopenharmony_ci			p1_13 = 0x80;
93262306a36Sopenharmony_ci			backlight = false;
93362306a36Sopenharmony_ci			break;
93462306a36Sopenharmony_ci		case FB_BLANK_HSYNC_SUSPEND:	/* no hsync */
93562306a36Sopenharmony_ci			sr01  = 0x20;
93662306a36Sopenharmony_ci			sr11  = 0x08;
93762306a36Sopenharmony_ci			sr1f  = 0x40;
93862306a36Sopenharmony_ci			cr63  = 0x40;
93962306a36Sopenharmony_ci			p2_0  = 0x80;
94062306a36Sopenharmony_ci			p1_13 = 0x40;
94162306a36Sopenharmony_ci			backlight = false;
94262306a36Sopenharmony_ci			break;
94362306a36Sopenharmony_ci		case FB_BLANK_POWERDOWN:	/* off */
94462306a36Sopenharmony_ci			sr01  = 0x20;
94562306a36Sopenharmony_ci			sr11  = 0x08;
94662306a36Sopenharmony_ci			sr1f  = 0xc0;
94762306a36Sopenharmony_ci			cr63  = 0x40;
94862306a36Sopenharmony_ci			p2_0  = 0xc0;
94962306a36Sopenharmony_ci			p1_13 = 0xc0;
95062306a36Sopenharmony_ci			backlight = false;
95162306a36Sopenharmony_ci			break;
95262306a36Sopenharmony_ci		default:
95362306a36Sopenharmony_ci			return 1;
95462306a36Sopenharmony_ci	}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci		if( (!ivideo->sisfb_thismonitor.datavalid) ||
95962306a36Sopenharmony_ci		    ((ivideo->sisfb_thismonitor.datavalid) &&
96062306a36Sopenharmony_ci		     (ivideo->sisfb_thismonitor.feature & 0xe0))) {
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci			if(ivideo->sisvga_engine == SIS_315_VGA) {
96362306a36Sopenharmony_ci				SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
96462306a36Sopenharmony_ci			}
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci			if(!(sisfb_bridgeisslave(ivideo))) {
96762306a36Sopenharmony_ci				SiS_SetRegANDOR(SISSR, 0x01, ~0x20, sr01);
96862306a36Sopenharmony_ci				SiS_SetRegANDOR(SISSR, 0x1f, 0x3f, sr1f);
96962306a36Sopenharmony_ci			}
97062306a36Sopenharmony_ci		}
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	if(ivideo->currentvbflags & CRT2_LCD) {
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci		if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
97762306a36Sopenharmony_ci			if(backlight) {
97862306a36Sopenharmony_ci				SiS_SiS30xBLOn(&ivideo->SiS_Pr);
97962306a36Sopenharmony_ci			} else {
98062306a36Sopenharmony_ci				SiS_SiS30xBLOff(&ivideo->SiS_Pr);
98162306a36Sopenharmony_ci			}
98262306a36Sopenharmony_ci		} else if(ivideo->sisvga_engine == SIS_315_VGA) {
98362306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
98462306a36Sopenharmony_ci			if(ivideo->vbflags2 & VB2_CHRONTEL) {
98562306a36Sopenharmony_ci				if(backlight) {
98662306a36Sopenharmony_ci					SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
98762306a36Sopenharmony_ci				} else {
98862306a36Sopenharmony_ci					SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
98962306a36Sopenharmony_ci				}
99062306a36Sopenharmony_ci			}
99162306a36Sopenharmony_ci#endif
99262306a36Sopenharmony_ci		}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci		if(((ivideo->sisvga_engine == SIS_300_VGA) &&
99562306a36Sopenharmony_ci		    (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
99662306a36Sopenharmony_ci		   ((ivideo->sisvga_engine == SIS_315_VGA) &&
99762306a36Sopenharmony_ci		    ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
99862306a36Sopenharmony_ci			SiS_SetRegANDOR(SISSR, 0x11, ~0x0c, sr11);
99962306a36Sopenharmony_ci		}
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci		if(ivideo->sisvga_engine == SIS_300_VGA) {
100262306a36Sopenharmony_ci			if((ivideo->vbflags2 & VB2_30xB) &&
100362306a36Sopenharmony_ci			   (!(ivideo->vbflags2 & VB2_30xBDH))) {
100462306a36Sopenharmony_ci				SiS_SetRegANDOR(SISPART1, 0x13, 0x3f, p1_13);
100562306a36Sopenharmony_ci			}
100662306a36Sopenharmony_ci		} else if(ivideo->sisvga_engine == SIS_315_VGA) {
100762306a36Sopenharmony_ci			if((ivideo->vbflags2 & VB2_30xB) &&
100862306a36Sopenharmony_ci			   (!(ivideo->vbflags2 & VB2_30xBDH))) {
100962306a36Sopenharmony_ci				SiS_SetRegANDOR(SISPART2, 0x00, 0x1f, p2_0);
101062306a36Sopenharmony_ci			}
101162306a36Sopenharmony_ci		}
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	} else if(ivideo->currentvbflags & CRT2_VGA) {
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci		if(ivideo->vbflags2 & VB2_30xB) {
101662306a36Sopenharmony_ci			SiS_SetRegANDOR(SISPART2, 0x00, 0x1f, p2_0);
101762306a36Sopenharmony_ci		}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	return 0;
102262306a36Sopenharmony_ci}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci/* ------------- Callbacks from init.c/init301.c  -------------- */
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
102762306a36Sopenharmony_ciunsigned int
102862306a36Sopenharmony_cisisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
102962306a36Sopenharmony_ci{
103062306a36Sopenharmony_ci   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
103162306a36Sopenharmony_ci   u32 val = 0;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci   pci_read_config_dword(ivideo->nbridge, reg, &val);
103462306a36Sopenharmony_ci   return (unsigned int)val;
103562306a36Sopenharmony_ci}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_civoid
103862306a36Sopenharmony_cisisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
103962306a36Sopenharmony_ci{
104062306a36Sopenharmony_ci   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci   pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ciunsigned int
104662306a36Sopenharmony_cisisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
104762306a36Sopenharmony_ci{
104862306a36Sopenharmony_ci   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
104962306a36Sopenharmony_ci   u32 val = 0;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci   if(!ivideo->lpcdev) return 0;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci   pci_read_config_dword(ivideo->lpcdev, reg, &val);
105462306a36Sopenharmony_ci   return (unsigned int)val;
105562306a36Sopenharmony_ci}
105662306a36Sopenharmony_ci#endif
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
105962306a36Sopenharmony_civoid
106062306a36Sopenharmony_cisisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
106162306a36Sopenharmony_ci{
106262306a36Sopenharmony_ci   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci   pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
106562306a36Sopenharmony_ci}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ciunsigned int
106862306a36Sopenharmony_cisisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
106962306a36Sopenharmony_ci{
107062306a36Sopenharmony_ci   struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
107162306a36Sopenharmony_ci   u16 val = 0;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci   if(!ivideo->lpcdev) return 0;
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci   pci_read_config_word(ivideo->lpcdev, reg, &val);
107662306a36Sopenharmony_ci   return (unsigned int)val;
107762306a36Sopenharmony_ci}
107862306a36Sopenharmony_ci#endif
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci/* ----------- FBDev related routines for all series ----------- */
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_cistatic int
108362306a36Sopenharmony_cisisfb_get_cmap_len(const struct fb_var_screeninfo *var)
108462306a36Sopenharmony_ci{
108562306a36Sopenharmony_ci	return (var->bits_per_pixel == 8) ? 256 : 16;
108662306a36Sopenharmony_ci}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_cistatic void
108962306a36Sopenharmony_cisisfb_set_vparms(struct sis_video_info *ivideo)
109062306a36Sopenharmony_ci{
109162306a36Sopenharmony_ci	switch(ivideo->video_bpp) {
109262306a36Sopenharmony_ci	case 8:
109362306a36Sopenharmony_ci		ivideo->DstColor = 0x0000;
109462306a36Sopenharmony_ci		ivideo->SiS310_AccelDepth = 0x00000000;
109562306a36Sopenharmony_ci		ivideo->video_cmap_len = 256;
109662306a36Sopenharmony_ci		break;
109762306a36Sopenharmony_ci	case 16:
109862306a36Sopenharmony_ci		ivideo->DstColor = 0x8000;
109962306a36Sopenharmony_ci		ivideo->SiS310_AccelDepth = 0x00010000;
110062306a36Sopenharmony_ci		ivideo->video_cmap_len = 16;
110162306a36Sopenharmony_ci		break;
110262306a36Sopenharmony_ci	case 32:
110362306a36Sopenharmony_ci		ivideo->DstColor = 0xC000;
110462306a36Sopenharmony_ci		ivideo->SiS310_AccelDepth = 0x00020000;
110562306a36Sopenharmony_ci		ivideo->video_cmap_len = 16;
110662306a36Sopenharmony_ci		break;
110762306a36Sopenharmony_ci	default:
110862306a36Sopenharmony_ci		ivideo->video_cmap_len = 16;
110962306a36Sopenharmony_ci		printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
111062306a36Sopenharmony_ci		ivideo->accel = 0;
111162306a36Sopenharmony_ci	}
111262306a36Sopenharmony_ci}
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_cistatic int
111562306a36Sopenharmony_cisisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
111662306a36Sopenharmony_ci{
111762306a36Sopenharmony_ci	int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	if(maxyres > 32767) maxyres = 32767;
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	return maxyres;
112262306a36Sopenharmony_ci}
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_cistatic void
112562306a36Sopenharmony_cisisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
112662306a36Sopenharmony_ci{
112762306a36Sopenharmony_ci	ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
112862306a36Sopenharmony_ci	ivideo->scrnpitchCRT1 = ivideo->video_linelength;
112962306a36Sopenharmony_ci	if(!(ivideo->currentvbflags & CRT1_LCDA)) {
113062306a36Sopenharmony_ci		if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
113162306a36Sopenharmony_ci			ivideo->scrnpitchCRT1 <<= 1;
113262306a36Sopenharmony_ci		}
113362306a36Sopenharmony_ci	}
113462306a36Sopenharmony_ci}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_cistatic void
113762306a36Sopenharmony_cisisfb_set_pitch(struct sis_video_info *ivideo)
113862306a36Sopenharmony_ci{
113962306a36Sopenharmony_ci	bool isslavemode = false;
114062306a36Sopenharmony_ci	unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
114162306a36Sopenharmony_ci	unsigned short HDisplay2 = ivideo->video_linelength >> 3;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	if(sisfb_bridgeisslave(ivideo)) isslavemode = true;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	/* We need to set pitch for CRT1 if bridge is in slave mode, too */
114662306a36Sopenharmony_ci	if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
114762306a36Sopenharmony_ci		SiS_SetReg(SISCR, 0x13, (HDisplay1 & 0xFF));
114862306a36Sopenharmony_ci		SiS_SetRegANDOR(SISSR, 0x0E, 0xF0, (HDisplay1 >> 8));
114962306a36Sopenharmony_ci	}
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	/* We must not set the pitch for CRT2 if bridge is in slave mode */
115262306a36Sopenharmony_ci	if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
115362306a36Sopenharmony_ci		SiS_SetRegOR(SISPART1, ivideo->CRT2_write_enable, 0x01);
115462306a36Sopenharmony_ci		SiS_SetReg(SISPART1, 0x07, (HDisplay2 & 0xFF));
115562306a36Sopenharmony_ci		SiS_SetRegANDOR(SISPART1, 0x09, 0xF0, (HDisplay2 >> 8));
115662306a36Sopenharmony_ci	}
115762306a36Sopenharmony_ci}
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_cistatic void
116062306a36Sopenharmony_cisisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
116162306a36Sopenharmony_ci{
116262306a36Sopenharmony_ci	ivideo->video_cmap_len = sisfb_get_cmap_len(var);
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	switch(var->bits_per_pixel) {
116562306a36Sopenharmony_ci	case 8:
116662306a36Sopenharmony_ci		var->red.offset = var->green.offset = var->blue.offset = 0;
116762306a36Sopenharmony_ci		var->red.length = var->green.length = var->blue.length = 8;
116862306a36Sopenharmony_ci		break;
116962306a36Sopenharmony_ci	case 16:
117062306a36Sopenharmony_ci		var->red.offset = 11;
117162306a36Sopenharmony_ci		var->red.length = 5;
117262306a36Sopenharmony_ci		var->green.offset = 5;
117362306a36Sopenharmony_ci		var->green.length = 6;
117462306a36Sopenharmony_ci		var->blue.offset = 0;
117562306a36Sopenharmony_ci		var->blue.length = 5;
117662306a36Sopenharmony_ci		var->transp.offset = 0;
117762306a36Sopenharmony_ci		var->transp.length = 0;
117862306a36Sopenharmony_ci		break;
117962306a36Sopenharmony_ci	case 32:
118062306a36Sopenharmony_ci		var->red.offset = 16;
118162306a36Sopenharmony_ci		var->red.length = 8;
118262306a36Sopenharmony_ci		var->green.offset = 8;
118362306a36Sopenharmony_ci		var->green.length = 8;
118462306a36Sopenharmony_ci		var->blue.offset = 0;
118562306a36Sopenharmony_ci		var->blue.length = 8;
118662306a36Sopenharmony_ci		var->transp.offset = 24;
118762306a36Sopenharmony_ci		var->transp.length = 8;
118862306a36Sopenharmony_ci		break;
118962306a36Sopenharmony_ci	}
119062306a36Sopenharmony_ci}
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_cistatic int
119362306a36Sopenharmony_cisisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
119462306a36Sopenharmony_ci{
119562306a36Sopenharmony_ci	unsigned short modeno = ivideo->mode_no;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	/* >=2.6.12's fbcon clears the screen anyway */
119862306a36Sopenharmony_ci	modeno |= 0x80;
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	sisfb_pre_setmode(ivideo);
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	if(!SiSSetMode(&ivideo->SiS_Pr, modeno)) {
120562306a36Sopenharmony_ci		printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
120662306a36Sopenharmony_ci		return -EINVAL;
120762306a36Sopenharmony_ci	}
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	sisfb_post_setmode(ivideo);
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	return 0;
121462306a36Sopenharmony_ci}
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_cistatic int
121862306a36Sopenharmony_cisisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
121962306a36Sopenharmony_ci{
122062306a36Sopenharmony_ci	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
122162306a36Sopenharmony_ci	unsigned int htotal = 0, vtotal = 0;
122262306a36Sopenharmony_ci	unsigned int drate = 0, hrate = 0;
122362306a36Sopenharmony_ci	int found_mode = 0, ret;
122462306a36Sopenharmony_ci	int old_mode;
122562306a36Sopenharmony_ci	u32 pixclock;
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	pixclock = var->pixclock;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
123462306a36Sopenharmony_ci		vtotal += var->yres;
123562306a36Sopenharmony_ci		vtotal <<= 1;
123662306a36Sopenharmony_ci	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
123762306a36Sopenharmony_ci		vtotal += var->yres;
123862306a36Sopenharmony_ci		vtotal <<= 2;
123962306a36Sopenharmony_ci	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
124062306a36Sopenharmony_ci		vtotal += var->yres;
124162306a36Sopenharmony_ci		vtotal <<= 1;
124262306a36Sopenharmony_ci	} else 	vtotal += var->yres;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	if(!(htotal) || !(vtotal)) {
124562306a36Sopenharmony_ci		DPRINTK("sisfb: Invalid 'var' information\n");
124662306a36Sopenharmony_ci		return -EINVAL;
124762306a36Sopenharmony_ci	}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	if(pixclock && htotal && vtotal) {
125062306a36Sopenharmony_ci		drate = 1000000000 / pixclock;
125162306a36Sopenharmony_ci		hrate = (drate * 1000) / htotal;
125262306a36Sopenharmony_ci		ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
125362306a36Sopenharmony_ci	} else {
125462306a36Sopenharmony_ci		ivideo->refresh_rate = 60;
125562306a36Sopenharmony_ci	}
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	old_mode = ivideo->sisfb_mode_idx;
125862306a36Sopenharmony_ci	ivideo->sisfb_mode_idx = 0;
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
126162306a36Sopenharmony_ci	       (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
126262306a36Sopenharmony_ci		if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
126362306a36Sopenharmony_ci		    (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
126462306a36Sopenharmony_ci		    (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
126562306a36Sopenharmony_ci			ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
126662306a36Sopenharmony_ci			found_mode = 1;
126762306a36Sopenharmony_ci			break;
126862306a36Sopenharmony_ci		}
126962306a36Sopenharmony_ci		ivideo->sisfb_mode_idx++;
127062306a36Sopenharmony_ci	}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	if(found_mode) {
127362306a36Sopenharmony_ci		ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
127462306a36Sopenharmony_ci				ivideo->sisfb_mode_idx, ivideo->currentvbflags);
127562306a36Sopenharmony_ci	} else {
127662306a36Sopenharmony_ci		ivideo->sisfb_mode_idx = -1;
127762306a36Sopenharmony_ci	}
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci       	if(ivideo->sisfb_mode_idx < 0) {
128062306a36Sopenharmony_ci		printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
128162306a36Sopenharmony_ci		       var->yres, var->bits_per_pixel);
128262306a36Sopenharmony_ci		ivideo->sisfb_mode_idx = old_mode;
128362306a36Sopenharmony_ci		return -EINVAL;
128462306a36Sopenharmony_ci	}
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
128962306a36Sopenharmony_ci		ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
129062306a36Sopenharmony_ci		ivideo->refresh_rate = 60;
129162306a36Sopenharmony_ci	}
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	if(isactive) {
129462306a36Sopenharmony_ci		/* If acceleration to be used? Need to know
129562306a36Sopenharmony_ci		 * before pre/post_set_mode()
129662306a36Sopenharmony_ci		 */
129762306a36Sopenharmony_ci		ivideo->accel = 0;
129862306a36Sopenharmony_ci#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
129962306a36Sopenharmony_ci#ifdef STUPID_ACCELF_TEXT_SHIT
130062306a36Sopenharmony_ci		if(var->accel_flags & FB_ACCELF_TEXT) {
130162306a36Sopenharmony_ci			info->flags &= ~FBINFO_HWACCEL_DISABLED;
130262306a36Sopenharmony_ci		} else {
130362306a36Sopenharmony_ci			info->flags |= FBINFO_HWACCEL_DISABLED;
130462306a36Sopenharmony_ci		}
130562306a36Sopenharmony_ci#endif
130662306a36Sopenharmony_ci		if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
130762306a36Sopenharmony_ci#else
130862306a36Sopenharmony_ci		if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
130962306a36Sopenharmony_ci#endif
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci		if((ret = sisfb_set_mode(ivideo, 1))) {
131262306a36Sopenharmony_ci			return ret;
131362306a36Sopenharmony_ci		}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci		ivideo->video_bpp    = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
131662306a36Sopenharmony_ci		ivideo->video_width  = sisbios_mode[ivideo->sisfb_mode_idx].xres;
131762306a36Sopenharmony_ci		ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci		sisfb_calc_pitch(ivideo, var);
132062306a36Sopenharmony_ci		sisfb_set_pitch(ivideo);
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci		sisfb_set_vparms(ivideo);
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci		ivideo->current_width = ivideo->video_width;
132562306a36Sopenharmony_ci		ivideo->current_height = ivideo->video_height;
132662306a36Sopenharmony_ci		ivideo->current_bpp = ivideo->video_bpp;
132762306a36Sopenharmony_ci		ivideo->current_htotal = htotal;
132862306a36Sopenharmony_ci		ivideo->current_vtotal = vtotal;
132962306a36Sopenharmony_ci		ivideo->current_linelength = ivideo->video_linelength;
133062306a36Sopenharmony_ci		ivideo->current_pixclock = var->pixclock;
133162306a36Sopenharmony_ci		ivideo->current_refresh_rate = ivideo->refresh_rate;
133262306a36Sopenharmony_ci		ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
133362306a36Sopenharmony_ci	}
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	return 0;
133662306a36Sopenharmony_ci}
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_cistatic void
133962306a36Sopenharmony_cisisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
134062306a36Sopenharmony_ci{
134162306a36Sopenharmony_ci	SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x0D, base & 0xFF);
134462306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x0C, (base >> 8) & 0xFF);
134562306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x0D, (base >> 16) & 0xFF);
134662306a36Sopenharmony_ci	if(ivideo->sisvga_engine == SIS_315_VGA) {
134762306a36Sopenharmony_ci		SiS_SetRegANDOR(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
134862306a36Sopenharmony_ci	}
134962306a36Sopenharmony_ci}
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_cistatic void
135262306a36Sopenharmony_cisisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
135362306a36Sopenharmony_ci{
135462306a36Sopenharmony_ci	if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
135562306a36Sopenharmony_ci		SiS_SetRegOR(SISPART1, ivideo->CRT2_write_enable, 0x01);
135662306a36Sopenharmony_ci		SiS_SetReg(SISPART1, 0x06, (base & 0xFF));
135762306a36Sopenharmony_ci		SiS_SetReg(SISPART1, 0x05, ((base >> 8) & 0xFF));
135862306a36Sopenharmony_ci		SiS_SetReg(SISPART1, 0x04, ((base >> 16) & 0xFF));
135962306a36Sopenharmony_ci		if(ivideo->sisvga_engine == SIS_315_VGA) {
136062306a36Sopenharmony_ci			SiS_SetRegANDOR(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
136162306a36Sopenharmony_ci		}
136262306a36Sopenharmony_ci	}
136362306a36Sopenharmony_ci}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_cistatic int
136662306a36Sopenharmony_cisisfb_pan_var(struct sis_video_info *ivideo, struct fb_info *info,
136762306a36Sopenharmony_ci	      struct fb_var_screeninfo *var)
136862306a36Sopenharmony_ci{
136962306a36Sopenharmony_ci	ivideo->current_base = var->yoffset * info->var.xres_virtual
137062306a36Sopenharmony_ci			     + var->xoffset;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	/* calculate base bpp dep. */
137362306a36Sopenharmony_ci	switch (info->var.bits_per_pixel) {
137462306a36Sopenharmony_ci	case 32:
137562306a36Sopenharmony_ci		break;
137662306a36Sopenharmony_ci	case 16:
137762306a36Sopenharmony_ci		ivideo->current_base >>= 1;
137862306a36Sopenharmony_ci		break;
137962306a36Sopenharmony_ci	case 8:
138062306a36Sopenharmony_ci	default:
138162306a36Sopenharmony_ci		ivideo->current_base >>= 2;
138262306a36Sopenharmony_ci		break;
138362306a36Sopenharmony_ci	}
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	ivideo->current_base += (ivideo->video_offset >> 2);
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	sisfb_set_base_CRT1(ivideo, ivideo->current_base);
138862306a36Sopenharmony_ci	sisfb_set_base_CRT2(ivideo, ivideo->current_base);
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	return 0;
139162306a36Sopenharmony_ci}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_cistatic int
139462306a36Sopenharmony_cisisfb_open(struct fb_info *info, int user)
139562306a36Sopenharmony_ci{
139662306a36Sopenharmony_ci	return 0;
139762306a36Sopenharmony_ci}
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_cistatic int
140062306a36Sopenharmony_cisisfb_release(struct fb_info *info, int user)
140162306a36Sopenharmony_ci{
140262306a36Sopenharmony_ci	return 0;
140362306a36Sopenharmony_ci}
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_cistatic int
140662306a36Sopenharmony_cisisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
140762306a36Sopenharmony_ci		unsigned transp, struct fb_info *info)
140862306a36Sopenharmony_ci{
140962306a36Sopenharmony_ci	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	if(regno >= sisfb_get_cmap_len(&info->var))
141262306a36Sopenharmony_ci		return 1;
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	switch(info->var.bits_per_pixel) {
141562306a36Sopenharmony_ci	case 8:
141662306a36Sopenharmony_ci		SiS_SetRegByte(SISDACA, regno);
141762306a36Sopenharmony_ci		SiS_SetRegByte(SISDACD, (red >> 10));
141862306a36Sopenharmony_ci		SiS_SetRegByte(SISDACD, (green >> 10));
141962306a36Sopenharmony_ci		SiS_SetRegByte(SISDACD, (blue >> 10));
142062306a36Sopenharmony_ci		if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
142162306a36Sopenharmony_ci			SiS_SetRegByte(SISDAC2A, regno);
142262306a36Sopenharmony_ci			SiS_SetRegByte(SISDAC2D, (red >> 8));
142362306a36Sopenharmony_ci			SiS_SetRegByte(SISDAC2D, (green >> 8));
142462306a36Sopenharmony_ci			SiS_SetRegByte(SISDAC2D, (blue >> 8));
142562306a36Sopenharmony_ci		}
142662306a36Sopenharmony_ci		break;
142762306a36Sopenharmony_ci	case 16:
142862306a36Sopenharmony_ci		if (regno >= 16)
142962306a36Sopenharmony_ci			break;
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci		((u32 *)(info->pseudo_palette))[regno] =
143262306a36Sopenharmony_ci				(red & 0xf800)          |
143362306a36Sopenharmony_ci				((green & 0xfc00) >> 5) |
143462306a36Sopenharmony_ci				((blue & 0xf800) >> 11);
143562306a36Sopenharmony_ci		break;
143662306a36Sopenharmony_ci	case 32:
143762306a36Sopenharmony_ci		if (regno >= 16)
143862306a36Sopenharmony_ci			break;
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci		red >>= 8;
144162306a36Sopenharmony_ci		green >>= 8;
144262306a36Sopenharmony_ci		blue >>= 8;
144362306a36Sopenharmony_ci		((u32 *)(info->pseudo_palette))[regno] =
144462306a36Sopenharmony_ci				(red << 16) | (green << 8) | (blue);
144562306a36Sopenharmony_ci		break;
144662306a36Sopenharmony_ci	}
144762306a36Sopenharmony_ci	return 0;
144862306a36Sopenharmony_ci}
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_cistatic int
145162306a36Sopenharmony_cisisfb_set_par(struct fb_info *info)
145262306a36Sopenharmony_ci{
145362306a36Sopenharmony_ci	int err;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	if((err = sisfb_do_set_var(&info->var, 1, info)))
145662306a36Sopenharmony_ci		return err;
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	sisfb_get_fix(&info->fix, -1, info);
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	return 0;
146162306a36Sopenharmony_ci}
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_cistatic int
146462306a36Sopenharmony_cisisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
146562306a36Sopenharmony_ci{
146662306a36Sopenharmony_ci	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
146762306a36Sopenharmony_ci	unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
146862306a36Sopenharmony_ci	unsigned int drate = 0, hrate = 0, maxyres;
146962306a36Sopenharmony_ci	int found_mode = 0;
147062306a36Sopenharmony_ci	int refresh_rate, search_idx, tidx;
147162306a36Sopenharmony_ci	bool recalc_clock = false;
147262306a36Sopenharmony_ci	u32 pixclock;
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	if (!var->pixclock)
147962306a36Sopenharmony_ci		return -EINVAL;
148062306a36Sopenharmony_ci	pixclock = var->pixclock;
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
148362306a36Sopenharmony_ci		vtotal += var->yres;
148462306a36Sopenharmony_ci		vtotal <<= 1;
148562306a36Sopenharmony_ci	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
148662306a36Sopenharmony_ci		vtotal += var->yres;
148762306a36Sopenharmony_ci		vtotal <<= 2;
148862306a36Sopenharmony_ci	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
148962306a36Sopenharmony_ci		vtotal += var->yres;
149062306a36Sopenharmony_ci		vtotal <<= 1;
149162306a36Sopenharmony_ci	} else
149262306a36Sopenharmony_ci		vtotal += var->yres;
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	if(!(htotal) || !(vtotal)) {
149562306a36Sopenharmony_ci		SISFAIL("sisfb: no valid timing data");
149662306a36Sopenharmony_ci	}
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	search_idx = 0;
149962306a36Sopenharmony_ci	while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
150062306a36Sopenharmony_ci	       (sisbios_mode[search_idx].xres <= var->xres) ) {
150162306a36Sopenharmony_ci		if( (sisbios_mode[search_idx].xres == var->xres) &&
150262306a36Sopenharmony_ci		    (sisbios_mode[search_idx].yres == var->yres) &&
150362306a36Sopenharmony_ci		    (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
150462306a36Sopenharmony_ci			if((tidx = sisfb_validate_mode(ivideo, search_idx,
150562306a36Sopenharmony_ci						ivideo->currentvbflags)) > 0) {
150662306a36Sopenharmony_ci				found_mode = 1;
150762306a36Sopenharmony_ci				search_idx = tidx;
150862306a36Sopenharmony_ci				break;
150962306a36Sopenharmony_ci			}
151062306a36Sopenharmony_ci		}
151162306a36Sopenharmony_ci		search_idx++;
151262306a36Sopenharmony_ci	}
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	if(!found_mode) {
151562306a36Sopenharmony_ci		search_idx = 0;
151662306a36Sopenharmony_ci		while(sisbios_mode[search_idx].mode_no[0] != 0) {
151762306a36Sopenharmony_ci		   if( (var->xres <= sisbios_mode[search_idx].xres) &&
151862306a36Sopenharmony_ci		       (var->yres <= sisbios_mode[search_idx].yres) &&
151962306a36Sopenharmony_ci		       (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
152062306a36Sopenharmony_ci			if((tidx = sisfb_validate_mode(ivideo,search_idx,
152162306a36Sopenharmony_ci						ivideo->currentvbflags)) > 0) {
152262306a36Sopenharmony_ci				found_mode = 1;
152362306a36Sopenharmony_ci				search_idx = tidx;
152462306a36Sopenharmony_ci				break;
152562306a36Sopenharmony_ci			}
152662306a36Sopenharmony_ci		   }
152762306a36Sopenharmony_ci		   search_idx++;
152862306a36Sopenharmony_ci		}
152962306a36Sopenharmony_ci		if(found_mode) {
153062306a36Sopenharmony_ci			printk(KERN_DEBUG
153162306a36Sopenharmony_ci				"sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
153262306a36Sopenharmony_ci				var->xres, var->yres, var->bits_per_pixel,
153362306a36Sopenharmony_ci				sisbios_mode[search_idx].xres,
153462306a36Sopenharmony_ci				sisbios_mode[search_idx].yres,
153562306a36Sopenharmony_ci				var->bits_per_pixel);
153662306a36Sopenharmony_ci			var->xres = sisbios_mode[search_idx].xres;
153762306a36Sopenharmony_ci			var->yres = sisbios_mode[search_idx].yres;
153862306a36Sopenharmony_ci		} else {
153962306a36Sopenharmony_ci			printk(KERN_ERR
154062306a36Sopenharmony_ci				"sisfb: Failed to find supported mode near %dx%dx%d\n",
154162306a36Sopenharmony_ci				var->xres, var->yres, var->bits_per_pixel);
154262306a36Sopenharmony_ci			return -EINVAL;
154362306a36Sopenharmony_ci		}
154462306a36Sopenharmony_ci	}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	if( ((ivideo->vbflags2 & VB2_LVDS) ||
154762306a36Sopenharmony_ci	     ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
154862306a36Sopenharmony_ci	    (var->bits_per_pixel == 8) ) {
154962306a36Sopenharmony_ci		/* Slave modes on LVDS and 301B-DH */
155062306a36Sopenharmony_ci		refresh_rate = 60;
155162306a36Sopenharmony_ci		recalc_clock = true;
155262306a36Sopenharmony_ci	} else if( (ivideo->current_htotal == htotal) &&
155362306a36Sopenharmony_ci		   (ivideo->current_vtotal == vtotal) &&
155462306a36Sopenharmony_ci		   (ivideo->current_pixclock == pixclock) ) {
155562306a36Sopenharmony_ci		/* x=x & y=y & c=c -> assume depth change */
155662306a36Sopenharmony_ci		drate = 1000000000 / pixclock;
155762306a36Sopenharmony_ci		hrate = (drate * 1000) / htotal;
155862306a36Sopenharmony_ci		refresh_rate = (unsigned int) (hrate * 2 / vtotal);
155962306a36Sopenharmony_ci	} else if( ( (ivideo->current_htotal != htotal) ||
156062306a36Sopenharmony_ci		     (ivideo->current_vtotal != vtotal) ) &&
156162306a36Sopenharmony_ci		   (ivideo->current_pixclock == var->pixclock) ) {
156262306a36Sopenharmony_ci		/* x!=x | y!=y & c=c -> invalid pixclock */
156362306a36Sopenharmony_ci		if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
156462306a36Sopenharmony_ci			refresh_rate =
156562306a36Sopenharmony_ci				ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
156662306a36Sopenharmony_ci		} else if(ivideo->sisfb_parm_rate != -1) {
156762306a36Sopenharmony_ci			/* Sic, sisfb_parm_rate - want to know originally desired rate here */
156862306a36Sopenharmony_ci			refresh_rate = ivideo->sisfb_parm_rate;
156962306a36Sopenharmony_ci		} else {
157062306a36Sopenharmony_ci			refresh_rate = 60;
157162306a36Sopenharmony_ci		}
157262306a36Sopenharmony_ci		recalc_clock = true;
157362306a36Sopenharmony_ci	} else if((pixclock) && (htotal) && (vtotal)) {
157462306a36Sopenharmony_ci		drate = 1000000000 / pixclock;
157562306a36Sopenharmony_ci		hrate = (drate * 1000) / htotal;
157662306a36Sopenharmony_ci		refresh_rate = (unsigned int) (hrate * 2 / vtotal);
157762306a36Sopenharmony_ci	} else if(ivideo->current_refresh_rate) {
157862306a36Sopenharmony_ci		refresh_rate = ivideo->current_refresh_rate;
157962306a36Sopenharmony_ci		recalc_clock = true;
158062306a36Sopenharmony_ci	} else {
158162306a36Sopenharmony_ci		refresh_rate = 60;
158262306a36Sopenharmony_ci		recalc_clock = true;
158362306a36Sopenharmony_ci	}
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	/* Eventually recalculate timing and clock */
158862306a36Sopenharmony_ci	if(recalc_clock) {
158962306a36Sopenharmony_ci		if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
159062306a36Sopenharmony_ci		var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
159162306a36Sopenharmony_ci						sisbios_mode[search_idx].mode_no[ivideo->mni],
159262306a36Sopenharmony_ci						myrateindex));
159362306a36Sopenharmony_ci		sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
159462306a36Sopenharmony_ci					sisbios_mode[search_idx].mode_no[ivideo->mni],
159562306a36Sopenharmony_ci					myrateindex, var);
159662306a36Sopenharmony_ci		if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
159762306a36Sopenharmony_ci			var->pixclock <<= 1;
159862306a36Sopenharmony_ci		}
159962306a36Sopenharmony_ci	}
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	if(ivideo->sisfb_thismonitor.datavalid) {
160262306a36Sopenharmony_ci		if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
160362306a36Sopenharmony_ci				myrateindex, refresh_rate)) {
160462306a36Sopenharmony_ci			printk(KERN_INFO
160562306a36Sopenharmony_ci				"sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
160662306a36Sopenharmony_ci		}
160762306a36Sopenharmony_ci	}
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	/* Adapt RGB settings */
161062306a36Sopenharmony_ci	sisfb_bpp_to_var(ivideo, var);
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	if(var->xres > var->xres_virtual)
161362306a36Sopenharmony_ci		var->xres_virtual = var->xres;
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci	if(ivideo->sisfb_ypan) {
161662306a36Sopenharmony_ci		maxyres = sisfb_calc_maxyres(ivideo, var);
161762306a36Sopenharmony_ci		if(ivideo->sisfb_max) {
161862306a36Sopenharmony_ci			var->yres_virtual = maxyres;
161962306a36Sopenharmony_ci		} else {
162062306a36Sopenharmony_ci			if(var->yres_virtual > maxyres) {
162162306a36Sopenharmony_ci				var->yres_virtual = maxyres;
162262306a36Sopenharmony_ci			}
162362306a36Sopenharmony_ci		}
162462306a36Sopenharmony_ci		if(var->yres_virtual <= var->yres) {
162562306a36Sopenharmony_ci			var->yres_virtual = var->yres;
162662306a36Sopenharmony_ci		}
162762306a36Sopenharmony_ci	} else {
162862306a36Sopenharmony_ci		if(var->yres != var->yres_virtual) {
162962306a36Sopenharmony_ci			var->yres_virtual = var->yres;
163062306a36Sopenharmony_ci		}
163162306a36Sopenharmony_ci		var->xoffset = 0;
163262306a36Sopenharmony_ci		var->yoffset = 0;
163362306a36Sopenharmony_ci	}
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	/* Truncate offsets to maximum if too high */
163662306a36Sopenharmony_ci	if(var->xoffset > var->xres_virtual - var->xres) {
163762306a36Sopenharmony_ci		var->xoffset = var->xres_virtual - var->xres - 1;
163862306a36Sopenharmony_ci	}
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci	if(var->yoffset > var->yres_virtual - var->yres) {
164162306a36Sopenharmony_ci		var->yoffset = var->yres_virtual - var->yres - 1;
164262306a36Sopenharmony_ci	}
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	/* Set everything else to 0 */
164562306a36Sopenharmony_ci	var->red.msb_right =
164662306a36Sopenharmony_ci		var->green.msb_right =
164762306a36Sopenharmony_ci		var->blue.msb_right =
164862306a36Sopenharmony_ci		var->transp.offset =
164962306a36Sopenharmony_ci		var->transp.length =
165062306a36Sopenharmony_ci		var->transp.msb_right = 0;
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	return 0;
165362306a36Sopenharmony_ci}
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_cistatic int
165662306a36Sopenharmony_cisisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
165762306a36Sopenharmony_ci{
165862306a36Sopenharmony_ci	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
165962306a36Sopenharmony_ci	int err;
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	if (var->vmode & FB_VMODE_YWRAP)
166262306a36Sopenharmony_ci		return -EINVAL;
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	if (var->xoffset + info->var.xres > info->var.xres_virtual ||
166562306a36Sopenharmony_ci	    var->yoffset + info->var.yres > info->var.yres_virtual)
166662306a36Sopenharmony_ci		return -EINVAL;
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	err = sisfb_pan_var(ivideo, info, var);
166962306a36Sopenharmony_ci	if (err < 0)
167062306a36Sopenharmony_ci		return err;
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	info->var.xoffset = var->xoffset;
167362306a36Sopenharmony_ci	info->var.yoffset = var->yoffset;
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	return 0;
167662306a36Sopenharmony_ci}
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_cistatic int
167962306a36Sopenharmony_cisisfb_blank(int blank, struct fb_info *info)
168062306a36Sopenharmony_ci{
168162306a36Sopenharmony_ci	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	return sisfb_myblank(ivideo, blank);
168462306a36Sopenharmony_ci}
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci/* ----------- FBDev related routines for all series ---------- */
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_cistatic int	sisfb_ioctl(struct fb_info *info, unsigned int cmd,
168962306a36Sopenharmony_ci			    unsigned long arg)
169062306a36Sopenharmony_ci{
169162306a36Sopenharmony_ci	struct sis_video_info	*ivideo = (struct sis_video_info *)info->par;
169262306a36Sopenharmony_ci	struct sis_memreq	sismemreq;
169362306a36Sopenharmony_ci	struct fb_vblank	sisvbblank;
169462306a36Sopenharmony_ci	u32			gpu32 = 0;
169562306a36Sopenharmony_ci#ifndef __user
169662306a36Sopenharmony_ci#define __user
169762306a36Sopenharmony_ci#endif
169862306a36Sopenharmony_ci	u32 __user 		*argp = (u32 __user *)arg;
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	switch(cmd) {
170162306a36Sopenharmony_ci	   case FBIO_ALLOC:
170262306a36Sopenharmony_ci		if(!capable(CAP_SYS_RAWIO))
170362306a36Sopenharmony_ci			return -EPERM;
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci		if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
170662306a36Sopenharmony_ci			return -EFAULT;
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci		sis_malloc(&sismemreq);
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci		if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
171162306a36Sopenharmony_ci			sis_free((u32)sismemreq.offset);
171262306a36Sopenharmony_ci			return -EFAULT;
171362306a36Sopenharmony_ci		}
171462306a36Sopenharmony_ci		break;
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	   case FBIO_FREE:
171762306a36Sopenharmony_ci		if(!capable(CAP_SYS_RAWIO))
171862306a36Sopenharmony_ci			return -EPERM;
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci		if(get_user(gpu32, argp))
172162306a36Sopenharmony_ci			return -EFAULT;
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci		sis_free(gpu32);
172462306a36Sopenharmony_ci		break;
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	   case FBIOGET_VBLANK:
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci		memset(&sisvbblank, 0, sizeof(struct fb_vblank));
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci		sisvbblank.count = 0;
173162306a36Sopenharmony_ci		sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci		if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
173462306a36Sopenharmony_ci			return -EFAULT;
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci		break;
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci	   case SISFB_GET_INFO_SIZE:
173962306a36Sopenharmony_ci		return put_user(sizeof(struct sisfb_info), argp);
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	   case SISFB_GET_INFO_OLD:
174262306a36Sopenharmony_ci		if(ivideo->warncount++ < 10)
174362306a36Sopenharmony_ci			printk(KERN_INFO
174462306a36Sopenharmony_ci				"sisfb: Deprecated ioctl call received - update your application!\n");
174562306a36Sopenharmony_ci		fallthrough;
174662306a36Sopenharmony_ci	   case SISFB_GET_INFO:  /* For communication with X driver */
174762306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_id         = SISFB_ID;
174862306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_version    = VER_MAJOR;
174962306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_revision   = VER_MINOR;
175062306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
175162306a36Sopenharmony_ci		ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
175262306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
175362306a36Sopenharmony_ci		ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
175462306a36Sopenharmony_ci		ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
175562306a36Sopenharmony_ci		if(ivideo->modechanged) {
175662306a36Sopenharmony_ci			ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
175762306a36Sopenharmony_ci		} else {
175862306a36Sopenharmony_ci			ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
175962306a36Sopenharmony_ci		}
176062306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
176162306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
176262306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
176362306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
176462306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
176562306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
176662306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
176762306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
176862306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
176962306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
177062306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
177162306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
177262306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
177362306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
177462306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
177562306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
177662306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
177762306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
177862306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
177962306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
178062306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
178162306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
178262306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
178362306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
178462306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
178562306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
178662306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
178762306a36Sopenharmony_ci		ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci		if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
179062306a36Sopenharmony_ci						sizeof(ivideo->sisfb_infoblock)))
179162306a36Sopenharmony_ci			return -EFAULT;
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	        break;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	   case SISFB_GET_VBRSTATUS_OLD:
179662306a36Sopenharmony_ci		if(ivideo->warncount++ < 10)
179762306a36Sopenharmony_ci			printk(KERN_INFO
179862306a36Sopenharmony_ci				"sisfb: Deprecated ioctl call received - update your application!\n");
179962306a36Sopenharmony_ci		fallthrough;
180062306a36Sopenharmony_ci	   case SISFB_GET_VBRSTATUS:
180162306a36Sopenharmony_ci		if(sisfb_CheckVBRetrace(ivideo))
180262306a36Sopenharmony_ci			return put_user((u32)1, argp);
180362306a36Sopenharmony_ci		else
180462306a36Sopenharmony_ci			return put_user((u32)0, argp);
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	   case SISFB_GET_AUTOMAXIMIZE_OLD:
180762306a36Sopenharmony_ci		if(ivideo->warncount++ < 10)
180862306a36Sopenharmony_ci			printk(KERN_INFO
180962306a36Sopenharmony_ci				"sisfb: Deprecated ioctl call received - update your application!\n");
181062306a36Sopenharmony_ci		fallthrough;
181162306a36Sopenharmony_ci	   case SISFB_GET_AUTOMAXIMIZE:
181262306a36Sopenharmony_ci		if(ivideo->sisfb_max)
181362306a36Sopenharmony_ci			return put_user((u32)1, argp);
181462306a36Sopenharmony_ci		else
181562306a36Sopenharmony_ci			return put_user((u32)0, argp);
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	   case SISFB_SET_AUTOMAXIMIZE_OLD:
181862306a36Sopenharmony_ci		if(ivideo->warncount++ < 10)
181962306a36Sopenharmony_ci			printk(KERN_INFO
182062306a36Sopenharmony_ci				"sisfb: Deprecated ioctl call received - update your application!\n");
182162306a36Sopenharmony_ci		fallthrough;
182262306a36Sopenharmony_ci	   case SISFB_SET_AUTOMAXIMIZE:
182362306a36Sopenharmony_ci		if(get_user(gpu32, argp))
182462306a36Sopenharmony_ci			return -EFAULT;
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci		ivideo->sisfb_max = (gpu32) ? 1 : 0;
182762306a36Sopenharmony_ci		break;
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	   case SISFB_SET_TVPOSOFFSET:
183062306a36Sopenharmony_ci		if(get_user(gpu32, argp))
183162306a36Sopenharmony_ci			return -EFAULT;
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci		sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
183462306a36Sopenharmony_ci		sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
183562306a36Sopenharmony_ci		break;
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	   case SISFB_GET_TVPOSOFFSET:
183862306a36Sopenharmony_ci		return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
183962306a36Sopenharmony_ci							argp);
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	   case SISFB_COMMAND:
184262306a36Sopenharmony_ci		if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
184362306a36Sopenharmony_ci							sizeof(struct sisfb_cmd)))
184462306a36Sopenharmony_ci			return -EFAULT;
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci		sisfb_handle_command(ivideo, &ivideo->sisfb_command);
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci		if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
184962306a36Sopenharmony_ci							sizeof(struct sisfb_cmd)))
185062306a36Sopenharmony_ci			return -EFAULT;
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci		break;
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	   case SISFB_SET_LOCK:
185562306a36Sopenharmony_ci		if(get_user(gpu32, argp))
185662306a36Sopenharmony_ci			return -EFAULT;
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci		ivideo->sisfblocked = (gpu32) ? 1 : 0;
185962306a36Sopenharmony_ci		break;
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	   default:
186262306a36Sopenharmony_ci#ifdef SIS_NEW_CONFIG_COMPAT
186362306a36Sopenharmony_ci		return -ENOIOCTLCMD;
186462306a36Sopenharmony_ci#else
186562306a36Sopenharmony_ci		return -EINVAL;
186662306a36Sopenharmony_ci#endif
186762306a36Sopenharmony_ci	}
186862306a36Sopenharmony_ci	return 0;
186962306a36Sopenharmony_ci}
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_cistatic int
187262306a36Sopenharmony_cisisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
187362306a36Sopenharmony_ci{
187462306a36Sopenharmony_ci	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci	strscpy(fix->id, ivideo->myid, sizeof(fix->id));
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	mutex_lock(&info->mm_lock);
188162306a36Sopenharmony_ci	fix->smem_start  = ivideo->video_base + ivideo->video_offset;
188262306a36Sopenharmony_ci	fix->smem_len    = ivideo->sisfb_mem;
188362306a36Sopenharmony_ci	mutex_unlock(&info->mm_lock);
188462306a36Sopenharmony_ci	fix->type        = FB_TYPE_PACKED_PIXELS;
188562306a36Sopenharmony_ci	fix->type_aux    = 0;
188662306a36Sopenharmony_ci	fix->visual      = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
188762306a36Sopenharmony_ci	fix->xpanstep    = 1;
188862306a36Sopenharmony_ci	fix->ypanstep 	 = (ivideo->sisfb_ypan) ? 1 : 0;
188962306a36Sopenharmony_ci	fix->ywrapstep   = 0;
189062306a36Sopenharmony_ci	fix->line_length = ivideo->video_linelength;
189162306a36Sopenharmony_ci	fix->mmio_start  = ivideo->mmio_base;
189262306a36Sopenharmony_ci	fix->mmio_len    = ivideo->mmio_size;
189362306a36Sopenharmony_ci	if(ivideo->sisvga_engine == SIS_300_VGA) {
189462306a36Sopenharmony_ci		fix->accel = FB_ACCEL_SIS_GLAMOUR;
189562306a36Sopenharmony_ci	} else if((ivideo->chip == SIS_330) ||
189662306a36Sopenharmony_ci		  (ivideo->chip == SIS_760) ||
189762306a36Sopenharmony_ci		  (ivideo->chip == SIS_761)) {
189862306a36Sopenharmony_ci		fix->accel = FB_ACCEL_SIS_XABRE;
189962306a36Sopenharmony_ci	} else if(ivideo->chip == XGI_20) {
190062306a36Sopenharmony_ci		fix->accel = FB_ACCEL_XGI_VOLARI_Z;
190162306a36Sopenharmony_ci	} else if(ivideo->chip >= XGI_40) {
190262306a36Sopenharmony_ci		fix->accel = FB_ACCEL_XGI_VOLARI_V;
190362306a36Sopenharmony_ci	} else {
190462306a36Sopenharmony_ci		fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
190562306a36Sopenharmony_ci	}
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	return 0;
190862306a36Sopenharmony_ci}
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci/* ----------------  fb_ops structures ----------------- */
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_cistatic const struct fb_ops sisfb_ops = {
191362306a36Sopenharmony_ci	.owner		= THIS_MODULE,
191462306a36Sopenharmony_ci	.fb_open	= sisfb_open,
191562306a36Sopenharmony_ci	.fb_release	= sisfb_release,
191662306a36Sopenharmony_ci	.fb_check_var	= sisfb_check_var,
191762306a36Sopenharmony_ci	.fb_set_par	= sisfb_set_par,
191862306a36Sopenharmony_ci	.fb_setcolreg	= sisfb_setcolreg,
191962306a36Sopenharmony_ci	.fb_pan_display	= sisfb_pan_display,
192062306a36Sopenharmony_ci	.fb_blank	= sisfb_blank,
192162306a36Sopenharmony_ci	.fb_fillrect	= fbcon_sis_fillrect,
192262306a36Sopenharmony_ci	.fb_copyarea	= fbcon_sis_copyarea,
192362306a36Sopenharmony_ci	.fb_imageblit	= cfb_imageblit,
192462306a36Sopenharmony_ci	.fb_sync	= fbcon_sis_sync,
192562306a36Sopenharmony_ci#ifdef SIS_NEW_CONFIG_COMPAT
192662306a36Sopenharmony_ci	.fb_compat_ioctl= sisfb_ioctl,
192762306a36Sopenharmony_ci#endif
192862306a36Sopenharmony_ci	.fb_ioctl	= sisfb_ioctl
192962306a36Sopenharmony_ci};
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci/* ---------------- Chip generation dependent routines ---------------- */
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_cistatic struct pci_dev *sisfb_get_northbridge(int basechipid)
193462306a36Sopenharmony_ci{
193562306a36Sopenharmony_ci	struct pci_dev *pdev = NULL;
193662306a36Sopenharmony_ci	int nbridgenum, nbridgeidx, i;
193762306a36Sopenharmony_ci	static const unsigned short nbridgeids[] = {
193862306a36Sopenharmony_ci		PCI_DEVICE_ID_SI_540,	/* for SiS 540 VGA */
193962306a36Sopenharmony_ci		PCI_DEVICE_ID_SI_630,	/* for SiS 630/730 VGA */
194062306a36Sopenharmony_ci		PCI_DEVICE_ID_SI_730,
194162306a36Sopenharmony_ci		PCI_DEVICE_ID_SI_550,   /* for SiS 550 VGA */
194262306a36Sopenharmony_ci		PCI_DEVICE_ID_SI_650,   /* for SiS 650/651/740 VGA */
194362306a36Sopenharmony_ci		PCI_DEVICE_ID_SI_651,
194462306a36Sopenharmony_ci		PCI_DEVICE_ID_SI_740,
194562306a36Sopenharmony_ci		PCI_DEVICE_ID_SI_661,	/* for SiS 661/741/660/760/761 VGA */
194662306a36Sopenharmony_ci		PCI_DEVICE_ID_SI_741,
194762306a36Sopenharmony_ci		PCI_DEVICE_ID_SI_660,
194862306a36Sopenharmony_ci		PCI_DEVICE_ID_SI_760,
194962306a36Sopenharmony_ci		PCI_DEVICE_ID_SI_761
195062306a36Sopenharmony_ci	};
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_ci	switch(basechipid) {
195362306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
195462306a36Sopenharmony_ci	case SIS_540:	nbridgeidx = 0; nbridgenum = 1; break;
195562306a36Sopenharmony_ci	case SIS_630:	nbridgeidx = 1; nbridgenum = 2; break;
195662306a36Sopenharmony_ci#endif
195762306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
195862306a36Sopenharmony_ci	case SIS_550:   nbridgeidx = 3; nbridgenum = 1; break;
195962306a36Sopenharmony_ci	case SIS_650:	nbridgeidx = 4; nbridgenum = 3; break;
196062306a36Sopenharmony_ci	case SIS_660:	nbridgeidx = 7; nbridgenum = 5; break;
196162306a36Sopenharmony_ci#endif
196262306a36Sopenharmony_ci	default:	return NULL;
196362306a36Sopenharmony_ci	}
196462306a36Sopenharmony_ci	for(i = 0; i < nbridgenum; i++) {
196562306a36Sopenharmony_ci		if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
196662306a36Sopenharmony_ci				nbridgeids[nbridgeidx+i], NULL)))
196762306a36Sopenharmony_ci			break;
196862306a36Sopenharmony_ci	}
196962306a36Sopenharmony_ci	return pdev;
197062306a36Sopenharmony_ci}
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_cistatic int sisfb_get_dram_size(struct sis_video_info *ivideo)
197362306a36Sopenharmony_ci{
197462306a36Sopenharmony_ci#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
197562306a36Sopenharmony_ci	u8 reg;
197662306a36Sopenharmony_ci#endif
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	ivideo->video_size = 0;
197962306a36Sopenharmony_ci	ivideo->UMAsize = ivideo->LFBsize = 0;
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci	switch(ivideo->chip) {
198262306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
198362306a36Sopenharmony_ci	case SIS_300:
198462306a36Sopenharmony_ci		reg = SiS_GetReg(SISSR, 0x14);
198562306a36Sopenharmony_ci		ivideo->video_size = ((reg & 0x3F) + 1) << 20;
198662306a36Sopenharmony_ci		break;
198762306a36Sopenharmony_ci	case SIS_540:
198862306a36Sopenharmony_ci	case SIS_630:
198962306a36Sopenharmony_ci	case SIS_730:
199062306a36Sopenharmony_ci		if(!ivideo->nbridge)
199162306a36Sopenharmony_ci			return -1;
199262306a36Sopenharmony_ci		pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
199362306a36Sopenharmony_ci		ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
199462306a36Sopenharmony_ci		break;
199562306a36Sopenharmony_ci#endif
199662306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
199762306a36Sopenharmony_ci	case SIS_315H:
199862306a36Sopenharmony_ci	case SIS_315PRO:
199962306a36Sopenharmony_ci	case SIS_315:
200062306a36Sopenharmony_ci		reg = SiS_GetReg(SISSR, 0x14);
200162306a36Sopenharmony_ci		ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
200262306a36Sopenharmony_ci		switch((reg >> 2) & 0x03) {
200362306a36Sopenharmony_ci		case 0x01:
200462306a36Sopenharmony_ci		case 0x03:
200562306a36Sopenharmony_ci			ivideo->video_size <<= 1;
200662306a36Sopenharmony_ci			break;
200762306a36Sopenharmony_ci		case 0x02:
200862306a36Sopenharmony_ci			ivideo->video_size += (ivideo->video_size/2);
200962306a36Sopenharmony_ci		}
201062306a36Sopenharmony_ci		break;
201162306a36Sopenharmony_ci	case SIS_330:
201262306a36Sopenharmony_ci		reg = SiS_GetReg(SISSR, 0x14);
201362306a36Sopenharmony_ci		ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
201462306a36Sopenharmony_ci		if(reg & 0x0c) ivideo->video_size <<= 1;
201562306a36Sopenharmony_ci		break;
201662306a36Sopenharmony_ci	case SIS_550:
201762306a36Sopenharmony_ci	case SIS_650:
201862306a36Sopenharmony_ci	case SIS_740:
201962306a36Sopenharmony_ci		reg = SiS_GetReg(SISSR, 0x14);
202062306a36Sopenharmony_ci		ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
202162306a36Sopenharmony_ci		break;
202262306a36Sopenharmony_ci	case SIS_661:
202362306a36Sopenharmony_ci	case SIS_741:
202462306a36Sopenharmony_ci		reg = SiS_GetReg(SISCR, 0x79);
202562306a36Sopenharmony_ci		ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
202662306a36Sopenharmony_ci		break;
202762306a36Sopenharmony_ci	case SIS_660:
202862306a36Sopenharmony_ci	case SIS_760:
202962306a36Sopenharmony_ci	case SIS_761:
203062306a36Sopenharmony_ci		reg = SiS_GetReg(SISCR, 0x79);
203162306a36Sopenharmony_ci		reg = (reg & 0xf0) >> 4;
203262306a36Sopenharmony_ci		if(reg)	{
203362306a36Sopenharmony_ci			ivideo->video_size = (1 << reg) << 20;
203462306a36Sopenharmony_ci			ivideo->UMAsize = ivideo->video_size;
203562306a36Sopenharmony_ci		}
203662306a36Sopenharmony_ci		reg = SiS_GetReg(SISCR, 0x78);
203762306a36Sopenharmony_ci		reg &= 0x30;
203862306a36Sopenharmony_ci		if(reg) {
203962306a36Sopenharmony_ci			if(reg == 0x10) {
204062306a36Sopenharmony_ci				ivideo->LFBsize = (32 << 20);
204162306a36Sopenharmony_ci			} else {
204262306a36Sopenharmony_ci				ivideo->LFBsize = (64 << 20);
204362306a36Sopenharmony_ci			}
204462306a36Sopenharmony_ci			ivideo->video_size += ivideo->LFBsize;
204562306a36Sopenharmony_ci		}
204662306a36Sopenharmony_ci		break;
204762306a36Sopenharmony_ci	case SIS_340:
204862306a36Sopenharmony_ci	case XGI_20:
204962306a36Sopenharmony_ci	case XGI_40:
205062306a36Sopenharmony_ci		reg = SiS_GetReg(SISSR, 0x14);
205162306a36Sopenharmony_ci		ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
205262306a36Sopenharmony_ci		if(ivideo->chip != XGI_20) {
205362306a36Sopenharmony_ci			reg = (reg & 0x0c) >> 2;
205462306a36Sopenharmony_ci			if(ivideo->revision_id == 2) {
205562306a36Sopenharmony_ci				if(reg & 0x01) reg = 0x02;
205662306a36Sopenharmony_ci				else	       reg = 0x00;
205762306a36Sopenharmony_ci			}
205862306a36Sopenharmony_ci			if(reg == 0x02)		ivideo->video_size <<= 1;
205962306a36Sopenharmony_ci			else if(reg == 0x03)	ivideo->video_size <<= 2;
206062306a36Sopenharmony_ci		}
206162306a36Sopenharmony_ci		break;
206262306a36Sopenharmony_ci#endif
206362306a36Sopenharmony_ci	default:
206462306a36Sopenharmony_ci		return -1;
206562306a36Sopenharmony_ci	}
206662306a36Sopenharmony_ci	return 0;
206762306a36Sopenharmony_ci}
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci/* -------------- video bridge device detection --------------- */
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_cistatic void sisfb_detect_VB_connect(struct sis_video_info *ivideo)
207262306a36Sopenharmony_ci{
207362306a36Sopenharmony_ci	u8 cr32, temp;
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci	/* No CRT2 on XGI Z7 */
207662306a36Sopenharmony_ci	if(ivideo->chip == XGI_20) {
207762306a36Sopenharmony_ci		ivideo->sisfb_crt1off = 0;
207862306a36Sopenharmony_ci		return;
207962306a36Sopenharmony_ci	}
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
208262306a36Sopenharmony_ci	if(ivideo->sisvga_engine == SIS_300_VGA) {
208362306a36Sopenharmony_ci		temp = SiS_GetReg(SISSR, 0x17);
208462306a36Sopenharmony_ci		if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
208562306a36Sopenharmony_ci			/* PAL/NTSC is stored on SR16 on such machines */
208662306a36Sopenharmony_ci			if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
208762306a36Sopenharmony_ci				temp = SiS_GetReg(SISSR, 0x16);
208862306a36Sopenharmony_ci				if(temp & 0x20)
208962306a36Sopenharmony_ci					ivideo->vbflags |= TV_PAL;
209062306a36Sopenharmony_ci				else
209162306a36Sopenharmony_ci					ivideo->vbflags |= TV_NTSC;
209262306a36Sopenharmony_ci			}
209362306a36Sopenharmony_ci		}
209462306a36Sopenharmony_ci	}
209562306a36Sopenharmony_ci#endif
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	cr32 = SiS_GetReg(SISCR, 0x32);
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci	if(cr32 & SIS_CRT1) {
210062306a36Sopenharmony_ci		ivideo->sisfb_crt1off = 0;
210162306a36Sopenharmony_ci	} else {
210262306a36Sopenharmony_ci		ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
210362306a36Sopenharmony_ci	}
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci	if(cr32 & SIS_VB_TV)   ivideo->vbflags |= CRT2_TV;
210862306a36Sopenharmony_ci	if(cr32 & SIS_VB_LCD)  ivideo->vbflags |= CRT2_LCD;
210962306a36Sopenharmony_ci	if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci	/* Check given parms for hardware compatibility.
211262306a36Sopenharmony_ci	 * (Cannot do this in the search_xx routines since we don't
211362306a36Sopenharmony_ci	 * know what hardware we are running on then)
211462306a36Sopenharmony_ci	 */
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci	if(ivideo->chip != SIS_550) {
211762306a36Sopenharmony_ci	   ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
211862306a36Sopenharmony_ci	}
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	if(ivideo->sisfb_tvplug != -1) {
212162306a36Sopenharmony_ci	   if( (ivideo->sisvga_engine != SIS_315_VGA) ||
212262306a36Sopenharmony_ci	       (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
212362306a36Sopenharmony_ci	      if(ivideo->sisfb_tvplug & TV_YPBPR) {
212462306a36Sopenharmony_ci		 ivideo->sisfb_tvplug = -1;
212562306a36Sopenharmony_ci		 printk(KERN_ERR "sisfb: YPbPr not supported\n");
212662306a36Sopenharmony_ci	      }
212762306a36Sopenharmony_ci	   }
212862306a36Sopenharmony_ci	}
212962306a36Sopenharmony_ci	if(ivideo->sisfb_tvplug != -1) {
213062306a36Sopenharmony_ci	   if( (ivideo->sisvga_engine != SIS_315_VGA) ||
213162306a36Sopenharmony_ci	       (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
213262306a36Sopenharmony_ci	      if(ivideo->sisfb_tvplug & TV_HIVISION) {
213362306a36Sopenharmony_ci		 ivideo->sisfb_tvplug = -1;
213462306a36Sopenharmony_ci		 printk(KERN_ERR "sisfb: HiVision not supported\n");
213562306a36Sopenharmony_ci	      }
213662306a36Sopenharmony_ci	   }
213762306a36Sopenharmony_ci	}
213862306a36Sopenharmony_ci	if(ivideo->sisfb_tvstd != -1) {
213962306a36Sopenharmony_ci	   if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
214062306a36Sopenharmony_ci	       (!((ivideo->sisvga_engine == SIS_315_VGA) &&
214162306a36Sopenharmony_ci			(ivideo->vbflags2 & VB2_CHRONTEL))) ) {
214262306a36Sopenharmony_ci	      if(ivideo->sisfb_tvstd & (TV_PALM | TV_PALN | TV_NTSCJ)) {
214362306a36Sopenharmony_ci		 ivideo->sisfb_tvstd = -1;
214462306a36Sopenharmony_ci		 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
214562306a36Sopenharmony_ci	      }
214662306a36Sopenharmony_ci	   }
214762306a36Sopenharmony_ci	}
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	/* Detect/set TV plug & type */
215062306a36Sopenharmony_ci	if(ivideo->sisfb_tvplug != -1) {
215162306a36Sopenharmony_ci		ivideo->vbflags |= ivideo->sisfb_tvplug;
215262306a36Sopenharmony_ci	} else {
215362306a36Sopenharmony_ci		if(cr32 & SIS_VB_YPBPR)     	 ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
215462306a36Sopenharmony_ci		else if(cr32 & SIS_VB_HIVISION)  ivideo->vbflags |= TV_HIVISION;
215562306a36Sopenharmony_ci		else if(cr32 & SIS_VB_SCART)     ivideo->vbflags |= TV_SCART;
215662306a36Sopenharmony_ci		else {
215762306a36Sopenharmony_ci			if(cr32 & SIS_VB_SVIDEO)    ivideo->vbflags |= TV_SVIDEO;
215862306a36Sopenharmony_ci			if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
215962306a36Sopenharmony_ci		}
216062306a36Sopenharmony_ci	}
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_ci	if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
216362306a36Sopenharmony_ci	    if(ivideo->sisfb_tvstd != -1) {
216462306a36Sopenharmony_ci	       ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
216562306a36Sopenharmony_ci	       ivideo->vbflags |= ivideo->sisfb_tvstd;
216662306a36Sopenharmony_ci	    }
216762306a36Sopenharmony_ci	    if(ivideo->vbflags & TV_SCART) {
216862306a36Sopenharmony_ci	       ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
216962306a36Sopenharmony_ci	       ivideo->vbflags |= TV_PAL;
217062306a36Sopenharmony_ci	    }
217162306a36Sopenharmony_ci	    if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
217262306a36Sopenharmony_ci		if(ivideo->sisvga_engine == SIS_300_VGA) {
217362306a36Sopenharmony_ci			temp = SiS_GetReg(SISSR, 0x38);
217462306a36Sopenharmony_ci			if(temp & 0x01) ivideo->vbflags |= TV_PAL;
217562306a36Sopenharmony_ci			else		ivideo->vbflags |= TV_NTSC;
217662306a36Sopenharmony_ci		} else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
217762306a36Sopenharmony_ci			temp = SiS_GetReg(SISSR, 0x38);
217862306a36Sopenharmony_ci			if(temp & 0x01) ivideo->vbflags |= TV_PAL;
217962306a36Sopenharmony_ci			else		ivideo->vbflags |= TV_NTSC;
218062306a36Sopenharmony_ci		} else {
218162306a36Sopenharmony_ci			temp = SiS_GetReg(SISCR, 0x79);
218262306a36Sopenharmony_ci			if(temp & 0x20)	ivideo->vbflags |= TV_PAL;
218362306a36Sopenharmony_ci			else		ivideo->vbflags |= TV_NTSC;
218462306a36Sopenharmony_ci		}
218562306a36Sopenharmony_ci	    }
218662306a36Sopenharmony_ci	}
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci	/* Copy forceCRT1 option to CRT1off if option is given */
218962306a36Sopenharmony_ci	if(ivideo->sisfb_forcecrt1 != -1) {
219062306a36Sopenharmony_ci	   ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
219162306a36Sopenharmony_ci	}
219262306a36Sopenharmony_ci}
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci/* ------------------ Sensing routines ------------------ */
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_cistatic bool sisfb_test_DDC1(struct sis_video_info *ivideo)
219762306a36Sopenharmony_ci{
219862306a36Sopenharmony_ci    unsigned short old;
219962306a36Sopenharmony_ci    int count = 48;
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci    old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
220262306a36Sopenharmony_ci    do {
220362306a36Sopenharmony_ci	if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
220462306a36Sopenharmony_ci    } while(count--);
220562306a36Sopenharmony_ci    return (count != -1);
220662306a36Sopenharmony_ci}
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_cistatic void sisfb_sense_crt1(struct sis_video_info *ivideo)
220962306a36Sopenharmony_ci{
221062306a36Sopenharmony_ci	bool mustwait = false;
221162306a36Sopenharmony_ci	u8  sr1F, cr17;
221262306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
221362306a36Sopenharmony_ci	u8  cr63 = 0;
221462306a36Sopenharmony_ci#endif
221562306a36Sopenharmony_ci	u16 temp = 0xffff;
221662306a36Sopenharmony_ci	int i;
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci	sr1F = SiS_GetReg(SISSR, 0x1F);
221962306a36Sopenharmony_ci	SiS_SetRegOR(SISSR, 0x1F, 0x04);
222062306a36Sopenharmony_ci	SiS_SetRegAND(SISSR, 0x1F, 0x3F);
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	if (sr1F & 0xc0)
222362306a36Sopenharmony_ci		mustwait = true;
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
222662306a36Sopenharmony_ci	if (ivideo->sisvga_engine == SIS_315_VGA) {
222762306a36Sopenharmony_ci		cr63 = SiS_GetReg(SISCR, ivideo->SiS_Pr.SiS_MyCR63);
222862306a36Sopenharmony_ci		cr63 &= 0x40;
222962306a36Sopenharmony_ci		SiS_SetRegAND(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF);
223062306a36Sopenharmony_ci	}
223162306a36Sopenharmony_ci#endif
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_ci	cr17 = SiS_GetReg(SISCR, 0x17);
223462306a36Sopenharmony_ci	cr17 &= 0x80;
223562306a36Sopenharmony_ci
223662306a36Sopenharmony_ci	if (!cr17) {
223762306a36Sopenharmony_ci		SiS_SetRegOR(SISCR, 0x17, 0x80);
223862306a36Sopenharmony_ci		mustwait = true;
223962306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x00, 0x01);
224062306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x00, 0x03);
224162306a36Sopenharmony_ci	}
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci	if (mustwait) {
224462306a36Sopenharmony_ci		for (i = 0; i < 10; i++)
224562306a36Sopenharmony_ci			sisfbwaitretracecrt1(ivideo);
224662306a36Sopenharmony_ci	}
224762306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
224862306a36Sopenharmony_ci	if (ivideo->chip >= SIS_330) {
224962306a36Sopenharmony_ci		SiS_SetRegAND(SISCR, 0x32, ~0x20);
225062306a36Sopenharmony_ci		if (ivideo->chip >= SIS_340)
225162306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x57, 0x4a);
225262306a36Sopenharmony_ci		else
225362306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x57, 0x5f);
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci		SiS_SetRegOR(SISCR, 0x53, 0x02);
225662306a36Sopenharmony_ci		while ((SiS_GetRegByte(SISINPSTAT)) & 0x01)
225762306a36Sopenharmony_ci			break;
225862306a36Sopenharmony_ci		while (!((SiS_GetRegByte(SISINPSTAT)) & 0x01))
225962306a36Sopenharmony_ci			break;
226062306a36Sopenharmony_ci		if ((SiS_GetRegByte(SISMISCW)) & 0x10)
226162306a36Sopenharmony_ci			temp = 1;
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci		SiS_SetRegAND(SISCR, 0x53, 0xfd);
226462306a36Sopenharmony_ci		SiS_SetRegAND(SISCR, 0x57, 0x00);
226562306a36Sopenharmony_ci	}
226662306a36Sopenharmony_ci#endif
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_ci	if (temp == 0xffff) {
226962306a36Sopenharmony_ci		i = 3;
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci		do {
227262306a36Sopenharmony_ci			temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
227362306a36Sopenharmony_ci			ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
227462306a36Sopenharmony_ci		} while (((temp == 0) || (temp == 0xffff)) && i--);
227562306a36Sopenharmony_ci
227662306a36Sopenharmony_ci		if ((temp == 0) || (temp == 0xffff)) {
227762306a36Sopenharmony_ci			if (sisfb_test_DDC1(ivideo))
227862306a36Sopenharmony_ci				temp = 1;
227962306a36Sopenharmony_ci		}
228062306a36Sopenharmony_ci	}
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci	if ((temp) && (temp != 0xffff))
228362306a36Sopenharmony_ci		SiS_SetRegOR(SISCR, 0x32, 0x20);
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
228662306a36Sopenharmony_ci	if (ivideo->sisvga_engine == SIS_315_VGA)
228762306a36Sopenharmony_ci		SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF, cr63);
228862306a36Sopenharmony_ci#endif
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_ci	SiS_SetRegANDOR(SISCR, 0x17, 0x7F, cr17);
229162306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x1F, sr1F);
229262306a36Sopenharmony_ci}
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci/* Determine and detect attached devices on SiS30x */
229562306a36Sopenharmony_cistatic void SiS_SenseLCD(struct sis_video_info *ivideo)
229662306a36Sopenharmony_ci{
229762306a36Sopenharmony_ci	unsigned char buffer[256];
229862306a36Sopenharmony_ci	unsigned short temp, realcrtno, i;
229962306a36Sopenharmony_ci	u8 reg, cr37 = 0, paneltype = 0;
230062306a36Sopenharmony_ci	u16 xres, yres;
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci	ivideo->SiS_Pr.PanelSelfDetected = false;
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_ci	/* LCD detection only for TMDS bridges */
230562306a36Sopenharmony_ci	if (!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
230662306a36Sopenharmony_ci		return;
230762306a36Sopenharmony_ci	if (ivideo->vbflags2 & VB2_30xBDH)
230862306a36Sopenharmony_ci		return;
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci	/* If LCD already set up by BIOS, skip it */
231162306a36Sopenharmony_ci	reg = SiS_GetReg(SISCR, 0x32);
231262306a36Sopenharmony_ci	if (reg & 0x08)
231362306a36Sopenharmony_ci		return;
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci	realcrtno = 1;
231662306a36Sopenharmony_ci	if (ivideo->SiS_Pr.DDCPortMixup)
231762306a36Sopenharmony_ci		realcrtno = 0;
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	/* Check DDC capabilities */
232062306a36Sopenharmony_ci	temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
232162306a36Sopenharmony_ci				realcrtno, 0, &buffer[0], ivideo->vbflags2);
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_ci	if ((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
232462306a36Sopenharmony_ci		return;
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci	/* Read DDC data */
232762306a36Sopenharmony_ci	i = 3;  /* Number of retrys */
232862306a36Sopenharmony_ci	do {
232962306a36Sopenharmony_ci		temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
233062306a36Sopenharmony_ci				ivideo->sisvga_engine, realcrtno, 1,
233162306a36Sopenharmony_ci				&buffer[0], ivideo->vbflags2);
233262306a36Sopenharmony_ci	} while ((temp) && i--);
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci	if (temp)
233562306a36Sopenharmony_ci		return;
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_ci	/* No digital device */
233862306a36Sopenharmony_ci	if (!(buffer[0x14] & 0x80))
233962306a36Sopenharmony_ci		return;
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_ci	/* First detailed timing preferred timing? */
234262306a36Sopenharmony_ci	if (!(buffer[0x18] & 0x02))
234362306a36Sopenharmony_ci		return;
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci	xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
234662306a36Sopenharmony_ci	yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci	switch(xres) {
234962306a36Sopenharmony_ci		case 1024:
235062306a36Sopenharmony_ci			if (yres == 768)
235162306a36Sopenharmony_ci				paneltype = 0x02;
235262306a36Sopenharmony_ci			break;
235362306a36Sopenharmony_ci		case 1280:
235462306a36Sopenharmony_ci			if (yres == 1024)
235562306a36Sopenharmony_ci				paneltype = 0x03;
235662306a36Sopenharmony_ci			break;
235762306a36Sopenharmony_ci		case 1600:
235862306a36Sopenharmony_ci			if ((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
235962306a36Sopenharmony_ci				paneltype = 0x0b;
236062306a36Sopenharmony_ci			break;
236162306a36Sopenharmony_ci	}
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci	if (!paneltype)
236462306a36Sopenharmony_ci		return;
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci	if (buffer[0x23])
236762306a36Sopenharmony_ci		cr37 |= 0x10;
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci	if ((buffer[0x47] & 0x18) == 0x18)
237062306a36Sopenharmony_ci		cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
237162306a36Sopenharmony_ci	else
237262306a36Sopenharmony_ci		cr37 |= 0xc0;
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x36, paneltype);
237562306a36Sopenharmony_ci	cr37 &= 0xf1;
237662306a36Sopenharmony_ci	SiS_SetRegANDOR(SISCR, 0x37, 0x0c, cr37);
237762306a36Sopenharmony_ci	SiS_SetRegOR(SISCR, 0x32, 0x08);
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci	ivideo->SiS_Pr.PanelSelfDetected = true;
238062306a36Sopenharmony_ci}
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_cistatic int SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
238362306a36Sopenharmony_ci{
238462306a36Sopenharmony_ci	int temp, mytest, result, i, j;
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci	for (j = 0; j < 10; j++) {
238762306a36Sopenharmony_ci		result = 0;
238862306a36Sopenharmony_ci		for (i = 0; i < 3; i++) {
238962306a36Sopenharmony_ci			mytest = test;
239062306a36Sopenharmony_ci			SiS_SetReg(SISPART4, 0x11, (type & 0x00ff));
239162306a36Sopenharmony_ci			temp = (type >> 8) | (mytest & 0x00ff);
239262306a36Sopenharmony_ci			SiS_SetRegANDOR(SISPART4, 0x10, 0xe0, temp);
239362306a36Sopenharmony_ci			SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
239462306a36Sopenharmony_ci			mytest >>= 8;
239562306a36Sopenharmony_ci			mytest &= 0x7f;
239662306a36Sopenharmony_ci			temp = SiS_GetReg(SISPART4, 0x03);
239762306a36Sopenharmony_ci			temp ^= 0x0e;
239862306a36Sopenharmony_ci			temp &= mytest;
239962306a36Sopenharmony_ci			if (temp == mytest)
240062306a36Sopenharmony_ci				result++;
240162306a36Sopenharmony_ci#if 1
240262306a36Sopenharmony_ci			SiS_SetReg(SISPART4, 0x11, 0x00);
240362306a36Sopenharmony_ci			SiS_SetRegAND(SISPART4, 0x10, 0xe0);
240462306a36Sopenharmony_ci			SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
240562306a36Sopenharmony_ci#endif
240662306a36Sopenharmony_ci		}
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci		if ((result == 0) || (result >= 2))
240962306a36Sopenharmony_ci			break;
241062306a36Sopenharmony_ci	}
241162306a36Sopenharmony_ci	return result;
241262306a36Sopenharmony_ci}
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_cistatic void SiS_Sense30x(struct sis_video_info *ivideo)
241562306a36Sopenharmony_ci{
241662306a36Sopenharmony_ci    u8  backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
241762306a36Sopenharmony_ci    u16 svhs=0, svhs_c=0;
241862306a36Sopenharmony_ci    u16 cvbs=0, cvbs_c=0;
241962306a36Sopenharmony_ci    u16 vga2=0, vga2_c=0;
242062306a36Sopenharmony_ci    int myflag, result;
242162306a36Sopenharmony_ci    char stdstr[] = "sisfb: Detected";
242262306a36Sopenharmony_ci    char tvstr[]  = "TV connected to";
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_ci    if(ivideo->vbflags2 & VB2_301) {
242562306a36Sopenharmony_ci       svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
242662306a36Sopenharmony_ci       myflag = SiS_GetReg(SISPART4, 0x01);
242762306a36Sopenharmony_ci       if(myflag & 0x04) {
242862306a36Sopenharmony_ci	  svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
242962306a36Sopenharmony_ci       }
243062306a36Sopenharmony_ci    } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
243162306a36Sopenharmony_ci       svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
243262306a36Sopenharmony_ci    } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
243362306a36Sopenharmony_ci       svhs = 0x0200; cvbs = 0x0100;
243462306a36Sopenharmony_ci    } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
243562306a36Sopenharmony_ci       svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
243662306a36Sopenharmony_ci    } else
243762306a36Sopenharmony_ci       return;
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_ci    vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
244062306a36Sopenharmony_ci    if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
244162306a36Sopenharmony_ci       svhs_c = 0x0408; cvbs_c = 0x0808;
244262306a36Sopenharmony_ci    }
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci    biosflag = 2;
244562306a36Sopenharmony_ci    if(ivideo->haveXGIROM) {
244662306a36Sopenharmony_ci       biosflag = ivideo->bios_abase[0x58] & 0x03;
244762306a36Sopenharmony_ci    } else if(ivideo->newrom) {
244862306a36Sopenharmony_ci       if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
244962306a36Sopenharmony_ci    } else if(ivideo->sisvga_engine == SIS_300_VGA) {
245062306a36Sopenharmony_ci       if(ivideo->bios_abase) {
245162306a36Sopenharmony_ci          biosflag = ivideo->bios_abase[0xfe] & 0x03;
245262306a36Sopenharmony_ci       }
245362306a36Sopenharmony_ci    }
245462306a36Sopenharmony_ci
245562306a36Sopenharmony_ci    if(ivideo->chip == SIS_300) {
245662306a36Sopenharmony_ci       myflag = SiS_GetReg(SISSR, 0x3b);
245762306a36Sopenharmony_ci       if(!(myflag & 0x01)) vga2 = vga2_c = 0;
245862306a36Sopenharmony_ci    }
245962306a36Sopenharmony_ci
246062306a36Sopenharmony_ci    if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
246162306a36Sopenharmony_ci       vga2 = vga2_c = 0;
246262306a36Sopenharmony_ci    }
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ci    backupSR_1e = SiS_GetReg(SISSR, 0x1e);
246562306a36Sopenharmony_ci    SiS_SetRegOR(SISSR, 0x1e, 0x20);
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci    backupP4_0d = SiS_GetReg(SISPART4, 0x0d);
246862306a36Sopenharmony_ci    if(ivideo->vbflags2 & VB2_30xC) {
246962306a36Sopenharmony_ci	SiS_SetRegANDOR(SISPART4, 0x0d, ~0x07, 0x01);
247062306a36Sopenharmony_ci    } else {
247162306a36Sopenharmony_ci       SiS_SetRegOR(SISPART4, 0x0d, 0x04);
247262306a36Sopenharmony_ci    }
247362306a36Sopenharmony_ci    SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
247462306a36Sopenharmony_ci
247562306a36Sopenharmony_ci    backupP2_00 = SiS_GetReg(SISPART2, 0x00);
247662306a36Sopenharmony_ci    SiS_SetReg(SISPART2, 0x00, ((backupP2_00 | 0x1c) & 0xfc));
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_ci    backupP2_4d = SiS_GetReg(SISPART2, 0x4d);
247962306a36Sopenharmony_ci    if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
248062306a36Sopenharmony_ci	SiS_SetReg(SISPART2, 0x4d, (backupP2_4d & ~0x10));
248162306a36Sopenharmony_ci    }
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_ci    if(!(ivideo->vbflags2 & VB2_30xCLV)) {
248462306a36Sopenharmony_ci       SISDoSense(ivideo, 0, 0);
248562306a36Sopenharmony_ci    }
248662306a36Sopenharmony_ci
248762306a36Sopenharmony_ci    SiS_SetRegAND(SISCR, 0x32, ~0x14);
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_ci    if(vga2_c || vga2) {
249062306a36Sopenharmony_ci       if(SISDoSense(ivideo, vga2, vga2_c)) {
249162306a36Sopenharmony_ci          if(biosflag & 0x01) {
249262306a36Sopenharmony_ci	     printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
249362306a36Sopenharmony_ci	     SiS_SetRegOR(SISCR, 0x32, 0x04);
249462306a36Sopenharmony_ci	  } else {
249562306a36Sopenharmony_ci	     printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
249662306a36Sopenharmony_ci	     SiS_SetRegOR(SISCR, 0x32, 0x10);
249762306a36Sopenharmony_ci	  }
249862306a36Sopenharmony_ci       }
249962306a36Sopenharmony_ci    }
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ci    SiS_SetRegAND(SISCR, 0x32, 0x3f);
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ci    if(ivideo->vbflags2 & VB2_30xCLV) {
250462306a36Sopenharmony_ci       SiS_SetRegOR(SISPART4, 0x0d, 0x04);
250562306a36Sopenharmony_ci    }
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_ci    if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
250862306a36Sopenharmony_ci       SiS_SetReg(SISPART2, 0x4d, (backupP2_4d | 0x10));
250962306a36Sopenharmony_ci       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
251062306a36Sopenharmony_ci       if((result = SISDoSense(ivideo, svhs, 0x0604))) {
251162306a36Sopenharmony_ci          if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
251262306a36Sopenharmony_ci	     printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
251362306a36Sopenharmony_ci	     SiS_SetRegOR(SISCR, 0x32, 0x80);
251462306a36Sopenharmony_ci	  }
251562306a36Sopenharmony_ci       }
251662306a36Sopenharmony_ci       SiS_SetReg(SISPART2, 0x4d, backupP2_4d);
251762306a36Sopenharmony_ci    }
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ci    SiS_SetRegAND(SISCR, 0x32, ~0x03);
252062306a36Sopenharmony_ci
252162306a36Sopenharmony_ci    if(!(ivideo->vbflags & TV_YPBPR)) {
252262306a36Sopenharmony_ci       if((result = SISDoSense(ivideo, svhs, svhs_c))) {
252362306a36Sopenharmony_ci          printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
252462306a36Sopenharmony_ci	   SiS_SetRegOR(SISCR, 0x32, 0x02);
252562306a36Sopenharmony_ci       }
252662306a36Sopenharmony_ci       if((biosflag & 0x02) || (!result)) {
252762306a36Sopenharmony_ci          if(SISDoSense(ivideo, cvbs, cvbs_c)) {
252862306a36Sopenharmony_ci	     printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
252962306a36Sopenharmony_ci	     SiS_SetRegOR(SISCR, 0x32, 0x01);
253062306a36Sopenharmony_ci          }
253162306a36Sopenharmony_ci       }
253262306a36Sopenharmony_ci    }
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci    SISDoSense(ivideo, 0, 0);
253562306a36Sopenharmony_ci
253662306a36Sopenharmony_ci    SiS_SetReg(SISPART2, 0x00, backupP2_00);
253762306a36Sopenharmony_ci    SiS_SetReg(SISPART4, 0x0d, backupP4_0d);
253862306a36Sopenharmony_ci    SiS_SetReg(SISSR, 0x1e, backupSR_1e);
253962306a36Sopenharmony_ci
254062306a36Sopenharmony_ci    if(ivideo->vbflags2 & VB2_30xCLV) {
254162306a36Sopenharmony_ci	biosflag = SiS_GetReg(SISPART2, 0x00);
254262306a36Sopenharmony_ci       if(biosflag & 0x20) {
254362306a36Sopenharmony_ci          for(myflag = 2; myflag > 0; myflag--) {
254462306a36Sopenharmony_ci	     biosflag ^= 0x20;
254562306a36Sopenharmony_ci	     SiS_SetReg(SISPART2, 0x00, biosflag);
254662306a36Sopenharmony_ci	  }
254762306a36Sopenharmony_ci       }
254862306a36Sopenharmony_ci    }
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci    SiS_SetReg(SISPART2, 0x00, backupP2_00);
255162306a36Sopenharmony_ci}
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci/* Determine and detect attached TV's on Chrontel */
255462306a36Sopenharmony_cistatic void SiS_SenseCh(struct sis_video_info *ivideo)
255562306a36Sopenharmony_ci{
255662306a36Sopenharmony_ci#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
255762306a36Sopenharmony_ci    u8 temp1, temp2;
255862306a36Sopenharmony_ci    char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
255962306a36Sopenharmony_ci#endif
256062306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
256162306a36Sopenharmony_ci    unsigned char test[3];
256262306a36Sopenharmony_ci    int i;
256362306a36Sopenharmony_ci#endif
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_ci    if(ivideo->chip < SIS_315H) {
256662306a36Sopenharmony_ci
256762306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
256862306a36Sopenharmony_ci       ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1;		/* Chrontel 700x */
256962306a36Sopenharmony_ci       SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c);	/* Set general purpose IO for Chrontel communication */
257062306a36Sopenharmony_ci       SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
257162306a36Sopenharmony_ci       temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
257262306a36Sopenharmony_ci       /* See Chrontel TB31 for explanation */
257362306a36Sopenharmony_ci       temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
257462306a36Sopenharmony_ci       if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
257562306a36Sopenharmony_ci	  SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
257662306a36Sopenharmony_ci	  SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
257762306a36Sopenharmony_ci       }
257862306a36Sopenharmony_ci       temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
257962306a36Sopenharmony_ci       if(temp2 != temp1) temp1 = temp2;
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_ci       if((temp1 >= 0x22) && (temp1 <= 0x50)) {
258262306a36Sopenharmony_ci	   /* Read power status */
258362306a36Sopenharmony_ci	   temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
258462306a36Sopenharmony_ci	   if((temp1 & 0x03) != 0x03) {
258562306a36Sopenharmony_ci		/* Power all outputs */
258662306a36Sopenharmony_ci		SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
258762306a36Sopenharmony_ci		SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
258862306a36Sopenharmony_ci	   }
258962306a36Sopenharmony_ci	   /* Sense connected TV devices */
259062306a36Sopenharmony_ci	   for(i = 0; i < 3; i++) {
259162306a36Sopenharmony_ci	       SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
259262306a36Sopenharmony_ci	       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
259362306a36Sopenharmony_ci	       SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
259462306a36Sopenharmony_ci	       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
259562306a36Sopenharmony_ci	       temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
259662306a36Sopenharmony_ci	       if(!(temp1 & 0x08))       test[i] = 0x02;
259762306a36Sopenharmony_ci	       else if(!(temp1 & 0x02))  test[i] = 0x01;
259862306a36Sopenharmony_ci	       else                      test[i] = 0;
259962306a36Sopenharmony_ci	       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
260062306a36Sopenharmony_ci	   }
260162306a36Sopenharmony_ci
260262306a36Sopenharmony_ci	   if(test[0] == test[1])      temp1 = test[0];
260362306a36Sopenharmony_ci	   else if(test[0] == test[2]) temp1 = test[0];
260462306a36Sopenharmony_ci	   else if(test[1] == test[2]) temp1 = test[1];
260562306a36Sopenharmony_ci	   else {
260662306a36Sopenharmony_ci		printk(KERN_INFO
260762306a36Sopenharmony_ci			"sisfb: TV detection unreliable - test results varied\n");
260862306a36Sopenharmony_ci		temp1 = test[2];
260962306a36Sopenharmony_ci	   }
261062306a36Sopenharmony_ci	   if(temp1 == 0x02) {
261162306a36Sopenharmony_ci		printk(KERN_INFO "%s SVIDEO output\n", stdstr);
261262306a36Sopenharmony_ci		ivideo->vbflags |= TV_SVIDEO;
261362306a36Sopenharmony_ci		SiS_SetRegOR(SISCR, 0x32, 0x02);
261462306a36Sopenharmony_ci		SiS_SetRegAND(SISCR, 0x32, ~0x05);
261562306a36Sopenharmony_ci	   } else if (temp1 == 0x01) {
261662306a36Sopenharmony_ci		printk(KERN_INFO "%s CVBS output\n", stdstr);
261762306a36Sopenharmony_ci		ivideo->vbflags |= TV_AVIDEO;
261862306a36Sopenharmony_ci		SiS_SetRegOR(SISCR, 0x32, 0x01);
261962306a36Sopenharmony_ci		SiS_SetRegAND(SISCR, 0x32, ~0x06);
262062306a36Sopenharmony_ci	   } else {
262162306a36Sopenharmony_ci		SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
262262306a36Sopenharmony_ci		SiS_SetRegAND(SISCR, 0x32, ~0x07);
262362306a36Sopenharmony_ci	   }
262462306a36Sopenharmony_ci       } else if(temp1 == 0) {
262562306a36Sopenharmony_ci	  SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
262662306a36Sopenharmony_ci	  SiS_SetRegAND(SISCR, 0x32, ~0x07);
262762306a36Sopenharmony_ci       }
262862306a36Sopenharmony_ci       /* Set general purpose IO for Chrontel communication */
262962306a36Sopenharmony_ci       SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
263062306a36Sopenharmony_ci#endif
263162306a36Sopenharmony_ci
263262306a36Sopenharmony_ci    } else {
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
263562306a36Sopenharmony_ci	ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2;		/* Chrontel 7019 */
263662306a36Sopenharmony_ci	temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
263762306a36Sopenharmony_ci	SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
263862306a36Sopenharmony_ci	SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
263962306a36Sopenharmony_ci	temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
264062306a36Sopenharmony_ci	temp2 |= 0x01;
264162306a36Sopenharmony_ci	SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
264262306a36Sopenharmony_ci	SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
264362306a36Sopenharmony_ci	temp2 ^= 0x01;
264462306a36Sopenharmony_ci	SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
264562306a36Sopenharmony_ci	SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
264662306a36Sopenharmony_ci	temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
264762306a36Sopenharmony_ci	SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
264862306a36Sopenharmony_ci	temp1 = 0;
264962306a36Sopenharmony_ci	if(temp2 & 0x02) temp1 |= 0x01;
265062306a36Sopenharmony_ci	if(temp2 & 0x10) temp1 |= 0x01;
265162306a36Sopenharmony_ci	if(temp2 & 0x04) temp1 |= 0x02;
265262306a36Sopenharmony_ci	if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
265362306a36Sopenharmony_ci	switch(temp1) {
265462306a36Sopenharmony_ci	case 0x01:
265562306a36Sopenharmony_ci	     printk(KERN_INFO "%s CVBS output\n", stdstr);
265662306a36Sopenharmony_ci	     ivideo->vbflags |= TV_AVIDEO;
265762306a36Sopenharmony_ci	     SiS_SetRegOR(SISCR, 0x32, 0x01);
265862306a36Sopenharmony_ci	     SiS_SetRegAND(SISCR, 0x32, ~0x06);
265962306a36Sopenharmony_ci	     break;
266062306a36Sopenharmony_ci	case 0x02:
266162306a36Sopenharmony_ci	     printk(KERN_INFO "%s SVIDEO output\n", stdstr);
266262306a36Sopenharmony_ci	     ivideo->vbflags |= TV_SVIDEO;
266362306a36Sopenharmony_ci	     SiS_SetRegOR(SISCR, 0x32, 0x02);
266462306a36Sopenharmony_ci	     SiS_SetRegAND(SISCR, 0x32, ~0x05);
266562306a36Sopenharmony_ci	     break;
266662306a36Sopenharmony_ci	case 0x04:
266762306a36Sopenharmony_ci	     printk(KERN_INFO "%s SCART output\n", stdstr);
266862306a36Sopenharmony_ci	     SiS_SetRegOR(SISCR, 0x32, 0x04);
266962306a36Sopenharmony_ci	     SiS_SetRegAND(SISCR, 0x32, ~0x03);
267062306a36Sopenharmony_ci	     break;
267162306a36Sopenharmony_ci	default:
267262306a36Sopenharmony_ci	     SiS_SetRegAND(SISCR, 0x32, ~0x07);
267362306a36Sopenharmony_ci	}
267462306a36Sopenharmony_ci#endif
267562306a36Sopenharmony_ci    }
267662306a36Sopenharmony_ci}
267762306a36Sopenharmony_ci
267862306a36Sopenharmony_cistatic void sisfb_get_VB_type(struct sis_video_info *ivideo)
267962306a36Sopenharmony_ci{
268062306a36Sopenharmony_ci	char stdstr[]    = "sisfb: Detected";
268162306a36Sopenharmony_ci	char bridgestr[] = "video bridge";
268262306a36Sopenharmony_ci	u8 vb_chipid;
268362306a36Sopenharmony_ci	u8 reg;
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_ci	/* No CRT2 on XGI Z7 */
268662306a36Sopenharmony_ci	if(ivideo->chip == XGI_20)
268762306a36Sopenharmony_ci		return;
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_ci	vb_chipid = SiS_GetReg(SISPART4, 0x00);
269062306a36Sopenharmony_ci	switch(vb_chipid) {
269162306a36Sopenharmony_ci	case 0x01:
269262306a36Sopenharmony_ci		reg = SiS_GetReg(SISPART4, 0x01);
269362306a36Sopenharmony_ci		if(reg < 0xb0) {
269462306a36Sopenharmony_ci			ivideo->vbflags |= VB_301;	/* Deprecated */
269562306a36Sopenharmony_ci			ivideo->vbflags2 |= VB2_301;
269662306a36Sopenharmony_ci			printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
269762306a36Sopenharmony_ci		} else if(reg < 0xc0) {
269862306a36Sopenharmony_ci			ivideo->vbflags |= VB_301B;	/* Deprecated */
269962306a36Sopenharmony_ci			ivideo->vbflags2 |= VB2_301B;
270062306a36Sopenharmony_ci			reg = SiS_GetReg(SISPART4, 0x23);
270162306a36Sopenharmony_ci			if(!(reg & 0x02)) {
270262306a36Sopenharmony_ci			   ivideo->vbflags |= VB_30xBDH;	/* Deprecated */
270362306a36Sopenharmony_ci			   ivideo->vbflags2 |= VB2_30xBDH;
270462306a36Sopenharmony_ci			   printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
270562306a36Sopenharmony_ci			} else {
270662306a36Sopenharmony_ci			   printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
270762306a36Sopenharmony_ci			}
270862306a36Sopenharmony_ci		} else if(reg < 0xd0) {
270962306a36Sopenharmony_ci			ivideo->vbflags |= VB_301C;	/* Deprecated */
271062306a36Sopenharmony_ci			ivideo->vbflags2 |= VB2_301C;
271162306a36Sopenharmony_ci			printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
271262306a36Sopenharmony_ci		} else if(reg < 0xe0) {
271362306a36Sopenharmony_ci			ivideo->vbflags |= VB_301LV;	/* Deprecated */
271462306a36Sopenharmony_ci			ivideo->vbflags2 |= VB2_301LV;
271562306a36Sopenharmony_ci			printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
271662306a36Sopenharmony_ci		} else if(reg <= 0xe1) {
271762306a36Sopenharmony_ci			reg = SiS_GetReg(SISPART4, 0x39);
271862306a36Sopenharmony_ci			if(reg == 0xff) {
271962306a36Sopenharmony_ci			   ivideo->vbflags |= VB_302LV;	/* Deprecated */
272062306a36Sopenharmony_ci			   ivideo->vbflags2 |= VB2_302LV;
272162306a36Sopenharmony_ci			   printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
272262306a36Sopenharmony_ci			} else {
272362306a36Sopenharmony_ci			   ivideo->vbflags |= VB_301C;	/* Deprecated */
272462306a36Sopenharmony_ci			   ivideo->vbflags2 |= VB2_301C;
272562306a36Sopenharmony_ci			   printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
272662306a36Sopenharmony_ci#if 0
272762306a36Sopenharmony_ci			   ivideo->vbflags |= VB_302ELV;	/* Deprecated */
272862306a36Sopenharmony_ci			   ivideo->vbflags2 |= VB2_302ELV;
272962306a36Sopenharmony_ci			   printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
273062306a36Sopenharmony_ci#endif
273162306a36Sopenharmony_ci			}
273262306a36Sopenharmony_ci		}
273362306a36Sopenharmony_ci		break;
273462306a36Sopenharmony_ci	case 0x02:
273562306a36Sopenharmony_ci		ivideo->vbflags |= VB_302B;	/* Deprecated */
273662306a36Sopenharmony_ci		ivideo->vbflags2 |= VB2_302B;
273762306a36Sopenharmony_ci		printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
273862306a36Sopenharmony_ci		break;
273962306a36Sopenharmony_ci	}
274062306a36Sopenharmony_ci
274162306a36Sopenharmony_ci	if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
274262306a36Sopenharmony_ci		reg = SiS_GetReg(SISCR, 0x37);
274362306a36Sopenharmony_ci		reg &= SIS_EXTERNAL_CHIP_MASK;
274462306a36Sopenharmony_ci		reg >>= 1;
274562306a36Sopenharmony_ci		if(ivideo->sisvga_engine == SIS_300_VGA) {
274662306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
274762306a36Sopenharmony_ci			switch(reg) {
274862306a36Sopenharmony_ci			   case SIS_EXTERNAL_CHIP_LVDS:
274962306a36Sopenharmony_ci				ivideo->vbflags |= VB_LVDS;	/* Deprecated */
275062306a36Sopenharmony_ci				ivideo->vbflags2 |= VB2_LVDS;
275162306a36Sopenharmony_ci				break;
275262306a36Sopenharmony_ci			   case SIS_EXTERNAL_CHIP_TRUMPION:
275362306a36Sopenharmony_ci				ivideo->vbflags |= (VB_LVDS | VB_TRUMPION);	/* Deprecated */
275462306a36Sopenharmony_ci				ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
275562306a36Sopenharmony_ci				break;
275662306a36Sopenharmony_ci			   case SIS_EXTERNAL_CHIP_CHRONTEL:
275762306a36Sopenharmony_ci				ivideo->vbflags |= VB_CHRONTEL;	/* Deprecated */
275862306a36Sopenharmony_ci				ivideo->vbflags2 |= VB2_CHRONTEL;
275962306a36Sopenharmony_ci				break;
276062306a36Sopenharmony_ci			   case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
276162306a36Sopenharmony_ci				ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);	/* Deprecated */
276262306a36Sopenharmony_ci				ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
276362306a36Sopenharmony_ci				break;
276462306a36Sopenharmony_ci			}
276562306a36Sopenharmony_ci			if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
276662306a36Sopenharmony_ci#endif
276762306a36Sopenharmony_ci		} else if(ivideo->chip < SIS_661) {
276862306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
276962306a36Sopenharmony_ci			switch (reg) {
277062306a36Sopenharmony_ci			   case SIS310_EXTERNAL_CHIP_LVDS:
277162306a36Sopenharmony_ci				ivideo->vbflags |= VB_LVDS;	/* Deprecated */
277262306a36Sopenharmony_ci				ivideo->vbflags2 |= VB2_LVDS;
277362306a36Sopenharmony_ci				break;
277462306a36Sopenharmony_ci			   case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
277562306a36Sopenharmony_ci				ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);	/* Deprecated */
277662306a36Sopenharmony_ci				ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
277762306a36Sopenharmony_ci				break;
277862306a36Sopenharmony_ci			}
277962306a36Sopenharmony_ci			if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
278062306a36Sopenharmony_ci#endif
278162306a36Sopenharmony_ci		} else if(ivideo->chip >= SIS_661) {
278262306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
278362306a36Sopenharmony_ci			reg = SiS_GetReg(SISCR, 0x38);
278462306a36Sopenharmony_ci			reg >>= 5;
278562306a36Sopenharmony_ci			switch(reg) {
278662306a36Sopenharmony_ci			   case 0x02:
278762306a36Sopenharmony_ci				ivideo->vbflags |= VB_LVDS;	/* Deprecated */
278862306a36Sopenharmony_ci				ivideo->vbflags2 |= VB2_LVDS;
278962306a36Sopenharmony_ci				break;
279062306a36Sopenharmony_ci			   case 0x03:
279162306a36Sopenharmony_ci				ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);	/* Deprecated */
279262306a36Sopenharmony_ci				ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
279362306a36Sopenharmony_ci				break;
279462306a36Sopenharmony_ci			   case 0x04:
279562306a36Sopenharmony_ci				ivideo->vbflags |= (VB_LVDS | VB_CONEXANT);	/* Deprecated */
279662306a36Sopenharmony_ci				ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
279762306a36Sopenharmony_ci				break;
279862306a36Sopenharmony_ci			}
279962306a36Sopenharmony_ci			if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
280062306a36Sopenharmony_ci#endif
280162306a36Sopenharmony_ci		}
280262306a36Sopenharmony_ci		if(ivideo->vbflags2 & VB2_LVDS) {
280362306a36Sopenharmony_ci		   printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
280462306a36Sopenharmony_ci		}
280562306a36Sopenharmony_ci		if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
280662306a36Sopenharmony_ci		   printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
280762306a36Sopenharmony_ci		}
280862306a36Sopenharmony_ci		if(ivideo->vbflags2 & VB2_CHRONTEL) {
280962306a36Sopenharmony_ci		   printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
281062306a36Sopenharmony_ci		}
281162306a36Sopenharmony_ci		if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
281262306a36Sopenharmony_ci		   printk(KERN_INFO "%s Conexant external device\n", stdstr);
281362306a36Sopenharmony_ci		}
281462306a36Sopenharmony_ci	}
281562306a36Sopenharmony_ci
281662306a36Sopenharmony_ci	if(ivideo->vbflags2 & VB2_SISBRIDGE) {
281762306a36Sopenharmony_ci		SiS_SenseLCD(ivideo);
281862306a36Sopenharmony_ci		SiS_Sense30x(ivideo);
281962306a36Sopenharmony_ci	} else if(ivideo->vbflags2 & VB2_CHRONTEL) {
282062306a36Sopenharmony_ci		SiS_SenseCh(ivideo);
282162306a36Sopenharmony_ci	}
282262306a36Sopenharmony_ci}
282362306a36Sopenharmony_ci
282462306a36Sopenharmony_ci/* ---------- Engine initialization routines ------------ */
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_cistatic void
282762306a36Sopenharmony_cisisfb_engine_init(struct sis_video_info *ivideo)
282862306a36Sopenharmony_ci{
282962306a36Sopenharmony_ci
283062306a36Sopenharmony_ci	/* Initialize command queue (we use MMIO only) */
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_ci	/* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
283362306a36Sopenharmony_ci
283462306a36Sopenharmony_ci	ivideo->caps &= ~(TURBO_QUEUE_CAP    |
283562306a36Sopenharmony_ci			  MMIO_CMD_QUEUE_CAP |
283662306a36Sopenharmony_ci			  VM_CMD_QUEUE_CAP   |
283762306a36Sopenharmony_ci			  AGP_CMD_QUEUE_CAP);
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
284062306a36Sopenharmony_ci	if(ivideo->sisvga_engine == SIS_300_VGA) {
284162306a36Sopenharmony_ci		u32 tqueue_pos;
284262306a36Sopenharmony_ci		u8 tq_state;
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci		tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
284562306a36Sopenharmony_ci
284662306a36Sopenharmony_ci		tq_state = SiS_GetReg(SISSR, IND_SIS_TURBOQUEUE_SET);
284762306a36Sopenharmony_ci		tq_state |= 0xf0;
284862306a36Sopenharmony_ci		tq_state &= 0xfc;
284962306a36Sopenharmony_ci		tq_state |= (u8)(tqueue_pos >> 8);
285062306a36Sopenharmony_ci		SiS_SetReg(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
285162306a36Sopenharmony_ci
285262306a36Sopenharmony_ci		SiS_SetReg(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
285362306a36Sopenharmony_ci
285462306a36Sopenharmony_ci		ivideo->caps |= TURBO_QUEUE_CAP;
285562306a36Sopenharmony_ci	}
285662306a36Sopenharmony_ci#endif
285762306a36Sopenharmony_ci
285862306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
285962306a36Sopenharmony_ci	if(ivideo->sisvga_engine == SIS_315_VGA) {
286062306a36Sopenharmony_ci		u32 tempq = 0, templ;
286162306a36Sopenharmony_ci		u8  temp;
286262306a36Sopenharmony_ci
286362306a36Sopenharmony_ci		if(ivideo->chip == XGI_20) {
286462306a36Sopenharmony_ci			switch(ivideo->cmdQueueSize) {
286562306a36Sopenharmony_ci			case (64 * 1024):
286662306a36Sopenharmony_ci				temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
286762306a36Sopenharmony_ci				break;
286862306a36Sopenharmony_ci			case (128 * 1024):
286962306a36Sopenharmony_ci			default:
287062306a36Sopenharmony_ci				temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
287162306a36Sopenharmony_ci			}
287262306a36Sopenharmony_ci		} else {
287362306a36Sopenharmony_ci			switch(ivideo->cmdQueueSize) {
287462306a36Sopenharmony_ci			case (4 * 1024 * 1024):
287562306a36Sopenharmony_ci				temp = SIS_CMD_QUEUE_SIZE_4M;
287662306a36Sopenharmony_ci				break;
287762306a36Sopenharmony_ci			case (2 * 1024 * 1024):
287862306a36Sopenharmony_ci				temp = SIS_CMD_QUEUE_SIZE_2M;
287962306a36Sopenharmony_ci				break;
288062306a36Sopenharmony_ci			case (1 * 1024 * 1024):
288162306a36Sopenharmony_ci				temp = SIS_CMD_QUEUE_SIZE_1M;
288262306a36Sopenharmony_ci				break;
288362306a36Sopenharmony_ci			default:
288462306a36Sopenharmony_ci			case (512 * 1024):
288562306a36Sopenharmony_ci				temp = SIS_CMD_QUEUE_SIZE_512k;
288662306a36Sopenharmony_ci			}
288762306a36Sopenharmony_ci		}
288862306a36Sopenharmony_ci
288962306a36Sopenharmony_ci		SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
289062306a36Sopenharmony_ci		SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
289162306a36Sopenharmony_ci
289262306a36Sopenharmony_ci		if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
289362306a36Sopenharmony_ci			/* Must disable dual pipe on XGI_40. Can't do
289462306a36Sopenharmony_ci			 * this in MMIO mode, because it requires
289562306a36Sopenharmony_ci			 * setting/clearing a bit in the MMIO fire trigger
289662306a36Sopenharmony_ci			 * register.
289762306a36Sopenharmony_ci			 */
289862306a36Sopenharmony_ci			if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_ci				MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
290162306a36Sopenharmony_ci
290262306a36Sopenharmony_ci				SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
290362306a36Sopenharmony_ci
290462306a36Sopenharmony_ci				tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
290562306a36Sopenharmony_ci				MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
290662306a36Sopenharmony_ci
290762306a36Sopenharmony_ci				tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
290862306a36Sopenharmony_ci				MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci				writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
291162306a36Sopenharmony_ci				writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
291262306a36Sopenharmony_ci				writel(0x168F0000, ivideo->video_vbase + tempq + 8);
291362306a36Sopenharmony_ci				writel(0x168F0000, ivideo->video_vbase + tempq + 12);
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_ci				MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ci				sisfb_syncaccel(ivideo);
291862306a36Sopenharmony_ci
291962306a36Sopenharmony_ci				SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
292062306a36Sopenharmony_ci
292162306a36Sopenharmony_ci			}
292262306a36Sopenharmony_ci		}
292362306a36Sopenharmony_ci
292462306a36Sopenharmony_ci		tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
292562306a36Sopenharmony_ci		MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
292662306a36Sopenharmony_ci
292762306a36Sopenharmony_ci		temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
292862306a36Sopenharmony_ci		SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, temp);
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_ci		tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
293162306a36Sopenharmony_ci		MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
293262306a36Sopenharmony_ci
293362306a36Sopenharmony_ci		ivideo->caps |= MMIO_CMD_QUEUE_CAP;
293462306a36Sopenharmony_ci	}
293562306a36Sopenharmony_ci#endif
293662306a36Sopenharmony_ci
293762306a36Sopenharmony_ci	ivideo->engineok = 1;
293862306a36Sopenharmony_ci}
293962306a36Sopenharmony_ci
294062306a36Sopenharmony_cistatic void sisfb_detect_lcd_type(struct sis_video_info *ivideo)
294162306a36Sopenharmony_ci{
294262306a36Sopenharmony_ci	u8 reg;
294362306a36Sopenharmony_ci	int i;
294462306a36Sopenharmony_ci
294562306a36Sopenharmony_ci	reg = SiS_GetReg(SISCR, 0x36);
294662306a36Sopenharmony_ci	reg &= 0x0f;
294762306a36Sopenharmony_ci	if(ivideo->sisvga_engine == SIS_300_VGA) {
294862306a36Sopenharmony_ci		ivideo->CRT2LCDType = sis300paneltype[reg];
294962306a36Sopenharmony_ci	} else if(ivideo->chip >= SIS_661) {
295062306a36Sopenharmony_ci		ivideo->CRT2LCDType = sis661paneltype[reg];
295162306a36Sopenharmony_ci	} else {
295262306a36Sopenharmony_ci		ivideo->CRT2LCDType = sis310paneltype[reg];
295362306a36Sopenharmony_ci		if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
295462306a36Sopenharmony_ci			if((ivideo->CRT2LCDType != LCD_320x240_2) &&
295562306a36Sopenharmony_ci			   (ivideo->CRT2LCDType != LCD_320x240_3)) {
295662306a36Sopenharmony_ci				ivideo->CRT2LCDType = LCD_320x240;
295762306a36Sopenharmony_ci			}
295862306a36Sopenharmony_ci		}
295962306a36Sopenharmony_ci	}
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_ci	if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
296262306a36Sopenharmony_ci		/* For broken BIOSes: Assume 1024x768, RGB18 */
296362306a36Sopenharmony_ci		ivideo->CRT2LCDType = LCD_1024x768;
296462306a36Sopenharmony_ci		SiS_SetRegANDOR(SISCR, 0x36, 0xf0, 0x02);
296562306a36Sopenharmony_ci		SiS_SetRegANDOR(SISCR, 0x37, 0xee, 0x01);
296662306a36Sopenharmony_ci		printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
296762306a36Sopenharmony_ci	}
296862306a36Sopenharmony_ci
296962306a36Sopenharmony_ci	for(i = 0; i < SIS_LCD_NUMBER; i++) {
297062306a36Sopenharmony_ci		if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
297162306a36Sopenharmony_ci			ivideo->lcdxres = sis_lcd_data[i].xres;
297262306a36Sopenharmony_ci			ivideo->lcdyres = sis_lcd_data[i].yres;
297362306a36Sopenharmony_ci			ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
297462306a36Sopenharmony_ci			break;
297562306a36Sopenharmony_ci		}
297662306a36Sopenharmony_ci	}
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
297962306a36Sopenharmony_ci	if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
298062306a36Sopenharmony_ci		ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
298162306a36Sopenharmony_ci		ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
298262306a36Sopenharmony_ci	} else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
298362306a36Sopenharmony_ci		ivideo->lcdxres =  848; ivideo->lcdyres =  480;
298462306a36Sopenharmony_ci		ivideo->lcddefmodeidx = DEFAULT_MODE_848;
298562306a36Sopenharmony_ci	} else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
298662306a36Sopenharmony_ci		ivideo->lcdxres =  856; ivideo->lcdyres =  480;
298762306a36Sopenharmony_ci		ivideo->lcddefmodeidx = DEFAULT_MODE_856;
298862306a36Sopenharmony_ci	}
298962306a36Sopenharmony_ci#endif
299062306a36Sopenharmony_ci
299162306a36Sopenharmony_ci	printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
299262306a36Sopenharmony_ci			ivideo->lcdxres, ivideo->lcdyres);
299362306a36Sopenharmony_ci}
299462306a36Sopenharmony_ci
299562306a36Sopenharmony_cistatic void sisfb_save_pdc_emi(struct sis_video_info *ivideo)
299662306a36Sopenharmony_ci{
299762306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
299862306a36Sopenharmony_ci	/* Save the current PanelDelayCompensation if the LCD is currently used */
299962306a36Sopenharmony_ci	if(ivideo->sisvga_engine == SIS_300_VGA) {
300062306a36Sopenharmony_ci		if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
300162306a36Sopenharmony_ci			int tmp;
300262306a36Sopenharmony_ci			tmp = SiS_GetReg(SISCR, 0x30);
300362306a36Sopenharmony_ci			if(tmp & 0x20) {
300462306a36Sopenharmony_ci				/* Currently on LCD? If yes, read current pdc */
300562306a36Sopenharmony_ci				ivideo->detectedpdc = SiS_GetReg(SISPART1, 0x13);
300662306a36Sopenharmony_ci				ivideo->detectedpdc &= 0x3c;
300762306a36Sopenharmony_ci				if(ivideo->SiS_Pr.PDC == -1) {
300862306a36Sopenharmony_ci					/* Let option override detection */
300962306a36Sopenharmony_ci					ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
301062306a36Sopenharmony_ci				}
301162306a36Sopenharmony_ci				printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
301262306a36Sopenharmony_ci					ivideo->detectedpdc);
301362306a36Sopenharmony_ci			}
301462306a36Sopenharmony_ci			if((ivideo->SiS_Pr.PDC != -1) &&
301562306a36Sopenharmony_ci			   (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
301662306a36Sopenharmony_ci				printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
301762306a36Sopenharmony_ci					ivideo->SiS_Pr.PDC);
301862306a36Sopenharmony_ci			}
301962306a36Sopenharmony_ci		}
302062306a36Sopenharmony_ci	}
302162306a36Sopenharmony_ci#endif
302262306a36Sopenharmony_ci
302362306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
302462306a36Sopenharmony_ci	if(ivideo->sisvga_engine == SIS_315_VGA) {
302562306a36Sopenharmony_ci
302662306a36Sopenharmony_ci		/* Try to find about LCDA */
302762306a36Sopenharmony_ci		if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
302862306a36Sopenharmony_ci			int tmp;
302962306a36Sopenharmony_ci			tmp = SiS_GetReg(SISPART1, 0x13);
303062306a36Sopenharmony_ci			if(tmp & 0x04) {
303162306a36Sopenharmony_ci				ivideo->SiS_Pr.SiS_UseLCDA = true;
303262306a36Sopenharmony_ci				ivideo->detectedlcda = 0x03;
303362306a36Sopenharmony_ci			}
303462306a36Sopenharmony_ci		}
303562306a36Sopenharmony_ci
303662306a36Sopenharmony_ci		/* Save PDC */
303762306a36Sopenharmony_ci		if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
303862306a36Sopenharmony_ci			int tmp;
303962306a36Sopenharmony_ci			tmp = SiS_GetReg(SISCR, 0x30);
304062306a36Sopenharmony_ci			if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
304162306a36Sopenharmony_ci				/* Currently on LCD? If yes, read current pdc */
304262306a36Sopenharmony_ci				u8 pdc;
304362306a36Sopenharmony_ci				pdc = SiS_GetReg(SISPART1, 0x2D);
304462306a36Sopenharmony_ci				ivideo->detectedpdc  = (pdc & 0x0f) << 1;
304562306a36Sopenharmony_ci				ivideo->detectedpdca = (pdc & 0xf0) >> 3;
304662306a36Sopenharmony_ci				pdc = SiS_GetReg(SISPART1, 0x35);
304762306a36Sopenharmony_ci				ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
304862306a36Sopenharmony_ci				pdc = SiS_GetReg(SISPART1, 0x20);
304962306a36Sopenharmony_ci				ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
305062306a36Sopenharmony_ci				if(ivideo->newrom) {
305162306a36Sopenharmony_ci					/* New ROM invalidates other PDC resp. */
305262306a36Sopenharmony_ci					if(ivideo->detectedlcda != 0xff) {
305362306a36Sopenharmony_ci						ivideo->detectedpdc = 0xff;
305462306a36Sopenharmony_ci					} else {
305562306a36Sopenharmony_ci						ivideo->detectedpdca = 0xff;
305662306a36Sopenharmony_ci					}
305762306a36Sopenharmony_ci				}
305862306a36Sopenharmony_ci				if(ivideo->SiS_Pr.PDC == -1) {
305962306a36Sopenharmony_ci					if(ivideo->detectedpdc != 0xff) {
306062306a36Sopenharmony_ci						ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
306162306a36Sopenharmony_ci					}
306262306a36Sopenharmony_ci				}
306362306a36Sopenharmony_ci				if(ivideo->SiS_Pr.PDCA == -1) {
306462306a36Sopenharmony_ci					if(ivideo->detectedpdca != 0xff) {
306562306a36Sopenharmony_ci						ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
306662306a36Sopenharmony_ci					}
306762306a36Sopenharmony_ci				}
306862306a36Sopenharmony_ci				if(ivideo->detectedpdc != 0xff) {
306962306a36Sopenharmony_ci					printk(KERN_INFO
307062306a36Sopenharmony_ci						"sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
307162306a36Sopenharmony_ci						ivideo->detectedpdc);
307262306a36Sopenharmony_ci				}
307362306a36Sopenharmony_ci				if(ivideo->detectedpdca != 0xff) {
307462306a36Sopenharmony_ci					printk(KERN_INFO
307562306a36Sopenharmony_ci						"sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
307662306a36Sopenharmony_ci						ivideo->detectedpdca);
307762306a36Sopenharmony_ci				}
307862306a36Sopenharmony_ci			}
307962306a36Sopenharmony_ci
308062306a36Sopenharmony_ci			/* Save EMI */
308162306a36Sopenharmony_ci			if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
308262306a36Sopenharmony_ci				ivideo->SiS_Pr.EMI_30 = SiS_GetReg(SISPART4, 0x30);
308362306a36Sopenharmony_ci				ivideo->SiS_Pr.EMI_31 = SiS_GetReg(SISPART4, 0x31);
308462306a36Sopenharmony_ci				ivideo->SiS_Pr.EMI_32 = SiS_GetReg(SISPART4, 0x32);
308562306a36Sopenharmony_ci				ivideo->SiS_Pr.EMI_33 = SiS_GetReg(SISPART4, 0x33);
308662306a36Sopenharmony_ci				ivideo->SiS_Pr.HaveEMI = true;
308762306a36Sopenharmony_ci				if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
308862306a36Sopenharmony_ci					ivideo->SiS_Pr.HaveEMILCD = true;
308962306a36Sopenharmony_ci				}
309062306a36Sopenharmony_ci			}
309162306a36Sopenharmony_ci		}
309262306a36Sopenharmony_ci
309362306a36Sopenharmony_ci		/* Let user override detected PDCs (all bridges) */
309462306a36Sopenharmony_ci		if(ivideo->vbflags2 & VB2_30xBLV) {
309562306a36Sopenharmony_ci			if((ivideo->SiS_Pr.PDC != -1) &&
309662306a36Sopenharmony_ci			   (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
309762306a36Sopenharmony_ci				printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
309862306a36Sopenharmony_ci					ivideo->SiS_Pr.PDC);
309962306a36Sopenharmony_ci			}
310062306a36Sopenharmony_ci			if((ivideo->SiS_Pr.PDCA != -1) &&
310162306a36Sopenharmony_ci			   (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
310262306a36Sopenharmony_ci				printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
310362306a36Sopenharmony_ci				 ivideo->SiS_Pr.PDCA);
310462306a36Sopenharmony_ci			}
310562306a36Sopenharmony_ci		}
310662306a36Sopenharmony_ci
310762306a36Sopenharmony_ci	}
310862306a36Sopenharmony_ci#endif
310962306a36Sopenharmony_ci}
311062306a36Sopenharmony_ci
311162306a36Sopenharmony_ci/* -------------------- Memory manager routines ---------------------- */
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_cistatic u32 sisfb_getheapstart(struct sis_video_info *ivideo)
311462306a36Sopenharmony_ci{
311562306a36Sopenharmony_ci	u32 ret = ivideo->sisfb_parm_mem * 1024;
311662306a36Sopenharmony_ci	u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
311762306a36Sopenharmony_ci	u32 def;
311862306a36Sopenharmony_ci
311962306a36Sopenharmony_ci	/* Calculate heap start = end of memory for console
312062306a36Sopenharmony_ci	 *
312162306a36Sopenharmony_ci	 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
312262306a36Sopenharmony_ci	 * C = console, D = heap, H = HWCursor, Q = cmd-queue
312362306a36Sopenharmony_ci	 *
312462306a36Sopenharmony_ci	 * On 76x in UMA+LFB mode, the layout is as follows:
312562306a36Sopenharmony_ci	 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
312662306a36Sopenharmony_ci	 * where the heap is the entire UMA area, eventually
312762306a36Sopenharmony_ci	 * into the LFB area if the given mem parameter is
312862306a36Sopenharmony_ci	 * higher than the size of the UMA memory.
312962306a36Sopenharmony_ci	 *
313062306a36Sopenharmony_ci	 * Basically given by "mem" parameter
313162306a36Sopenharmony_ci	 *
313262306a36Sopenharmony_ci	 * maximum = videosize - cmd_queue - hwcursor
313362306a36Sopenharmony_ci	 *           (results in a heap of size 0)
313462306a36Sopenharmony_ci	 * default = SiS 300: depends on videosize
313562306a36Sopenharmony_ci	 *           SiS 315/330/340/XGI: 32k below max
313662306a36Sopenharmony_ci	 */
313762306a36Sopenharmony_ci
313862306a36Sopenharmony_ci	if(ivideo->sisvga_engine == SIS_300_VGA) {
313962306a36Sopenharmony_ci		if(ivideo->video_size > 0x1000000) {
314062306a36Sopenharmony_ci			def = 0xc00000;
314162306a36Sopenharmony_ci		} else if(ivideo->video_size > 0x800000) {
314262306a36Sopenharmony_ci			def = 0x800000;
314362306a36Sopenharmony_ci		} else {
314462306a36Sopenharmony_ci			def = 0x400000;
314562306a36Sopenharmony_ci		}
314662306a36Sopenharmony_ci	} else if(ivideo->UMAsize && ivideo->LFBsize) {
314762306a36Sopenharmony_ci		ret = def = 0;
314862306a36Sopenharmony_ci	} else {
314962306a36Sopenharmony_ci		def = maxoffs - 0x8000;
315062306a36Sopenharmony_ci	}
315162306a36Sopenharmony_ci
315262306a36Sopenharmony_ci	/* Use default for secondary card for now (FIXME) */
315362306a36Sopenharmony_ci	if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
315462306a36Sopenharmony_ci		ret = def;
315562306a36Sopenharmony_ci
315662306a36Sopenharmony_ci	return ret;
315762306a36Sopenharmony_ci}
315862306a36Sopenharmony_ci
315962306a36Sopenharmony_cistatic u32 sisfb_getheapsize(struct sis_video_info *ivideo)
316062306a36Sopenharmony_ci{
316162306a36Sopenharmony_ci	u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
316262306a36Sopenharmony_ci	u32 ret = 0;
316362306a36Sopenharmony_ci
316462306a36Sopenharmony_ci	if(ivideo->UMAsize && ivideo->LFBsize) {
316562306a36Sopenharmony_ci		if( (!ivideo->sisfb_parm_mem)			||
316662306a36Sopenharmony_ci		    ((ivideo->sisfb_parm_mem * 1024) > max)	||
316762306a36Sopenharmony_ci		    ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
316862306a36Sopenharmony_ci			ret = ivideo->UMAsize;
316962306a36Sopenharmony_ci			max -= ivideo->UMAsize;
317062306a36Sopenharmony_ci		} else {
317162306a36Sopenharmony_ci			ret = max - (ivideo->sisfb_parm_mem * 1024);
317262306a36Sopenharmony_ci			max = ivideo->sisfb_parm_mem * 1024;
317362306a36Sopenharmony_ci		}
317462306a36Sopenharmony_ci		ivideo->video_offset = ret;
317562306a36Sopenharmony_ci		ivideo->sisfb_mem = max;
317662306a36Sopenharmony_ci	} else {
317762306a36Sopenharmony_ci		ret = max - ivideo->heapstart;
317862306a36Sopenharmony_ci		ivideo->sisfb_mem = ivideo->heapstart;
317962306a36Sopenharmony_ci	}
318062306a36Sopenharmony_ci
318162306a36Sopenharmony_ci	return ret;
318262306a36Sopenharmony_ci}
318362306a36Sopenharmony_ci
318462306a36Sopenharmony_cistatic int sisfb_heap_init(struct sis_video_info *ivideo)
318562306a36Sopenharmony_ci{
318662306a36Sopenharmony_ci	struct SIS_OH *poh;
318762306a36Sopenharmony_ci
318862306a36Sopenharmony_ci	ivideo->video_offset = 0;
318962306a36Sopenharmony_ci	if(ivideo->sisfb_parm_mem) {
319062306a36Sopenharmony_ci		if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
319162306a36Sopenharmony_ci		    (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
319262306a36Sopenharmony_ci			ivideo->sisfb_parm_mem = 0;
319362306a36Sopenharmony_ci		}
319462306a36Sopenharmony_ci	}
319562306a36Sopenharmony_ci
319662306a36Sopenharmony_ci	ivideo->heapstart = sisfb_getheapstart(ivideo);
319762306a36Sopenharmony_ci	ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
319862306a36Sopenharmony_ci
319962306a36Sopenharmony_ci	ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
320062306a36Sopenharmony_ci	ivideo->sisfb_heap_end   = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
320162306a36Sopenharmony_ci
320262306a36Sopenharmony_ci	printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
320362306a36Sopenharmony_ci		(int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
320462306a36Sopenharmony_ci
320562306a36Sopenharmony_ci	ivideo->sisfb_heap.vinfo = ivideo;
320662306a36Sopenharmony_ci
320762306a36Sopenharmony_ci	ivideo->sisfb_heap.poha_chain = NULL;
320862306a36Sopenharmony_ci	ivideo->sisfb_heap.poh_freelist = NULL;
320962306a36Sopenharmony_ci
321062306a36Sopenharmony_ci	poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
321162306a36Sopenharmony_ci	if(poh == NULL)
321262306a36Sopenharmony_ci		return 1;
321362306a36Sopenharmony_ci
321462306a36Sopenharmony_ci	poh->poh_next = &ivideo->sisfb_heap.oh_free;
321562306a36Sopenharmony_ci	poh->poh_prev = &ivideo->sisfb_heap.oh_free;
321662306a36Sopenharmony_ci	poh->size = ivideo->sisfb_heap_size;
321762306a36Sopenharmony_ci	poh->offset = ivideo->heapstart;
321862306a36Sopenharmony_ci
321962306a36Sopenharmony_ci	ivideo->sisfb_heap.oh_free.poh_next = poh;
322062306a36Sopenharmony_ci	ivideo->sisfb_heap.oh_free.poh_prev = poh;
322162306a36Sopenharmony_ci	ivideo->sisfb_heap.oh_free.size = 0;
322262306a36Sopenharmony_ci	ivideo->sisfb_heap.max_freesize = poh->size;
322362306a36Sopenharmony_ci
322462306a36Sopenharmony_ci	ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
322562306a36Sopenharmony_ci	ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
322662306a36Sopenharmony_ci	ivideo->sisfb_heap.oh_used.size = SENTINEL;
322762306a36Sopenharmony_ci
322862306a36Sopenharmony_ci	if(ivideo->cardnumber == 0) {
322962306a36Sopenharmony_ci		/* For the first card, make this heap the "global" one
323062306a36Sopenharmony_ci		 * for old DRM (which could handle only one card)
323162306a36Sopenharmony_ci		 */
323262306a36Sopenharmony_ci		sisfb_heap = &ivideo->sisfb_heap;
323362306a36Sopenharmony_ci	}
323462306a36Sopenharmony_ci
323562306a36Sopenharmony_ci	return 0;
323662306a36Sopenharmony_ci}
323762306a36Sopenharmony_ci
323862306a36Sopenharmony_cistatic struct SIS_OH *
323962306a36Sopenharmony_cisisfb_poh_new_node(struct SIS_HEAP *memheap)
324062306a36Sopenharmony_ci{
324162306a36Sopenharmony_ci	struct SIS_OHALLOC	*poha;
324262306a36Sopenharmony_ci	struct SIS_OH		*poh;
324362306a36Sopenharmony_ci	unsigned long		cOhs;
324462306a36Sopenharmony_ci	int			i;
324562306a36Sopenharmony_ci
324662306a36Sopenharmony_ci	if(memheap->poh_freelist == NULL) {
324762306a36Sopenharmony_ci		poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
324862306a36Sopenharmony_ci		if(!poha)
324962306a36Sopenharmony_ci			return NULL;
325062306a36Sopenharmony_ci
325162306a36Sopenharmony_ci		poha->poha_next = memheap->poha_chain;
325262306a36Sopenharmony_ci		memheap->poha_chain = poha;
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ci		cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
325562306a36Sopenharmony_ci
325662306a36Sopenharmony_ci		poh = &poha->aoh[0];
325762306a36Sopenharmony_ci		for(i = cOhs - 1; i != 0; i--) {
325862306a36Sopenharmony_ci			poh->poh_next = poh + 1;
325962306a36Sopenharmony_ci			poh = poh + 1;
326062306a36Sopenharmony_ci		}
326162306a36Sopenharmony_ci
326262306a36Sopenharmony_ci		poh->poh_next = NULL;
326362306a36Sopenharmony_ci		memheap->poh_freelist = &poha->aoh[0];
326462306a36Sopenharmony_ci	}
326562306a36Sopenharmony_ci
326662306a36Sopenharmony_ci	poh = memheap->poh_freelist;
326762306a36Sopenharmony_ci	memheap->poh_freelist = poh->poh_next;
326862306a36Sopenharmony_ci
326962306a36Sopenharmony_ci	return poh;
327062306a36Sopenharmony_ci}
327162306a36Sopenharmony_ci
327262306a36Sopenharmony_cistatic struct SIS_OH *
327362306a36Sopenharmony_cisisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
327462306a36Sopenharmony_ci{
327562306a36Sopenharmony_ci	struct SIS_OH	*pohThis;
327662306a36Sopenharmony_ci	struct SIS_OH	*pohRoot;
327762306a36Sopenharmony_ci	int		bAllocated = 0;
327862306a36Sopenharmony_ci
327962306a36Sopenharmony_ci	if(size > memheap->max_freesize) {
328062306a36Sopenharmony_ci		DPRINTK("sisfb: Can't allocate %dk video memory\n",
328162306a36Sopenharmony_ci			(unsigned int) size / 1024);
328262306a36Sopenharmony_ci		return NULL;
328362306a36Sopenharmony_ci	}
328462306a36Sopenharmony_ci
328562306a36Sopenharmony_ci	pohThis = memheap->oh_free.poh_next;
328662306a36Sopenharmony_ci
328762306a36Sopenharmony_ci	while(pohThis != &memheap->oh_free) {
328862306a36Sopenharmony_ci		if(size <= pohThis->size) {
328962306a36Sopenharmony_ci			bAllocated = 1;
329062306a36Sopenharmony_ci			break;
329162306a36Sopenharmony_ci		}
329262306a36Sopenharmony_ci		pohThis = pohThis->poh_next;
329362306a36Sopenharmony_ci	}
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_ci	if(!bAllocated) {
329662306a36Sopenharmony_ci		DPRINTK("sisfb: Can't allocate %dk video memory\n",
329762306a36Sopenharmony_ci			(unsigned int) size / 1024);
329862306a36Sopenharmony_ci		return NULL;
329962306a36Sopenharmony_ci	}
330062306a36Sopenharmony_ci
330162306a36Sopenharmony_ci	if(size == pohThis->size) {
330262306a36Sopenharmony_ci		pohRoot = pohThis;
330362306a36Sopenharmony_ci		sisfb_delete_node(pohThis);
330462306a36Sopenharmony_ci	} else {
330562306a36Sopenharmony_ci		pohRoot = sisfb_poh_new_node(memheap);
330662306a36Sopenharmony_ci		if(pohRoot == NULL)
330762306a36Sopenharmony_ci			return NULL;
330862306a36Sopenharmony_ci
330962306a36Sopenharmony_ci		pohRoot->offset = pohThis->offset;
331062306a36Sopenharmony_ci		pohRoot->size = size;
331162306a36Sopenharmony_ci
331262306a36Sopenharmony_ci		pohThis->offset += size;
331362306a36Sopenharmony_ci		pohThis->size -= size;
331462306a36Sopenharmony_ci	}
331562306a36Sopenharmony_ci
331662306a36Sopenharmony_ci	memheap->max_freesize -= size;
331762306a36Sopenharmony_ci
331862306a36Sopenharmony_ci	pohThis = &memheap->oh_used;
331962306a36Sopenharmony_ci	sisfb_insert_node(pohThis, pohRoot);
332062306a36Sopenharmony_ci
332162306a36Sopenharmony_ci	return pohRoot;
332262306a36Sopenharmony_ci}
332362306a36Sopenharmony_ci
332462306a36Sopenharmony_cistatic void
332562306a36Sopenharmony_cisisfb_delete_node(struct SIS_OH *poh)
332662306a36Sopenharmony_ci{
332762306a36Sopenharmony_ci	poh->poh_prev->poh_next = poh->poh_next;
332862306a36Sopenharmony_ci	poh->poh_next->poh_prev = poh->poh_prev;
332962306a36Sopenharmony_ci}
333062306a36Sopenharmony_ci
333162306a36Sopenharmony_cistatic void
333262306a36Sopenharmony_cisisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
333362306a36Sopenharmony_ci{
333462306a36Sopenharmony_ci	struct SIS_OH *pohTemp = pohList->poh_next;
333562306a36Sopenharmony_ci
333662306a36Sopenharmony_ci	pohList->poh_next = poh;
333762306a36Sopenharmony_ci	pohTemp->poh_prev = poh;
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_ci	poh->poh_prev = pohList;
334062306a36Sopenharmony_ci	poh->poh_next = pohTemp;
334162306a36Sopenharmony_ci}
334262306a36Sopenharmony_ci
334362306a36Sopenharmony_cistatic struct SIS_OH *
334462306a36Sopenharmony_cisisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
334562306a36Sopenharmony_ci{
334662306a36Sopenharmony_ci	struct SIS_OH *pohThis;
334762306a36Sopenharmony_ci	struct SIS_OH *poh_freed;
334862306a36Sopenharmony_ci	struct SIS_OH *poh_prev;
334962306a36Sopenharmony_ci	struct SIS_OH *poh_next;
335062306a36Sopenharmony_ci	u32    ulUpper;
335162306a36Sopenharmony_ci	u32    ulLower;
335262306a36Sopenharmony_ci	int    foundNode = 0;
335362306a36Sopenharmony_ci
335462306a36Sopenharmony_ci	poh_freed = memheap->oh_used.poh_next;
335562306a36Sopenharmony_ci
335662306a36Sopenharmony_ci	while(poh_freed != &memheap->oh_used) {
335762306a36Sopenharmony_ci		if(poh_freed->offset == base) {
335862306a36Sopenharmony_ci			foundNode = 1;
335962306a36Sopenharmony_ci			break;
336062306a36Sopenharmony_ci		}
336162306a36Sopenharmony_ci
336262306a36Sopenharmony_ci		poh_freed = poh_freed->poh_next;
336362306a36Sopenharmony_ci	}
336462306a36Sopenharmony_ci
336562306a36Sopenharmony_ci	if(!foundNode)
336662306a36Sopenharmony_ci		return NULL;
336762306a36Sopenharmony_ci
336862306a36Sopenharmony_ci	memheap->max_freesize += poh_freed->size;
336962306a36Sopenharmony_ci
337062306a36Sopenharmony_ci	poh_prev = poh_next = NULL;
337162306a36Sopenharmony_ci	ulUpper = poh_freed->offset + poh_freed->size;
337262306a36Sopenharmony_ci	ulLower = poh_freed->offset;
337362306a36Sopenharmony_ci
337462306a36Sopenharmony_ci	pohThis = memheap->oh_free.poh_next;
337562306a36Sopenharmony_ci
337662306a36Sopenharmony_ci	while(pohThis != &memheap->oh_free) {
337762306a36Sopenharmony_ci		if(pohThis->offset == ulUpper) {
337862306a36Sopenharmony_ci			poh_next = pohThis;
337962306a36Sopenharmony_ci		} else if((pohThis->offset + pohThis->size) == ulLower) {
338062306a36Sopenharmony_ci			poh_prev = pohThis;
338162306a36Sopenharmony_ci		}
338262306a36Sopenharmony_ci		pohThis = pohThis->poh_next;
338362306a36Sopenharmony_ci	}
338462306a36Sopenharmony_ci
338562306a36Sopenharmony_ci	sisfb_delete_node(poh_freed);
338662306a36Sopenharmony_ci
338762306a36Sopenharmony_ci	if(poh_prev && poh_next) {
338862306a36Sopenharmony_ci		poh_prev->size += (poh_freed->size + poh_next->size);
338962306a36Sopenharmony_ci		sisfb_delete_node(poh_next);
339062306a36Sopenharmony_ci		sisfb_free_node(memheap, poh_freed);
339162306a36Sopenharmony_ci		sisfb_free_node(memheap, poh_next);
339262306a36Sopenharmony_ci		return poh_prev;
339362306a36Sopenharmony_ci	}
339462306a36Sopenharmony_ci
339562306a36Sopenharmony_ci	if(poh_prev) {
339662306a36Sopenharmony_ci		poh_prev->size += poh_freed->size;
339762306a36Sopenharmony_ci		sisfb_free_node(memheap, poh_freed);
339862306a36Sopenharmony_ci		return poh_prev;
339962306a36Sopenharmony_ci	}
340062306a36Sopenharmony_ci
340162306a36Sopenharmony_ci	if(poh_next) {
340262306a36Sopenharmony_ci		poh_next->size += poh_freed->size;
340362306a36Sopenharmony_ci		poh_next->offset = poh_freed->offset;
340462306a36Sopenharmony_ci		sisfb_free_node(memheap, poh_freed);
340562306a36Sopenharmony_ci		return poh_next;
340662306a36Sopenharmony_ci	}
340762306a36Sopenharmony_ci
340862306a36Sopenharmony_ci	sisfb_insert_node(&memheap->oh_free, poh_freed);
340962306a36Sopenharmony_ci
341062306a36Sopenharmony_ci	return poh_freed;
341162306a36Sopenharmony_ci}
341262306a36Sopenharmony_ci
341362306a36Sopenharmony_cistatic void
341462306a36Sopenharmony_cisisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
341562306a36Sopenharmony_ci{
341662306a36Sopenharmony_ci	if(poh == NULL)
341762306a36Sopenharmony_ci		return;
341862306a36Sopenharmony_ci
341962306a36Sopenharmony_ci	poh->poh_next = memheap->poh_freelist;
342062306a36Sopenharmony_ci	memheap->poh_freelist = poh;
342162306a36Sopenharmony_ci}
342262306a36Sopenharmony_ci
342362306a36Sopenharmony_cistatic void
342462306a36Sopenharmony_cisis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
342562306a36Sopenharmony_ci{
342662306a36Sopenharmony_ci	struct SIS_OH *poh = NULL;
342762306a36Sopenharmony_ci
342862306a36Sopenharmony_ci	if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
342962306a36Sopenharmony_ci		poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
343062306a36Sopenharmony_ci
343162306a36Sopenharmony_ci	if(poh == NULL) {
343262306a36Sopenharmony_ci		req->offset = req->size = 0;
343362306a36Sopenharmony_ci		DPRINTK("sisfb: Video RAM allocation failed\n");
343462306a36Sopenharmony_ci	} else {
343562306a36Sopenharmony_ci		req->offset = poh->offset;
343662306a36Sopenharmony_ci		req->size = poh->size;
343762306a36Sopenharmony_ci		DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
343862306a36Sopenharmony_ci			(poh->offset + ivideo->video_vbase));
343962306a36Sopenharmony_ci	}
344062306a36Sopenharmony_ci}
344162306a36Sopenharmony_ci
344262306a36Sopenharmony_civoid
344362306a36Sopenharmony_cisis_malloc(struct sis_memreq *req)
344462306a36Sopenharmony_ci{
344562306a36Sopenharmony_ci	struct sis_video_info *ivideo = sisfb_heap->vinfo;
344662306a36Sopenharmony_ci
344762306a36Sopenharmony_ci	if(&ivideo->sisfb_heap == sisfb_heap)
344862306a36Sopenharmony_ci		sis_int_malloc(ivideo, req);
344962306a36Sopenharmony_ci	else
345062306a36Sopenharmony_ci		req->offset = req->size = 0;
345162306a36Sopenharmony_ci}
345262306a36Sopenharmony_ci
345362306a36Sopenharmony_civoid
345462306a36Sopenharmony_cisis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
345562306a36Sopenharmony_ci{
345662306a36Sopenharmony_ci	struct sis_video_info *ivideo = pci_get_drvdata(pdev);
345762306a36Sopenharmony_ci
345862306a36Sopenharmony_ci	sis_int_malloc(ivideo, req);
345962306a36Sopenharmony_ci}
346062306a36Sopenharmony_ci
346162306a36Sopenharmony_ci/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
346262306a36Sopenharmony_ci
346362306a36Sopenharmony_cistatic void
346462306a36Sopenharmony_cisis_int_free(struct sis_video_info *ivideo, u32 base)
346562306a36Sopenharmony_ci{
346662306a36Sopenharmony_ci	struct SIS_OH *poh;
346762306a36Sopenharmony_ci
346862306a36Sopenharmony_ci	if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
346962306a36Sopenharmony_ci		return;
347062306a36Sopenharmony_ci
347162306a36Sopenharmony_ci	poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
347262306a36Sopenharmony_ci
347362306a36Sopenharmony_ci	if(poh == NULL) {
347462306a36Sopenharmony_ci		DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
347562306a36Sopenharmony_ci			(unsigned int) base);
347662306a36Sopenharmony_ci	}
347762306a36Sopenharmony_ci}
347862306a36Sopenharmony_ci
347962306a36Sopenharmony_civoid
348062306a36Sopenharmony_cisis_free(u32 base)
348162306a36Sopenharmony_ci{
348262306a36Sopenharmony_ci	struct sis_video_info *ivideo = sisfb_heap->vinfo;
348362306a36Sopenharmony_ci
348462306a36Sopenharmony_ci	sis_int_free(ivideo, base);
348562306a36Sopenharmony_ci}
348662306a36Sopenharmony_ci
348762306a36Sopenharmony_civoid
348862306a36Sopenharmony_cisis_free_new(struct pci_dev *pdev, u32 base)
348962306a36Sopenharmony_ci{
349062306a36Sopenharmony_ci	struct sis_video_info *ivideo = pci_get_drvdata(pdev);
349162306a36Sopenharmony_ci
349262306a36Sopenharmony_ci	sis_int_free(ivideo, base);
349362306a36Sopenharmony_ci}
349462306a36Sopenharmony_ci
349562306a36Sopenharmony_ci/* --------------------- SetMode routines ------------------------- */
349662306a36Sopenharmony_ci
349762306a36Sopenharmony_cistatic void
349862306a36Sopenharmony_cisisfb_check_engine_and_sync(struct sis_video_info *ivideo)
349962306a36Sopenharmony_ci{
350062306a36Sopenharmony_ci	u8 cr30, cr31;
350162306a36Sopenharmony_ci
350262306a36Sopenharmony_ci	/* Check if MMIO and engines are enabled,
350362306a36Sopenharmony_ci	 * and sync in case they are. Can't use
350462306a36Sopenharmony_ci	 * ivideo->accel here, as this might have
350562306a36Sopenharmony_ci	 * been changed before this is called.
350662306a36Sopenharmony_ci	 */
350762306a36Sopenharmony_ci	cr30 = SiS_GetReg(SISSR, IND_SIS_PCI_ADDRESS_SET);
350862306a36Sopenharmony_ci	cr31 = SiS_GetReg(SISSR, IND_SIS_MODULE_ENABLE);
350962306a36Sopenharmony_ci	/* MMIO and 2D/3D engine enabled? */
351062306a36Sopenharmony_ci	if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
351162306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
351262306a36Sopenharmony_ci		if(ivideo->sisvga_engine == SIS_300_VGA) {
351362306a36Sopenharmony_ci			/* Don't care about TurboQueue. It's
351462306a36Sopenharmony_ci			 * enough to know that the engines
351562306a36Sopenharmony_ci			 * are enabled
351662306a36Sopenharmony_ci			 */
351762306a36Sopenharmony_ci			sisfb_syncaccel(ivideo);
351862306a36Sopenharmony_ci		}
351962306a36Sopenharmony_ci#endif
352062306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
352162306a36Sopenharmony_ci		if(ivideo->sisvga_engine == SIS_315_VGA) {
352262306a36Sopenharmony_ci			/* Check that any queue mode is
352362306a36Sopenharmony_ci			 * enabled, and that the queue
352462306a36Sopenharmony_ci			 * is not in the state of "reset"
352562306a36Sopenharmony_ci			 */
352662306a36Sopenharmony_ci			cr30 = SiS_GetReg(SISSR, 0x26);
352762306a36Sopenharmony_ci			if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
352862306a36Sopenharmony_ci				sisfb_syncaccel(ivideo);
352962306a36Sopenharmony_ci			}
353062306a36Sopenharmony_ci		}
353162306a36Sopenharmony_ci#endif
353262306a36Sopenharmony_ci	}
353362306a36Sopenharmony_ci}
353462306a36Sopenharmony_ci
353562306a36Sopenharmony_cistatic void
353662306a36Sopenharmony_cisisfb_pre_setmode(struct sis_video_info *ivideo)
353762306a36Sopenharmony_ci{
353862306a36Sopenharmony_ci	u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
353962306a36Sopenharmony_ci	int tvregnum = 0;
354062306a36Sopenharmony_ci
354162306a36Sopenharmony_ci	ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
354262306a36Sopenharmony_ci
354362306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x05, 0x86);
354462306a36Sopenharmony_ci
354562306a36Sopenharmony_ci	cr31 = SiS_GetReg(SISCR, 0x31);
354662306a36Sopenharmony_ci	cr31 &= ~0x60;
354762306a36Sopenharmony_ci	cr31 |= 0x04;
354862306a36Sopenharmony_ci
354962306a36Sopenharmony_ci	cr33 = ivideo->rate_idx & 0x0F;
355062306a36Sopenharmony_ci
355162306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
355262306a36Sopenharmony_ci	if(ivideo->sisvga_engine == SIS_315_VGA) {
355362306a36Sopenharmony_ci	   if(ivideo->chip >= SIS_661) {
355462306a36Sopenharmony_ci	      cr38 = SiS_GetReg(SISCR, 0x38);
355562306a36Sopenharmony_ci	      cr38 &= ~0x07;  /* Clear LCDA/DualEdge and YPbPr bits */
355662306a36Sopenharmony_ci	   } else {
355762306a36Sopenharmony_ci	      tvregnum = 0x38;
355862306a36Sopenharmony_ci	      cr38 = SiS_GetReg(SISCR, tvregnum);
355962306a36Sopenharmony_ci	      cr38 &= ~0x3b;  /* Clear LCDA/DualEdge and YPbPr bits */
356062306a36Sopenharmony_ci	   }
356162306a36Sopenharmony_ci	}
356262306a36Sopenharmony_ci#endif
356362306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
356462306a36Sopenharmony_ci	if(ivideo->sisvga_engine == SIS_300_VGA) {
356562306a36Sopenharmony_ci	   tvregnum = 0x35;
356662306a36Sopenharmony_ci	   cr38 = SiS_GetReg(SISCR, tvregnum);
356762306a36Sopenharmony_ci	}
356862306a36Sopenharmony_ci#endif
356962306a36Sopenharmony_ci
357062306a36Sopenharmony_ci	SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
357162306a36Sopenharmony_ci	SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
357262306a36Sopenharmony_ci	ivideo->curFSTN = ivideo->curDSTN = 0;
357362306a36Sopenharmony_ci
357462306a36Sopenharmony_ci	switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
357562306a36Sopenharmony_ci
357662306a36Sopenharmony_ci	   case CRT2_TV:
357762306a36Sopenharmony_ci	      cr38 &= ~0xc0;   /* Clear PAL-M / PAL-N bits */
357862306a36Sopenharmony_ci	      if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
357962306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
358062306a36Sopenharmony_ci		 if(ivideo->chip >= SIS_661) {
358162306a36Sopenharmony_ci		    cr38 |= 0x04;
358262306a36Sopenharmony_ci		    if(ivideo->vbflags & TV_YPBPR525P)       cr35 |= 0x20;
358362306a36Sopenharmony_ci		    else if(ivideo->vbflags & TV_YPBPR750P)  cr35 |= 0x40;
358462306a36Sopenharmony_ci		    else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
358562306a36Sopenharmony_ci		    cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
358662306a36Sopenharmony_ci		    cr35 &= ~0x01;
358762306a36Sopenharmony_ci		    ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
358862306a36Sopenharmony_ci		 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
358962306a36Sopenharmony_ci		    cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
359062306a36Sopenharmony_ci		    cr38 |= 0x08;
359162306a36Sopenharmony_ci		    if(ivideo->vbflags & TV_YPBPR525P)       cr38 |= 0x10;
359262306a36Sopenharmony_ci		    else if(ivideo->vbflags & TV_YPBPR750P)  cr38 |= 0x20;
359362306a36Sopenharmony_ci		    else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
359462306a36Sopenharmony_ci		    cr31 &= ~0x01;
359562306a36Sopenharmony_ci		    ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
359662306a36Sopenharmony_ci		 }
359762306a36Sopenharmony_ci#endif
359862306a36Sopenharmony_ci	      } else if((ivideo->vbflags & TV_HIVISION) &&
359962306a36Sopenharmony_ci				(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
360062306a36Sopenharmony_ci		 if(ivideo->chip >= SIS_661) {
360162306a36Sopenharmony_ci		    cr38 |= 0x04;
360262306a36Sopenharmony_ci		    cr35 |= 0x60;
360362306a36Sopenharmony_ci		 } else {
360462306a36Sopenharmony_ci		    cr30 |= 0x80;
360562306a36Sopenharmony_ci		 }
360662306a36Sopenharmony_ci		 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
360762306a36Sopenharmony_ci		 cr31 |= 0x01;
360862306a36Sopenharmony_ci		 cr35 |= 0x01;
360962306a36Sopenharmony_ci		 ivideo->currentvbflags |= TV_HIVISION;
361062306a36Sopenharmony_ci	      } else if(ivideo->vbflags & TV_SCART) {
361162306a36Sopenharmony_ci		 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
361262306a36Sopenharmony_ci		 cr31 |= 0x01;
361362306a36Sopenharmony_ci		 cr35 |= 0x01;
361462306a36Sopenharmony_ci		 ivideo->currentvbflags |= TV_SCART;
361562306a36Sopenharmony_ci	      } else {
361662306a36Sopenharmony_ci		 if(ivideo->vbflags & TV_SVIDEO) {
361762306a36Sopenharmony_ci		    cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
361862306a36Sopenharmony_ci		    ivideo->currentvbflags |= TV_SVIDEO;
361962306a36Sopenharmony_ci		 }
362062306a36Sopenharmony_ci		 if(ivideo->vbflags & TV_AVIDEO) {
362162306a36Sopenharmony_ci		    cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
362262306a36Sopenharmony_ci		    ivideo->currentvbflags |= TV_AVIDEO;
362362306a36Sopenharmony_ci		 }
362462306a36Sopenharmony_ci	      }
362562306a36Sopenharmony_ci	      cr31 |= SIS_DRIVER_MODE;
362662306a36Sopenharmony_ci
362762306a36Sopenharmony_ci	      if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
362862306a36Sopenharmony_ci		 if(ivideo->vbflags & TV_PAL) {
362962306a36Sopenharmony_ci		    cr31 |= 0x01; cr35 |= 0x01;
363062306a36Sopenharmony_ci		    ivideo->currentvbflags |= TV_PAL;
363162306a36Sopenharmony_ci		    if(ivideo->vbflags & TV_PALM) {
363262306a36Sopenharmony_ci		       cr38 |= 0x40; cr35 |= 0x04;
363362306a36Sopenharmony_ci		       ivideo->currentvbflags |= TV_PALM;
363462306a36Sopenharmony_ci		    } else if(ivideo->vbflags & TV_PALN) {
363562306a36Sopenharmony_ci		       cr38 |= 0x80; cr35 |= 0x08;
363662306a36Sopenharmony_ci		       ivideo->currentvbflags |= TV_PALN;
363762306a36Sopenharmony_ci		    }
363862306a36Sopenharmony_ci		 } else {
363962306a36Sopenharmony_ci		    cr31 &= ~0x01; cr35 &= ~0x01;
364062306a36Sopenharmony_ci		    ivideo->currentvbflags |= TV_NTSC;
364162306a36Sopenharmony_ci		    if(ivideo->vbflags & TV_NTSCJ) {
364262306a36Sopenharmony_ci		       cr38 |= 0x40; cr35 |= 0x02;
364362306a36Sopenharmony_ci		       ivideo->currentvbflags |= TV_NTSCJ;
364462306a36Sopenharmony_ci		    }
364562306a36Sopenharmony_ci		 }
364662306a36Sopenharmony_ci	      }
364762306a36Sopenharmony_ci	      break;
364862306a36Sopenharmony_ci
364962306a36Sopenharmony_ci	   case CRT2_LCD:
365062306a36Sopenharmony_ci	      cr30  = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
365162306a36Sopenharmony_ci	      cr31 |= SIS_DRIVER_MODE;
365262306a36Sopenharmony_ci	      SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
365362306a36Sopenharmony_ci	      SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
365462306a36Sopenharmony_ci	      ivideo->curFSTN = ivideo->sisfb_fstn;
365562306a36Sopenharmony_ci	      ivideo->curDSTN = ivideo->sisfb_dstn;
365662306a36Sopenharmony_ci	      break;
365762306a36Sopenharmony_ci
365862306a36Sopenharmony_ci	   case CRT2_VGA:
365962306a36Sopenharmony_ci	      cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
366062306a36Sopenharmony_ci	      cr31 |= SIS_DRIVER_MODE;
366162306a36Sopenharmony_ci	      if(ivideo->sisfb_nocrt2rate) {
366262306a36Sopenharmony_ci		 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
366362306a36Sopenharmony_ci	      } else {
366462306a36Sopenharmony_ci		 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
366562306a36Sopenharmony_ci	      }
366662306a36Sopenharmony_ci	      break;
366762306a36Sopenharmony_ci
366862306a36Sopenharmony_ci	   default:	/* disable CRT2 */
366962306a36Sopenharmony_ci	      cr30 = 0x00;
367062306a36Sopenharmony_ci	      cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
367162306a36Sopenharmony_ci	}
367262306a36Sopenharmony_ci
367362306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x30, cr30);
367462306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x33, cr33);
367562306a36Sopenharmony_ci
367662306a36Sopenharmony_ci	if(ivideo->chip >= SIS_661) {
367762306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
367862306a36Sopenharmony_ci	   cr31 &= ~0x01;                          /* Clear PAL flag (now in CR35) */
367962306a36Sopenharmony_ci	   SiS_SetRegANDOR(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
368062306a36Sopenharmony_ci	   cr38 &= 0x07;                           /* Use only LCDA and HiVision/YPbPr bits */
368162306a36Sopenharmony_ci	   SiS_SetRegANDOR(SISCR, 0x38, 0xf8, cr38);
368262306a36Sopenharmony_ci#endif
368362306a36Sopenharmony_ci	} else if(ivideo->chip != SIS_300) {
368462306a36Sopenharmony_ci	   SiS_SetReg(SISCR, tvregnum, cr38);
368562306a36Sopenharmony_ci	}
368662306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x31, cr31);
368762306a36Sopenharmony_ci
368862306a36Sopenharmony_ci	ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
368962306a36Sopenharmony_ci
369062306a36Sopenharmony_ci	sisfb_check_engine_and_sync(ivideo);
369162306a36Sopenharmony_ci}
369262306a36Sopenharmony_ci
369362306a36Sopenharmony_ci/* Fix SR11 for 661 and later */
369462306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
369562306a36Sopenharmony_cistatic void
369662306a36Sopenharmony_cisisfb_fixup_SR11(struct sis_video_info *ivideo)
369762306a36Sopenharmony_ci{
369862306a36Sopenharmony_ci	u8  tmpreg;
369962306a36Sopenharmony_ci
370062306a36Sopenharmony_ci	if(ivideo->chip >= SIS_661) {
370162306a36Sopenharmony_ci		tmpreg = SiS_GetReg(SISSR, 0x11);
370262306a36Sopenharmony_ci		if(tmpreg & 0x20) {
370362306a36Sopenharmony_ci			tmpreg = SiS_GetReg(SISSR, 0x3e);
370462306a36Sopenharmony_ci			tmpreg = (tmpreg + 1) & 0xff;
370562306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x3e, tmpreg);
370662306a36Sopenharmony_ci			tmpreg = SiS_GetReg(SISSR, 0x11);
370762306a36Sopenharmony_ci		}
370862306a36Sopenharmony_ci		if(tmpreg & 0xf0) {
370962306a36Sopenharmony_ci			SiS_SetRegAND(SISSR, 0x11, 0x0f);
371062306a36Sopenharmony_ci		}
371162306a36Sopenharmony_ci	}
371262306a36Sopenharmony_ci}
371362306a36Sopenharmony_ci#endif
371462306a36Sopenharmony_ci
371562306a36Sopenharmony_cistatic void
371662306a36Sopenharmony_cisisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
371762306a36Sopenharmony_ci{
371862306a36Sopenharmony_ci	if(val > 32) val = 32;
371962306a36Sopenharmony_ci	if(val < -32) val = -32;
372062306a36Sopenharmony_ci	ivideo->tvxpos = val;
372162306a36Sopenharmony_ci
372262306a36Sopenharmony_ci	if(ivideo->sisfblocked) return;
372362306a36Sopenharmony_ci	if(!ivideo->modechanged) return;
372462306a36Sopenharmony_ci
372562306a36Sopenharmony_ci	if(ivideo->currentvbflags & CRT2_TV) {
372662306a36Sopenharmony_ci
372762306a36Sopenharmony_ci		if(ivideo->vbflags2 & VB2_CHRONTEL) {
372862306a36Sopenharmony_ci
372962306a36Sopenharmony_ci			int x = ivideo->tvx;
373062306a36Sopenharmony_ci
373162306a36Sopenharmony_ci			switch(ivideo->chronteltype) {
373262306a36Sopenharmony_ci			case 1:
373362306a36Sopenharmony_ci				x += val;
373462306a36Sopenharmony_ci				if(x < 0) x = 0;
373562306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x05, 0x86);
373662306a36Sopenharmony_ci				SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
373762306a36Sopenharmony_ci				SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
373862306a36Sopenharmony_ci				break;
373962306a36Sopenharmony_ci			case 2:
374062306a36Sopenharmony_ci				/* Not supported by hardware */
374162306a36Sopenharmony_ci				break;
374262306a36Sopenharmony_ci			}
374362306a36Sopenharmony_ci
374462306a36Sopenharmony_ci		} else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
374562306a36Sopenharmony_ci
374662306a36Sopenharmony_ci			u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
374762306a36Sopenharmony_ci			unsigned short temp;
374862306a36Sopenharmony_ci
374962306a36Sopenharmony_ci			p2_1f = ivideo->p2_1f;
375062306a36Sopenharmony_ci			p2_20 = ivideo->p2_20;
375162306a36Sopenharmony_ci			p2_2b = ivideo->p2_2b;
375262306a36Sopenharmony_ci			p2_42 = ivideo->p2_42;
375362306a36Sopenharmony_ci			p2_43 = ivideo->p2_43;
375462306a36Sopenharmony_ci
375562306a36Sopenharmony_ci			temp = p2_1f | ((p2_20 & 0xf0) << 4);
375662306a36Sopenharmony_ci			temp += (val * 2);
375762306a36Sopenharmony_ci			p2_1f = temp & 0xff;
375862306a36Sopenharmony_ci			p2_20 = (temp & 0xf00) >> 4;
375962306a36Sopenharmony_ci			p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
376062306a36Sopenharmony_ci			temp = p2_43 | ((p2_42 & 0xf0) << 4);
376162306a36Sopenharmony_ci			temp += (val * 2);
376262306a36Sopenharmony_ci			p2_43 = temp & 0xff;
376362306a36Sopenharmony_ci			p2_42 = (temp & 0xf00) >> 4;
376462306a36Sopenharmony_ci			SiS_SetReg(SISPART2, 0x1f, p2_1f);
376562306a36Sopenharmony_ci			SiS_SetRegANDOR(SISPART2, 0x20, 0x0F, p2_20);
376662306a36Sopenharmony_ci			SiS_SetRegANDOR(SISPART2, 0x2b, 0xF0, p2_2b);
376762306a36Sopenharmony_ci			SiS_SetRegANDOR(SISPART2, 0x42, 0x0F, p2_42);
376862306a36Sopenharmony_ci			SiS_SetReg(SISPART2, 0x43, p2_43);
376962306a36Sopenharmony_ci		}
377062306a36Sopenharmony_ci	}
377162306a36Sopenharmony_ci}
377262306a36Sopenharmony_ci
377362306a36Sopenharmony_cistatic void
377462306a36Sopenharmony_cisisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
377562306a36Sopenharmony_ci{
377662306a36Sopenharmony_ci	if(val > 32) val = 32;
377762306a36Sopenharmony_ci	if(val < -32) val = -32;
377862306a36Sopenharmony_ci	ivideo->tvypos = val;
377962306a36Sopenharmony_ci
378062306a36Sopenharmony_ci	if(ivideo->sisfblocked) return;
378162306a36Sopenharmony_ci	if(!ivideo->modechanged) return;
378262306a36Sopenharmony_ci
378362306a36Sopenharmony_ci	if(ivideo->currentvbflags & CRT2_TV) {
378462306a36Sopenharmony_ci
378562306a36Sopenharmony_ci		if(ivideo->vbflags2 & VB2_CHRONTEL) {
378662306a36Sopenharmony_ci
378762306a36Sopenharmony_ci			int y = ivideo->tvy;
378862306a36Sopenharmony_ci
378962306a36Sopenharmony_ci			switch(ivideo->chronteltype) {
379062306a36Sopenharmony_ci			case 1:
379162306a36Sopenharmony_ci				y -= val;
379262306a36Sopenharmony_ci				if(y < 0) y = 0;
379362306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x05, 0x86);
379462306a36Sopenharmony_ci				SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
379562306a36Sopenharmony_ci				SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
379662306a36Sopenharmony_ci				break;
379762306a36Sopenharmony_ci			case 2:
379862306a36Sopenharmony_ci				/* Not supported by hardware */
379962306a36Sopenharmony_ci				break;
380062306a36Sopenharmony_ci			}
380162306a36Sopenharmony_ci
380262306a36Sopenharmony_ci		} else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
380362306a36Sopenharmony_ci
380462306a36Sopenharmony_ci			char p2_01, p2_02;
380562306a36Sopenharmony_ci			val /= 2;
380662306a36Sopenharmony_ci			p2_01 = ivideo->p2_01;
380762306a36Sopenharmony_ci			p2_02 = ivideo->p2_02;
380862306a36Sopenharmony_ci
380962306a36Sopenharmony_ci			p2_01 += val;
381062306a36Sopenharmony_ci			p2_02 += val;
381162306a36Sopenharmony_ci			if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
381262306a36Sopenharmony_ci				while((p2_01 <= 0) || (p2_02 <= 0)) {
381362306a36Sopenharmony_ci					p2_01 += 2;
381462306a36Sopenharmony_ci					p2_02 += 2;
381562306a36Sopenharmony_ci				}
381662306a36Sopenharmony_ci			}
381762306a36Sopenharmony_ci			SiS_SetReg(SISPART2, 0x01, p2_01);
381862306a36Sopenharmony_ci			SiS_SetReg(SISPART2, 0x02, p2_02);
381962306a36Sopenharmony_ci		}
382062306a36Sopenharmony_ci	}
382162306a36Sopenharmony_ci}
382262306a36Sopenharmony_ci
382362306a36Sopenharmony_cistatic void
382462306a36Sopenharmony_cisisfb_post_setmode(struct sis_video_info *ivideo)
382562306a36Sopenharmony_ci{
382662306a36Sopenharmony_ci	bool crt1isoff = false;
382762306a36Sopenharmony_ci	bool doit = true;
382862306a36Sopenharmony_ci#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
382962306a36Sopenharmony_ci	u8 reg;
383062306a36Sopenharmony_ci#endif
383162306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
383262306a36Sopenharmony_ci	u8 reg1;
383362306a36Sopenharmony_ci#endif
383462306a36Sopenharmony_ci
383562306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x05, 0x86);
383662306a36Sopenharmony_ci
383762306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
383862306a36Sopenharmony_ci	sisfb_fixup_SR11(ivideo);
383962306a36Sopenharmony_ci#endif
384062306a36Sopenharmony_ci
384162306a36Sopenharmony_ci	/* Now we actually HAVE changed the display mode */
384262306a36Sopenharmony_ci	ivideo->modechanged = 1;
384362306a36Sopenharmony_ci
384462306a36Sopenharmony_ci	/* We can't switch off CRT1 if bridge is in slave mode */
384562306a36Sopenharmony_ci	if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
384662306a36Sopenharmony_ci		if(sisfb_bridgeisslave(ivideo)) doit = false;
384762306a36Sopenharmony_ci	} else
384862306a36Sopenharmony_ci		ivideo->sisfb_crt1off = 0;
384962306a36Sopenharmony_ci
385062306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
385162306a36Sopenharmony_ci	if(ivideo->sisvga_engine == SIS_300_VGA) {
385262306a36Sopenharmony_ci		if((ivideo->sisfb_crt1off) && (doit)) {
385362306a36Sopenharmony_ci			crt1isoff = true;
385462306a36Sopenharmony_ci			reg = 0x00;
385562306a36Sopenharmony_ci		} else {
385662306a36Sopenharmony_ci			crt1isoff = false;
385762306a36Sopenharmony_ci			reg = 0x80;
385862306a36Sopenharmony_ci		}
385962306a36Sopenharmony_ci		SiS_SetRegANDOR(SISCR, 0x17, 0x7f, reg);
386062306a36Sopenharmony_ci	}
386162306a36Sopenharmony_ci#endif
386262306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
386362306a36Sopenharmony_ci	if(ivideo->sisvga_engine == SIS_315_VGA) {
386462306a36Sopenharmony_ci		if((ivideo->sisfb_crt1off) && (doit)) {
386562306a36Sopenharmony_ci			crt1isoff = true;
386662306a36Sopenharmony_ci			reg  = 0x40;
386762306a36Sopenharmony_ci			reg1 = 0xc0;
386862306a36Sopenharmony_ci		} else {
386962306a36Sopenharmony_ci			crt1isoff = false;
387062306a36Sopenharmony_ci			reg  = 0x00;
387162306a36Sopenharmony_ci			reg1 = 0x00;
387262306a36Sopenharmony_ci		}
387362306a36Sopenharmony_ci		SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
387462306a36Sopenharmony_ci		SiS_SetRegANDOR(SISSR, 0x1f, 0x3f, reg1);
387562306a36Sopenharmony_ci	}
387662306a36Sopenharmony_ci#endif
387762306a36Sopenharmony_ci
387862306a36Sopenharmony_ci	if(crt1isoff) {
387962306a36Sopenharmony_ci		ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
388062306a36Sopenharmony_ci		ivideo->currentvbflags |= VB_SINGLE_MODE;
388162306a36Sopenharmony_ci	} else {
388262306a36Sopenharmony_ci		ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
388362306a36Sopenharmony_ci		if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
388462306a36Sopenharmony_ci			ivideo->currentvbflags |= VB_MIRROR_MODE;
388562306a36Sopenharmony_ci		} else {
388662306a36Sopenharmony_ci			ivideo->currentvbflags |= VB_SINGLE_MODE;
388762306a36Sopenharmony_ci		}
388862306a36Sopenharmony_ci	}
388962306a36Sopenharmony_ci
389062306a36Sopenharmony_ci	SiS_SetRegAND(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
389162306a36Sopenharmony_ci
389262306a36Sopenharmony_ci	if(ivideo->currentvbflags & CRT2_TV) {
389362306a36Sopenharmony_ci		if(ivideo->vbflags2 & VB2_SISBRIDGE) {
389462306a36Sopenharmony_ci			ivideo->p2_1f = SiS_GetReg(SISPART2, 0x1f);
389562306a36Sopenharmony_ci			ivideo->p2_20 = SiS_GetReg(SISPART2, 0x20);
389662306a36Sopenharmony_ci			ivideo->p2_2b = SiS_GetReg(SISPART2, 0x2b);
389762306a36Sopenharmony_ci			ivideo->p2_42 = SiS_GetReg(SISPART2, 0x42);
389862306a36Sopenharmony_ci			ivideo->p2_43 = SiS_GetReg(SISPART2, 0x43);
389962306a36Sopenharmony_ci			ivideo->p2_01 = SiS_GetReg(SISPART2, 0x01);
390062306a36Sopenharmony_ci			ivideo->p2_02 = SiS_GetReg(SISPART2, 0x02);
390162306a36Sopenharmony_ci		} else if(ivideo->vbflags2 & VB2_CHRONTEL) {
390262306a36Sopenharmony_ci			if(ivideo->chronteltype == 1) {
390362306a36Sopenharmony_ci				ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
390462306a36Sopenharmony_ci				ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
390562306a36Sopenharmony_ci				ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
390662306a36Sopenharmony_ci				ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
390762306a36Sopenharmony_ci			}
390862306a36Sopenharmony_ci		}
390962306a36Sopenharmony_ci	}
391062306a36Sopenharmony_ci
391162306a36Sopenharmony_ci	if(ivideo->tvxpos) {
391262306a36Sopenharmony_ci		sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
391362306a36Sopenharmony_ci	}
391462306a36Sopenharmony_ci	if(ivideo->tvypos) {
391562306a36Sopenharmony_ci		sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
391662306a36Sopenharmony_ci	}
391762306a36Sopenharmony_ci
391862306a36Sopenharmony_ci	/* Eventually sync engines */
391962306a36Sopenharmony_ci	sisfb_check_engine_and_sync(ivideo);
392062306a36Sopenharmony_ci
392162306a36Sopenharmony_ci	/* (Re-)Initialize chip engines */
392262306a36Sopenharmony_ci	if(ivideo->accel) {
392362306a36Sopenharmony_ci		sisfb_engine_init(ivideo);
392462306a36Sopenharmony_ci	} else {
392562306a36Sopenharmony_ci		ivideo->engineok = 0;
392662306a36Sopenharmony_ci	}
392762306a36Sopenharmony_ci}
392862306a36Sopenharmony_ci
392962306a36Sopenharmony_cistatic int
393062306a36Sopenharmony_cisisfb_reset_mode(struct sis_video_info *ivideo)
393162306a36Sopenharmony_ci{
393262306a36Sopenharmony_ci	if(sisfb_set_mode(ivideo, 0))
393362306a36Sopenharmony_ci		return 1;
393462306a36Sopenharmony_ci
393562306a36Sopenharmony_ci	sisfb_set_pitch(ivideo);
393662306a36Sopenharmony_ci	sisfb_set_base_CRT1(ivideo, ivideo->current_base);
393762306a36Sopenharmony_ci	sisfb_set_base_CRT2(ivideo, ivideo->current_base);
393862306a36Sopenharmony_ci
393962306a36Sopenharmony_ci	return 0;
394062306a36Sopenharmony_ci}
394162306a36Sopenharmony_ci
394262306a36Sopenharmony_cistatic void
394362306a36Sopenharmony_cisisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
394462306a36Sopenharmony_ci{
394562306a36Sopenharmony_ci	int mycrt1off;
394662306a36Sopenharmony_ci
394762306a36Sopenharmony_ci	switch(sisfb_command->sisfb_cmd) {
394862306a36Sopenharmony_ci	case SISFB_CMD_GETVBFLAGS:
394962306a36Sopenharmony_ci		if(!ivideo->modechanged) {
395062306a36Sopenharmony_ci			sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
395162306a36Sopenharmony_ci		} else {
395262306a36Sopenharmony_ci			sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
395362306a36Sopenharmony_ci			sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
395462306a36Sopenharmony_ci			sisfb_command->sisfb_result[2] = ivideo->vbflags2;
395562306a36Sopenharmony_ci		}
395662306a36Sopenharmony_ci		break;
395762306a36Sopenharmony_ci	case SISFB_CMD_SWITCHCRT1:
395862306a36Sopenharmony_ci		/* arg[0]: 0 = off, 1 = on, 99 = query */
395962306a36Sopenharmony_ci		if(!ivideo->modechanged) {
396062306a36Sopenharmony_ci			sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
396162306a36Sopenharmony_ci		} else if(sisfb_command->sisfb_arg[0] == 99) {
396262306a36Sopenharmony_ci			/* Query */
396362306a36Sopenharmony_ci			sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
396462306a36Sopenharmony_ci			sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
396562306a36Sopenharmony_ci		} else if(ivideo->sisfblocked) {
396662306a36Sopenharmony_ci			sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
396762306a36Sopenharmony_ci		} else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
396862306a36Sopenharmony_ci					(sisfb_command->sisfb_arg[0] == 0)) {
396962306a36Sopenharmony_ci			sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
397062306a36Sopenharmony_ci		} else {
397162306a36Sopenharmony_ci			sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
397262306a36Sopenharmony_ci			mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
397362306a36Sopenharmony_ci			if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
397462306a36Sopenharmony_ci			    ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
397562306a36Sopenharmony_ci				ivideo->sisfb_crt1off = mycrt1off;
397662306a36Sopenharmony_ci				if(sisfb_reset_mode(ivideo)) {
397762306a36Sopenharmony_ci					sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
397862306a36Sopenharmony_ci				}
397962306a36Sopenharmony_ci			}
398062306a36Sopenharmony_ci			sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
398162306a36Sopenharmony_ci		}
398262306a36Sopenharmony_ci		break;
398362306a36Sopenharmony_ci	/* more to come */
398462306a36Sopenharmony_ci	default:
398562306a36Sopenharmony_ci		sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
398662306a36Sopenharmony_ci		printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
398762306a36Sopenharmony_ci			sisfb_command->sisfb_cmd);
398862306a36Sopenharmony_ci	}
398962306a36Sopenharmony_ci}
399062306a36Sopenharmony_ci
399162306a36Sopenharmony_ci#ifndef MODULE
399262306a36Sopenharmony_cistatic int __init sisfb_setup(char *options)
399362306a36Sopenharmony_ci{
399462306a36Sopenharmony_ci	char *this_opt;
399562306a36Sopenharmony_ci
399662306a36Sopenharmony_ci	sisfb_setdefaultparms();
399762306a36Sopenharmony_ci
399862306a36Sopenharmony_ci	if(!options || !(*options))
399962306a36Sopenharmony_ci		return 0;
400062306a36Sopenharmony_ci
400162306a36Sopenharmony_ci	while((this_opt = strsep(&options, ",")) != NULL) {
400262306a36Sopenharmony_ci
400362306a36Sopenharmony_ci		if(!(*this_opt)) continue;
400462306a36Sopenharmony_ci
400562306a36Sopenharmony_ci		if(!strncasecmp(this_opt, "off", 3)) {
400662306a36Sopenharmony_ci			sisfb_off = 1;
400762306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "forcecrt2type:", 14)) {
400862306a36Sopenharmony_ci			/* Need to check crt2 type first for fstn/dstn */
400962306a36Sopenharmony_ci			sisfb_search_crt2type(this_opt + 14);
401062306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "tvmode:",7)) {
401162306a36Sopenharmony_ci			sisfb_search_tvstd(this_opt + 7);
401262306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "tvstandard:",11)) {
401362306a36Sopenharmony_ci			sisfb_search_tvstd(this_opt + 11);
401462306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "mode:", 5)) {
401562306a36Sopenharmony_ci			sisfb_search_mode(this_opt + 5, false);
401662306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "vesa:", 5)) {
401762306a36Sopenharmony_ci			sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
401862306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "rate:", 5)) {
401962306a36Sopenharmony_ci			sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
402062306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "forcecrt1:", 10)) {
402162306a36Sopenharmony_ci			sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
402262306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "mem:",4)) {
402362306a36Sopenharmony_ci			sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
402462306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "pdc:", 4)) {
402562306a36Sopenharmony_ci			sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
402662306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "pdc1:", 5)) {
402762306a36Sopenharmony_ci			sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
402862306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "noaccel", 7)) {
402962306a36Sopenharmony_ci			sisfb_accel = 0;
403062306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "accel", 5)) {
403162306a36Sopenharmony_ci			sisfb_accel = -1;
403262306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "noypan", 6)) {
403362306a36Sopenharmony_ci			sisfb_ypan = 0;
403462306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "ypan", 4)) {
403562306a36Sopenharmony_ci			sisfb_ypan = -1;
403662306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "nomax", 5)) {
403762306a36Sopenharmony_ci			sisfb_max = 0;
403862306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "max", 3)) {
403962306a36Sopenharmony_ci			sisfb_max = -1;
404062306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "userom:", 7)) {
404162306a36Sopenharmony_ci			sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
404262306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "useoem:", 7)) {
404362306a36Sopenharmony_ci			sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
404462306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "nocrt2rate", 10)) {
404562306a36Sopenharmony_ci			sisfb_nocrt2rate = 1;
404662306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "scalelcd:", 9)) {
404762306a36Sopenharmony_ci			unsigned long temp = 2;
404862306a36Sopenharmony_ci			temp = simple_strtoul(this_opt + 9, NULL, 0);
404962306a36Sopenharmony_ci			if((temp == 0) || (temp == 1)) {
405062306a36Sopenharmony_ci			   sisfb_scalelcd = temp ^ 1;
405162306a36Sopenharmony_ci			}
405262306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "tvxposoffset:", 13)) {
405362306a36Sopenharmony_ci			int temp = 0;
405462306a36Sopenharmony_ci			temp = (int)simple_strtol(this_opt + 13, NULL, 0);
405562306a36Sopenharmony_ci			if((temp >= -32) && (temp <= 32)) {
405662306a36Sopenharmony_ci			   sisfb_tvxposoffset = temp;
405762306a36Sopenharmony_ci			}
405862306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "tvyposoffset:", 13)) {
405962306a36Sopenharmony_ci			int temp = 0;
406062306a36Sopenharmony_ci			temp = (int)simple_strtol(this_opt + 13, NULL, 0);
406162306a36Sopenharmony_ci			if((temp >= -32) && (temp <= 32)) {
406262306a36Sopenharmony_ci			   sisfb_tvyposoffset = temp;
406362306a36Sopenharmony_ci			}
406462306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "specialtiming:", 14)) {
406562306a36Sopenharmony_ci			sisfb_search_specialtiming(this_opt + 14);
406662306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "lvdshl:", 7)) {
406762306a36Sopenharmony_ci			int temp = 4;
406862306a36Sopenharmony_ci			temp = simple_strtoul(this_opt + 7, NULL, 0);
406962306a36Sopenharmony_ci			if((temp >= 0) && (temp <= 3)) {
407062306a36Sopenharmony_ci			   sisfb_lvdshl = temp;
407162306a36Sopenharmony_ci			}
407262306a36Sopenharmony_ci		} else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
407362306a36Sopenharmony_ci			sisfb_search_mode(this_opt, true);
407462306a36Sopenharmony_ci#if !defined(__i386__) && !defined(__x86_64__)
407562306a36Sopenharmony_ci		} else if(!strncasecmp(this_opt, "resetcard", 9)) {
407662306a36Sopenharmony_ci			sisfb_resetcard = 1;
407762306a36Sopenharmony_ci	        } else if(!strncasecmp(this_opt, "videoram:", 9)) {
407862306a36Sopenharmony_ci			sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
407962306a36Sopenharmony_ci#endif
408062306a36Sopenharmony_ci		} else {
408162306a36Sopenharmony_ci			printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
408262306a36Sopenharmony_ci		}
408362306a36Sopenharmony_ci
408462306a36Sopenharmony_ci	}
408562306a36Sopenharmony_ci
408662306a36Sopenharmony_ci	return 0;
408762306a36Sopenharmony_ci}
408862306a36Sopenharmony_ci#endif
408962306a36Sopenharmony_ci
409062306a36Sopenharmony_cistatic int sisfb_check_rom(void __iomem *rom_base,
409162306a36Sopenharmony_ci			   struct sis_video_info *ivideo)
409262306a36Sopenharmony_ci{
409362306a36Sopenharmony_ci	void __iomem *rom;
409462306a36Sopenharmony_ci	int romptr;
409562306a36Sopenharmony_ci
409662306a36Sopenharmony_ci	if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
409762306a36Sopenharmony_ci		return 0;
409862306a36Sopenharmony_ci
409962306a36Sopenharmony_ci	romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
410062306a36Sopenharmony_ci	if(romptr > (0x10000 - 8))
410162306a36Sopenharmony_ci		return 0;
410262306a36Sopenharmony_ci
410362306a36Sopenharmony_ci	rom = rom_base + romptr;
410462306a36Sopenharmony_ci
410562306a36Sopenharmony_ci	if((readb(rom)     != 'P') || (readb(rom + 1) != 'C') ||
410662306a36Sopenharmony_ci	   (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
410762306a36Sopenharmony_ci		return 0;
410862306a36Sopenharmony_ci
410962306a36Sopenharmony_ci	if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
411062306a36Sopenharmony_ci		return 0;
411162306a36Sopenharmony_ci
411262306a36Sopenharmony_ci	if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
411362306a36Sopenharmony_ci		return 0;
411462306a36Sopenharmony_ci
411562306a36Sopenharmony_ci	return 1;
411662306a36Sopenharmony_ci}
411762306a36Sopenharmony_ci
411862306a36Sopenharmony_cistatic unsigned char *sisfb_find_rom(struct pci_dev *pdev)
411962306a36Sopenharmony_ci{
412062306a36Sopenharmony_ci	struct sis_video_info *ivideo = pci_get_drvdata(pdev);
412162306a36Sopenharmony_ci	void __iomem *rom_base;
412262306a36Sopenharmony_ci	unsigned char *myrombase = NULL;
412362306a36Sopenharmony_ci	size_t romsize;
412462306a36Sopenharmony_ci
412562306a36Sopenharmony_ci	/* First, try the official pci ROM functions (except
412662306a36Sopenharmony_ci	 * on integrated chipsets which have no ROM).
412762306a36Sopenharmony_ci	 */
412862306a36Sopenharmony_ci
412962306a36Sopenharmony_ci	if(!ivideo->nbridge) {
413062306a36Sopenharmony_ci
413162306a36Sopenharmony_ci		if((rom_base = pci_map_rom(pdev, &romsize))) {
413262306a36Sopenharmony_ci
413362306a36Sopenharmony_ci			if(sisfb_check_rom(rom_base, ivideo)) {
413462306a36Sopenharmony_ci
413562306a36Sopenharmony_ci				if((myrombase = vmalloc(65536))) {
413662306a36Sopenharmony_ci					memcpy_fromio(myrombase, rom_base,
413762306a36Sopenharmony_ci							(romsize > 65536) ? 65536 : romsize);
413862306a36Sopenharmony_ci				}
413962306a36Sopenharmony_ci			}
414062306a36Sopenharmony_ci			pci_unmap_rom(pdev, rom_base);
414162306a36Sopenharmony_ci		}
414262306a36Sopenharmony_ci	}
414362306a36Sopenharmony_ci
414462306a36Sopenharmony_ci	if(myrombase) return myrombase;
414562306a36Sopenharmony_ci
414662306a36Sopenharmony_ci	/* Otherwise do it the conventional way. */
414762306a36Sopenharmony_ci
414862306a36Sopenharmony_ci#if defined(__i386__) || defined(__x86_64__)
414962306a36Sopenharmony_ci	{
415062306a36Sopenharmony_ci		u32 temp;
415162306a36Sopenharmony_ci
415262306a36Sopenharmony_ci		for (temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
415362306a36Sopenharmony_ci
415462306a36Sopenharmony_ci			rom_base = ioremap(temp, 65536);
415562306a36Sopenharmony_ci			if (!rom_base)
415662306a36Sopenharmony_ci				continue;
415762306a36Sopenharmony_ci
415862306a36Sopenharmony_ci			if (!sisfb_check_rom(rom_base, ivideo)) {
415962306a36Sopenharmony_ci				iounmap(rom_base);
416062306a36Sopenharmony_ci				continue;
416162306a36Sopenharmony_ci			}
416262306a36Sopenharmony_ci
416362306a36Sopenharmony_ci			if ((myrombase = vmalloc(65536)))
416462306a36Sopenharmony_ci				memcpy_fromio(myrombase, rom_base, 65536);
416562306a36Sopenharmony_ci
416662306a36Sopenharmony_ci			iounmap(rom_base);
416762306a36Sopenharmony_ci			break;
416862306a36Sopenharmony_ci
416962306a36Sopenharmony_ci		}
417062306a36Sopenharmony_ci
417162306a36Sopenharmony_ci	}
417262306a36Sopenharmony_ci#endif
417362306a36Sopenharmony_ci
417462306a36Sopenharmony_ci	return myrombase;
417562306a36Sopenharmony_ci}
417662306a36Sopenharmony_ci
417762306a36Sopenharmony_cistatic void sisfb_post_map_vram(struct sis_video_info *ivideo,
417862306a36Sopenharmony_ci				unsigned int *mapsize, unsigned int min)
417962306a36Sopenharmony_ci{
418062306a36Sopenharmony_ci	if (*mapsize < (min << 20))
418162306a36Sopenharmony_ci		return;
418262306a36Sopenharmony_ci
418362306a36Sopenharmony_ci	ivideo->video_vbase = ioremap_wc(ivideo->video_base, (*mapsize));
418462306a36Sopenharmony_ci
418562306a36Sopenharmony_ci	if(!ivideo->video_vbase) {
418662306a36Sopenharmony_ci		printk(KERN_ERR
418762306a36Sopenharmony_ci			"sisfb: Unable to map maximum video RAM for size detection\n");
418862306a36Sopenharmony_ci		(*mapsize) >>= 1;
418962306a36Sopenharmony_ci		while((!(ivideo->video_vbase = ioremap_wc(ivideo->video_base, (*mapsize))))) {
419062306a36Sopenharmony_ci			(*mapsize) >>= 1;
419162306a36Sopenharmony_ci			if((*mapsize) < (min << 20))
419262306a36Sopenharmony_ci				break;
419362306a36Sopenharmony_ci		}
419462306a36Sopenharmony_ci		if(ivideo->video_vbase) {
419562306a36Sopenharmony_ci			printk(KERN_ERR
419662306a36Sopenharmony_ci				"sisfb: Video RAM size detection limited to %dMB\n",
419762306a36Sopenharmony_ci				(int)((*mapsize) >> 20));
419862306a36Sopenharmony_ci		}
419962306a36Sopenharmony_ci	}
420062306a36Sopenharmony_ci}
420162306a36Sopenharmony_ci
420262306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
420362306a36Sopenharmony_cistatic int sisfb_post_300_buswidth(struct sis_video_info *ivideo)
420462306a36Sopenharmony_ci{
420562306a36Sopenharmony_ci	void __iomem *FBAddress = ivideo->video_vbase;
420662306a36Sopenharmony_ci	unsigned short temp;
420762306a36Sopenharmony_ci	unsigned char reg;
420862306a36Sopenharmony_ci	int i, j;
420962306a36Sopenharmony_ci
421062306a36Sopenharmony_ci	SiS_SetRegAND(SISSR, 0x15, 0xFB);
421162306a36Sopenharmony_ci	SiS_SetRegOR(SISSR, 0x15, 0x04);
421262306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x13, 0x00);
421362306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x14, 0xBF);
421462306a36Sopenharmony_ci
421562306a36Sopenharmony_ci	for(i = 0; i < 2; i++) {
421662306a36Sopenharmony_ci		temp = 0x1234;
421762306a36Sopenharmony_ci		for(j = 0; j < 4; j++) {
421862306a36Sopenharmony_ci			writew(temp, FBAddress);
421962306a36Sopenharmony_ci			if(readw(FBAddress) == temp)
422062306a36Sopenharmony_ci				break;
422162306a36Sopenharmony_ci			SiS_SetRegOR(SISSR, 0x3c, 0x01);
422262306a36Sopenharmony_ci			reg = SiS_GetReg(SISSR, 0x05);
422362306a36Sopenharmony_ci			reg = SiS_GetReg(SISSR, 0x05);
422462306a36Sopenharmony_ci			SiS_SetRegAND(SISSR, 0x3c, 0xfe);
422562306a36Sopenharmony_ci			reg = SiS_GetReg(SISSR, 0x05);
422662306a36Sopenharmony_ci			reg = SiS_GetReg(SISSR, 0x05);
422762306a36Sopenharmony_ci			temp++;
422862306a36Sopenharmony_ci		}
422962306a36Sopenharmony_ci	}
423062306a36Sopenharmony_ci
423162306a36Sopenharmony_ci	writel(0x01234567L, FBAddress);
423262306a36Sopenharmony_ci	writel(0x456789ABL, (FBAddress + 4));
423362306a36Sopenharmony_ci	writel(0x89ABCDEFL, (FBAddress + 8));
423462306a36Sopenharmony_ci	writel(0xCDEF0123L, (FBAddress + 12));
423562306a36Sopenharmony_ci
423662306a36Sopenharmony_ci	reg = SiS_GetReg(SISSR, 0x3b);
423762306a36Sopenharmony_ci	if(reg & 0x01) {
423862306a36Sopenharmony_ci		if(readl((FBAddress + 12)) == 0xCDEF0123L)
423962306a36Sopenharmony_ci			return 4;	/* Channel A 128bit */
424062306a36Sopenharmony_ci	}
424162306a36Sopenharmony_ci
424262306a36Sopenharmony_ci	if(readl((FBAddress + 4)) == 0x456789ABL)
424362306a36Sopenharmony_ci		return 2;		/* Channel B 64bit */
424462306a36Sopenharmony_ci
424562306a36Sopenharmony_ci	return 1;			/* 32bit */
424662306a36Sopenharmony_ci}
424762306a36Sopenharmony_ci
424862306a36Sopenharmony_cistatic const unsigned short SiS_DRAMType[17][5] = {
424962306a36Sopenharmony_ci	{0x0C,0x0A,0x02,0x40,0x39},
425062306a36Sopenharmony_ci	{0x0D,0x0A,0x01,0x40,0x48},
425162306a36Sopenharmony_ci	{0x0C,0x09,0x02,0x20,0x35},
425262306a36Sopenharmony_ci	{0x0D,0x09,0x01,0x20,0x44},
425362306a36Sopenharmony_ci	{0x0C,0x08,0x02,0x10,0x31},
425462306a36Sopenharmony_ci	{0x0D,0x08,0x01,0x10,0x40},
425562306a36Sopenharmony_ci	{0x0C,0x0A,0x01,0x20,0x34},
425662306a36Sopenharmony_ci	{0x0C,0x09,0x01,0x08,0x32},
425762306a36Sopenharmony_ci	{0x0B,0x08,0x02,0x08,0x21},
425862306a36Sopenharmony_ci	{0x0C,0x08,0x01,0x08,0x30},
425962306a36Sopenharmony_ci	{0x0A,0x08,0x02,0x04,0x11},
426062306a36Sopenharmony_ci	{0x0B,0x0A,0x01,0x10,0x28},
426162306a36Sopenharmony_ci	{0x09,0x08,0x02,0x02,0x01},
426262306a36Sopenharmony_ci	{0x0B,0x09,0x01,0x08,0x24},
426362306a36Sopenharmony_ci	{0x0B,0x08,0x01,0x04,0x20},
426462306a36Sopenharmony_ci	{0x0A,0x08,0x01,0x02,0x10},
426562306a36Sopenharmony_ci	{0x09,0x08,0x01,0x01,0x00}
426662306a36Sopenharmony_ci};
426762306a36Sopenharmony_ci
426862306a36Sopenharmony_cistatic int sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration,
426962306a36Sopenharmony_ci				 int buswidth, int PseudoRankCapacity,
427062306a36Sopenharmony_ci				 int PseudoAdrPinCount, unsigned int mapsize)
427162306a36Sopenharmony_ci{
427262306a36Sopenharmony_ci	void __iomem *FBAddr = ivideo->video_vbase;
427362306a36Sopenharmony_ci	unsigned short sr14;
427462306a36Sopenharmony_ci	unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
427562306a36Sopenharmony_ci	unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
427662306a36Sopenharmony_ci
427762306a36Sopenharmony_ci	for (k = 0; k < ARRAY_SIZE(SiS_DRAMType); k++) {
427862306a36Sopenharmony_ci		RankCapacity = buswidth * SiS_DRAMType[k][3];
427962306a36Sopenharmony_ci
428062306a36Sopenharmony_ci		if (RankCapacity != PseudoRankCapacity)
428162306a36Sopenharmony_ci			continue;
428262306a36Sopenharmony_ci
428362306a36Sopenharmony_ci		if ((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
428462306a36Sopenharmony_ci			continue;
428562306a36Sopenharmony_ci
428662306a36Sopenharmony_ci		BankNumHigh = RankCapacity * 16 * iteration - 1;
428762306a36Sopenharmony_ci		if (iteration == 3) {             /* Rank No */
428862306a36Sopenharmony_ci			BankNumMid  = RankCapacity * 16 - 1;
428962306a36Sopenharmony_ci		} else {
429062306a36Sopenharmony_ci			BankNumMid  = RankCapacity * 16 * iteration / 2 - 1;
429162306a36Sopenharmony_ci		}
429262306a36Sopenharmony_ci
429362306a36Sopenharmony_ci		PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
429462306a36Sopenharmony_ci		PhysicalAdrHigh = BankNumHigh;
429562306a36Sopenharmony_ci		PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
429662306a36Sopenharmony_ci		PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
429762306a36Sopenharmony_ci
429862306a36Sopenharmony_ci		SiS_SetRegAND(SISSR, 0x15, 0xFB); /* Test */
429962306a36Sopenharmony_ci		SiS_SetRegOR(SISSR, 0x15, 0x04);  /* Test */
430062306a36Sopenharmony_ci		sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
430162306a36Sopenharmony_ci
430262306a36Sopenharmony_ci		if (buswidth == 4)
430362306a36Sopenharmony_ci			sr14 |= 0x80;
430462306a36Sopenharmony_ci		else if (buswidth == 2)
430562306a36Sopenharmony_ci			sr14 |= 0x40;
430662306a36Sopenharmony_ci
430762306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x13, SiS_DRAMType[k][4]);
430862306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x14, sr14);
430962306a36Sopenharmony_ci
431062306a36Sopenharmony_ci		BankNumHigh <<= 16;
431162306a36Sopenharmony_ci		BankNumMid <<= 16;
431262306a36Sopenharmony_ci
431362306a36Sopenharmony_ci		if ((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
431462306a36Sopenharmony_ci		    (BankNumMid  + PhysicalAdrHigh >= mapsize) ||
431562306a36Sopenharmony_ci		    (BankNumHigh + PhysicalAdrHalfPage  >= mapsize) ||
431662306a36Sopenharmony_ci		    (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
431762306a36Sopenharmony_ci			continue;
431862306a36Sopenharmony_ci
431962306a36Sopenharmony_ci		/* Write data */
432062306a36Sopenharmony_ci		writew(((unsigned short)PhysicalAdrHigh),
432162306a36Sopenharmony_ci				(FBAddr + BankNumHigh + PhysicalAdrHigh));
432262306a36Sopenharmony_ci		writew(((unsigned short)BankNumMid),
432362306a36Sopenharmony_ci				(FBAddr + BankNumMid  + PhysicalAdrHigh));
432462306a36Sopenharmony_ci		writew(((unsigned short)PhysicalAdrHalfPage),
432562306a36Sopenharmony_ci				(FBAddr + BankNumHigh + PhysicalAdrHalfPage));
432662306a36Sopenharmony_ci		writew(((unsigned short)PhysicalAdrOtherPage),
432762306a36Sopenharmony_ci				(FBAddr + BankNumHigh + PhysicalAdrOtherPage));
432862306a36Sopenharmony_ci
432962306a36Sopenharmony_ci		/* Read data */
433062306a36Sopenharmony_ci		if (readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
433162306a36Sopenharmony_ci			return 1;
433262306a36Sopenharmony_ci	}
433362306a36Sopenharmony_ci
433462306a36Sopenharmony_ci	return 0;
433562306a36Sopenharmony_ci}
433662306a36Sopenharmony_ci
433762306a36Sopenharmony_cistatic void sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
433862306a36Sopenharmony_ci{
433962306a36Sopenharmony_ci	struct	sis_video_info *ivideo = pci_get_drvdata(pdev);
434062306a36Sopenharmony_ci	int	i, j, buswidth;
434162306a36Sopenharmony_ci	int	PseudoRankCapacity, PseudoAdrPinCount;
434262306a36Sopenharmony_ci
434362306a36Sopenharmony_ci	buswidth = sisfb_post_300_buswidth(ivideo);
434462306a36Sopenharmony_ci
434562306a36Sopenharmony_ci	for(i = 6; i >= 0; i--) {
434662306a36Sopenharmony_ci		PseudoRankCapacity = 1 << i;
434762306a36Sopenharmony_ci		for(j = 4; j >= 1; j--) {
434862306a36Sopenharmony_ci			PseudoAdrPinCount = 15 - j;
434962306a36Sopenharmony_ci			if((PseudoRankCapacity * j) <= 64) {
435062306a36Sopenharmony_ci				if(sisfb_post_300_rwtest(ivideo,
435162306a36Sopenharmony_ci						j,
435262306a36Sopenharmony_ci						buswidth,
435362306a36Sopenharmony_ci						PseudoRankCapacity,
435462306a36Sopenharmony_ci						PseudoAdrPinCount,
435562306a36Sopenharmony_ci						mapsize))
435662306a36Sopenharmony_ci					return;
435762306a36Sopenharmony_ci			}
435862306a36Sopenharmony_ci		}
435962306a36Sopenharmony_ci	}
436062306a36Sopenharmony_ci}
436162306a36Sopenharmony_ci
436262306a36Sopenharmony_cistatic void sisfb_post_sis300(struct pci_dev *pdev)
436362306a36Sopenharmony_ci{
436462306a36Sopenharmony_ci	struct sis_video_info *ivideo = pci_get_drvdata(pdev);
436562306a36Sopenharmony_ci	unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
436662306a36Sopenharmony_ci	u8  reg, v1, v2, v3, v4, v5, v6, v7, v8;
436762306a36Sopenharmony_ci	u16 index, rindex, memtype = 0;
436862306a36Sopenharmony_ci	unsigned int mapsize;
436962306a36Sopenharmony_ci
437062306a36Sopenharmony_ci	if(!ivideo->SiS_Pr.UseROM)
437162306a36Sopenharmony_ci		bios = NULL;
437262306a36Sopenharmony_ci
437362306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x05, 0x86);
437462306a36Sopenharmony_ci
437562306a36Sopenharmony_ci	if(bios) {
437662306a36Sopenharmony_ci		if(bios[0x52] & 0x80) {
437762306a36Sopenharmony_ci			memtype = bios[0x52];
437862306a36Sopenharmony_ci		} else {
437962306a36Sopenharmony_ci			memtype = SiS_GetReg(SISSR, 0x3a);
438062306a36Sopenharmony_ci		}
438162306a36Sopenharmony_ci		memtype &= 0x07;
438262306a36Sopenharmony_ci	}
438362306a36Sopenharmony_ci
438462306a36Sopenharmony_ci	v3 = 0x80; v6 = 0x80;
438562306a36Sopenharmony_ci	if(ivideo->revision_id <= 0x13) {
438662306a36Sopenharmony_ci		v1 = 0x44; v2 = 0x42;
438762306a36Sopenharmony_ci		v4 = 0x44; v5 = 0x42;
438862306a36Sopenharmony_ci	} else {
438962306a36Sopenharmony_ci		v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
439062306a36Sopenharmony_ci		v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
439162306a36Sopenharmony_ci		if(bios) {
439262306a36Sopenharmony_ci			index = memtype * 5;
439362306a36Sopenharmony_ci			rindex = index + 0x54;
439462306a36Sopenharmony_ci			v1 = bios[rindex++];
439562306a36Sopenharmony_ci			v2 = bios[rindex++];
439662306a36Sopenharmony_ci			v3 = bios[rindex++];
439762306a36Sopenharmony_ci			rindex = index + 0x7c;
439862306a36Sopenharmony_ci			v4 = bios[rindex++];
439962306a36Sopenharmony_ci			v5 = bios[rindex++];
440062306a36Sopenharmony_ci			v6 = bios[rindex++];
440162306a36Sopenharmony_ci		}
440262306a36Sopenharmony_ci	}
440362306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x28, v1);
440462306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x29, v2);
440562306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x2a, v3);
440662306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x2e, v4);
440762306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x2f, v5);
440862306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x30, v6);
440962306a36Sopenharmony_ci
441062306a36Sopenharmony_ci	v1 = 0x10;
441162306a36Sopenharmony_ci	if(bios)
441262306a36Sopenharmony_ci		v1 = bios[0xa4];
441362306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x07, v1);       /* DAC speed */
441462306a36Sopenharmony_ci
441562306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x11, 0x0f);     /* DDC, power save */
441662306a36Sopenharmony_ci
441762306a36Sopenharmony_ci	v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
441862306a36Sopenharmony_ci	v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
441962306a36Sopenharmony_ci	if(bios) {
442062306a36Sopenharmony_ci		memtype += 0xa5;
442162306a36Sopenharmony_ci		v1 = bios[memtype];
442262306a36Sopenharmony_ci		v2 = bios[memtype + 8];
442362306a36Sopenharmony_ci		v3 = bios[memtype + 16];
442462306a36Sopenharmony_ci		v4 = bios[memtype + 24];
442562306a36Sopenharmony_ci		v5 = bios[memtype + 32];
442662306a36Sopenharmony_ci		v6 = bios[memtype + 40];
442762306a36Sopenharmony_ci		v7 = bios[memtype + 48];
442862306a36Sopenharmony_ci		v8 = bios[memtype + 56];
442962306a36Sopenharmony_ci	}
443062306a36Sopenharmony_ci	if(ivideo->revision_id >= 0x80)
443162306a36Sopenharmony_ci		v3 &= 0xfd;
443262306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x15, v1);       /* Ram type (assuming 0, BIOS 0xa5 step 8) */
443362306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x16, v2);
443462306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x17, v3);
443562306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x18, v4);
443662306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x19, v5);
443762306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x1a, v6);
443862306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x1b, v7);
443962306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x1c, v8);	   /* ---- */
444062306a36Sopenharmony_ci	SiS_SetRegAND(SISSR, 0x15, 0xfb);
444162306a36Sopenharmony_ci	SiS_SetRegOR(SISSR, 0x15, 0x04);
444262306a36Sopenharmony_ci	if(bios) {
444362306a36Sopenharmony_ci		if(bios[0x53] & 0x02) {
444462306a36Sopenharmony_ci			SiS_SetRegOR(SISSR, 0x19, 0x20);
444562306a36Sopenharmony_ci		}
444662306a36Sopenharmony_ci	}
444762306a36Sopenharmony_ci	v1 = 0x04;			   /* DAC pedestal (BIOS 0xe5) */
444862306a36Sopenharmony_ci	if(ivideo->revision_id >= 0x80)
444962306a36Sopenharmony_ci		v1 |= 0x01;
445062306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x1f, v1);
445162306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x20, 0xa4);     /* linear & relocated io & disable a0000 */
445262306a36Sopenharmony_ci	v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
445362306a36Sopenharmony_ci	if(bios) {
445462306a36Sopenharmony_ci		v1 = bios[0xe8];
445562306a36Sopenharmony_ci		v2 = bios[0xe9];
445662306a36Sopenharmony_ci		v3 = bios[0xea];
445762306a36Sopenharmony_ci	}
445862306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x23, v1);
445962306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x24, v2);
446062306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x25, v3);
446162306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x21, 0x84);
446262306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x22, 0x00);
446362306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x37, 0x00);
446462306a36Sopenharmony_ci	SiS_SetRegOR(SISPART1, 0x24, 0x01);   /* unlock crt2 */
446562306a36Sopenharmony_ci	SiS_SetReg(SISPART1, 0x00, 0x00);
446662306a36Sopenharmony_ci	v1 = 0x40; v2 = 0x11;
446762306a36Sopenharmony_ci	if(bios) {
446862306a36Sopenharmony_ci		v1 = bios[0xec];
446962306a36Sopenharmony_ci		v2 = bios[0xeb];
447062306a36Sopenharmony_ci	}
447162306a36Sopenharmony_ci	SiS_SetReg(SISPART1, 0x02, v1);
447262306a36Sopenharmony_ci
447362306a36Sopenharmony_ci	if(ivideo->revision_id >= 0x80)
447462306a36Sopenharmony_ci		v2 &= ~0x01;
447562306a36Sopenharmony_ci
447662306a36Sopenharmony_ci	reg = SiS_GetReg(SISPART4, 0x00);
447762306a36Sopenharmony_ci	if((reg == 1) || (reg == 2)) {
447862306a36Sopenharmony_ci		SiS_SetReg(SISCR, 0x37, 0x02);
447962306a36Sopenharmony_ci		SiS_SetReg(SISPART2, 0x00, 0x1c);
448062306a36Sopenharmony_ci		v4 = 0x00; v5 = 0x00; v6 = 0x10;
448162306a36Sopenharmony_ci		if (ivideo->SiS_Pr.UseROM && bios) {
448262306a36Sopenharmony_ci			v4 = bios[0xf5];
448362306a36Sopenharmony_ci			v5 = bios[0xf6];
448462306a36Sopenharmony_ci			v6 = bios[0xf7];
448562306a36Sopenharmony_ci		}
448662306a36Sopenharmony_ci		SiS_SetReg(SISPART4, 0x0d, v4);
448762306a36Sopenharmony_ci		SiS_SetReg(SISPART4, 0x0e, v5);
448862306a36Sopenharmony_ci		SiS_SetReg(SISPART4, 0x10, v6);
448962306a36Sopenharmony_ci		SiS_SetReg(SISPART4, 0x0f, 0x3f);
449062306a36Sopenharmony_ci		reg = SiS_GetReg(SISPART4, 0x01);
449162306a36Sopenharmony_ci		if(reg >= 0xb0) {
449262306a36Sopenharmony_ci			reg = SiS_GetReg(SISPART4, 0x23);
449362306a36Sopenharmony_ci			reg &= 0x20;
449462306a36Sopenharmony_ci			reg <<= 1;
449562306a36Sopenharmony_ci			SiS_SetReg(SISPART4, 0x23, reg);
449662306a36Sopenharmony_ci		}
449762306a36Sopenharmony_ci	} else {
449862306a36Sopenharmony_ci		v2 &= ~0x10;
449962306a36Sopenharmony_ci	}
450062306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x32, v2);
450162306a36Sopenharmony_ci
450262306a36Sopenharmony_ci	SiS_SetRegAND(SISPART1, 0x24, 0xfe);  /* Lock CRT2 */
450362306a36Sopenharmony_ci
450462306a36Sopenharmony_ci	reg = SiS_GetReg(SISSR, 0x16);
450562306a36Sopenharmony_ci	reg &= 0xc3;
450662306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x35, reg);
450762306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x83, 0x00);
450862306a36Sopenharmony_ci#if !defined(__i386__) && !defined(__x86_64__)
450962306a36Sopenharmony_ci	if(sisfb_videoram) {
451062306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x13, 0x28);  /* ? */
451162306a36Sopenharmony_ci		reg = ((sisfb_videoram >> 10) - 1) | 0x40;
451262306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x14, reg);
451362306a36Sopenharmony_ci	} else {
451462306a36Sopenharmony_ci#endif
451562306a36Sopenharmony_ci		/* Need to map max FB size for finding out about RAM size */
451662306a36Sopenharmony_ci		mapsize = ivideo->video_size;
451762306a36Sopenharmony_ci		sisfb_post_map_vram(ivideo, &mapsize, 4);
451862306a36Sopenharmony_ci
451962306a36Sopenharmony_ci		if(ivideo->video_vbase) {
452062306a36Sopenharmony_ci			sisfb_post_300_ramsize(pdev, mapsize);
452162306a36Sopenharmony_ci			iounmap(ivideo->video_vbase);
452262306a36Sopenharmony_ci		} else {
452362306a36Sopenharmony_ci			printk(KERN_DEBUG
452462306a36Sopenharmony_ci				"sisfb: Failed to map memory for size detection, assuming 8MB\n");
452562306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x13, 0x28);  /* ? */
452662306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x14, 0x47);  /* 8MB, 64bit default */
452762306a36Sopenharmony_ci		}
452862306a36Sopenharmony_ci#if !defined(__i386__) && !defined(__x86_64__)
452962306a36Sopenharmony_ci	}
453062306a36Sopenharmony_ci#endif
453162306a36Sopenharmony_ci	if(bios) {
453262306a36Sopenharmony_ci		v1 = bios[0xe6];
453362306a36Sopenharmony_ci		v2 = bios[0xe7];
453462306a36Sopenharmony_ci	} else {
453562306a36Sopenharmony_ci		reg = SiS_GetReg(SISSR, 0x3a);
453662306a36Sopenharmony_ci		if((reg & 0x30) == 0x30) {
453762306a36Sopenharmony_ci			v1 = 0x04; /* PCI */
453862306a36Sopenharmony_ci			v2 = 0x92;
453962306a36Sopenharmony_ci		} else {
454062306a36Sopenharmony_ci			v1 = 0x14; /* AGP */
454162306a36Sopenharmony_ci			v2 = 0xb2;
454262306a36Sopenharmony_ci		}
454362306a36Sopenharmony_ci	}
454462306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x21, v1);
454562306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x22, v2);
454662306a36Sopenharmony_ci
454762306a36Sopenharmony_ci	/* Sense CRT1 */
454862306a36Sopenharmony_ci	sisfb_sense_crt1(ivideo);
454962306a36Sopenharmony_ci
455062306a36Sopenharmony_ci	/* Set default mode, don't clear screen */
455162306a36Sopenharmony_ci	ivideo->SiS_Pr.SiS_UseOEM = false;
455262306a36Sopenharmony_ci	SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
455362306a36Sopenharmony_ci	SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
455462306a36Sopenharmony_ci	ivideo->curFSTN = ivideo->curDSTN = 0;
455562306a36Sopenharmony_ci	ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
455662306a36Sopenharmony_ci	SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
455762306a36Sopenharmony_ci
455862306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x05, 0x86);
455962306a36Sopenharmony_ci
456062306a36Sopenharmony_ci	/* Display off */
456162306a36Sopenharmony_ci	SiS_SetRegOR(SISSR, 0x01, 0x20);
456262306a36Sopenharmony_ci
456362306a36Sopenharmony_ci	/* Save mode number in CR34 */
456462306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x34, 0x2e);
456562306a36Sopenharmony_ci
456662306a36Sopenharmony_ci	/* Let everyone know what the current mode is */
456762306a36Sopenharmony_ci	ivideo->modeprechange = 0x2e;
456862306a36Sopenharmony_ci}
456962306a36Sopenharmony_ci#endif
457062306a36Sopenharmony_ci
457162306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
457262306a36Sopenharmony_ci#if 0
457362306a36Sopenharmony_cistatic void sisfb_post_sis315330(struct pci_dev *pdev)
457462306a36Sopenharmony_ci{
457562306a36Sopenharmony_ci	/* TODO */
457662306a36Sopenharmony_ci}
457762306a36Sopenharmony_ci#endif
457862306a36Sopenharmony_ci
457962306a36Sopenharmony_cistatic inline int sisfb_xgi_is21(struct sis_video_info *ivideo)
458062306a36Sopenharmony_ci{
458162306a36Sopenharmony_ci	return ivideo->chip_real_id == XGI_21;
458262306a36Sopenharmony_ci}
458362306a36Sopenharmony_ci
458462306a36Sopenharmony_cistatic void sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
458562306a36Sopenharmony_ci{
458662306a36Sopenharmony_ci	unsigned int i;
458762306a36Sopenharmony_ci	u8 reg;
458862306a36Sopenharmony_ci
458962306a36Sopenharmony_ci	for(i = 0; i <= (delay * 10 * 36); i++) {
459062306a36Sopenharmony_ci		reg = SiS_GetReg(SISSR, 0x05);
459162306a36Sopenharmony_ci		reg++;
459262306a36Sopenharmony_ci	}
459362306a36Sopenharmony_ci}
459462306a36Sopenharmony_ci
459562306a36Sopenharmony_cistatic int sisfb_find_host_bridge(struct sis_video_info *ivideo,
459662306a36Sopenharmony_ci				  struct pci_dev *mypdev,
459762306a36Sopenharmony_ci				  unsigned short pcivendor)
459862306a36Sopenharmony_ci{
459962306a36Sopenharmony_ci	struct pci_dev *pdev = NULL;
460062306a36Sopenharmony_ci	unsigned short temp;
460162306a36Sopenharmony_ci	int ret = 0;
460262306a36Sopenharmony_ci
460362306a36Sopenharmony_ci	while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
460462306a36Sopenharmony_ci		temp = pdev->vendor;
460562306a36Sopenharmony_ci		if(temp == pcivendor) {
460662306a36Sopenharmony_ci			ret = 1;
460762306a36Sopenharmony_ci			pci_dev_put(pdev);
460862306a36Sopenharmony_ci			break;
460962306a36Sopenharmony_ci		}
461062306a36Sopenharmony_ci	}
461162306a36Sopenharmony_ci
461262306a36Sopenharmony_ci	return ret;
461362306a36Sopenharmony_ci}
461462306a36Sopenharmony_ci
461562306a36Sopenharmony_cistatic int sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
461662306a36Sopenharmony_ci				 unsigned int enda, unsigned int mapsize)
461762306a36Sopenharmony_ci{
461862306a36Sopenharmony_ci	unsigned int pos;
461962306a36Sopenharmony_ci	int i;
462062306a36Sopenharmony_ci
462162306a36Sopenharmony_ci	writel(0, ivideo->video_vbase);
462262306a36Sopenharmony_ci
462362306a36Sopenharmony_ci	for(i = starta; i <= enda; i++) {
462462306a36Sopenharmony_ci		pos = 1 << i;
462562306a36Sopenharmony_ci		if(pos < mapsize)
462662306a36Sopenharmony_ci			writel(pos, ivideo->video_vbase + pos);
462762306a36Sopenharmony_ci	}
462862306a36Sopenharmony_ci
462962306a36Sopenharmony_ci	sisfb_post_xgi_delay(ivideo, 150);
463062306a36Sopenharmony_ci
463162306a36Sopenharmony_ci	if(readl(ivideo->video_vbase) != 0)
463262306a36Sopenharmony_ci		return 0;
463362306a36Sopenharmony_ci
463462306a36Sopenharmony_ci	for(i = starta; i <= enda; i++) {
463562306a36Sopenharmony_ci		pos = 1 << i;
463662306a36Sopenharmony_ci		if(pos < mapsize) {
463762306a36Sopenharmony_ci			if(readl(ivideo->video_vbase + pos) != pos)
463862306a36Sopenharmony_ci				return 0;
463962306a36Sopenharmony_ci		} else
464062306a36Sopenharmony_ci			return 0;
464162306a36Sopenharmony_ci	}
464262306a36Sopenharmony_ci
464362306a36Sopenharmony_ci	return 1;
464462306a36Sopenharmony_ci}
464562306a36Sopenharmony_ci
464662306a36Sopenharmony_cistatic int sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
464762306a36Sopenharmony_ci{
464862306a36Sopenharmony_ci	unsigned int buswidth, ranksize, channelab, mapsize;
464962306a36Sopenharmony_ci	int i, j, k, l, status;
465062306a36Sopenharmony_ci	u8 reg, sr14;
465162306a36Sopenharmony_ci	static const u8 dramsr13[12 * 5] = {
465262306a36Sopenharmony_ci		0x02, 0x0e, 0x0b, 0x80, 0x5d,
465362306a36Sopenharmony_ci		0x02, 0x0e, 0x0a, 0x40, 0x59,
465462306a36Sopenharmony_ci		0x02, 0x0d, 0x0b, 0x40, 0x4d,
465562306a36Sopenharmony_ci		0x02, 0x0e, 0x09, 0x20, 0x55,
465662306a36Sopenharmony_ci		0x02, 0x0d, 0x0a, 0x20, 0x49,
465762306a36Sopenharmony_ci		0x02, 0x0c, 0x0b, 0x20, 0x3d,
465862306a36Sopenharmony_ci		0x02, 0x0e, 0x08, 0x10, 0x51,
465962306a36Sopenharmony_ci		0x02, 0x0d, 0x09, 0x10, 0x45,
466062306a36Sopenharmony_ci		0x02, 0x0c, 0x0a, 0x10, 0x39,
466162306a36Sopenharmony_ci		0x02, 0x0d, 0x08, 0x08, 0x41,
466262306a36Sopenharmony_ci		0x02, 0x0c, 0x09, 0x08, 0x35,
466362306a36Sopenharmony_ci		0x02, 0x0c, 0x08, 0x04, 0x31
466462306a36Sopenharmony_ci	};
466562306a36Sopenharmony_ci	static const u8 dramsr13_4[4 * 5] = {
466662306a36Sopenharmony_ci		0x02, 0x0d, 0x09, 0x40, 0x45,
466762306a36Sopenharmony_ci		0x02, 0x0c, 0x09, 0x20, 0x35,
466862306a36Sopenharmony_ci		0x02, 0x0c, 0x08, 0x10, 0x31,
466962306a36Sopenharmony_ci		0x02, 0x0b, 0x08, 0x08, 0x21
467062306a36Sopenharmony_ci	};
467162306a36Sopenharmony_ci
467262306a36Sopenharmony_ci	/* Enable linear mode, disable 0xa0000 address decoding */
467362306a36Sopenharmony_ci	/* We disable a0000 address decoding, because
467462306a36Sopenharmony_ci	 * - if running on x86, if the card is disabled, it means
467562306a36Sopenharmony_ci	 *   that another card is in the system. We don't want
467662306a36Sopenharmony_ci	 *   to interphere with that primary card's textmode.
467762306a36Sopenharmony_ci	 * - if running on non-x86, there usually is no VGA window
467862306a36Sopenharmony_ci	 *   at a0000.
467962306a36Sopenharmony_ci	 */
468062306a36Sopenharmony_ci	SiS_SetRegOR(SISSR, 0x20, (0x80 | 0x04));
468162306a36Sopenharmony_ci
468262306a36Sopenharmony_ci	/* Need to map max FB size for finding out about RAM size */
468362306a36Sopenharmony_ci	mapsize = ivideo->video_size;
468462306a36Sopenharmony_ci	sisfb_post_map_vram(ivideo, &mapsize, 32);
468562306a36Sopenharmony_ci
468662306a36Sopenharmony_ci	if(!ivideo->video_vbase) {
468762306a36Sopenharmony_ci		printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
468862306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x13, 0x35);
468962306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x14, 0x41);
469062306a36Sopenharmony_ci		/* TODO */
469162306a36Sopenharmony_ci		return -ENOMEM;
469262306a36Sopenharmony_ci	}
469362306a36Sopenharmony_ci
469462306a36Sopenharmony_ci	/* Non-interleaving */
469562306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x15, 0x00);
469662306a36Sopenharmony_ci	/* No tiling */
469762306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x1c, 0x00);
469862306a36Sopenharmony_ci
469962306a36Sopenharmony_ci	if(ivideo->chip == XGI_20) {
470062306a36Sopenharmony_ci
470162306a36Sopenharmony_ci		channelab = 1;
470262306a36Sopenharmony_ci		reg = SiS_GetReg(SISCR, 0x97);
470362306a36Sopenharmony_ci		if(!(reg & 0x01)) {	/* Single 32/16 */
470462306a36Sopenharmony_ci			buswidth = 32;
470562306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x13, 0xb1);
470662306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x14, 0x52);
470762306a36Sopenharmony_ci			sisfb_post_xgi_delay(ivideo, 1);
470862306a36Sopenharmony_ci			sr14 = 0x02;
470962306a36Sopenharmony_ci			if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
471062306a36Sopenharmony_ci				goto bail_out;
471162306a36Sopenharmony_ci
471262306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x13, 0x31);
471362306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x14, 0x42);
471462306a36Sopenharmony_ci			sisfb_post_xgi_delay(ivideo, 1);
471562306a36Sopenharmony_ci			if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
471662306a36Sopenharmony_ci				goto bail_out;
471762306a36Sopenharmony_ci
471862306a36Sopenharmony_ci			buswidth = 16;
471962306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x13, 0xb1);
472062306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x14, 0x41);
472162306a36Sopenharmony_ci			sisfb_post_xgi_delay(ivideo, 1);
472262306a36Sopenharmony_ci			sr14 = 0x01;
472362306a36Sopenharmony_ci			if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
472462306a36Sopenharmony_ci				goto bail_out;
472562306a36Sopenharmony_ci			else
472662306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x13, 0x31);
472762306a36Sopenharmony_ci		} else {		/* Dual 16/8 */
472862306a36Sopenharmony_ci			buswidth = 16;
472962306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x13, 0xb1);
473062306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x14, 0x41);
473162306a36Sopenharmony_ci			sisfb_post_xgi_delay(ivideo, 1);
473262306a36Sopenharmony_ci			sr14 = 0x01;
473362306a36Sopenharmony_ci			if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
473462306a36Sopenharmony_ci				goto bail_out;
473562306a36Sopenharmony_ci
473662306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x13, 0x31);
473762306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x14, 0x31);
473862306a36Sopenharmony_ci			sisfb_post_xgi_delay(ivideo, 1);
473962306a36Sopenharmony_ci			if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
474062306a36Sopenharmony_ci				goto bail_out;
474162306a36Sopenharmony_ci
474262306a36Sopenharmony_ci			buswidth = 8;
474362306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x13, 0xb1);
474462306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x14, 0x30);
474562306a36Sopenharmony_ci			sisfb_post_xgi_delay(ivideo, 1);
474662306a36Sopenharmony_ci			sr14 = 0x00;
474762306a36Sopenharmony_ci			if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
474862306a36Sopenharmony_ci				goto bail_out;
474962306a36Sopenharmony_ci			else
475062306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x13, 0x31);
475162306a36Sopenharmony_ci		}
475262306a36Sopenharmony_ci
475362306a36Sopenharmony_ci	} else {	/* XGI_40 */
475462306a36Sopenharmony_ci
475562306a36Sopenharmony_ci		reg = SiS_GetReg(SISCR, 0x97);
475662306a36Sopenharmony_ci		if(!(reg & 0x10)) {
475762306a36Sopenharmony_ci			reg = SiS_GetReg(SISSR, 0x39);
475862306a36Sopenharmony_ci			reg >>= 1;
475962306a36Sopenharmony_ci		}
476062306a36Sopenharmony_ci
476162306a36Sopenharmony_ci		if(reg & 0x01) {	/* DDRII */
476262306a36Sopenharmony_ci			buswidth = 32;
476362306a36Sopenharmony_ci			if(ivideo->revision_id == 2) {
476462306a36Sopenharmony_ci				channelab = 2;
476562306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x13, 0xa1);
476662306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x14, 0x44);
476762306a36Sopenharmony_ci				sr14 = 0x04;
476862306a36Sopenharmony_ci				sisfb_post_xgi_delay(ivideo, 1);
476962306a36Sopenharmony_ci				if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
477062306a36Sopenharmony_ci					goto bail_out;
477162306a36Sopenharmony_ci
477262306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x13, 0x21);
477362306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x14, 0x34);
477462306a36Sopenharmony_ci				if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
477562306a36Sopenharmony_ci					goto bail_out;
477662306a36Sopenharmony_ci
477762306a36Sopenharmony_ci				channelab = 1;
477862306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x13, 0xa1);
477962306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x14, 0x40);
478062306a36Sopenharmony_ci				sr14 = 0x00;
478162306a36Sopenharmony_ci				if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
478262306a36Sopenharmony_ci					goto bail_out;
478362306a36Sopenharmony_ci
478462306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x13, 0x21);
478562306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x14, 0x30);
478662306a36Sopenharmony_ci			} else {
478762306a36Sopenharmony_ci				channelab = 3;
478862306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x13, 0xa1);
478962306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x14, 0x4c);
479062306a36Sopenharmony_ci				sr14 = 0x0c;
479162306a36Sopenharmony_ci				sisfb_post_xgi_delay(ivideo, 1);
479262306a36Sopenharmony_ci				if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
479362306a36Sopenharmony_ci					goto bail_out;
479462306a36Sopenharmony_ci
479562306a36Sopenharmony_ci				channelab = 2;
479662306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x14, 0x48);
479762306a36Sopenharmony_ci				sisfb_post_xgi_delay(ivideo, 1);
479862306a36Sopenharmony_ci				sr14 = 0x08;
479962306a36Sopenharmony_ci				if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
480062306a36Sopenharmony_ci					goto bail_out;
480162306a36Sopenharmony_ci
480262306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x13, 0x21);
480362306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x14, 0x3c);
480462306a36Sopenharmony_ci				sr14 = 0x0c;
480562306a36Sopenharmony_ci
480662306a36Sopenharmony_ci				if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
480762306a36Sopenharmony_ci					channelab = 3;
480862306a36Sopenharmony_ci				} else {
480962306a36Sopenharmony_ci					channelab = 2;
481062306a36Sopenharmony_ci					SiS_SetReg(SISSR, 0x14, 0x38);
481162306a36Sopenharmony_ci					sr14 = 0x08;
481262306a36Sopenharmony_ci				}
481362306a36Sopenharmony_ci			}
481462306a36Sopenharmony_ci			sisfb_post_xgi_delay(ivideo, 1);
481562306a36Sopenharmony_ci
481662306a36Sopenharmony_ci		} else {	/* DDR */
481762306a36Sopenharmony_ci
481862306a36Sopenharmony_ci			buswidth = 64;
481962306a36Sopenharmony_ci			if(ivideo->revision_id == 2) {
482062306a36Sopenharmony_ci				channelab = 1;
482162306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x13, 0xa1);
482262306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x14, 0x52);
482362306a36Sopenharmony_ci				sisfb_post_xgi_delay(ivideo, 1);
482462306a36Sopenharmony_ci				sr14 = 0x02;
482562306a36Sopenharmony_ci				if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
482662306a36Sopenharmony_ci					goto bail_out;
482762306a36Sopenharmony_ci
482862306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x13, 0x21);
482962306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x14, 0x42);
483062306a36Sopenharmony_ci			} else {
483162306a36Sopenharmony_ci				channelab = 2;
483262306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x13, 0xa1);
483362306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x14, 0x5a);
483462306a36Sopenharmony_ci				sisfb_post_xgi_delay(ivideo, 1);
483562306a36Sopenharmony_ci				sr14 = 0x0a;
483662306a36Sopenharmony_ci				if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
483762306a36Sopenharmony_ci					goto bail_out;
483862306a36Sopenharmony_ci
483962306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x13, 0x21);
484062306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x14, 0x4a);
484162306a36Sopenharmony_ci			}
484262306a36Sopenharmony_ci			sisfb_post_xgi_delay(ivideo, 1);
484362306a36Sopenharmony_ci
484462306a36Sopenharmony_ci		}
484562306a36Sopenharmony_ci	}
484662306a36Sopenharmony_ci
484762306a36Sopenharmony_cibail_out:
484862306a36Sopenharmony_ci	SiS_SetRegANDOR(SISSR, 0x14, 0xf0, sr14);
484962306a36Sopenharmony_ci	sisfb_post_xgi_delay(ivideo, 1);
485062306a36Sopenharmony_ci
485162306a36Sopenharmony_ci	j = (ivideo->chip == XGI_20) ? 5 : 9;
485262306a36Sopenharmony_ci	k = (ivideo->chip == XGI_20) ? 12 : 4;
485362306a36Sopenharmony_ci	status = -EIO;
485462306a36Sopenharmony_ci
485562306a36Sopenharmony_ci	for(i = 0; i < k; i++) {
485662306a36Sopenharmony_ci
485762306a36Sopenharmony_ci		reg = (ivideo->chip == XGI_20) ?
485862306a36Sopenharmony_ci				dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
485962306a36Sopenharmony_ci		SiS_SetRegANDOR(SISSR, 0x13, 0x80, reg);
486062306a36Sopenharmony_ci		sisfb_post_xgi_delay(ivideo, 50);
486162306a36Sopenharmony_ci
486262306a36Sopenharmony_ci		ranksize = (ivideo->chip == XGI_20) ?
486362306a36Sopenharmony_ci				dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
486462306a36Sopenharmony_ci
486562306a36Sopenharmony_ci		reg = SiS_GetReg(SISSR, 0x13);
486662306a36Sopenharmony_ci		if(reg & 0x80) ranksize <<= 1;
486762306a36Sopenharmony_ci
486862306a36Sopenharmony_ci		if(ivideo->chip == XGI_20) {
486962306a36Sopenharmony_ci			if(buswidth == 16)      ranksize <<= 1;
487062306a36Sopenharmony_ci			else if(buswidth == 32) ranksize <<= 2;
487162306a36Sopenharmony_ci		} else {
487262306a36Sopenharmony_ci			if(buswidth == 64)      ranksize <<= 1;
487362306a36Sopenharmony_ci		}
487462306a36Sopenharmony_ci
487562306a36Sopenharmony_ci		reg = 0;
487662306a36Sopenharmony_ci		l = channelab;
487762306a36Sopenharmony_ci		if(l == 3) l = 4;
487862306a36Sopenharmony_ci		if((ranksize * l) <= 256) {
487962306a36Sopenharmony_ci			while((ranksize >>= 1)) reg += 0x10;
488062306a36Sopenharmony_ci		}
488162306a36Sopenharmony_ci
488262306a36Sopenharmony_ci		if(!reg) continue;
488362306a36Sopenharmony_ci
488462306a36Sopenharmony_ci		SiS_SetRegANDOR(SISSR, 0x14, 0x0f, (reg & 0xf0));
488562306a36Sopenharmony_ci		sisfb_post_xgi_delay(ivideo, 1);
488662306a36Sopenharmony_ci
488762306a36Sopenharmony_ci		if (sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize)) {
488862306a36Sopenharmony_ci			status = 0;
488962306a36Sopenharmony_ci			break;
489062306a36Sopenharmony_ci		}
489162306a36Sopenharmony_ci	}
489262306a36Sopenharmony_ci
489362306a36Sopenharmony_ci	iounmap(ivideo->video_vbase);
489462306a36Sopenharmony_ci
489562306a36Sopenharmony_ci	return status;
489662306a36Sopenharmony_ci}
489762306a36Sopenharmony_ci
489862306a36Sopenharmony_cistatic void sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
489962306a36Sopenharmony_ci{
490062306a36Sopenharmony_ci	u8 v1, v2, v3;
490162306a36Sopenharmony_ci	int index;
490262306a36Sopenharmony_ci	static const u8 cs90[8 * 3] = {
490362306a36Sopenharmony_ci		0x16, 0x01, 0x01,
490462306a36Sopenharmony_ci		0x3e, 0x03, 0x01,
490562306a36Sopenharmony_ci		0x7c, 0x08, 0x01,
490662306a36Sopenharmony_ci		0x79, 0x06, 0x01,
490762306a36Sopenharmony_ci		0x29, 0x01, 0x81,
490862306a36Sopenharmony_ci		0x5c, 0x23, 0x01,
490962306a36Sopenharmony_ci		0x5c, 0x23, 0x01,
491062306a36Sopenharmony_ci		0x5c, 0x23, 0x01
491162306a36Sopenharmony_ci	};
491262306a36Sopenharmony_ci	static const u8 csb8[8 * 3] = {
491362306a36Sopenharmony_ci		0x5c, 0x23, 0x01,
491462306a36Sopenharmony_ci		0x29, 0x01, 0x01,
491562306a36Sopenharmony_ci		0x7c, 0x08, 0x01,
491662306a36Sopenharmony_ci		0x79, 0x06, 0x01,
491762306a36Sopenharmony_ci		0x29, 0x01, 0x81,
491862306a36Sopenharmony_ci		0x5c, 0x23, 0x01,
491962306a36Sopenharmony_ci		0x5c, 0x23, 0x01,
492062306a36Sopenharmony_ci		0x5c, 0x23, 0x01
492162306a36Sopenharmony_ci	};
492262306a36Sopenharmony_ci
492362306a36Sopenharmony_ci	regb = 0;  /* ! */
492462306a36Sopenharmony_ci
492562306a36Sopenharmony_ci	index = regb * 3;
492662306a36Sopenharmony_ci	v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
492762306a36Sopenharmony_ci	if(ivideo->haveXGIROM) {
492862306a36Sopenharmony_ci		v1 = ivideo->bios_abase[0x90 + index];
492962306a36Sopenharmony_ci		v2 = ivideo->bios_abase[0x90 + index + 1];
493062306a36Sopenharmony_ci		v3 = ivideo->bios_abase[0x90 + index + 2];
493162306a36Sopenharmony_ci	}
493262306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x28, v1);
493362306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x29, v2);
493462306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x2a, v3);
493562306a36Sopenharmony_ci	sisfb_post_xgi_delay(ivideo, 0x43);
493662306a36Sopenharmony_ci	sisfb_post_xgi_delay(ivideo, 0x43);
493762306a36Sopenharmony_ci	sisfb_post_xgi_delay(ivideo, 0x43);
493862306a36Sopenharmony_ci	index = regb * 3;
493962306a36Sopenharmony_ci	v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
494062306a36Sopenharmony_ci	if(ivideo->haveXGIROM) {
494162306a36Sopenharmony_ci		v1 = ivideo->bios_abase[0xb8 + index];
494262306a36Sopenharmony_ci		v2 = ivideo->bios_abase[0xb8 + index + 1];
494362306a36Sopenharmony_ci		v3 = ivideo->bios_abase[0xb8 + index + 2];
494462306a36Sopenharmony_ci	}
494562306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x2e, v1);
494662306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x2f, v2);
494762306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x30, v3);
494862306a36Sopenharmony_ci	sisfb_post_xgi_delay(ivideo, 0x43);
494962306a36Sopenharmony_ci	sisfb_post_xgi_delay(ivideo, 0x43);
495062306a36Sopenharmony_ci	sisfb_post_xgi_delay(ivideo, 0x43);
495162306a36Sopenharmony_ci}
495262306a36Sopenharmony_ci
495362306a36Sopenharmony_cistatic void sisfb_post_xgi_ddr2_mrs_default(struct sis_video_info *ivideo,
495462306a36Sopenharmony_ci					    u8 regb)
495562306a36Sopenharmony_ci{
495662306a36Sopenharmony_ci	unsigned char *bios = ivideo->bios_abase;
495762306a36Sopenharmony_ci	u8 v1;
495862306a36Sopenharmony_ci
495962306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x28, 0x64);
496062306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x29, 0x63);
496162306a36Sopenharmony_ci	sisfb_post_xgi_delay(ivideo, 15);
496262306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x18, 0x00);
496362306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x19, 0x20);
496462306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x16, 0x00);
496562306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x16, 0x80);
496662306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x18, 0xc5);
496762306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x19, 0x23);
496862306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x16, 0x00);
496962306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x16, 0x80);
497062306a36Sopenharmony_ci	sisfb_post_xgi_delay(ivideo, 1);
497162306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x97, 0x11);
497262306a36Sopenharmony_ci	sisfb_post_xgi_setclocks(ivideo, regb);
497362306a36Sopenharmony_ci	sisfb_post_xgi_delay(ivideo, 0x46);
497462306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x18, 0xc5);
497562306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x19, 0x23);
497662306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x16, 0x00);
497762306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x16, 0x80);
497862306a36Sopenharmony_ci	sisfb_post_xgi_delay(ivideo, 1);
497962306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x1b, 0x04);
498062306a36Sopenharmony_ci	sisfb_post_xgi_delay(ivideo, 1);
498162306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x1b, 0x00);
498262306a36Sopenharmony_ci	sisfb_post_xgi_delay(ivideo, 1);
498362306a36Sopenharmony_ci	v1 = 0x31;
498462306a36Sopenharmony_ci	if (ivideo->haveXGIROM) {
498562306a36Sopenharmony_ci		v1 = bios[0xf0];
498662306a36Sopenharmony_ci	}
498762306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x18, v1);
498862306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x19, 0x06);
498962306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x16, 0x04);
499062306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x16, 0x84);
499162306a36Sopenharmony_ci	sisfb_post_xgi_delay(ivideo, 1);
499262306a36Sopenharmony_ci}
499362306a36Sopenharmony_ci
499462306a36Sopenharmony_cistatic void sisfb_post_xgi_ddr2_mrs_xg21(struct sis_video_info *ivideo)
499562306a36Sopenharmony_ci{
499662306a36Sopenharmony_ci	sisfb_post_xgi_setclocks(ivideo, 1);
499762306a36Sopenharmony_ci
499862306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x97, 0x11);
499962306a36Sopenharmony_ci	sisfb_post_xgi_delay(ivideo, 0x46);
500062306a36Sopenharmony_ci
500162306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x18, 0x00);	/* EMRS2 */
500262306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x19, 0x80);
500362306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x16, 0x05);
500462306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x16, 0x85);
500562306a36Sopenharmony_ci
500662306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x18, 0x00);	/* EMRS3 */
500762306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x19, 0xc0);
500862306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x16, 0x05);
500962306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x16, 0x85);
501062306a36Sopenharmony_ci
501162306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x18, 0x00);	/* EMRS1 */
501262306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x19, 0x40);
501362306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x16, 0x05);
501462306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x16, 0x85);
501562306a36Sopenharmony_ci
501662306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x18, 0x42);	/* MRS1 */
501762306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x19, 0x02);
501862306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x16, 0x05);
501962306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x16, 0x85);
502062306a36Sopenharmony_ci	sisfb_post_xgi_delay(ivideo, 1);
502162306a36Sopenharmony_ci
502262306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x1b, 0x04);
502362306a36Sopenharmony_ci	sisfb_post_xgi_delay(ivideo, 1);
502462306a36Sopenharmony_ci
502562306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x1b, 0x00);
502662306a36Sopenharmony_ci	sisfb_post_xgi_delay(ivideo, 1);
502762306a36Sopenharmony_ci
502862306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x18, 0x42);	/* MRS1 */
502962306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x19, 0x00);
503062306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x16, 0x05);
503162306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x16, 0x85);
503262306a36Sopenharmony_ci	sisfb_post_xgi_delay(ivideo, 1);
503362306a36Sopenharmony_ci}
503462306a36Sopenharmony_ci
503562306a36Sopenharmony_cistatic void sisfb_post_xgi_ddr2(struct sis_video_info *ivideo, u8 regb)
503662306a36Sopenharmony_ci{
503762306a36Sopenharmony_ci	unsigned char *bios = ivideo->bios_abase;
503862306a36Sopenharmony_ci	static const u8 cs158[8] = {
503962306a36Sopenharmony_ci		0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
504062306a36Sopenharmony_ci	};
504162306a36Sopenharmony_ci	static const u8 cs160[8] = {
504262306a36Sopenharmony_ci		0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
504362306a36Sopenharmony_ci	};
504462306a36Sopenharmony_ci	static const u8 cs168[8] = {
504562306a36Sopenharmony_ci		0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
504662306a36Sopenharmony_ci	};
504762306a36Sopenharmony_ci	u8 v1;
504862306a36Sopenharmony_ci	u8 v2;
504962306a36Sopenharmony_ci	u8 v3;
505062306a36Sopenharmony_ci
505162306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0xb0, 0x80); /* DDR2 dual frequency mode */
505262306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x82, 0x77);
505362306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x86, 0x00);
505462306a36Sopenharmony_ci	SiS_GetReg(SISCR, 0x86);
505562306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x86, 0x88);
505662306a36Sopenharmony_ci	SiS_GetReg(SISCR, 0x86);
505762306a36Sopenharmony_ci	v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
505862306a36Sopenharmony_ci	if (ivideo->haveXGIROM) {
505962306a36Sopenharmony_ci		v1 = bios[regb + 0x168];
506062306a36Sopenharmony_ci		v2 = bios[regb + 0x160];
506162306a36Sopenharmony_ci		v3 = bios[regb + 0x158];
506262306a36Sopenharmony_ci	}
506362306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x86, v1);
506462306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x82, 0x77);
506562306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x85, 0x00);
506662306a36Sopenharmony_ci	SiS_GetReg(SISCR, 0x85);
506762306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x85, 0x88);
506862306a36Sopenharmony_ci	SiS_GetReg(SISCR, 0x85);
506962306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x85, v2);
507062306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x82, v3);
507162306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x98, 0x01);
507262306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x9a, 0x02);
507362306a36Sopenharmony_ci	if (sisfb_xgi_is21(ivideo))
507462306a36Sopenharmony_ci		sisfb_post_xgi_ddr2_mrs_xg21(ivideo);
507562306a36Sopenharmony_ci	else
507662306a36Sopenharmony_ci		sisfb_post_xgi_ddr2_mrs_default(ivideo, regb);
507762306a36Sopenharmony_ci}
507862306a36Sopenharmony_ci
507962306a36Sopenharmony_cistatic u8 sisfb_post_xgi_ramtype(struct sis_video_info *ivideo)
508062306a36Sopenharmony_ci{
508162306a36Sopenharmony_ci	unsigned char *bios = ivideo->bios_abase;
508262306a36Sopenharmony_ci	u8 ramtype;
508362306a36Sopenharmony_ci	u8 reg;
508462306a36Sopenharmony_ci	u8 v1;
508562306a36Sopenharmony_ci
508662306a36Sopenharmony_ci	ramtype = 0x00; v1 = 0x10;
508762306a36Sopenharmony_ci	if (ivideo->haveXGIROM) {
508862306a36Sopenharmony_ci		ramtype = bios[0x62];
508962306a36Sopenharmony_ci		v1 = bios[0x1d2];
509062306a36Sopenharmony_ci	}
509162306a36Sopenharmony_ci	if (!(ramtype & 0x80)) {
509262306a36Sopenharmony_ci		if (sisfb_xgi_is21(ivideo)) {
509362306a36Sopenharmony_ci			SiS_SetRegAND(SISCR, 0xb4, 0xfd); /* GPIO control */
509462306a36Sopenharmony_ci			SiS_SetRegOR(SISCR, 0x4a, 0x80);  /* GPIOH EN */
509562306a36Sopenharmony_ci			reg = SiS_GetReg(SISCR, 0x48);
509662306a36Sopenharmony_ci			SiS_SetRegOR(SISCR, 0xb4, 0x02);
509762306a36Sopenharmony_ci			ramtype = reg & 0x01;		  /* GPIOH */
509862306a36Sopenharmony_ci		} else if (ivideo->chip == XGI_20) {
509962306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x97, v1);
510062306a36Sopenharmony_ci			reg = SiS_GetReg(SISCR, 0x97);
510162306a36Sopenharmony_ci			if (reg & 0x10) {
510262306a36Sopenharmony_ci				ramtype = (reg & 0x01) << 1;
510362306a36Sopenharmony_ci			}
510462306a36Sopenharmony_ci		} else {
510562306a36Sopenharmony_ci			reg = SiS_GetReg(SISSR, 0x39);
510662306a36Sopenharmony_ci			ramtype = reg & 0x02;
510762306a36Sopenharmony_ci			if (!(ramtype)) {
510862306a36Sopenharmony_ci				reg = SiS_GetReg(SISSR, 0x3a);
510962306a36Sopenharmony_ci				ramtype = (reg >> 1) & 0x01;
511062306a36Sopenharmony_ci			}
511162306a36Sopenharmony_ci		}
511262306a36Sopenharmony_ci	}
511362306a36Sopenharmony_ci	ramtype &= 0x07;
511462306a36Sopenharmony_ci
511562306a36Sopenharmony_ci	return ramtype;
511662306a36Sopenharmony_ci}
511762306a36Sopenharmony_ci
511862306a36Sopenharmony_cistatic int sisfb_post_xgi(struct pci_dev *pdev)
511962306a36Sopenharmony_ci{
512062306a36Sopenharmony_ci	struct sis_video_info *ivideo = pci_get_drvdata(pdev);
512162306a36Sopenharmony_ci	unsigned char *bios = ivideo->bios_abase;
512262306a36Sopenharmony_ci	struct pci_dev *mypdev = NULL;
512362306a36Sopenharmony_ci	const u8 *ptr, *ptr2;
512462306a36Sopenharmony_ci	u8 v1, v2, v3, v4, v5, reg, ramtype;
512562306a36Sopenharmony_ci	u32 rega, regb, regd;
512662306a36Sopenharmony_ci	int i, j, k, index;
512762306a36Sopenharmony_ci	static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
512862306a36Sopenharmony_ci	static const u8 cs76[2] = { 0xa3, 0xfb };
512962306a36Sopenharmony_ci	static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
513062306a36Sopenharmony_ci	static const u8 cs158[8] = {
513162306a36Sopenharmony_ci		0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
513262306a36Sopenharmony_ci	};
513362306a36Sopenharmony_ci	static const u8 cs160[8] = {
513462306a36Sopenharmony_ci		0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
513562306a36Sopenharmony_ci	};
513662306a36Sopenharmony_ci	static const u8 cs168[8] = {
513762306a36Sopenharmony_ci		0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
513862306a36Sopenharmony_ci	};
513962306a36Sopenharmony_ci	static const u8 cs128[3 * 8] = {
514062306a36Sopenharmony_ci		0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
514162306a36Sopenharmony_ci		0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
514262306a36Sopenharmony_ci		0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
514362306a36Sopenharmony_ci	};
514462306a36Sopenharmony_ci	static const u8 cs148[2 * 8] = {
514562306a36Sopenharmony_ci		0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
514662306a36Sopenharmony_ci		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
514762306a36Sopenharmony_ci	};
514862306a36Sopenharmony_ci	static const u8 cs31a[8 * 4] = {
514962306a36Sopenharmony_ci		0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
515062306a36Sopenharmony_ci		0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
515162306a36Sopenharmony_ci		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
515262306a36Sopenharmony_ci		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
515362306a36Sopenharmony_ci	};
515462306a36Sopenharmony_ci	static const u8 cs33a[8 * 4] = {
515562306a36Sopenharmony_ci		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
515662306a36Sopenharmony_ci		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
515762306a36Sopenharmony_ci		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
515862306a36Sopenharmony_ci		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
515962306a36Sopenharmony_ci	};
516062306a36Sopenharmony_ci	static const u8 cs45a[8 * 2] = {
516162306a36Sopenharmony_ci		0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
516262306a36Sopenharmony_ci		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
516362306a36Sopenharmony_ci	};
516462306a36Sopenharmony_ci	static const u8 cs170[7 * 8] = {
516562306a36Sopenharmony_ci		0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
516662306a36Sopenharmony_ci		0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
516762306a36Sopenharmony_ci		0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
516862306a36Sopenharmony_ci		0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
516962306a36Sopenharmony_ci		0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
517062306a36Sopenharmony_ci		0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
517162306a36Sopenharmony_ci		0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
517262306a36Sopenharmony_ci	};
517362306a36Sopenharmony_ci	static const u8 cs1a8[3 * 8] = {
517462306a36Sopenharmony_ci		0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
517562306a36Sopenharmony_ci		0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
517662306a36Sopenharmony_ci		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
517762306a36Sopenharmony_ci	};
517862306a36Sopenharmony_ci	static const u8 cs100[2 * 8] = {
517962306a36Sopenharmony_ci		0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
518062306a36Sopenharmony_ci		0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
518162306a36Sopenharmony_ci	};
518262306a36Sopenharmony_ci
518362306a36Sopenharmony_ci	/* VGA enable */
518462306a36Sopenharmony_ci	reg = SiS_GetRegByte(SISVGAENABLE) | 0x01;
518562306a36Sopenharmony_ci	SiS_SetRegByte(SISVGAENABLE, reg);
518662306a36Sopenharmony_ci
518762306a36Sopenharmony_ci	/* Misc */
518862306a36Sopenharmony_ci	reg = SiS_GetRegByte(SISMISCR) | 0x01;
518962306a36Sopenharmony_ci	SiS_SetRegByte(SISMISCW, reg);
519062306a36Sopenharmony_ci
519162306a36Sopenharmony_ci	/* Unlock SR */
519262306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x05, 0x86);
519362306a36Sopenharmony_ci	reg = SiS_GetReg(SISSR, 0x05);
519462306a36Sopenharmony_ci	if(reg != 0xa1)
519562306a36Sopenharmony_ci		return 0;
519662306a36Sopenharmony_ci
519762306a36Sopenharmony_ci	/* Clear some regs */
519862306a36Sopenharmony_ci	for(i = 0; i < 0x22; i++) {
519962306a36Sopenharmony_ci		if(0x06 + i == 0x20) continue;
520062306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x06 + i, 0x00);
520162306a36Sopenharmony_ci	}
520262306a36Sopenharmony_ci	for(i = 0; i < 0x0b; i++) {
520362306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x31 + i, 0x00);
520462306a36Sopenharmony_ci	}
520562306a36Sopenharmony_ci	for(i = 0; i < 0x10; i++) {
520662306a36Sopenharmony_ci		SiS_SetReg(SISCR, 0x30 + i, 0x00);
520762306a36Sopenharmony_ci	}
520862306a36Sopenharmony_ci
520962306a36Sopenharmony_ci	ptr = cs78;
521062306a36Sopenharmony_ci	if(ivideo->haveXGIROM) {
521162306a36Sopenharmony_ci		ptr = (const u8 *)&bios[0x78];
521262306a36Sopenharmony_ci	}
521362306a36Sopenharmony_ci	for(i = 0; i < 3; i++) {
521462306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x23 + i, ptr[i]);
521562306a36Sopenharmony_ci	}
521662306a36Sopenharmony_ci
521762306a36Sopenharmony_ci	ptr = cs76;
521862306a36Sopenharmony_ci	if(ivideo->haveXGIROM) {
521962306a36Sopenharmony_ci		ptr = (const u8 *)&bios[0x76];
522062306a36Sopenharmony_ci	}
522162306a36Sopenharmony_ci	for(i = 0; i < 2; i++) {
522262306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x21 + i, ptr[i]);
522362306a36Sopenharmony_ci	}
522462306a36Sopenharmony_ci
522562306a36Sopenharmony_ci	v1 = 0x18; v2 = 0x00;
522662306a36Sopenharmony_ci	if(ivideo->haveXGIROM) {
522762306a36Sopenharmony_ci		v1 = bios[0x74];
522862306a36Sopenharmony_ci		v2 = bios[0x75];
522962306a36Sopenharmony_ci	}
523062306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x07, v1);
523162306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x11, 0x0f);
523262306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x1f, v2);
523362306a36Sopenharmony_ci	/* PCI linear mode, RelIO enabled, A0000 decoding disabled */
523462306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x20, 0x80 | 0x20 | 0x04);
523562306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x27, 0x74);
523662306a36Sopenharmony_ci
523762306a36Sopenharmony_ci	ptr = cs7b;
523862306a36Sopenharmony_ci	if(ivideo->haveXGIROM) {
523962306a36Sopenharmony_ci		ptr = (const u8 *)&bios[0x7b];
524062306a36Sopenharmony_ci	}
524162306a36Sopenharmony_ci	for(i = 0; i < 3; i++) {
524262306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x31 + i, ptr[i]);
524362306a36Sopenharmony_ci	}
524462306a36Sopenharmony_ci
524562306a36Sopenharmony_ci	if(ivideo->chip == XGI_40) {
524662306a36Sopenharmony_ci		if(ivideo->revision_id == 2) {
524762306a36Sopenharmony_ci			SiS_SetRegANDOR(SISSR, 0x3b, 0x3f, 0xc0);
524862306a36Sopenharmony_ci		}
524962306a36Sopenharmony_ci		SiS_SetReg(SISCR, 0x7d, 0xfe);
525062306a36Sopenharmony_ci		SiS_SetReg(SISCR, 0x7e, 0x0f);
525162306a36Sopenharmony_ci	}
525262306a36Sopenharmony_ci	if(ivideo->revision_id == 0) {	/* 40 *and* 20? */
525362306a36Sopenharmony_ci		SiS_SetRegAND(SISCR, 0x58, 0xd7);
525462306a36Sopenharmony_ci		reg = SiS_GetReg(SISCR, 0xcb);
525562306a36Sopenharmony_ci		if(reg & 0x20) {
525662306a36Sopenharmony_ci			SiS_SetRegANDOR(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
525762306a36Sopenharmony_ci		}
525862306a36Sopenharmony_ci	}
525962306a36Sopenharmony_ci
526062306a36Sopenharmony_ci	reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
526162306a36Sopenharmony_ci	SiS_SetRegANDOR(SISCR, 0x38, 0x1f, reg);
526262306a36Sopenharmony_ci
526362306a36Sopenharmony_ci	if(ivideo->chip == XGI_20) {
526462306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x36, 0x70);
526562306a36Sopenharmony_ci	} else {
526662306a36Sopenharmony_ci		SiS_SetReg(SISVID, 0x00, 0x86);
526762306a36Sopenharmony_ci		SiS_SetReg(SISVID, 0x32, 0x00);
526862306a36Sopenharmony_ci		SiS_SetReg(SISVID, 0x30, 0x00);
526962306a36Sopenharmony_ci		SiS_SetReg(SISVID, 0x32, 0x01);
527062306a36Sopenharmony_ci		SiS_SetReg(SISVID, 0x30, 0x00);
527162306a36Sopenharmony_ci		SiS_SetRegAND(SISVID, 0x2f, 0xdf);
527262306a36Sopenharmony_ci		SiS_SetRegAND(SISCAP, 0x00, 0x3f);
527362306a36Sopenharmony_ci
527462306a36Sopenharmony_ci		SiS_SetReg(SISPART1, 0x2f, 0x01);
527562306a36Sopenharmony_ci		SiS_SetReg(SISPART1, 0x00, 0x00);
527662306a36Sopenharmony_ci		SiS_SetReg(SISPART1, 0x02, bios[0x7e]);
527762306a36Sopenharmony_ci		SiS_SetReg(SISPART1, 0x2e, 0x08);
527862306a36Sopenharmony_ci		SiS_SetRegAND(SISPART1, 0x35, 0x7f);
527962306a36Sopenharmony_ci		SiS_SetRegAND(SISPART1, 0x50, 0xfe);
528062306a36Sopenharmony_ci
528162306a36Sopenharmony_ci		reg = SiS_GetReg(SISPART4, 0x00);
528262306a36Sopenharmony_ci		if(reg == 1 || reg == 2) {
528362306a36Sopenharmony_ci			SiS_SetReg(SISPART2, 0x00, 0x1c);
528462306a36Sopenharmony_ci			SiS_SetReg(SISPART4, 0x0d, bios[0x7f]);
528562306a36Sopenharmony_ci			SiS_SetReg(SISPART4, 0x0e, bios[0x80]);
528662306a36Sopenharmony_ci			SiS_SetReg(SISPART4, 0x10, bios[0x81]);
528762306a36Sopenharmony_ci			SiS_SetRegAND(SISPART4, 0x0f, 0x3f);
528862306a36Sopenharmony_ci
528962306a36Sopenharmony_ci			reg = SiS_GetReg(SISPART4, 0x01);
529062306a36Sopenharmony_ci			if((reg & 0xf0) >= 0xb0) {
529162306a36Sopenharmony_ci				reg = SiS_GetReg(SISPART4, 0x23);
529262306a36Sopenharmony_ci				if(reg & 0x20) reg |= 0x40;
529362306a36Sopenharmony_ci				SiS_SetReg(SISPART4, 0x23, reg);
529462306a36Sopenharmony_ci				reg = (reg & 0x20) ? 0x02 : 0x00;
529562306a36Sopenharmony_ci				SiS_SetRegANDOR(SISPART1, 0x1e, 0xfd, reg);
529662306a36Sopenharmony_ci			}
529762306a36Sopenharmony_ci		}
529862306a36Sopenharmony_ci
529962306a36Sopenharmony_ci		v1 = bios[0x77];
530062306a36Sopenharmony_ci
530162306a36Sopenharmony_ci		reg = SiS_GetReg(SISSR, 0x3b);
530262306a36Sopenharmony_ci		if(reg & 0x02) {
530362306a36Sopenharmony_ci			reg = SiS_GetReg(SISSR, 0x3a);
530462306a36Sopenharmony_ci			v2 = (reg & 0x30) >> 3;
530562306a36Sopenharmony_ci			if(!(v2 & 0x04)) v2 ^= 0x02;
530662306a36Sopenharmony_ci			reg = SiS_GetReg(SISSR, 0x39);
530762306a36Sopenharmony_ci			if(reg & 0x80) v2 |= 0x80;
530862306a36Sopenharmony_ci			v2 |= 0x01;
530962306a36Sopenharmony_ci
531062306a36Sopenharmony_ci			if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
531162306a36Sopenharmony_ci				pci_dev_put(mypdev);
531262306a36Sopenharmony_ci				if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
531362306a36Sopenharmony_ci					v2 &= 0xf9;
531462306a36Sopenharmony_ci				v2 |= 0x08;
531562306a36Sopenharmony_ci				v1 &= 0xfe;
531662306a36Sopenharmony_ci			} else {
531762306a36Sopenharmony_ci				mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL);
531862306a36Sopenharmony_ci				if(!mypdev)
531962306a36Sopenharmony_ci					mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL);
532062306a36Sopenharmony_ci				if(!mypdev)
532162306a36Sopenharmony_ci					mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
532262306a36Sopenharmony_ci				if(mypdev) {
532362306a36Sopenharmony_ci					pci_read_config_dword(mypdev, 0x94, &regd);
532462306a36Sopenharmony_ci					regd &= 0xfffffeff;
532562306a36Sopenharmony_ci					pci_write_config_dword(mypdev, 0x94, regd);
532662306a36Sopenharmony_ci					v1 &= 0xfe;
532762306a36Sopenharmony_ci					pci_dev_put(mypdev);
532862306a36Sopenharmony_ci				} else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
532962306a36Sopenharmony_ci					v1 &= 0xfe;
533062306a36Sopenharmony_ci				} else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
533162306a36Sopenharmony_ci					  sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
533262306a36Sopenharmony_ci					  sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
533362306a36Sopenharmony_ci					  sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
533462306a36Sopenharmony_ci					if((v2 & 0x06) == 4)
533562306a36Sopenharmony_ci						v2 ^= 0x06;
533662306a36Sopenharmony_ci					v2 |= 0x08;
533762306a36Sopenharmony_ci				}
533862306a36Sopenharmony_ci			}
533962306a36Sopenharmony_ci			SiS_SetRegANDOR(SISCR, 0x5f, 0xf0, v2);
534062306a36Sopenharmony_ci		}
534162306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x22, v1);
534262306a36Sopenharmony_ci
534362306a36Sopenharmony_ci		if(ivideo->revision_id == 2) {
534462306a36Sopenharmony_ci			v1 = SiS_GetReg(SISSR, 0x3b);
534562306a36Sopenharmony_ci			v2 = SiS_GetReg(SISSR, 0x3a);
534662306a36Sopenharmony_ci			regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
534762306a36Sopenharmony_ci			if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
534862306a36Sopenharmony_ci				SiS_SetRegANDOR(SISCR, 0x5f, 0xf1, 0x01);
534962306a36Sopenharmony_ci
535062306a36Sopenharmony_ci			if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
535162306a36Sopenharmony_ci				/* TODO: set CR5f &0xf1 | 0x01 for version 6570
535262306a36Sopenharmony_ci				 * of nforce 2 ROM
535362306a36Sopenharmony_ci				 */
535462306a36Sopenharmony_ci				if(0)
535562306a36Sopenharmony_ci					SiS_SetRegANDOR(SISCR, 0x5f, 0xf1, 0x01);
535662306a36Sopenharmony_ci				pci_dev_put(mypdev);
535762306a36Sopenharmony_ci			}
535862306a36Sopenharmony_ci		}
535962306a36Sopenharmony_ci
536062306a36Sopenharmony_ci		v1 = 0x30;
536162306a36Sopenharmony_ci		reg = SiS_GetReg(SISSR, 0x3b);
536262306a36Sopenharmony_ci		v2 = SiS_GetReg(SISCR, 0x5f);
536362306a36Sopenharmony_ci		if((!(reg & 0x02)) && (v2 & 0x0e))
536462306a36Sopenharmony_ci			v1 |= 0x08;
536562306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x27, v1);
536662306a36Sopenharmony_ci
536762306a36Sopenharmony_ci		if(bios[0x64] & 0x01) {
536862306a36Sopenharmony_ci			SiS_SetRegANDOR(SISCR, 0x5f, 0xf0, bios[0x64]);
536962306a36Sopenharmony_ci		}
537062306a36Sopenharmony_ci
537162306a36Sopenharmony_ci		v1 = bios[0x4f7];
537262306a36Sopenharmony_ci		pci_read_config_dword(pdev, 0x50, &regd);
537362306a36Sopenharmony_ci		regd = (regd >> 20) & 0x0f;
537462306a36Sopenharmony_ci		if(regd == 1) {
537562306a36Sopenharmony_ci			v1 &= 0xfc;
537662306a36Sopenharmony_ci			SiS_SetRegOR(SISCR, 0x5f, 0x08);
537762306a36Sopenharmony_ci		}
537862306a36Sopenharmony_ci		SiS_SetReg(SISCR, 0x48, v1);
537962306a36Sopenharmony_ci
538062306a36Sopenharmony_ci		SiS_SetRegANDOR(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
538162306a36Sopenharmony_ci		SiS_SetRegANDOR(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
538262306a36Sopenharmony_ci		SiS_SetRegANDOR(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
538362306a36Sopenharmony_ci		SiS_SetRegANDOR(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
538462306a36Sopenharmony_ci		SiS_SetRegANDOR(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
538562306a36Sopenharmony_ci		SiS_SetReg(SISCR, 0x70, bios[0x4fc]);
538662306a36Sopenharmony_ci		SiS_SetRegANDOR(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
538762306a36Sopenharmony_ci		SiS_SetReg(SISCR, 0x74, 0xd0);
538862306a36Sopenharmony_ci		SiS_SetRegANDOR(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
538962306a36Sopenharmony_ci		SiS_SetRegANDOR(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
539062306a36Sopenharmony_ci		SiS_SetRegANDOR(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
539162306a36Sopenharmony_ci		v1 = bios[0x501];
539262306a36Sopenharmony_ci		if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
539362306a36Sopenharmony_ci			v1 = 0xf0;
539462306a36Sopenharmony_ci			pci_dev_put(mypdev);
539562306a36Sopenharmony_ci		}
539662306a36Sopenharmony_ci		SiS_SetReg(SISCR, 0x77, v1);
539762306a36Sopenharmony_ci	}
539862306a36Sopenharmony_ci
539962306a36Sopenharmony_ci	/* RAM type:
540062306a36Sopenharmony_ci	 *
540162306a36Sopenharmony_ci	 * 0 == DDR1, 1 == DDR2, 2..7 == reserved?
540262306a36Sopenharmony_ci	 *
540362306a36Sopenharmony_ci	 * The code seems to written so that regb should equal ramtype,
540462306a36Sopenharmony_ci	 * however, so far it has been hardcoded to 0. Enable other values only
540562306a36Sopenharmony_ci	 * on XGI Z9, as it passes the POST, and add a warning for others.
540662306a36Sopenharmony_ci	 */
540762306a36Sopenharmony_ci	ramtype = sisfb_post_xgi_ramtype(ivideo);
540862306a36Sopenharmony_ci	if (!sisfb_xgi_is21(ivideo) && ramtype) {
540962306a36Sopenharmony_ci		dev_warn(&pdev->dev,
541062306a36Sopenharmony_ci			 "RAM type something else than expected: %d\n",
541162306a36Sopenharmony_ci			 ramtype);
541262306a36Sopenharmony_ci		regb = 0;
541362306a36Sopenharmony_ci	} else {
541462306a36Sopenharmony_ci		regb = ramtype;
541562306a36Sopenharmony_ci	}
541662306a36Sopenharmony_ci
541762306a36Sopenharmony_ci	v1 = 0xff;
541862306a36Sopenharmony_ci	if(ivideo->haveXGIROM) {
541962306a36Sopenharmony_ci		v1 = bios[0x140 + regb];
542062306a36Sopenharmony_ci	}
542162306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x6d, v1);
542262306a36Sopenharmony_ci
542362306a36Sopenharmony_ci	ptr = cs128;
542462306a36Sopenharmony_ci	if(ivideo->haveXGIROM) {
542562306a36Sopenharmony_ci		ptr = (const u8 *)&bios[0x128];
542662306a36Sopenharmony_ci	}
542762306a36Sopenharmony_ci	for(i = 0, j = 0; i < 3; i++, j += 8) {
542862306a36Sopenharmony_ci		SiS_SetReg(SISCR, 0x68 + i, ptr[j + regb]);
542962306a36Sopenharmony_ci	}
543062306a36Sopenharmony_ci
543162306a36Sopenharmony_ci	ptr  = cs31a;
543262306a36Sopenharmony_ci	ptr2 = cs33a;
543362306a36Sopenharmony_ci	if(ivideo->haveXGIROM) {
543462306a36Sopenharmony_ci		index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
543562306a36Sopenharmony_ci		ptr  = (const u8 *)&bios[index];
543662306a36Sopenharmony_ci		ptr2 = (const u8 *)&bios[index + 0x20];
543762306a36Sopenharmony_ci	}
543862306a36Sopenharmony_ci	for(i = 0; i < 2; i++) {
543962306a36Sopenharmony_ci		if(i == 0) {
544062306a36Sopenharmony_ci			regd = le32_to_cpu(((u32 *)ptr)[regb]);
544162306a36Sopenharmony_ci			rega = 0x6b;
544262306a36Sopenharmony_ci		} else {
544362306a36Sopenharmony_ci			regd = le32_to_cpu(((u32 *)ptr2)[regb]);
544462306a36Sopenharmony_ci			rega = 0x6e;
544562306a36Sopenharmony_ci		}
544662306a36Sopenharmony_ci		reg = 0x00;
544762306a36Sopenharmony_ci		for(j = 0; j < 16; j++) {
544862306a36Sopenharmony_ci			reg &= 0xf3;
544962306a36Sopenharmony_ci			if(regd & 0x01) reg |= 0x04;
545062306a36Sopenharmony_ci			if(regd & 0x02) reg |= 0x08;
545162306a36Sopenharmony_ci			regd >>= 2;
545262306a36Sopenharmony_ci			SiS_SetReg(SISCR, rega, reg);
545362306a36Sopenharmony_ci			reg = SiS_GetReg(SISCR, rega);
545462306a36Sopenharmony_ci			reg = SiS_GetReg(SISCR, rega);
545562306a36Sopenharmony_ci			reg += 0x10;
545662306a36Sopenharmony_ci		}
545762306a36Sopenharmony_ci	}
545862306a36Sopenharmony_ci
545962306a36Sopenharmony_ci	SiS_SetRegAND(SISCR, 0x6e, 0xfc);
546062306a36Sopenharmony_ci
546162306a36Sopenharmony_ci	ptr  = NULL;
546262306a36Sopenharmony_ci	if(ivideo->haveXGIROM) {
546362306a36Sopenharmony_ci		index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
546462306a36Sopenharmony_ci		ptr  = (const u8 *)&bios[index];
546562306a36Sopenharmony_ci	}
546662306a36Sopenharmony_ci	for(i = 0; i < 4; i++) {
546762306a36Sopenharmony_ci		SiS_SetRegANDOR(SISCR, 0x6e, 0xfc, i);
546862306a36Sopenharmony_ci		reg = 0x00;
546962306a36Sopenharmony_ci		for(j = 0; j < 2; j++) {
547062306a36Sopenharmony_ci			regd = 0;
547162306a36Sopenharmony_ci			if(ptr) {
547262306a36Sopenharmony_ci				regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
547362306a36Sopenharmony_ci				ptr += 4;
547462306a36Sopenharmony_ci			}
547562306a36Sopenharmony_ci			/* reg = 0x00; */
547662306a36Sopenharmony_ci			for(k = 0; k < 16; k++) {
547762306a36Sopenharmony_ci				reg &= 0xfc;
547862306a36Sopenharmony_ci				if(regd & 0x01) reg |= 0x01;
547962306a36Sopenharmony_ci				if(regd & 0x02) reg |= 0x02;
548062306a36Sopenharmony_ci				regd >>= 2;
548162306a36Sopenharmony_ci				SiS_SetReg(SISCR, 0x6f, reg);
548262306a36Sopenharmony_ci				reg = SiS_GetReg(SISCR, 0x6f);
548362306a36Sopenharmony_ci				reg = SiS_GetReg(SISCR, 0x6f);
548462306a36Sopenharmony_ci				reg += 0x08;
548562306a36Sopenharmony_ci			}
548662306a36Sopenharmony_ci		}
548762306a36Sopenharmony_ci	}
548862306a36Sopenharmony_ci
548962306a36Sopenharmony_ci	ptr  = cs148;
549062306a36Sopenharmony_ci	if(ivideo->haveXGIROM) {
549162306a36Sopenharmony_ci		ptr  = (const u8 *)&bios[0x148];
549262306a36Sopenharmony_ci	}
549362306a36Sopenharmony_ci	for(i = 0, j = 0; i < 2; i++, j += 8) {
549462306a36Sopenharmony_ci		SiS_SetReg(SISCR, 0x80 + i, ptr[j + regb]);
549562306a36Sopenharmony_ci	}
549662306a36Sopenharmony_ci
549762306a36Sopenharmony_ci	SiS_SetRegAND(SISCR, 0x89, 0x8f);
549862306a36Sopenharmony_ci
549962306a36Sopenharmony_ci	ptr  = cs45a;
550062306a36Sopenharmony_ci	if(ivideo->haveXGIROM) {
550162306a36Sopenharmony_ci		index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
550262306a36Sopenharmony_ci		ptr  = (const u8 *)&bios[index];
550362306a36Sopenharmony_ci	}
550462306a36Sopenharmony_ci	regd = le16_to_cpu(((const u16 *)ptr)[regb]);
550562306a36Sopenharmony_ci	reg = 0x80;
550662306a36Sopenharmony_ci	for(i = 0; i < 5; i++) {
550762306a36Sopenharmony_ci		reg &= 0xfc;
550862306a36Sopenharmony_ci		if(regd & 0x01) reg |= 0x01;
550962306a36Sopenharmony_ci		if(regd & 0x02) reg |= 0x02;
551062306a36Sopenharmony_ci		regd >>= 2;
551162306a36Sopenharmony_ci		SiS_SetReg(SISCR, 0x89, reg);
551262306a36Sopenharmony_ci		reg = SiS_GetReg(SISCR, 0x89);
551362306a36Sopenharmony_ci		reg = SiS_GetReg(SISCR, 0x89);
551462306a36Sopenharmony_ci		reg += 0x10;
551562306a36Sopenharmony_ci	}
551662306a36Sopenharmony_ci
551762306a36Sopenharmony_ci	v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
551862306a36Sopenharmony_ci	if(ivideo->haveXGIROM) {
551962306a36Sopenharmony_ci		v1 = bios[0x118 + regb];
552062306a36Sopenharmony_ci		v2 = bios[0xf8 + regb];
552162306a36Sopenharmony_ci		v3 = bios[0x120 + regb];
552262306a36Sopenharmony_ci		v4 = bios[0x1ca];
552362306a36Sopenharmony_ci	}
552462306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x45, v1 & 0x0f);
552562306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x99, (v1 >> 4) & 0x07);
552662306a36Sopenharmony_ci	SiS_SetRegOR(SISCR, 0x40, v1 & 0x80);
552762306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x41, v2);
552862306a36Sopenharmony_ci
552962306a36Sopenharmony_ci	ptr  = cs170;
553062306a36Sopenharmony_ci	if(ivideo->haveXGIROM) {
553162306a36Sopenharmony_ci		ptr  = (const u8 *)&bios[0x170];
553262306a36Sopenharmony_ci	}
553362306a36Sopenharmony_ci	for(i = 0, j = 0; i < 7; i++, j += 8) {
553462306a36Sopenharmony_ci		SiS_SetReg(SISCR, 0x90 + i, ptr[j + regb]);
553562306a36Sopenharmony_ci	}
553662306a36Sopenharmony_ci
553762306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x59, v3);
553862306a36Sopenharmony_ci
553962306a36Sopenharmony_ci	ptr  = cs1a8;
554062306a36Sopenharmony_ci	if(ivideo->haveXGIROM) {
554162306a36Sopenharmony_ci		ptr  = (const u8 *)&bios[0x1a8];
554262306a36Sopenharmony_ci	}
554362306a36Sopenharmony_ci	for(i = 0, j = 0; i < 3; i++, j += 8) {
554462306a36Sopenharmony_ci		SiS_SetReg(SISCR, 0xc3 + i, ptr[j + regb]);
554562306a36Sopenharmony_ci	}
554662306a36Sopenharmony_ci
554762306a36Sopenharmony_ci	ptr  = cs100;
554862306a36Sopenharmony_ci	if(ivideo->haveXGIROM) {
554962306a36Sopenharmony_ci		ptr  = (const u8 *)&bios[0x100];
555062306a36Sopenharmony_ci	}
555162306a36Sopenharmony_ci	for(i = 0, j = 0; i < 2; i++, j += 8) {
555262306a36Sopenharmony_ci		SiS_SetReg(SISCR, 0x8a + i, ptr[j + regb]);
555362306a36Sopenharmony_ci	}
555462306a36Sopenharmony_ci
555562306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0xcf, v4);
555662306a36Sopenharmony_ci
555762306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x83, 0x09);
555862306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x87, 0x00);
555962306a36Sopenharmony_ci
556062306a36Sopenharmony_ci	if(ivideo->chip == XGI_40) {
556162306a36Sopenharmony_ci		if( (ivideo->revision_id == 1) ||
556262306a36Sopenharmony_ci		    (ivideo->revision_id == 2) ) {
556362306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x8c, 0x87);
556462306a36Sopenharmony_ci		}
556562306a36Sopenharmony_ci	}
556662306a36Sopenharmony_ci
556762306a36Sopenharmony_ci	if (regb == 1)
556862306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x17, 0x80);		/* DDR2 */
556962306a36Sopenharmony_ci	else
557062306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x17, 0x00);		/* DDR1 */
557162306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x1a, 0x87);
557262306a36Sopenharmony_ci
557362306a36Sopenharmony_ci	if(ivideo->chip == XGI_20) {
557462306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x15, 0x00);
557562306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x1c, 0x00);
557662306a36Sopenharmony_ci	}
557762306a36Sopenharmony_ci
557862306a36Sopenharmony_ci	switch(ramtype) {
557962306a36Sopenharmony_ci	case 0:
558062306a36Sopenharmony_ci		sisfb_post_xgi_setclocks(ivideo, regb);
558162306a36Sopenharmony_ci		if((ivideo->chip == XGI_20) ||
558262306a36Sopenharmony_ci		   (ivideo->revision_id == 1)   ||
558362306a36Sopenharmony_ci		   (ivideo->revision_id == 2)) {
558462306a36Sopenharmony_ci			v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
558562306a36Sopenharmony_ci			if(ivideo->haveXGIROM) {
558662306a36Sopenharmony_ci				v1 = bios[regb + 0x158];
558762306a36Sopenharmony_ci				v2 = bios[regb + 0x160];
558862306a36Sopenharmony_ci				v3 = bios[regb + 0x168];
558962306a36Sopenharmony_ci			}
559062306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x82, v1);
559162306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x85, v2);
559262306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x86, v3);
559362306a36Sopenharmony_ci		} else {
559462306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x82, 0x88);
559562306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x86, 0x00);
559662306a36Sopenharmony_ci			reg = SiS_GetReg(SISCR, 0x86);
559762306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x86, 0x88);
559862306a36Sopenharmony_ci			reg = SiS_GetReg(SISCR, 0x86);
559962306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x86, bios[regb + 0x168]);
560062306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x82, 0x77);
560162306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x85, 0x00);
560262306a36Sopenharmony_ci			reg = SiS_GetReg(SISCR, 0x85);
560362306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x85, 0x88);
560462306a36Sopenharmony_ci			reg = SiS_GetReg(SISCR, 0x85);
560562306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x85, bios[regb + 0x160]);
560662306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x82, bios[regb + 0x158]);
560762306a36Sopenharmony_ci		}
560862306a36Sopenharmony_ci		if(ivideo->chip == XGI_40) {
560962306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x97, 0x00);
561062306a36Sopenharmony_ci		}
561162306a36Sopenharmony_ci		SiS_SetReg(SISCR, 0x98, 0x01);
561262306a36Sopenharmony_ci		SiS_SetReg(SISCR, 0x9a, 0x02);
561362306a36Sopenharmony_ci
561462306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x18, 0x01);
561562306a36Sopenharmony_ci		if((ivideo->chip == XGI_20) ||
561662306a36Sopenharmony_ci		   (ivideo->revision_id == 2)) {
561762306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x19, 0x40);
561862306a36Sopenharmony_ci		} else {
561962306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x19, 0x20);
562062306a36Sopenharmony_ci		}
562162306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x16, 0x00);
562262306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x16, 0x80);
562362306a36Sopenharmony_ci		if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
562462306a36Sopenharmony_ci			sisfb_post_xgi_delay(ivideo, 0x43);
562562306a36Sopenharmony_ci			sisfb_post_xgi_delay(ivideo, 0x43);
562662306a36Sopenharmony_ci			sisfb_post_xgi_delay(ivideo, 0x43);
562762306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x18, 0x00);
562862306a36Sopenharmony_ci			if((ivideo->chip == XGI_20) ||
562962306a36Sopenharmony_ci			   (ivideo->revision_id == 2)) {
563062306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x19, 0x40);
563162306a36Sopenharmony_ci			} else {
563262306a36Sopenharmony_ci				SiS_SetReg(SISSR, 0x19, 0x20);
563362306a36Sopenharmony_ci			}
563462306a36Sopenharmony_ci		} else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
563562306a36Sopenharmony_ci			/* SiS_SetReg(SISSR, 0x16, 0x0c); */ /* ? */
563662306a36Sopenharmony_ci		}
563762306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x16, 0x00);
563862306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x16, 0x80);
563962306a36Sopenharmony_ci		sisfb_post_xgi_delay(ivideo, 4);
564062306a36Sopenharmony_ci		v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
564162306a36Sopenharmony_ci		if(ivideo->haveXGIROM) {
564262306a36Sopenharmony_ci			v1 = bios[0xf0];
564362306a36Sopenharmony_ci			index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
564462306a36Sopenharmony_ci			v2 = bios[index];
564562306a36Sopenharmony_ci			v3 = bios[index + 1];
564662306a36Sopenharmony_ci			v4 = bios[index + 2];
564762306a36Sopenharmony_ci			v5 = bios[index + 3];
564862306a36Sopenharmony_ci		}
564962306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x18, v1);
565062306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
565162306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x16, v2);
565262306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x16, v3);
565362306a36Sopenharmony_ci		sisfb_post_xgi_delay(ivideo, 0x43);
565462306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x1b, 0x03);
565562306a36Sopenharmony_ci		sisfb_post_xgi_delay(ivideo, 0x22);
565662306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x18, v1);
565762306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x19, 0x00);
565862306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x16, v4);
565962306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x16, v5);
566062306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x1b, 0x00);
566162306a36Sopenharmony_ci		break;
566262306a36Sopenharmony_ci	case 1:
566362306a36Sopenharmony_ci		sisfb_post_xgi_ddr2(ivideo, regb);
566462306a36Sopenharmony_ci		break;
566562306a36Sopenharmony_ci	default:
566662306a36Sopenharmony_ci		sisfb_post_xgi_setclocks(ivideo, regb);
566762306a36Sopenharmony_ci		if((ivideo->chip == XGI_40) &&
566862306a36Sopenharmony_ci		   ((ivideo->revision_id == 1) ||
566962306a36Sopenharmony_ci		    (ivideo->revision_id == 2))) {
567062306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x82, bios[regb + 0x158]);
567162306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x85, bios[regb + 0x160]);
567262306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x86, bios[regb + 0x168]);
567362306a36Sopenharmony_ci		} else {
567462306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x82, 0x88);
567562306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x86, 0x00);
567662306a36Sopenharmony_ci			reg = SiS_GetReg(SISCR, 0x86);
567762306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x86, 0x88);
567862306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x82, 0x77);
567962306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x85, 0x00);
568062306a36Sopenharmony_ci			reg = SiS_GetReg(SISCR, 0x85);
568162306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x85, 0x88);
568262306a36Sopenharmony_ci			reg = SiS_GetReg(SISCR, 0x85);
568362306a36Sopenharmony_ci			v1 = cs160[regb]; v2 = cs158[regb];
568462306a36Sopenharmony_ci			if(ivideo->haveXGIROM) {
568562306a36Sopenharmony_ci				v1 = bios[regb + 0x160];
568662306a36Sopenharmony_ci				v2 = bios[regb + 0x158];
568762306a36Sopenharmony_ci			}
568862306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x85, v1);
568962306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x82, v2);
569062306a36Sopenharmony_ci		}
569162306a36Sopenharmony_ci		if(ivideo->chip == XGI_40) {
569262306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x97, 0x11);
569362306a36Sopenharmony_ci		}
569462306a36Sopenharmony_ci		if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
569562306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x98, 0x01);
569662306a36Sopenharmony_ci		} else {
569762306a36Sopenharmony_ci			SiS_SetReg(SISCR, 0x98, 0x03);
569862306a36Sopenharmony_ci		}
569962306a36Sopenharmony_ci		SiS_SetReg(SISCR, 0x9a, 0x02);
570062306a36Sopenharmony_ci
570162306a36Sopenharmony_ci		if(ivideo->chip == XGI_40) {
570262306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x18, 0x01);
570362306a36Sopenharmony_ci		} else {
570462306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x18, 0x00);
570562306a36Sopenharmony_ci		}
570662306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x19, 0x40);
570762306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x16, 0x00);
570862306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x16, 0x80);
570962306a36Sopenharmony_ci		if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
571062306a36Sopenharmony_ci			sisfb_post_xgi_delay(ivideo, 0x43);
571162306a36Sopenharmony_ci			sisfb_post_xgi_delay(ivideo, 0x43);
571262306a36Sopenharmony_ci			sisfb_post_xgi_delay(ivideo, 0x43);
571362306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x18, 0x00);
571462306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x19, 0x40);
571562306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x16, 0x00);
571662306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x16, 0x80);
571762306a36Sopenharmony_ci		}
571862306a36Sopenharmony_ci		sisfb_post_xgi_delay(ivideo, 4);
571962306a36Sopenharmony_ci		v1 = 0x31;
572062306a36Sopenharmony_ci		if(ivideo->haveXGIROM) {
572162306a36Sopenharmony_ci			v1 = bios[0xf0];
572262306a36Sopenharmony_ci		}
572362306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x18, v1);
572462306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x19, 0x01);
572562306a36Sopenharmony_ci		if(ivideo->chip == XGI_40) {
572662306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x16, bios[0x53e]);
572762306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x16, bios[0x53f]);
572862306a36Sopenharmony_ci		} else {
572962306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x16, 0x05);
573062306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x16, 0x85);
573162306a36Sopenharmony_ci		}
573262306a36Sopenharmony_ci		sisfb_post_xgi_delay(ivideo, 0x43);
573362306a36Sopenharmony_ci		if(ivideo->chip == XGI_40) {
573462306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x1b, 0x01);
573562306a36Sopenharmony_ci		} else {
573662306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x1b, 0x03);
573762306a36Sopenharmony_ci		}
573862306a36Sopenharmony_ci		sisfb_post_xgi_delay(ivideo, 0x22);
573962306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x18, v1);
574062306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x19, 0x00);
574162306a36Sopenharmony_ci		if(ivideo->chip == XGI_40) {
574262306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x16, bios[0x540]);
574362306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x16, bios[0x541]);
574462306a36Sopenharmony_ci		} else {
574562306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x16, 0x05);
574662306a36Sopenharmony_ci			SiS_SetReg(SISSR, 0x16, 0x85);
574762306a36Sopenharmony_ci		}
574862306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x1b, 0x00);
574962306a36Sopenharmony_ci	}
575062306a36Sopenharmony_ci
575162306a36Sopenharmony_ci	regb = 0;	/* ! */
575262306a36Sopenharmony_ci	v1 = 0x03;
575362306a36Sopenharmony_ci	if(ivideo->haveXGIROM) {
575462306a36Sopenharmony_ci		v1 = bios[0x110 + regb];
575562306a36Sopenharmony_ci	}
575662306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x1b, v1);
575762306a36Sopenharmony_ci
575862306a36Sopenharmony_ci	/* RAM size */
575962306a36Sopenharmony_ci	v1 = 0x00; v2 = 0x00;
576062306a36Sopenharmony_ci	if(ivideo->haveXGIROM) {
576162306a36Sopenharmony_ci		v1 = bios[0x62];
576262306a36Sopenharmony_ci		v2 = bios[0x63];
576362306a36Sopenharmony_ci	}
576462306a36Sopenharmony_ci	regb = 0;	/* ! */
576562306a36Sopenharmony_ci	regd = 1 << regb;
576662306a36Sopenharmony_ci	if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
576762306a36Sopenharmony_ci
576862306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x13, bios[regb + 0xe0]);
576962306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x14, bios[regb + 0xe0 + 8]);
577062306a36Sopenharmony_ci
577162306a36Sopenharmony_ci	} else {
577262306a36Sopenharmony_ci		int err;
577362306a36Sopenharmony_ci
577462306a36Sopenharmony_ci		/* Set default mode, don't clear screen */
577562306a36Sopenharmony_ci		ivideo->SiS_Pr.SiS_UseOEM = false;
577662306a36Sopenharmony_ci		SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
577762306a36Sopenharmony_ci		SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
577862306a36Sopenharmony_ci		ivideo->curFSTN = ivideo->curDSTN = 0;
577962306a36Sopenharmony_ci		ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
578062306a36Sopenharmony_ci		SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
578162306a36Sopenharmony_ci
578262306a36Sopenharmony_ci		SiS_SetReg(SISSR, 0x05, 0x86);
578362306a36Sopenharmony_ci
578462306a36Sopenharmony_ci		/* Disable read-cache */
578562306a36Sopenharmony_ci		SiS_SetRegAND(SISSR, 0x21, 0xdf);
578662306a36Sopenharmony_ci		err = sisfb_post_xgi_ramsize(ivideo);
578762306a36Sopenharmony_ci		/* Enable read-cache */
578862306a36Sopenharmony_ci		SiS_SetRegOR(SISSR, 0x21, 0x20);
578962306a36Sopenharmony_ci
579062306a36Sopenharmony_ci		if (err) {
579162306a36Sopenharmony_ci			dev_err(&pdev->dev,
579262306a36Sopenharmony_ci				"%s: RAM size detection failed: %d\n",
579362306a36Sopenharmony_ci				__func__, err);
579462306a36Sopenharmony_ci			return 0;
579562306a36Sopenharmony_ci		}
579662306a36Sopenharmony_ci	}
579762306a36Sopenharmony_ci
579862306a36Sopenharmony_ci#if 0
579962306a36Sopenharmony_ci	printk(KERN_DEBUG "-----------------\n");
580062306a36Sopenharmony_ci	for(i = 0; i < 0xff; i++) {
580162306a36Sopenharmony_ci		reg = SiS_GetReg(SISCR, i);
580262306a36Sopenharmony_ci		printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
580362306a36Sopenharmony_ci	}
580462306a36Sopenharmony_ci	for(i = 0; i < 0x40; i++) {
580562306a36Sopenharmony_ci		reg = SiS_GetReg(SISSR, i);
580662306a36Sopenharmony_ci		printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
580762306a36Sopenharmony_ci	}
580862306a36Sopenharmony_ci	printk(KERN_DEBUG "-----------------\n");
580962306a36Sopenharmony_ci#endif
581062306a36Sopenharmony_ci
581162306a36Sopenharmony_ci	/* Sense CRT1 */
581262306a36Sopenharmony_ci	if(ivideo->chip == XGI_20) {
581362306a36Sopenharmony_ci		SiS_SetRegOR(SISCR, 0x32, 0x20);
581462306a36Sopenharmony_ci	} else {
581562306a36Sopenharmony_ci		reg = SiS_GetReg(SISPART4, 0x00);
581662306a36Sopenharmony_ci		if((reg == 1) || (reg == 2)) {
581762306a36Sopenharmony_ci			sisfb_sense_crt1(ivideo);
581862306a36Sopenharmony_ci		} else {
581962306a36Sopenharmony_ci			SiS_SetRegOR(SISCR, 0x32, 0x20);
582062306a36Sopenharmony_ci		}
582162306a36Sopenharmony_ci	}
582262306a36Sopenharmony_ci
582362306a36Sopenharmony_ci	/* Set default mode, don't clear screen */
582462306a36Sopenharmony_ci	ivideo->SiS_Pr.SiS_UseOEM = false;
582562306a36Sopenharmony_ci	SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
582662306a36Sopenharmony_ci	SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
582762306a36Sopenharmony_ci	ivideo->curFSTN = ivideo->curDSTN = 0;
582862306a36Sopenharmony_ci	SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
582962306a36Sopenharmony_ci
583062306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x05, 0x86);
583162306a36Sopenharmony_ci
583262306a36Sopenharmony_ci	/* Display off */
583362306a36Sopenharmony_ci	SiS_SetRegOR(SISSR, 0x01, 0x20);
583462306a36Sopenharmony_ci
583562306a36Sopenharmony_ci	/* Save mode number in CR34 */
583662306a36Sopenharmony_ci	SiS_SetReg(SISCR, 0x34, 0x2e);
583762306a36Sopenharmony_ci
583862306a36Sopenharmony_ci	/* Let everyone know what the current mode is */
583962306a36Sopenharmony_ci	ivideo->modeprechange = 0x2e;
584062306a36Sopenharmony_ci
584162306a36Sopenharmony_ci	if(ivideo->chip == XGI_40) {
584262306a36Sopenharmony_ci		reg = SiS_GetReg(SISCR, 0xca);
584362306a36Sopenharmony_ci		v1 = SiS_GetReg(SISCR, 0xcc);
584462306a36Sopenharmony_ci		if((reg & 0x10) && (!(v1 & 0x04))) {
584562306a36Sopenharmony_ci			printk(KERN_ERR
584662306a36Sopenharmony_ci				"sisfb: Please connect power to the card.\n");
584762306a36Sopenharmony_ci			return 0;
584862306a36Sopenharmony_ci		}
584962306a36Sopenharmony_ci	}
585062306a36Sopenharmony_ci
585162306a36Sopenharmony_ci	return 1;
585262306a36Sopenharmony_ci}
585362306a36Sopenharmony_ci#endif
585462306a36Sopenharmony_ci
585562306a36Sopenharmony_cistatic int sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
585662306a36Sopenharmony_ci{
585762306a36Sopenharmony_ci	struct sisfb_chip_info	*chipinfo = &sisfb_chip_info[ent->driver_data];
585862306a36Sopenharmony_ci	struct sis_video_info	*ivideo = NULL;
585962306a36Sopenharmony_ci	struct fb_info		*sis_fb_info = NULL;
586062306a36Sopenharmony_ci	u16 reg16;
586162306a36Sopenharmony_ci	u8  reg;
586262306a36Sopenharmony_ci	int i, ret;
586362306a36Sopenharmony_ci
586462306a36Sopenharmony_ci	if(sisfb_off)
586562306a36Sopenharmony_ci		return -ENXIO;
586662306a36Sopenharmony_ci
586762306a36Sopenharmony_ci	ret = aperture_remove_conflicting_pci_devices(pdev, "sisfb");
586862306a36Sopenharmony_ci	if (ret)
586962306a36Sopenharmony_ci		return ret;
587062306a36Sopenharmony_ci
587162306a36Sopenharmony_ci	sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
587262306a36Sopenharmony_ci	if(!sis_fb_info)
587362306a36Sopenharmony_ci		return -ENOMEM;
587462306a36Sopenharmony_ci
587562306a36Sopenharmony_ci	ivideo = (struct sis_video_info *)sis_fb_info->par;
587662306a36Sopenharmony_ci	ivideo->memyselfandi = sis_fb_info;
587762306a36Sopenharmony_ci
587862306a36Sopenharmony_ci	ivideo->sisfb_id = SISFB_ID;
587962306a36Sopenharmony_ci
588062306a36Sopenharmony_ci	if(card_list == NULL) {
588162306a36Sopenharmony_ci		ivideo->cardnumber = 0;
588262306a36Sopenharmony_ci	} else {
588362306a36Sopenharmony_ci		struct sis_video_info *countvideo = card_list;
588462306a36Sopenharmony_ci		ivideo->cardnumber = 1;
588562306a36Sopenharmony_ci		while((countvideo = countvideo->next) != NULL)
588662306a36Sopenharmony_ci			ivideo->cardnumber++;
588762306a36Sopenharmony_ci	}
588862306a36Sopenharmony_ci
588962306a36Sopenharmony_ci	strscpy(ivideo->myid, chipinfo->chip_name, sizeof(ivideo->myid));
589062306a36Sopenharmony_ci
589162306a36Sopenharmony_ci	ivideo->warncount = 0;
589262306a36Sopenharmony_ci	ivideo->chip_id = pdev->device;
589362306a36Sopenharmony_ci	ivideo->chip_vendor = pdev->vendor;
589462306a36Sopenharmony_ci	ivideo->revision_id = pdev->revision;
589562306a36Sopenharmony_ci	ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
589662306a36Sopenharmony_ci	pci_read_config_word(pdev, PCI_COMMAND, &reg16);
589762306a36Sopenharmony_ci	ivideo->sisvga_enabled = reg16 & 0x01;
589862306a36Sopenharmony_ci	ivideo->pcibus = pdev->bus->number;
589962306a36Sopenharmony_ci	ivideo->pcislot = PCI_SLOT(pdev->devfn);
590062306a36Sopenharmony_ci	ivideo->pcifunc = PCI_FUNC(pdev->devfn);
590162306a36Sopenharmony_ci	ivideo->subsysvendor = pdev->subsystem_vendor;
590262306a36Sopenharmony_ci	ivideo->subsysdevice = pdev->subsystem_device;
590362306a36Sopenharmony_ci
590462306a36Sopenharmony_ci#ifndef MODULE
590562306a36Sopenharmony_ci	if(sisfb_mode_idx == -1) {
590662306a36Sopenharmony_ci		sisfb_get_vga_mode_from_kernel();
590762306a36Sopenharmony_ci	}
590862306a36Sopenharmony_ci#endif
590962306a36Sopenharmony_ci
591062306a36Sopenharmony_ci	ivideo->chip = chipinfo->chip;
591162306a36Sopenharmony_ci	ivideo->chip_real_id = chipinfo->chip;
591262306a36Sopenharmony_ci	ivideo->sisvga_engine = chipinfo->vgaengine;
591362306a36Sopenharmony_ci	ivideo->hwcursor_size = chipinfo->hwcursor_size;
591462306a36Sopenharmony_ci	ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
591562306a36Sopenharmony_ci	ivideo->mni = chipinfo->mni;
591662306a36Sopenharmony_ci
591762306a36Sopenharmony_ci	ivideo->detectedpdc  = 0xff;
591862306a36Sopenharmony_ci	ivideo->detectedpdca = 0xff;
591962306a36Sopenharmony_ci	ivideo->detectedlcda = 0xff;
592062306a36Sopenharmony_ci
592162306a36Sopenharmony_ci	ivideo->sisfb_thismonitor.datavalid = false;
592262306a36Sopenharmony_ci
592362306a36Sopenharmony_ci	ivideo->current_base = 0;
592462306a36Sopenharmony_ci
592562306a36Sopenharmony_ci	ivideo->engineok = 0;
592662306a36Sopenharmony_ci
592762306a36Sopenharmony_ci	ivideo->sisfb_was_boot_device = 0;
592862306a36Sopenharmony_ci
592962306a36Sopenharmony_ci	if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
593062306a36Sopenharmony_ci		if(ivideo->sisvga_enabled)
593162306a36Sopenharmony_ci			ivideo->sisfb_was_boot_device = 1;
593262306a36Sopenharmony_ci		else {
593362306a36Sopenharmony_ci			printk(KERN_DEBUG "sisfb: PCI device is disabled, "
593462306a36Sopenharmony_ci				"but marked as boot video device ???\n");
593562306a36Sopenharmony_ci			printk(KERN_DEBUG "sisfb: I will not accept this "
593662306a36Sopenharmony_ci				"as the primary VGA device\n");
593762306a36Sopenharmony_ci		}
593862306a36Sopenharmony_ci	}
593962306a36Sopenharmony_ci
594062306a36Sopenharmony_ci	ivideo->sisfb_parm_mem = sisfb_parm_mem;
594162306a36Sopenharmony_ci	ivideo->sisfb_accel = sisfb_accel;
594262306a36Sopenharmony_ci	ivideo->sisfb_ypan = sisfb_ypan;
594362306a36Sopenharmony_ci	ivideo->sisfb_max = sisfb_max;
594462306a36Sopenharmony_ci	ivideo->sisfb_userom = sisfb_userom;
594562306a36Sopenharmony_ci	ivideo->sisfb_useoem = sisfb_useoem;
594662306a36Sopenharmony_ci	ivideo->sisfb_mode_idx = sisfb_mode_idx;
594762306a36Sopenharmony_ci	ivideo->sisfb_parm_rate = sisfb_parm_rate;
594862306a36Sopenharmony_ci	ivideo->sisfb_crt1off = sisfb_crt1off;
594962306a36Sopenharmony_ci	ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
595062306a36Sopenharmony_ci	ivideo->sisfb_crt2type = sisfb_crt2type;
595162306a36Sopenharmony_ci	ivideo->sisfb_crt2flags = sisfb_crt2flags;
595262306a36Sopenharmony_ci	/* pdc(a), scalelcd, special timing, lvdshl handled below */
595362306a36Sopenharmony_ci	ivideo->sisfb_dstn = sisfb_dstn;
595462306a36Sopenharmony_ci	ivideo->sisfb_fstn = sisfb_fstn;
595562306a36Sopenharmony_ci	ivideo->sisfb_tvplug = sisfb_tvplug;
595662306a36Sopenharmony_ci	ivideo->sisfb_tvstd = sisfb_tvstd;
595762306a36Sopenharmony_ci	ivideo->tvxpos = sisfb_tvxposoffset;
595862306a36Sopenharmony_ci	ivideo->tvypos = sisfb_tvyposoffset;
595962306a36Sopenharmony_ci	ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
596062306a36Sopenharmony_ci	ivideo->refresh_rate = 0;
596162306a36Sopenharmony_ci	if(ivideo->sisfb_parm_rate != -1) {
596262306a36Sopenharmony_ci		ivideo->refresh_rate = ivideo->sisfb_parm_rate;
596362306a36Sopenharmony_ci	}
596462306a36Sopenharmony_ci
596562306a36Sopenharmony_ci	ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
596662306a36Sopenharmony_ci	ivideo->SiS_Pr.CenterScreen = -1;
596762306a36Sopenharmony_ci	ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
596862306a36Sopenharmony_ci	ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
596962306a36Sopenharmony_ci
597062306a36Sopenharmony_ci	ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
597162306a36Sopenharmony_ci	ivideo->SiS_Pr.SiS_CHOverScan = -1;
597262306a36Sopenharmony_ci	ivideo->SiS_Pr.SiS_ChSW = false;
597362306a36Sopenharmony_ci	ivideo->SiS_Pr.SiS_UseLCDA = false;
597462306a36Sopenharmony_ci	ivideo->SiS_Pr.HaveEMI = false;
597562306a36Sopenharmony_ci	ivideo->SiS_Pr.HaveEMILCD = false;
597662306a36Sopenharmony_ci	ivideo->SiS_Pr.OverruleEMI = false;
597762306a36Sopenharmony_ci	ivideo->SiS_Pr.SiS_SensibleSR11 = false;
597862306a36Sopenharmony_ci	ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
597962306a36Sopenharmony_ci	ivideo->SiS_Pr.PDC  = -1;
598062306a36Sopenharmony_ci	ivideo->SiS_Pr.PDCA = -1;
598162306a36Sopenharmony_ci	ivideo->SiS_Pr.DDCPortMixup = false;
598262306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
598362306a36Sopenharmony_ci	if(ivideo->chip >= SIS_330) {
598462306a36Sopenharmony_ci		ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
598562306a36Sopenharmony_ci		if(ivideo->chip >= SIS_661) {
598662306a36Sopenharmony_ci			ivideo->SiS_Pr.SiS_SensibleSR11 = true;
598762306a36Sopenharmony_ci		}
598862306a36Sopenharmony_ci	}
598962306a36Sopenharmony_ci#endif
599062306a36Sopenharmony_ci
599162306a36Sopenharmony_ci	memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
599262306a36Sopenharmony_ci
599362306a36Sopenharmony_ci	pci_set_drvdata(pdev, ivideo);
599462306a36Sopenharmony_ci
599562306a36Sopenharmony_ci	/* Patch special cases */
599662306a36Sopenharmony_ci	if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
599762306a36Sopenharmony_ci		switch(ivideo->nbridge->device) {
599862306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
599962306a36Sopenharmony_ci		case PCI_DEVICE_ID_SI_730:
600062306a36Sopenharmony_ci			ivideo->chip = SIS_730;
600162306a36Sopenharmony_ci			strcpy(ivideo->myid, "SiS 730");
600262306a36Sopenharmony_ci			break;
600362306a36Sopenharmony_ci#endif
600462306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
600562306a36Sopenharmony_ci		case PCI_DEVICE_ID_SI_651:
600662306a36Sopenharmony_ci			/* ivideo->chip is ok */
600762306a36Sopenharmony_ci			strcpy(ivideo->myid, "SiS 651");
600862306a36Sopenharmony_ci			break;
600962306a36Sopenharmony_ci		case PCI_DEVICE_ID_SI_740:
601062306a36Sopenharmony_ci			ivideo->chip = SIS_740;
601162306a36Sopenharmony_ci			strcpy(ivideo->myid, "SiS 740");
601262306a36Sopenharmony_ci			break;
601362306a36Sopenharmony_ci		case PCI_DEVICE_ID_SI_661:
601462306a36Sopenharmony_ci			ivideo->chip = SIS_661;
601562306a36Sopenharmony_ci			strcpy(ivideo->myid, "SiS 661");
601662306a36Sopenharmony_ci			break;
601762306a36Sopenharmony_ci		case PCI_DEVICE_ID_SI_741:
601862306a36Sopenharmony_ci			ivideo->chip = SIS_741;
601962306a36Sopenharmony_ci			strcpy(ivideo->myid, "SiS 741");
602062306a36Sopenharmony_ci			break;
602162306a36Sopenharmony_ci		case PCI_DEVICE_ID_SI_760:
602262306a36Sopenharmony_ci			ivideo->chip = SIS_760;
602362306a36Sopenharmony_ci			strcpy(ivideo->myid, "SiS 760");
602462306a36Sopenharmony_ci			break;
602562306a36Sopenharmony_ci		case PCI_DEVICE_ID_SI_761:
602662306a36Sopenharmony_ci			ivideo->chip = SIS_761;
602762306a36Sopenharmony_ci			strcpy(ivideo->myid, "SiS 761");
602862306a36Sopenharmony_ci			break;
602962306a36Sopenharmony_ci#endif
603062306a36Sopenharmony_ci		default:
603162306a36Sopenharmony_ci			break;
603262306a36Sopenharmony_ci		}
603362306a36Sopenharmony_ci	}
603462306a36Sopenharmony_ci
603562306a36Sopenharmony_ci	ivideo->SiS_Pr.ChipType = ivideo->chip;
603662306a36Sopenharmony_ci
603762306a36Sopenharmony_ci	ivideo->SiS_Pr.ivideo = (void *)ivideo;
603862306a36Sopenharmony_ci
603962306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
604062306a36Sopenharmony_ci	if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
604162306a36Sopenharmony_ci	   (ivideo->SiS_Pr.ChipType == SIS_315)) {
604262306a36Sopenharmony_ci		ivideo->SiS_Pr.ChipType = SIS_315H;
604362306a36Sopenharmony_ci	}
604462306a36Sopenharmony_ci#endif
604562306a36Sopenharmony_ci
604662306a36Sopenharmony_ci	if(!ivideo->sisvga_enabled) {
604762306a36Sopenharmony_ci		if(pci_enable_device(pdev)) {
604862306a36Sopenharmony_ci			pci_dev_put(ivideo->nbridge);
604962306a36Sopenharmony_ci			framebuffer_release(sis_fb_info);
605062306a36Sopenharmony_ci			return -EIO;
605162306a36Sopenharmony_ci		}
605262306a36Sopenharmony_ci	}
605362306a36Sopenharmony_ci
605462306a36Sopenharmony_ci	ivideo->video_base = pci_resource_start(pdev, 0);
605562306a36Sopenharmony_ci	ivideo->video_size = pci_resource_len(pdev, 0);
605662306a36Sopenharmony_ci	ivideo->mmio_base  = pci_resource_start(pdev, 1);
605762306a36Sopenharmony_ci	ivideo->mmio_size  = pci_resource_len(pdev, 1);
605862306a36Sopenharmony_ci	ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
605962306a36Sopenharmony_ci	ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
606062306a36Sopenharmony_ci
606162306a36Sopenharmony_ci	SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
606262306a36Sopenharmony_ci
606362306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
606462306a36Sopenharmony_ci	/* Find PCI systems for Chrontel/GPIO communication setup */
606562306a36Sopenharmony_ci	if(ivideo->chip == SIS_630) {
606662306a36Sopenharmony_ci		i = 0;
606762306a36Sopenharmony_ci        	do {
606862306a36Sopenharmony_ci			if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
606962306a36Sopenharmony_ci			   mychswtable[i].subsysCard   == ivideo->subsysdevice) {
607062306a36Sopenharmony_ci				ivideo->SiS_Pr.SiS_ChSW = true;
607162306a36Sopenharmony_ci				printk(KERN_DEBUG "sisfb: Identified [%s %s] "
607262306a36Sopenharmony_ci					"requiring Chrontel/GPIO setup\n",
607362306a36Sopenharmony_ci					mychswtable[i].vendorName,
607462306a36Sopenharmony_ci					mychswtable[i].cardName);
607562306a36Sopenharmony_ci				ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
607662306a36Sopenharmony_ci				break;
607762306a36Sopenharmony_ci			}
607862306a36Sopenharmony_ci			i++;
607962306a36Sopenharmony_ci		} while(mychswtable[i].subsysVendor != 0);
608062306a36Sopenharmony_ci	}
608162306a36Sopenharmony_ci#endif
608262306a36Sopenharmony_ci
608362306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
608462306a36Sopenharmony_ci	if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
608562306a36Sopenharmony_ci		ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
608662306a36Sopenharmony_ci	}
608762306a36Sopenharmony_ci#endif
608862306a36Sopenharmony_ci
608962306a36Sopenharmony_ci	SiS_SetReg(SISSR, 0x05, 0x86);
609062306a36Sopenharmony_ci
609162306a36Sopenharmony_ci	if( (!ivideo->sisvga_enabled)
609262306a36Sopenharmony_ci#if !defined(__i386__) && !defined(__x86_64__)
609362306a36Sopenharmony_ci			      || (sisfb_resetcard)
609462306a36Sopenharmony_ci#endif
609562306a36Sopenharmony_ci						   ) {
609662306a36Sopenharmony_ci		for(i = 0x30; i <= 0x3f; i++) {
609762306a36Sopenharmony_ci			SiS_SetReg(SISCR, i, 0x00);
609862306a36Sopenharmony_ci		}
609962306a36Sopenharmony_ci	}
610062306a36Sopenharmony_ci
610162306a36Sopenharmony_ci	/* Find out about current video mode */
610262306a36Sopenharmony_ci	ivideo->modeprechange = 0x03;
610362306a36Sopenharmony_ci	reg = SiS_GetReg(SISCR, 0x34);
610462306a36Sopenharmony_ci	if(reg & 0x7f) {
610562306a36Sopenharmony_ci		ivideo->modeprechange = reg & 0x7f;
610662306a36Sopenharmony_ci	} else if(ivideo->sisvga_enabled) {
610762306a36Sopenharmony_ci#if defined(__i386__) || defined(__x86_64__)
610862306a36Sopenharmony_ci		unsigned char __iomem *tt = ioremap(0x400, 0x100);
610962306a36Sopenharmony_ci		if(tt) {
611062306a36Sopenharmony_ci			ivideo->modeprechange = readb(tt + 0x49);
611162306a36Sopenharmony_ci			iounmap(tt);
611262306a36Sopenharmony_ci		}
611362306a36Sopenharmony_ci#endif
611462306a36Sopenharmony_ci	}
611562306a36Sopenharmony_ci
611662306a36Sopenharmony_ci	/* Search and copy ROM image */
611762306a36Sopenharmony_ci	ivideo->bios_abase = NULL;
611862306a36Sopenharmony_ci	ivideo->SiS_Pr.VirtualRomBase = NULL;
611962306a36Sopenharmony_ci	ivideo->SiS_Pr.UseROM = false;
612062306a36Sopenharmony_ci	ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
612162306a36Sopenharmony_ci	if(ivideo->sisfb_userom) {
612262306a36Sopenharmony_ci		ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
612362306a36Sopenharmony_ci		ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
612462306a36Sopenharmony_ci		ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
612562306a36Sopenharmony_ci		printk(KERN_INFO "sisfb: Video ROM %sfound\n",
612662306a36Sopenharmony_ci			ivideo->SiS_Pr.UseROM ? "" : "not ");
612762306a36Sopenharmony_ci		if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
612862306a36Sopenharmony_ci		   ivideo->SiS_Pr.UseROM = false;
612962306a36Sopenharmony_ci		   ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
613062306a36Sopenharmony_ci		   if( (ivideo->revision_id == 2) &&
613162306a36Sopenharmony_ci		       (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
613262306a36Sopenharmony_ci			ivideo->SiS_Pr.DDCPortMixup = true;
613362306a36Sopenharmony_ci		   }
613462306a36Sopenharmony_ci		}
613562306a36Sopenharmony_ci	} else {
613662306a36Sopenharmony_ci		printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
613762306a36Sopenharmony_ci	}
613862306a36Sopenharmony_ci
613962306a36Sopenharmony_ci	/* Find systems for special custom timing */
614062306a36Sopenharmony_ci	if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
614162306a36Sopenharmony_ci		sisfb_detect_custom_timing(ivideo);
614262306a36Sopenharmony_ci	}
614362306a36Sopenharmony_ci
614462306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
614562306a36Sopenharmony_ci	if (ivideo->chip == XGI_20) {
614662306a36Sopenharmony_ci		/* Check if our Z7 chip is actually Z9 */
614762306a36Sopenharmony_ci		SiS_SetRegOR(SISCR, 0x4a, 0x40);	/* GPIOG EN */
614862306a36Sopenharmony_ci		reg = SiS_GetReg(SISCR, 0x48);
614962306a36Sopenharmony_ci		if (reg & 0x02) {			/* GPIOG */
615062306a36Sopenharmony_ci			ivideo->chip_real_id = XGI_21;
615162306a36Sopenharmony_ci			dev_info(&pdev->dev, "Z9 detected\n");
615262306a36Sopenharmony_ci		}
615362306a36Sopenharmony_ci	}
615462306a36Sopenharmony_ci#endif
615562306a36Sopenharmony_ci
615662306a36Sopenharmony_ci	/* POST card in case this has not been done by the BIOS */
615762306a36Sopenharmony_ci	if( (!ivideo->sisvga_enabled)
615862306a36Sopenharmony_ci#if !defined(__i386__) && !defined(__x86_64__)
615962306a36Sopenharmony_ci			     || (sisfb_resetcard)
616062306a36Sopenharmony_ci#endif
616162306a36Sopenharmony_ci						 ) {
616262306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
616362306a36Sopenharmony_ci		if(ivideo->sisvga_engine == SIS_300_VGA) {
616462306a36Sopenharmony_ci			if(ivideo->chip == SIS_300) {
616562306a36Sopenharmony_ci				sisfb_post_sis300(pdev);
616662306a36Sopenharmony_ci				ivideo->sisfb_can_post = 1;
616762306a36Sopenharmony_ci			}
616862306a36Sopenharmony_ci		}
616962306a36Sopenharmony_ci#endif
617062306a36Sopenharmony_ci
617162306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
617262306a36Sopenharmony_ci		if (ivideo->sisvga_engine == SIS_315_VGA) {
617362306a36Sopenharmony_ci			int result = 1;
617462306a36Sopenharmony_ci
617562306a36Sopenharmony_ci			if (ivideo->chip == XGI_20) {
617662306a36Sopenharmony_ci				result = sisfb_post_xgi(pdev);
617762306a36Sopenharmony_ci				ivideo->sisfb_can_post = 1;
617862306a36Sopenharmony_ci			} else if ((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
617962306a36Sopenharmony_ci				result = sisfb_post_xgi(pdev);
618062306a36Sopenharmony_ci				ivideo->sisfb_can_post = 1;
618162306a36Sopenharmony_ci			} else {
618262306a36Sopenharmony_ci				printk(KERN_INFO "sisfb: Card is not "
618362306a36Sopenharmony_ci					"POSTed and sisfb can't do this either.\n");
618462306a36Sopenharmony_ci			}
618562306a36Sopenharmony_ci			if (!result) {
618662306a36Sopenharmony_ci				printk(KERN_ERR "sisfb: Failed to POST card\n");
618762306a36Sopenharmony_ci				ret = -ENODEV;
618862306a36Sopenharmony_ci				goto error_3;
618962306a36Sopenharmony_ci			}
619062306a36Sopenharmony_ci		}
619162306a36Sopenharmony_ci#endif
619262306a36Sopenharmony_ci	}
619362306a36Sopenharmony_ci
619462306a36Sopenharmony_ci	ivideo->sisfb_card_posted = 1;
619562306a36Sopenharmony_ci
619662306a36Sopenharmony_ci	/* Find out about RAM size */
619762306a36Sopenharmony_ci	if(sisfb_get_dram_size(ivideo)) {
619862306a36Sopenharmony_ci		printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
619962306a36Sopenharmony_ci		ret = -ENODEV;
620062306a36Sopenharmony_ci		goto error_3;
620162306a36Sopenharmony_ci	}
620262306a36Sopenharmony_ci
620362306a36Sopenharmony_ci
620462306a36Sopenharmony_ci	/* Enable PCI addressing and MMIO */
620562306a36Sopenharmony_ci	if((ivideo->sisfb_mode_idx < 0) ||
620662306a36Sopenharmony_ci	   ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
620762306a36Sopenharmony_ci		/* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE  */
620862306a36Sopenharmony_ci		SiS_SetRegOR(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
620962306a36Sopenharmony_ci		/* Enable 2D accelerator engine */
621062306a36Sopenharmony_ci		SiS_SetRegOR(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
621162306a36Sopenharmony_ci	}
621262306a36Sopenharmony_ci
621362306a36Sopenharmony_ci	if(sisfb_pdc != 0xff) {
621462306a36Sopenharmony_ci		if(ivideo->sisvga_engine == SIS_300_VGA)
621562306a36Sopenharmony_ci			sisfb_pdc &= 0x3c;
621662306a36Sopenharmony_ci		else
621762306a36Sopenharmony_ci			sisfb_pdc &= 0x1f;
621862306a36Sopenharmony_ci		ivideo->SiS_Pr.PDC = sisfb_pdc;
621962306a36Sopenharmony_ci	}
622062306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
622162306a36Sopenharmony_ci	if(ivideo->sisvga_engine == SIS_315_VGA) {
622262306a36Sopenharmony_ci		if(sisfb_pdca != 0xff)
622362306a36Sopenharmony_ci			ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
622462306a36Sopenharmony_ci	}
622562306a36Sopenharmony_ci#endif
622662306a36Sopenharmony_ci
622762306a36Sopenharmony_ci	if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
622862306a36Sopenharmony_ci		printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
622962306a36Sopenharmony_ci				(int)(ivideo->video_size >> 20));
623062306a36Sopenharmony_ci		printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
623162306a36Sopenharmony_ci		ret = -ENODEV;
623262306a36Sopenharmony_ci		goto error_3;
623362306a36Sopenharmony_ci	}
623462306a36Sopenharmony_ci
623562306a36Sopenharmony_ci	if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
623662306a36Sopenharmony_ci		printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
623762306a36Sopenharmony_ci		ret = -ENODEV;
623862306a36Sopenharmony_ci		goto error_2;
623962306a36Sopenharmony_ci	}
624062306a36Sopenharmony_ci
624162306a36Sopenharmony_ci	ivideo->video_vbase = ioremap_wc(ivideo->video_base, ivideo->video_size);
624262306a36Sopenharmony_ci	ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
624362306a36Sopenharmony_ci	if(!ivideo->video_vbase) {
624462306a36Sopenharmony_ci		printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
624562306a36Sopenharmony_ci		ret = -ENODEV;
624662306a36Sopenharmony_ci		goto error_1;
624762306a36Sopenharmony_ci	}
624862306a36Sopenharmony_ci
624962306a36Sopenharmony_ci	ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
625062306a36Sopenharmony_ci	if(!ivideo->mmio_vbase) {
625162306a36Sopenharmony_ci		printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
625262306a36Sopenharmony_ci		ret = -ENODEV;
625362306a36Sopenharmony_cierror_0:	iounmap(ivideo->video_vbase);
625462306a36Sopenharmony_cierror_1:	release_mem_region(ivideo->video_base, ivideo->video_size);
625562306a36Sopenharmony_cierror_2:	release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
625662306a36Sopenharmony_cierror_3:	vfree(ivideo->bios_abase);
625762306a36Sopenharmony_ci		pci_dev_put(ivideo->lpcdev);
625862306a36Sopenharmony_ci		pci_dev_put(ivideo->nbridge);
625962306a36Sopenharmony_ci		if(!ivideo->sisvga_enabled)
626062306a36Sopenharmony_ci			pci_disable_device(pdev);
626162306a36Sopenharmony_ci		framebuffer_release(sis_fb_info);
626262306a36Sopenharmony_ci		return ret;
626362306a36Sopenharmony_ci	}
626462306a36Sopenharmony_ci
626562306a36Sopenharmony_ci	printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
626662306a36Sopenharmony_ci		ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
626762306a36Sopenharmony_ci
626862306a36Sopenharmony_ci	if(ivideo->video_offset) {
626962306a36Sopenharmony_ci		printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
627062306a36Sopenharmony_ci			ivideo->video_offset / 1024);
627162306a36Sopenharmony_ci	}
627262306a36Sopenharmony_ci
627362306a36Sopenharmony_ci	printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
627462306a36Sopenharmony_ci		ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
627562306a36Sopenharmony_ci
627662306a36Sopenharmony_ci
627762306a36Sopenharmony_ci	/* Determine the size of the command queue */
627862306a36Sopenharmony_ci	if(ivideo->sisvga_engine == SIS_300_VGA) {
627962306a36Sopenharmony_ci		ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
628062306a36Sopenharmony_ci	} else {
628162306a36Sopenharmony_ci		if(ivideo->chip == XGI_20) {
628262306a36Sopenharmony_ci			ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
628362306a36Sopenharmony_ci		} else {
628462306a36Sopenharmony_ci			ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
628562306a36Sopenharmony_ci		}
628662306a36Sopenharmony_ci	}
628762306a36Sopenharmony_ci
628862306a36Sopenharmony_ci	/* Engines are no longer initialized here; this is
628962306a36Sopenharmony_ci	 * now done after the first mode-switch (if the
629062306a36Sopenharmony_ci	 * submitted var has its acceleration flags set).
629162306a36Sopenharmony_ci	 */
629262306a36Sopenharmony_ci
629362306a36Sopenharmony_ci	/* Calculate the base of the (unused) hw cursor */
629462306a36Sopenharmony_ci	ivideo->hwcursor_vbase = ivideo->video_vbase
629562306a36Sopenharmony_ci				 + ivideo->video_size
629662306a36Sopenharmony_ci				 - ivideo->cmdQueueSize
629762306a36Sopenharmony_ci				 - ivideo->hwcursor_size;
629862306a36Sopenharmony_ci	ivideo->caps |= HW_CURSOR_CAP;
629962306a36Sopenharmony_ci
630062306a36Sopenharmony_ci	/* Initialize offscreen memory manager */
630162306a36Sopenharmony_ci	if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
630262306a36Sopenharmony_ci		printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
630362306a36Sopenharmony_ci	}
630462306a36Sopenharmony_ci
630562306a36Sopenharmony_ci	/* Used for clearing the screen only, therefore respect our mem limit */
630662306a36Sopenharmony_ci	ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
630762306a36Sopenharmony_ci	ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
630862306a36Sopenharmony_ci
630962306a36Sopenharmony_ci	ivideo->vbflags = 0;
631062306a36Sopenharmony_ci	ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
631162306a36Sopenharmony_ci	ivideo->tvdefmodeidx  = DEFAULT_TVMODE;
631262306a36Sopenharmony_ci	ivideo->defmodeidx    = DEFAULT_MODE;
631362306a36Sopenharmony_ci
631462306a36Sopenharmony_ci	ivideo->newrom = 0;
631562306a36Sopenharmony_ci	if(ivideo->chip < XGI_20) {
631662306a36Sopenharmony_ci		if(ivideo->bios_abase) {
631762306a36Sopenharmony_ci			ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
631862306a36Sopenharmony_ci		}
631962306a36Sopenharmony_ci	}
632062306a36Sopenharmony_ci
632162306a36Sopenharmony_ci	if((ivideo->sisfb_mode_idx < 0) ||
632262306a36Sopenharmony_ci	   ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
632362306a36Sopenharmony_ci
632462306a36Sopenharmony_ci		sisfb_sense_crt1(ivideo);
632562306a36Sopenharmony_ci
632662306a36Sopenharmony_ci		sisfb_get_VB_type(ivideo);
632762306a36Sopenharmony_ci
632862306a36Sopenharmony_ci		if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
632962306a36Sopenharmony_ci			sisfb_detect_VB_connect(ivideo);
633062306a36Sopenharmony_ci		}
633162306a36Sopenharmony_ci
633262306a36Sopenharmony_ci		ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
633362306a36Sopenharmony_ci
633462306a36Sopenharmony_ci		/* Decide on which CRT2 device to use */
633562306a36Sopenharmony_ci		if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
633662306a36Sopenharmony_ci			if(ivideo->sisfb_crt2type != -1) {
633762306a36Sopenharmony_ci				if((ivideo->sisfb_crt2type == CRT2_LCD) &&
633862306a36Sopenharmony_ci				   (ivideo->vbflags & CRT2_LCD)) {
633962306a36Sopenharmony_ci					ivideo->currentvbflags |= CRT2_LCD;
634062306a36Sopenharmony_ci				} else if(ivideo->sisfb_crt2type != CRT2_LCD) {
634162306a36Sopenharmony_ci					ivideo->currentvbflags |= ivideo->sisfb_crt2type;
634262306a36Sopenharmony_ci				}
634362306a36Sopenharmony_ci			} else {
634462306a36Sopenharmony_ci				/* Chrontel 700x TV detection often unreliable, therefore
634562306a36Sopenharmony_ci				 * use a different default order on such machines
634662306a36Sopenharmony_ci				 */
634762306a36Sopenharmony_ci				if((ivideo->sisvga_engine == SIS_300_VGA) &&
634862306a36Sopenharmony_ci				   (ivideo->vbflags2 & VB2_CHRONTEL)) {
634962306a36Sopenharmony_ci					if(ivideo->vbflags & CRT2_LCD)
635062306a36Sopenharmony_ci						ivideo->currentvbflags |= CRT2_LCD;
635162306a36Sopenharmony_ci					else if(ivideo->vbflags & CRT2_TV)
635262306a36Sopenharmony_ci						ivideo->currentvbflags |= CRT2_TV;
635362306a36Sopenharmony_ci					else if(ivideo->vbflags & CRT2_VGA)
635462306a36Sopenharmony_ci						ivideo->currentvbflags |= CRT2_VGA;
635562306a36Sopenharmony_ci				} else {
635662306a36Sopenharmony_ci					if(ivideo->vbflags & CRT2_TV)
635762306a36Sopenharmony_ci						ivideo->currentvbflags |= CRT2_TV;
635862306a36Sopenharmony_ci					else if(ivideo->vbflags & CRT2_LCD)
635962306a36Sopenharmony_ci						ivideo->currentvbflags |= CRT2_LCD;
636062306a36Sopenharmony_ci					else if(ivideo->vbflags & CRT2_VGA)
636162306a36Sopenharmony_ci						ivideo->currentvbflags |= CRT2_VGA;
636262306a36Sopenharmony_ci				}
636362306a36Sopenharmony_ci			}
636462306a36Sopenharmony_ci		}
636562306a36Sopenharmony_ci
636662306a36Sopenharmony_ci		if(ivideo->vbflags & CRT2_LCD) {
636762306a36Sopenharmony_ci			sisfb_detect_lcd_type(ivideo);
636862306a36Sopenharmony_ci		}
636962306a36Sopenharmony_ci
637062306a36Sopenharmony_ci		sisfb_save_pdc_emi(ivideo);
637162306a36Sopenharmony_ci
637262306a36Sopenharmony_ci		if(!ivideo->sisfb_crt1off) {
637362306a36Sopenharmony_ci			sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
637462306a36Sopenharmony_ci		} else {
637562306a36Sopenharmony_ci			if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
637662306a36Sopenharmony_ci			   (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
637762306a36Sopenharmony_ci				sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
637862306a36Sopenharmony_ci			}
637962306a36Sopenharmony_ci		}
638062306a36Sopenharmony_ci
638162306a36Sopenharmony_ci		if(ivideo->sisfb_mode_idx >= 0) {
638262306a36Sopenharmony_ci			int bu = ivideo->sisfb_mode_idx;
638362306a36Sopenharmony_ci			ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
638462306a36Sopenharmony_ci					ivideo->sisfb_mode_idx, ivideo->currentvbflags);
638562306a36Sopenharmony_ci			if(bu != ivideo->sisfb_mode_idx) {
638662306a36Sopenharmony_ci				printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
638762306a36Sopenharmony_ci					sisbios_mode[bu].xres,
638862306a36Sopenharmony_ci					sisbios_mode[bu].yres,
638962306a36Sopenharmony_ci					sisbios_mode[bu].bpp);
639062306a36Sopenharmony_ci			}
639162306a36Sopenharmony_ci		}
639262306a36Sopenharmony_ci
639362306a36Sopenharmony_ci		if(ivideo->sisfb_mode_idx < 0) {
639462306a36Sopenharmony_ci			switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
639562306a36Sopenharmony_ci			   case CRT2_LCD:
639662306a36Sopenharmony_ci				ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
639762306a36Sopenharmony_ci				break;
639862306a36Sopenharmony_ci			   case CRT2_TV:
639962306a36Sopenharmony_ci				ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
640062306a36Sopenharmony_ci				break;
640162306a36Sopenharmony_ci			   default:
640262306a36Sopenharmony_ci				ivideo->sisfb_mode_idx = ivideo->defmodeidx;
640362306a36Sopenharmony_ci				break;
640462306a36Sopenharmony_ci			}
640562306a36Sopenharmony_ci		}
640662306a36Sopenharmony_ci
640762306a36Sopenharmony_ci		ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
640862306a36Sopenharmony_ci
640962306a36Sopenharmony_ci		if(ivideo->refresh_rate != 0) {
641062306a36Sopenharmony_ci			sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
641162306a36Sopenharmony_ci						ivideo->sisfb_mode_idx);
641262306a36Sopenharmony_ci		}
641362306a36Sopenharmony_ci
641462306a36Sopenharmony_ci		if(ivideo->rate_idx == 0) {
641562306a36Sopenharmony_ci			ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
641662306a36Sopenharmony_ci			ivideo->refresh_rate = 60;
641762306a36Sopenharmony_ci		}
641862306a36Sopenharmony_ci
641962306a36Sopenharmony_ci		if(ivideo->sisfb_thismonitor.datavalid) {
642062306a36Sopenharmony_ci			if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
642162306a36Sopenharmony_ci						ivideo->sisfb_mode_idx,
642262306a36Sopenharmony_ci						ivideo->rate_idx,
642362306a36Sopenharmony_ci						ivideo->refresh_rate)) {
642462306a36Sopenharmony_ci				printk(KERN_INFO "sisfb: WARNING: Refresh rate "
642562306a36Sopenharmony_ci							"exceeds monitor specs!\n");
642662306a36Sopenharmony_ci			}
642762306a36Sopenharmony_ci		}
642862306a36Sopenharmony_ci
642962306a36Sopenharmony_ci		ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
643062306a36Sopenharmony_ci		ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
643162306a36Sopenharmony_ci		ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
643262306a36Sopenharmony_ci
643362306a36Sopenharmony_ci		sisfb_set_vparms(ivideo);
643462306a36Sopenharmony_ci
643562306a36Sopenharmony_ci		printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
643662306a36Sopenharmony_ci			ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
643762306a36Sopenharmony_ci			ivideo->refresh_rate);
643862306a36Sopenharmony_ci
643962306a36Sopenharmony_ci		/* Set up the default var according to chosen default display mode */
644062306a36Sopenharmony_ci		ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
644162306a36Sopenharmony_ci		ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
644262306a36Sopenharmony_ci		ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
644362306a36Sopenharmony_ci
644462306a36Sopenharmony_ci		sisfb_bpp_to_var(ivideo, &ivideo->default_var);
644562306a36Sopenharmony_ci
644662306a36Sopenharmony_ci		ivideo->default_var.pixclock = (u32) (1000000000 /
644762306a36Sopenharmony_ci			sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
644862306a36Sopenharmony_ci
644962306a36Sopenharmony_ci		if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
645062306a36Sopenharmony_ci						ivideo->rate_idx, &ivideo->default_var)) {
645162306a36Sopenharmony_ci			if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
645262306a36Sopenharmony_ci				ivideo->default_var.pixclock <<= 1;
645362306a36Sopenharmony_ci			}
645462306a36Sopenharmony_ci		}
645562306a36Sopenharmony_ci
645662306a36Sopenharmony_ci		if(ivideo->sisfb_ypan) {
645762306a36Sopenharmony_ci			/* Maximize regardless of sisfb_max at startup */
645862306a36Sopenharmony_ci			ivideo->default_var.yres_virtual =
645962306a36Sopenharmony_ci				sisfb_calc_maxyres(ivideo, &ivideo->default_var);
646062306a36Sopenharmony_ci			if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
646162306a36Sopenharmony_ci				ivideo->default_var.yres_virtual = ivideo->default_var.yres;
646262306a36Sopenharmony_ci			}
646362306a36Sopenharmony_ci		}
646462306a36Sopenharmony_ci
646562306a36Sopenharmony_ci		sisfb_calc_pitch(ivideo, &ivideo->default_var);
646662306a36Sopenharmony_ci
646762306a36Sopenharmony_ci		ivideo->accel = 0;
646862306a36Sopenharmony_ci		if(ivideo->sisfb_accel) {
646962306a36Sopenharmony_ci			ivideo->accel = -1;
647062306a36Sopenharmony_ci#ifdef STUPID_ACCELF_TEXT_SHIT
647162306a36Sopenharmony_ci			ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
647262306a36Sopenharmony_ci#endif
647362306a36Sopenharmony_ci		}
647462306a36Sopenharmony_ci		sisfb_initaccel(ivideo);
647562306a36Sopenharmony_ci
647662306a36Sopenharmony_ci#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
647762306a36Sopenharmony_ci		sis_fb_info->flags = FBINFO_HWACCEL_YPAN	|
647862306a36Sopenharmony_ci				     FBINFO_HWACCEL_XPAN 	|
647962306a36Sopenharmony_ci				     FBINFO_HWACCEL_COPYAREA 	|
648062306a36Sopenharmony_ci				     FBINFO_HWACCEL_FILLRECT 	|
648162306a36Sopenharmony_ci				     ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
648262306a36Sopenharmony_ci#endif
648362306a36Sopenharmony_ci		sis_fb_info->var = ivideo->default_var;
648462306a36Sopenharmony_ci		sis_fb_info->fix = ivideo->sisfb_fix;
648562306a36Sopenharmony_ci		sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
648662306a36Sopenharmony_ci		sis_fb_info->fbops = &sisfb_ops;
648762306a36Sopenharmony_ci		sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
648862306a36Sopenharmony_ci
648962306a36Sopenharmony_ci		fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
649062306a36Sopenharmony_ci
649162306a36Sopenharmony_ci		printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
649262306a36Sopenharmony_ci
649362306a36Sopenharmony_ci		ivideo->wc_cookie = arch_phys_wc_add(ivideo->video_base,
649462306a36Sopenharmony_ci						     ivideo->video_size);
649562306a36Sopenharmony_ci		if(register_framebuffer(sis_fb_info) < 0) {
649662306a36Sopenharmony_ci			printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
649762306a36Sopenharmony_ci			ret = -EINVAL;
649862306a36Sopenharmony_ci			iounmap(ivideo->mmio_vbase);
649962306a36Sopenharmony_ci			goto error_0;
650062306a36Sopenharmony_ci		}
650162306a36Sopenharmony_ci
650262306a36Sopenharmony_ci		ivideo->registered = 1;
650362306a36Sopenharmony_ci
650462306a36Sopenharmony_ci		/* Enlist us */
650562306a36Sopenharmony_ci		ivideo->next = card_list;
650662306a36Sopenharmony_ci		card_list = ivideo;
650762306a36Sopenharmony_ci
650862306a36Sopenharmony_ci		printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
650962306a36Sopenharmony_ci			ivideo->sisfb_accel ? "enabled" : "disabled",
651062306a36Sopenharmony_ci			ivideo->sisfb_ypan  ?
651162306a36Sopenharmony_ci				(ivideo->sisfb_max ? "enabled (auto-max)" :
651262306a36Sopenharmony_ci						"enabled (no auto-max)") :
651362306a36Sopenharmony_ci									"disabled");
651462306a36Sopenharmony_ci
651562306a36Sopenharmony_ci
651662306a36Sopenharmony_ci		fb_info(sis_fb_info, "%s frame buffer device version %d.%d.%d\n",
651762306a36Sopenharmony_ci			ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
651862306a36Sopenharmony_ci
651962306a36Sopenharmony_ci		printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
652062306a36Sopenharmony_ci
652162306a36Sopenharmony_ci	}	/* if mode = "none" */
652262306a36Sopenharmony_ci
652362306a36Sopenharmony_ci	return 0;
652462306a36Sopenharmony_ci}
652562306a36Sopenharmony_ci
652662306a36Sopenharmony_ci/*****************************************************/
652762306a36Sopenharmony_ci/*                PCI DEVICE HANDLING                */
652862306a36Sopenharmony_ci/*****************************************************/
652962306a36Sopenharmony_ci
653062306a36Sopenharmony_cistatic void sisfb_remove(struct pci_dev *pdev)
653162306a36Sopenharmony_ci{
653262306a36Sopenharmony_ci	struct sis_video_info	*ivideo = pci_get_drvdata(pdev);
653362306a36Sopenharmony_ci	struct fb_info		*sis_fb_info = ivideo->memyselfandi;
653462306a36Sopenharmony_ci	int			registered = ivideo->registered;
653562306a36Sopenharmony_ci	int			modechanged = ivideo->modechanged;
653662306a36Sopenharmony_ci
653762306a36Sopenharmony_ci	/* Unmap */
653862306a36Sopenharmony_ci	iounmap(ivideo->mmio_vbase);
653962306a36Sopenharmony_ci	iounmap(ivideo->video_vbase);
654062306a36Sopenharmony_ci
654162306a36Sopenharmony_ci	/* Release mem regions */
654262306a36Sopenharmony_ci	release_mem_region(ivideo->video_base, ivideo->video_size);
654362306a36Sopenharmony_ci	release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
654462306a36Sopenharmony_ci
654562306a36Sopenharmony_ci	vfree(ivideo->bios_abase);
654662306a36Sopenharmony_ci
654762306a36Sopenharmony_ci	pci_dev_put(ivideo->lpcdev);
654862306a36Sopenharmony_ci
654962306a36Sopenharmony_ci	pci_dev_put(ivideo->nbridge);
655062306a36Sopenharmony_ci
655162306a36Sopenharmony_ci	arch_phys_wc_del(ivideo->wc_cookie);
655262306a36Sopenharmony_ci
655362306a36Sopenharmony_ci	/* If device was disabled when starting, disable
655462306a36Sopenharmony_ci	 * it when quitting.
655562306a36Sopenharmony_ci	 */
655662306a36Sopenharmony_ci	if(!ivideo->sisvga_enabled)
655762306a36Sopenharmony_ci		pci_disable_device(pdev);
655862306a36Sopenharmony_ci
655962306a36Sopenharmony_ci	/* Unregister the framebuffer */
656062306a36Sopenharmony_ci	if(ivideo->registered) {
656162306a36Sopenharmony_ci		unregister_framebuffer(sis_fb_info);
656262306a36Sopenharmony_ci		framebuffer_release(sis_fb_info);
656362306a36Sopenharmony_ci	}
656462306a36Sopenharmony_ci
656562306a36Sopenharmony_ci	/* OK, our ivideo is gone for good from here. */
656662306a36Sopenharmony_ci
656762306a36Sopenharmony_ci	/* TODO: Restore the initial mode
656862306a36Sopenharmony_ci	 * This sounds easy but is as good as impossible
656962306a36Sopenharmony_ci	 * on many machines with SiS chip and video bridge
657062306a36Sopenharmony_ci	 * since text modes are always set up differently
657162306a36Sopenharmony_ci	 * from machine to machine. Depends on the type
657262306a36Sopenharmony_ci	 * of integration between chipset and bridge.
657362306a36Sopenharmony_ci	 */
657462306a36Sopenharmony_ci	if(registered && modechanged)
657562306a36Sopenharmony_ci		printk(KERN_INFO
657662306a36Sopenharmony_ci			"sisfb: Restoring of text mode not supported yet\n");
657762306a36Sopenharmony_ci};
657862306a36Sopenharmony_ci
657962306a36Sopenharmony_cistatic struct pci_driver sisfb_driver = {
658062306a36Sopenharmony_ci	.name		= "sisfb",
658162306a36Sopenharmony_ci	.id_table 	= sisfb_pci_table,
658262306a36Sopenharmony_ci	.probe		= sisfb_probe,
658362306a36Sopenharmony_ci	.remove 	= sisfb_remove,
658462306a36Sopenharmony_ci};
658562306a36Sopenharmony_ci
658662306a36Sopenharmony_cistatic int __init sisfb_init(void)
658762306a36Sopenharmony_ci{
658862306a36Sopenharmony_ci#ifndef MODULE
658962306a36Sopenharmony_ci	char *options = NULL;
659062306a36Sopenharmony_ci#endif
659162306a36Sopenharmony_ci
659262306a36Sopenharmony_ci	if (fb_modesetting_disabled("sisfb"))
659362306a36Sopenharmony_ci		return -ENODEV;
659462306a36Sopenharmony_ci
659562306a36Sopenharmony_ci#ifndef MODULE
659662306a36Sopenharmony_ci	if(fb_get_options("sisfb", &options))
659762306a36Sopenharmony_ci		return -ENODEV;
659862306a36Sopenharmony_ci
659962306a36Sopenharmony_ci	sisfb_setup(options);
660062306a36Sopenharmony_ci#endif
660162306a36Sopenharmony_ci	return pci_register_driver(&sisfb_driver);
660262306a36Sopenharmony_ci}
660362306a36Sopenharmony_ci
660462306a36Sopenharmony_ci#ifndef MODULE
660562306a36Sopenharmony_cimodule_init(sisfb_init);
660662306a36Sopenharmony_ci#endif
660762306a36Sopenharmony_ci
660862306a36Sopenharmony_ci/*****************************************************/
660962306a36Sopenharmony_ci/*                      MODULE                       */
661062306a36Sopenharmony_ci/*****************************************************/
661162306a36Sopenharmony_ci
661262306a36Sopenharmony_ci#ifdef MODULE
661362306a36Sopenharmony_ci
661462306a36Sopenharmony_cistatic char		*mode = NULL;
661562306a36Sopenharmony_cistatic int		vesa = -1;
661662306a36Sopenharmony_cistatic unsigned int	rate = 0;
661762306a36Sopenharmony_cistatic unsigned int	crt1off = 1;
661862306a36Sopenharmony_cistatic unsigned int	mem = 0;
661962306a36Sopenharmony_cistatic char		*forcecrt2type = NULL;
662062306a36Sopenharmony_cistatic int		forcecrt1 = -1;
662162306a36Sopenharmony_cistatic int		pdc = -1;
662262306a36Sopenharmony_cistatic int		pdc1 = -1;
662362306a36Sopenharmony_cistatic int		noaccel = -1;
662462306a36Sopenharmony_cistatic int		noypan  = -1;
662562306a36Sopenharmony_cistatic int		nomax = -1;
662662306a36Sopenharmony_cistatic int		userom = -1;
662762306a36Sopenharmony_cistatic int		useoem = -1;
662862306a36Sopenharmony_cistatic char		*tvstandard = NULL;
662962306a36Sopenharmony_cistatic int		nocrt2rate = 0;
663062306a36Sopenharmony_cistatic int		scalelcd = -1;
663162306a36Sopenharmony_cistatic char		*specialtiming = NULL;
663262306a36Sopenharmony_cistatic int		lvdshl = -1;
663362306a36Sopenharmony_cistatic int		tvxposoffset = 0, tvyposoffset = 0;
663462306a36Sopenharmony_ci#if !defined(__i386__) && !defined(__x86_64__)
663562306a36Sopenharmony_cistatic int		resetcard = 0;
663662306a36Sopenharmony_cistatic int		videoram = 0;
663762306a36Sopenharmony_ci#endif
663862306a36Sopenharmony_ci
663962306a36Sopenharmony_cistatic int __init sisfb_init_module(void)
664062306a36Sopenharmony_ci{
664162306a36Sopenharmony_ci	sisfb_setdefaultparms();
664262306a36Sopenharmony_ci
664362306a36Sopenharmony_ci	if(rate)
664462306a36Sopenharmony_ci		sisfb_parm_rate = rate;
664562306a36Sopenharmony_ci
664662306a36Sopenharmony_ci	if((scalelcd == 0) || (scalelcd == 1))
664762306a36Sopenharmony_ci		sisfb_scalelcd = scalelcd ^ 1;
664862306a36Sopenharmony_ci
664962306a36Sopenharmony_ci	/* Need to check crt2 type first for fstn/dstn */
665062306a36Sopenharmony_ci
665162306a36Sopenharmony_ci	if(forcecrt2type)
665262306a36Sopenharmony_ci		sisfb_search_crt2type(forcecrt2type);
665362306a36Sopenharmony_ci
665462306a36Sopenharmony_ci	if(tvstandard)
665562306a36Sopenharmony_ci		sisfb_search_tvstd(tvstandard);
665662306a36Sopenharmony_ci
665762306a36Sopenharmony_ci	if(mode)
665862306a36Sopenharmony_ci		sisfb_search_mode(mode, false);
665962306a36Sopenharmony_ci	else if(vesa != -1)
666062306a36Sopenharmony_ci		sisfb_search_vesamode(vesa, false);
666162306a36Sopenharmony_ci
666262306a36Sopenharmony_ci	sisfb_crt1off = (crt1off == 0) ? 1 : 0;
666362306a36Sopenharmony_ci
666462306a36Sopenharmony_ci	sisfb_forcecrt1 = forcecrt1;
666562306a36Sopenharmony_ci	if(forcecrt1 == 1)
666662306a36Sopenharmony_ci		sisfb_crt1off = 0;
666762306a36Sopenharmony_ci	else if(forcecrt1 == 0)
666862306a36Sopenharmony_ci		sisfb_crt1off = 1;
666962306a36Sopenharmony_ci
667062306a36Sopenharmony_ci	if(noaccel == 1)
667162306a36Sopenharmony_ci		sisfb_accel = 0;
667262306a36Sopenharmony_ci	else if(noaccel == 0)
667362306a36Sopenharmony_ci		sisfb_accel = 1;
667462306a36Sopenharmony_ci
667562306a36Sopenharmony_ci	if(noypan == 1)
667662306a36Sopenharmony_ci		sisfb_ypan = 0;
667762306a36Sopenharmony_ci	else if(noypan == 0)
667862306a36Sopenharmony_ci		sisfb_ypan = 1;
667962306a36Sopenharmony_ci
668062306a36Sopenharmony_ci	if(nomax == 1)
668162306a36Sopenharmony_ci		sisfb_max = 0;
668262306a36Sopenharmony_ci	else if(nomax == 0)
668362306a36Sopenharmony_ci		sisfb_max = 1;
668462306a36Sopenharmony_ci
668562306a36Sopenharmony_ci	if(mem)
668662306a36Sopenharmony_ci		sisfb_parm_mem = mem;
668762306a36Sopenharmony_ci
668862306a36Sopenharmony_ci	if(userom != -1)
668962306a36Sopenharmony_ci		sisfb_userom = userom;
669062306a36Sopenharmony_ci
669162306a36Sopenharmony_ci	if(useoem != -1)
669262306a36Sopenharmony_ci		sisfb_useoem = useoem;
669362306a36Sopenharmony_ci
669462306a36Sopenharmony_ci        if(pdc != -1)
669562306a36Sopenharmony_ci		sisfb_pdc  = (pdc  & 0x7f);
669662306a36Sopenharmony_ci
669762306a36Sopenharmony_ci	if(pdc1 != -1)
669862306a36Sopenharmony_ci		sisfb_pdca = (pdc1 & 0x1f);
669962306a36Sopenharmony_ci
670062306a36Sopenharmony_ci	sisfb_nocrt2rate = nocrt2rate;
670162306a36Sopenharmony_ci
670262306a36Sopenharmony_ci	if(specialtiming)
670362306a36Sopenharmony_ci		sisfb_search_specialtiming(specialtiming);
670462306a36Sopenharmony_ci
670562306a36Sopenharmony_ci	if((lvdshl >= 0) && (lvdshl <= 3))
670662306a36Sopenharmony_ci		sisfb_lvdshl = lvdshl;
670762306a36Sopenharmony_ci
670862306a36Sopenharmony_ci	sisfb_tvxposoffset = tvxposoffset;
670962306a36Sopenharmony_ci	sisfb_tvyposoffset = tvyposoffset;
671062306a36Sopenharmony_ci
671162306a36Sopenharmony_ci#if !defined(__i386__) && !defined(__x86_64__)
671262306a36Sopenharmony_ci	sisfb_resetcard = (resetcard) ? 1 : 0;
671362306a36Sopenharmony_ci	if(videoram)
671462306a36Sopenharmony_ci		sisfb_videoram = videoram;
671562306a36Sopenharmony_ci#endif
671662306a36Sopenharmony_ci
671762306a36Sopenharmony_ci	return sisfb_init();
671862306a36Sopenharmony_ci}
671962306a36Sopenharmony_ci
672062306a36Sopenharmony_cistatic void __exit sisfb_remove_module(void)
672162306a36Sopenharmony_ci{
672262306a36Sopenharmony_ci	pci_unregister_driver(&sisfb_driver);
672362306a36Sopenharmony_ci	printk(KERN_DEBUG "sisfb: Module unloaded\n");
672462306a36Sopenharmony_ci}
672562306a36Sopenharmony_ci
672662306a36Sopenharmony_cimodule_init(sisfb_init_module);
672762306a36Sopenharmony_cimodule_exit(sisfb_remove_module);
672862306a36Sopenharmony_ci
672962306a36Sopenharmony_ciMODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
673062306a36Sopenharmony_ciMODULE_LICENSE("GPL");
673162306a36Sopenharmony_ciMODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
673262306a36Sopenharmony_ci
673362306a36Sopenharmony_cimodule_param(mem, int, 0);
673462306a36Sopenharmony_cimodule_param(noaccel, int, 0);
673562306a36Sopenharmony_cimodule_param(noypan, int, 0);
673662306a36Sopenharmony_cimodule_param(nomax, int, 0);
673762306a36Sopenharmony_cimodule_param(userom, int, 0);
673862306a36Sopenharmony_cimodule_param(useoem, int, 0);
673962306a36Sopenharmony_cimodule_param(mode, charp, 0);
674062306a36Sopenharmony_cimodule_param(vesa, int, 0);
674162306a36Sopenharmony_cimodule_param(rate, int, 0);
674262306a36Sopenharmony_cimodule_param(forcecrt1, int, 0);
674362306a36Sopenharmony_cimodule_param(forcecrt2type, charp, 0);
674462306a36Sopenharmony_cimodule_param(scalelcd, int, 0);
674562306a36Sopenharmony_cimodule_param(pdc, int, 0);
674662306a36Sopenharmony_cimodule_param(pdc1, int, 0);
674762306a36Sopenharmony_cimodule_param(specialtiming, charp, 0);
674862306a36Sopenharmony_cimodule_param(lvdshl, int, 0);
674962306a36Sopenharmony_cimodule_param(tvstandard, charp, 0);
675062306a36Sopenharmony_cimodule_param(tvxposoffset, int, 0);
675162306a36Sopenharmony_cimodule_param(tvyposoffset, int, 0);
675262306a36Sopenharmony_cimodule_param(nocrt2rate, int, 0);
675362306a36Sopenharmony_ci#if !defined(__i386__) && !defined(__x86_64__)
675462306a36Sopenharmony_cimodule_param(resetcard, int, 0);
675562306a36Sopenharmony_cimodule_param(videoram, int, 0);
675662306a36Sopenharmony_ci#endif
675762306a36Sopenharmony_ci
675862306a36Sopenharmony_ciMODULE_PARM_DESC(mem,
675962306a36Sopenharmony_ci	"\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
676062306a36Sopenharmony_ci	  "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
676162306a36Sopenharmony_ci	  "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
676262306a36Sopenharmony_ci	  "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
676362306a36Sopenharmony_ci	  "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
676462306a36Sopenharmony_ci	  "The value is to be specified without 'KB'.\n");
676562306a36Sopenharmony_ci
676662306a36Sopenharmony_ciMODULE_PARM_DESC(noaccel,
676762306a36Sopenharmony_ci	"\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
676862306a36Sopenharmony_ci	  "(default: 0)\n");
676962306a36Sopenharmony_ci
677062306a36Sopenharmony_ciMODULE_PARM_DESC(noypan,
677162306a36Sopenharmony_ci	"\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
677262306a36Sopenharmony_ci	  "will be performed by redrawing the screen. (default: 0)\n");
677362306a36Sopenharmony_ci
677462306a36Sopenharmony_ciMODULE_PARM_DESC(nomax,
677562306a36Sopenharmony_ci	"\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
677662306a36Sopenharmony_ci	  "memory for the virtual screen in order to optimize scrolling performance. If\n"
677762306a36Sopenharmony_ci	  "this is set to anything other than 0, sisfb will not do this and thereby \n"
677862306a36Sopenharmony_ci	  "enable the user to positively specify a virtual Y size of the screen using\n"
677962306a36Sopenharmony_ci	  "fbset. (default: 0)\n");
678062306a36Sopenharmony_ci
678162306a36Sopenharmony_ciMODULE_PARM_DESC(mode,
678262306a36Sopenharmony_ci	"\nSelects the desired default display mode in the format XxYxDepth,\n"
678362306a36Sopenharmony_ci	 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
678462306a36Sopenharmony_ci	 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
678562306a36Sopenharmony_ci	 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
678662306a36Sopenharmony_ci
678762306a36Sopenharmony_ciMODULE_PARM_DESC(vesa,
678862306a36Sopenharmony_ci	"\nSelects the desired default display mode by VESA defined mode number, eg.\n"
678962306a36Sopenharmony_ci	 "0x117 (default: 0x0103)\n");
679062306a36Sopenharmony_ci
679162306a36Sopenharmony_ciMODULE_PARM_DESC(rate,
679262306a36Sopenharmony_ci	"\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
679362306a36Sopenharmony_ci	  "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
679462306a36Sopenharmony_ci	  "will be ignored (default: 60)\n");
679562306a36Sopenharmony_ci
679662306a36Sopenharmony_ciMODULE_PARM_DESC(forcecrt1,
679762306a36Sopenharmony_ci	"\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
679862306a36Sopenharmony_ci	  "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
679962306a36Sopenharmony_ci	  "0=CRT1 OFF) (default: [autodetected])\n");
680062306a36Sopenharmony_ci
680162306a36Sopenharmony_ciMODULE_PARM_DESC(forcecrt2type,
680262306a36Sopenharmony_ci	"\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
680362306a36Sopenharmony_ci	  "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
680462306a36Sopenharmony_ci	  "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
680562306a36Sopenharmony_ci	  "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
680662306a36Sopenharmony_ci	  "be used instead of TV to override the TV detection. Furthermore, on systems\n"
680762306a36Sopenharmony_ci	  "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
680862306a36Sopenharmony_ci	  "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
680962306a36Sopenharmony_ci	  "depends on the very hardware in use. (default: [autodetected])\n");
681062306a36Sopenharmony_ci
681162306a36Sopenharmony_ciMODULE_PARM_DESC(scalelcd,
681262306a36Sopenharmony_ci	"\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
681362306a36Sopenharmony_ci	  "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
681462306a36Sopenharmony_ci	  "show black bars around the image, TMDS panels will probably do the scaling\n"
681562306a36Sopenharmony_ci	  "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
681662306a36Sopenharmony_ci
681762306a36Sopenharmony_ciMODULE_PARM_DESC(pdc,
681862306a36Sopenharmony_ci	"\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
681962306a36Sopenharmony_ci	  "should detect this correctly in most cases; however, sometimes this is not\n"
682062306a36Sopenharmony_ci	  "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
682162306a36Sopenharmony_ci	  "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
682262306a36Sopenharmony_ci	  "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
682362306a36Sopenharmony_ci	  "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
682462306a36Sopenharmony_ci
682562306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
682662306a36Sopenharmony_ciMODULE_PARM_DESC(pdc1,
682762306a36Sopenharmony_ci	"\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
682862306a36Sopenharmony_ci	  "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
682962306a36Sopenharmony_ci	  "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
683062306a36Sopenharmony_ci	  "implemented yet.\n");
683162306a36Sopenharmony_ci#endif
683262306a36Sopenharmony_ci
683362306a36Sopenharmony_ciMODULE_PARM_DESC(specialtiming,
683462306a36Sopenharmony_ci	"\nPlease refer to documentation for more information on this option.\n");
683562306a36Sopenharmony_ci
683662306a36Sopenharmony_ciMODULE_PARM_DESC(lvdshl,
683762306a36Sopenharmony_ci	"\nPlease refer to documentation for more information on this option.\n");
683862306a36Sopenharmony_ci
683962306a36Sopenharmony_ciMODULE_PARM_DESC(tvstandard,
684062306a36Sopenharmony_ci	"\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
684162306a36Sopenharmony_ci	  "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
684262306a36Sopenharmony_ci
684362306a36Sopenharmony_ciMODULE_PARM_DESC(tvxposoffset,
684462306a36Sopenharmony_ci	"\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
684562306a36Sopenharmony_ci	  "Default: 0\n");
684662306a36Sopenharmony_ci
684762306a36Sopenharmony_ciMODULE_PARM_DESC(tvyposoffset,
684862306a36Sopenharmony_ci	"\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
684962306a36Sopenharmony_ci	  "Default: 0\n");
685062306a36Sopenharmony_ci
685162306a36Sopenharmony_ciMODULE_PARM_DESC(nocrt2rate,
685262306a36Sopenharmony_ci	"\nSetting this to 1 will force the driver to use the default refresh rate for\n"
685362306a36Sopenharmony_ci	  "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
685462306a36Sopenharmony_ci
685562306a36Sopenharmony_ci#if !defined(__i386__) && !defined(__x86_64__)
685662306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
685762306a36Sopenharmony_ciMODULE_PARM_DESC(resetcard,
685862306a36Sopenharmony_ci	"\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
685962306a36Sopenharmony_ci	  "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
686062306a36Sopenharmony_ci	  "currently). Default: 0\n");
686162306a36Sopenharmony_ci
686262306a36Sopenharmony_ciMODULE_PARM_DESC(videoram,
686362306a36Sopenharmony_ci	"\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
686462306a36Sopenharmony_ci	  "some non-x86 architectures where the memory auto detection fails. Only\n"
686562306a36Sopenharmony_ci	  "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
686662306a36Sopenharmony_ci#endif
686762306a36Sopenharmony_ci#endif
686862306a36Sopenharmony_ci
686962306a36Sopenharmony_ci#endif 	   /*  /MODULE  */
687062306a36Sopenharmony_ci
687162306a36Sopenharmony_ci/* _GPL only for new symbols. */
687262306a36Sopenharmony_ciEXPORT_SYMBOL(sis_malloc);
687362306a36Sopenharmony_ciEXPORT_SYMBOL(sis_free);
687462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sis_malloc_new);
687562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sis_free_new);
687662306a36Sopenharmony_ci
687762306a36Sopenharmony_ci
687862306a36Sopenharmony_ci
6879