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, ®); 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, ®d); 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, ®d); 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, ®16); 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