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