2005-04-17 02:20:36 +04:00
/*
2005-09-10 00:04:45 +04:00
* SiS 300 / 540 / 630 [ S ] / 730 [ S ] ,
* SiS 315 [ E | PRO ] / 550 / [ M ] 65 x / [ M ] 66 x [ F | M | G ] X / [ M ] 74 x [ GX ] / 330 / [ M ] 76 x [ GX ] ,
* XGI V3XT / V5 / V8 , Z7
2005-04-17 02:20:36 +04:00
* frame buffer driver for Linux kernels > = 2.4 .14 and > = 2.6 .3
*
2005-09-10 00:04:45 +04:00
* Copyright ( C ) 2001 - 2005 Thomas Winischhofer , Vienna , Austria .
2005-04-17 02:20:36 +04:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the named License ,
* or any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 , USA
*
2005-09-10 00:04:45 +04:00
* Author : Thomas Winischhofer < thomas @ winischhofer . net >
2005-04-17 02:20:36 +04:00
*
* Author of ( practically wiped ) code base :
* SiS ( www . sis . com )
2005-09-10 00:04:45 +04:00
* Copyright ( C ) 1999 Silicon Integrated Systems , Inc .
2005-04-17 02:20:36 +04:00
*
* See http : //www.winischhofer.net/ for more information and updates
*
* Originally based on the VBE 2.0 compliant graphic boards framebuffer driver ,
* which is ( c ) 1998 Gerd Knorr < kraxel @ goldbach . in - berlin . de >
*
*/
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/kernel.h>
# include <linux/spinlock.h>
# include <linux/errno.h>
# include <linux/string.h>
# include <linux/mm.h>
2006-07-10 15:44:12 +04:00
# include <linux/screen_info.h>
2005-04-17 02:20:36 +04:00
# include <linux/slab.h>
# include <linux/fb.h>
# include <linux/selection.h>
# include <linux/ioport.h>
# include <linux/init.h>
# include <linux/pci.h>
# include <linux/vmalloc.h>
# include <linux/capability.h>
# include <linux/fs.h>
# include <linux/types.h>
2007-10-16 12:29:04 +04:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
# include <asm/io.h>
# ifdef CONFIG_MTRR
# include <asm/mtrr.h>
# endif
# include "sis.h"
# include "sis_main.h"
2010-11-20 00:58:50 +03:00
# if !defined(CONFIG_FB_SIS_300) && !defined(CONFIG_FB_SIS_315)
# warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set
# warning sisfb will not work!
# endif
2005-09-10 00:04:45 +04:00
static void sisfb_handle_command ( struct sis_video_info * ivideo ,
struct sisfb_cmd * sisfb_command ) ;
2005-04-17 02:20:36 +04:00
/* ------------------ Internal helper routines ----------------- */
static void __init
sisfb_setdefaultparms ( void )
{
2005-09-10 00:04:45 +04:00
sisfb_off = 0 ;
sisfb_parm_mem = 0 ;
sisfb_accel = - 1 ;
sisfb_ypan = - 1 ;
sisfb_max = - 1 ;
sisfb_userom = - 1 ;
sisfb_useoem = - 1 ;
sisfb_mode_idx = - 1 ;
sisfb_parm_rate = - 1 ;
sisfb_crt1off = 0 ;
sisfb_forcecrt1 = - 1 ;
sisfb_crt2type = - 1 ;
sisfb_crt2flags = 0 ;
sisfb_pdc = 0xff ;
sisfb_pdca = 0xff ;
sisfb_scalelcd = - 1 ;
2005-04-17 02:20:36 +04:00
sisfb_specialtiming = CUT_NONE ;
2005-09-10 00:04:45 +04:00
sisfb_lvdshl = - 1 ;
sisfb_dstn = 0 ;
sisfb_fstn = 0 ;
sisfb_tvplug = - 1 ;
sisfb_tvstd = - 1 ;
sisfb_tvxposoffset = 0 ;
sisfb_tvyposoffset = 0 ;
sisfb_nocrt2rate = 0 ;
2005-04-17 02:20:36 +04:00
# if !defined(__i386__) && !defined(__x86_64__)
2005-09-10 00:04:45 +04:00
sisfb_resetcard = 0 ;
sisfb_videoram = 0 ;
2005-04-17 02:20:36 +04:00
# endif
}
2005-09-10 00:04:45 +04:00
/* ------------- Parameter parsing -------------- */
2012-12-22 01:07:39 +04:00
static void sisfb_search_vesamode ( unsigned int vesamode , bool quiet )
2005-04-17 02:20:36 +04:00
{
int i = 0 , j = 0 ;
2005-09-10 00:04:45 +04:00
/* We don't know the hardware specs yet and there is no ivideo */
2005-04-17 02:20:36 +04:00
if ( vesamode = = 0 ) {
2005-09-10 00:04:45 +04:00
if ( ! quiet )
printk ( KERN_ERR " sisfb: Invalid mode. Using default. \n " ) ;
2005-04-17 02:20:36 +04:00
sisfb_mode_idx = DEFAULT_MODE ;
2006-10-03 12:15:00 +04:00
2005-04-17 02:20:36 +04:00
return ;
}
vesamode & = 0x1dff ; /* Clean VESA mode number from other flags */
while ( sisbios_mode [ i + + ] . mode_no [ 0 ] ! = 0 ) {
if ( ( sisbios_mode [ i - 1 ] . vesa_mode_no_1 = = vesamode ) | |
( sisbios_mode [ i - 1 ] . vesa_mode_no_2 = = vesamode ) ) {
2005-09-10 00:04:45 +04:00
if ( sisfb_fstn ) {
if ( sisbios_mode [ i - 1 ] . mode_no [ 1 ] = = 0x50 | |
sisbios_mode [ i - 1 ] . mode_no [ 1 ] = = 0x56 | |
sisbios_mode [ i - 1 ] . mode_no [ 1 ] = = 0x53 )
continue ;
} else {
if ( sisbios_mode [ i - 1 ] . mode_no [ 1 ] = = 0x5a | |
sisbios_mode [ i - 1 ] . mode_no [ 1 ] = = 0x5b )
continue ;
}
sisfb_mode_idx = i - 1 ;
j = 1 ;
break ;
2005-04-17 02:20:36 +04:00
}
}
2005-09-10 00:04:45 +04:00
if ( ( ! j ) & & ! quiet )
printk ( KERN_ERR " sisfb: Invalid VESA mode 0x%x' \n " , vesamode ) ;
2005-04-17 02:20:36 +04:00
}
2012-12-22 01:07:39 +04:00
static void sisfb_search_mode ( char * name , bool quiet )
2005-04-17 02:20:36 +04:00
{
unsigned int j = 0 , xres = 0 , yres = 0 , depth = 0 , rate = 0 ;
2005-09-10 00:04:45 +04:00
int i = 0 ;
2005-04-17 02:20:36 +04:00
char strbuf [ 16 ] , strbuf1 [ 20 ] ;
char * nameptr = name ;
2005-09-10 00:04:45 +04:00
/* We don't know the hardware specs yet and there is no ivideo */
2005-04-17 02:20:36 +04:00
if ( name = = NULL ) {
2005-09-10 00:04:45 +04:00
if ( ! quiet )
printk ( KERN_ERR " sisfb: Internal error, using default mode. \n " ) ;
sisfb_mode_idx = DEFAULT_MODE ;
return ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
if ( ! strnicmp ( name , sisbios_mode [ MODE_INDEX_NONE ] . name , strlen ( name ) ) ) {
if ( ! quiet )
printk ( KERN_ERR " sisfb: Mode 'none' not supported anymore. Using default. \n " ) ;
sisfb_mode_idx = DEFAULT_MODE ;
return ;
2005-04-17 02:20:36 +04:00
}
2006-10-03 12:15:00 +04:00
2005-04-17 02:20:36 +04:00
if ( strlen ( name ) < = 19 ) {
2005-09-10 00:04:45 +04:00
strcpy ( strbuf1 , name ) ;
for ( i = 0 ; i < strlen ( strbuf1 ) ; i + + ) {
if ( strbuf1 [ i ] < ' 0 ' | | strbuf1 [ i ] > ' 9 ' ) strbuf1 [ i ] = ' ' ;
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* This does some fuzzy mode naming detection */
if ( sscanf ( strbuf1 , " %u %u %u %u " , & xres , & yres , & depth , & rate ) = = 4 ) {
if ( ( rate < = 32 ) | | ( depth > 32 ) ) {
j = rate ; rate = depth ; depth = j ;
}
sprintf ( strbuf , " %ux%ux%u " , xres , yres , depth ) ;
nameptr = strbuf ;
sisfb_parm_rate = rate ;
} else if ( sscanf ( strbuf1 , " %u %u %u " , & xres , & yres , & depth ) = = 3 ) {
sprintf ( strbuf , " %ux%ux%u " , xres , yres , depth ) ;
nameptr = strbuf ;
} else {
xres = 0 ;
if ( ( sscanf ( strbuf1 , " %u %u " , & xres , & yres ) = = 2 ) & & ( xres ! = 0 ) ) {
sprintf ( strbuf , " %ux%ux8 " , xres , yres ) ;
nameptr = strbuf ;
} else {
sisfb_search_vesamode ( simple_strtoul ( name , NULL , 0 ) , quiet ) ;
return ;
}
}
2005-04-17 02:20:36 +04:00
}
i = 0 ; j = 0 ;
while ( sisbios_mode [ i ] . mode_no [ 0 ] ! = 0 ) {
if ( ! strnicmp ( nameptr , sisbios_mode [ i + + ] . name , strlen ( nameptr ) ) ) {
2005-09-10 00:04:45 +04:00
if ( sisfb_fstn ) {
if ( sisbios_mode [ i - 1 ] . mode_no [ 1 ] = = 0x50 | |
sisbios_mode [ i - 1 ] . mode_no [ 1 ] = = 0x56 | |
sisbios_mode [ i - 1 ] . mode_no [ 1 ] = = 0x53 )
continue ;
} else {
if ( sisbios_mode [ i - 1 ] . mode_no [ 1 ] = = 0x5a | |
sisbios_mode [ i - 1 ] . mode_no [ 1 ] = = 0x5b )
continue ;
}
sisfb_mode_idx = i - 1 ;
j = 1 ;
break ;
}
}
if ( ( ! j ) & & ! quiet )
printk ( KERN_ERR " sisfb: Invalid mode '%s' \n " , nameptr ) ;
2005-04-17 02:20:36 +04:00
}
# ifndef MODULE
2012-12-22 01:07:39 +04:00
static void sisfb_get_vga_mode_from_kernel ( void )
2005-04-17 02:20:36 +04:00
{
2006-06-26 11:26:28 +04:00
# ifdef CONFIG_X86
2005-09-10 00:04:45 +04:00
char mymode [ 32 ] ;
2005-04-17 02:20:36 +04:00
int mydepth = screen_info . lfb_depth ;
if ( screen_info . orig_video_isVGA ! = VIDEO_TYPE_VLFB ) return ;
if ( ( screen_info . lfb_width > = 320 ) & & ( screen_info . lfb_width < = 2048 ) & &
( screen_info . lfb_height > = 200 ) & & ( screen_info . lfb_height < = 1536 ) & &
( mydepth > = 8 ) & & ( mydepth < = 32 ) ) {
2005-09-10 00:04:45 +04:00
if ( mydepth = = 24 ) mydepth = 32 ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
sprintf ( mymode , " %ux%ux%u " , screen_info . lfb_width ,
screen_info . lfb_height ,
2005-04-17 02:20:36 +04:00
mydepth ) ;
2005-09-10 00:04:45 +04:00
printk ( KERN_DEBUG
" sisfb: Using vga mode %s pre-set by kernel as default \n " ,
mymode ) ;
2005-04-17 02:20:36 +04:00
2007-02-12 11:55:06 +03:00
sisfb_search_mode ( mymode , true ) ;
2005-04-17 02:20:36 +04:00
}
# endif
return ;
}
# endif
static void __init
sisfb_search_crt2type ( const char * name )
{
int i = 0 ;
2005-09-10 00:04:45 +04:00
/* We don't know the hardware specs yet and there is no ivideo */
2005-04-17 02:20:36 +04:00
if ( name = = NULL ) return ;
while ( sis_crt2type [ i ] . type_no ! = - 1 ) {
2005-09-10 00:04:45 +04:00
if ( ! strnicmp ( name , sis_crt2type [ i ] . name , strlen ( sis_crt2type [ i ] . name ) ) ) {
sisfb_crt2type = sis_crt2type [ i ] . type_no ;
sisfb_tvplug = sis_crt2type [ i ] . tvplug_no ;
sisfb_crt2flags = sis_crt2type [ i ] . flags ;
break ;
}
i + + ;
2005-04-17 02:20:36 +04:00
}
sisfb_dstn = ( sisfb_crt2flags & FL_550_DSTN ) ? 1 : 0 ;
sisfb_fstn = ( sisfb_crt2flags & FL_550_FSTN ) ? 1 : 0 ;
2005-09-10 00:04:45 +04:00
if ( sisfb_crt2type < 0 )
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " sisfb: Invalid CRT2 type: %s \n " , name ) ;
}
static void __init
sisfb_search_tvstd ( const char * name )
{
int i = 0 ;
2005-09-10 00:04:45 +04:00
/* We don't know the hardware specs yet and there is no ivideo */
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( name = = NULL )
return ;
2005-04-17 02:20:36 +04:00
while ( sis_tvtype [ i ] . type_no ! = - 1 ) {
2005-09-10 00:04:45 +04:00
if ( ! strnicmp ( name , sis_tvtype [ i ] . name , strlen ( sis_tvtype [ i ] . name ) ) ) {
sisfb_tvstd = sis_tvtype [ i ] . type_no ;
break ;
}
i + + ;
2005-04-17 02:20:36 +04:00
}
}
static void __init
sisfb_search_specialtiming ( const char * name )
{
int i = 0 ;
2007-02-12 11:55:06 +03:00
bool found = false ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* We don't know the hardware specs yet and there is no ivideo */
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( name = = NULL )
return ;
2005-04-17 02:20:36 +04:00
if ( ! strnicmp ( name , " none " , 4 ) ) {
2005-09-10 00:04:45 +04:00
sisfb_specialtiming = CUT_FORCENONE ;
2005-04-17 02:20:36 +04:00
printk ( KERN_DEBUG " sisfb: Special timing disabled \n " ) ;
} else {
2005-09-10 00:04:45 +04:00
while ( mycustomttable [ i ] . chipID ! = 0 ) {
if ( ! strnicmp ( name , mycustomttable [ i ] . optionName ,
strlen ( mycustomttable [ i ] . optionName ) ) ) {
sisfb_specialtiming = mycustomttable [ i ] . SpecialID ;
2007-02-12 11:55:06 +03:00
found = true ;
2005-09-10 00:04:45 +04:00
printk ( KERN_INFO " sisfb: Special timing for %s %s forced ( \" %s \" ) \n " ,
mycustomttable [ i ] . vendorName ,
mycustomttable [ i ] . cardName ,
mycustomttable [ i ] . optionName ) ;
break ;
}
i + + ;
}
if ( ! found ) {
printk ( KERN_WARNING " sisfb: Invalid SpecialTiming parameter, valid are: " ) ;
printk ( KERN_WARNING " \t \" none \" (to disable special timings) \n " ) ;
i = 0 ;
while ( mycustomttable [ i ] . chipID ! = 0 ) {
printk ( KERN_WARNING " \t \" %s \" (for %s %s) \n " ,
mycustomttable [ i ] . optionName ,
mycustomttable [ i ] . vendorName ,
mycustomttable [ i ] . cardName ) ;
i + + ;
}
}
}
}
/* ----------- Various detection routines ----------- */
2012-12-22 01:07:39 +04:00
static void sisfb_detect_custom_timing ( struct sis_video_info * ivideo )
2005-09-10 00:04:45 +04:00
{
unsigned char * biosver = NULL ;
unsigned char * biosdate = NULL ;
2007-02-12 11:55:06 +03:00
bool footprint ;
2005-09-10 00:04:45 +04:00
u32 chksum = 0 ;
int i , j ;
if ( ivideo - > SiS_Pr . UseROM ) {
biosver = ivideo - > SiS_Pr . VirtualRomBase + 0x06 ;
biosdate = ivideo - > SiS_Pr . VirtualRomBase + 0x2c ;
for ( i = 0 ; i < 32768 ; i + + )
chksum + = ivideo - > SiS_Pr . VirtualRomBase [ i ] ;
}
i = 0 ;
do {
if ( ( mycustomttable [ i ] . chipID = = ivideo - > chip ) & &
( ( ! strlen ( mycustomttable [ i ] . biosversion ) ) | |
( ivideo - > SiS_Pr . UseROM & &
( ! strncmp ( mycustomttable [ i ] . biosversion , biosver ,
strlen ( mycustomttable [ i ] . biosversion ) ) ) ) ) & &
( ( ! strlen ( mycustomttable [ i ] . biosdate ) ) | |
( ivideo - > SiS_Pr . UseROM & &
( ! strncmp ( mycustomttable [ i ] . biosdate , biosdate ,
strlen ( mycustomttable [ i ] . biosdate ) ) ) ) ) & &
( ( ! mycustomttable [ i ] . bioschksum ) | |
( ivideo - > SiS_Pr . UseROM & &
( mycustomttable [ i ] . bioschksum = = chksum ) ) ) & &
( mycustomttable [ i ] . pcisubsysvendor = = ivideo - > subsysvendor ) & &
( mycustomttable [ i ] . pcisubsyscard = = ivideo - > subsysdevice ) ) {
2007-02-12 11:55:06 +03:00
footprint = true ;
2005-09-10 00:04:45 +04:00
for ( j = 0 ; j < 5 ; j + + ) {
if ( mycustomttable [ i ] . biosFootprintAddr [ j ] ) {
if ( ivideo - > SiS_Pr . UseROM ) {
if ( ivideo - > SiS_Pr . VirtualRomBase [ mycustomttable [ i ] . biosFootprintAddr [ j ] ] ! =
mycustomttable [ i ] . biosFootprintData [ j ] ) {
2007-02-12 11:55:06 +03:00
footprint = false ;
2005-09-10 00:04:45 +04:00
}
} else
2007-02-12 11:55:06 +03:00
footprint = false ;
2005-09-10 00:04:45 +04:00
}
}
if ( footprint ) {
ivideo - > SiS_Pr . SiS_CustomT = mycustomttable [ i ] . SpecialID ;
printk ( KERN_DEBUG " sisfb: Identified [%s %s], special timing applies \n " ,
mycustomttable [ i ] . vendorName ,
mycustomttable [ i ] . cardName ) ;
printk ( KERN_DEBUG " sisfb: [specialtiming parameter name: %s] \n " ,
mycustomttable [ i ] . optionName ) ;
break ;
}
}
i + + ;
} while ( mycustomttable [ i ] . chipID ) ;
2005-04-17 02:20:36 +04:00
}
2012-12-22 01:07:39 +04:00
static bool sisfb_interpret_edid ( struct sisfb_monitor * monitor , u8 * buffer )
2005-04-17 02:20:36 +04:00
{
int i , j , xres , yres , refresh , index ;
u32 emodes ;
if ( buffer [ 0 ] ! = 0x00 | | buffer [ 1 ] ! = 0xff | |
buffer [ 2 ] ! = 0xff | | buffer [ 3 ] ! = 0xff | |
buffer [ 4 ] ! = 0xff | | buffer [ 5 ] ! = 0xff | |
buffer [ 6 ] ! = 0xff | | buffer [ 7 ] ! = 0x00 ) {
2005-09-10 00:04:45 +04:00
printk ( KERN_DEBUG " sisfb: Bad EDID header \n " ) ;
2007-02-12 11:55:06 +03:00
return false ;
2005-04-17 02:20:36 +04:00
}
if ( buffer [ 0x12 ] ! = 0x01 ) {
2005-09-10 00:04:45 +04:00
printk ( KERN_INFO " sisfb: EDID version %d not supported \n " ,
buffer [ 0x12 ] ) ;
2007-02-12 11:55:06 +03:00
return false ;
2005-04-17 02:20:36 +04:00
}
monitor - > feature = buffer [ 0x18 ] ;
2008-02-06 12:36:06 +03:00
if ( ! ( buffer [ 0x14 ] & 0x80 ) ) {
2005-09-10 00:04:45 +04:00
if ( ! ( buffer [ 0x14 ] & 0x08 ) ) {
printk ( KERN_INFO
" sisfb: WARNING: Monitor does not support separate syncs \n " ) ;
}
2005-04-17 02:20:36 +04:00
}
if ( buffer [ 0x13 ] > = 0x01 ) {
/* EDID V1 rev 1 and 2: Search for monitor descriptor
* to extract ranges
*/
j = 0x36 ;
for ( i = 0 ; i < 4 ; i + + ) {
if ( buffer [ j ] = = 0x00 & & buffer [ j + 1 ] = = 0x00 & &
2005-09-10 00:04:45 +04:00
buffer [ j + 2 ] = = 0x00 & & buffer [ j + 3 ] = = 0xfd & &
2005-04-17 02:20:36 +04:00
buffer [ j + 4 ] = = 0x00 ) {
monitor - > hmin = buffer [ j + 7 ] ;
monitor - > hmax = buffer [ j + 8 ] ;
monitor - > vmin = buffer [ j + 5 ] ;
monitor - > vmax = buffer [ j + 6 ] ;
monitor - > dclockmax = buffer [ j + 9 ] * 10 * 1000 ;
2007-02-12 11:55:06 +03:00
monitor - > datavalid = true ;
2005-04-17 02:20:36 +04:00
break ;
}
j + = 18 ;
}
}
if ( ! monitor - > datavalid ) {
/* Otherwise: Get a range from the list of supported
* Estabished Timings . This is not entirely accurate ,
* because fixed frequency monitors are not supported
* that way .
*/
monitor - > hmin = 65535 ; monitor - > hmax = 0 ;
monitor - > vmin = 65535 ; monitor - > vmax = 0 ;
monitor - > dclockmax = 0 ;
emodes = buffer [ 0x23 ] | ( buffer [ 0x24 ] < < 8 ) | ( buffer [ 0x25 ] < < 16 ) ;
for ( i = 0 ; i < 13 ; i + + ) {
if ( emodes & sisfb_ddcsmodes [ i ] . mask ) {
2005-09-10 00:04:45 +04:00
if ( monitor - > hmin > sisfb_ddcsmodes [ i ] . h ) monitor - > hmin = sisfb_ddcsmodes [ i ] . h ;
2005-04-17 02:20:36 +04:00
if ( monitor - > hmax < sisfb_ddcsmodes [ i ] . h ) monitor - > hmax = sisfb_ddcsmodes [ i ] . h + 1 ;
if ( monitor - > vmin > sisfb_ddcsmodes [ i ] . v ) monitor - > vmin = sisfb_ddcsmodes [ i ] . v ;
if ( monitor - > vmax < sisfb_ddcsmodes [ i ] . v ) monitor - > vmax = sisfb_ddcsmodes [ i ] . v ;
if ( monitor - > dclockmax < sisfb_ddcsmodes [ i ] . d ) monitor - > dclockmax = sisfb_ddcsmodes [ i ] . d ;
}
}
index = 0x26 ;
for ( i = 0 ; i < 8 ; i + + ) {
xres = ( buffer [ index ] + 31 ) * 8 ;
switch ( buffer [ index + 1 ] & 0xc0 ) {
2005-09-10 00:04:45 +04:00
case 0xc0 : yres = ( xres * 9 ) / 16 ; break ;
case 0x80 : yres = ( xres * 4 ) / 5 ; break ;
case 0x40 : yres = ( xres * 3 ) / 4 ; break ;
default : yres = xres ; break ;
2005-04-17 02:20:36 +04:00
}
refresh = ( buffer [ index + 1 ] & 0x3f ) + 60 ;
if ( ( xres > = 640 ) & & ( yres > = 480 ) ) {
2005-09-10 00:04:45 +04:00
for ( j = 0 ; j < 8 ; j + + ) {
if ( ( xres = = sisfb_ddcfmodes [ j ] . x ) & &
( yres = = sisfb_ddcfmodes [ j ] . y ) & &
2005-04-17 02:20:36 +04:00
( refresh = = sisfb_ddcfmodes [ j ] . v ) ) {
if ( monitor - > hmin > sisfb_ddcfmodes [ j ] . h ) monitor - > hmin = sisfb_ddcfmodes [ j ] . h ;
if ( monitor - > hmax < sisfb_ddcfmodes [ j ] . h ) monitor - > hmax = sisfb_ddcfmodes [ j ] . h + 1 ;
if ( monitor - > vmin > sisfb_ddcsmodes [ j ] . v ) monitor - > vmin = sisfb_ddcsmodes [ j ] . v ;
if ( monitor - > vmax < sisfb_ddcsmodes [ j ] . v ) monitor - > vmax = sisfb_ddcsmodes [ j ] . v ;
2005-09-10 00:04:45 +04:00
if ( monitor - > dclockmax < sisfb_ddcsmodes [ j ] . d ) monitor - > dclockmax = sisfb_ddcsmodes [ j ] . d ;
}
}
2005-04-17 02:20:36 +04:00
}
index + = 2 ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
if ( ( monitor - > hmin < = monitor - > hmax ) & & ( monitor - > vmin < = monitor - > vmax ) ) {
2007-02-12 11:55:06 +03:00
monitor - > datavalid = true ;
2005-04-17 02:20:36 +04:00
}
}
2005-09-10 00:04:45 +04:00
return monitor - > datavalid ;
2005-04-17 02:20:36 +04:00
}
2012-12-22 01:07:39 +04:00
static void sisfb_handle_ddc ( struct sis_video_info * ivideo ,
struct sisfb_monitor * monitor , int crtno )
2005-04-17 02:20:36 +04:00
{
2005-09-10 00:04:45 +04:00
unsigned short temp , i , realcrtno = crtno ;
unsigned char buffer [ 256 ] ;
2005-04-17 02:20:36 +04:00
2007-02-12 11:55:06 +03:00
monitor - > datavalid = false ;
2005-04-17 02:20:36 +04:00
if ( crtno ) {
2005-09-10 00:04:45 +04:00
if ( ivideo - > vbflags & CRT2_LCD ) realcrtno = 1 ;
else if ( ivideo - > vbflags & CRT2_VGA ) realcrtno = 2 ;
else return ;
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ( ivideo - > sisfb_crt1off ) & & ( ! crtno ) )
return ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
temp = SiS_HandleDDC ( & ivideo - > SiS_Pr , ivideo - > vbflags , ivideo - > sisvga_engine ,
realcrtno , 0 , & buffer [ 0 ] , ivideo - > vbflags2 ) ;
if ( ( ! temp ) | | ( temp = = 0xffff ) ) {
printk ( KERN_INFO " sisfb: CRT%d DDC probing failed \n " , crtno + 1 ) ;
2005-04-17 02:20:36 +04:00
return ;
2005-09-10 00:04:45 +04:00
} else {
printk ( KERN_INFO " sisfb: CRT%d DDC supported \n " , crtno + 1 ) ;
printk ( KERN_INFO " sisfb: CRT%d DDC level: %s%s%s%s \n " ,
crtno + 1 ,
( temp & 0x1a ) ? " " : " [none of the supported] " ,
( temp & 0x02 ) ? " 2 " : " " ,
( temp & 0x08 ) ? " D&P " : " " ,
( temp & 0x10 ) ? " FPDI-2 " : " " ) ;
if ( temp & 0x02 ) {
2005-04-17 02:20:36 +04:00
i = 3 ; /* Number of retrys */
do {
2005-09-10 00:04:45 +04:00
temp = SiS_HandleDDC ( & ivideo - > SiS_Pr , ivideo - > vbflags , ivideo - > sisvga_engine ,
realcrtno , 1 , & buffer [ 0 ] , ivideo - > vbflags2 ) ;
2005-04-17 02:20:36 +04:00
} while ( ( temp ) & & i - - ) ;
2005-09-10 00:04:45 +04:00
if ( ! temp ) {
if ( sisfb_interpret_edid ( monitor , & buffer [ 0 ] ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_INFO " sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz \n " ,
2005-09-10 00:04:45 +04:00
monitor - > hmin , monitor - > hmax , monitor - > vmin , monitor - > vmax ,
2005-04-17 02:20:36 +04:00
monitor - > dclockmax / 1000 ) ;
} else {
2005-09-10 00:04:45 +04:00
printk ( KERN_INFO " sisfb: CRT%d DDC EDID corrupt \n " , crtno + 1 ) ;
}
2005-04-17 02:20:36 +04:00
} else {
2005-09-10 00:04:45 +04:00
printk ( KERN_INFO " sisfb: CRT%d DDC reading failed \n " , crtno + 1 ) ;
2005-04-17 02:20:36 +04:00
}
} else {
printk ( KERN_INFO " sisfb: VESA D&P and FPDI-2 not supported yet \n " ) ;
}
}
}
2005-09-10 00:04:45 +04:00
/* -------------- Mode validation --------------- */
2007-02-12 11:55:06 +03:00
static bool
2005-04-17 02:20:36 +04:00
sisfb_verify_rate ( struct sis_video_info * ivideo , struct sisfb_monitor * monitor ,
int mode_idx , int rate_idx , int rate )
{
int htotal , vtotal ;
unsigned int dclock , hsync ;
2005-09-10 00:04:45 +04:00
if ( ! monitor - > datavalid )
2007-02-12 11:55:06 +03:00
return true ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( mode_idx < 0 )
2007-02-12 11:55:06 +03:00
return false ;
2005-04-17 02:20:36 +04:00
/* Skip for 320x200, 320x240, 640x400 */
2005-09-10 00:04:45 +04:00
switch ( sisbios_mode [ mode_idx ] . mode_no [ ivideo - > mni ] ) {
case 0x59 :
case 0x41 :
case 0x4f :
case 0x50 :
case 0x56 :
case 0x53 :
case 0x2f :
case 0x5d :
case 0x5e :
2007-02-12 11:55:06 +03:00
return true ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_FB_SIS_315
case 0x5a :
case 0x5b :
2007-02-12 11:55:06 +03:00
if ( ivideo - > sisvga_engine = = SIS_315_VGA ) return true ;
2005-04-17 02:20:36 +04:00
# endif
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( rate < ( monitor - > vmin - 1 ) )
2007-02-12 11:55:06 +03:00
return false ;
2005-09-10 00:04:45 +04:00
if ( rate > ( monitor - > vmax + 1 ) )
2007-02-12 11:55:06 +03:00
return false ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( sisfb_gettotalfrommode ( & ivideo - > SiS_Pr ,
2005-04-17 02:20:36 +04:00
sisbios_mode [ mode_idx ] . mode_no [ ivideo - > mni ] ,
2005-09-10 00:04:45 +04:00
& htotal , & vtotal , rate_idx ) ) {
2005-04-17 02:20:36 +04:00
dclock = ( htotal * vtotal * rate ) / 1000 ;
2005-09-10 00:04:45 +04:00
if ( dclock > ( monitor - > dclockmax + 1000 ) )
2007-02-12 11:55:06 +03:00
return false ;
2005-04-17 02:20:36 +04:00
hsync = dclock / htotal ;
2005-09-10 00:04:45 +04:00
if ( hsync < ( monitor - > hmin - 1 ) )
2007-02-12 11:55:06 +03:00
return false ;
2005-09-10 00:04:45 +04:00
if ( hsync > ( monitor - > hmax + 1 ) )
2007-02-12 11:55:06 +03:00
return false ;
2005-04-17 02:20:36 +04:00
} else {
2007-02-12 11:55:06 +03:00
return false ;
2005-04-17 02:20:36 +04:00
}
2007-02-12 11:55:06 +03:00
return true ;
2005-04-17 02:20:36 +04:00
}
static int
sisfb_validate_mode ( struct sis_video_info * ivideo , int myindex , u32 vbflags )
{
2005-09-10 00:04:45 +04:00
u16 xres = 0 , yres , myres ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_FB_SIS_300
2005-09-10 00:04:45 +04:00
if ( ivideo - > sisvga_engine = = SIS_300_VGA ) {
if ( ! ( sisbios_mode [ myindex ] . chipset & MD_SIS300 ) )
return - 1 ;
}
2005-04-17 02:20:36 +04:00
# endif
# ifdef CONFIG_FB_SIS_315
2005-09-10 00:04:45 +04:00
if ( ivideo - > sisvga_engine = = SIS_315_VGA ) {
if ( ! ( sisbios_mode [ myindex ] . chipset & MD_SIS315 ) )
return - 1 ;
}
2005-04-17 02:20:36 +04:00
# endif
2005-09-10 00:04:45 +04:00
myres = sisbios_mode [ myindex ] . yres ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
switch ( vbflags & VB_DISPTYPE_DISP2 ) {
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
case CRT2_LCD :
xres = ivideo - > lcdxres ; yres = ivideo - > lcdyres ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ( ivideo - > SiS_Pr . SiS_CustomT ! = CUT_PANEL848 ) & &
( ivideo - > SiS_Pr . SiS_CustomT ! = CUT_PANEL856 ) ) {
if ( sisbios_mode [ myindex ] . xres > xres )
return - 1 ;
if ( myres > yres )
return - 1 ;
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ivideo - > sisfb_fstn ) {
if ( sisbios_mode [ myindex ] . xres = = 320 ) {
if ( myres = = 240 ) {
switch ( sisbios_mode [ myindex ] . mode_no [ 1 ] ) {
case 0x50 : myindex = MODE_FSTN_8 ; break ;
case 0x56 : myindex = MODE_FSTN_16 ; break ;
case 0x53 : return - 1 ;
}
}
}
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( SiS_GetModeID_LCD ( ivideo - > sisvga_engine , vbflags , sisbios_mode [ myindex ] . xres ,
sisbios_mode [ myindex ] . yres , 0 , ivideo - > sisfb_fstn ,
ivideo - > SiS_Pr . SiS_CustomT , xres , yres , ivideo - > vbflags2 ) < 0x14 ) {
return - 1 ;
}
break ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
case CRT2_TV :
if ( SiS_GetModeID_TV ( ivideo - > sisvga_engine , vbflags , sisbios_mode [ myindex ] . xres ,
sisbios_mode [ myindex ] . yres , 0 , ivideo - > vbflags2 ) < 0x14 ) {
return - 1 ;
}
break ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
case CRT2_VGA :
if ( SiS_GetModeID_VGA2 ( ivideo - > sisvga_engine , vbflags , sisbios_mode [ myindex ] . xres ,
sisbios_mode [ myindex ] . yres , 0 , ivideo - > vbflags2 ) < 0x14 ) {
return - 1 ;
}
break ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
return myindex ;
2005-04-17 02:20:36 +04:00
}
static u8
sisfb_search_refresh_rate ( struct sis_video_info * ivideo , unsigned int rate , int mode_idx )
{
int i = 0 ;
2005-09-10 00:04:45 +04:00
u16 xres = sisbios_mode [ mode_idx ] . xres ;
u16 yres = sisbios_mode [ mode_idx ] . yres ;
2005-04-17 02:20:36 +04:00
ivideo - > rate_idx = 0 ;
while ( ( sisfb_vrate [ i ] . idx ! = 0 ) & & ( sisfb_vrate [ i ] . xres < = xres ) ) {
if ( ( sisfb_vrate [ i ] . xres = = xres ) & & ( sisfb_vrate [ i ] . yres = = yres ) ) {
if ( sisfb_vrate [ i ] . refresh = = rate ) {
ivideo - > rate_idx = sisfb_vrate [ i ] . idx ;
break ;
} else if ( sisfb_vrate [ i ] . refresh > rate ) {
if ( ( sisfb_vrate [ i ] . refresh - rate ) < = 3 ) {
DPRINTK ( " sisfb: Adjusting rate from %d up to %d \n " ,
rate , sisfb_vrate [ i ] . refresh ) ;
ivideo - > rate_idx = sisfb_vrate [ i ] . idx ;
ivideo - > refresh_rate = sisfb_vrate [ i ] . refresh ;
2009-09-23 03:47:07 +04:00
} else if ( ( sisfb_vrate [ i ] . idx ! = 1 ) & &
( ( rate - sisfb_vrate [ i - 1 ] . refresh ) < = 2 ) ) {
2005-04-17 02:20:36 +04:00
DPRINTK ( " sisfb: Adjusting rate from %d down to %d \n " ,
rate , sisfb_vrate [ i - 1 ] . refresh ) ;
ivideo - > rate_idx = sisfb_vrate [ i - 1 ] . idx ;
ivideo - > refresh_rate = sisfb_vrate [ i - 1 ] . refresh ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
break ;
} else if ( ( rate - sisfb_vrate [ i ] . refresh ) < = 2 ) {
DPRINTK ( " sisfb: Adjusting rate from %d down to %d \n " ,
rate , sisfb_vrate [ i ] . refresh ) ;
2005-09-10 00:04:45 +04:00
ivideo - > rate_idx = sisfb_vrate [ i ] . idx ;
break ;
}
2005-04-17 02:20:36 +04:00
}
i + + ;
}
if ( ivideo - > rate_idx > 0 ) {
return ivideo - > rate_idx ;
} else {
printk ( KERN_INFO " sisfb: Unsupported rate %d for %dx%d \n " ,
rate , xres , yres ) ;
return 0 ;
}
}
2007-02-12 11:55:06 +03:00
static bool
2005-04-17 02:20:36 +04:00
sisfb_bridgeisslave ( struct sis_video_info * ivideo )
{
2005-09-10 00:04:45 +04:00
unsigned char P1_00 ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ! ( ivideo - > vbflags2 & VB2_VIDEOBRIDGE ) )
2007-02-12 11:55:06 +03:00
return false ;
2005-04-17 02:20:36 +04:00
2010-12-21 00:50:16 +03:00
P1_00 = SiS_GetReg ( SISPART1 , 0x00 ) ;
2005-09-10 00:04:45 +04:00
if ( ( ( ivideo - > sisvga_engine = = SIS_300_VGA ) & & ( P1_00 & 0xa0 ) = = 0x20 ) | |
( ( ivideo - > sisvga_engine = = SIS_315_VGA ) & & ( P1_00 & 0x50 ) = = 0x10 ) ) {
2007-02-12 11:55:06 +03:00
return true ;
2005-09-10 00:04:45 +04:00
} else {
2007-02-12 11:55:06 +03:00
return false ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
}
2007-02-12 11:55:06 +03:00
static bool
2005-04-17 02:20:36 +04:00
sisfballowretracecrt1 ( struct sis_video_info * ivideo )
{
2005-09-10 00:04:45 +04:00
u8 temp ;
2005-04-17 02:20:36 +04:00
2010-12-21 00:50:16 +03:00
temp = SiS_GetReg ( SISCR , 0x17 ) ;
2005-09-10 00:04:45 +04:00
if ( ! ( temp & 0x80 ) )
2007-02-12 11:55:06 +03:00
return false ;
2005-04-17 02:20:36 +04:00
2010-12-21 00:50:16 +03:00
temp = SiS_GetReg ( SISSR , 0x1f ) ;
2005-09-10 00:04:45 +04:00
if ( temp & 0xc0 )
2007-02-12 11:55:06 +03:00
return false ;
2005-04-17 02:20:36 +04:00
2007-02-12 11:55:06 +03:00
return true ;
2005-04-17 02:20:36 +04:00
}
2007-02-12 11:55:06 +03:00
static bool
2005-04-17 02:20:36 +04:00
sisfbcheckvretracecrt1 ( struct sis_video_info * ivideo )
{
2005-09-10 00:04:45 +04:00
if ( ! sisfballowretracecrt1 ( ivideo ) )
2007-02-12 11:55:06 +03:00
return false ;
2005-04-17 02:20:36 +04:00
2010-12-21 00:50:14 +03:00
if ( SiS_GetRegByte ( SISINPSTAT ) & 0x08 )
2007-02-12 11:55:06 +03:00
return true ;
2005-09-10 00:04:45 +04:00
else
2007-02-12 11:55:06 +03:00
return false ;
2005-04-17 02:20:36 +04:00
}
static void
sisfbwaitretracecrt1 ( struct sis_video_info * ivideo )
{
2005-09-10 00:04:45 +04:00
int watchdog ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ! sisfballowretracecrt1 ( ivideo ) )
return ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
watchdog = 65536 ;
2010-12-21 00:50:14 +03:00
while ( ( ! ( SiS_GetRegByte ( SISINPSTAT ) & 0x08 ) ) & & - - watchdog ) ;
2005-09-10 00:04:45 +04:00
watchdog = 65536 ;
2010-12-21 00:50:14 +03:00
while ( ( SiS_GetRegByte ( SISINPSTAT ) & 0x08 ) & & - - watchdog ) ;
2005-04-17 02:20:36 +04:00
}
2007-02-12 11:55:06 +03:00
static bool
2005-04-17 02:20:36 +04:00
sisfbcheckvretracecrt2 ( struct sis_video_info * ivideo )
{
2005-09-10 00:04:45 +04:00
unsigned char temp , reg ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
switch ( ivideo - > sisvga_engine ) {
case SIS_300_VGA : reg = 0x25 ; break ;
case SIS_315_VGA : reg = 0x30 ; break ;
2007-02-12 11:55:06 +03:00
default : return false ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
2010-12-21 00:50:16 +03:00
temp = SiS_GetReg ( SISPART1 , reg ) ;
2005-09-10 00:04:45 +04:00
if ( temp & 0x02 )
2007-02-12 11:55:06 +03:00
return true ;
2005-09-10 00:04:45 +04:00
else
2007-02-12 11:55:06 +03:00
return false ;
2005-04-17 02:20:36 +04:00
}
2007-02-12 11:55:06 +03:00
static bool
2005-04-17 02:20:36 +04:00
sisfb_CheckVBRetrace ( struct sis_video_info * ivideo )
{
2005-09-10 00:04:45 +04:00
if ( ivideo - > currentvbflags & VB_DISPTYPE_DISP2 ) {
if ( ! sisfb_bridgeisslave ( ivideo ) ) {
return sisfbcheckvretracecrt2 ( ivideo ) ;
}
}
return sisfbcheckvretracecrt1 ( ivideo ) ;
2005-04-17 02:20:36 +04:00
}
static u32
sisfb_setupvbblankflags ( struct sis_video_info * ivideo , u32 * vcount , u32 * hcount )
{
2005-09-10 00:04:45 +04:00
u8 idx , reg1 , reg2 , reg3 , reg4 ;
u32 ret = 0 ;
( * vcount ) = ( * hcount ) = 0 ;
if ( ( ivideo - > currentvbflags & VB_DISPTYPE_DISP2 ) & & ( ! ( sisfb_bridgeisslave ( ivideo ) ) ) ) {
ret | = ( FB_VBLANK_HAVE_VSYNC |
FB_VBLANK_HAVE_HBLANK |
FB_VBLANK_HAVE_VBLANK |
FB_VBLANK_HAVE_VCOUNT |
FB_VBLANK_HAVE_HCOUNT ) ;
switch ( ivideo - > sisvga_engine ) {
case SIS_300_VGA : idx = 0x25 ; break ;
default :
case SIS_315_VGA : idx = 0x30 ; break ;
}
2010-12-21 00:50:16 +03:00
reg1 = SiS_GetReg ( SISPART1 , ( idx + 0 ) ) ; /* 30 */
reg2 = SiS_GetReg ( SISPART1 , ( idx + 1 ) ) ; /* 31 */
reg3 = SiS_GetReg ( SISPART1 , ( idx + 2 ) ) ; /* 32 */
reg4 = SiS_GetReg ( SISPART1 , ( idx + 3 ) ) ; /* 33 */
2005-09-10 00:04:45 +04:00
if ( reg1 & 0x01 ) ret | = FB_VBLANK_VBLANKING ;
if ( reg1 & 0x02 ) ret | = FB_VBLANK_VSYNCING ;
if ( reg4 & 0x80 ) ret | = FB_VBLANK_HBLANKING ;
( * vcount ) = reg3 | ( ( reg4 & 0x70 ) < < 4 ) ;
( * hcount ) = reg2 | ( ( reg4 & 0x0f ) < < 8 ) ;
} else if ( sisfballowretracecrt1 ( ivideo ) ) {
ret | = ( FB_VBLANK_HAVE_VSYNC |
FB_VBLANK_HAVE_VBLANK |
FB_VBLANK_HAVE_VCOUNT |
FB_VBLANK_HAVE_HCOUNT ) ;
2010-12-21 00:50:14 +03:00
reg1 = SiS_GetRegByte ( SISINPSTAT ) ;
2005-09-10 00:04:45 +04:00
if ( reg1 & 0x08 ) ret | = FB_VBLANK_VSYNCING ;
if ( reg1 & 0x01 ) ret | = FB_VBLANK_VBLANKING ;
2010-12-21 00:50:16 +03:00
reg1 = SiS_GetReg ( SISCR , 0x20 ) ;
reg1 = SiS_GetReg ( SISCR , 0x1b ) ;
reg2 = SiS_GetReg ( SISCR , 0x1c ) ;
reg3 = SiS_GetReg ( SISCR , 0x1d ) ;
2005-09-10 00:04:45 +04:00
( * vcount ) = reg2 | ( ( reg3 & 0x07 ) < < 8 ) ;
( * hcount ) = ( reg1 | ( ( reg3 & 0x10 ) < < 4 ) ) < < 3 ;
}
return ret ;
2005-04-17 02:20:36 +04:00
}
static int
sisfb_myblank ( struct sis_video_info * ivideo , int blank )
{
2005-09-10 00:04:45 +04:00
u8 sr01 , sr11 , sr1f , cr63 = 0 , p2_0 , p1_13 ;
2007-02-12 11:55:06 +03:00
bool backlight = true ;
2005-09-10 00:04:45 +04:00
switch ( blank ) {
case FB_BLANK_UNBLANK : /* on */
sr01 = 0x00 ;
sr11 = 0x00 ;
sr1f = 0x00 ;
cr63 = 0x00 ;
p2_0 = 0x20 ;
p1_13 = 0x00 ;
2007-02-12 11:55:06 +03:00
backlight = true ;
2005-09-10 00:04:45 +04:00
break ;
case FB_BLANK_NORMAL : /* blank */
sr01 = 0x20 ;
sr11 = 0x00 ;
sr1f = 0x00 ;
cr63 = 0x00 ;
p2_0 = 0x20 ;
p1_13 = 0x00 ;
2007-02-12 11:55:06 +03:00
backlight = true ;
2005-09-10 00:04:45 +04:00
break ;
case FB_BLANK_VSYNC_SUSPEND : /* no vsync */
sr01 = 0x20 ;
sr11 = 0x08 ;
sr1f = 0x80 ;
cr63 = 0x40 ;
p2_0 = 0x40 ;
p1_13 = 0x80 ;
2007-02-12 11:55:06 +03:00
backlight = false ;
2005-09-10 00:04:45 +04:00
break ;
case FB_BLANK_HSYNC_SUSPEND : /* no hsync */
sr01 = 0x20 ;
sr11 = 0x08 ;
sr1f = 0x40 ;
cr63 = 0x40 ;
p2_0 = 0x80 ;
p1_13 = 0x40 ;
2007-02-12 11:55:06 +03:00
backlight = false ;
2005-09-10 00:04:45 +04:00
break ;
case FB_BLANK_POWERDOWN : /* off */
sr01 = 0x20 ;
sr11 = 0x08 ;
sr1f = 0xc0 ;
cr63 = 0x40 ;
p2_0 = 0xc0 ;
p1_13 = 0xc0 ;
2007-02-12 11:55:06 +03:00
backlight = false ;
2005-09-10 00:04:45 +04:00
break ;
default :
return 1 ;
}
if ( ivideo - > currentvbflags & VB_DISPTYPE_CRT1 ) {
if ( ( ! ivideo - > sisfb_thismonitor . datavalid ) | |
( ( ivideo - > sisfb_thismonitor . datavalid ) & &
( ivideo - > sisfb_thismonitor . feature & 0xe0 ) ) ) {
if ( ivideo - > sisvga_engine = = SIS_315_VGA ) {
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISCR , ivideo - > SiS_Pr . SiS_MyCR63 , 0xbf , cr63 ) ;
2005-09-10 00:04:45 +04:00
}
if ( ! ( sisfb_bridgeisslave ( ivideo ) ) ) {
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISSR , 0x01 , ~ 0x20 , sr01 ) ;
SiS_SetRegANDOR ( SISSR , 0x1f , 0x3f , sr1f ) ;
2005-09-10 00:04:45 +04:00
}
}
}
if ( ivideo - > currentvbflags & CRT2_LCD ) {
if ( ivideo - > vbflags2 & VB2_SISLVDSBRIDGE ) {
if ( backlight ) {
SiS_SiS30xBLOn ( & ivideo - > SiS_Pr ) ;
} else {
SiS_SiS30xBLOff ( & ivideo - > SiS_Pr ) ;
}
} else if ( ivideo - > sisvga_engine = = SIS_315_VGA ) {
# ifdef CONFIG_FB_SIS_315
if ( ivideo - > vbflags2 & VB2_CHRONTEL ) {
if ( backlight ) {
SiS_Chrontel701xBLOn ( & ivideo - > SiS_Pr ) ;
} else {
SiS_Chrontel701xBLOff ( & ivideo - > SiS_Pr ) ;
}
}
# endif
}
if ( ( ( ivideo - > sisvga_engine = = SIS_300_VGA ) & &
( ivideo - > vbflags2 & ( VB2_301 | VB2_30xBDH | VB2_LVDS ) ) ) | |
( ( ivideo - > sisvga_engine = = SIS_315_VGA ) & &
( ( ivideo - > vbflags2 & ( VB2_LVDS | VB2_CHRONTEL ) ) = = VB2_LVDS ) ) ) {
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISSR , 0x11 , ~ 0x0c , sr11 ) ;
2005-09-10 00:04:45 +04:00
}
if ( ivideo - > sisvga_engine = = SIS_300_VGA ) {
if ( ( ivideo - > vbflags2 & VB2_30xB ) & &
( ! ( ivideo - > vbflags2 & VB2_30xBDH ) ) ) {
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISPART1 , 0x13 , 0x3f , p1_13 ) ;
2005-09-10 00:04:45 +04:00
}
} else if ( ivideo - > sisvga_engine = = SIS_315_VGA ) {
if ( ( ivideo - > vbflags2 & VB2_30xB ) & &
( ! ( ivideo - > vbflags2 & VB2_30xBDH ) ) ) {
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISPART2 , 0x00 , 0x1f , p2_0 ) ;
2005-09-10 00:04:45 +04:00
}
}
} else if ( ivideo - > currentvbflags & CRT2_VGA ) {
if ( ivideo - > vbflags2 & VB2_30xB ) {
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISPART2 , 0x00 , 0x1f , p2_0 ) ;
2005-09-10 00:04:45 +04:00
}
}
return 0 ;
}
/* ------------- Callbacks from init.c/init301.c -------------- */
# ifdef CONFIG_FB_SIS_300
unsigned int
sisfb_read_nbridge_pci_dword ( struct SiS_Private * SiS_Pr , int reg )
{
struct sis_video_info * ivideo = ( struct sis_video_info * ) SiS_Pr - > ivideo ;
u32 val = 0 ;
pci_read_config_dword ( ivideo - > nbridge , reg , & val ) ;
return ( unsigned int ) val ;
}
void
sisfb_write_nbridge_pci_dword ( struct SiS_Private * SiS_Pr , int reg , unsigned int val )
{
struct sis_video_info * ivideo = ( struct sis_video_info * ) SiS_Pr - > ivideo ;
pci_write_config_dword ( ivideo - > nbridge , reg , ( u32 ) val ) ;
}
unsigned int
sisfb_read_lpc_pci_dword ( struct SiS_Private * SiS_Pr , int reg )
{
struct sis_video_info * ivideo = ( struct sis_video_info * ) SiS_Pr - > ivideo ;
u32 val = 0 ;
if ( ! ivideo - > lpcdev ) return 0 ;
pci_read_config_dword ( ivideo - > lpcdev , reg , & val ) ;
return ( unsigned int ) val ;
}
# endif
# ifdef CONFIG_FB_SIS_315
void
sisfb_write_nbridge_pci_byte ( struct SiS_Private * SiS_Pr , int reg , unsigned char val )
{
struct sis_video_info * ivideo = ( struct sis_video_info * ) SiS_Pr - > ivideo ;
pci_write_config_byte ( ivideo - > nbridge , reg , ( u8 ) val ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
unsigned int
sisfb_read_mio_pci_word ( struct SiS_Private * SiS_Pr , int reg )
{
struct sis_video_info * ivideo = ( struct sis_video_info * ) SiS_Pr - > ivideo ;
u16 val = 0 ;
if ( ! ivideo - > lpcdev ) return 0 ;
pci_read_config_word ( ivideo - > lpcdev , reg , & val ) ;
return ( unsigned int ) val ;
}
# endif
2005-04-17 02:20:36 +04:00
/* ----------- FBDev related routines for all series ----------- */
static int
sisfb_get_cmap_len ( const struct fb_var_screeninfo * var )
{
return ( var - > bits_per_pixel = = 8 ) ? 256 : 16 ;
}
static void
sisfb_set_vparms ( struct sis_video_info * ivideo )
{
2005-09-10 00:04:45 +04:00
switch ( ivideo - > video_bpp ) {
2005-04-17 02:20:36 +04:00
case 8 :
ivideo - > DstColor = 0x0000 ;
ivideo - > SiS310_AccelDepth = 0x00000000 ;
ivideo - > video_cmap_len = 256 ;
break ;
case 16 :
ivideo - > DstColor = 0x8000 ;
ivideo - > SiS310_AccelDepth = 0x00010000 ;
ivideo - > video_cmap_len = 16 ;
break ;
case 32 :
ivideo - > DstColor = 0xC000 ;
ivideo - > SiS310_AccelDepth = 0x00020000 ;
ivideo - > video_cmap_len = 16 ;
break ;
default :
ivideo - > video_cmap_len = 16 ;
printk ( KERN_ERR " sisfb: Unsupported depth %d " , ivideo - > video_bpp ) ;
ivideo - > accel = 0 ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
}
static int
sisfb_calc_maxyres ( struct sis_video_info * ivideo , struct fb_var_screeninfo * var )
{
2005-09-10 00:04:45 +04:00
int maxyres = ivideo - > sisfb_mem / ( var - > xres_virtual * ( var - > bits_per_pixel > > 3 ) ) ;
2005-04-17 02:20:36 +04:00
if ( maxyres > 32767 ) maxyres = 32767 ;
return maxyres ;
}
static void
sisfb_calc_pitch ( struct sis_video_info * ivideo , struct fb_var_screeninfo * var )
{
ivideo - > video_linelength = var - > xres_virtual * ( var - > bits_per_pixel > > 3 ) ;
ivideo - > scrnpitchCRT1 = ivideo - > video_linelength ;
if ( ! ( ivideo - > currentvbflags & CRT1_LCDA ) ) {
if ( ( var - > vmode & FB_VMODE_MASK ) = = FB_VMODE_INTERLACED ) {
ivideo - > scrnpitchCRT1 < < = 1 ;
}
}
}
static void
sisfb_set_pitch ( struct sis_video_info * ivideo )
{
2007-02-12 11:55:06 +03:00
bool isslavemode = false ;
2005-04-17 02:20:36 +04:00
unsigned short HDisplay1 = ivideo - > scrnpitchCRT1 > > 3 ;
unsigned short HDisplay2 = ivideo - > video_linelength > > 3 ;
2007-02-12 11:55:06 +03:00
if ( sisfb_bridgeisslave ( ivideo ) ) isslavemode = true ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* We need to set pitch for CRT1 if bridge is in slave mode, too */
if ( ( ivideo - > currentvbflags & VB_DISPTYPE_DISP1 ) | | ( isslavemode ) ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x13 , ( HDisplay1 & 0xFF ) ) ;
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISSR , 0x0E , 0xF0 , ( HDisplay1 > > 8 ) ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
/* We must not set the pitch for CRT2 if bridge is in slave mode */
if ( ( ivideo - > currentvbflags & VB_DISPTYPE_DISP2 ) & & ( ! isslavemode ) ) {
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISPART1 , ivideo - > CRT2_write_enable , 0x01 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART1 , 0x07 , ( HDisplay2 & 0xFF ) ) ;
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISPART1 , 0x09 , 0xF0 , ( HDisplay2 > > 8 ) ) ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
}
static void
sisfb_bpp_to_var ( struct sis_video_info * ivideo , struct fb_var_screeninfo * var )
{
ivideo - > video_cmap_len = sisfb_get_cmap_len ( var ) ;
switch ( var - > bits_per_pixel ) {
case 8 :
var - > red . offset = var - > green . offset = var - > blue . offset = 0 ;
2009-04-14 01:39:52 +04:00
var - > red . length = var - > green . length = var - > blue . length = 8 ;
2005-04-17 02:20:36 +04:00
break ;
case 16 :
var - > red . offset = 11 ;
var - > red . length = 5 ;
var - > green . offset = 5 ;
var - > green . length = 6 ;
var - > blue . offset = 0 ;
var - > blue . length = 5 ;
var - > transp . offset = 0 ;
var - > transp . length = 0 ;
break ;
case 32 :
var - > red . offset = 16 ;
var - > red . length = 8 ;
var - > green . offset = 8 ;
var - > green . length = 8 ;
var - > blue . offset = 0 ;
var - > blue . length = 8 ;
var - > transp . offset = 24 ;
var - > transp . length = 8 ;
break ;
}
}
2005-09-10 00:04:45 +04:00
static int
sisfb_set_mode ( struct sis_video_info * ivideo , int clrscrn )
{
unsigned short modeno = ivideo - > mode_no ;
/* >=2.6.12's fbcon clears the screen anyway */
modeno | = 0x80 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , IND_SIS_PASSWORD , SIS_PASSWORD ) ;
2005-09-10 00:04:45 +04:00
sisfb_pre_setmode ( ivideo ) ;
2007-02-12 11:55:06 +03:00
if ( ! SiSSetMode ( & ivideo - > SiS_Pr , modeno ) ) {
2005-09-10 00:04:45 +04:00
printk ( KERN_ERR " sisfb: Setting mode[0x%x] failed \n " , ivideo - > mode_no ) ;
return - EINVAL ;
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , IND_SIS_PASSWORD , SIS_PASSWORD ) ;
2005-09-10 00:04:45 +04:00
sisfb_post_setmode ( ivideo ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
static int
sisfb_do_set_var ( struct fb_var_screeninfo * var , int isactive , struct fb_info * info )
{
struct sis_video_info * ivideo = ( struct sis_video_info * ) info - > par ;
unsigned int htotal = 0 , vtotal = 0 ;
unsigned int drate = 0 , hrate = 0 ;
2005-09-10 00:04:45 +04:00
int found_mode = 0 , ret ;
2005-04-17 02:20:36 +04:00
int old_mode ;
u32 pixclock ;
htotal = var - > left_margin + var - > xres + var - > right_margin + var - > hsync_len ;
vtotal = var - > upper_margin + var - > lower_margin + var - > vsync_len ;
pixclock = var - > pixclock ;
if ( ( var - > vmode & FB_VMODE_MASK ) = = FB_VMODE_NONINTERLACED ) {
vtotal + = var - > yres ;
vtotal < < = 1 ;
} else if ( ( var - > vmode & FB_VMODE_MASK ) = = FB_VMODE_DOUBLE ) {
vtotal + = var - > yres ;
vtotal < < = 2 ;
} else if ( ( var - > vmode & FB_VMODE_MASK ) = = FB_VMODE_INTERLACED ) {
vtotal + = var - > yres ;
vtotal < < = 1 ;
} else vtotal + = var - > yres ;
if ( ! ( htotal ) | | ! ( vtotal ) ) {
DPRINTK ( " sisfb: Invalid 'var' information \n " ) ;
return - EINVAL ;
}
if ( pixclock & & htotal & & vtotal ) {
2005-09-10 00:04:45 +04:00
drate = 1000000000 / pixclock ;
hrate = ( drate * 1000 ) / htotal ;
ivideo - > refresh_rate = ( unsigned int ) ( hrate * 2 / vtotal ) ;
2005-04-17 02:20:36 +04:00
} else {
2005-09-10 00:04:45 +04:00
ivideo - > refresh_rate = 60 ;
2005-04-17 02:20:36 +04:00
}
old_mode = ivideo - > sisfb_mode_idx ;
ivideo - > sisfb_mode_idx = 0 ;
while ( ( sisbios_mode [ ivideo - > sisfb_mode_idx ] . mode_no [ 0 ] ! = 0 ) & &
( sisbios_mode [ ivideo - > sisfb_mode_idx ] . xres < = var - > xres ) ) {
if ( ( sisbios_mode [ ivideo - > sisfb_mode_idx ] . xres = = var - > xres ) & &
( sisbios_mode [ ivideo - > sisfb_mode_idx ] . yres = = var - > yres ) & &
( sisbios_mode [ ivideo - > sisfb_mode_idx ] . bpp = = var - > bits_per_pixel ) ) {
ivideo - > mode_no = sisbios_mode [ ivideo - > sisfb_mode_idx ] . mode_no [ ivideo - > mni ] ;
found_mode = 1 ;
break ;
}
ivideo - > sisfb_mode_idx + + ;
}
if ( found_mode ) {
ivideo - > sisfb_mode_idx = sisfb_validate_mode ( ivideo ,
ivideo - > sisfb_mode_idx , ivideo - > currentvbflags ) ;
} else {
ivideo - > sisfb_mode_idx = - 1 ;
}
if ( ivideo - > sisfb_mode_idx < 0 ) {
printk ( KERN_ERR " sisfb: Mode %dx%dx%d not supported \n " , var - > xres ,
var - > yres , var - > bits_per_pixel ) ;
ivideo - > sisfb_mode_idx = old_mode ;
return - EINVAL ;
}
2007-11-15 03:59:02 +03:00
ivideo - > mode_no = sisbios_mode [ ivideo - > sisfb_mode_idx ] . mode_no [ ivideo - > mni ] ;
2005-04-17 02:20:36 +04:00
if ( sisfb_search_refresh_rate ( ivideo , ivideo - > refresh_rate , ivideo - > sisfb_mode_idx ) = = 0 ) {
ivideo - > rate_idx = sisbios_mode [ ivideo - > sisfb_mode_idx ] . rate_idx ;
ivideo - > refresh_rate = 60 ;
}
if ( isactive ) {
2005-09-10 00:04:45 +04:00
/* If acceleration to be used? Need to know
* before pre / post_set_mode ( )
*/
2005-04-17 02:20:36 +04:00
ivideo - > accel = 0 ;
# if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
# ifdef STUPID_ACCELF_TEXT_SHIT
if ( var - > accel_flags & FB_ACCELF_TEXT ) {
info - > flags & = ~ FBINFO_HWACCEL_DISABLED ;
} else {
info - > flags | = FBINFO_HWACCEL_DISABLED ;
}
# endif
if ( ! ( info - > flags & FBINFO_HWACCEL_DISABLED ) ) ivideo - > accel = - 1 ;
# else
if ( var - > accel_flags & FB_ACCELF_TEXT ) ivideo - > accel = - 1 ;
# endif
2005-09-10 00:04:45 +04:00
if ( ( ret = sisfb_set_mode ( ivideo , 1 ) ) ) {
return ret ;
}
ivideo - > video_bpp = sisbios_mode [ ivideo - > sisfb_mode_idx ] . bpp ;
ivideo - > video_width = sisbios_mode [ ivideo - > sisfb_mode_idx ] . xres ;
ivideo - > video_height = sisbios_mode [ ivideo - > sisfb_mode_idx ] . yres ;
sisfb_calc_pitch ( ivideo , var ) ;
sisfb_set_pitch ( ivideo ) ;
2005-04-17 02:20:36 +04:00
sisfb_set_vparms ( ivideo ) ;
ivideo - > current_width = ivideo - > video_width ;
ivideo - > current_height = ivideo - > video_height ;
ivideo - > current_bpp = ivideo - > video_bpp ;
ivideo - > current_htotal = htotal ;
ivideo - > current_vtotal = vtotal ;
ivideo - > current_linelength = ivideo - > video_linelength ;
ivideo - > current_pixclock = var - > pixclock ;
ivideo - > current_refresh_rate = ivideo - > refresh_rate ;
2005-09-10 00:04:45 +04:00
ivideo - > sisfb_lastrates [ ivideo - > mode_no ] = ivideo - > refresh_rate ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
2005-09-10 00:04:45 +04:00
static void
sisfb_set_base_CRT1 ( struct sis_video_info * ivideo , unsigned int base )
2005-04-17 02:20:36 +04:00
{
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , IND_SIS_PASSWORD , SIS_PASSWORD ) ;
2005-04-17 02:20:36 +04:00
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x0D , base & 0xFF ) ;
SiS_SetReg ( SISCR , 0x0C , ( base > > 8 ) & 0xFF ) ;
SiS_SetReg ( SISSR , 0x0D , ( base > > 16 ) & 0xFF ) ;
2005-04-17 02:20:36 +04:00
if ( ivideo - > sisvga_engine = = SIS_315_VGA ) {
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISSR , 0x37 , 0xFE , ( base > > 24 ) & 0x01 ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
}
static void
sisfb_set_base_CRT2 ( struct sis_video_info * ivideo , unsigned int base )
{
if ( ivideo - > currentvbflags & VB_DISPTYPE_DISP2 ) {
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISPART1 , ivideo - > CRT2_write_enable , 0x01 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART1 , 0x06 , ( base & 0xFF ) ) ;
SiS_SetReg ( SISPART1 , 0x05 , ( ( base > > 8 ) & 0xFF ) ) ;
SiS_SetReg ( SISPART1 , 0x04 , ( ( base > > 16 ) & 0xFF ) ) ;
2005-04-17 02:20:36 +04:00
if ( ivideo - > sisvga_engine = = SIS_315_VGA ) {
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISPART1 , 0x02 , 0x7F , ( ( base > > 24 ) & 0x01 ) < < 7 ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
static int
2011-05-25 13:34:52 +04:00
sisfb_pan_var ( struct sis_video_info * ivideo , struct fb_info * info ,
struct fb_var_screeninfo * var )
2005-04-17 02:20:36 +04:00
{
2011-05-25 13:34:52 +04:00
ivideo - > current_base = var - > yoffset * info - > var . xres_virtual
+ var - > xoffset ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* calculate base bpp dep. */
2011-05-25 13:34:52 +04:00
switch ( info - > var . bits_per_pixel ) {
2005-09-10 00:04:45 +04:00
case 32 :
2005-04-17 02:20:36 +04:00
break ;
2005-09-10 00:04:45 +04:00
case 16 :
ivideo - > current_base > > = 1 ;
2005-04-17 02:20:36 +04:00
break ;
2005-09-10 00:04:45 +04:00
case 8 :
default :
ivideo - > current_base > > = 2 ;
2005-04-17 02:20:36 +04:00
break ;
}
2005-09-10 00:04:45 +04:00
ivideo - > current_base + = ( ivideo - > video_offset > > 2 ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
sisfb_set_base_CRT1 ( ivideo , ivideo - > current_base ) ;
sisfb_set_base_CRT2 ( ivideo , ivideo - > current_base ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
static int
sisfb_open ( struct fb_info * info , int user )
{
return 0 ;
2005-04-17 02:20:36 +04:00
}
static int
2005-09-10 00:04:45 +04:00
sisfb_release ( struct fb_info * info , int user )
2005-04-17 02:20:36 +04:00
{
return 0 ;
}
static int
sisfb_setcolreg ( unsigned regno , unsigned red , unsigned green , unsigned blue ,
2005-09-10 00:04:45 +04:00
unsigned transp , struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
struct sis_video_info * ivideo = ( struct sis_video_info * ) info - > par ;
2005-09-10 00:04:45 +04:00
if ( regno > = sisfb_get_cmap_len ( & info - > var ) )
return 1 ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
switch ( info - > var . bits_per_pixel ) {
2005-04-17 02:20:36 +04:00
case 8 :
2010-12-21 00:50:15 +03:00
SiS_SetRegByte ( SISDACA , regno ) ;
SiS_SetRegByte ( SISDACD , ( red > > 10 ) ) ;
SiS_SetRegByte ( SISDACD , ( green > > 10 ) ) ;
SiS_SetRegByte ( SISDACD , ( blue > > 10 ) ) ;
2005-04-17 02:20:36 +04:00
if ( ivideo - > currentvbflags & VB_DISPTYPE_DISP2 ) {
2010-12-21 00:50:15 +03:00
SiS_SetRegByte ( SISDAC2A , regno ) ;
SiS_SetRegByte ( SISDAC2D , ( red > > 8 ) ) ;
SiS_SetRegByte ( SISDAC2D , ( green > > 8 ) ) ;
SiS_SetRegByte ( SISDAC2D , ( blue > > 8 ) ) ;
2005-04-17 02:20:36 +04:00
}
break ;
case 16 :
2007-07-17 15:05:44 +04:00
if ( regno > = 16 )
break ;
2005-09-10 00:04:45 +04:00
( ( u32 * ) ( info - > pseudo_palette ) ) [ regno ] =
( red & 0xf800 ) |
( ( green & 0xfc00 ) > > 5 ) |
( ( blue & 0xf800 ) > > 11 ) ;
2005-04-17 02:20:36 +04:00
break ;
case 32 :
2007-07-17 15:05:44 +04:00
if ( regno > = 16 )
break ;
2005-09-10 00:04:45 +04:00
red > > = 8 ;
2005-04-17 02:20:36 +04:00
green > > = 8 ;
2005-09-10 00:04:45 +04:00
blue > > = 8 ;
( ( u32 * ) ( info - > pseudo_palette ) ) [ regno ] =
( red < < 16 ) | ( green < < 8 ) | ( blue ) ;
2005-04-17 02:20:36 +04:00
break ;
}
return 0 ;
}
static int
2005-09-10 00:04:45 +04:00
sisfb_set_par ( struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
2005-09-10 00:04:45 +04:00
int err ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ( err = sisfb_do_set_var ( & info - > var , 1 , info ) ) )
return err ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
sisfb_get_fix ( & info - > fix , - 1 , info ) ;
2008-07-24 08:31:12 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int
2005-09-10 00:04:45 +04:00
sisfb_check_var ( struct fb_var_screeninfo * var , struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
struct sis_video_info * ivideo = ( struct sis_video_info * ) info - > par ;
2005-09-10 00:04:45 +04:00
unsigned int htotal = 0 , vtotal = 0 , myrateindex = 0 ;
unsigned int drate = 0 , hrate = 0 , maxyres ;
int found_mode = 0 ;
int refresh_rate , search_idx , tidx ;
2007-02-12 11:55:06 +03:00
bool recalc_clock = false ;
2005-09-10 00:04:45 +04:00
u32 pixclock ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
htotal = var - > left_margin + var - > xres + var - > right_margin + var - > hsync_len ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
vtotal = var - > upper_margin + var - > lower_margin + var - > vsync_len ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
pixclock = var - > pixclock ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ( var - > vmode & FB_VMODE_MASK ) = = FB_VMODE_NONINTERLACED ) {
vtotal + = var - > yres ;
vtotal < < = 1 ;
} else if ( ( var - > vmode & FB_VMODE_MASK ) = = FB_VMODE_DOUBLE ) {
vtotal + = var - > yres ;
vtotal < < = 2 ;
} else if ( ( var - > vmode & FB_VMODE_MASK ) = = FB_VMODE_INTERLACED ) {
vtotal + = var - > yres ;
vtotal < < = 1 ;
} else
vtotal + = var - > yres ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ! ( htotal ) | | ! ( vtotal ) ) {
SISFAIL ( " sisfb: no valid timing data " ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
search_idx = 0 ;
while ( ( sisbios_mode [ search_idx ] . mode_no [ 0 ] ! = 0 ) & &
( sisbios_mode [ search_idx ] . xres < = var - > xres ) ) {
if ( ( sisbios_mode [ search_idx ] . xres = = var - > xres ) & &
( sisbios_mode [ search_idx ] . yres = = var - > yres ) & &
( sisbios_mode [ search_idx ] . bpp = = var - > bits_per_pixel ) ) {
if ( ( tidx = sisfb_validate_mode ( ivideo , search_idx ,
ivideo - > currentvbflags ) ) > 0 ) {
found_mode = 1 ;
search_idx = tidx ;
break ;
}
}
search_idx + + ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
if ( ! found_mode ) {
search_idx = 0 ;
while ( sisbios_mode [ search_idx ] . mode_no [ 0 ] ! = 0 ) {
if ( ( var - > xres < = sisbios_mode [ search_idx ] . xres ) & &
( var - > yres < = sisbios_mode [ search_idx ] . yres ) & &
( var - > bits_per_pixel = = sisbios_mode [ search_idx ] . bpp ) ) {
if ( ( tidx = sisfb_validate_mode ( ivideo , search_idx ,
ivideo - > currentvbflags ) ) > 0 ) {
found_mode = 1 ;
search_idx = tidx ;
break ;
}
}
search_idx + + ;
}
if ( found_mode ) {
printk ( KERN_DEBUG
" sisfb: Adapted from %dx%dx%d to %dx%dx%d \n " ,
var - > xres , var - > yres , var - > bits_per_pixel ,
sisbios_mode [ search_idx ] . xres ,
sisbios_mode [ search_idx ] . yres ,
var - > bits_per_pixel ) ;
var - > xres = sisbios_mode [ search_idx ] . xres ;
var - > yres = sisbios_mode [ search_idx ] . yres ;
} else {
printk ( KERN_ERR
" sisfb: Failed to find supported mode near %dx%dx%d \n " ,
var - > xres , var - > yres , var - > bits_per_pixel ) ;
return - EINVAL ;
}
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ( ( ivideo - > vbflags2 & VB2_LVDS ) | |
( ( ivideo - > vbflags2 & VB2_30xBDH ) & & ( ivideo - > currentvbflags & CRT2_LCD ) ) ) & &
( var - > bits_per_pixel = = 8 ) ) {
/* Slave modes on LVDS and 301B-DH */
refresh_rate = 60 ;
2007-02-12 11:55:06 +03:00
recalc_clock = true ;
2005-09-10 00:04:45 +04:00
} else if ( ( ivideo - > current_htotal = = htotal ) & &
( ivideo - > current_vtotal = = vtotal ) & &
( ivideo - > current_pixclock = = pixclock ) ) {
/* x=x & y=y & c=c -> assume depth change */
drate = 1000000000 / pixclock ;
hrate = ( drate * 1000 ) / htotal ;
refresh_rate = ( unsigned int ) ( hrate * 2 / vtotal ) ;
} else if ( ( ( ivideo - > current_htotal ! = htotal ) | |
( ivideo - > current_vtotal ! = vtotal ) ) & &
( ivideo - > current_pixclock = = var - > pixclock ) ) {
/* x!=x | y!=y & c=c -> invalid pixclock */
if ( ivideo - > sisfb_lastrates [ sisbios_mode [ search_idx ] . mode_no [ ivideo - > mni ] ] ) {
refresh_rate =
ivideo - > sisfb_lastrates [ sisbios_mode [ search_idx ] . mode_no [ ivideo - > mni ] ] ;
} else if ( ivideo - > sisfb_parm_rate ! = - 1 ) {
/* Sic, sisfb_parm_rate - want to know originally desired rate here */
refresh_rate = ivideo - > sisfb_parm_rate ;
} else {
refresh_rate = 60 ;
}
2007-02-12 11:55:06 +03:00
recalc_clock = true ;
2005-09-10 00:04:45 +04:00
} else if ( ( pixclock ) & & ( htotal ) & & ( vtotal ) ) {
drate = 1000000000 / pixclock ;
hrate = ( drate * 1000 ) / htotal ;
refresh_rate = ( unsigned int ) ( hrate * 2 / vtotal ) ;
} else if ( ivideo - > current_refresh_rate ) {
refresh_rate = ivideo - > current_refresh_rate ;
2007-02-12 11:55:06 +03:00
recalc_clock = true ;
2005-09-10 00:04:45 +04:00
} else {
refresh_rate = 60 ;
2007-02-12 11:55:06 +03:00
recalc_clock = true ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
myrateindex = sisfb_search_refresh_rate ( ivideo , refresh_rate , search_idx ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* Eventually recalculate timing and clock */
if ( recalc_clock ) {
if ( ! myrateindex ) myrateindex = sisbios_mode [ search_idx ] . rate_idx ;
var - > pixclock = ( u32 ) ( 1000000000 / sisfb_mode_rate_to_dclock ( & ivideo - > SiS_Pr ,
sisbios_mode [ search_idx ] . mode_no [ ivideo - > mni ] ,
myrateindex ) ) ;
sisfb_mode_rate_to_ddata ( & ivideo - > SiS_Pr ,
sisbios_mode [ search_idx ] . mode_no [ ivideo - > mni ] ,
myrateindex , var ) ;
if ( ( var - > vmode & FB_VMODE_MASK ) = = FB_VMODE_DOUBLE ) {
var - > pixclock < < = 1 ;
}
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ivideo - > sisfb_thismonitor . datavalid ) {
if ( ! sisfb_verify_rate ( ivideo , & ivideo - > sisfb_thismonitor , search_idx ,
myrateindex , refresh_rate ) ) {
printk ( KERN_INFO
" sisfb: WARNING: Refresh rate exceeds monitor specs! \n " ) ;
}
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* Adapt RGB settings */
sisfb_bpp_to_var ( ivideo , var ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* Sanity check for offsets */
if ( var - > xoffset < 0 ) var - > xoffset = 0 ;
if ( var - > yoffset < 0 ) var - > yoffset = 0 ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( var - > xres > var - > xres_virtual )
var - > xres_virtual = var - > xres ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ivideo - > sisfb_ypan ) {
maxyres = sisfb_calc_maxyres ( ivideo , var ) ;
if ( ivideo - > sisfb_max ) {
var - > yres_virtual = maxyres ;
2005-04-17 02:20:36 +04:00
} else {
2005-09-10 00:04:45 +04:00
if ( var - > yres_virtual > maxyres ) {
var - > yres_virtual = maxyres ;
}
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
if ( var - > yres_virtual < = var - > yres ) {
var - > yres_virtual = var - > yres ;
2005-04-17 02:20:36 +04:00
}
} else {
2005-09-10 00:04:45 +04:00
if ( var - > yres ! = var - > yres_virtual ) {
var - > yres_virtual = var - > yres ;
}
var - > xoffset = 0 ;
var - > yoffset = 0 ;
2005-04-17 02:20:36 +04:00
}
/* Truncate offsets to maximum if too high */
if ( var - > xoffset > var - > xres_virtual - var - > xres ) {
2005-09-10 00:04:45 +04:00
var - > xoffset = var - > xres_virtual - var - > xres - 1 ;
2005-04-17 02:20:36 +04:00
}
if ( var - > yoffset > var - > yres_virtual - var - > yres ) {
2005-09-10 00:04:45 +04:00
var - > yoffset = var - > yres_virtual - var - > yres - 1 ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
2005-04-17 02:20:36 +04:00
/* Set everything else to 0 */
2005-09-10 00:04:45 +04:00
var - > red . msb_right =
var - > green . msb_right =
var - > blue . msb_right =
var - > transp . offset =
var - > transp . length =
var - > transp . msb_right = 0 ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int
sisfb_pan_display ( struct fb_var_screeninfo * var , struct fb_info * info )
{
struct sis_video_info * ivideo = ( struct sis_video_info * ) info - > par ;
int err ;
2011-05-25 13:34:52 +04:00
if ( var - > vmode & FB_VMODE_YWRAP )
2005-09-10 00:04:45 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2011-05-25 13:34:52 +04:00
if ( var - > xoffset + info - > var . xres > info - > var . xres_virtual | |
var - > yoffset + info - > var . yres > info - > var . yres_virtual )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2011-05-25 13:34:52 +04:00
err = sisfb_pan_var ( ivideo , info , var ) ;
if ( err < 0 )
2005-09-10 00:04:45 +04:00
return err ;
2005-04-17 02:20:36 +04:00
info - > var . xoffset = var - > xoffset ;
info - > var . yoffset = var - > yoffset ;
return 0 ;
}
static int
sisfb_blank ( int blank , struct fb_info * info )
{
struct sis_video_info * ivideo = ( struct sis_video_info * ) info - > par ;
2005-09-10 00:04:45 +04:00
return sisfb_myblank ( ivideo , blank ) ;
2005-04-17 02:20:36 +04:00
}
/* ----------- FBDev related routines for all series ---------- */
2006-01-15 00:21:25 +03:00
static int sisfb_ioctl ( struct fb_info * info , unsigned int cmd ,
unsigned long arg )
2005-04-17 02:20:36 +04:00
{
struct sis_video_info * ivideo = ( struct sis_video_info * ) info - > par ;
2005-09-10 00:04:45 +04:00
struct sis_memreq sismemreq ;
struct fb_vblank sisvbblank ;
2005-04-17 02:20:36 +04:00
u32 gpu32 = 0 ;
# ifndef __user
# define __user
# endif
u32 __user * argp = ( u32 __user * ) arg ;
2005-09-10 00:04:45 +04:00
switch ( cmd ) {
2005-04-17 02:20:36 +04:00
case FBIO_ALLOC :
2005-09-10 00:04:45 +04:00
if ( ! capable ( CAP_SYS_RAWIO ) )
2005-04-17 02:20:36 +04:00
return - EPERM ;
2005-09-10 00:04:45 +04:00
if ( copy_from_user ( & sismemreq , ( void __user * ) arg , sizeof ( sismemreq ) ) )
return - EFAULT ;
2005-04-17 02:20:36 +04:00
sis_malloc ( & sismemreq ) ;
2005-09-10 00:04:45 +04:00
2005-04-17 02:20:36 +04:00
if ( copy_to_user ( ( void __user * ) arg , & sismemreq , sizeof ( sismemreq ) ) ) {
sis_free ( ( u32 ) sismemreq . offset ) ;
2005-09-10 00:04:45 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
}
break ;
case FBIO_FREE :
2005-09-10 00:04:45 +04:00
if ( ! capable ( CAP_SYS_RAWIO ) )
2005-04-17 02:20:36 +04:00
return - EPERM ;
2005-09-10 00:04:45 +04:00
if ( get_user ( gpu32 , argp ) )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
2005-09-10 00:04:45 +04:00
2005-04-17 02:20:36 +04:00
sis_free ( gpu32 ) ;
break ;
case FBIOGET_VBLANK :
2010-09-23 00:05:09 +04:00
memset ( & sisvbblank , 0 , sizeof ( struct fb_vblank ) ) ;
2005-04-17 02:20:36 +04:00
sisvbblank . count = 0 ;
sisvbblank . flags = sisfb_setupvbblankflags ( ivideo , & sisvbblank . vcount , & sisvbblank . hcount ) ;
2005-09-10 00:04:45 +04:00
if ( copy_to_user ( ( void __user * ) arg , & sisvbblank , sizeof ( sisvbblank ) ) )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
2005-09-10 00:04:45 +04:00
2005-04-17 02:20:36 +04:00
break ;
case SISFB_GET_INFO_SIZE :
2005-09-10 00:04:45 +04:00
return put_user ( sizeof ( struct sisfb_info ) , argp ) ;
2005-04-17 02:20:36 +04:00
case SISFB_GET_INFO_OLD :
2005-09-10 00:04:45 +04:00
if ( ivideo - > warncount + + < 10 )
printk ( KERN_INFO
" sisfb: Deprecated ioctl call received - update your application! \n " ) ;
2005-04-17 02:20:36 +04:00
case SISFB_GET_INFO : /* For communication with X driver */
2005-09-10 00:04:45 +04:00
ivideo - > sisfb_infoblock . sisfb_id = SISFB_ID ;
ivideo - > sisfb_infoblock . sisfb_version = VER_MAJOR ;
ivideo - > sisfb_infoblock . sisfb_revision = VER_MINOR ;
ivideo - > sisfb_infoblock . sisfb_patchlevel = VER_LEVEL ;
ivideo - > sisfb_infoblock . chip_id = ivideo - > chip_id ;
ivideo - > sisfb_infoblock . sisfb_pci_vendor = ivideo - > chip_vendor ;
ivideo - > sisfb_infoblock . memory = ivideo - > video_size / 1024 ;
ivideo - > sisfb_infoblock . heapstart = ivideo - > heapstart / 1024 ;
2005-04-17 02:20:36 +04:00
if ( ivideo - > modechanged ) {
2005-09-10 00:04:45 +04:00
ivideo - > sisfb_infoblock . fbvidmode = ivideo - > mode_no ;
2005-04-17 02:20:36 +04:00
} else {
2005-09-10 00:04:45 +04:00
ivideo - > sisfb_infoblock . fbvidmode = ivideo - > modeprechange ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
ivideo - > sisfb_infoblock . sisfb_caps = ivideo - > caps ;
ivideo - > sisfb_infoblock . sisfb_tqlen = ivideo - > cmdQueueSize / 1024 ;
ivideo - > sisfb_infoblock . sisfb_pcibus = ivideo - > pcibus ;
ivideo - > sisfb_infoblock . sisfb_pcislot = ivideo - > pcislot ;
ivideo - > sisfb_infoblock . sisfb_pcifunc = ivideo - > pcifunc ;
ivideo - > sisfb_infoblock . sisfb_lcdpdc = ivideo - > detectedpdc ;
ivideo - > sisfb_infoblock . sisfb_lcdpdca = ivideo - > detectedpdca ;
ivideo - > sisfb_infoblock . sisfb_lcda = ivideo - > detectedlcda ;
ivideo - > sisfb_infoblock . sisfb_vbflags = ivideo - > vbflags ;
ivideo - > sisfb_infoblock . sisfb_currentvbflags = ivideo - > currentvbflags ;
ivideo - > sisfb_infoblock . sisfb_scalelcd = ivideo - > SiS_Pr . UsePanelScaler ;
ivideo - > sisfb_infoblock . sisfb_specialtiming = ivideo - > SiS_Pr . SiS_CustomT ;
ivideo - > sisfb_infoblock . sisfb_haveemi = ivideo - > SiS_Pr . HaveEMI ? 1 : 0 ;
ivideo - > sisfb_infoblock . sisfb_haveemilcd = ivideo - > SiS_Pr . HaveEMILCD ? 1 : 0 ;
ivideo - > sisfb_infoblock . sisfb_emi30 = ivideo - > SiS_Pr . EMI_30 ;
ivideo - > sisfb_infoblock . sisfb_emi31 = ivideo - > SiS_Pr . EMI_31 ;
ivideo - > sisfb_infoblock . sisfb_emi32 = ivideo - > SiS_Pr . EMI_32 ;
ivideo - > sisfb_infoblock . sisfb_emi33 = ivideo - > SiS_Pr . EMI_33 ;
ivideo - > sisfb_infoblock . sisfb_tvxpos = ( u16 ) ( ivideo - > tvxpos + 32 ) ;
ivideo - > sisfb_infoblock . sisfb_tvypos = ( u16 ) ( ivideo - > tvypos + 32 ) ;
ivideo - > sisfb_infoblock . sisfb_heapsize = ivideo - > sisfb_heap_size / 1024 ;
ivideo - > sisfb_infoblock . sisfb_videooffset = ivideo - > video_offset ;
ivideo - > sisfb_infoblock . sisfb_curfstn = ivideo - > curFSTN ;
ivideo - > sisfb_infoblock . sisfb_curdstn = ivideo - > curDSTN ;
ivideo - > sisfb_infoblock . sisfb_vbflags2 = ivideo - > vbflags2 ;
ivideo - > sisfb_infoblock . sisfb_can_post = ivideo - > sisfb_can_post ? 1 : 0 ;
ivideo - > sisfb_infoblock . sisfb_card_posted = ivideo - > sisfb_card_posted ? 1 : 0 ;
ivideo - > sisfb_infoblock . sisfb_was_boot_device = ivideo - > sisfb_was_boot_device ? 1 : 0 ;
if ( copy_to_user ( ( void __user * ) arg , & ivideo - > sisfb_infoblock ,
sizeof ( ivideo - > sisfb_infoblock ) ) )
return - EFAULT ;
2005-04-17 02:20:36 +04:00
break ;
case SISFB_GET_VBRSTATUS_OLD :
2005-09-10 00:04:45 +04:00
if ( ivideo - > warncount + + < 10 )
printk ( KERN_INFO
" sisfb: Deprecated ioctl call received - update your application! \n " ) ;
2005-04-17 02:20:36 +04:00
case SISFB_GET_VBRSTATUS :
2005-09-10 00:04:45 +04:00
if ( sisfb_CheckVBRetrace ( ivideo ) )
2005-04-17 02:20:36 +04:00
return put_user ( ( u32 ) 1 , argp ) ;
2005-09-10 00:04:45 +04:00
else
2005-04-17 02:20:36 +04:00
return put_user ( ( u32 ) 0 , argp ) ;
case SISFB_GET_AUTOMAXIMIZE_OLD :
2005-09-10 00:04:45 +04:00
if ( ivideo - > warncount + + < 10 )
printk ( KERN_INFO
" sisfb: Deprecated ioctl call received - update your application! \n " ) ;
2005-04-17 02:20:36 +04:00
case SISFB_GET_AUTOMAXIMIZE :
2005-09-10 00:04:45 +04:00
if ( ivideo - > sisfb_max )
return put_user ( ( u32 ) 1 , argp ) ;
else
return put_user ( ( u32 ) 0 , argp ) ;
2005-04-17 02:20:36 +04:00
case SISFB_SET_AUTOMAXIMIZE_OLD :
2005-09-10 00:04:45 +04:00
if ( ivideo - > warncount + + < 10 )
printk ( KERN_INFO
" sisfb: Deprecated ioctl call received - update your application! \n " ) ;
2005-04-17 02:20:36 +04:00
case SISFB_SET_AUTOMAXIMIZE :
2005-09-10 00:04:45 +04:00
if ( get_user ( gpu32 , argp ) )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
2005-09-10 00:04:45 +04:00
2005-04-17 02:20:36 +04:00
ivideo - > sisfb_max = ( gpu32 ) ? 1 : 0 ;
break ;
case SISFB_SET_TVPOSOFFSET :
2005-09-10 00:04:45 +04:00
if ( get_user ( gpu32 , argp ) )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
2005-09-10 00:04:45 +04:00
2005-04-17 02:20:36 +04:00
sisfb_set_TVxposoffset ( ivideo , ( ( int ) ( gpu32 > > 16 ) ) - 32 ) ;
sisfb_set_TVyposoffset ( ivideo , ( ( int ) ( gpu32 & 0xffff ) ) - 32 ) ;
break ;
case SISFB_GET_TVPOSOFFSET :
2005-09-10 00:04:45 +04:00
return put_user ( ( u32 ) ( ( ( ivideo - > tvxpos + 32 ) < < 16 ) | ( ( ivideo - > tvypos + 32 ) & 0xffff ) ) ,
argp ) ;
case SISFB_COMMAND :
if ( copy_from_user ( & ivideo - > sisfb_command , ( void __user * ) arg ,
sizeof ( struct sisfb_cmd ) ) )
return - EFAULT ;
sisfb_handle_command ( ivideo , & ivideo - > sisfb_command ) ;
if ( copy_to_user ( ( void __user * ) arg , & ivideo - > sisfb_command ,
sizeof ( struct sisfb_cmd ) ) )
return - EFAULT ;
break ;
2005-04-17 02:20:36 +04:00
case SISFB_SET_LOCK :
2005-09-10 00:04:45 +04:00
if ( get_user ( gpu32 , argp ) )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
2005-09-10 00:04:45 +04:00
2005-04-17 02:20:36 +04:00
ivideo - > sisfblocked = ( gpu32 ) ? 1 : 0 ;
break ;
default :
2005-09-10 00:04:45 +04:00
# ifdef SIS_NEW_CONFIG_COMPAT
2005-04-17 02:20:36 +04:00
return - ENOIOCTLCMD ;
2005-09-10 00:04:45 +04:00
# else
return - EINVAL ;
# endif
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
static int
sisfb_get_fix ( struct fb_fix_screeninfo * fix , int con , struct fb_info * info )
{
struct sis_video_info * ivideo = ( struct sis_video_info * ) info - > par ;
memset ( fix , 0 , sizeof ( struct fb_fix_screeninfo ) ) ;
2010-05-25 01:33:53 +04:00
strlcpy ( fix - > id , ivideo - > myid , sizeof ( fix - > id ) ) ;
2005-04-17 02:20:36 +04:00
2009-06-30 22:41:29 +04:00
mutex_lock ( & info - > mm_lock ) ;
2005-09-10 00:04:45 +04:00
fix - > smem_start = ivideo - > video_base + ivideo - > video_offset ;
2005-04-17 02:20:36 +04:00
fix - > smem_len = ivideo - > sisfb_mem ;
2009-06-30 22:41:29 +04:00
mutex_unlock ( & info - > mm_lock ) ;
2005-04-17 02:20:36 +04:00
fix - > type = FB_TYPE_PACKED_PIXELS ;
fix - > type_aux = 0 ;
fix - > visual = ( ivideo - > video_bpp = = 8 ) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR ;
fix - > xpanstep = 1 ;
fix - > ypanstep = ( ivideo - > sisfb_ypan ) ? 1 : 0 ;
fix - > ywrapstep = 0 ;
fix - > line_length = ivideo - > video_linelength ;
fix - > mmio_start = ivideo - > mmio_base ;
fix - > mmio_len = ivideo - > mmio_size ;
if ( ivideo - > sisvga_engine = = SIS_300_VGA ) {
2005-09-10 00:04:45 +04:00
fix - > accel = FB_ACCEL_SIS_GLAMOUR ;
} else if ( ( ivideo - > chip = = SIS_330 ) | |
( ivideo - > chip = = SIS_760 ) | |
( ivideo - > chip = = SIS_761 ) ) {
fix - > accel = FB_ACCEL_SIS_XABRE ;
} else if ( ivideo - > chip = = XGI_20 ) {
fix - > accel = FB_ACCEL_XGI_VOLARI_Z ;
} else if ( ivideo - > chip > = XGI_40 ) {
fix - > accel = FB_ACCEL_XGI_VOLARI_V ;
2005-04-17 02:20:36 +04:00
} else {
2005-09-10 00:04:45 +04:00
fix - > accel = FB_ACCEL_SIS_GLAMOUR_2 ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
/* ---------------- fb_ops structures ----------------- */
static struct fb_ops sisfb_ops = {
2005-09-10 00:04:45 +04:00
. owner = THIS_MODULE ,
. fb_open = sisfb_open ,
. fb_release = sisfb_release ,
. fb_check_var = sisfb_check_var ,
. fb_set_par = sisfb_set_par ,
. fb_setcolreg = sisfb_setcolreg ,
. fb_pan_display = sisfb_pan_display ,
. fb_blank = sisfb_blank ,
. fb_fillrect = fbcon_sis_fillrect ,
. fb_copyarea = fbcon_sis_copyarea ,
. fb_imageblit = cfb_imageblit ,
. fb_sync = fbcon_sis_sync ,
# ifdef SIS_NEW_CONFIG_COMPAT
2006-01-15 00:21:25 +03:00
. fb_compat_ioctl = sisfb_ioctl ,
2005-04-17 02:20:36 +04:00
# endif
2005-09-10 00:04:45 +04:00
. fb_ioctl = sisfb_ioctl
2005-04-17 02:20:36 +04:00
} ;
/* ---------------- Chip generation dependent routines ---------------- */
2012-12-22 01:07:39 +04:00
static struct pci_dev * sisfb_get_northbridge ( int basechipid )
2005-04-17 02:20:36 +04:00
{
struct pci_dev * pdev = NULL ;
int nbridgenum , nbridgeidx , i ;
2005-09-10 00:04:45 +04:00
static const unsigned short nbridgeids [ ] = {
2005-04-17 02:20:36 +04:00
PCI_DEVICE_ID_SI_540 , /* for SiS 540 VGA */
PCI_DEVICE_ID_SI_630 , /* for SiS 630/730 VGA */
PCI_DEVICE_ID_SI_730 ,
PCI_DEVICE_ID_SI_550 , /* for SiS 550 VGA */
PCI_DEVICE_ID_SI_650 , /* for SiS 650/651/740 VGA */
PCI_DEVICE_ID_SI_651 ,
PCI_DEVICE_ID_SI_740 ,
2005-09-10 00:04:45 +04:00
PCI_DEVICE_ID_SI_661 , /* for SiS 661/741/660/760/761 VGA */
2005-04-17 02:20:36 +04:00
PCI_DEVICE_ID_SI_741 ,
PCI_DEVICE_ID_SI_660 ,
2005-09-10 00:04:45 +04:00
PCI_DEVICE_ID_SI_760 ,
PCI_DEVICE_ID_SI_761
2005-04-17 02:20:36 +04:00
} ;
2005-09-10 00:04:45 +04:00
switch ( basechipid ) {
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_FB_SIS_300
case SIS_540 : nbridgeidx = 0 ; nbridgenum = 1 ; break ;
case SIS_630 : nbridgeidx = 1 ; nbridgenum = 2 ; break ;
# endif
# ifdef CONFIG_FB_SIS_315
case SIS_550 : nbridgeidx = 3 ; nbridgenum = 1 ; break ;
case SIS_650 : nbridgeidx = 4 ; nbridgenum = 3 ; break ;
2005-09-10 00:04:45 +04:00
case SIS_660 : nbridgeidx = 7 ; nbridgenum = 5 ; break ;
2005-04-17 02:20:36 +04:00
# endif
default : return NULL ;
}
for ( i = 0 ; i < nbridgenum ; i + + ) {
2007-05-08 11:39:50 +04:00
if ( ( pdev = pci_get_device ( PCI_VENDOR_ID_SI ,
2005-09-10 00:04:45 +04:00
nbridgeids [ nbridgeidx + i ] , NULL ) ) )
break ;
2005-04-17 02:20:36 +04:00
}
return pdev ;
}
2012-12-22 01:07:39 +04:00
static int sisfb_get_dram_size ( struct sis_video_info * ivideo )
2005-04-17 02:20:36 +04:00
{
# if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
u8 reg ;
# endif
ivideo - > video_size = 0 ;
2005-09-10 00:04:45 +04:00
ivideo - > UMAsize = ivideo - > LFBsize = 0 ;
2005-04-17 02:20:36 +04:00
switch ( ivideo - > chip ) {
# ifdef CONFIG_FB_SIS_300
case SIS_300 :
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISSR , 0x14 ) ;
2005-04-17 02:20:36 +04:00
ivideo - > video_size = ( ( reg & 0x3F ) + 1 ) < < 20 ;
break ;
case SIS_540 :
case SIS_630 :
case SIS_730 :
2005-09-10 00:04:45 +04:00
if ( ! ivideo - > nbridge )
return - 1 ;
pci_read_config_byte ( ivideo - > nbridge , 0x63 , & reg ) ;
2005-04-17 02:20:36 +04:00
ivideo - > video_size = 1 < < ( ( ( reg & 0x70 ) > > 4 ) + 21 ) ;
break ;
# endif
# ifdef CONFIG_FB_SIS_315
case SIS_315H :
case SIS_315PRO :
case SIS_315 :
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISSR , 0x14 ) ;
2005-04-17 02:20:36 +04:00
ivideo - > video_size = ( 1 < < ( ( reg & 0xf0 ) > > 4 ) ) < < 20 ;
switch ( ( reg > > 2 ) & 0x03 ) {
case 0x01 :
case 0x03 :
2005-09-10 00:04:45 +04:00
ivideo - > video_size < < = 1 ;
break ;
2005-04-17 02:20:36 +04:00
case 0x02 :
2005-09-10 00:04:45 +04:00
ivideo - > video_size + = ( ivideo - > video_size / 2 ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
break ;
2005-04-17 02:20:36 +04:00
case SIS_330 :
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISSR , 0x14 ) ;
2005-04-17 02:20:36 +04:00
ivideo - > video_size = ( 1 < < ( ( reg & 0xf0 ) > > 4 ) ) < < 20 ;
if ( reg & 0x0c ) ivideo - > video_size < < = 1 ;
2005-09-10 00:04:45 +04:00
break ;
2005-04-17 02:20:36 +04:00
case SIS_550 :
case SIS_650 :
case SIS_740 :
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISSR , 0x14 ) ;
2005-04-17 02:20:36 +04:00
ivideo - > video_size = ( ( ( reg & 0x3f ) + 1 ) < < 2 ) < < 20 ;
break ;
case SIS_661 :
case SIS_741 :
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0x79 ) ;
2005-04-17 02:20:36 +04:00
ivideo - > video_size = ( 1 < < ( ( reg & 0xf0 ) > > 4 ) ) < < 20 ;
2005-09-10 00:04:45 +04:00
break ;
2005-04-17 02:20:36 +04:00
case SIS_660 :
case SIS_760 :
2005-09-10 00:04:45 +04:00
case SIS_761 :
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0x79 ) ;
2005-04-17 02:20:36 +04:00
reg = ( reg & 0xf0 ) > > 4 ;
2005-09-10 00:04:45 +04:00
if ( reg ) {
ivideo - > video_size = ( 1 < < reg ) < < 20 ;
ivideo - > UMAsize = ivideo - > video_size ;
}
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0x78 ) ;
2005-04-17 02:20:36 +04:00
reg & = 0x30 ;
if ( reg ) {
2005-09-10 00:04:45 +04:00
if ( reg = = 0x10 ) {
ivideo - > LFBsize = ( 32 < < 20 ) ;
} else {
ivideo - > LFBsize = ( 64 < < 20 ) ;
}
ivideo - > video_size + = ivideo - > LFBsize ;
}
break ;
case SIS_340 :
case XGI_20 :
case XGI_40 :
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISSR , 0x14 ) ;
2005-09-10 00:04:45 +04:00
ivideo - > video_size = ( 1 < < ( ( reg & 0xf0 ) > > 4 ) ) < < 20 ;
if ( ivideo - > chip ! = XGI_20 ) {
reg = ( reg & 0x0c ) > > 2 ;
if ( ivideo - > revision_id = = 2 ) {
if ( reg & 0x01 ) reg = 0x02 ;
else reg = 0x00 ;
}
if ( reg = = 0x02 ) ivideo - > video_size < < = 1 ;
else if ( reg = = 0x03 ) ivideo - > video_size < < = 2 ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
break ;
2005-04-17 02:20:36 +04:00
# endif
default :
return - 1 ;
}
return 0 ;
}
/* -------------- video bridge device detection --------------- */
2012-12-22 01:07:39 +04:00
static void sisfb_detect_VB_connect ( struct sis_video_info * ivideo )
2005-04-17 02:20:36 +04:00
{
u8 cr32 , temp ;
2005-09-10 00:04:45 +04:00
/* No CRT2 on XGI Z7 */
if ( ivideo - > chip = = XGI_20 ) {
ivideo - > sisfb_crt1off = 0 ;
return ;
}
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_FB_SIS_300
if ( ivideo - > sisvga_engine = = SIS_300_VGA ) {
2010-12-21 00:50:16 +03:00
temp = SiS_GetReg ( SISSR , 0x17 ) ;
2005-04-17 02:20:36 +04:00
if ( ( temp & 0x0F ) & & ( ivideo - > chip ! = SIS_300 ) ) {
/* PAL/NTSC is stored on SR16 on such machines */
if ( ! ( ivideo - > vbflags & ( TV_PAL | TV_NTSC | TV_PALM | TV_PALN ) ) ) {
2010-12-21 00:50:16 +03:00
temp = SiS_GetReg ( SISSR , 0x16 ) ;
2005-04-17 02:20:36 +04:00
if ( temp & 0x20 )
ivideo - > vbflags | = TV_PAL ;
else
ivideo - > vbflags | = TV_NTSC ;
}
}
}
# endif
2010-12-21 00:50:16 +03:00
cr32 = SiS_GetReg ( SISCR , 0x32 ) ;
2005-04-17 02:20:36 +04:00
if ( cr32 & SIS_CRT1 ) {
ivideo - > sisfb_crt1off = 0 ;
} else {
ivideo - > sisfb_crt1off = ( cr32 & 0xDF ) ? 1 : 0 ;
}
ivideo - > vbflags & = ~ ( CRT2_TV | CRT2_LCD | CRT2_VGA ) ;
if ( cr32 & SIS_VB_TV ) ivideo - > vbflags | = CRT2_TV ;
if ( cr32 & SIS_VB_LCD ) ivideo - > vbflags | = CRT2_LCD ;
if ( cr32 & SIS_VB_CRT2 ) ivideo - > vbflags | = CRT2_VGA ;
/* Check given parms for hardware compatibility.
* ( Cannot do this in the search_xx routines since we don ' t
* know what hardware we are running on then )
*/
if ( ivideo - > chip ! = SIS_550 ) {
ivideo - > sisfb_dstn = ivideo - > sisfb_fstn = 0 ;
}
if ( ivideo - > sisfb_tvplug ! = - 1 ) {
if ( ( ivideo - > sisvga_engine ! = SIS_315_VGA ) | |
2005-09-10 00:04:45 +04:00
( ! ( ivideo - > vbflags2 & VB2_SISYPBPRBRIDGE ) ) ) {
2005-04-17 02:20:36 +04:00
if ( ivideo - > sisfb_tvplug & TV_YPBPR ) {
2005-09-10 00:04:45 +04:00
ivideo - > sisfb_tvplug = - 1 ;
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " sisfb: YPbPr not supported \n " ) ;
}
}
}
if ( ivideo - > sisfb_tvplug ! = - 1 ) {
if ( ( ivideo - > sisvga_engine ! = SIS_315_VGA ) | |
2005-09-10 00:04:45 +04:00
( ! ( ivideo - > vbflags2 & VB2_SISHIVISIONBRIDGE ) ) ) {
2005-04-17 02:20:36 +04:00
if ( ivideo - > sisfb_tvplug & TV_HIVISION ) {
2005-09-10 00:04:45 +04:00
ivideo - > sisfb_tvplug = - 1 ;
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " sisfb: HiVision not supported \n " ) ;
}
}
}
if ( ivideo - > sisfb_tvstd ! = - 1 ) {
2005-09-10 00:04:45 +04:00
if ( ( ! ( ivideo - > vbflags2 & VB2_SISBRIDGE ) ) & &
( ! ( ( ivideo - > sisvga_engine = = SIS_315_VGA ) & &
( ivideo - > vbflags2 & VB2_CHRONTEL ) ) ) ) {
2009-12-16 03:46:23 +03:00
if ( ivideo - > sisfb_tvstd & ( TV_PALM | TV_PALN | TV_NTSCJ ) ) {
2005-09-10 00:04:45 +04:00
ivideo - > sisfb_tvstd = - 1 ;
printk ( KERN_ERR " sisfb: PALM/PALN/NTSCJ not supported \n " ) ;
2005-04-17 02:20:36 +04:00
}
}
}
/* Detect/set TV plug & type */
if ( ivideo - > sisfb_tvplug ! = - 1 ) {
ivideo - > vbflags | = ivideo - > sisfb_tvplug ;
} else {
if ( cr32 & SIS_VB_YPBPR ) ivideo - > vbflags | = ( TV_YPBPR | TV_YPBPR525I ) ; /* default: 480i */
else if ( cr32 & SIS_VB_HIVISION ) ivideo - > vbflags | = TV_HIVISION ;
else if ( cr32 & SIS_VB_SCART ) ivideo - > vbflags | = TV_SCART ;
2005-09-10 00:04:45 +04:00
else {
2005-04-17 02:20:36 +04:00
if ( cr32 & SIS_VB_SVIDEO ) ivideo - > vbflags | = TV_SVIDEO ;
if ( cr32 & SIS_VB_COMPOSITE ) ivideo - > vbflags | = TV_AVIDEO ;
}
}
if ( ! ( ivideo - > vbflags & ( TV_YPBPR | TV_HIVISION ) ) ) {
if ( ivideo - > sisfb_tvstd ! = - 1 ) {
ivideo - > vbflags & = ~ ( TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ ) ;
ivideo - > vbflags | = ivideo - > sisfb_tvstd ;
}
if ( ivideo - > vbflags & TV_SCART ) {
ivideo - > vbflags & = ~ ( TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ ) ;
ivideo - > vbflags | = TV_PAL ;
}
if ( ! ( ivideo - > vbflags & ( TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ ) ) ) {
if ( ivideo - > sisvga_engine = = SIS_300_VGA ) {
2010-12-21 00:50:16 +03:00
temp = SiS_GetReg ( SISSR , 0x38 ) ;
2005-04-17 02:20:36 +04:00
if ( temp & 0x01 ) ivideo - > vbflags | = TV_PAL ;
else ivideo - > vbflags | = TV_NTSC ;
} else if ( ( ivideo - > chip < = SIS_315PRO ) | | ( ivideo - > chip > = SIS_330 ) ) {
2010-12-21 00:50:16 +03:00
temp = SiS_GetReg ( SISSR , 0x38 ) ;
2005-04-17 02:20:36 +04:00
if ( temp & 0x01 ) ivideo - > vbflags | = TV_PAL ;
else ivideo - > vbflags | = TV_NTSC ;
2005-09-10 00:04:45 +04:00
} else {
2010-12-21 00:50:16 +03:00
temp = SiS_GetReg ( SISCR , 0x79 ) ;
2005-04-17 02:20:36 +04:00
if ( temp & 0x20 ) ivideo - > vbflags | = TV_PAL ;
else ivideo - > vbflags | = TV_NTSC ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
}
}
/* Copy forceCRT1 option to CRT1off if option is given */
2005-09-10 00:04:45 +04:00
if ( ivideo - > sisfb_forcecrt1 ! = - 1 ) {
ivideo - > sisfb_crt1off = ( ivideo - > sisfb_forcecrt1 ) ? 0 : 1 ;
2005-04-17 02:20:36 +04:00
}
}
/* ------------------ Sensing routines ------------------ */
2012-12-22 01:07:39 +04:00
static bool sisfb_test_DDC1 ( struct sis_video_info * ivideo )
2005-04-17 02:20:36 +04:00
{
unsigned short old ;
int count = 48 ;
old = SiS_ReadDDC1Bit ( & ivideo - > SiS_Pr ) ;
do {
2005-09-10 00:04:45 +04:00
if ( old ! = SiS_ReadDDC1Bit ( & ivideo - > SiS_Pr ) ) break ;
2005-04-17 02:20:36 +04:00
} while ( count - - ) ;
2007-02-12 11:55:06 +03:00
return ( count ! = - 1 ) ;
2005-04-17 02:20:36 +04:00
}
2012-12-22 01:07:39 +04:00
static void sisfb_sense_crt1 ( struct sis_video_info * ivideo )
2005-04-17 02:20:36 +04:00
{
2007-02-12 11:55:06 +03:00
bool mustwait = false ;
2005-04-17 02:20:36 +04:00
u8 sr1F , cr17 ;
# ifdef CONFIG_FB_SIS_315
u8 cr63 = 0 ;
# endif
u16 temp = 0xffff ;
int i ;
2010-12-21 00:50:16 +03:00
sr1F = SiS_GetReg ( SISSR , 0x1F ) ;
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISSR , 0x1F , 0x04 ) ;
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISSR , 0x1F , 0x3F ) ;
2007-02-12 11:55:06 +03:00
if ( sr1F & 0xc0 ) mustwait = true ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_FB_SIS_315
if ( ivideo - > sisvga_engine = = SIS_315_VGA ) {
2010-12-21 00:50:16 +03:00
cr63 = SiS_GetReg ( SISCR , ivideo - > SiS_Pr . SiS_MyCR63 ) ;
2005-04-17 02:20:36 +04:00
cr63 & = 0x40 ;
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISCR , ivideo - > SiS_Pr . SiS_MyCR63 , 0xBF ) ;
2005-04-17 02:20:36 +04:00
}
# endif
2010-12-21 00:50:16 +03:00
cr17 = SiS_GetReg ( SISCR , 0x17 ) ;
2005-04-17 02:20:36 +04:00
cr17 & = 0x80 ;
if ( ! cr17 ) {
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISCR , 0x17 , 0x80 ) ;
2007-02-12 11:55:06 +03:00
mustwait = true ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x00 , 0x01 ) ;
SiS_SetReg ( SISSR , 0x00 , 0x03 ) ;
2005-04-17 02:20:36 +04:00
}
if ( mustwait ) {
for ( i = 0 ; i < 10 ; i + + ) sisfbwaitretracecrt1 ( ivideo ) ;
}
# ifdef CONFIG_FB_SIS_315
if ( ivideo - > chip > = SIS_330 ) {
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISCR , 0x32 , ~ 0x20 ) ;
2005-04-17 02:20:36 +04:00
if ( ivideo - > chip > = SIS_340 ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x57 , 0x4a ) ;
2005-04-17 02:20:36 +04:00
} else {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x57 , 0x5f ) ;
2005-04-17 02:20:36 +04:00
}
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISCR , 0x53 , 0x02 ) ;
2010-12-21 00:50:14 +03:00
while ( ( SiS_GetRegByte ( SISINPSTAT ) ) & 0x01 ) break ;
while ( ! ( ( SiS_GetRegByte ( SISINPSTAT ) ) & 0x01 ) ) break ;
if ( ( SiS_GetRegByte ( SISMISCW ) ) & 0x10 ) temp = 1 ;
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISCR , 0x53 , 0xfd ) ;
SiS_SetRegAND ( SISCR , 0x57 , 0x00 ) ;
2005-04-17 02:20:36 +04:00
}
# endif
if ( temp = = 0xffff ) {
i = 3 ;
do {
2005-09-10 00:04:45 +04:00
temp = SiS_HandleDDC ( & ivideo - > SiS_Pr , ivideo - > vbflags ,
ivideo - > sisvga_engine , 0 , 0 , NULL , ivideo - > vbflags2 ) ;
2005-04-17 02:20:36 +04:00
} while ( ( ( temp = = 0 ) | | ( temp = = 0xffff ) ) & & i - - ) ;
if ( ( temp = = 0 ) | | ( temp = = 0xffff ) ) {
if ( sisfb_test_DDC1 ( ivideo ) ) temp = 1 ;
}
}
if ( ( temp ) & & ( temp ! = 0xffff ) ) {
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISCR , 0x32 , 0x20 ) ;
2005-04-17 02:20:36 +04:00
}
# ifdef CONFIG_FB_SIS_315
if ( ivideo - > sisvga_engine = = SIS_315_VGA ) {
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISCR , ivideo - > SiS_Pr . SiS_MyCR63 , 0xBF , cr63 ) ;
2005-04-17 02:20:36 +04:00
}
# endif
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISCR , 0x17 , 0x7F , cr17 ) ;
2005-04-17 02:20:36 +04:00
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x1F , sr1F ) ;
2005-04-17 02:20:36 +04:00
}
/* Determine and detect attached devices on SiS30x */
2012-12-22 01:07:39 +04:00
static void SiS_SenseLCD ( struct sis_video_info * ivideo )
2005-09-10 00:04:45 +04:00
{
unsigned char buffer [ 256 ] ;
unsigned short temp , realcrtno , i ;
u8 reg , cr37 = 0 , paneltype = 0 ;
u16 xres , yres ;
2007-02-12 11:55:06 +03:00
ivideo - > SiS_Pr . PanelSelfDetected = false ;
2005-09-10 00:04:45 +04:00
/* LCD detection only for TMDS bridges */
if ( ! ( ivideo - > vbflags2 & VB2_SISTMDSBRIDGE ) )
return ;
if ( ivideo - > vbflags2 & VB2_30xBDH )
return ;
/* If LCD already set up by BIOS, skip it */
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0x32 ) ;
2005-09-10 00:04:45 +04:00
if ( reg & 0x08 )
return ;
realcrtno = 1 ;
if ( ivideo - > SiS_Pr . DDCPortMixup )
realcrtno = 0 ;
/* Check DDC capabilities */
temp = SiS_HandleDDC ( & ivideo - > SiS_Pr , ivideo - > vbflags , ivideo - > sisvga_engine ,
realcrtno , 0 , & buffer [ 0 ] , ivideo - > vbflags2 ) ;
if ( ( ! temp ) | | ( temp = = 0xffff ) | | ( ! ( temp & 0x02 ) ) )
return ;
/* Read DDC data */
i = 3 ; /* Number of retrys */
do {
temp = SiS_HandleDDC ( & ivideo - > SiS_Pr , ivideo - > vbflags ,
ivideo - > sisvga_engine , realcrtno , 1 ,
& buffer [ 0 ] , ivideo - > vbflags2 ) ;
} while ( ( temp ) & & i - - ) ;
if ( temp )
return ;
/* No digital device */
if ( ! ( buffer [ 0x14 ] & 0x80 ) )
return ;
/* First detailed timing preferred timing? */
if ( ! ( buffer [ 0x18 ] & 0x02 ) )
return ;
xres = buffer [ 0x38 ] | ( ( buffer [ 0x3a ] & 0xf0 ) < < 4 ) ;
yres = buffer [ 0x3b ] | ( ( buffer [ 0x3d ] & 0xf0 ) < < 4 ) ;
switch ( xres ) {
case 1024 :
if ( yres = = 768 )
paneltype = 0x02 ;
break ;
case 1280 :
if ( yres = = 1024 )
paneltype = 0x03 ;
break ;
case 1600 :
if ( ( yres = = 1200 ) & & ( ivideo - > vbflags2 & VB2_30xC ) )
paneltype = 0x0b ;
break ;
}
if ( ! paneltype )
return ;
if ( buffer [ 0x23 ] )
cr37 | = 0x10 ;
if ( ( buffer [ 0x47 ] & 0x18 ) = = 0x18 )
cr37 | = ( ( ( ( buffer [ 0x47 ] & 0x06 ) ^ 0x06 ) < < 5 ) | 0x20 ) ;
else
cr37 | = 0xc0 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x36 , paneltype ) ;
2005-09-10 00:04:45 +04:00
cr37 & = 0xf1 ;
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISCR , 0x37 , 0x0c , cr37 ) ;
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISCR , 0x32 , 0x08 ) ;
2005-09-10 00:04:45 +04:00
2007-02-12 11:55:06 +03:00
ivideo - > SiS_Pr . PanelSelfDetected = true ;
2005-09-10 00:04:45 +04:00
}
2012-12-22 01:07:39 +04:00
static int SISDoSense ( struct sis_video_info * ivideo , u16 type , u16 test )
2005-04-17 02:20:36 +04:00
{
int temp , mytest , result , i , j ;
for ( j = 0 ; j < 10 ; j + + ) {
result = 0 ;
for ( i = 0 ; i < 3 ; i + + ) {
mytest = test ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART4 , 0x11 , ( type & 0x00ff ) ) ;
2005-04-17 02:20:36 +04:00
temp = ( type > > 8 ) | ( mytest & 0x00ff ) ;
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISPART4 , 0x10 , 0xe0 , temp ) ;
2005-04-17 02:20:36 +04:00
SiS_DDC2Delay ( & ivideo - > SiS_Pr , 0x1500 ) ;
mytest > > = 8 ;
mytest & = 0x7f ;
2010-12-21 00:50:16 +03:00
temp = SiS_GetReg ( SISPART4 , 0x03 ) ;
2005-04-17 02:20:36 +04:00
temp ^ = 0x0e ;
temp & = mytest ;
if ( temp = = mytest ) result + + ;
# if 1
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART4 , 0x11 , 0x00 ) ;
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISPART4 , 0x10 , 0xe0 ) ;
2005-04-17 02:20:36 +04:00
SiS_DDC2Delay ( & ivideo - > SiS_Pr , 0x1000 ) ;
# endif
}
if ( ( result = = 0 ) | | ( result > = 2 ) ) break ;
}
2005-09-10 00:04:45 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
2012-12-22 01:07:39 +04:00
static void SiS_Sense30x ( struct sis_video_info * ivideo )
2005-04-17 02:20:36 +04:00
{
u8 backupP4_0d , backupP2_00 , backupP2_4d , backupSR_1e , biosflag = 0 ;
u16 svhs = 0 , svhs_c = 0 ;
u16 cvbs = 0 , cvbs_c = 0 ;
u16 vga2 = 0 , vga2_c = 0 ;
int myflag , result ;
char stdstr [ ] = " sisfb: Detected " ;
char tvstr [ ] = " TV connected to " ;
2005-09-10 00:04:45 +04:00
if ( ivideo - > vbflags2 & VB2_301 ) {
2005-04-17 02:20:36 +04:00
svhs = 0x00b9 ; cvbs = 0x00b3 ; vga2 = 0x00d1 ;
2010-12-21 00:50:16 +03:00
myflag = SiS_GetReg ( SISPART4 , 0x01 ) ;
2005-04-17 02:20:36 +04:00
if ( myflag & 0x04 ) {
svhs = 0x00dd ; cvbs = 0x00ee ; vga2 = 0x00fd ;
}
2005-09-10 00:04:45 +04:00
} else if ( ivideo - > vbflags2 & ( VB2_301B | VB2_302B ) ) {
2005-04-17 02:20:36 +04:00
svhs = 0x016b ; cvbs = 0x0174 ; vga2 = 0x0190 ;
2005-09-10 00:04:45 +04:00
} else if ( ivideo - > vbflags2 & ( VB2_301LV | VB2_302LV ) ) {
2005-04-17 02:20:36 +04:00
svhs = 0x0200 ; cvbs = 0x0100 ;
2005-09-10 00:04:45 +04:00
} else if ( ivideo - > vbflags2 & ( VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV ) ) {
2005-04-17 02:20:36 +04:00
svhs = 0x016b ; cvbs = 0x0110 ; vga2 = 0x0190 ;
2005-09-10 00:04:45 +04:00
} else
return ;
2005-04-17 02:20:36 +04:00
vga2_c = 0x0e08 ; svhs_c = 0x0404 ; cvbs_c = 0x0804 ;
2005-09-10 00:04:45 +04:00
if ( ivideo - > vbflags & ( VB2_301LV | VB2_302LV | VB2_302ELV | VB2_307LV ) ) {
2005-04-17 02:20:36 +04:00
svhs_c = 0x0408 ; cvbs_c = 0x0808 ;
}
2005-09-10 00:04:45 +04:00
2005-04-17 02:20:36 +04:00
biosflag = 2 ;
2005-09-10 00:04:45 +04:00
if ( ivideo - > haveXGIROM ) {
biosflag = ivideo - > bios_abase [ 0x58 ] & 0x03 ;
} else if ( ivideo - > newrom ) {
if ( ivideo - > bios_abase [ 0x5d ] & 0x04 ) biosflag | = 0x01 ;
} else if ( ivideo - > sisvga_engine = = SIS_300_VGA ) {
if ( ivideo - > bios_abase ) {
biosflag = ivideo - > bios_abase [ 0xfe ] & 0x03 ;
}
}
2005-04-17 02:20:36 +04:00
if ( ivideo - > chip = = SIS_300 ) {
2010-12-21 00:50:16 +03:00
myflag = SiS_GetReg ( SISSR , 0x3b ) ;
2005-04-17 02:20:36 +04:00
if ( ! ( myflag & 0x01 ) ) vga2 = vga2_c = 0 ;
}
2005-09-10 00:04:45 +04:00
if ( ! ( ivideo - > vbflags2 & VB2_SISVGA2BRIDGE ) ) {
vga2 = vga2_c = 0 ;
}
2010-12-21 00:50:16 +03:00
backupSR_1e = SiS_GetReg ( SISSR , 0x1e ) ;
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISSR , 0x1e , 0x20 ) ;
2005-04-17 02:20:36 +04:00
2010-12-21 00:50:16 +03:00
backupP4_0d = SiS_GetReg ( SISPART4 , 0x0d ) ;
2005-09-10 00:04:45 +04:00
if ( ivideo - > vbflags2 & VB2_30xC ) {
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISPART4 , 0x0d , ~ 0x07 , 0x01 ) ;
2005-04-17 02:20:36 +04:00
} else {
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISPART4 , 0x0d , 0x04 ) ;
2005-04-17 02:20:36 +04:00
}
SiS_DDC2Delay ( & ivideo - > SiS_Pr , 0x2000 ) ;
2010-12-21 00:50:16 +03:00
backupP2_00 = SiS_GetReg ( SISPART2 , 0x00 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART2 , 0x00 , ( ( backupP2_00 | 0x1c ) & 0xfc ) ) ;
2005-04-17 02:20:36 +04:00
2010-12-21 00:50:16 +03:00
backupP2_4d = SiS_GetReg ( SISPART2 , 0x4d ) ;
2005-09-10 00:04:45 +04:00
if ( ivideo - > vbflags2 & VB2_SISYPBPRBRIDGE ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART2 , 0x4d , ( backupP2_4d & ~ 0x10 ) ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
if ( ! ( ivideo - > vbflags2 & VB2_30xCLV ) ) {
2005-04-17 02:20:36 +04:00
SISDoSense ( ivideo , 0 , 0 ) ;
}
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISCR , 0x32 , ~ 0x14 ) ;
2005-04-17 02:20:36 +04:00
if ( vga2_c | | vga2 ) {
if ( SISDoSense ( ivideo , vga2 , vga2_c ) ) {
if ( biosflag & 0x01 ) {
printk ( KERN_INFO " %s %s SCART output \n " , stdstr , tvstr ) ;
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISCR , 0x32 , 0x04 ) ;
2005-04-17 02:20:36 +04:00
} else {
printk ( KERN_INFO " %s secondary VGA connection \n " , stdstr ) ;
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISCR , 0x32 , 0x10 ) ;
2005-04-17 02:20:36 +04:00
}
}
}
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISCR , 0x32 , 0x3f ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ivideo - > vbflags2 & VB2_30xCLV ) {
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISPART4 , 0x0d , 0x04 ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
if ( ( ivideo - > sisvga_engine = = SIS_315_VGA ) & & ( ivideo - > vbflags2 & VB2_SISYPBPRBRIDGE ) ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART2 , 0x4d , ( backupP2_4d | 0x10 ) ) ;
2005-04-17 02:20:36 +04:00
SiS_DDC2Delay ( & ivideo - > SiS_Pr , 0x2000 ) ;
if ( ( result = SISDoSense ( ivideo , svhs , 0x0604 ) ) ) {
if ( ( result = SISDoSense ( ivideo , cvbs , 0x0804 ) ) ) {
printk ( KERN_INFO " %s %s YPbPr component output \n " , stdstr , tvstr ) ;
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISCR , 0x32 , 0x80 ) ;
2005-04-17 02:20:36 +04:00
}
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART2 , 0x4d , backupP2_4d ) ;
2005-04-17 02:20:36 +04:00
}
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISCR , 0x32 , ~ 0x03 ) ;
2005-04-17 02:20:36 +04:00
if ( ! ( ivideo - > vbflags & TV_YPBPR ) ) {
if ( ( result = SISDoSense ( ivideo , svhs , svhs_c ) ) ) {
printk ( KERN_INFO " %s %s SVIDEO output \n " , stdstr , tvstr ) ;
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISCR , 0x32 , 0x02 ) ;
2005-04-17 02:20:36 +04:00
}
if ( ( biosflag & 0x02 ) | | ( ! result ) ) {
if ( SISDoSense ( ivideo , cvbs , cvbs_c ) ) {
printk ( KERN_INFO " %s %s COMPOSITE output \n " , stdstr , tvstr ) ;
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISCR , 0x32 , 0x01 ) ;
2005-04-17 02:20:36 +04:00
}
}
}
SISDoSense ( ivideo , 0 , 0 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART2 , 0x00 , backupP2_00 ) ;
SiS_SetReg ( SISPART4 , 0x0d , backupP4_0d ) ;
SiS_SetReg ( SISSR , 0x1e , backupSR_1e ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ivideo - > vbflags2 & VB2_30xCLV ) {
2010-12-21 00:50:16 +03:00
biosflag = SiS_GetReg ( SISPART2 , 0x00 ) ;
2005-04-17 02:20:36 +04:00
if ( biosflag & 0x20 ) {
for ( myflag = 2 ; myflag > 0 ; myflag - - ) {
biosflag ^ = 0x20 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART2 , 0x00 , biosflag ) ;
2005-04-17 02:20:36 +04:00
}
}
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART2 , 0x00 , backupP2_00 ) ;
2005-04-17 02:20:36 +04:00
}
/* Determine and detect attached TV's on Chrontel */
2012-12-22 01:07:39 +04:00
static void SiS_SenseCh ( struct sis_video_info * ivideo )
2005-04-17 02:20:36 +04:00
{
# if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
u8 temp1 , temp2 ;
char stdstr [ ] = " sisfb: Chrontel: Detected TV connected to " ;
# endif
# ifdef CONFIG_FB_SIS_300
unsigned char test [ 3 ] ;
int i ;
# endif
if ( ivideo - > chip < SIS_315H ) {
# ifdef CONFIG_FB_SIS_300
ivideo - > SiS_Pr . SiS_IF_DEF_CH70xx = 1 ; /* Chrontel 700x */
SiS_SetChrontelGPIO ( & ivideo - > SiS_Pr , 0x9c ) ; /* Set general purpose IO for Chrontel communication */
SiS_DDC2Delay ( & ivideo - > SiS_Pr , 1000 ) ;
temp1 = SiS_GetCH700x ( & ivideo - > SiS_Pr , 0x25 ) ;
/* See Chrontel TB31 for explanation */
temp2 = SiS_GetCH700x ( & ivideo - > SiS_Pr , 0x0e ) ;
if ( ( ( temp2 & 0x07 ) = = 0x01 ) | | ( temp2 & 0x04 ) ) {
2005-09-10 00:04:45 +04:00
SiS_SetCH700x ( & ivideo - > SiS_Pr , 0x0e , 0x0b ) ;
2005-04-17 02:20:36 +04:00
SiS_DDC2Delay ( & ivideo - > SiS_Pr , 300 ) ;
}
temp2 = SiS_GetCH700x ( & ivideo - > SiS_Pr , 0x25 ) ;
if ( temp2 ! = temp1 ) temp1 = temp2 ;
if ( ( temp1 > = 0x22 ) & & ( temp1 < = 0x50 ) ) {
/* Read power status */
temp1 = SiS_GetCH700x ( & ivideo - > SiS_Pr , 0x0e ) ;
if ( ( temp1 & 0x03 ) ! = 0x03 ) {
2005-09-10 00:04:45 +04:00
/* Power all outputs */
SiS_SetCH700x ( & ivideo - > SiS_Pr , 0x0e , 0x0b ) ;
2005-04-17 02:20:36 +04:00
SiS_DDC2Delay ( & ivideo - > SiS_Pr , 300 ) ;
}
/* Sense connected TV devices */
for ( i = 0 ; i < 3 ; i + + ) {
2005-09-10 00:04:45 +04:00
SiS_SetCH700x ( & ivideo - > SiS_Pr , 0x10 , 0x01 ) ;
2005-04-17 02:20:36 +04:00
SiS_DDC2Delay ( & ivideo - > SiS_Pr , 0x96 ) ;
2005-09-10 00:04:45 +04:00
SiS_SetCH700x ( & ivideo - > SiS_Pr , 0x10 , 0x00 ) ;
2005-04-17 02:20:36 +04:00
SiS_DDC2Delay ( & ivideo - > SiS_Pr , 0x96 ) ;
temp1 = SiS_GetCH700x ( & ivideo - > SiS_Pr , 0x10 ) ;
if ( ! ( temp1 & 0x08 ) ) test [ i ] = 0x02 ;
else if ( ! ( temp1 & 0x02 ) ) test [ i ] = 0x01 ;
else test [ i ] = 0 ;
SiS_DDC2Delay ( & ivideo - > SiS_Pr , 0x96 ) ;
}
if ( test [ 0 ] = = test [ 1 ] ) temp1 = test [ 0 ] ;
else if ( test [ 0 ] = = test [ 2 ] ) temp1 = test [ 0 ] ;
else if ( test [ 1 ] = = test [ 2 ] ) temp1 = test [ 1 ] ;
else {
2005-09-10 00:04:45 +04:00
printk ( KERN_INFO
2005-04-17 02:20:36 +04:00
" sisfb: TV detection unreliable - test results varied \n " ) ;
temp1 = test [ 2 ] ;
}
if ( temp1 = = 0x02 ) {
printk ( KERN_INFO " %s SVIDEO output \n " , stdstr ) ;
ivideo - > vbflags | = TV_SVIDEO ;
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISCR , 0x32 , 0x02 ) ;
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISCR , 0x32 , ~ 0x05 ) ;
2005-04-17 02:20:36 +04:00
} else if ( temp1 = = 0x01 ) {
printk ( KERN_INFO " %s CVBS output \n " , stdstr ) ;
ivideo - > vbflags | = TV_AVIDEO ;
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISCR , 0x32 , 0x01 ) ;
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISCR , 0x32 , ~ 0x06 ) ;
2005-04-17 02:20:36 +04:00
} else {
2005-09-10 00:04:45 +04:00
SiS_SetCH70xxANDOR ( & ivideo - > SiS_Pr , 0x0e , 0x01 , 0xF8 ) ;
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISCR , 0x32 , ~ 0x07 ) ;
2005-04-17 02:20:36 +04:00
}
} else if ( temp1 = = 0 ) {
2005-09-10 00:04:45 +04:00
SiS_SetCH70xxANDOR ( & ivideo - > SiS_Pr , 0x0e , 0x01 , 0xF8 ) ;
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISCR , 0x32 , ~ 0x07 ) ;
2005-04-17 02:20:36 +04:00
}
/* Set general purpose IO for Chrontel communication */
SiS_SetChrontelGPIO ( & ivideo - > SiS_Pr , 0x00 ) ;
# endif
} else {
# ifdef CONFIG_FB_SIS_315
ivideo - > SiS_Pr . SiS_IF_DEF_CH70xx = 2 ; /* Chrontel 7019 */
2005-09-10 00:04:45 +04:00
temp1 = SiS_GetCH701x ( & ivideo - > SiS_Pr , 0x49 ) ;
SiS_SetCH701x ( & ivideo - > SiS_Pr , 0x49 , 0x20 ) ;
2005-04-17 02:20:36 +04:00
SiS_DDC2Delay ( & ivideo - > SiS_Pr , 0x96 ) ;
temp2 = SiS_GetCH701x ( & ivideo - > SiS_Pr , 0x20 ) ;
temp2 | = 0x01 ;
2005-09-10 00:04:45 +04:00
SiS_SetCH701x ( & ivideo - > SiS_Pr , 0x20 , temp2 ) ;
2005-04-17 02:20:36 +04:00
SiS_DDC2Delay ( & ivideo - > SiS_Pr , 0x96 ) ;
temp2 ^ = 0x01 ;
2005-09-10 00:04:45 +04:00
SiS_SetCH701x ( & ivideo - > SiS_Pr , 0x20 , temp2 ) ;
2005-04-17 02:20:36 +04:00
SiS_DDC2Delay ( & ivideo - > SiS_Pr , 0x96 ) ;
temp2 = SiS_GetCH701x ( & ivideo - > SiS_Pr , 0x20 ) ;
2005-09-10 00:04:45 +04:00
SiS_SetCH701x ( & ivideo - > SiS_Pr , 0x49 , temp1 ) ;
temp1 = 0 ;
2005-04-17 02:20:36 +04:00
if ( temp2 & 0x02 ) temp1 | = 0x01 ;
if ( temp2 & 0x10 ) temp1 | = 0x01 ;
if ( temp2 & 0x04 ) temp1 | = 0x02 ;
if ( ( temp1 & 0x01 ) & & ( temp1 & 0x02 ) ) temp1 = 0x04 ;
switch ( temp1 ) {
case 0x01 :
printk ( KERN_INFO " %s CVBS output \n " , stdstr ) ;
ivideo - > vbflags | = TV_AVIDEO ;
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISCR , 0x32 , 0x01 ) ;
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISCR , 0x32 , ~ 0x06 ) ;
2005-09-10 00:04:45 +04:00
break ;
2005-04-17 02:20:36 +04:00
case 0x02 :
printk ( KERN_INFO " %s SVIDEO output \n " , stdstr ) ;
ivideo - > vbflags | = TV_SVIDEO ;
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISCR , 0x32 , 0x02 ) ;
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISCR , 0x32 , ~ 0x05 ) ;
2005-09-10 00:04:45 +04:00
break ;
2005-04-17 02:20:36 +04:00
case 0x04 :
printk ( KERN_INFO " %s SCART output \n " , stdstr ) ;
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISCR , 0x32 , 0x04 ) ;
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISCR , 0x32 , ~ 0x03 ) ;
2005-09-10 00:04:45 +04:00
break ;
2005-04-17 02:20:36 +04:00
default :
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISCR , 0x32 , ~ 0x07 ) ;
2005-04-17 02:20:36 +04:00
}
# endif
}
}
2012-12-22 01:07:39 +04:00
static void sisfb_get_VB_type ( struct sis_video_info * ivideo )
2005-04-17 02:20:36 +04:00
{
2005-09-10 00:04:45 +04:00
char stdstr [ ] = " sisfb: Detected " ;
char bridgestr [ ] = " video bridge " ;
u8 vb_chipid ;
u8 reg ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* No CRT2 on XGI Z7 */
if ( ivideo - > chip = = XGI_20 )
return ;
2005-04-17 02:20:36 +04:00
2010-12-21 00:50:16 +03:00
vb_chipid = SiS_GetReg ( SISPART4 , 0x00 ) ;
2005-09-10 00:04:45 +04:00
switch ( vb_chipid ) {
case 0x01 :
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISPART4 , 0x01 ) ;
2005-09-10 00:04:45 +04:00
if ( reg < 0xb0 ) {
ivideo - > vbflags | = VB_301 ; /* Deprecated */
ivideo - > vbflags2 | = VB2_301 ;
printk ( KERN_INFO " %s SiS301 %s \n " , stdstr , bridgestr ) ;
} else if ( reg < 0xc0 ) {
ivideo - > vbflags | = VB_301B ; /* Deprecated */
ivideo - > vbflags2 | = VB2_301B ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISPART4 , 0x23 ) ;
2005-09-10 00:04:45 +04:00
if ( ! ( reg & 0x02 ) ) {
ivideo - > vbflags | = VB_30xBDH ; /* Deprecated */
ivideo - > vbflags2 | = VB2_30xBDH ;
printk ( KERN_INFO " %s SiS301B-DH %s \n " , stdstr , bridgestr ) ;
} else {
printk ( KERN_INFO " %s SiS301B %s \n " , stdstr , bridgestr ) ;
}
} else if ( reg < 0xd0 ) {
ivideo - > vbflags | = VB_301C ; /* Deprecated */
ivideo - > vbflags2 | = VB2_301C ;
printk ( KERN_INFO " %s SiS301C %s \n " , stdstr , bridgestr ) ;
} else if ( reg < 0xe0 ) {
ivideo - > vbflags | = VB_301LV ; /* Deprecated */
ivideo - > vbflags2 | = VB2_301LV ;
printk ( KERN_INFO " %s SiS301LV %s \n " , stdstr , bridgestr ) ;
} else if ( reg < = 0xe1 ) {
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISPART4 , 0x39 ) ;
2005-09-10 00:04:45 +04:00
if ( reg = = 0xff ) {
ivideo - > vbflags | = VB_302LV ; /* Deprecated */
ivideo - > vbflags2 | = VB2_302LV ;
printk ( KERN_INFO " %s SiS302LV %s \n " , stdstr , bridgestr ) ;
} else {
ivideo - > vbflags | = VB_301C ; /* Deprecated */
ivideo - > vbflags2 | = VB2_301C ;
printk ( KERN_INFO " %s SiS301C(P4) %s \n " , stdstr , bridgestr ) ;
#if 0
ivideo - > vbflags | = VB_302ELV ; /* Deprecated */
ivideo - > vbflags2 | = VB2_302ELV ;
printk ( KERN_INFO " %s SiS302ELV %s \n " , stdstr , bridgestr ) ;
# endif
}
}
break ;
case 0x02 :
ivideo - > vbflags | = VB_302B ; /* Deprecated */
ivideo - > vbflags2 | = VB2_302B ;
printk ( KERN_INFO " %s SiS302B %s \n " , stdstr , bridgestr ) ;
break ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
if ( ( ! ( ivideo - > vbflags2 & VB2_VIDEOBRIDGE ) ) & & ( ivideo - > chip ! = SIS_300 ) ) {
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0x37 ) ;
2005-09-10 00:04:45 +04:00
reg & = SIS_EXTERNAL_CHIP_MASK ;
reg > > = 1 ;
if ( ivideo - > sisvga_engine = = SIS_300_VGA ) {
# ifdef CONFIG_FB_SIS_300
switch ( reg ) {
case SIS_EXTERNAL_CHIP_LVDS :
ivideo - > vbflags | = VB_LVDS ; /* Deprecated */
ivideo - > vbflags2 | = VB2_LVDS ;
break ;
case SIS_EXTERNAL_CHIP_TRUMPION :
ivideo - > vbflags | = ( VB_LVDS | VB_TRUMPION ) ; /* Deprecated */
ivideo - > vbflags2 | = ( VB2_LVDS | VB2_TRUMPION ) ;
break ;
case SIS_EXTERNAL_CHIP_CHRONTEL :
ivideo - > vbflags | = VB_CHRONTEL ; /* Deprecated */
ivideo - > vbflags2 | = VB2_CHRONTEL ;
break ;
case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL :
ivideo - > vbflags | = ( VB_LVDS | VB_CHRONTEL ) ; /* Deprecated */
ivideo - > vbflags2 | = ( VB2_LVDS | VB2_CHRONTEL ) ;
break ;
}
if ( ivideo - > vbflags2 & VB2_CHRONTEL ) ivideo - > chronteltype = 1 ;
# endif
} else if ( ivideo - > chip < SIS_661 ) {
# ifdef CONFIG_FB_SIS_315
switch ( reg ) {
case SIS310_EXTERNAL_CHIP_LVDS :
ivideo - > vbflags | = VB_LVDS ; /* Deprecated */
ivideo - > vbflags2 | = VB2_LVDS ;
break ;
case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL :
ivideo - > vbflags | = ( VB_LVDS | VB_CHRONTEL ) ; /* Deprecated */
ivideo - > vbflags2 | = ( VB2_LVDS | VB2_CHRONTEL ) ;
break ;
}
if ( ivideo - > vbflags2 & VB2_CHRONTEL ) ivideo - > chronteltype = 2 ;
# endif
} else if ( ivideo - > chip > = SIS_661 ) {
# ifdef CONFIG_FB_SIS_315
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0x38 ) ;
2005-09-10 00:04:45 +04:00
reg > > = 5 ;
switch ( reg ) {
case 0x02 :
ivideo - > vbflags | = VB_LVDS ; /* Deprecated */
ivideo - > vbflags2 | = VB2_LVDS ;
break ;
case 0x03 :
ivideo - > vbflags | = ( VB_LVDS | VB_CHRONTEL ) ; /* Deprecated */
ivideo - > vbflags2 | = ( VB2_LVDS | VB2_CHRONTEL ) ;
break ;
case 0x04 :
ivideo - > vbflags | = ( VB_LVDS | VB_CONEXANT ) ; /* Deprecated */
ivideo - > vbflags2 | = ( VB2_LVDS | VB2_CONEXANT ) ;
break ;
}
if ( ivideo - > vbflags2 & VB2_CHRONTEL ) ivideo - > chronteltype = 2 ;
# endif
}
if ( ivideo - > vbflags2 & VB2_LVDS ) {
printk ( KERN_INFO " %s LVDS transmitter \n " , stdstr ) ;
}
if ( ( ivideo - > sisvga_engine = = SIS_300_VGA ) & & ( ivideo - > vbflags2 & VB2_TRUMPION ) ) {
printk ( KERN_INFO " %s Trumpion Zurac LCD scaler \n " , stdstr ) ;
}
if ( ivideo - > vbflags2 & VB2_CHRONTEL ) {
printk ( KERN_INFO " %s Chrontel TV encoder \n " , stdstr ) ;
}
if ( ( ivideo - > chip > = SIS_661 ) & & ( ivideo - > vbflags2 & VB2_CONEXANT ) ) {
printk ( KERN_INFO " %s Conexant external device \n " , stdstr ) ;
}
}
if ( ivideo - > vbflags2 & VB2_SISBRIDGE ) {
SiS_SenseLCD ( ivideo ) ;
SiS_Sense30x ( ivideo ) ;
} else if ( ivideo - > vbflags2 & VB2_CHRONTEL ) {
SiS_SenseCh ( ivideo ) ;
}
}
/* ---------- Engine initialization routines ------------ */
static void
sisfb_engine_init ( struct sis_video_info * ivideo )
2005-04-17 02:20:36 +04:00
{
2005-09-10 00:04:45 +04:00
/* Initialize command queue (we use MMIO only) */
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
ivideo - > caps & = ~ ( TURBO_QUEUE_CAP |
MMIO_CMD_QUEUE_CAP |
VM_CMD_QUEUE_CAP |
AGP_CMD_QUEUE_CAP ) ;
# ifdef CONFIG_FB_SIS_300
if ( ivideo - > sisvga_engine = = SIS_300_VGA ) {
u32 tqueue_pos ;
u8 tq_state ;
tqueue_pos = ( ivideo - > video_size - ivideo - > cmdQueueSize ) / ( 64 * 1024 ) ;
2010-12-21 00:50:16 +03:00
tq_state = SiS_GetReg ( SISSR , IND_SIS_TURBOQUEUE_SET ) ;
2005-09-10 00:04:45 +04:00
tq_state | = 0xf0 ;
tq_state & = 0xfc ;
tq_state | = ( u8 ) ( tqueue_pos > > 8 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , IND_SIS_TURBOQUEUE_SET , tq_state ) ;
2005-09-10 00:04:45 +04:00
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , IND_SIS_TURBOQUEUE_ADR , ( u8 ) ( tqueue_pos & 0xff ) ) ;
2005-09-10 00:04:45 +04:00
ivideo - > caps | = TURBO_QUEUE_CAP ;
}
# endif
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_FB_SIS_315
2005-09-10 00:04:45 +04:00
if ( ivideo - > sisvga_engine = = SIS_315_VGA ) {
u32 tempq = 0 , templ ;
u8 temp ;
if ( ivideo - > chip = = XGI_20 ) {
switch ( ivideo - > cmdQueueSize ) {
case ( 64 * 1024 ) :
temp = SIS_CMD_QUEUE_SIZE_Z7_64k ;
break ;
case ( 128 * 1024 ) :
default :
temp = SIS_CMD_QUEUE_SIZE_Z7_128k ;
}
} else {
switch ( ivideo - > cmdQueueSize ) {
case ( 4 * 1024 * 1024 ) :
temp = SIS_CMD_QUEUE_SIZE_4M ;
break ;
case ( 2 * 1024 * 1024 ) :
temp = SIS_CMD_QUEUE_SIZE_2M ;
break ;
case ( 1 * 1024 * 1024 ) :
temp = SIS_CMD_QUEUE_SIZE_1M ;
break ;
default :
case ( 512 * 1024 ) :
temp = SIS_CMD_QUEUE_SIZE_512k ;
}
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , IND_SIS_CMDQUEUE_THRESHOLD , COMMAND_QUEUE_THRESHOLD ) ;
SiS_SetReg ( SISSR , IND_SIS_CMDQUEUE_SET , SIS_CMD_QUEUE_RESET ) ;
2005-09-10 00:04:45 +04:00
if ( ( ivideo - > chip > = XGI_40 ) & & ivideo - > modechanged ) {
/* Must disable dual pipe on XGI_40. Can't do
* this in MMIO mode , because it requires
* setting / clearing a bit in the MMIO fire trigger
* register .
*/
if ( ! ( ( templ = MMIO_IN32 ( ivideo - > mmio_vbase , 0x8240 ) ) & ( 1 < < 10 ) ) ) {
MMIO_OUT32 ( ivideo - > mmio_vbase , Q_WRITE_PTR , 0 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , IND_SIS_CMDQUEUE_SET , ( temp | SIS_VRAM_CMDQUEUE_ENABLE ) ) ;
2005-09-10 00:04:45 +04:00
tempq = MMIO_IN32 ( ivideo - > mmio_vbase , Q_READ_PTR ) ;
MMIO_OUT32 ( ivideo - > mmio_vbase , Q_WRITE_PTR , tempq ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
tempq = ( u32 ) ( ivideo - > video_size - ivideo - > cmdQueueSize ) ;
MMIO_OUT32 ( ivideo - > mmio_vbase , Q_BASE_ADDR , tempq ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
writel ( 0x16800000 + 0x8240 , ivideo - > video_vbase + tempq ) ;
writel ( templ | ( 1 < < 10 ) , ivideo - > video_vbase + tempq + 4 ) ;
writel ( 0x168F0000 , ivideo - > video_vbase + tempq + 8 ) ;
writel ( 0x168F0000 , ivideo - > video_vbase + tempq + 12 ) ;
MMIO_OUT32 ( ivideo - > mmio_vbase , Q_WRITE_PTR , ( tempq + 16 ) ) ;
sisfb_syncaccel ( ivideo ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , IND_SIS_CMDQUEUE_SET , SIS_CMD_QUEUE_RESET ) ;
2005-09-10 00:04:45 +04:00
}
}
tempq = MMIO_IN32 ( ivideo - > mmio_vbase , MMIO_QUEUE_READPORT ) ;
MMIO_OUT32 ( ivideo - > mmio_vbase , MMIO_QUEUE_WRITEPORT , tempq ) ;
temp | = ( SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , IND_SIS_CMDQUEUE_SET , temp ) ;
2005-09-10 00:04:45 +04:00
tempq = ( u32 ) ( ivideo - > video_size - ivideo - > cmdQueueSize ) ;
MMIO_OUT32 ( ivideo - > mmio_vbase , MMIO_QUEUE_PHYBASE , tempq ) ;
ivideo - > caps | = MMIO_CMD_QUEUE_CAP ;
}
# endif
ivideo - > engineok = 1 ;
}
2012-12-22 01:07:39 +04:00
static void sisfb_detect_lcd_type ( struct sis_video_info * ivideo )
2005-09-10 00:04:45 +04:00
{
u8 reg ;
int i ;
2005-04-17 02:20:36 +04:00
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0x36 ) ;
2005-09-10 00:04:45 +04:00
reg & = 0x0f ;
if ( ivideo - > sisvga_engine = = SIS_300_VGA ) {
ivideo - > CRT2LCDType = sis300paneltype [ reg ] ;
} else if ( ivideo - > chip > = SIS_661 ) {
ivideo - > CRT2LCDType = sis661paneltype [ reg ] ;
} else {
ivideo - > CRT2LCDType = sis310paneltype [ reg ] ;
if ( ( ivideo - > chip = = SIS_550 ) & & ( sisfb_fstn ) ) {
if ( ( ivideo - > CRT2LCDType ! = LCD_320x240_2 ) & &
( ivideo - > CRT2LCDType ! = LCD_320x240_3 ) ) {
ivideo - > CRT2LCDType = LCD_320x240 ;
}
}
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ivideo - > CRT2LCDType = = LCD_UNKNOWN ) {
/* For broken BIOSes: Assume 1024x768, RGB18 */
ivideo - > CRT2LCDType = LCD_1024x768 ;
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISCR , 0x36 , 0xf0 , 0x02 ) ;
SiS_SetRegANDOR ( SISCR , 0x37 , 0xee , 0x01 ) ;
2005-09-10 00:04:45 +04:00
printk ( KERN_DEBUG " sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18 \n " , reg ) ;
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
for ( i = 0 ; i < SIS_LCD_NUMBER ; i + + ) {
if ( ivideo - > CRT2LCDType = = sis_lcd_data [ i ] . lcdtype ) {
ivideo - > lcdxres = sis_lcd_data [ i ] . xres ;
ivideo - > lcdyres = sis_lcd_data [ i ] . yres ;
ivideo - > lcddefmodeidx = sis_lcd_data [ i ] . default_mode_idx ;
break ;
}
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
# ifdef CONFIG_FB_SIS_300
if ( ivideo - > SiS_Pr . SiS_CustomT = = CUT_BARCO1366 ) {
ivideo - > lcdxres = 1360 ; ivideo - > lcdyres = 1024 ;
ivideo - > lcddefmodeidx = DEFAULT_MODE_1360 ;
} else if ( ivideo - > SiS_Pr . SiS_CustomT = = CUT_PANEL848 ) {
ivideo - > lcdxres = 848 ; ivideo - > lcdyres = 480 ;
ivideo - > lcddefmodeidx = DEFAULT_MODE_848 ;
} else if ( ivideo - > SiS_Pr . SiS_CustomT = = CUT_PANEL856 ) {
ivideo - > lcdxres = 856 ; ivideo - > lcdyres = 480 ;
ivideo - > lcddefmodeidx = DEFAULT_MODE_856 ;
}
2005-04-17 02:20:36 +04:00
# endif
2005-09-10 00:04:45 +04:00
printk ( KERN_DEBUG " sisfb: Detected %dx%d flat panel \n " ,
ivideo - > lcdxres , ivideo - > lcdyres ) ;
}
2012-12-22 01:07:39 +04:00
static void sisfb_save_pdc_emi ( struct sis_video_info * ivideo )
2005-09-10 00:04:45 +04:00
{
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_FB_SIS_300
2005-09-10 00:04:45 +04:00
/* Save the current PanelDelayCompensation if the LCD is currently used */
if ( ivideo - > sisvga_engine = = SIS_300_VGA ) {
if ( ivideo - > vbflags2 & ( VB2_LVDS | VB2_30xBDH ) ) {
int tmp ;
2010-12-21 00:50:16 +03:00
tmp = SiS_GetReg ( SISCR , 0x30 ) ;
2005-09-10 00:04:45 +04:00
if ( tmp & 0x20 ) {
/* Currently on LCD? If yes, read current pdc */
2010-12-21 00:50:16 +03:00
ivideo - > detectedpdc = SiS_GetReg ( SISPART1 , 0x13 ) ;
2005-09-10 00:04:45 +04:00
ivideo - > detectedpdc & = 0x3c ;
if ( ivideo - > SiS_Pr . PDC = = - 1 ) {
/* Let option override detection */
ivideo - > SiS_Pr . PDC = ivideo - > detectedpdc ;
}
printk ( KERN_INFO " sisfb: Detected LCD PDC 0x%02x \n " ,
ivideo - > detectedpdc ) ;
}
if ( ( ivideo - > SiS_Pr . PDC ! = - 1 ) & &
( ivideo - > SiS_Pr . PDC ! = ivideo - > detectedpdc ) ) {
printk ( KERN_INFO " sisfb: Using LCD PDC 0x%02x \n " ,
ivideo - > SiS_Pr . PDC ) ;
}
}
}
# endif
# ifdef CONFIG_FB_SIS_315
if ( ivideo - > sisvga_engine = = SIS_315_VGA ) {
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* Try to find about LCDA */
if ( ivideo - > vbflags2 & VB2_SISLCDABRIDGE ) {
int tmp ;
2010-12-21 00:50:16 +03:00
tmp = SiS_GetReg ( SISPART1 , 0x13 ) ;
2005-09-10 00:04:45 +04:00
if ( tmp & 0x04 ) {
2007-02-12 11:55:06 +03:00
ivideo - > SiS_Pr . SiS_UseLCDA = true ;
2005-09-10 00:04:45 +04:00
ivideo - > detectedlcda = 0x03 ;
}
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* Save PDC */
if ( ivideo - > vbflags2 & VB2_SISLVDSBRIDGE ) {
int tmp ;
2010-12-21 00:50:16 +03:00
tmp = SiS_GetReg ( SISCR , 0x30 ) ;
2005-09-10 00:04:45 +04:00
if ( ( tmp & 0x20 ) | | ( ivideo - > detectedlcda ! = 0xff ) ) {
/* Currently on LCD? If yes, read current pdc */
u8 pdc ;
2010-12-21 00:50:16 +03:00
pdc = SiS_GetReg ( SISPART1 , 0x2D ) ;
2005-09-10 00:04:45 +04:00
ivideo - > detectedpdc = ( pdc & 0x0f ) < < 1 ;
ivideo - > detectedpdca = ( pdc & 0xf0 ) > > 3 ;
2010-12-21 00:50:16 +03:00
pdc = SiS_GetReg ( SISPART1 , 0x35 ) ;
2005-09-10 00:04:45 +04:00
ivideo - > detectedpdc | = ( ( pdc > > 7 ) & 0x01 ) ;
2010-12-21 00:50:16 +03:00
pdc = SiS_GetReg ( SISPART1 , 0x20 ) ;
2005-09-10 00:04:45 +04:00
ivideo - > detectedpdca | = ( ( pdc > > 6 ) & 0x01 ) ;
if ( ivideo - > newrom ) {
/* New ROM invalidates other PDC resp. */
if ( ivideo - > detectedlcda ! = 0xff ) {
ivideo - > detectedpdc = 0xff ;
} else {
ivideo - > detectedpdca = 0xff ;
}
}
if ( ivideo - > SiS_Pr . PDC = = - 1 ) {
if ( ivideo - > detectedpdc ! = 0xff ) {
ivideo - > SiS_Pr . PDC = ivideo - > detectedpdc ;
}
}
if ( ivideo - > SiS_Pr . PDCA = = - 1 ) {
if ( ivideo - > detectedpdca ! = 0xff ) {
ivideo - > SiS_Pr . PDCA = ivideo - > detectedpdca ;
}
}
if ( ivideo - > detectedpdc ! = 0xff ) {
printk ( KERN_INFO
" sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2) \n " ,
ivideo - > detectedpdc ) ;
}
if ( ivideo - > detectedpdca ! = 0xff ) {
printk ( KERN_INFO
" sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1) \n " ,
ivideo - > detectedpdca ) ;
}
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* Save EMI */
if ( ivideo - > vbflags2 & VB2_SISEMIBRIDGE ) {
2010-12-21 00:50:16 +03:00
ivideo - > SiS_Pr . EMI_30 = SiS_GetReg ( SISPART4 , 0x30 ) ;
ivideo - > SiS_Pr . EMI_31 = SiS_GetReg ( SISPART4 , 0x31 ) ;
ivideo - > SiS_Pr . EMI_32 = SiS_GetReg ( SISPART4 , 0x32 ) ;
ivideo - > SiS_Pr . EMI_33 = SiS_GetReg ( SISPART4 , 0x33 ) ;
2007-02-12 11:55:06 +03:00
ivideo - > SiS_Pr . HaveEMI = true ;
2005-09-10 00:04:45 +04:00
if ( ( tmp & 0x20 ) | | ( ivideo - > detectedlcda ! = 0xff ) ) {
2007-02-12 11:55:06 +03:00
ivideo - > SiS_Pr . HaveEMILCD = true ;
2005-09-10 00:04:45 +04:00
}
}
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* Let user override detected PDCs (all bridges) */
if ( ivideo - > vbflags2 & VB2_30xBLV ) {
if ( ( ivideo - > SiS_Pr . PDC ! = - 1 ) & &
( ivideo - > SiS_Pr . PDC ! = ivideo - > detectedpdc ) ) {
printk ( KERN_INFO " sisfb: Using LCD PDC 0x%02x (for LCD=CRT2) \n " ,
ivideo - > SiS_Pr . PDC ) ;
}
if ( ( ivideo - > SiS_Pr . PDCA ! = - 1 ) & &
( ivideo - > SiS_Pr . PDCA ! = ivideo - > detectedpdca ) ) {
printk ( KERN_INFO " sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1) \n " ,
ivideo - > SiS_Pr . PDCA ) ;
}
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
# endif
2005-09-10 00:04:45 +04:00
}
/* -------------------- Memory manager routines ---------------------- */
2012-12-22 01:07:39 +04:00
static u32 sisfb_getheapstart ( struct sis_video_info * ivideo )
2005-09-10 00:04:45 +04:00
{
u32 ret = ivideo - > sisfb_parm_mem * 1024 ;
u32 maxoffs = ivideo - > video_size - ivideo - > hwcursor_size - ivideo - > cmdQueueSize ;
u32 def ;
/* Calculate heap start = end of memory for console
*
* CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
* C = console , D = heap , H = HWCursor , Q = cmd - queue
*
* On 76 x in UMA + LFB mode , the layout is as follows :
* DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
* where the heap is the entire UMA area , eventually
* into the LFB area if the given mem parameter is
* higher than the size of the UMA memory .
*
* Basically given by " mem " parameter
*
* maximum = videosize - cmd_queue - hwcursor
* ( results in a heap of size 0 )
* default = SiS 300 : depends on videosize
* SiS 315 / 330 / 340 / XGI : 32 k below max
*/
if ( ivideo - > sisvga_engine = = SIS_300_VGA ) {
if ( ivideo - > video_size > 0x1000000 ) {
def = 0xc00000 ;
} else if ( ivideo - > video_size > 0x800000 ) {
def = 0x800000 ;
} else {
def = 0x400000 ;
}
} else if ( ivideo - > UMAsize & & ivideo - > LFBsize ) {
ret = def = 0 ;
} else {
def = maxoffs - 0x8000 ;
}
/* Use default for secondary card for now (FIXME) */
if ( ( ! ret ) | | ( ret > maxoffs ) | | ( ivideo - > cardnumber ! = 0 ) )
ret = def ;
return ret ;
}
2012-12-22 01:07:39 +04:00
static u32 sisfb_getheapsize ( struct sis_video_info * ivideo )
2005-09-10 00:04:45 +04:00
{
u32 max = ivideo - > video_size - ivideo - > hwcursor_size - ivideo - > cmdQueueSize ;
u32 ret = 0 ;
if ( ivideo - > UMAsize & & ivideo - > LFBsize ) {
if ( ( ! ivideo - > sisfb_parm_mem ) | |
( ( ivideo - > sisfb_parm_mem * 1024 ) > max ) | |
( ( max - ( ivideo - > sisfb_parm_mem * 1024 ) ) < ivideo - > UMAsize ) ) {
ret = ivideo - > UMAsize ;
max - = ivideo - > UMAsize ;
} else {
ret = max - ( ivideo - > sisfb_parm_mem * 1024 ) ;
max = ivideo - > sisfb_parm_mem * 1024 ;
}
ivideo - > video_offset = ret ;
ivideo - > sisfb_mem = max ;
} else {
ret = max - ivideo - > heapstart ;
ivideo - > sisfb_mem = ivideo - > heapstart ;
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
return ret ;
}
2005-04-17 02:20:36 +04:00
2012-12-22 01:07:39 +04:00
static int sisfb_heap_init ( struct sis_video_info * ivideo )
2005-09-10 00:04:45 +04:00
{
struct SIS_OH * poh ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
ivideo - > video_offset = 0 ;
if ( ivideo - > sisfb_parm_mem ) {
if ( ( ivideo - > sisfb_parm_mem < ( 2 * 1024 * 1024 ) ) | |
( ivideo - > sisfb_parm_mem > ivideo - > video_size ) ) {
ivideo - > sisfb_parm_mem = 0 ;
}
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
ivideo - > heapstart = sisfb_getheapstart ( ivideo ) ;
ivideo - > sisfb_heap_size = sisfb_getheapsize ( ivideo ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
ivideo - > sisfb_heap_start = ivideo - > video_vbase + ivideo - > heapstart ;
ivideo - > sisfb_heap_end = ivideo - > sisfb_heap_start + ivideo - > sisfb_heap_size ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
printk ( KERN_INFO " sisfb: Memory heap starting at %dK, size %dK \n " ,
( int ) ( ivideo - > heapstart / 1024 ) , ( int ) ( ivideo - > sisfb_heap_size / 1024 ) ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
ivideo - > sisfb_heap . vinfo = ivideo ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
ivideo - > sisfb_heap . poha_chain = NULL ;
ivideo - > sisfb_heap . poh_freelist = NULL ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
poh = sisfb_poh_new_node ( & ivideo - > sisfb_heap ) ;
if ( poh = = NULL )
return 1 ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
poh - > poh_next = & ivideo - > sisfb_heap . oh_free ;
poh - > poh_prev = & ivideo - > sisfb_heap . oh_free ;
poh - > size = ivideo - > sisfb_heap_size ;
poh - > offset = ivideo - > heapstart ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
ivideo - > sisfb_heap . oh_free . poh_next = poh ;
ivideo - > sisfb_heap . oh_free . poh_prev = poh ;
ivideo - > sisfb_heap . oh_free . size = 0 ;
ivideo - > sisfb_heap . max_freesize = poh - > size ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
ivideo - > sisfb_heap . oh_used . poh_next = & ivideo - > sisfb_heap . oh_used ;
ivideo - > sisfb_heap . oh_used . poh_prev = & ivideo - > sisfb_heap . oh_used ;
ivideo - > sisfb_heap . oh_used . size = SENTINEL ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ivideo - > cardnumber = = 0 ) {
/* For the first card, make this heap the "global" one
* for old DRM ( which could handle only one card )
*/
sisfb_heap = & ivideo - > sisfb_heap ;
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
static struct SIS_OH *
sisfb_poh_new_node ( struct SIS_HEAP * memheap )
2005-04-17 02:20:36 +04:00
{
2005-09-10 00:04:45 +04:00
struct SIS_OHALLOC * poha ;
struct SIS_OH * poh ;
unsigned long cOhs ;
int i ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( memheap - > poh_freelist = = NULL ) {
2005-04-17 02:20:36 +04:00
poha = kmalloc ( SIS_OH_ALLOC_SIZE , GFP_KERNEL ) ;
2005-09-10 00:04:45 +04:00
if ( ! poha )
return NULL ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
poha - > poha_next = memheap - > poha_chain ;
memheap - > poha_chain = poha ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
cOhs = ( SIS_OH_ALLOC_SIZE - sizeof ( struct SIS_OHALLOC ) ) / sizeof ( struct SIS_OH ) + 1 ;
2005-04-17 02:20:36 +04:00
poh = & poha - > aoh [ 0 ] ;
for ( i = cOhs - 1 ; i ! = 0 ; i - - ) {
poh - > poh_next = poh + 1 ;
poh = poh + 1 ;
}
poh - > poh_next = NULL ;
2005-09-10 00:04:45 +04:00
memheap - > poh_freelist = & poha - > aoh [ 0 ] ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
poh = memheap - > poh_freelist ;
memheap - > poh_freelist = poh - > poh_next ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
return poh ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
static struct SIS_OH *
sisfb_poh_allocate ( struct SIS_HEAP * memheap , u32 size )
2005-04-17 02:20:36 +04:00
{
2005-09-10 00:04:45 +04:00
struct SIS_OH * pohThis ;
struct SIS_OH * pohRoot ;
int bAllocated = 0 ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( size > memheap - > max_freesize ) {
2005-04-17 02:20:36 +04:00
DPRINTK ( " sisfb: Can't allocate %dk video memory \n " ,
( unsigned int ) size / 1024 ) ;
2005-09-10 00:04:45 +04:00
return NULL ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
pohThis = memheap - > oh_free . poh_next ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
while ( pohThis ! = & memheap - > oh_free ) {
if ( size < = pohThis - > size ) {
2005-04-17 02:20:36 +04:00
bAllocated = 1 ;
break ;
}
pohThis = pohThis - > poh_next ;
}
if ( ! bAllocated ) {
DPRINTK ( " sisfb: Can't allocate %dk video memory \n " ,
( unsigned int ) size / 1024 ) ;
2005-09-10 00:04:45 +04:00
return NULL ;
2005-04-17 02:20:36 +04:00
}
if ( size = = pohThis - > size ) {
pohRoot = pohThis ;
sisfb_delete_node ( pohThis ) ;
} else {
2005-09-10 00:04:45 +04:00
pohRoot = sisfb_poh_new_node ( memheap ) ;
if ( pohRoot = = NULL )
return NULL ;
2005-04-17 02:20:36 +04:00
pohRoot - > offset = pohThis - > offset ;
pohRoot - > size = size ;
pohThis - > offset + = size ;
pohThis - > size - = size ;
}
2005-09-10 00:04:45 +04:00
memheap - > max_freesize - = size ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
pohThis = & memheap - > oh_used ;
2005-04-17 02:20:36 +04:00
sisfb_insert_node ( pohThis , pohRoot ) ;
2005-09-10 00:04:45 +04:00
return pohRoot ;
2005-04-17 02:20:36 +04:00
}
static void
2005-09-10 00:04:45 +04:00
sisfb_delete_node ( struct SIS_OH * poh )
2005-04-17 02:20:36 +04:00
{
2005-09-10 00:04:45 +04:00
poh - > poh_prev - > poh_next = poh - > poh_next ;
poh - > poh_next - > poh_prev = poh - > poh_prev ;
2005-04-17 02:20:36 +04:00
}
static void
2005-09-10 00:04:45 +04:00
sisfb_insert_node ( struct SIS_OH * pohList , struct SIS_OH * poh )
2005-04-17 02:20:36 +04:00
{
2005-09-10 00:04:45 +04:00
struct SIS_OH * pohTemp = pohList - > poh_next ;
2005-04-17 02:20:36 +04:00
pohList - > poh_next = poh ;
pohTemp - > poh_prev = poh ;
poh - > poh_prev = pohList ;
poh - > poh_next = pohTemp ;
}
2005-09-10 00:04:45 +04:00
static struct SIS_OH *
sisfb_poh_free ( struct SIS_HEAP * memheap , u32 base )
2005-04-17 02:20:36 +04:00
{
2005-09-10 00:04:45 +04:00
struct SIS_OH * pohThis ;
struct SIS_OH * poh_freed ;
struct SIS_OH * poh_prev ;
struct SIS_OH * poh_next ;
u32 ulUpper ;
u32 ulLower ;
int foundNode = 0 ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
poh_freed = memheap - > oh_used . poh_next ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
while ( poh_freed ! = & memheap - > oh_used ) {
2005-04-17 02:20:36 +04:00
if ( poh_freed - > offset = = base ) {
foundNode = 1 ;
break ;
}
poh_freed = poh_freed - > poh_next ;
}
2005-09-10 00:04:45 +04:00
if ( ! foundNode )
return NULL ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
memheap - > max_freesize + = poh_freed - > size ;
2005-04-17 02:20:36 +04:00
poh_prev = poh_next = NULL ;
ulUpper = poh_freed - > offset + poh_freed - > size ;
ulLower = poh_freed - > offset ;
2005-09-10 00:04:45 +04:00
pohThis = memheap - > oh_free . poh_next ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
while ( pohThis ! = & memheap - > oh_free ) {
2005-04-17 02:20:36 +04:00
if ( pohThis - > offset = = ulUpper ) {
poh_next = pohThis ;
} else if ( ( pohThis - > offset + pohThis - > size ) = = ulLower ) {
poh_prev = pohThis ;
}
pohThis = pohThis - > poh_next ;
}
sisfb_delete_node ( poh_freed ) ;
if ( poh_prev & & poh_next ) {
poh_prev - > size + = ( poh_freed - > size + poh_next - > size ) ;
sisfb_delete_node ( poh_next ) ;
2005-09-10 00:04:45 +04:00
sisfb_free_node ( memheap , poh_freed ) ;
sisfb_free_node ( memheap , poh_next ) ;
return poh_prev ;
2005-04-17 02:20:36 +04:00
}
if ( poh_prev ) {
poh_prev - > size + = poh_freed - > size ;
2005-09-10 00:04:45 +04:00
sisfb_free_node ( memheap , poh_freed ) ;
return poh_prev ;
2005-04-17 02:20:36 +04:00
}
if ( poh_next ) {
poh_next - > size + = poh_freed - > size ;
poh_next - > offset = poh_freed - > offset ;
2005-09-10 00:04:45 +04:00
sisfb_free_node ( memheap , poh_freed ) ;
return poh_next ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
sisfb_insert_node ( & memheap - > oh_free , poh_freed ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
return poh_freed ;
2005-04-17 02:20:36 +04:00
}
static void
2005-09-10 00:04:45 +04:00
sisfb_free_node ( struct SIS_HEAP * memheap , struct SIS_OH * poh )
2005-04-17 02:20:36 +04:00
{
2005-09-10 00:04:45 +04:00
if ( poh = = NULL )
return ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
poh - > poh_next = memheap - > poh_freelist ;
memheap - > poh_freelist = poh ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
static void
sis_int_malloc ( struct sis_video_info * ivideo , struct sis_memreq * req )
2005-04-17 02:20:36 +04:00
{
2005-09-10 00:04:45 +04:00
struct SIS_OH * poh = NULL ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ( ivideo ) & & ( ivideo - > sisfb_id = = SISFB_ID ) & & ( ! ivideo - > havenoheap ) )
poh = sisfb_poh_allocate ( & ivideo - > sisfb_heap , ( u32 ) req - > size ) ;
2005-04-17 02:20:36 +04:00
if ( poh = = NULL ) {
2005-09-10 00:04:45 +04:00
req - > offset = req - > size = 0 ;
DPRINTK ( " sisfb: Video RAM allocation failed \n " ) ;
2005-04-17 02:20:36 +04:00
} else {
2005-09-10 00:04:45 +04:00
req - > offset = poh - > offset ;
req - > size = poh - > size ;
DPRINTK ( " sisfb: Video RAM allocation succeeded: 0x%lx \n " ,
( poh - > offset + ivideo - > video_vbase ) ) ;
2005-04-17 02:20:36 +04:00
}
}
2005-09-10 00:04:45 +04:00
void
sis_malloc ( struct sis_memreq * req )
{
struct sis_video_info * ivideo = sisfb_heap - > vinfo ;
if ( & ivideo - > sisfb_heap = = sisfb_heap )
sis_int_malloc ( ivideo , req ) ;
else
req - > offset = req - > size = 0 ;
}
2005-04-17 02:20:36 +04:00
void
2005-09-10 00:04:45 +04:00
sis_malloc_new ( struct pci_dev * pdev , struct sis_memreq * req )
{
struct sis_video_info * ivideo = pci_get_drvdata ( pdev ) ;
sis_int_malloc ( ivideo , req ) ;
}
/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
static void
sis_int_free ( struct sis_video_info * ivideo , u32 base )
2005-04-17 02:20:36 +04:00
{
2005-09-10 00:04:45 +04:00
struct SIS_OH * poh ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ( ! ivideo ) | | ( ivideo - > sisfb_id ! = SISFB_ID ) | | ( ivideo - > havenoheap ) )
return ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
poh = sisfb_poh_free ( & ivideo - > sisfb_heap , base ) ;
2005-04-17 02:20:36 +04:00
if ( poh = = NULL ) {
DPRINTK ( " sisfb: sisfb_poh_free() failed at base 0x%x \n " ,
( unsigned int ) base ) ;
}
}
2005-09-10 00:04:45 +04:00
void
sis_free ( u32 base )
{
struct sis_video_info * ivideo = sisfb_heap - > vinfo ;
sis_int_free ( ivideo , base ) ;
}
void
sis_free_new ( struct pci_dev * pdev , u32 base )
{
struct sis_video_info * ivideo = pci_get_drvdata ( pdev ) ;
sis_int_free ( ivideo , base ) ;
}
2005-04-17 02:20:36 +04:00
/* --------------------- SetMode routines ------------------------- */
2005-09-10 00:04:45 +04:00
static void
sisfb_check_engine_and_sync ( struct sis_video_info * ivideo )
{
u8 cr30 , cr31 ;
/* Check if MMIO and engines are enabled,
* and sync in case they are . Can ' t use
* ivideo - > accel here , as this might have
* been changed before this is called .
*/
2010-12-21 00:50:16 +03:00
cr30 = SiS_GetReg ( SISSR , IND_SIS_PCI_ADDRESS_SET ) ;
cr31 = SiS_GetReg ( SISSR , IND_SIS_MODULE_ENABLE ) ;
2005-09-10 00:04:45 +04:00
/* MMIO and 2D/3D engine enabled? */
if ( ( cr30 & SIS_MEM_MAP_IO_ENABLE ) & & ( cr31 & 0x42 ) ) {
# ifdef CONFIG_FB_SIS_300
if ( ivideo - > sisvga_engine = = SIS_300_VGA ) {
/* Don't care about TurboQueue. It's
* enough to know that the engines
* are enabled
*/
sisfb_syncaccel ( ivideo ) ;
}
# endif
# ifdef CONFIG_FB_SIS_315
if ( ivideo - > sisvga_engine = = SIS_315_VGA ) {
/* Check that any queue mode is
* enabled , and that the queue
* is not in the state of " reset "
*/
2010-12-21 00:50:16 +03:00
cr30 = SiS_GetReg ( SISSR , 0x26 ) ;
2005-09-10 00:04:45 +04:00
if ( ( cr30 & 0xe0 ) & & ( ! ( cr30 & 0x01 ) ) ) {
sisfb_syncaccel ( ivideo ) ;
}
}
# endif
}
}
2005-04-17 02:20:36 +04:00
static void
sisfb_pre_setmode ( struct sis_video_info * ivideo )
{
u8 cr30 = 0 , cr31 = 0 , cr33 = 0 , cr35 = 0 , cr38 = 0 ;
int tvregnum = 0 ;
ivideo - > currentvbflags & = ( VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x05 , 0x86 ) ;
2005-09-10 00:04:45 +04:00
2010-12-21 00:50:16 +03:00
cr31 = SiS_GetReg ( SISCR , 0x31 ) ;
2005-04-17 02:20:36 +04:00
cr31 & = ~ 0x60 ;
cr31 | = 0x04 ;
cr33 = ivideo - > rate_idx & 0x0F ;
# ifdef CONFIG_FB_SIS_315
if ( ivideo - > sisvga_engine = = SIS_315_VGA ) {
if ( ivideo - > chip > = SIS_661 ) {
2010-12-21 00:50:16 +03:00
cr38 = SiS_GetReg ( SISCR , 0x38 ) ;
2005-04-17 02:20:36 +04:00
cr38 & = ~ 0x07 ; /* Clear LCDA/DualEdge and YPbPr bits */
} else {
tvregnum = 0x38 ;
2010-12-21 00:50:16 +03:00
cr38 = SiS_GetReg ( SISCR , tvregnum ) ;
2005-04-17 02:20:36 +04:00
cr38 & = ~ 0x3b ; /* Clear LCDA/DualEdge and YPbPr bits */
}
}
# endif
# ifdef CONFIG_FB_SIS_300
if ( ivideo - > sisvga_engine = = SIS_300_VGA ) {
tvregnum = 0x35 ;
2010-12-21 00:50:16 +03:00
cr38 = SiS_GetReg ( SISCR , tvregnum ) ;
2005-04-17 02:20:36 +04:00
}
# endif
2007-02-12 11:55:06 +03:00
SiS_SetEnableDstn ( & ivideo - > SiS_Pr , false ) ;
SiS_SetEnableFstn ( & ivideo - > SiS_Pr , false ) ;
2005-09-10 00:04:45 +04:00
ivideo - > curFSTN = ivideo - > curDSTN = 0 ;
2005-04-17 02:20:36 +04:00
switch ( ivideo - > currentvbflags & VB_DISPTYPE_DISP2 ) {
case CRT2_TV :
cr38 & = ~ 0xc0 ; /* Clear PAL-M / PAL-N bits */
2005-09-10 00:04:45 +04:00
if ( ( ivideo - > vbflags & TV_YPBPR ) & & ( ivideo - > vbflags2 & VB2_SISYPBPRBRIDGE ) ) {
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_FB_SIS_315
2005-09-10 00:04:45 +04:00
if ( ivideo - > chip > = SIS_661 ) {
cr38 | = 0x04 ;
if ( ivideo - > vbflags & TV_YPBPR525P ) cr35 | = 0x20 ;
2005-04-17 02:20:36 +04:00
else if ( ivideo - > vbflags & TV_YPBPR750P ) cr35 | = 0x40 ;
else if ( ivideo - > vbflags & TV_YPBPR1080I ) cr35 | = 0x60 ;
cr30 | = SIS_SIMULTANEOUS_VIEW_ENABLE ;
cr35 & = ~ 0x01 ;
ivideo - > currentvbflags | = ( TV_YPBPR | ( ivideo - > vbflags & TV_YPBPRALL ) ) ;
2005-09-10 00:04:45 +04:00
} else if ( ivideo - > sisvga_engine = = SIS_315_VGA ) {
cr30 | = ( 0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE ) ;
2005-04-17 02:20:36 +04:00
cr38 | = 0x08 ;
2005-09-10 00:04:45 +04:00
if ( ivideo - > vbflags & TV_YPBPR525P ) cr38 | = 0x10 ;
2005-04-17 02:20:36 +04:00
else if ( ivideo - > vbflags & TV_YPBPR750P ) cr38 | = 0x20 ;
else if ( ivideo - > vbflags & TV_YPBPR1080I ) cr38 | = 0x30 ;
cr31 & = ~ 0x01 ;
ivideo - > currentvbflags | = ( TV_YPBPR | ( ivideo - > vbflags & TV_YPBPRALL ) ) ;
2005-09-10 00:04:45 +04:00
}
# endif
} else if ( ( ivideo - > vbflags & TV_HIVISION ) & &
( ivideo - > vbflags2 & VB2_SISHIVISIONBRIDGE ) ) {
if ( ivideo - > chip > = SIS_661 ) {
cr38 | = 0x04 ;
cr35 | = 0x60 ;
} else {
cr30 | = 0x80 ;
}
2005-04-17 02:20:36 +04:00
cr30 | = SIS_SIMULTANEOUS_VIEW_ENABLE ;
2005-09-10 00:04:45 +04:00
cr31 | = 0x01 ;
cr35 | = 0x01 ;
2005-04-17 02:20:36 +04:00
ivideo - > currentvbflags | = TV_HIVISION ;
} else if ( ivideo - > vbflags & TV_SCART ) {
cr30 = ( SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE ) ;
cr31 | = 0x01 ;
cr35 | = 0x01 ;
ivideo - > currentvbflags | = TV_SCART ;
} else {
if ( ivideo - > vbflags & TV_SVIDEO ) {
cr30 = ( SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE ) ;
ivideo - > currentvbflags | = TV_SVIDEO ;
}
if ( ivideo - > vbflags & TV_AVIDEO ) {
cr30 = ( SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE ) ;
ivideo - > currentvbflags | = TV_AVIDEO ;
}
}
cr31 | = SIS_DRIVER_MODE ;
2005-09-10 00:04:45 +04:00
if ( ivideo - > vbflags & ( TV_AVIDEO | TV_SVIDEO ) ) {
if ( ivideo - > vbflags & TV_PAL ) {
2005-04-17 02:20:36 +04:00
cr31 | = 0x01 ; cr35 | = 0x01 ;
ivideo - > currentvbflags | = TV_PAL ;
if ( ivideo - > vbflags & TV_PALM ) {
cr38 | = 0x40 ; cr35 | = 0x04 ;
ivideo - > currentvbflags | = TV_PALM ;
} else if ( ivideo - > vbflags & TV_PALN ) {
cr38 | = 0x80 ; cr35 | = 0x08 ;
ivideo - > currentvbflags | = TV_PALN ;
2005-09-10 00:04:45 +04:00
}
} else {
2005-04-17 02:20:36 +04:00
cr31 & = ~ 0x01 ; cr35 & = ~ 0x01 ;
ivideo - > currentvbflags | = TV_NTSC ;
if ( ivideo - > vbflags & TV_NTSCJ ) {
cr38 | = 0x40 ; cr35 | = 0x02 ;
ivideo - > currentvbflags | = TV_NTSCJ ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
}
}
break ;
case CRT2_LCD :
cr30 = ( SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE ) ;
cr31 | = SIS_DRIVER_MODE ;
SiS_SetEnableDstn ( & ivideo - > SiS_Pr , ivideo - > sisfb_dstn ) ;
SiS_SetEnableFstn ( & ivideo - > SiS_Pr , ivideo - > sisfb_fstn ) ;
2005-09-10 00:04:45 +04:00
ivideo - > curFSTN = ivideo - > sisfb_fstn ;
ivideo - > curDSTN = ivideo - > sisfb_dstn ;
2005-04-17 02:20:36 +04:00
break ;
case CRT2_VGA :
cr30 = ( SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE ) ;
cr31 | = SIS_DRIVER_MODE ;
if ( ivideo - > sisfb_nocrt2rate ) {
cr33 | = ( sisbios_mode [ ivideo - > sisfb_mode_idx ] . rate_idx < < 4 ) ;
} else {
cr33 | = ( ( ivideo - > rate_idx & 0x0F ) < < 4 ) ;
}
break ;
default : /* disable CRT2 */
cr30 = 0x00 ;
cr31 | = ( SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE ) ;
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x30 , cr30 ) ;
SiS_SetReg ( SISCR , 0x33 , cr33 ) ;
2005-04-17 02:20:36 +04:00
if ( ivideo - > chip > = SIS_661 ) {
# ifdef CONFIG_FB_SIS_315
cr31 & = ~ 0x01 ; /* Clear PAL flag (now in CR35) */
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISCR , 0x35 , ~ 0x10 , cr35 ) ; /* Leave overscan bit alone */
2005-04-17 02:20:36 +04:00
cr38 & = 0x07 ; /* Use only LCDA and HiVision/YPbPr bits */
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISCR , 0x38 , 0xf8 , cr38 ) ;
2005-04-17 02:20:36 +04:00
# endif
} else if ( ivideo - > chip ! = SIS_300 ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , tvregnum , cr38 ) ;
2005-04-17 02:20:36 +04:00
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x31 , cr31 ) ;
2005-04-17 02:20:36 +04:00
ivideo - > SiS_Pr . SiS_UseOEM = ivideo - > sisfb_useoem ;
2005-09-10 00:04:45 +04:00
sisfb_check_engine_and_sync ( ivideo ) ;
2005-04-17 02:20:36 +04:00
}
/* Fix SR11 for 661 and later */
# ifdef CONFIG_FB_SIS_315
static void
sisfb_fixup_SR11 ( struct sis_video_info * ivideo )
{
2005-09-10 00:04:45 +04:00
u8 tmpreg ;
if ( ivideo - > chip > = SIS_661 ) {
2010-12-21 00:50:16 +03:00
tmpreg = SiS_GetReg ( SISSR , 0x11 ) ;
2005-09-10 00:04:45 +04:00
if ( tmpreg & 0x20 ) {
2010-12-21 00:50:16 +03:00
tmpreg = SiS_GetReg ( SISSR , 0x3e ) ;
2005-09-10 00:04:45 +04:00
tmpreg = ( tmpreg + 1 ) & 0xff ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x3e , tmpreg ) ;
2010-12-21 00:50:16 +03:00
tmpreg = SiS_GetReg ( SISSR , 0x11 ) ;
2005-09-10 00:04:45 +04:00
}
if ( tmpreg & 0xf0 ) {
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISSR , 0x11 , 0x0f ) ;
2005-09-10 00:04:45 +04:00
}
}
2005-04-17 02:20:36 +04:00
}
# endif
2005-09-10 00:04:45 +04:00
static void
sisfb_set_TVxposoffset ( struct sis_video_info * ivideo , int val )
2005-04-17 02:20:36 +04:00
{
2005-09-10 00:04:45 +04:00
if ( val > 32 ) val = 32 ;
if ( val < - 32 ) val = - 32 ;
ivideo - > tvxpos = val ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ivideo - > sisfblocked ) return ;
if ( ! ivideo - > modechanged ) return ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ivideo - > currentvbflags & CRT2_TV ) {
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ivideo - > vbflags2 & VB2_CHRONTEL ) {
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
int x = ivideo - > tvx ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
switch ( ivideo - > chronteltype ) {
case 1 :
x + = val ;
if ( x < 0 ) x = 0 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x05 , 0x86 ) ;
2005-09-10 00:04:45 +04:00
SiS_SetCH700x ( & ivideo - > SiS_Pr , 0x0a , ( x & 0xff ) ) ;
SiS_SetCH70xxANDOR ( & ivideo - > SiS_Pr , 0x08 , ( ( x & 0x0100 ) > > 7 ) , 0xFD ) ;
break ;
case 2 :
/* Not supported by hardware */
break ;
}
} else if ( ivideo - > vbflags2 & VB2_SISBRIDGE ) {
u8 p2_1f , p2_20 , p2_2b , p2_42 , p2_43 ;
unsigned short temp ;
p2_1f = ivideo - > p2_1f ;
p2_20 = ivideo - > p2_20 ;
p2_2b = ivideo - > p2_2b ;
p2_42 = ivideo - > p2_42 ;
p2_43 = ivideo - > p2_43 ;
temp = p2_1f | ( ( p2_20 & 0xf0 ) < < 4 ) ;
temp + = ( val * 2 ) ;
p2_1f = temp & 0xff ;
p2_20 = ( temp & 0xf00 ) > > 4 ;
p2_2b = ( ( p2_2b & 0x0f ) + ( val * 2 ) ) & 0x0f ;
temp = p2_43 | ( ( p2_42 & 0xf0 ) < < 4 ) ;
temp + = ( val * 2 ) ;
p2_43 = temp & 0xff ;
p2_42 = ( temp & 0xf00 ) > > 4 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART2 , 0x1f , p2_1f ) ;
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISPART2 , 0x20 , 0x0F , p2_20 ) ;
SiS_SetRegANDOR ( SISPART2 , 0x2b , 0xF0 , p2_2b ) ;
SiS_SetRegANDOR ( SISPART2 , 0x42 , 0x0F , p2_42 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART2 , 0x43 , p2_43 ) ;
2005-09-10 00:04:45 +04:00
}
}
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
static void
sisfb_set_TVyposoffset ( struct sis_video_info * ivideo , int val )
2005-04-17 02:20:36 +04:00
{
2005-09-10 00:04:45 +04:00
if ( val > 32 ) val = 32 ;
if ( val < - 32 ) val = - 32 ;
ivideo - > tvypos = val ;
if ( ivideo - > sisfblocked ) return ;
if ( ! ivideo - > modechanged ) return ;
if ( ivideo - > currentvbflags & CRT2_TV ) {
if ( ivideo - > vbflags2 & VB2_CHRONTEL ) {
int y = ivideo - > tvy ;
switch ( ivideo - > chronteltype ) {
case 1 :
y - = val ;
if ( y < 0 ) y = 0 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x05 , 0x86 ) ;
2005-09-10 00:04:45 +04:00
SiS_SetCH700x ( & ivideo - > SiS_Pr , 0x0b , ( y & 0xff ) ) ;
SiS_SetCH70xxANDOR ( & ivideo - > SiS_Pr , 0x08 , ( ( y & 0x0100 ) > > 8 ) , 0xFE ) ;
break ;
case 2 :
/* Not supported by hardware */
break ;
}
} else if ( ivideo - > vbflags2 & VB2_SISBRIDGE ) {
char p2_01 , p2_02 ;
val / = 2 ;
p2_01 = ivideo - > p2_01 ;
p2_02 = ivideo - > p2_02 ;
p2_01 + = val ;
p2_02 + = val ;
if ( ! ( ivideo - > currentvbflags & ( TV_HIVISION | TV_YPBPR ) ) ) {
while ( ( p2_01 < = 0 ) | | ( p2_02 < = 0 ) ) {
p2_01 + = 2 ;
p2_02 + = 2 ;
}
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART2 , 0x01 , p2_01 ) ;
SiS_SetReg ( SISPART2 , 0x02 , p2_02 ) ;
2005-09-10 00:04:45 +04:00
}
}
2005-04-17 02:20:36 +04:00
}
static void
sisfb_post_setmode ( struct sis_video_info * ivideo )
{
2007-02-12 11:55:06 +03:00
bool crt1isoff = false ;
bool doit = true ;
2005-04-17 02:20:36 +04:00
# if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
u8 reg ;
# endif
# ifdef CONFIG_FB_SIS_315
u8 reg1 ;
# endif
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x05 , 0x86 ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_FB_SIS_315
sisfb_fixup_SR11 ( ivideo ) ;
# endif
/* Now we actually HAVE changed the display mode */
2005-09-10 00:04:45 +04:00
ivideo - > modechanged = 1 ;
2005-04-17 02:20:36 +04:00
/* We can't switch off CRT1 if bridge is in slave mode */
2005-09-10 00:04:45 +04:00
if ( ivideo - > vbflags2 & VB2_VIDEOBRIDGE ) {
2007-02-12 11:55:06 +03:00
if ( sisfb_bridgeisslave ( ivideo ) ) doit = false ;
2005-09-10 00:04:45 +04:00
} else
ivideo - > sisfb_crt1off = 0 ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_FB_SIS_300
if ( ivideo - > sisvga_engine = = SIS_300_VGA ) {
2005-09-10 00:04:45 +04:00
if ( ( ivideo - > sisfb_crt1off ) & & ( doit ) ) {
2007-02-12 11:55:06 +03:00
crt1isoff = true ;
2005-09-10 00:04:45 +04:00
reg = 0x00 ;
} else {
2007-02-12 11:55:06 +03:00
crt1isoff = false ;
2005-09-10 00:04:45 +04:00
reg = 0x80 ;
}
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISCR , 0x17 , 0x7f , reg ) ;
2005-04-17 02:20:36 +04:00
}
# endif
# ifdef CONFIG_FB_SIS_315
if ( ivideo - > sisvga_engine = = SIS_315_VGA ) {
2005-09-10 00:04:45 +04:00
if ( ( ivideo - > sisfb_crt1off ) & & ( doit ) ) {
2007-02-12 11:55:06 +03:00
crt1isoff = true ;
2005-09-10 00:04:45 +04:00
reg = 0x40 ;
reg1 = 0xc0 ;
} else {
2007-02-12 11:55:06 +03:00
crt1isoff = false ;
2005-09-10 00:04:45 +04:00
reg = 0x00 ;
reg1 = 0x00 ;
}
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISCR , ivideo - > SiS_Pr . SiS_MyCR63 , ~ 0x40 , reg ) ;
2010-12-21 00:50:22 +03:00
SiS_SetRegANDOR ( SISSR , 0x1f , 0x3f , reg1 ) ;
2005-04-17 02:20:36 +04:00
}
# endif
if ( crt1isoff ) {
2005-09-10 00:04:45 +04:00
ivideo - > currentvbflags & = ~ VB_DISPTYPE_CRT1 ;
ivideo - > currentvbflags | = VB_SINGLE_MODE ;
2005-04-17 02:20:36 +04:00
} else {
2005-09-10 00:04:45 +04:00
ivideo - > currentvbflags | = VB_DISPTYPE_CRT1 ;
if ( ivideo - > currentvbflags & VB_DISPTYPE_CRT2 ) {
ivideo - > currentvbflags | = VB_MIRROR_MODE ;
} else {
ivideo - > currentvbflags | = VB_SINGLE_MODE ;
}
2005-04-17 02:20:36 +04:00
}
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISSR , IND_SIS_RAMDAC_CONTROL , ~ 0x04 ) ;
2005-04-17 02:20:36 +04:00
if ( ivideo - > currentvbflags & CRT2_TV ) {
2005-09-10 00:04:45 +04:00
if ( ivideo - > vbflags2 & VB2_SISBRIDGE ) {
2010-12-21 00:50:16 +03:00
ivideo - > p2_1f = SiS_GetReg ( SISPART2 , 0x1f ) ;
ivideo - > p2_20 = SiS_GetReg ( SISPART2 , 0x20 ) ;
ivideo - > p2_2b = SiS_GetReg ( SISPART2 , 0x2b ) ;
ivideo - > p2_42 = SiS_GetReg ( SISPART2 , 0x42 ) ;
ivideo - > p2_43 = SiS_GetReg ( SISPART2 , 0x43 ) ;
ivideo - > p2_01 = SiS_GetReg ( SISPART2 , 0x01 ) ;
ivideo - > p2_02 = SiS_GetReg ( SISPART2 , 0x02 ) ;
2005-09-10 00:04:45 +04:00
} else if ( ivideo - > vbflags2 & VB2_CHRONTEL ) {
if ( ivideo - > chronteltype = = 1 ) {
ivideo - > tvx = SiS_GetCH700x ( & ivideo - > SiS_Pr , 0x0a ) ;
ivideo - > tvx | = ( ( ( SiS_GetCH700x ( & ivideo - > SiS_Pr , 0x08 ) & 0x02 ) > > 1 ) < < 8 ) ;
ivideo - > tvy = SiS_GetCH700x ( & ivideo - > SiS_Pr , 0x0b ) ;
ivideo - > tvy | = ( ( SiS_GetCH700x ( & ivideo - > SiS_Pr , 0x08 ) & 0x01 ) < < 8 ) ;
}
}
2005-04-17 02:20:36 +04:00
}
if ( ivideo - > tvxpos ) {
2005-09-10 00:04:45 +04:00
sisfb_set_TVxposoffset ( ivideo , ivideo - > tvxpos ) ;
2005-04-17 02:20:36 +04:00
}
if ( ivideo - > tvypos ) {
2005-09-10 00:04:45 +04:00
sisfb_set_TVyposoffset ( ivideo , ivideo - > tvypos ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
/* Eventually sync engines */
sisfb_check_engine_and_sync ( ivideo ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* (Re-)Initialize chip engines */
if ( ivideo - > accel ) {
sisfb_engine_init ( ivideo ) ;
} else {
ivideo - > engineok = 0 ;
}
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
static int
sisfb_reset_mode ( struct sis_video_info * ivideo )
{
if ( sisfb_set_mode ( ivideo , 0 ) )
return 1 ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
sisfb_set_pitch ( ivideo ) ;
sisfb_set_base_CRT1 ( ivideo , ivideo - > current_base ) ;
sisfb_set_base_CRT2 ( ivideo , ivideo - > current_base ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
return 0 ;
}
static void
sisfb_handle_command ( struct sis_video_info * ivideo , struct sisfb_cmd * sisfb_command )
{
int mycrt1off ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
switch ( sisfb_command - > sisfb_cmd ) {
case SISFB_CMD_GETVBFLAGS :
if ( ! ivideo - > modechanged ) {
sisfb_command - > sisfb_result [ 0 ] = SISFB_CMD_ERR_EARLY ;
} else {
sisfb_command - > sisfb_result [ 0 ] = SISFB_CMD_ERR_OK ;
sisfb_command - > sisfb_result [ 1 ] = ivideo - > currentvbflags ;
sisfb_command - > sisfb_result [ 2 ] = ivideo - > vbflags2 ;
}
break ;
case SISFB_CMD_SWITCHCRT1 :
/* arg[0]: 0 = off, 1 = on, 99 = query */
if ( ! ivideo - > modechanged ) {
sisfb_command - > sisfb_result [ 0 ] = SISFB_CMD_ERR_EARLY ;
} else if ( sisfb_command - > sisfb_arg [ 0 ] = = 99 ) {
/* Query */
sisfb_command - > sisfb_result [ 1 ] = ivideo - > sisfb_crt1off ? 0 : 1 ;
sisfb_command - > sisfb_result [ 0 ] = SISFB_CMD_ERR_OK ;
} else if ( ivideo - > sisfblocked ) {
sisfb_command - > sisfb_result [ 0 ] = SISFB_CMD_ERR_LOCKED ;
} else if ( ( ! ( ivideo - > currentvbflags & CRT2_ENABLE ) ) & &
( sisfb_command - > sisfb_arg [ 0 ] = = 0 ) ) {
sisfb_command - > sisfb_result [ 0 ] = SISFB_CMD_ERR_NOCRT2 ;
} else {
sisfb_command - > sisfb_result [ 0 ] = SISFB_CMD_ERR_OK ;
mycrt1off = sisfb_command - > sisfb_arg [ 0 ] ? 0 : 1 ;
if ( ( ( ivideo - > currentvbflags & VB_DISPTYPE_CRT1 ) & & mycrt1off ) | |
( ( ! ( ivideo - > currentvbflags & VB_DISPTYPE_CRT1 ) ) & & ! mycrt1off ) ) {
ivideo - > sisfb_crt1off = mycrt1off ;
if ( sisfb_reset_mode ( ivideo ) ) {
sisfb_command - > sisfb_result [ 0 ] = SISFB_CMD_ERR_OTHER ;
2005-04-17 02:20:36 +04:00
}
}
2005-09-10 00:04:45 +04:00
sisfb_command - > sisfb_result [ 1 ] = ivideo - > sisfb_crt1off ? 0 : 1 ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
break ;
/* more to come */
default :
sisfb_command - > sisfb_result [ 0 ] = SISFB_CMD_ERR_UNKNOWN ;
printk ( KERN_ERR " sisfb: Unknown command 0x%x \n " ,
sisfb_command - > sisfb_cmd ) ;
2005-04-17 02:20:36 +04:00
}
}
# ifndef MODULE
2008-07-24 08:31:12 +04:00
static int __init sisfb_setup ( char * options )
2005-04-17 02:20:36 +04:00
{
char * this_opt ;
2005-09-10 00:04:45 +04:00
sisfb_setdefaultparms ( ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ! options | | ! ( * options ) )
2005-04-17 02:20:36 +04:00
return 0 ;
while ( ( this_opt = strsep ( & options , " , " ) ) ! = NULL ) {
if ( ! ( * this_opt ) ) continue ;
if ( ! strnicmp ( this_opt , " off " , 3 ) ) {
sisfb_off = 1 ;
} else if ( ! strnicmp ( this_opt , " forcecrt2type: " , 14 ) ) {
/* Need to check crt2 type first for fstn/dstn */
sisfb_search_crt2type ( this_opt + 14 ) ;
} else if ( ! strnicmp ( this_opt , " tvmode: " , 7 ) ) {
sisfb_search_tvstd ( this_opt + 7 ) ;
2005-09-10 00:04:45 +04:00
} else if ( ! strnicmp ( this_opt , " tvstandard: " , 11 ) ) {
sisfb_search_tvstd ( this_opt + 11 ) ;
2005-04-17 02:20:36 +04:00
} else if ( ! strnicmp ( this_opt , " mode: " , 5 ) ) {
2007-02-12 11:55:06 +03:00
sisfb_search_mode ( this_opt + 5 , false ) ;
2005-04-17 02:20:36 +04:00
} else if ( ! strnicmp ( this_opt , " vesa: " , 5 ) ) {
2007-02-12 11:55:06 +03:00
sisfb_search_vesamode ( simple_strtoul ( this_opt + 5 , NULL , 0 ) , false ) ;
2005-04-17 02:20:36 +04:00
} else if ( ! strnicmp ( this_opt , " rate: " , 5 ) ) {
sisfb_parm_rate = simple_strtoul ( this_opt + 5 , NULL , 0 ) ;
} else if ( ! strnicmp ( this_opt , " forcecrt1: " , 10 ) ) {
sisfb_forcecrt1 = ( int ) simple_strtoul ( this_opt + 10 , NULL , 0 ) ;
2005-09-10 00:04:45 +04:00
} else if ( ! strnicmp ( this_opt , " mem: " , 4 ) ) {
sisfb_parm_mem = simple_strtoul ( this_opt + 4 , NULL , 0 ) ;
2005-04-17 02:20:36 +04:00
} else if ( ! strnicmp ( this_opt , " pdc: " , 4 ) ) {
2005-09-10 00:04:45 +04:00
sisfb_pdc = simple_strtoul ( this_opt + 4 , NULL , 0 ) ;
2005-04-17 02:20:36 +04:00
} else if ( ! strnicmp ( this_opt , " pdc1: " , 5 ) ) {
2005-09-10 00:04:45 +04:00
sisfb_pdca = simple_strtoul ( this_opt + 5 , NULL , 0 ) ;
2005-04-17 02:20:36 +04:00
} else if ( ! strnicmp ( this_opt , " noaccel " , 7 ) ) {
sisfb_accel = 0 ;
} else if ( ! strnicmp ( this_opt , " accel " , 5 ) ) {
sisfb_accel = - 1 ;
} else if ( ! strnicmp ( this_opt , " noypan " , 6 ) ) {
2005-09-10 00:04:45 +04:00
sisfb_ypan = 0 ;
2005-04-17 02:20:36 +04:00
} else if ( ! strnicmp ( this_opt , " ypan " , 4 ) ) {
2005-09-10 00:04:45 +04:00
sisfb_ypan = - 1 ;
2005-04-17 02:20:36 +04:00
} else if ( ! strnicmp ( this_opt , " nomax " , 5 ) ) {
2005-09-10 00:04:45 +04:00
sisfb_max = 0 ;
2005-04-17 02:20:36 +04:00
} else if ( ! strnicmp ( this_opt , " max " , 3 ) ) {
2005-09-10 00:04:45 +04:00
sisfb_max = - 1 ;
2005-04-17 02:20:36 +04:00
} else if ( ! strnicmp ( this_opt , " userom: " , 7 ) ) {
sisfb_userom = ( int ) simple_strtoul ( this_opt + 7 , NULL , 0 ) ;
} else if ( ! strnicmp ( this_opt , " useoem: " , 7 ) ) {
sisfb_useoem = ( int ) simple_strtoul ( this_opt + 7 , NULL , 0 ) ;
} else if ( ! strnicmp ( this_opt , " nocrt2rate " , 10 ) ) {
sisfb_nocrt2rate = 1 ;
2005-09-10 00:04:45 +04:00
} else if ( ! strnicmp ( this_opt , " scalelcd: " , 9 ) ) {
unsigned long temp = 2 ;
temp = simple_strtoul ( this_opt + 9 , NULL , 0 ) ;
if ( ( temp = = 0 ) | | ( temp = = 1 ) ) {
2005-04-17 02:20:36 +04:00
sisfb_scalelcd = temp ^ 1 ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
} else if ( ! strnicmp ( this_opt , " tvxposoffset: " , 13 ) ) {
2005-09-10 00:04:45 +04:00
int temp = 0 ;
temp = ( int ) simple_strtol ( this_opt + 13 , NULL , 0 ) ;
if ( ( temp > = - 32 ) & & ( temp < = 32 ) ) {
2005-04-17 02:20:36 +04:00
sisfb_tvxposoffset = temp ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
} else if ( ! strnicmp ( this_opt , " tvyposoffset: " , 13 ) ) {
2005-09-10 00:04:45 +04:00
int temp = 0 ;
temp = ( int ) simple_strtol ( this_opt + 13 , NULL , 0 ) ;
if ( ( temp > = - 32 ) & & ( temp < = 32 ) ) {
2005-04-17 02:20:36 +04:00
sisfb_tvyposoffset = temp ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
} else if ( ! strnicmp ( this_opt , " specialtiming: " , 14 ) ) {
sisfb_search_specialtiming ( this_opt + 14 ) ;
} else if ( ! strnicmp ( this_opt , " lvdshl: " , 7 ) ) {
2005-09-10 00:04:45 +04:00
int temp = 4 ;
temp = simple_strtoul ( this_opt + 7 , NULL , 0 ) ;
if ( ( temp > = 0 ) & & ( temp < = 3 ) ) {
2005-04-17 02:20:36 +04:00
sisfb_lvdshl = temp ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
} else if ( this_opt [ 0 ] > = ' 0 ' & & this_opt [ 0 ] < = ' 9 ' ) {
2007-02-12 11:55:06 +03:00
sisfb_search_mode ( this_opt , true ) ;
2005-04-17 02:20:36 +04:00
# if !defined(__i386__) && !defined(__x86_64__)
2005-09-10 00:04:45 +04:00
} else if ( ! strnicmp ( this_opt , " resetcard " , 9 ) ) {
sisfb_resetcard = 1 ;
2005-04-17 02:20:36 +04:00
} else if ( ! strnicmp ( this_opt , " videoram: " , 9 ) ) {
2005-09-10 00:04:45 +04:00
sisfb_videoram = simple_strtoul ( this_opt + 9 , NULL , 0 ) ;
2005-04-17 02:20:36 +04:00
# endif
} else {
printk ( KERN_INFO " sisfb: Invalid option %s \n " , this_opt ) ;
}
}
2005-09-10 00:04:45 +04:00
return 0 ;
}
# endif
2012-12-22 01:07:39 +04:00
static int sisfb_check_rom ( void __iomem * rom_base ,
struct sis_video_info * ivideo )
2005-09-10 00:04:45 +04:00
{
2008-07-24 08:31:12 +04:00
void __iomem * rom ;
2005-09-10 00:04:45 +04:00
int romptr ;
if ( ( readb ( rom_base ) ! = 0x55 ) | | ( readb ( rom_base + 1 ) ! = 0xaa ) )
return 0 ;
romptr = ( readb ( rom_base + 0x18 ) | ( readb ( rom_base + 0x19 ) < < 8 ) ) ;
if ( romptr > ( 0x10000 - 8 ) )
return 0 ;
rom = rom_base + romptr ;
if ( ( readb ( rom ) ! = ' P ' ) | | ( readb ( rom + 1 ) ! = ' C ' ) | |
( readb ( rom + 2 ) ! = ' I ' ) | | ( readb ( rom + 3 ) ! = ' R ' ) )
return 0 ;
if ( ( readb ( rom + 4 ) | ( readb ( rom + 5 ) < < 8 ) ) ! = ivideo - > chip_vendor )
return 0 ;
if ( ( readb ( rom + 6 ) | ( readb ( rom + 7 ) < < 8 ) ) ! = ivideo - > chip_id )
return 0 ;
return 1 ;
}
2012-12-22 01:07:39 +04:00
static unsigned char * sisfb_find_rom ( struct pci_dev * pdev )
2005-09-10 00:04:45 +04:00
{
struct sis_video_info * ivideo = pci_get_drvdata ( pdev ) ;
2008-07-24 08:31:12 +04:00
void __iomem * rom_base ;
2005-09-10 00:04:45 +04:00
unsigned char * myrombase = NULL ;
size_t romsize ;
/* First, try the official pci ROM functions (except
* on integrated chipsets which have no ROM ) .
*/
if ( ! ivideo - > nbridge ) {
if ( ( rom_base = pci_map_rom ( pdev , & romsize ) ) ) {
if ( sisfb_check_rom ( rom_base , ivideo ) ) {
if ( ( myrombase = vmalloc ( 65536 ) ) ) {
memcpy_fromio ( myrombase , rom_base ,
( romsize > 65536 ) ? 65536 : romsize ) ;
}
}
pci_unmap_rom ( pdev , rom_base ) ;
}
}
if ( myrombase ) return myrombase ;
/* Otherwise do it the conventional way. */
# if defined(__i386__) || defined(__x86_64__)
2010-12-21 00:50:10 +03:00
{
u32 temp ;
2005-09-10 00:04:45 +04:00
2010-12-21 00:50:10 +03:00
for ( temp = 0x000c0000 ; temp < 0x000f0000 ; temp + = 0x00001000 ) {
2005-09-10 00:04:45 +04:00
2010-12-21 00:50:10 +03:00
rom_base = ioremap ( temp , 65536 ) ;
if ( ! rom_base )
continue ;
2005-09-10 00:04:45 +04:00
2010-12-21 00:50:10 +03:00
if ( ! sisfb_check_rom ( rom_base , ivideo ) ) {
iounmap ( rom_base ) ;
continue ;
}
2005-09-10 00:04:45 +04:00
2010-12-21 00:50:10 +03:00
if ( ( myrombase = vmalloc ( 65536 ) ) )
memcpy_fromio ( myrombase , rom_base , 65536 ) ;
2005-09-10 00:04:45 +04:00
2010-12-21 00:50:10 +03:00
iounmap ( rom_base ) ;
break ;
2005-09-10 00:04:45 +04:00
2010-12-21 00:50:10 +03:00
}
2005-09-10 00:04:45 +04:00
2010-12-21 00:50:10 +03:00
}
2005-09-10 00:04:45 +04:00
# endif
return myrombase ;
}
2012-12-22 01:07:39 +04:00
static void sisfb_post_map_vram ( struct sis_video_info * ivideo ,
unsigned int * mapsize , unsigned int min )
2005-09-10 00:04:45 +04:00
{
2010-11-10 14:04:19 +03:00
if ( * mapsize < ( min < < 20 ) )
return ;
2005-09-10 00:04:45 +04:00
ivideo - > video_vbase = ioremap ( ivideo - > video_base , ( * mapsize ) ) ;
if ( ! ivideo - > video_vbase ) {
printk ( KERN_ERR
" sisfb: Unable to map maximum video RAM for size detection \n " ) ;
( * mapsize ) > > = 1 ;
while ( ( ! ( ivideo - > video_vbase = ioremap ( ivideo - > video_base , ( * mapsize ) ) ) ) ) {
( * mapsize ) > > = 1 ;
if ( ( * mapsize ) < ( min < < 20 ) )
break ;
}
if ( ivideo - > video_vbase ) {
printk ( KERN_ERR
" sisfb: Video RAM size detection limited to %dMB \n " ,
( int ) ( ( * mapsize ) > > 20 ) ) ;
}
}
}
# ifdef CONFIG_FB_SIS_300
2012-12-22 01:07:39 +04:00
static int sisfb_post_300_buswidth ( struct sis_video_info * ivideo )
2005-09-10 00:04:45 +04:00
{
2008-07-24 08:31:12 +04:00
void __iomem * FBAddress = ivideo - > video_vbase ;
2005-09-10 00:04:45 +04:00
unsigned short temp ;
unsigned char reg ;
int i , j ;
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISSR , 0x15 , 0xFB ) ;
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISSR , 0x15 , 0x04 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0x00 ) ;
SiS_SetReg ( SISSR , 0x14 , 0xBF ) ;
2005-09-10 00:04:45 +04:00
for ( i = 0 ; i < 2 ; i + + ) {
temp = 0x1234 ;
for ( j = 0 ; j < 4 ; j + + ) {
writew ( temp , FBAddress ) ;
if ( readw ( FBAddress ) = = temp )
break ;
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISSR , 0x3c , 0x01 ) ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISSR , 0x05 ) ;
reg = SiS_GetReg ( SISSR , 0x05 ) ;
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISSR , 0x3c , 0xfe ) ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISSR , 0x05 ) ;
reg = SiS_GetReg ( SISSR , 0x05 ) ;
2005-09-10 00:04:45 +04:00
temp + + ;
}
}
writel ( 0x01234567L , FBAddress ) ;
writel ( 0x456789ABL , ( FBAddress + 4 ) ) ;
writel ( 0x89ABCDEFL , ( FBAddress + 8 ) ) ;
writel ( 0xCDEF0123L , ( FBAddress + 12 ) ) ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISSR , 0x3b ) ;
2005-09-10 00:04:45 +04:00
if ( reg & 0x01 ) {
if ( readl ( ( FBAddress + 12 ) ) = = 0xCDEF0123L )
return 4 ; /* Channel A 128bit */
}
if ( readl ( ( FBAddress + 4 ) ) = = 0x456789ABL )
return 2 ; /* Channel B 64bit */
return 1 ; /* 32bit */
}
2012-12-22 01:07:39 +04:00
static const unsigned short SiS_DRAMType [ 17 ] [ 5 ] = {
2012-05-04 02:14:55 +04:00
{ 0x0C , 0x0A , 0x02 , 0x40 , 0x39 } ,
{ 0x0D , 0x0A , 0x01 , 0x40 , 0x48 } ,
{ 0x0C , 0x09 , 0x02 , 0x20 , 0x35 } ,
{ 0x0D , 0x09 , 0x01 , 0x20 , 0x44 } ,
{ 0x0C , 0x08 , 0x02 , 0x10 , 0x31 } ,
{ 0x0D , 0x08 , 0x01 , 0x10 , 0x40 } ,
{ 0x0C , 0x0A , 0x01 , 0x20 , 0x34 } ,
{ 0x0C , 0x09 , 0x01 , 0x08 , 0x32 } ,
{ 0x0B , 0x08 , 0x02 , 0x08 , 0x21 } ,
{ 0x0C , 0x08 , 0x01 , 0x08 , 0x30 } ,
{ 0x0A , 0x08 , 0x02 , 0x04 , 0x11 } ,
{ 0x0B , 0x0A , 0x01 , 0x10 , 0x28 } ,
{ 0x09 , 0x08 , 0x02 , 0x02 , 0x01 } ,
{ 0x0B , 0x09 , 0x01 , 0x08 , 0x24 } ,
{ 0x0B , 0x08 , 0x01 , 0x04 , 0x20 } ,
{ 0x0A , 0x08 , 0x01 , 0x02 , 0x10 } ,
{ 0x09 , 0x08 , 0x01 , 0x01 , 0x00 }
} ;
2012-12-22 01:07:39 +04:00
static int sisfb_post_300_rwtest ( struct sis_video_info * ivideo , int iteration ,
int buswidth , int PseudoRankCapacity ,
int PseudoAdrPinCount , unsigned int mapsize )
2005-09-10 00:04:45 +04:00
{
2008-07-24 08:31:12 +04:00
void __iomem * FBAddr = ivideo - > video_vbase ;
2005-09-10 00:04:45 +04:00
unsigned short sr14 ;
unsigned int k , RankCapacity , PageCapacity , BankNumHigh , BankNumMid ;
unsigned int PhysicalAdrOtherPage , PhysicalAdrHigh , PhysicalAdrHalfPage ;
2012-05-04 02:14:55 +04:00
for ( k = 0 ; k < ARRAY_SIZE ( SiS_DRAMType ) ; k + + ) {
2005-09-10 00:04:45 +04:00
RankCapacity = buswidth * SiS_DRAMType [ k ] [ 3 ] ;
if ( RankCapacity ! = PseudoRankCapacity )
continue ;
if ( ( SiS_DRAMType [ k ] [ 2 ] + SiS_DRAMType [ k ] [ 0 ] ) > PseudoAdrPinCount )
continue ;
BankNumHigh = RankCapacity * 16 * iteration - 1 ;
if ( iteration = = 3 ) { /* Rank No */
BankNumMid = RankCapacity * 16 - 1 ;
} else {
BankNumMid = RankCapacity * 16 * iteration / 2 - 1 ;
}
PageCapacity = ( 1 < < SiS_DRAMType [ k ] [ 1 ] ) * buswidth * 4 ;
PhysicalAdrHigh = BankNumHigh ;
PhysicalAdrHalfPage = ( PageCapacity / 2 + PhysicalAdrHigh ) % PageCapacity ;
PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType [ k ] [ 2 ] + PhysicalAdrHigh ;
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISSR , 0x15 , 0xFB ) ; /* Test */
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISSR , 0x15 , 0x04 ) ; /* Test */
2005-09-10 00:04:45 +04:00
sr14 = ( SiS_DRAMType [ k ] [ 3 ] * buswidth ) - 1 ;
if ( buswidth = = 4 ) sr14 | = 0x80 ;
else if ( buswidth = = 2 ) sr14 | = 0x40 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , SiS_DRAMType [ k ] [ 4 ] ) ;
SiS_SetReg ( SISSR , 0x14 , sr14 ) ;
2005-09-10 00:04:45 +04:00
BankNumHigh < < = 16 ;
BankNumMid < < = 16 ;
if ( ( BankNumHigh + PhysicalAdrHigh > = mapsize ) | |
( BankNumMid + PhysicalAdrHigh > = mapsize ) | |
( BankNumHigh + PhysicalAdrHalfPage > = mapsize ) | |
( BankNumHigh + PhysicalAdrOtherPage > = mapsize ) )
continue ;
/* Write data */
writew ( ( ( unsigned short ) PhysicalAdrHigh ) ,
( FBAddr + BankNumHigh + PhysicalAdrHigh ) ) ;
writew ( ( ( unsigned short ) BankNumMid ) ,
( FBAddr + BankNumMid + PhysicalAdrHigh ) ) ;
writew ( ( ( unsigned short ) PhysicalAdrHalfPage ) ,
( FBAddr + BankNumHigh + PhysicalAdrHalfPage ) ) ;
writew ( ( ( unsigned short ) PhysicalAdrOtherPage ) ,
( FBAddr + BankNumHigh + PhysicalAdrOtherPage ) ) ;
/* Read data */
if ( readw ( FBAddr + BankNumHigh + PhysicalAdrHigh ) = = PhysicalAdrHigh )
return 1 ;
}
return 0 ;
}
2012-12-22 01:07:39 +04:00
static void sisfb_post_300_ramsize ( struct pci_dev * pdev , unsigned int mapsize )
2005-09-10 00:04:45 +04:00
{
struct sis_video_info * ivideo = pci_get_drvdata ( pdev ) ;
int i , j , buswidth ;
int PseudoRankCapacity , PseudoAdrPinCount ;
buswidth = sisfb_post_300_buswidth ( ivideo ) ;
for ( i = 6 ; i > = 0 ; i - - ) {
PseudoRankCapacity = 1 < < i ;
for ( j = 4 ; j > = 1 ; j - - ) {
PseudoAdrPinCount = 15 - j ;
if ( ( PseudoRankCapacity * j ) < = 64 ) {
if ( sisfb_post_300_rwtest ( ivideo ,
j ,
buswidth ,
PseudoRankCapacity ,
PseudoAdrPinCount ,
mapsize ) )
return ;
}
}
}
}
2012-12-22 01:07:39 +04:00
static void sisfb_post_sis300 ( struct pci_dev * pdev )
2005-09-10 00:04:45 +04:00
{
struct sis_video_info * ivideo = pci_get_drvdata ( pdev ) ;
unsigned char * bios = ivideo - > SiS_Pr . VirtualRomBase ;
u8 reg , v1 , v2 , v3 , v4 , v5 , v6 , v7 , v8 ;
u16 index , rindex , memtype = 0 ;
unsigned int mapsize ;
if ( ! ivideo - > SiS_Pr . UseROM )
bios = NULL ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x05 , 0x86 ) ;
2005-09-10 00:04:45 +04:00
if ( bios ) {
if ( bios [ 0x52 ] & 0x80 ) {
memtype = bios [ 0x52 ] ;
} else {
2010-12-21 00:50:16 +03:00
memtype = SiS_GetReg ( SISSR , 0x3a ) ;
2005-09-10 00:04:45 +04:00
}
memtype & = 0x07 ;
}
v3 = 0x80 ; v6 = 0x80 ;
if ( ivideo - > revision_id < = 0x13 ) {
v1 = 0x44 ; v2 = 0x42 ;
v4 = 0x44 ; v5 = 0x42 ;
} else {
v1 = 0x68 ; v2 = 0x43 ; /* Assume 125Mhz MCLK */
v4 = 0x68 ; v5 = 0x43 ; /* Assume 125Mhz ECLK */
if ( bios ) {
index = memtype * 5 ;
rindex = index + 0x54 ;
v1 = bios [ rindex + + ] ;
v2 = bios [ rindex + + ] ;
v3 = bios [ rindex + + ] ;
rindex = index + 0x7c ;
v4 = bios [ rindex + + ] ;
v5 = bios [ rindex + + ] ;
v6 = bios [ rindex + + ] ;
}
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x28 , v1 ) ;
SiS_SetReg ( SISSR , 0x29 , v2 ) ;
SiS_SetReg ( SISSR , 0x2a , v3 ) ;
SiS_SetReg ( SISSR , 0x2e , v4 ) ;
SiS_SetReg ( SISSR , 0x2f , v5 ) ;
SiS_SetReg ( SISSR , 0x30 , v6 ) ;
2005-09-10 00:04:45 +04:00
v1 = 0x10 ;
if ( bios )
v1 = bios [ 0xa4 ] ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x07 , v1 ) ; /* DAC speed */
2005-09-10 00:04:45 +04:00
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x11 , 0x0f ) ; /* DDC, power save */
2005-09-10 00:04:45 +04:00
v1 = 0x01 ; v2 = 0x43 ; v3 = 0x1e ; v4 = 0x2a ;
v5 = 0x06 ; v6 = 0x00 ; v7 = 0x00 ; v8 = 0x00 ;
if ( bios ) {
memtype + = 0xa5 ;
v1 = bios [ memtype ] ;
v2 = bios [ memtype + 8 ] ;
v3 = bios [ memtype + 16 ] ;
v4 = bios [ memtype + 24 ] ;
v5 = bios [ memtype + 32 ] ;
v6 = bios [ memtype + 40 ] ;
v7 = bios [ memtype + 48 ] ;
v8 = bios [ memtype + 56 ] ;
}
if ( ivideo - > revision_id > = 0x80 )
v3 & = 0xfd ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x15 , v1 ) ; /* Ram type (assuming 0, BIOS 0xa5 step 8) */
SiS_SetReg ( SISSR , 0x16 , v2 ) ;
SiS_SetReg ( SISSR , 0x17 , v3 ) ;
SiS_SetReg ( SISSR , 0x18 , v4 ) ;
SiS_SetReg ( SISSR , 0x19 , v5 ) ;
SiS_SetReg ( SISSR , 0x1a , v6 ) ;
SiS_SetReg ( SISSR , 0x1b , v7 ) ;
SiS_SetReg ( SISSR , 0x1c , v8 ) ; /* ---- */
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISSR , 0x15 , 0xfb ) ;
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISSR , 0x15 , 0x04 ) ;
2005-09-10 00:04:45 +04:00
if ( bios ) {
if ( bios [ 0x53 ] & 0x02 ) {
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISSR , 0x19 , 0x20 ) ;
2005-09-10 00:04:45 +04:00
}
}
v1 = 0x04 ; /* DAC pedestal (BIOS 0xe5) */
if ( ivideo - > revision_id > = 0x80 )
v1 | = 0x01 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x1f , v1 ) ;
SiS_SetReg ( SISSR , 0x20 , 0xa4 ) ; /* linear & relocated io & disable a0000 */
2005-09-10 00:04:45 +04:00
v1 = 0xf6 ; v2 = 0x0d ; v3 = 0x00 ;
if ( bios ) {
v1 = bios [ 0xe8 ] ;
v2 = bios [ 0xe9 ] ;
v3 = bios [ 0xea ] ;
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x23 , v1 ) ;
SiS_SetReg ( SISSR , 0x24 , v2 ) ;
SiS_SetReg ( SISSR , 0x25 , v3 ) ;
SiS_SetReg ( SISSR , 0x21 , 0x84 ) ;
SiS_SetReg ( SISSR , 0x22 , 0x00 ) ;
SiS_SetReg ( SISCR , 0x37 , 0x00 ) ;
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISPART1 , 0x24 , 0x01 ) ; /* unlock crt2 */
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART1 , 0x00 , 0x00 ) ;
2005-09-10 00:04:45 +04:00
v1 = 0x40 ; v2 = 0x11 ;
if ( bios ) {
v1 = bios [ 0xec ] ;
v2 = bios [ 0xeb ] ;
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART1 , 0x02 , v1 ) ;
2005-09-10 00:04:45 +04:00
if ( ivideo - > revision_id > = 0x80 )
v2 & = ~ 0x01 ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISPART4 , 0x00 ) ;
2005-09-10 00:04:45 +04:00
if ( ( reg = = 1 ) | | ( reg = = 2 ) ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x37 , 0x02 ) ;
SiS_SetReg ( SISPART2 , 0x00 , 0x1c ) ;
2005-09-10 00:04:45 +04:00
v4 = 0x00 ; v5 = 0x00 ; v6 = 0x10 ;
if ( ivideo - > SiS_Pr . UseROM ) {
v4 = bios [ 0xf5 ] ;
v5 = bios [ 0xf6 ] ;
v6 = bios [ 0xf7 ] ;
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART4 , 0x0d , v4 ) ;
SiS_SetReg ( SISPART4 , 0x0e , v5 ) ;
SiS_SetReg ( SISPART4 , 0x10 , v6 ) ;
SiS_SetReg ( SISPART4 , 0x0f , 0x3f ) ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISPART4 , 0x01 ) ;
2005-09-10 00:04:45 +04:00
if ( reg > = 0xb0 ) {
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISPART4 , 0x23 ) ;
2005-09-10 00:04:45 +04:00
reg & = 0x20 ;
reg < < = 1 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART4 , 0x23 , reg ) ;
2005-09-10 00:04:45 +04:00
}
} else {
v2 & = ~ 0x10 ;
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x32 , v2 ) ;
2005-09-10 00:04:45 +04:00
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISPART1 , 0x24 , 0xfe ) ; /* Lock CRT2 */
2005-09-10 00:04:45 +04:00
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISSR , 0x16 ) ;
2005-09-10 00:04:45 +04:00
reg & = 0xc3 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x35 , reg ) ;
SiS_SetReg ( SISCR , 0x83 , 0x00 ) ;
2005-09-10 00:04:45 +04:00
# if !defined(__i386__) && !defined(__x86_64__)
if ( sisfb_videoram ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0x28 ) ; /* ? */
2005-09-10 00:04:45 +04:00
reg = ( ( sisfb_videoram > > 10 ) - 1 ) | 0x40 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x14 , reg ) ;
2005-09-10 00:04:45 +04:00
} else {
# endif
/* Need to map max FB size for finding out about RAM size */
2010-11-10 14:04:19 +03:00
mapsize = ivideo - > video_size ;
2005-09-10 00:04:45 +04:00
sisfb_post_map_vram ( ivideo , & mapsize , 4 ) ;
if ( ivideo - > video_vbase ) {
sisfb_post_300_ramsize ( pdev , mapsize ) ;
iounmap ( ivideo - > video_vbase ) ;
} else {
printk ( KERN_DEBUG
" sisfb: Failed to map memory for size detection, assuming 8MB \n " ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0x28 ) ; /* ? */
SiS_SetReg ( SISSR , 0x14 , 0x47 ) ; /* 8MB, 64bit default */
2005-09-10 00:04:45 +04:00
}
# if !defined(__i386__) && !defined(__x86_64__)
}
# endif
if ( bios ) {
v1 = bios [ 0xe6 ] ;
v2 = bios [ 0xe7 ] ;
} else {
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISSR , 0x3a ) ;
2005-09-10 00:04:45 +04:00
if ( ( reg & 0x30 ) = = 0x30 ) {
v1 = 0x04 ; /* PCI */
v2 = 0x92 ;
} else {
v1 = 0x14 ; /* AGP */
v2 = 0xb2 ;
}
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x21 , v1 ) ;
SiS_SetReg ( SISSR , 0x22 , v2 ) ;
2005-09-10 00:04:45 +04:00
/* Sense CRT1 */
sisfb_sense_crt1 ( ivideo ) ;
/* Set default mode, don't clear screen */
2007-02-12 11:55:06 +03:00
ivideo - > SiS_Pr . SiS_UseOEM = false ;
SiS_SetEnableDstn ( & ivideo - > SiS_Pr , false ) ;
SiS_SetEnableFstn ( & ivideo - > SiS_Pr , false ) ;
2005-09-10 00:04:45 +04:00
ivideo - > curFSTN = ivideo - > curDSTN = 0 ;
ivideo - > SiS_Pr . VideoMemorySize = 8 < < 20 ;
SiSSetMode ( & ivideo - > SiS_Pr , 0x2e | 0x80 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x05 , 0x86 ) ;
2005-09-10 00:04:45 +04:00
/* Display off */
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISSR , 0x01 , 0x20 ) ;
2005-09-10 00:04:45 +04:00
/* Save mode number in CR34 */
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x34 , 0x2e ) ;
2005-09-10 00:04:45 +04:00
/* Let everyone know what the current mode is */
ivideo - > modeprechange = 0x2e ;
}
# endif
# ifdef CONFIG_FB_SIS_315
#if 0
2012-12-22 01:07:39 +04:00
static void sisfb_post_sis315330 ( struct pci_dev * pdev )
2005-09-10 00:04:45 +04:00
{
/* TODO */
}
# endif
2011-02-14 01:11:25 +03:00
static inline int sisfb_xgi_is21 ( struct sis_video_info * ivideo )
{
return ivideo - > chip_real_id = = XGI_21 ;
}
2012-12-22 01:07:39 +04:00
static void sisfb_post_xgi_delay ( struct sis_video_info * ivideo , int delay )
2005-09-10 00:04:45 +04:00
{
unsigned int i ;
u8 reg ;
for ( i = 0 ; i < = ( delay * 10 * 36 ) ; i + + ) {
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISSR , 0x05 ) ;
2005-09-10 00:04:45 +04:00
reg + + ;
}
}
2012-12-22 01:07:39 +04:00
static int sisfb_find_host_bridge ( struct sis_video_info * ivideo ,
struct pci_dev * mypdev ,
unsigned short pcivendor )
2005-09-10 00:04:45 +04:00
{
struct pci_dev * pdev = NULL ;
unsigned short temp ;
int ret = 0 ;
2007-05-08 11:39:50 +04:00
while ( ( pdev = pci_get_class ( PCI_CLASS_BRIDGE_HOST , pdev ) ) ) {
2005-09-10 00:04:45 +04:00
temp = pdev - > vendor ;
if ( temp = = pcivendor ) {
ret = 1 ;
2008-02-06 12:39:07 +03:00
pci_dev_put ( pdev ) ;
2005-09-10 00:04:45 +04:00
break ;
}
}
return ret ;
}
2012-12-22 01:07:39 +04:00
static int sisfb_post_xgi_rwtest ( struct sis_video_info * ivideo , int starta ,
unsigned int enda , unsigned int mapsize )
2005-09-10 00:04:45 +04:00
{
unsigned int pos ;
int i ;
writel ( 0 , ivideo - > video_vbase ) ;
for ( i = starta ; i < = enda ; i + + ) {
pos = 1 < < i ;
if ( pos < mapsize )
writel ( pos , ivideo - > video_vbase + pos ) ;
}
sisfb_post_xgi_delay ( ivideo , 150 ) ;
if ( readl ( ivideo - > video_vbase ) ! = 0 )
return 0 ;
for ( i = starta ; i < = enda ; i + + ) {
pos = 1 < < i ;
if ( pos < mapsize ) {
if ( readl ( ivideo - > video_vbase + pos ) ! = pos )
return 0 ;
} else
return 0 ;
}
return 1 ;
}
2012-12-22 01:07:39 +04:00
static int sisfb_post_xgi_ramsize ( struct sis_video_info * ivideo )
2005-09-10 00:04:45 +04:00
{
unsigned int buswidth , ranksize , channelab , mapsize ;
2011-02-14 01:11:23 +03:00
int i , j , k , l , status ;
2005-09-10 00:04:45 +04:00
u8 reg , sr14 ;
static const u8 dramsr13 [ 12 * 5 ] = {
0x02 , 0x0e , 0x0b , 0x80 , 0x5d ,
0x02 , 0x0e , 0x0a , 0x40 , 0x59 ,
0x02 , 0x0d , 0x0b , 0x40 , 0x4d ,
0x02 , 0x0e , 0x09 , 0x20 , 0x55 ,
0x02 , 0x0d , 0x0a , 0x20 , 0x49 ,
0x02 , 0x0c , 0x0b , 0x20 , 0x3d ,
0x02 , 0x0e , 0x08 , 0x10 , 0x51 ,
0x02 , 0x0d , 0x09 , 0x10 , 0x45 ,
0x02 , 0x0c , 0x0a , 0x10 , 0x39 ,
0x02 , 0x0d , 0x08 , 0x08 , 0x41 ,
0x02 , 0x0c , 0x09 , 0x08 , 0x35 ,
0x02 , 0x0c , 0x08 , 0x04 , 0x31
} ;
static const u8 dramsr13_4 [ 4 * 5 ] = {
0x02 , 0x0d , 0x09 , 0x40 , 0x45 ,
0x02 , 0x0c , 0x09 , 0x20 , 0x35 ,
0x02 , 0x0c , 0x08 , 0x10 , 0x31 ,
0x02 , 0x0b , 0x08 , 0x08 , 0x21
} ;
/* Enable linear mode, disable 0xa0000 address decoding */
/* We disable a0000 address decoding, because
* - if running on x86 , if the card is disabled , it means
* that another card is in the system . We don ' t want
* to interphere with that primary card ' s textmode .
* - if running on non - x86 , there usually is no VGA window
* at a0000 .
*/
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISSR , 0x20 , ( 0x80 | 0x04 ) ) ;
2005-09-10 00:04:45 +04:00
/* Need to map max FB size for finding out about RAM size */
2010-11-10 14:04:19 +03:00
mapsize = ivideo - > video_size ;
2005-09-10 00:04:45 +04:00
sisfb_post_map_vram ( ivideo , & mapsize , 32 ) ;
if ( ! ivideo - > video_vbase ) {
printk ( KERN_ERR " sisfb: Unable to detect RAM size. Setting default. \n " ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0x35 ) ;
SiS_SetReg ( SISSR , 0x14 , 0x41 ) ;
2005-09-10 00:04:45 +04:00
/* TODO */
2011-02-14 01:11:23 +03:00
return - ENOMEM ;
2005-09-10 00:04:45 +04:00
}
/* Non-interleaving */
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x15 , 0x00 ) ;
2005-09-10 00:04:45 +04:00
/* No tiling */
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x1c , 0x00 ) ;
2005-09-10 00:04:45 +04:00
if ( ivideo - > chip = = XGI_20 ) {
channelab = 1 ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0x97 ) ;
2005-09-10 00:04:45 +04:00
if ( ! ( reg & 0x01 ) ) { /* Single 32/16 */
buswidth = 32 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0xb1 ) ;
SiS_SetReg ( SISSR , 0x14 , 0x52 ) ;
2005-09-10 00:04:45 +04:00
sisfb_post_xgi_delay ( ivideo , 1 ) ;
sr14 = 0x02 ;
if ( sisfb_post_xgi_rwtest ( ivideo , 23 , 24 , mapsize ) )
goto bail_out ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0x31 ) ;
SiS_SetReg ( SISSR , 0x14 , 0x42 ) ;
2005-09-10 00:04:45 +04:00
sisfb_post_xgi_delay ( ivideo , 1 ) ;
if ( sisfb_post_xgi_rwtest ( ivideo , 23 , 23 , mapsize ) )
goto bail_out ;
buswidth = 16 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0xb1 ) ;
SiS_SetReg ( SISSR , 0x14 , 0x41 ) ;
2005-09-10 00:04:45 +04:00
sisfb_post_xgi_delay ( ivideo , 1 ) ;
sr14 = 0x01 ;
if ( sisfb_post_xgi_rwtest ( ivideo , 22 , 23 , mapsize ) )
goto bail_out ;
else
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0x31 ) ;
2005-09-10 00:04:45 +04:00
} else { /* Dual 16/8 */
buswidth = 16 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0xb1 ) ;
SiS_SetReg ( SISSR , 0x14 , 0x41 ) ;
2005-09-10 00:04:45 +04:00
sisfb_post_xgi_delay ( ivideo , 1 ) ;
sr14 = 0x01 ;
if ( sisfb_post_xgi_rwtest ( ivideo , 22 , 23 , mapsize ) )
goto bail_out ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0x31 ) ;
SiS_SetReg ( SISSR , 0x14 , 0x31 ) ;
2005-09-10 00:04:45 +04:00
sisfb_post_xgi_delay ( ivideo , 1 ) ;
if ( sisfb_post_xgi_rwtest ( ivideo , 22 , 22 , mapsize ) )
goto bail_out ;
buswidth = 8 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0xb1 ) ;
SiS_SetReg ( SISSR , 0x14 , 0x30 ) ;
2005-09-10 00:04:45 +04:00
sisfb_post_xgi_delay ( ivideo , 1 ) ;
sr14 = 0x00 ;
if ( sisfb_post_xgi_rwtest ( ivideo , 21 , 22 , mapsize ) )
goto bail_out ;
else
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0x31 ) ;
2005-09-10 00:04:45 +04:00
}
} else { /* XGI_40 */
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0x97 ) ;
2005-09-10 00:04:45 +04:00
if ( ! ( reg & 0x10 ) ) {
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISSR , 0x39 ) ;
2005-09-10 00:04:45 +04:00
reg > > = 1 ;
}
if ( reg & 0x01 ) { /* DDRII */
buswidth = 32 ;
if ( ivideo - > revision_id = = 2 ) {
channelab = 2 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0xa1 ) ;
SiS_SetReg ( SISSR , 0x14 , 0x44 ) ;
2005-09-10 00:04:45 +04:00
sr14 = 0x04 ;
sisfb_post_xgi_delay ( ivideo , 1 ) ;
if ( sisfb_post_xgi_rwtest ( ivideo , 23 , 24 , mapsize ) )
goto bail_out ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0x21 ) ;
SiS_SetReg ( SISSR , 0x14 , 0x34 ) ;
2005-09-10 00:04:45 +04:00
if ( sisfb_post_xgi_rwtest ( ivideo , 22 , 23 , mapsize ) )
goto bail_out ;
channelab = 1 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0xa1 ) ;
SiS_SetReg ( SISSR , 0x14 , 0x40 ) ;
2005-09-10 00:04:45 +04:00
sr14 = 0x00 ;
if ( sisfb_post_xgi_rwtest ( ivideo , 22 , 23 , mapsize ) )
goto bail_out ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0x21 ) ;
SiS_SetReg ( SISSR , 0x14 , 0x30 ) ;
2005-09-10 00:04:45 +04:00
} else {
channelab = 3 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0xa1 ) ;
SiS_SetReg ( SISSR , 0x14 , 0x4c ) ;
2005-09-10 00:04:45 +04:00
sr14 = 0x0c ;
sisfb_post_xgi_delay ( ivideo , 1 ) ;
if ( sisfb_post_xgi_rwtest ( ivideo , 23 , 25 , mapsize ) )
goto bail_out ;
channelab = 2 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x14 , 0x48 ) ;
2005-09-10 00:04:45 +04:00
sisfb_post_xgi_delay ( ivideo , 1 ) ;
sr14 = 0x08 ;
if ( sisfb_post_xgi_rwtest ( ivideo , 23 , 24 , mapsize ) )
goto bail_out ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0x21 ) ;
SiS_SetReg ( SISSR , 0x14 , 0x3c ) ;
2005-09-10 00:04:45 +04:00
sr14 = 0x0c ;
if ( sisfb_post_xgi_rwtest ( ivideo , 23 , 24 , mapsize ) ) {
channelab = 3 ;
} else {
channelab = 2 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x14 , 0x38 ) ;
2005-09-10 00:04:45 +04:00
sr14 = 0x08 ;
}
}
sisfb_post_xgi_delay ( ivideo , 1 ) ;
} else { /* DDR */
buswidth = 64 ;
if ( ivideo - > revision_id = = 2 ) {
channelab = 1 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0xa1 ) ;
SiS_SetReg ( SISSR , 0x14 , 0x52 ) ;
2005-09-10 00:04:45 +04:00
sisfb_post_xgi_delay ( ivideo , 1 ) ;
sr14 = 0x02 ;
if ( sisfb_post_xgi_rwtest ( ivideo , 23 , 24 , mapsize ) )
goto bail_out ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0x21 ) ;
SiS_SetReg ( SISSR , 0x14 , 0x42 ) ;
2005-09-10 00:04:45 +04:00
} else {
channelab = 2 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0xa1 ) ;
SiS_SetReg ( SISSR , 0x14 , 0x5a ) ;
2005-09-10 00:04:45 +04:00
sisfb_post_xgi_delay ( ivideo , 1 ) ;
sr14 = 0x0a ;
if ( sisfb_post_xgi_rwtest ( ivideo , 24 , 25 , mapsize ) )
goto bail_out ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , 0x21 ) ;
SiS_SetReg ( SISSR , 0x14 , 0x4a ) ;
2005-09-10 00:04:45 +04:00
}
sisfb_post_xgi_delay ( ivideo , 1 ) ;
}
}
bail_out :
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISSR , 0x14 , 0xf0 , sr14 ) ;
2005-09-10 00:04:45 +04:00
sisfb_post_xgi_delay ( ivideo , 1 ) ;
j = ( ivideo - > chip = = XGI_20 ) ? 5 : 9 ;
k = ( ivideo - > chip = = XGI_20 ) ? 12 : 4 ;
2011-02-14 01:11:23 +03:00
status = - EIO ;
2005-09-10 00:04:45 +04:00
for ( i = 0 ; i < k ; i + + ) {
reg = ( ivideo - > chip = = XGI_20 ) ?
dramsr13 [ ( i * 5 ) + 4 ] : dramsr13_4 [ ( i * 5 ) + 4 ] ;
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISSR , 0x13 , 0x80 , reg ) ;
2005-09-10 00:04:45 +04:00
sisfb_post_xgi_delay ( ivideo , 50 ) ;
ranksize = ( ivideo - > chip = = XGI_20 ) ?
dramsr13 [ ( i * 5 ) + 3 ] : dramsr13_4 [ ( i * 5 ) + 3 ] ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISSR , 0x13 ) ;
2005-09-10 00:04:45 +04:00
if ( reg & 0x80 ) ranksize < < = 1 ;
if ( ivideo - > chip = = XGI_20 ) {
if ( buswidth = = 16 ) ranksize < < = 1 ;
else if ( buswidth = = 32 ) ranksize < < = 2 ;
} else {
if ( buswidth = = 64 ) ranksize < < = 1 ;
}
reg = 0 ;
l = channelab ;
if ( l = = 3 ) l = 4 ;
if ( ( ranksize * l ) < = 256 ) {
while ( ( ranksize > > = 1 ) ) reg + = 0x10 ;
}
if ( ! reg ) continue ;
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISSR , 0x14 , 0x0f , ( reg & 0xf0 ) ) ;
2005-09-10 00:04:45 +04:00
sisfb_post_xgi_delay ( ivideo , 1 ) ;
2011-02-14 01:11:23 +03:00
if ( sisfb_post_xgi_rwtest ( ivideo , j , ( ( reg > > 4 ) + channelab - 2 + 20 ) , mapsize ) ) {
status = 0 ;
2005-09-10 00:04:45 +04:00
break ;
2011-02-14 01:11:23 +03:00
}
2005-09-10 00:04:45 +04:00
}
iounmap ( ivideo - > video_vbase ) ;
2011-02-14 01:11:23 +03:00
return status ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
2012-12-22 01:07:39 +04:00
static void sisfb_post_xgi_setclocks ( struct sis_video_info * ivideo , u8 regb )
2005-09-10 00:04:45 +04:00
{
u8 v1 , v2 , v3 ;
int index ;
static const u8 cs90 [ 8 * 3 ] = {
0x16 , 0x01 , 0x01 ,
0x3e , 0x03 , 0x01 ,
0x7c , 0x08 , 0x01 ,
0x79 , 0x06 , 0x01 ,
0x29 , 0x01 , 0x81 ,
0x5c , 0x23 , 0x01 ,
0x5c , 0x23 , 0x01 ,
0x5c , 0x23 , 0x01
} ;
static const u8 csb8 [ 8 * 3 ] = {
0x5c , 0x23 , 0x01 ,
0x29 , 0x01 , 0x01 ,
0x7c , 0x08 , 0x01 ,
0x79 , 0x06 , 0x01 ,
0x29 , 0x01 , 0x81 ,
0x5c , 0x23 , 0x01 ,
0x5c , 0x23 , 0x01 ,
0x5c , 0x23 , 0x01
} ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
regb = 0 ; /* ! */
index = regb * 3 ;
v1 = cs90 [ index ] ; v2 = cs90 [ index + 1 ] ; v3 = cs90 [ index + 2 ] ;
if ( ivideo - > haveXGIROM ) {
v1 = ivideo - > bios_abase [ 0x90 + index ] ;
v2 = ivideo - > bios_abase [ 0x90 + index + 1 ] ;
v3 = ivideo - > bios_abase [ 0x90 + index + 2 ] ;
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x28 , v1 ) ;
SiS_SetReg ( SISSR , 0x29 , v2 ) ;
SiS_SetReg ( SISSR , 0x2a , v3 ) ;
2005-09-10 00:04:45 +04:00
sisfb_post_xgi_delay ( ivideo , 0x43 ) ;
sisfb_post_xgi_delay ( ivideo , 0x43 ) ;
sisfb_post_xgi_delay ( ivideo , 0x43 ) ;
index = regb * 3 ;
v1 = csb8 [ index ] ; v2 = csb8 [ index + 1 ] ; v3 = csb8 [ index + 2 ] ;
if ( ivideo - > haveXGIROM ) {
v1 = ivideo - > bios_abase [ 0xb8 + index ] ;
v2 = ivideo - > bios_abase [ 0xb8 + index + 1 ] ;
v3 = ivideo - > bios_abase [ 0xb8 + index + 2 ] ;
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x2e , v1 ) ;
SiS_SetReg ( SISSR , 0x2f , v2 ) ;
SiS_SetReg ( SISSR , 0x30 , v3 ) ;
2005-09-10 00:04:45 +04:00
sisfb_post_xgi_delay ( ivideo , 0x43 ) ;
sisfb_post_xgi_delay ( ivideo , 0x43 ) ;
sisfb_post_xgi_delay ( ivideo , 0x43 ) ;
2005-04-17 02:20:36 +04:00
}
2012-12-22 01:07:39 +04:00
static void sisfb_post_xgi_ddr2_mrs_default ( struct sis_video_info * ivideo ,
u8 regb )
2011-02-14 01:11:27 +03:00
{
unsigned char * bios = ivideo - > bios_abase ;
u8 v1 ;
SiS_SetReg ( SISSR , 0x28 , 0x64 ) ;
SiS_SetReg ( SISSR , 0x29 , 0x63 ) ;
sisfb_post_xgi_delay ( ivideo , 15 ) ;
SiS_SetReg ( SISSR , 0x18 , 0x00 ) ;
SiS_SetReg ( SISSR , 0x19 , 0x20 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x00 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x80 ) ;
SiS_SetReg ( SISSR , 0x18 , 0xc5 ) ;
SiS_SetReg ( SISSR , 0x19 , 0x23 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x00 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x80 ) ;
sisfb_post_xgi_delay ( ivideo , 1 ) ;
SiS_SetReg ( SISCR , 0x97 , 0x11 ) ;
sisfb_post_xgi_setclocks ( ivideo , regb ) ;
sisfb_post_xgi_delay ( ivideo , 0x46 ) ;
SiS_SetReg ( SISSR , 0x18 , 0xc5 ) ;
SiS_SetReg ( SISSR , 0x19 , 0x23 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x00 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x80 ) ;
sisfb_post_xgi_delay ( ivideo , 1 ) ;
SiS_SetReg ( SISSR , 0x1b , 0x04 ) ;
sisfb_post_xgi_delay ( ivideo , 1 ) ;
SiS_SetReg ( SISSR , 0x1b , 0x00 ) ;
sisfb_post_xgi_delay ( ivideo , 1 ) ;
v1 = 0x31 ;
if ( ivideo - > haveXGIROM ) {
v1 = bios [ 0xf0 ] ;
}
SiS_SetReg ( SISSR , 0x18 , v1 ) ;
SiS_SetReg ( SISSR , 0x19 , 0x06 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x04 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x84 ) ;
sisfb_post_xgi_delay ( ivideo , 1 ) ;
}
2012-12-22 01:07:39 +04:00
static void sisfb_post_xgi_ddr2_mrs_xg21 ( struct sis_video_info * ivideo )
2011-02-14 01:11:28 +03:00
{
sisfb_post_xgi_setclocks ( ivideo , 1 ) ;
SiS_SetReg ( SISCR , 0x97 , 0x11 ) ;
sisfb_post_xgi_delay ( ivideo , 0x46 ) ;
SiS_SetReg ( SISSR , 0x18 , 0x00 ) ; /* EMRS2 */
SiS_SetReg ( SISSR , 0x19 , 0x80 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x05 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x85 ) ;
SiS_SetReg ( SISSR , 0x18 , 0x00 ) ; /* EMRS3 */
SiS_SetReg ( SISSR , 0x19 , 0xc0 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x05 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x85 ) ;
SiS_SetReg ( SISSR , 0x18 , 0x00 ) ; /* EMRS1 */
SiS_SetReg ( SISSR , 0x19 , 0x40 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x05 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x85 ) ;
SiS_SetReg ( SISSR , 0x18 , 0x42 ) ; /* MRS1 */
SiS_SetReg ( SISSR , 0x19 , 0x02 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x05 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x85 ) ;
sisfb_post_xgi_delay ( ivideo , 1 ) ;
SiS_SetReg ( SISSR , 0x1b , 0x04 ) ;
sisfb_post_xgi_delay ( ivideo , 1 ) ;
SiS_SetReg ( SISSR , 0x1b , 0x00 ) ;
sisfb_post_xgi_delay ( ivideo , 1 ) ;
SiS_SetReg ( SISSR , 0x18 , 0x42 ) ; /* MRS1 */
SiS_SetReg ( SISSR , 0x19 , 0x00 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x05 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x85 ) ;
sisfb_post_xgi_delay ( ivideo , 1 ) ;
}
2012-12-22 01:07:39 +04:00
static void sisfb_post_xgi_ddr2 ( struct sis_video_info * ivideo , u8 regb )
2011-02-14 01:11:27 +03:00
{
unsigned char * bios = ivideo - > bios_abase ;
static const u8 cs158 [ 8 ] = {
0x88 , 0xaa , 0x48 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
} ;
static const u8 cs160 [ 8 ] = {
0x44 , 0x77 , 0x77 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
} ;
static const u8 cs168 [ 8 ] = {
0x48 , 0x78 , 0x88 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
} ;
u8 reg ;
u8 v1 ;
u8 v2 ;
u8 v3 ;
2011-02-14 01:11:28 +03:00
SiS_SetReg ( SISCR , 0xb0 , 0x80 ) ; /* DDR2 dual frequency mode */
2011-02-14 01:11:27 +03:00
SiS_SetReg ( SISCR , 0x82 , 0x77 ) ;
SiS_SetReg ( SISCR , 0x86 , 0x00 ) ;
reg = SiS_GetReg ( SISCR , 0x86 ) ;
SiS_SetReg ( SISCR , 0x86 , 0x88 ) ;
reg = SiS_GetReg ( SISCR , 0x86 ) ;
v1 = cs168 [ regb ] ; v2 = cs160 [ regb ] ; v3 = cs158 [ regb ] ;
if ( ivideo - > haveXGIROM ) {
v1 = bios [ regb + 0x168 ] ;
v2 = bios [ regb + 0x160 ] ;
v3 = bios [ regb + 0x158 ] ;
}
SiS_SetReg ( SISCR , 0x86 , v1 ) ;
SiS_SetReg ( SISCR , 0x82 , 0x77 ) ;
SiS_SetReg ( SISCR , 0x85 , 0x00 ) ;
reg = SiS_GetReg ( SISCR , 0x85 ) ;
SiS_SetReg ( SISCR , 0x85 , 0x88 ) ;
reg = SiS_GetReg ( SISCR , 0x85 ) ;
SiS_SetReg ( SISCR , 0x85 , v2 ) ;
SiS_SetReg ( SISCR , 0x82 , v3 ) ;
SiS_SetReg ( SISCR , 0x98 , 0x01 ) ;
SiS_SetReg ( SISCR , 0x9a , 0x02 ) ;
2011-02-14 01:11:28 +03:00
if ( sisfb_xgi_is21 ( ivideo ) )
sisfb_post_xgi_ddr2_mrs_xg21 ( ivideo ) ;
else
sisfb_post_xgi_ddr2_mrs_default ( ivideo , regb ) ;
2011-02-14 01:11:27 +03:00
}
2012-12-22 01:07:39 +04:00
static u8 sisfb_post_xgi_ramtype ( struct sis_video_info * ivideo )
2011-02-14 01:11:24 +03:00
{
unsigned char * bios = ivideo - > bios_abase ;
u8 ramtype ;
u8 reg ;
u8 v1 ;
ramtype = 0x00 ; v1 = 0x10 ;
if ( ivideo - > haveXGIROM ) {
ramtype = bios [ 0x62 ] ;
v1 = bios [ 0x1d2 ] ;
}
if ( ! ( ramtype & 0x80 ) ) {
2011-02-14 01:11:26 +03:00
if ( sisfb_xgi_is21 ( ivideo ) ) {
SiS_SetRegAND ( SISCR , 0xb4 , 0xfd ) ; /* GPIO control */
SiS_SetRegOR ( SISCR , 0x4a , 0x80 ) ; /* GPIOH EN */
reg = SiS_GetReg ( SISCR , 0x48 ) ;
SiS_SetRegOR ( SISCR , 0xb4 , 0x02 ) ;
ramtype = reg & 0x01 ; /* GPIOH */
} else if ( ivideo - > chip = = XGI_20 ) {
2011-02-14 01:11:24 +03:00
SiS_SetReg ( SISCR , 0x97 , v1 ) ;
reg = SiS_GetReg ( SISCR , 0x97 ) ;
if ( reg & 0x10 ) {
ramtype = ( reg & 0x01 ) < < 1 ;
}
} else {
reg = SiS_GetReg ( SISSR , 0x39 ) ;
ramtype = reg & 0x02 ;
if ( ! ( ramtype ) ) {
reg = SiS_GetReg ( SISSR , 0x3a ) ;
ramtype = ( reg > > 1 ) & 0x01 ;
}
}
}
ramtype & = 0x07 ;
return ramtype ;
}
2012-12-22 01:07:39 +04:00
static int sisfb_post_xgi ( struct pci_dev * pdev )
2005-04-17 02:20:36 +04:00
{
struct sis_video_info * ivideo = pci_get_drvdata ( pdev ) ;
2005-09-10 00:04:45 +04:00
unsigned char * bios = ivideo - > bios_abase ;
struct pci_dev * mypdev = NULL ;
const u8 * ptr , * ptr2 ;
u8 v1 , v2 , v3 , v4 , v5 , reg , ramtype ;
u32 rega , regb , regd ;
int i , j , k , index ;
static const u8 cs78 [ 3 ] = { 0xf6 , 0x0d , 0x00 } ;
static const u8 cs76 [ 2 ] = { 0xa3 , 0xfb } ;
static const u8 cs7b [ 3 ] = { 0xc0 , 0x11 , 0x00 } ;
static const u8 cs158 [ 8 ] = {
0x88 , 0xaa , 0x48 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
} ;
static const u8 cs160 [ 8 ] = {
0x44 , 0x77 , 0x77 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
} ;
static const u8 cs168 [ 8 ] = {
0x48 , 0x78 , 0x88 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
} ;
static const u8 cs128 [ 3 * 8 ] = {
0x90 , 0x28 , 0x24 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x77 , 0x44 , 0x44 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x77 , 0x44 , 0x44 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
} ;
static const u8 cs148 [ 2 * 8 ] = {
0x55 , 0x55 , 0x55 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
} ;
static const u8 cs31a [ 8 * 4 ] = {
0xaa , 0xaa , 0xaa , 0xaa , 0xaa , 0xaa , 0xaa , 0xaa ,
0xaa , 0xaa , 0xaa , 0xaa , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
} ;
static const u8 cs33a [ 8 * 4 ] = {
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
} ;
static const u8 cs45a [ 8 * 2 ] = {
0x00 , 0x00 , 0xa0 , 0x00 , 0xa0 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
} ;
static const u8 cs170 [ 7 * 8 ] = {
0x54 , 0x32 , 0x44 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x54 , 0x43 , 0x44 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x0a , 0x05 , 0x07 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x44 , 0x34 , 0x44 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x10 , 0x0a , 0x0a , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x11 , 0x0c , 0x0c , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x05 , 0x05 , 0x05 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
} ;
static const u8 cs1a8 [ 3 * 8 ] = {
0xf0 , 0xf0 , 0xf0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x05 , 0x02 , 0x02 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
} ;
static const u8 cs100 [ 2 * 8 ] = {
0xc4 , 0x04 , 0x84 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0xc4 , 0x04 , 0x84 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
} ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* VGA enable */
2010-12-21 00:50:14 +03:00
reg = SiS_GetRegByte ( SISVGAENABLE ) | 0x01 ;
2010-12-21 00:50:15 +03:00
SiS_SetRegByte ( SISVGAENABLE , reg ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* Misc */
2010-12-21 00:50:14 +03:00
reg = SiS_GetRegByte ( SISMISCR ) | 0x01 ;
2010-12-21 00:50:15 +03:00
SiS_SetRegByte ( SISMISCW , reg ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* Unlock SR */
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x05 , 0x86 ) ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISSR , 0x05 ) ;
2005-09-10 00:04:45 +04:00
if ( reg ! = 0xa1 )
return 0 ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* Clear some regs */
for ( i = 0 ; i < 0x22 ; i + + ) {
if ( 0x06 + i = = 0x20 ) continue ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x06 + i , 0x00 ) ;
2005-09-10 00:04:45 +04:00
}
for ( i = 0 ; i < 0x0b ; i + + ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x31 + i , 0x00 ) ;
2005-09-10 00:04:45 +04:00
}
for ( i = 0 ; i < 0x10 ; i + + ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x30 + i , 0x00 ) ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
ptr = cs78 ;
if ( ivideo - > haveXGIROM ) {
ptr = ( const u8 * ) & bios [ 0x78 ] ;
}
for ( i = 0 ; i < 3 ; i + + ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x23 + i , ptr [ i ] ) ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
ptr = cs76 ;
if ( ivideo - > haveXGIROM ) {
ptr = ( const u8 * ) & bios [ 0x76 ] ;
}
for ( i = 0 ; i < 2 ; i + + ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x21 + i , ptr [ i ] ) ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
v1 = 0x18 ; v2 = 0x00 ;
if ( ivideo - > haveXGIROM ) {
v1 = bios [ 0x74 ] ;
v2 = bios [ 0x75 ] ;
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x07 , v1 ) ;
SiS_SetReg ( SISSR , 0x11 , 0x0f ) ;
SiS_SetReg ( SISSR , 0x1f , v2 ) ;
2005-09-10 00:04:45 +04:00
/* PCI linear mode, RelIO enabled, A0000 decoding disabled */
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x20 , 0x80 | 0x20 | 0x04 ) ;
SiS_SetReg ( SISSR , 0x27 , 0x74 ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
ptr = cs7b ;
if ( ivideo - > haveXGIROM ) {
ptr = ( const u8 * ) & bios [ 0x7b ] ;
}
for ( i = 0 ; i < 3 ; i + + ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x31 + i , ptr [ i ] ) ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ivideo - > chip = = XGI_40 ) {
if ( ivideo - > revision_id = = 2 ) {
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISSR , 0x3b , 0x3f , 0xc0 ) ;
2005-09-10 00:04:45 +04:00
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x7d , 0xfe ) ;
SiS_SetReg ( SISCR , 0x7e , 0x0f ) ;
2005-09-10 00:04:45 +04:00
}
if ( ivideo - > revision_id = = 0 ) { /* 40 *and* 20? */
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISCR , 0x58 , 0xd7 ) ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0xcb ) ;
2005-09-10 00:04:45 +04:00
if ( reg & 0x20 ) {
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISCR , 0x58 , 0xd7 , ( reg & 0x10 ) ? 0x08 : 0x20 ) ; /* =0x28 Z7 ? */
2005-09-10 00:04:45 +04:00
}
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
reg = ( ivideo - > chip = = XGI_40 ) ? 0x20 : 0x00 ;
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISCR , 0x38 , 0x1f , reg ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ivideo - > chip = = XGI_20 ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x36 , 0x70 ) ;
2005-09-10 00:04:45 +04:00
} else {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISVID , 0x00 , 0x86 ) ;
SiS_SetReg ( SISVID , 0x32 , 0x00 ) ;
SiS_SetReg ( SISVID , 0x30 , 0x00 ) ;
SiS_SetReg ( SISVID , 0x32 , 0x01 ) ;
SiS_SetReg ( SISVID , 0x30 , 0x00 ) ;
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISVID , 0x2f , 0xdf ) ;
SiS_SetRegAND ( SISCAP , 0x00 , 0x3f ) ;
2005-09-10 00:04:45 +04:00
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART1 , 0x2f , 0x01 ) ;
SiS_SetReg ( SISPART1 , 0x00 , 0x00 ) ;
SiS_SetReg ( SISPART1 , 0x02 , bios [ 0x7e ] ) ;
SiS_SetReg ( SISPART1 , 0x2e , 0x08 ) ;
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISPART1 , 0x35 , 0x7f ) ;
SiS_SetRegAND ( SISPART1 , 0x50 , 0xfe ) ;
2005-09-10 00:04:45 +04:00
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISPART4 , 0x00 ) ;
2005-09-10 00:04:45 +04:00
if ( reg = = 1 | | reg = = 2 ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART2 , 0x00 , 0x1c ) ;
SiS_SetReg ( SISPART4 , 0x0d , bios [ 0x7f ] ) ;
SiS_SetReg ( SISPART4 , 0x0e , bios [ 0x80 ] ) ;
SiS_SetReg ( SISPART4 , 0x10 , bios [ 0x81 ] ) ;
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISPART4 , 0x0f , 0x3f ) ;
2005-09-10 00:04:45 +04:00
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISPART4 , 0x01 ) ;
2005-09-10 00:04:45 +04:00
if ( ( reg & 0xf0 ) > = 0xb0 ) {
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISPART4 , 0x23 ) ;
2005-09-10 00:04:45 +04:00
if ( reg & 0x20 ) reg | = 0x40 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISPART4 , 0x23 , reg ) ;
2005-09-10 00:04:45 +04:00
reg = ( reg & 0x20 ) ? 0x02 : 0x00 ;
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISPART1 , 0x1e , 0xfd , reg ) ;
2005-09-10 00:04:45 +04:00
}
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
v1 = bios [ 0x77 ] ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISSR , 0x3b ) ;
2005-09-10 00:04:45 +04:00
if ( reg & 0x02 ) {
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISSR , 0x3a ) ;
2005-09-10 00:04:45 +04:00
v2 = ( reg & 0x30 ) > > 3 ;
if ( ! ( v2 & 0x04 ) ) v2 ^ = 0x02 ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISSR , 0x39 ) ;
2005-09-10 00:04:45 +04:00
if ( reg & 0x80 ) v2 | = 0x80 ;
v2 | = 0x01 ;
2007-05-08 11:39:50 +04:00
if ( ( mypdev = pci_get_device ( PCI_VENDOR_ID_SI , 0x0730 , NULL ) ) ) {
pci_dev_put ( mypdev ) ;
2005-09-10 00:04:45 +04:00
if ( ( ( v2 & 0x06 ) = = 2 ) | | ( ( v2 & 0x06 ) = = 4 ) )
v2 & = 0xf9 ;
v2 | = 0x08 ;
v1 & = 0xfe ;
} else {
2007-05-08 11:39:50 +04:00
mypdev = pci_get_device ( PCI_VENDOR_ID_SI , 0x0735 , NULL ) ;
2005-09-10 00:04:45 +04:00
if ( ! mypdev )
2007-05-08 11:39:50 +04:00
mypdev = pci_get_device ( PCI_VENDOR_ID_SI , 0x0645 , NULL ) ;
2005-09-10 00:04:45 +04:00
if ( ! mypdev )
2007-05-08 11:39:50 +04:00
mypdev = pci_get_device ( PCI_VENDOR_ID_SI , 0x0650 , NULL ) ;
2005-09-10 00:04:45 +04:00
if ( mypdev ) {
pci_read_config_dword ( mypdev , 0x94 , & regd ) ;
regd & = 0xfffffeff ;
pci_write_config_dword ( mypdev , 0x94 , regd ) ;
v1 & = 0xfe ;
2007-05-08 11:39:50 +04:00
pci_dev_put ( mypdev ) ;
2005-09-10 00:04:45 +04:00
} else if ( sisfb_find_host_bridge ( ivideo , pdev , PCI_VENDOR_ID_SI ) ) {
v1 & = 0xfe ;
} else if ( sisfb_find_host_bridge ( ivideo , pdev , 0x1106 ) | |
sisfb_find_host_bridge ( ivideo , pdev , 0x1022 ) | |
sisfb_find_host_bridge ( ivideo , pdev , 0x700e ) | |
sisfb_find_host_bridge ( ivideo , pdev , 0x10de ) ) {
if ( ( v2 & 0x06 ) = = 4 )
v2 ^ = 0x06 ;
v2 | = 0x08 ;
}
}
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISCR , 0x5f , 0xf0 , v2 ) ;
2005-09-10 00:04:45 +04:00
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x22 , v1 ) ;
2005-09-10 00:04:45 +04:00
if ( ivideo - > revision_id = = 2 ) {
2010-12-21 00:50:16 +03:00
v1 = SiS_GetReg ( SISSR , 0x3b ) ;
v2 = SiS_GetReg ( SISSR , 0x3a ) ;
2005-09-10 00:04:45 +04:00
regd = bios [ 0x90 + 3 ] | ( bios [ 0x90 + 4 ] < < 8 ) ;
if ( ( ! ( v1 & 0x02 ) ) & & ( v2 & 0x30 ) & & ( regd < 0xcf ) )
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISCR , 0x5f , 0xf1 , 0x01 ) ;
2005-09-10 00:04:45 +04:00
2007-05-08 11:39:50 +04:00
if ( ( mypdev = pci_get_device ( 0x10de , 0x01e0 , NULL ) ) ) {
2005-09-10 00:04:45 +04:00
/* TODO: set CR5f &0xf1 | 0x01 for version 6570
* of nforce 2 ROM
*/
if ( 0 )
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISCR , 0x5f , 0xf1 , 0x01 ) ;
2007-05-08 11:39:50 +04:00
pci_dev_put ( mypdev ) ;
2005-09-10 00:04:45 +04:00
}
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
v1 = 0x30 ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISSR , 0x3b ) ;
v2 = SiS_GetReg ( SISCR , 0x5f ) ;
2005-09-10 00:04:45 +04:00
if ( ( ! ( reg & 0x02 ) ) & & ( v2 & 0x0e ) )
v1 | = 0x08 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x27 , v1 ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( bios [ 0x64 ] & 0x01 ) {
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISCR , 0x5f , 0xf0 , bios [ 0x64 ] ) ;
2005-09-10 00:04:45 +04:00
}
v1 = bios [ 0x4f7 ] ;
pci_read_config_dword ( pdev , 0x50 , & regd ) ;
regd = ( regd > > 20 ) & 0x0f ;
if ( regd = = 1 ) {
v1 & = 0xfc ;
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISCR , 0x5f , 0x08 ) ;
2005-09-10 00:04:45 +04:00
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x48 , v1 ) ;
2005-09-10 00:04:45 +04:00
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISCR , 0x47 , 0x04 , bios [ 0x4f6 ] & 0xfb ) ;
SiS_SetRegANDOR ( SISCR , 0x49 , 0xf0 , bios [ 0x4f8 ] & 0x0f ) ;
SiS_SetRegANDOR ( SISCR , 0x4a , 0x60 , bios [ 0x4f9 ] & 0x9f ) ;
SiS_SetRegANDOR ( SISCR , 0x4b , 0x08 , bios [ 0x4fa ] & 0xf7 ) ;
SiS_SetRegANDOR ( SISCR , 0x4c , 0x80 , bios [ 0x4fb ] & 0x7f ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x70 , bios [ 0x4fc ] ) ;
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISCR , 0x71 , 0xf0 , bios [ 0x4fd ] & 0x0f ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x74 , 0xd0 ) ;
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISCR , 0x74 , 0xcf , bios [ 0x4fe ] & 0x30 ) ;
SiS_SetRegANDOR ( SISCR , 0x75 , 0xe0 , bios [ 0x4ff ] & 0x1f ) ;
SiS_SetRegANDOR ( SISCR , 0x76 , 0xe0 , bios [ 0x500 ] & 0x1f ) ;
2005-09-10 00:04:45 +04:00
v1 = bios [ 0x501 ] ;
2007-05-08 11:39:50 +04:00
if ( ( mypdev = pci_get_device ( 0x8086 , 0x2530 , NULL ) ) ) {
2005-09-10 00:04:45 +04:00
v1 = 0xf0 ;
2007-05-08 11:39:50 +04:00
pci_dev_put ( mypdev ) ;
2005-09-10 00:04:45 +04:00
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x77 , v1 ) ;
2005-04-17 02:20:36 +04:00
}
2011-02-14 01:11:28 +03:00
/* RAM type:
*
* 0 = = DDR1 , 1 = = DDR2 , 2. .7 = = reserved ?
*
* The code seems to written so that regb should equal ramtype ,
* however , so far it has been hardcoded to 0. Enable other values only
* on XGI Z9 , as it passes the POST , and add a warning for others .
*/
ramtype = sisfb_post_xgi_ramtype ( ivideo ) ;
if ( ! sisfb_xgi_is21 ( ivideo ) & & ramtype ) {
dev_warn ( & pdev - > dev ,
" RAM type something else than expected: %d \n " ,
ramtype ) ;
regb = 0 ;
} else {
regb = ramtype ;
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
v1 = 0xff ;
if ( ivideo - > haveXGIROM ) {
v1 = bios [ 0x140 + regb ] ;
2005-04-17 02:20:36 +04:00
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x6d , v1 ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
ptr = cs128 ;
if ( ivideo - > haveXGIROM ) {
ptr = ( const u8 * ) & bios [ 0x128 ] ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
for ( i = 0 , j = 0 ; i < 3 ; i + + , j + = 8 ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x68 + i , ptr [ j + regb ] ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
ptr = cs31a ;
ptr2 = cs33a ;
if ( ivideo - > haveXGIROM ) {
index = ( ivideo - > chip = = XGI_20 ) ? 0x31a : 0x3a6 ;
ptr = ( const u8 * ) & bios [ index ] ;
ptr2 = ( const u8 * ) & bios [ index + 0x20 ] ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
for ( i = 0 ; i < 2 ; i + + ) {
if ( i = = 0 ) {
regd = le32_to_cpu ( ( ( u32 * ) ptr ) [ regb ] ) ;
rega = 0x6b ;
} else {
regd = le32_to_cpu ( ( ( u32 * ) ptr2 ) [ regb ] ) ;
rega = 0x6e ;
}
reg = 0x00 ;
for ( j = 0 ; j < 16 ; j + + ) {
reg & = 0xf3 ;
if ( regd & 0x01 ) reg | = 0x04 ;
if ( regd & 0x02 ) reg | = 0x08 ;
regd > > = 2 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , rega , reg ) ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , rega ) ;
reg = SiS_GetReg ( SISCR , rega ) ;
2005-09-10 00:04:45 +04:00
reg + = 0x10 ;
}
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISCR , 0x6e , 0xfc ) ;
2005-09-10 00:04:45 +04:00
ptr = NULL ;
if ( ivideo - > haveXGIROM ) {
index = ( ivideo - > chip = = XGI_20 ) ? 0x35a : 0x3e6 ;
ptr = ( const u8 * ) & bios [ index ] ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
for ( i = 0 ; i < 4 ; i + + ) {
2010-12-21 00:50:20 +03:00
SiS_SetRegANDOR ( SISCR , 0x6e , 0xfc , i ) ;
2005-09-10 00:04:45 +04:00
reg = 0x00 ;
for ( j = 0 ; j < 2 ; j + + ) {
regd = 0 ;
if ( ptr ) {
regd = le32_to_cpu ( ( ( u32 * ) ptr ) [ regb * 8 ] ) ;
ptr + = 4 ;
}
/* reg = 0x00; */
for ( k = 0 ; k < 16 ; k + + ) {
reg & = 0xfc ;
if ( regd & 0x01 ) reg | = 0x01 ;
if ( regd & 0x02 ) reg | = 0x02 ;
regd > > = 2 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x6f , reg ) ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0x6f ) ;
reg = SiS_GetReg ( SISCR , 0x6f ) ;
2005-09-10 00:04:45 +04:00
reg + = 0x08 ;
}
}
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
ptr = cs148 ;
if ( ivideo - > haveXGIROM ) {
ptr = ( const u8 * ) & bios [ 0x148 ] ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
for ( i = 0 , j = 0 ; i < 2 ; i + + , j + = 8 ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x80 + i , ptr [ j + regb ] ) ;
2005-04-17 02:20:36 +04:00
}
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISCR , 0x89 , 0x8f ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
ptr = cs45a ;
if ( ivideo - > haveXGIROM ) {
index = ( ivideo - > chip = = XGI_20 ) ? 0x45a : 0x4e6 ;
ptr = ( const u8 * ) & bios [ index ] ;
}
regd = le16_to_cpu ( ( ( const u16 * ) ptr ) [ regb ] ) ;
reg = 0x80 ;
for ( i = 0 ; i < 5 ; i + + ) {
reg & = 0xfc ;
if ( regd & 0x01 ) reg | = 0x01 ;
if ( regd & 0x02 ) reg | = 0x02 ;
regd > > = 2 ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x89 , reg ) ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0x89 ) ;
reg = SiS_GetReg ( SISCR , 0x89 ) ;
2005-09-10 00:04:45 +04:00
reg + = 0x10 ;
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
v1 = 0xb5 ; v2 = 0x20 ; v3 = 0xf0 ; v4 = 0x13 ;
if ( ivideo - > haveXGIROM ) {
v1 = bios [ 0x118 + regb ] ;
v2 = bios [ 0xf8 + regb ] ;
v3 = bios [ 0x120 + regb ] ;
v4 = bios [ 0x1ca ] ;
2005-04-17 02:20:36 +04:00
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x45 , v1 & 0x0f ) ;
SiS_SetReg ( SISCR , 0x99 , ( v1 > > 4 ) & 0x07 ) ;
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISCR , 0x40 , v1 & 0x80 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x41 , v2 ) ;
2005-09-10 00:04:45 +04:00
ptr = cs170 ;
if ( ivideo - > haveXGIROM ) {
ptr = ( const u8 * ) & bios [ 0x170 ] ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
for ( i = 0 , j = 0 ; i < 7 ; i + + , j + = 8 ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x90 + i , ptr [ j + regb ] ) ;
2005-04-17 02:20:36 +04:00
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x59 , v3 ) ;
2005-09-10 00:04:45 +04:00
ptr = cs1a8 ;
if ( ivideo - > haveXGIROM ) {
ptr = ( const u8 * ) & bios [ 0x1a8 ] ;
}
for ( i = 0 , j = 0 ; i < 3 ; i + + , j + = 8 ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0xc3 + i , ptr [ j + regb ] ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
ptr = cs100 ;
if ( ivideo - > haveXGIROM ) {
ptr = ( const u8 * ) & bios [ 0x100 ] ;
}
for ( i = 0 , j = 0 ; i < 2 ; i + + , j + = 8 ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x8a + i , ptr [ j + regb ] ) ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0xcf , v4 ) ;
2005-04-17 02:20:36 +04:00
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x83 , 0x09 ) ;
SiS_SetReg ( SISCR , 0x87 , 0x00 ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ivideo - > chip = = XGI_40 ) {
if ( ( ivideo - > revision_id = = 1 ) | |
( ivideo - > revision_id = = 2 ) ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x8c , 0x87 ) ;
2005-09-10 00:04:45 +04:00
}
}
2005-04-17 02:20:36 +04:00
2011-02-14 01:11:28 +03:00
if ( regb = = 1 )
SiS_SetReg ( SISSR , 0x17 , 0x80 ) ; /* DDR2 */
else
SiS_SetReg ( SISSR , 0x17 , 0x00 ) ; /* DDR1 */
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x1a , 0x87 ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ivideo - > chip = = XGI_20 ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x15 , 0x00 ) ;
SiS_SetReg ( SISSR , 0x1c , 0x00 ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
switch ( ramtype ) {
case 0 :
sisfb_post_xgi_setclocks ( ivideo , regb ) ;
if ( ( ivideo - > chip = = XGI_20 ) | |
( ivideo - > revision_id = = 1 ) | |
( ivideo - > revision_id = = 2 ) ) {
v1 = cs158 [ regb ] ; v2 = cs160 [ regb ] ; v3 = cs168 [ regb ] ;
if ( ivideo - > haveXGIROM ) {
v1 = bios [ regb + 0x158 ] ;
v2 = bios [ regb + 0x160 ] ;
v3 = bios [ regb + 0x168 ] ;
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x82 , v1 ) ;
SiS_SetReg ( SISCR , 0x85 , v2 ) ;
SiS_SetReg ( SISCR , 0x86 , v3 ) ;
2005-09-10 00:04:45 +04:00
} else {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x82 , 0x88 ) ;
SiS_SetReg ( SISCR , 0x86 , 0x00 ) ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0x86 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x86 , 0x88 ) ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0x86 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x86 , bios [ regb + 0x168 ] ) ;
SiS_SetReg ( SISCR , 0x82 , 0x77 ) ;
SiS_SetReg ( SISCR , 0x85 , 0x00 ) ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0x85 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x85 , 0x88 ) ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0x85 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x85 , bios [ regb + 0x160 ] ) ;
SiS_SetReg ( SISCR , 0x82 , bios [ regb + 0x158 ] ) ;
2005-09-10 00:04:45 +04:00
}
if ( ivideo - > chip = = XGI_40 ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x97 , 0x00 ) ;
2005-09-10 00:04:45 +04:00
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x98 , 0x01 ) ;
SiS_SetReg ( SISCR , 0x9a , 0x02 ) ;
2005-04-17 02:20:36 +04:00
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x18 , 0x01 ) ;
2005-09-10 00:04:45 +04:00
if ( ( ivideo - > chip = = XGI_20 ) | |
( ivideo - > revision_id = = 2 ) ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x19 , 0x40 ) ;
2005-09-10 00:04:45 +04:00
} else {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x19 , 0x20 ) ;
2005-09-10 00:04:45 +04:00
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x16 , 0x00 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x80 ) ;
2005-09-10 00:04:45 +04:00
if ( ( ivideo - > chip = = XGI_20 ) | | ( bios [ 0x1cb ] ! = 0x0c ) ) {
sisfb_post_xgi_delay ( ivideo , 0x43 ) ;
sisfb_post_xgi_delay ( ivideo , 0x43 ) ;
sisfb_post_xgi_delay ( ivideo , 0x43 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x18 , 0x00 ) ;
2005-09-10 00:04:45 +04:00
if ( ( ivideo - > chip = = XGI_20 ) | |
( ivideo - > revision_id = = 2 ) ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x19 , 0x40 ) ;
2005-09-10 00:04:45 +04:00
} else {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x19 , 0x20 ) ;
2005-09-10 00:04:45 +04:00
}
} else if ( ( ivideo - > chip = = XGI_40 ) & & ( bios [ 0x1cb ] = = 0x0c ) ) {
2010-12-21 00:50:17 +03:00
/* SiS_SetReg(SISSR, 0x16, 0x0c); */ /* ? */
2005-09-10 00:04:45 +04:00
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x16 , 0x00 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x80 ) ;
2005-09-10 00:04:45 +04:00
sisfb_post_xgi_delay ( ivideo , 4 ) ;
v1 = 0x31 ; v2 = 0x03 ; v3 = 0x83 ; v4 = 0x03 ; v5 = 0x83 ;
if ( ivideo - > haveXGIROM ) {
v1 = bios [ 0xf0 ] ;
index = ( ivideo - > chip = = XGI_20 ) ? 0x4b2 : 0x53e ;
v2 = bios [ index ] ;
v3 = bios [ index + 1 ] ;
v4 = bios [ index + 2 ] ;
v5 = bios [ index + 3 ] ;
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x18 , v1 ) ;
SiS_SetReg ( SISSR , 0x19 , ( ( ivideo - > chip = = XGI_20 ) ? 0x02 : 0x01 ) ) ;
SiS_SetReg ( SISSR , 0x16 , v2 ) ;
SiS_SetReg ( SISSR , 0x16 , v3 ) ;
2005-09-10 00:04:45 +04:00
sisfb_post_xgi_delay ( ivideo , 0x43 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x1b , 0x03 ) ;
2005-09-10 00:04:45 +04:00
sisfb_post_xgi_delay ( ivideo , 0x22 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x18 , v1 ) ;
SiS_SetReg ( SISSR , 0x19 , 0x00 ) ;
SiS_SetReg ( SISSR , 0x16 , v4 ) ;
SiS_SetReg ( SISSR , 0x16 , v5 ) ;
SiS_SetReg ( SISSR , 0x1b , 0x00 ) ;
2005-09-10 00:04:45 +04:00
break ;
case 1 :
2011-02-14 01:11:27 +03:00
sisfb_post_xgi_ddr2 ( ivideo , regb ) ;
2005-09-10 00:04:45 +04:00
break ;
default :
sisfb_post_xgi_setclocks ( ivideo , regb ) ;
if ( ( ivideo - > chip = = XGI_40 ) & &
( ( ivideo - > revision_id = = 1 ) | |
( ivideo - > revision_id = = 2 ) ) ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x82 , bios [ regb + 0x158 ] ) ;
SiS_SetReg ( SISCR , 0x85 , bios [ regb + 0x160 ] ) ;
SiS_SetReg ( SISCR , 0x86 , bios [ regb + 0x168 ] ) ;
2005-09-10 00:04:45 +04:00
} else {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x82 , 0x88 ) ;
SiS_SetReg ( SISCR , 0x86 , 0x00 ) ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0x86 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x86 , 0x88 ) ;
SiS_SetReg ( SISCR , 0x82 , 0x77 ) ;
SiS_SetReg ( SISCR , 0x85 , 0x00 ) ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0x85 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x85 , 0x88 ) ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0x85 ) ;
2005-09-10 00:04:45 +04:00
v1 = cs160 [ regb ] ; v2 = cs158 [ regb ] ;
if ( ivideo - > haveXGIROM ) {
v1 = bios [ regb + 0x160 ] ;
v2 = bios [ regb + 0x158 ] ;
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x85 , v1 ) ;
SiS_SetReg ( SISCR , 0x82 , v2 ) ;
2005-09-10 00:04:45 +04:00
}
if ( ivideo - > chip = = XGI_40 ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x97 , 0x11 ) ;
2005-09-10 00:04:45 +04:00
}
if ( ( ivideo - > chip = = XGI_40 ) & & ( ivideo - > revision_id = = 2 ) ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x98 , 0x01 ) ;
2005-09-10 00:04:45 +04:00
} else {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x98 , 0x03 ) ;
2005-09-10 00:04:45 +04:00
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x9a , 0x02 ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ivideo - > chip = = XGI_40 ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x18 , 0x01 ) ;
2005-09-10 00:04:45 +04:00
} else {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x18 , 0x00 ) ;
2005-09-10 00:04:45 +04:00
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x19 , 0x40 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x00 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x80 ) ;
2005-09-10 00:04:45 +04:00
if ( ( ivideo - > chip = = XGI_40 ) & & ( bios [ 0x1cb ] ! = 0x0c ) ) {
sisfb_post_xgi_delay ( ivideo , 0x43 ) ;
sisfb_post_xgi_delay ( ivideo , 0x43 ) ;
sisfb_post_xgi_delay ( ivideo , 0x43 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x18 , 0x00 ) ;
SiS_SetReg ( SISSR , 0x19 , 0x40 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x00 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x80 ) ;
2005-09-10 00:04:45 +04:00
}
sisfb_post_xgi_delay ( ivideo , 4 ) ;
v1 = 0x31 ;
if ( ivideo - > haveXGIROM ) {
v1 = bios [ 0xf0 ] ;
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x18 , v1 ) ;
SiS_SetReg ( SISSR , 0x19 , 0x01 ) ;
2005-09-10 00:04:45 +04:00
if ( ivideo - > chip = = XGI_40 ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x16 , bios [ 0x53e ] ) ;
SiS_SetReg ( SISSR , 0x16 , bios [ 0x53f ] ) ;
2005-09-10 00:04:45 +04:00
} else {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x16 , 0x05 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x85 ) ;
2005-09-10 00:04:45 +04:00
}
sisfb_post_xgi_delay ( ivideo , 0x43 ) ;
if ( ivideo - > chip = = XGI_40 ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x1b , 0x01 ) ;
2005-09-10 00:04:45 +04:00
} else {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x1b , 0x03 ) ;
2005-09-10 00:04:45 +04:00
}
sisfb_post_xgi_delay ( ivideo , 0x22 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x18 , v1 ) ;
SiS_SetReg ( SISSR , 0x19 , 0x00 ) ;
2005-09-10 00:04:45 +04:00
if ( ivideo - > chip = = XGI_40 ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x16 , bios [ 0x540 ] ) ;
SiS_SetReg ( SISSR , 0x16 , bios [ 0x541 ] ) ;
2005-09-10 00:04:45 +04:00
} else {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x16 , 0x05 ) ;
SiS_SetReg ( SISSR , 0x16 , 0x85 ) ;
2005-09-10 00:04:45 +04:00
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x1b , 0x00 ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
regb = 0 ; /* ! */
v1 = 0x03 ;
if ( ivideo - > haveXGIROM ) {
v1 = bios [ 0x110 + regb ] ;
2005-04-17 02:20:36 +04:00
}
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x1b , v1 ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* RAM size */
v1 = 0x00 ; v2 = 0x00 ;
if ( ivideo - > haveXGIROM ) {
v1 = bios [ 0x62 ] ;
v2 = bios [ 0x63 ] ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
regb = 0 ; /* ! */
regd = 1 < < regb ;
if ( ( v1 & 0x40 ) & & ( v2 & regd ) & & ivideo - > haveXGIROM ) {
2005-04-17 02:20:36 +04:00
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x13 , bios [ regb + 0xe0 ] ) ;
SiS_SetReg ( SISSR , 0x14 , bios [ regb + 0xe0 + 8 ] ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
} else {
2011-02-14 01:11:23 +03:00
int err ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* Set default mode, don't clear screen */
2007-02-12 11:55:06 +03:00
ivideo - > SiS_Pr . SiS_UseOEM = false ;
SiS_SetEnableDstn ( & ivideo - > SiS_Pr , false ) ;
SiS_SetEnableFstn ( & ivideo - > SiS_Pr , false ) ;
2005-09-10 00:04:45 +04:00
ivideo - > curFSTN = ivideo - > curDSTN = 0 ;
ivideo - > SiS_Pr . VideoMemorySize = 8 < < 20 ;
SiSSetMode ( & ivideo - > SiS_Pr , 0x2e | 0x80 ) ;
2005-04-17 02:20:36 +04:00
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x05 , 0x86 ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* Disable read-cache */
2010-12-21 00:50:19 +03:00
SiS_SetRegAND ( SISSR , 0x21 , 0xdf ) ;
2011-02-14 01:11:23 +03:00
err = sisfb_post_xgi_ramsize ( ivideo ) ;
2005-09-10 00:04:45 +04:00
/* Enable read-cache */
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISSR , 0x21 , 0x20 ) ;
2005-04-17 02:20:36 +04:00
2011-02-14 01:11:23 +03:00
if ( err ) {
dev_err ( & pdev - > dev ,
" %s: RAM size detection failed: %d \n " ,
__func__ , err ) ;
return 0 ;
}
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
#if 0
printk ( KERN_DEBUG " ----------------- \n " ) ;
for ( i = 0 ; i < 0xff ; i + + ) {
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , i ) ;
2005-09-10 00:04:45 +04:00
printk ( KERN_DEBUG " CR%02x(%x) = 0x%02x \n " , i , SISCR , reg ) ;
}
for ( i = 0 ; i < 0x40 ; i + + ) {
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISSR , i ) ;
2005-09-10 00:04:45 +04:00
printk ( KERN_DEBUG " SR%02x(%x) = 0x%02x \n " , i , SISSR , reg ) ;
}
printk ( KERN_DEBUG " ----------------- \n " ) ;
# endif
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* Sense CRT1 */
if ( ivideo - > chip = = XGI_20 ) {
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISCR , 0x32 , 0x20 ) ;
2005-04-17 02:20:36 +04:00
} else {
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISPART4 , 0x00 ) ;
2005-09-10 00:04:45 +04:00
if ( ( reg = = 1 ) | | ( reg = = 2 ) ) {
sisfb_sense_crt1 ( ivideo ) ;
} else {
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISCR , 0x32 , 0x20 ) ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
/* Set default mode, don't clear screen */
2007-02-12 11:55:06 +03:00
ivideo - > SiS_Pr . SiS_UseOEM = false ;
SiS_SetEnableDstn ( & ivideo - > SiS_Pr , false ) ;
SiS_SetEnableFstn ( & ivideo - > SiS_Pr , false ) ;
2005-09-10 00:04:45 +04:00
ivideo - > curFSTN = ivideo - > curDSTN = 0 ;
SiSSetMode ( & ivideo - > SiS_Pr , 0x2e | 0x80 ) ;
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x05 , 0x86 ) ;
2005-09-10 00:04:45 +04:00
/* Display off */
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISSR , 0x01 , 0x20 ) ;
2005-09-10 00:04:45 +04:00
/* Save mode number in CR34 */
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , 0x34 , 0x2e ) ;
2005-09-10 00:04:45 +04:00
/* Let everyone know what the current mode is */
ivideo - > modeprechange = 0x2e ;
if ( ivideo - > chip = = XGI_40 ) {
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0xca ) ;
v1 = SiS_GetReg ( SISCR , 0xcc ) ;
2005-09-10 00:04:45 +04:00
if ( ( reg & 0x10 ) & & ( ! ( v1 & 0x04 ) ) ) {
printk ( KERN_ERR
" sisfb: Please connect power to the card. \n " ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
return 1 ;
2005-04-17 02:20:36 +04:00
}
# endif
2012-12-22 01:07:39 +04:00
static int sisfb_probe ( struct pci_dev * pdev , const struct pci_device_id * ent )
2005-04-17 02:20:36 +04:00
{
2005-09-10 00:04:45 +04:00
struct sisfb_chip_info * chipinfo = & sisfb_chip_info [ ent - > driver_data ] ;
struct sis_video_info * ivideo = NULL ;
struct fb_info * sis_fb_info = NULL ;
2005-04-17 02:20:36 +04:00
u16 reg16 ;
u8 reg ;
2005-09-10 00:04:45 +04:00
int i , ret ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( sisfb_off )
return - ENXIO ;
2005-04-17 02:20:36 +04:00
sis_fb_info = framebuffer_alloc ( sizeof ( * ivideo ) , & pdev - > dev ) ;
2005-09-10 00:04:45 +04:00
if ( ! sis_fb_info )
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
ivideo = ( struct sis_video_info * ) sis_fb_info - > par ;
ivideo - > memyselfandi = sis_fb_info ;
2005-09-10 00:04:45 +04:00
ivideo - > sisfb_id = SISFB_ID ;
2005-04-17 02:20:36 +04:00
if ( card_list = = NULL ) {
2005-09-10 00:04:45 +04:00
ivideo - > cardnumber = 0 ;
2005-04-17 02:20:36 +04:00
} else {
2005-09-10 00:04:45 +04:00
struct sis_video_info * countvideo = card_list ;
ivideo - > cardnumber = 1 ;
2008-05-23 02:45:08 +04:00
while ( ( countvideo = countvideo - > next ) ! = NULL )
2005-09-10 00:04:45 +04:00
ivideo - > cardnumber + + ;
2005-04-17 02:20:36 +04:00
}
strncpy ( ivideo - > myid , chipinfo - > chip_name , 30 ) ;
ivideo - > warncount = 0 ;
ivideo - > chip_id = pdev - > device ;
2005-09-10 00:04:45 +04:00
ivideo - > chip_vendor = pdev - > vendor ;
2007-06-09 02:46:36 +04:00
ivideo - > revision_id = pdev - > revision ;
2005-09-10 00:04:45 +04:00
ivideo - > SiS_Pr . ChipRevision = ivideo - > revision_id ;
2005-04-17 02:20:36 +04:00
pci_read_config_word ( pdev , PCI_COMMAND , & reg16 ) ;
2005-09-10 00:04:45 +04:00
ivideo - > sisvga_enabled = reg16 & 0x01 ;
2005-04-17 02:20:36 +04:00
ivideo - > pcibus = pdev - > bus - > number ;
ivideo - > pcislot = PCI_SLOT ( pdev - > devfn ) ;
ivideo - > pcifunc = PCI_FUNC ( pdev - > devfn ) ;
ivideo - > subsysvendor = pdev - > subsystem_vendor ;
ivideo - > subsysdevice = pdev - > subsystem_device ;
# ifndef MODULE
if ( sisfb_mode_idx = = - 1 ) {
sisfb_get_vga_mode_from_kernel ( ) ;
}
# endif
ivideo - > chip = chipinfo - > chip ;
2011-02-14 01:11:25 +03:00
ivideo - > chip_real_id = chipinfo - > chip ;
2005-04-17 02:20:36 +04:00
ivideo - > sisvga_engine = chipinfo - > vgaengine ;
ivideo - > hwcursor_size = chipinfo - > hwcursor_size ;
ivideo - > CRT2_write_enable = chipinfo - > CRT2_write_enable ;
ivideo - > mni = chipinfo - > mni ;
ivideo - > detectedpdc = 0xff ;
ivideo - > detectedpdca = 0xff ;
ivideo - > detectedlcda = 0xff ;
2007-02-12 11:55:06 +03:00
ivideo - > sisfb_thismonitor . datavalid = false ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
ivideo - > current_base = 0 ;
ivideo - > engineok = 0 ;
ivideo - > sisfb_was_boot_device = 0 ;
2008-07-24 08:31:12 +04:00
2005-09-10 00:04:45 +04:00
if ( pdev - > resource [ PCI_ROM_RESOURCE ] . flags & IORESOURCE_ROM_SHADOW ) {
if ( ivideo - > sisvga_enabled )
ivideo - > sisfb_was_boot_device = 1 ;
else {
printk ( KERN_DEBUG " sisfb: PCI device is disabled, "
" but marked as boot video device ??? \n " ) ;
printk ( KERN_DEBUG " sisfb: I will not accept this "
" as the primary VGA device \n " ) ;
}
}
2005-04-17 02:20:36 +04:00
ivideo - > sisfb_parm_mem = sisfb_parm_mem ;
ivideo - > sisfb_accel = sisfb_accel ;
ivideo - > sisfb_ypan = sisfb_ypan ;
ivideo - > sisfb_max = sisfb_max ;
ivideo - > sisfb_userom = sisfb_userom ;
ivideo - > sisfb_useoem = sisfb_useoem ;
ivideo - > sisfb_mode_idx = sisfb_mode_idx ;
ivideo - > sisfb_parm_rate = sisfb_parm_rate ;
ivideo - > sisfb_crt1off = sisfb_crt1off ;
ivideo - > sisfb_forcecrt1 = sisfb_forcecrt1 ;
ivideo - > sisfb_crt2type = sisfb_crt2type ;
ivideo - > sisfb_crt2flags = sisfb_crt2flags ;
/* pdc(a), scalelcd, special timing, lvdshl handled below */
ivideo - > sisfb_dstn = sisfb_dstn ;
ivideo - > sisfb_fstn = sisfb_fstn ;
ivideo - > sisfb_tvplug = sisfb_tvplug ;
ivideo - > sisfb_tvstd = sisfb_tvstd ;
ivideo - > tvxpos = sisfb_tvxposoffset ;
ivideo - > tvypos = sisfb_tvyposoffset ;
ivideo - > sisfb_nocrt2rate = sisfb_nocrt2rate ;
ivideo - > refresh_rate = 0 ;
if ( ivideo - > sisfb_parm_rate ! = - 1 ) {
2005-09-10 00:04:45 +04:00
ivideo - > refresh_rate = ivideo - > sisfb_parm_rate ;
2005-04-17 02:20:36 +04:00
}
ivideo - > SiS_Pr . UsePanelScaler = sisfb_scalelcd ;
ivideo - > SiS_Pr . CenterScreen = - 1 ;
ivideo - > SiS_Pr . SiS_CustomT = sisfb_specialtiming ;
ivideo - > SiS_Pr . LVDSHL = sisfb_lvdshl ;
ivideo - > SiS_Pr . SiS_Backup70xx = 0xff ;
2005-09-10 00:04:45 +04:00
ivideo - > SiS_Pr . SiS_CHOverScan = - 1 ;
2007-02-12 11:55:06 +03:00
ivideo - > SiS_Pr . SiS_ChSW = false ;
ivideo - > SiS_Pr . SiS_UseLCDA = false ;
ivideo - > SiS_Pr . HaveEMI = false ;
ivideo - > SiS_Pr . HaveEMILCD = false ;
ivideo - > SiS_Pr . OverruleEMI = false ;
ivideo - > SiS_Pr . SiS_SensibleSR11 = false ;
2005-04-17 02:20:36 +04:00
ivideo - > SiS_Pr . SiS_MyCR63 = 0x63 ;
ivideo - > SiS_Pr . PDC = - 1 ;
ivideo - > SiS_Pr . PDCA = - 1 ;
2007-02-12 11:55:06 +03:00
ivideo - > SiS_Pr . DDCPortMixup = false ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_FB_SIS_315
if ( ivideo - > chip > = SIS_330 ) {
2005-09-10 00:04:45 +04:00
ivideo - > SiS_Pr . SiS_MyCR63 = 0x53 ;
if ( ivideo - > chip > = SIS_661 ) {
2007-02-12 11:55:06 +03:00
ivideo - > SiS_Pr . SiS_SensibleSR11 = true ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
}
# endif
memcpy ( & ivideo - > default_var , & my_default_var , sizeof ( my_default_var ) ) ;
pci_set_drvdata ( pdev , ivideo ) ;
/* Patch special cases */
if ( ( ivideo - > nbridge = sisfb_get_northbridge ( ivideo - > chip ) ) ) {
switch ( ivideo - > nbridge - > device ) {
# ifdef CONFIG_FB_SIS_300
case PCI_DEVICE_ID_SI_730 :
2005-09-10 00:04:45 +04:00
ivideo - > chip = SIS_730 ;
2005-04-17 02:20:36 +04:00
strcpy ( ivideo - > myid , " SiS 730 " ) ;
2005-09-10 00:04:45 +04:00
break ;
2005-04-17 02:20:36 +04:00
# endif
# ifdef CONFIG_FB_SIS_315
case PCI_DEVICE_ID_SI_651 :
/* ivideo->chip is ok */
strcpy ( ivideo - > myid , " SiS 651 " ) ;
break ;
case PCI_DEVICE_ID_SI_740 :
2005-09-10 00:04:45 +04:00
ivideo - > chip = SIS_740 ;
2005-04-17 02:20:36 +04:00
strcpy ( ivideo - > myid , " SiS 740 " ) ;
break ;
case PCI_DEVICE_ID_SI_661 :
2005-09-10 00:04:45 +04:00
ivideo - > chip = SIS_661 ;
2005-04-17 02:20:36 +04:00
strcpy ( ivideo - > myid , " SiS 661 " ) ;
break ;
case PCI_DEVICE_ID_SI_741 :
2005-09-10 00:04:45 +04:00
ivideo - > chip = SIS_741 ;
2005-04-17 02:20:36 +04:00
strcpy ( ivideo - > myid , " SiS 741 " ) ;
break ;
case PCI_DEVICE_ID_SI_760 :
2005-09-10 00:04:45 +04:00
ivideo - > chip = SIS_760 ;
2005-04-17 02:20:36 +04:00
strcpy ( ivideo - > myid , " SiS 760 " ) ;
break ;
2005-09-10 00:04:45 +04:00
case PCI_DEVICE_ID_SI_761 :
ivideo - > chip = SIS_761 ;
strcpy ( ivideo - > myid , " SiS 761 " ) ;
break ;
2005-04-17 02:20:36 +04:00
# endif
2005-09-10 00:04:45 +04:00
default :
break ;
2005-04-17 02:20:36 +04:00
}
}
2005-09-10 00:04:45 +04:00
ivideo - > SiS_Pr . ChipType = ivideo - > chip ;
ivideo - > SiS_Pr . ivideo = ( void * ) ivideo ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_FB_SIS_315
2005-09-10 00:04:45 +04:00
if ( ( ivideo - > SiS_Pr . ChipType = = SIS_315PRO ) | |
( ivideo - > SiS_Pr . ChipType = = SIS_315 ) ) {
ivideo - > SiS_Pr . ChipType = SIS_315H ;
2005-04-17 02:20:36 +04:00
}
# endif
2005-09-10 00:04:45 +04:00
if ( ! ivideo - > sisvga_enabled ) {
if ( pci_enable_device ( pdev ) ) {
2007-05-08 11:39:50 +04:00
if ( ivideo - > nbridge ) pci_dev_put ( ivideo - > nbridge ) ;
2005-09-10 00:04:45 +04:00
pci_set_drvdata ( pdev , NULL ) ;
2009-06-17 02:34:36 +04:00
framebuffer_release ( sis_fb_info ) ;
2005-09-10 00:04:45 +04:00
return - EIO ;
}
}
2005-04-17 02:20:36 +04:00
ivideo - > video_base = pci_resource_start ( pdev , 0 ) ;
2010-11-10 14:04:19 +03:00
ivideo - > video_size = pci_resource_len ( pdev , 0 ) ;
2005-04-17 02:20:36 +04:00
ivideo - > mmio_base = pci_resource_start ( pdev , 1 ) ;
ivideo - > mmio_size = pci_resource_len ( pdev , 1 ) ;
2005-09-10 00:04:45 +04:00
ivideo - > SiS_Pr . RelIO = pci_resource_start ( pdev , 2 ) + 0x30 ;
ivideo - > SiS_Pr . IOAddress = ivideo - > vga_base = ivideo - > SiS_Pr . RelIO ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
SiSRegInit ( & ivideo - > SiS_Pr , ivideo - > SiS_Pr . IOAddress ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_FB_SIS_300
/* Find PCI systems for Chrontel/GPIO communication setup */
if ( ivideo - > chip = = SIS_630 ) {
2005-09-10 00:04:45 +04:00
i = 0 ;
do {
if ( mychswtable [ i ] . subsysVendor = = ivideo - > subsysvendor & &
mychswtable [ i ] . subsysCard = = ivideo - > subsysdevice ) {
2007-02-12 11:55:06 +03:00
ivideo - > SiS_Pr . SiS_ChSW = true ;
2005-09-10 00:04:45 +04:00
printk ( KERN_DEBUG " sisfb: Identified [%s %s] "
" requiring Chrontel/GPIO setup \n " ,
mychswtable [ i ] . vendorName ,
mychswtable [ i ] . cardName ) ;
2007-05-08 11:39:50 +04:00
ivideo - > lpcdev = pci_get_device ( PCI_VENDOR_ID_SI , 0x0008 , NULL ) ;
2005-09-10 00:04:45 +04:00
break ;
}
i + + ;
} while ( mychswtable [ i ] . subsysVendor ! = 0 ) ;
}
# endif
# ifdef CONFIG_FB_SIS_315
if ( ( ivideo - > chip = = SIS_760 ) & & ( ivideo - > nbridge ) ) {
2007-05-08 11:39:50 +04:00
ivideo - > lpcdev = pci_get_slot ( ivideo - > nbridge - > bus , ( 2 < < 3 ) ) ;
2005-04-17 02:20:36 +04:00
}
# endif
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISSR , 0x05 , 0x86 ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
if ( ( ! ivideo - > sisvga_enabled )
2005-04-17 02:20:36 +04:00
# if !defined(__i386__) && !defined(__x86_64__)
2005-09-10 00:04:45 +04:00
| | ( sisfb_resetcard )
2005-04-17 02:20:36 +04:00
# endif
2005-09-10 00:04:45 +04:00
) {
for ( i = 0x30 ; i < = 0x3f ; i + + ) {
2010-12-21 00:50:17 +03:00
SiS_SetReg ( SISCR , i , 0x00 ) ;
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
}
/* Find out about current video mode */
ivideo - > modeprechange = 0x03 ;
2010-12-21 00:50:16 +03:00
reg = SiS_GetReg ( SISCR , 0x34 ) ;
2005-04-17 02:20:36 +04:00
if ( reg & 0x7f ) {
ivideo - > modeprechange = reg & 0x7f ;
2005-09-10 00:04:45 +04:00
} else if ( ivideo - > sisvga_enabled ) {
2005-04-17 02:20:36 +04:00
# if defined(__i386__) || defined(__x86_64__)
2008-07-24 08:31:12 +04:00
unsigned char __iomem * tt = ioremap ( 0x400 , 0x100 ) ;
2005-04-17 02:20:36 +04:00
if ( tt ) {
2005-09-10 00:04:45 +04:00
ivideo - > modeprechange = readb ( tt + 0x49 ) ;
iounmap ( tt ) ;
2005-04-17 02:20:36 +04:00
}
# endif
}
2005-09-10 00:04:45 +04:00
/* Search and copy ROM image */
2005-04-17 02:20:36 +04:00
ivideo - > bios_abase = NULL ;
2005-09-10 00:04:45 +04:00
ivideo - > SiS_Pr . VirtualRomBase = NULL ;
2007-02-12 11:55:06 +03:00
ivideo - > SiS_Pr . UseROM = false ;
ivideo - > haveXGIROM = ivideo - > SiS_Pr . SiS_XGIROM = false ;
2005-04-17 02:20:36 +04:00
if ( ivideo - > sisfb_userom ) {
2005-09-10 00:04:45 +04:00
ivideo - > SiS_Pr . VirtualRomBase = sisfb_find_rom ( pdev ) ;
ivideo - > bios_abase = ivideo - > SiS_Pr . VirtualRomBase ;
2007-02-12 11:55:06 +03:00
ivideo - > SiS_Pr . UseROM = ( bool ) ( ivideo - > SiS_Pr . VirtualRomBase ) ;
2005-09-10 00:04:45 +04:00
printk ( KERN_INFO " sisfb: Video ROM %sfound \n " ,
ivideo - > SiS_Pr . UseROM ? " " : " not " ) ;
if ( ( ivideo - > SiS_Pr . UseROM ) & & ( ivideo - > chip > = XGI_20 ) ) {
2007-02-12 11:55:06 +03:00
ivideo - > SiS_Pr . UseROM = false ;
ivideo - > haveXGIROM = ivideo - > SiS_Pr . SiS_XGIROM = true ;
2005-09-10 00:04:45 +04:00
if ( ( ivideo - > revision_id = = 2 ) & &
( ! ( ivideo - > bios_abase [ 0x1d1 ] & 0x01 ) ) ) {
2007-02-12 11:55:06 +03:00
ivideo - > SiS_Pr . DDCPortMixup = true ;
2005-09-10 00:04:45 +04:00
}
}
2005-04-17 02:20:36 +04:00
} else {
2005-09-10 00:04:45 +04:00
printk ( KERN_INFO " sisfb: Video ROM usage disabled \n " ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
/* Find systems for special custom timing */
2005-04-17 02:20:36 +04:00
if ( ivideo - > SiS_Pr . SiS_CustomT = = CUT_NONE ) {
2005-09-10 00:04:45 +04:00
sisfb_detect_custom_timing ( ivideo ) ;
2005-04-17 02:20:36 +04:00
}
2011-02-14 01:11:25 +03:00
# ifdef CONFIG_FB_SIS_315
if ( ivideo - > chip = = XGI_20 ) {
/* Check if our Z7 chip is actually Z9 */
SiS_SetRegOR ( SISCR , 0x4a , 0x40 ) ; /* GPIOG EN */
reg = SiS_GetReg ( SISCR , 0x48 ) ;
if ( reg & 0x02 ) { /* GPIOG */
ivideo - > chip_real_id = XGI_21 ;
dev_info ( & pdev - > dev , " Z9 detected \n " ) ;
}
}
# endif
2005-09-10 00:04:45 +04:00
/* POST card in case this has not been done by the BIOS */
if ( ( ! ivideo - > sisvga_enabled )
2005-04-17 02:20:36 +04:00
# if !defined(__i386__) && !defined(__x86_64__)
2005-09-10 00:04:45 +04:00
| | ( sisfb_resetcard )
2005-04-17 02:20:36 +04:00
# endif
2005-09-10 00:04:45 +04:00
) {
# ifdef CONFIG_FB_SIS_300
if ( ivideo - > sisvga_engine = = SIS_300_VGA ) {
2005-04-17 02:20:36 +04:00
if ( ivideo - > chip = = SIS_300 ) {
sisfb_post_sis300 ( pdev ) ;
2005-09-10 00:04:45 +04:00
ivideo - > sisfb_can_post = 1 ;
2005-04-17 02:20:36 +04:00
}
}
# endif
# ifdef CONFIG_FB_SIS_315
2005-09-10 00:04:45 +04:00
if ( ivideo - > sisvga_engine = = SIS_315_VGA ) {
int result = 1 ;
/* if((ivideo->chip == SIS_315H) ||
2005-04-17 02:20:36 +04:00
( ivideo - > chip = = SIS_315 ) | |
( ivideo - > chip = = SIS_315PRO ) | |
( ivideo - > chip = = SIS_330 ) ) {
sisfb_post_sis315330 ( pdev ) ;
2005-09-10 00:04:45 +04:00
} else */ if ( ivideo - > chip = = XGI_20 ) {
result = sisfb_post_xgi ( pdev ) ;
ivideo - > sisfb_can_post = 1 ;
} else if ( ( ivideo - > chip = = XGI_40 ) & & ivideo - > haveXGIROM ) {
result = sisfb_post_xgi ( pdev ) ;
ivideo - > sisfb_can_post = 1 ;
} else {
printk ( KERN_INFO " sisfb: Card is not "
" POSTed and sisfb can't do this either. \n " ) ;
}
if ( ! result ) {
printk ( KERN_ERR " sisfb: Failed to POST card \n " ) ;
ret = - ENODEV ;
goto error_3 ;
2005-04-17 02:20:36 +04:00
}
}
# endif
2005-09-10 00:04:45 +04:00
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
ivideo - > sisfb_card_posted = 1 ;
/* Find out about RAM size */
2005-04-17 02:20:36 +04:00
if ( sisfb_get_dram_size ( ivideo ) ) {
2005-09-10 00:04:45 +04:00
printk ( KERN_INFO " sisfb: Fatal error: Unable to determine VRAM size. \n " ) ;
ret = - ENODEV ;
goto error_3 ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
/* Enable PCI addressing and MMIO */
2005-04-17 02:20:36 +04:00
if ( ( ivideo - > sisfb_mode_idx < 0 ) | |
( ( sisbios_mode [ ivideo - > sisfb_mode_idx ] . mode_no [ ivideo - > mni ] ) ! = 0xFF ) ) {
2005-09-10 00:04:45 +04:00
/* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISSR , IND_SIS_PCI_ADDRESS_SET , ( SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE ) ) ;
2005-09-10 00:04:45 +04:00
/* Enable 2D accelerator engine */
2010-12-21 00:50:18 +03:00
SiS_SetRegOR ( SISSR , IND_SIS_MODULE_ENABLE , SIS_ENABLE_2D ) ;
2005-04-17 02:20:36 +04:00
}
if ( sisfb_pdc ! = 0xff ) {
2005-09-10 00:04:45 +04:00
if ( ivideo - > sisvga_engine = = SIS_300_VGA )
sisfb_pdc & = 0x3c ;
else
sisfb_pdc & = 0x1f ;
ivideo - > SiS_Pr . PDC = sisfb_pdc ;
2005-04-17 02:20:36 +04:00
}
# ifdef CONFIG_FB_SIS_315
if ( ivideo - > sisvga_engine = = SIS_315_VGA ) {
2005-09-10 00:04:45 +04:00
if ( sisfb_pdca ! = 0xff )
ivideo - > SiS_Pr . PDCA = sisfb_pdca & 0x1f ;
2005-04-17 02:20:36 +04:00
}
# endif
if ( ! request_mem_region ( ivideo - > video_base , ivideo - > video_size , " sisfb FB " ) ) {
2005-09-10 00:04:45 +04:00
printk ( KERN_ERR " sisfb: Fatal error: Unable to reserve %dMB framebuffer memory \n " ,
( int ) ( ivideo - > video_size > > 20 ) ) ;
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " sisfb: Is there another framebuffer driver active? \n " ) ;
2005-09-10 00:04:45 +04:00
ret = - ENODEV ;
goto error_3 ;
2005-04-17 02:20:36 +04:00
}
if ( ! request_mem_region ( ivideo - > mmio_base , ivideo - > mmio_size , " sisfb MMIO " ) ) {
printk ( KERN_ERR " sisfb: Fatal error: Unable to reserve MMIO region \n " ) ;
2005-09-10 00:04:45 +04:00
ret = - ENODEV ;
goto error_2 ;
2005-04-17 02:20:36 +04:00
}
ivideo - > video_vbase = ioremap ( ivideo - > video_base , ivideo - > video_size ) ;
2005-09-10 00:04:45 +04:00
ivideo - > SiS_Pr . VideoMemoryAddress = ivideo - > video_vbase ;
2005-04-17 02:20:36 +04:00
if ( ! ivideo - > video_vbase ) {
2005-09-10 00:04:45 +04:00
printk ( KERN_ERR " sisfb: Fatal error: Unable to map framebuffer memory \n " ) ;
ret = - ENODEV ;
goto error_1 ;
2005-04-17 02:20:36 +04:00
}
ivideo - > mmio_vbase = ioremap ( ivideo - > mmio_base , ivideo - > mmio_size ) ;
if ( ! ivideo - > mmio_vbase ) {
2005-09-10 00:04:45 +04:00
printk ( KERN_ERR " sisfb: Fatal error: Unable to map MMIO region \n " ) ;
ret = - ENODEV ;
error_0 : iounmap ( ivideo - > video_vbase ) ;
error_1 : release_mem_region ( ivideo - > video_base , ivideo - > video_size ) ;
error_2 : release_mem_region ( ivideo - > mmio_base , ivideo - > mmio_size ) ;
error_3 : vfree ( ivideo - > bios_abase ) ;
if ( ivideo - > lpcdev )
2007-05-08 11:39:50 +04:00
pci_dev_put ( ivideo - > lpcdev ) ;
2005-09-10 00:04:45 +04:00
if ( ivideo - > nbridge )
2007-05-08 11:39:50 +04:00
pci_dev_put ( ivideo - > nbridge ) ;
2005-04-17 02:20:36 +04:00
pci_set_drvdata ( pdev , NULL ) ;
2005-09-10 00:04:45 +04:00
if ( ! ivideo - > sisvga_enabled )
pci_disable_device ( pdev ) ;
2009-06-17 02:34:36 +04:00
framebuffer_release ( sis_fb_info ) ;
2005-09-10 00:04:45 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
printk ( KERN_INFO " sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk \n " ,
ivideo - > video_base , ( unsigned long ) ivideo - > video_vbase , ivideo - > video_size / 1024 ) ;
if ( ivideo - > video_offset ) {
printk ( KERN_INFO " sisfb: Viewport offset %ldk \n " ,
ivideo - > video_offset / 1024 ) ;
}
2005-04-17 02:20:36 +04:00
printk ( KERN_INFO " sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk \n " ,
2005-09-10 00:04:45 +04:00
ivideo - > mmio_base , ( unsigned long ) ivideo - > mmio_vbase , ivideo - > mmio_size / 1024 ) ;
/* Determine the size of the command queue */
if ( ivideo - > sisvga_engine = = SIS_300_VGA ) {
ivideo - > cmdQueueSize = TURBO_QUEUE_AREA_SIZE ;
} else {
if ( ivideo - > chip = = XGI_20 ) {
ivideo - > cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7 ;
} else {
ivideo - > cmdQueueSize = COMMAND_QUEUE_AREA_SIZE ;
}
}
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
/* Engines are no longer initialized here; this is
* now done after the first mode - switch ( if the
* submitted var has its acceleration flags set ) .
*/
/* Calculate the base of the (unused) hw cursor */
ivideo - > hwcursor_vbase = ivideo - > video_vbase
+ ivideo - > video_size
- ivideo - > cmdQueueSize
- ivideo - > hwcursor_size ;
ivideo - > caps | = HW_CURSOR_CAP ;
/* Initialize offscreen memory manager */
2005-04-17 02:20:36 +04:00
if ( ( ivideo - > havenoheap = sisfb_heap_init ( ivideo ) ) ) {
printk ( KERN_WARNING " sisfb: Failed to initialize offscreen memory heap \n " ) ;
}
/* Used for clearing the screen only, therefore respect our mem limit */
2005-09-10 00:04:45 +04:00
ivideo - > SiS_Pr . VideoMemoryAddress + = ivideo - > video_offset ;
ivideo - > SiS_Pr . VideoMemorySize = ivideo - > sisfb_mem ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
ivideo - > mtrr = - 1 ;
2005-04-17 02:20:36 +04:00
ivideo - > vbflags = 0 ;
ivideo - > lcddefmodeidx = DEFAULT_LCDMODE ;
ivideo - > tvdefmodeidx = DEFAULT_TVMODE ;
ivideo - > defmodeidx = DEFAULT_MODE ;
2005-09-10 00:04:45 +04:00
ivideo - > newrom = 0 ;
if ( ivideo - > chip < XGI_20 ) {
if ( ivideo - > bios_abase ) {
ivideo - > newrom = SiSDetermineROMLayout661 ( & ivideo - > SiS_Pr ) ;
}
}
2005-04-17 02:20:36 +04:00
if ( ( ivideo - > sisfb_mode_idx < 0 ) | |
( ( sisbios_mode [ ivideo - > sisfb_mode_idx ] . mode_no [ ivideo - > mni ] ) ! = 0xFF ) ) {
sisfb_sense_crt1 ( ivideo ) ;
sisfb_get_VB_type ( ivideo ) ;
2005-09-10 00:04:45 +04:00
if ( ivideo - > vbflags2 & VB2_VIDEOBRIDGE ) {
2005-04-17 02:20:36 +04:00
sisfb_detect_VB_connect ( ivideo ) ;
}
ivideo - > currentvbflags = ivideo - > vbflags & ( VB_VIDEOBRIDGE | TV_STANDARD ) ;
2005-09-10 00:04:45 +04:00
/* Decide on which CRT2 device to use */
if ( ivideo - > vbflags2 & VB2_VIDEOBRIDGE ) {
if ( ivideo - > sisfb_crt2type ! = - 1 ) {
if ( ( ivideo - > sisfb_crt2type = = CRT2_LCD ) & &
( ivideo - > vbflags & CRT2_LCD ) ) {
ivideo - > currentvbflags | = CRT2_LCD ;
} else if ( ivideo - > sisfb_crt2type ! = CRT2_LCD ) {
ivideo - > currentvbflags | = ivideo - > sisfb_crt2type ;
}
} else {
/* Chrontel 700x TV detection often unreliable, therefore
* use a different default order on such machines
*/
if ( ( ivideo - > sisvga_engine = = SIS_300_VGA ) & &
( ivideo - > vbflags2 & VB2_CHRONTEL ) ) {
if ( ivideo - > vbflags & CRT2_LCD )
ivideo - > currentvbflags | = CRT2_LCD ;
else if ( ivideo - > vbflags & CRT2_TV )
ivideo - > currentvbflags | = CRT2_TV ;
else if ( ivideo - > vbflags & CRT2_VGA )
ivideo - > currentvbflags | = CRT2_VGA ;
} else {
if ( ivideo - > vbflags & CRT2_TV )
ivideo - > currentvbflags | = CRT2_TV ;
else if ( ivideo - > vbflags & CRT2_LCD )
ivideo - > currentvbflags | = CRT2_LCD ;
else if ( ivideo - > vbflags & CRT2_VGA )
ivideo - > currentvbflags | = CRT2_VGA ;
}
}
2005-04-17 02:20:36 +04:00
}
if ( ivideo - > vbflags & CRT2_LCD ) {
2005-09-10 00:04:45 +04:00
sisfb_detect_lcd_type ( ivideo ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:04:45 +04:00
sisfb_save_pdc_emi ( ivideo ) ;
2005-04-17 02:20:36 +04:00
if ( ! ivideo - > sisfb_crt1off ) {
2005-09-10 00:04:45 +04:00
sisfb_handle_ddc ( ivideo , & ivideo - > sisfb_thismonitor , 0 ) ;
2005-04-17 02:20:36 +04:00
} else {
2005-09-10 00:04:45 +04:00
if ( ( ivideo - > vbflags2 & VB2_SISTMDSBRIDGE ) & &
( ivideo - > vbflags & ( CRT2_VGA | CRT2_LCD ) ) ) {
sisfb_handle_ddc ( ivideo , & ivideo - > sisfb_thismonitor , 1 ) ;
}
2005-04-17 02:20:36 +04:00
}
if ( ivideo - > sisfb_mode_idx > = 0 ) {
int bu = ivideo - > sisfb_mode_idx ;
ivideo - > sisfb_mode_idx = sisfb_validate_mode ( ivideo ,
ivideo - > sisfb_mode_idx , ivideo - > currentvbflags ) ;
if ( bu ! = ivideo - > sisfb_mode_idx ) {
printk ( KERN_ERR " Mode %dx%dx%d failed validation \n " ,
sisbios_mode [ bu ] . xres ,
sisbios_mode [ bu ] . yres ,
sisbios_mode [ bu ] . bpp ) ;
}
}
if ( ivideo - > sisfb_mode_idx < 0 ) {
switch ( ivideo - > currentvbflags & VB_DISPTYPE_DISP2 ) {
case CRT2_LCD :
ivideo - > sisfb_mode_idx = ivideo - > lcddefmodeidx ;
break ;
case CRT2_TV :
ivideo - > sisfb_mode_idx = ivideo - > tvdefmodeidx ;
break ;
default :
ivideo - > sisfb_mode_idx = ivideo - > defmodeidx ;
break ;
}
}
ivideo - > mode_no = sisbios_mode [ ivideo - > sisfb_mode_idx ] . mode_no [ ivideo - > mni ] ;
if ( ivideo - > refresh_rate ! = 0 ) {
2005-09-10 00:04:45 +04:00
sisfb_search_refresh_rate ( ivideo , ivideo - > refresh_rate ,
ivideo - > sisfb_mode_idx ) ;
2005-04-17 02:20:36 +04:00
}
if ( ivideo - > rate_idx = = 0 ) {
ivideo - > rate_idx = sisbios_mode [ ivideo - > sisfb_mode_idx ] . rate_idx ;
ivideo - > refresh_rate = 60 ;
}
if ( ivideo - > sisfb_thismonitor . datavalid ) {
2005-09-10 00:04:45 +04:00
if ( ! sisfb_verify_rate ( ivideo , & ivideo - > sisfb_thismonitor ,
ivideo - > sisfb_mode_idx ,
ivideo - > rate_idx ,
ivideo - > refresh_rate ) ) {
printk ( KERN_INFO " sisfb: WARNING: Refresh rate "
" exceeds monitor specs! \n " ) ;
2005-04-17 02:20:36 +04:00
}
}
ivideo - > video_bpp = sisbios_mode [ ivideo - > sisfb_mode_idx ] . bpp ;
ivideo - > video_width = sisbios_mode [ ivideo - > sisfb_mode_idx ] . xres ;
ivideo - > video_height = sisbios_mode [ ivideo - > sisfb_mode_idx ] . yres ;
sisfb_set_vparms ( ivideo ) ;
printk ( KERN_INFO " sisfb: Default mode is %dx%dx%d (%dHz) \n " ,
2005-09-10 00:04:45 +04:00
ivideo - > video_width , ivideo - > video_height , ivideo - > video_bpp ,
2005-04-17 02:20:36 +04:00
ivideo - > refresh_rate ) ;
2005-09-10 00:04:45 +04:00
/* Set up the default var according to chosen default display mode */
2005-04-17 02:20:36 +04:00
ivideo - > default_var . xres = ivideo - > default_var . xres_virtual = ivideo - > video_width ;
ivideo - > default_var . yres = ivideo - > default_var . yres_virtual = ivideo - > video_height ;
ivideo - > default_var . bits_per_pixel = ivideo - > video_bpp ;
sisfb_bpp_to_var ( ivideo , & ivideo - > default_var ) ;
2005-09-10 00:04:45 +04:00
2005-04-17 02:20:36 +04:00
ivideo - > default_var . pixclock = ( u32 ) ( 1000000000 /
2005-09-10 00:04:45 +04:00
sisfb_mode_rate_to_dclock ( & ivideo - > SiS_Pr , ivideo - > mode_no , ivideo - > rate_idx ) ) ;
if ( sisfb_mode_rate_to_ddata ( & ivideo - > SiS_Pr , ivideo - > mode_no ,
ivideo - > rate_idx , & ivideo - > default_var ) ) {
if ( ( ivideo - > default_var . vmode & FB_VMODE_MASK ) = = FB_VMODE_DOUBLE ) {
ivideo - > default_var . pixclock < < = 1 ;
}
}
2005-04-17 02:20:36 +04:00
if ( ivideo - > sisfb_ypan ) {
2005-09-10 00:04:45 +04:00
/* Maximize regardless of sisfb_max at startup */
ivideo - > default_var . yres_virtual =
sisfb_calc_maxyres ( ivideo , & ivideo - > default_var ) ;
if ( ivideo - > default_var . yres_virtual < ivideo - > default_var . yres ) {
ivideo - > default_var . yres_virtual = ivideo - > default_var . yres ;
}
2005-04-17 02:20:36 +04:00
}
sisfb_calc_pitch ( ivideo , & ivideo - > default_var ) ;
ivideo - > accel = 0 ;
if ( ivideo - > sisfb_accel ) {
2005-09-10 00:04:45 +04:00
ivideo - > accel = - 1 ;
2005-04-17 02:20:36 +04:00
# ifdef STUPID_ACCELF_TEXT_SHIT
2005-09-10 00:04:45 +04:00
ivideo - > default_var . accel_flags | = FB_ACCELF_TEXT ;
2005-04-17 02:20:36 +04:00
# endif
}
sisfb_initaccel ( ivideo ) ;
# if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
sis_fb_info - > flags = FBINFO_DEFAULT |
FBINFO_HWACCEL_YPAN |
FBINFO_HWACCEL_XPAN |
FBINFO_HWACCEL_COPYAREA |
FBINFO_HWACCEL_FILLRECT |
( ( ivideo - > accel ) ? 0 : FBINFO_HWACCEL_DISABLED ) ;
# else
sis_fb_info - > flags = FBINFO_FLAG_DEFAULT ;
# endif
sis_fb_info - > var = ivideo - > default_var ;
sis_fb_info - > fix = ivideo - > sisfb_fix ;
2005-09-10 00:04:45 +04:00
sis_fb_info - > screen_base = ivideo - > video_vbase + ivideo - > video_offset ;
2005-04-17 02:20:36 +04:00
sis_fb_info - > fbops = & sisfb_ops ;
sis_fb_info - > pseudo_palette = ivideo - > pseudo_palette ;
2005-09-10 00:04:45 +04:00
2005-04-17 02:20:36 +04:00
fb_alloc_cmap ( & sis_fb_info - > cmap , 256 , 0 ) ;
2005-09-10 00:04:45 +04:00
printk ( KERN_DEBUG " sisfb: Initial vbflags 0x%x \n " , ( int ) ivideo - > vbflags ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_MTRR
ivideo - > mtrr = mtrr_add ( ivideo - > video_base , ivideo - > video_size ,
MTRR_TYPE_WRCOMB , 1 ) ;
2005-09-10 00:04:45 +04:00
if ( ivideo - > mtrr < 0 ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_DEBUG " sisfb: Failed to add MTRRs \n " ) ;
}
# endif
if ( register_framebuffer ( sis_fb_info ) < 0 ) {
printk ( KERN_ERR " sisfb: Fatal error: Failed to register framebuffer \n " ) ;
2005-09-10 00:04:45 +04:00
ret = - EINVAL ;
2005-04-17 02:20:36 +04:00
iounmap ( ivideo - > mmio_vbase ) ;
2005-09-10 00:04:45 +04:00
goto error_0 ;
2005-04-17 02:20:36 +04:00
}
ivideo - > registered = 1 ;
/* Enlist us */
ivideo - > next = card_list ;
card_list = ivideo ;
printk ( KERN_INFO " sisfb: 2D acceleration is %s, y-panning %s \n " ,
2005-09-10 00:04:45 +04:00
ivideo - > sisfb_accel ? " enabled " : " disabled " ,
ivideo - > sisfb_ypan ?
( ivideo - > sisfb_max ? " enabled (auto-max) " :
" enabled (no auto-max) " ) :
" disabled " ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
printk ( KERN_INFO " fb%d: %s frame buffer device version %d.%d.%d \n " ,
2006-10-03 12:15:00 +04:00
sis_fb_info - > node , ivideo - > myid , VER_MAJOR , VER_MINOR , VER_LEVEL ) ;
2005-04-17 02:20:36 +04:00
2005-09-10 00:04:45 +04:00
printk ( KERN_INFO " sisfb: Copyright (C) 2001-2005 Thomas Winischhofer \n " ) ;
2005-04-17 02:20:36 +04:00
} /* if mode = "none" */
return 0 ;
}
/*****************************************************/
/* PCI DEVICE HANDLING */
/*****************************************************/
2012-12-22 01:07:39 +04:00
static void sisfb_remove ( struct pci_dev * pdev )
2005-04-17 02:20:36 +04:00
{
2005-09-10 00:04:45 +04:00
struct sis_video_info * ivideo = pci_get_drvdata ( pdev ) ;
struct fb_info * sis_fb_info = ivideo - > memyselfandi ;
int registered = ivideo - > registered ;
int modechanged = ivideo - > modechanged ;
2005-04-17 02:20:36 +04:00
/* Unmap */
iounmap ( ivideo - > mmio_vbase ) ;
2005-09-10 00:04:45 +04:00
iounmap ( ivideo - > video_vbase ) ;
2005-04-17 02:20:36 +04:00
/* Release mem regions */
release_mem_region ( ivideo - > video_base , ivideo - > video_size ) ;
release_mem_region ( ivideo - > mmio_base , ivideo - > mmio_size ) ;
2005-09-10 00:04:45 +04:00
vfree ( ivideo - > bios_abase ) ;
if ( ivideo - > lpcdev )
2007-05-08 11:39:50 +04:00
pci_dev_put ( ivideo - > lpcdev ) ;
2005-09-10 00:04:45 +04:00
if ( ivideo - > nbridge )
2007-05-08 11:39:50 +04:00
pci_dev_put ( ivideo - > nbridge ) ;
2005-09-10 00:04:45 +04:00
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_MTRR
/* Release MTRR region */
2005-09-10 00:04:45 +04:00
if ( ivideo - > mtrr > = 0 )
2005-04-17 02:20:36 +04:00
mtrr_del ( ivideo - > mtrr , ivideo - > video_base , ivideo - > video_size ) ;
# endif
2005-09-10 00:04:45 +04:00
pci_set_drvdata ( pdev , NULL ) ;
/* If device was disabled when starting, disable
* it when quitting .
*/
if ( ! ivideo - > sisvga_enabled )
pci_disable_device ( pdev ) ;
2005-04-17 02:20:36 +04:00
/* Unregister the framebuffer */
if ( ivideo - > registered ) {
unregister_framebuffer ( sis_fb_info ) ;
framebuffer_release ( sis_fb_info ) ;
}
2005-09-10 00:04:45 +04:00
/* OK, our ivideo is gone for good from here. */
2005-04-17 02:20:36 +04:00
/* TODO: Restore the initial mode
* This sounds easy but is as good as impossible
* on many machines with SiS chip and video bridge
* since text modes are always set up differently
* from machine to machine . Depends on the type
* of integration between chipset and bridge .
*/
2005-09-10 00:04:45 +04:00
if ( registered & & modechanged )
printk ( KERN_INFO
" sisfb: Restoring of text mode not supported yet \n " ) ;
2005-04-17 02:20:36 +04:00
} ;
static struct pci_driver sisfb_driver = {
. name = " sisfb " ,
. id_table = sisfb_pci_table ,
2005-09-10 00:04:45 +04:00
. probe = sisfb_probe ,
2012-12-22 01:07:39 +04:00
. remove = sisfb_remove ,
2005-04-17 02:20:36 +04:00
} ;
2008-07-24 08:31:12 +04:00
static int __init sisfb_init ( void )
2005-04-17 02:20:36 +04:00
{
# ifndef MODULE
char * options = NULL ;
if ( fb_get_options ( " sisfb " , & options ) )
return - ENODEV ;
2005-09-10 00:04:45 +04:00
2005-04-17 02:20:36 +04:00
sisfb_setup ( options ) ;
# endif
2005-09-10 00:04:45 +04:00
return pci_register_driver ( & sisfb_driver ) ;
2005-04-17 02:20:36 +04:00
}
# ifndef MODULE
module_init ( sisfb_init ) ;
# endif
/*****************************************************/
/* MODULE */
/*****************************************************/
# ifdef MODULE
2005-09-10 00:04:45 +04:00
static char * mode = NULL ;
static int vesa = - 1 ;
static unsigned int rate = 0 ;
static unsigned int crt1off = 1 ;
static unsigned int mem = 0 ;
static char * forcecrt2type = NULL ;
static int forcecrt1 = - 1 ;
static int pdc = - 1 ;
static int pdc1 = - 1 ;
static int noaccel = - 1 ;
static int noypan = - 1 ;
static int nomax = - 1 ;
static int userom = - 1 ;
static int useoem = - 1 ;
static char * tvstandard = NULL ;
static int nocrt2rate = 0 ;
static int scalelcd = - 1 ;
static char * specialtiming = NULL ;
static int lvdshl = - 1 ;
static int tvxposoffset = 0 , tvyposoffset = 0 ;
# if !defined(__i386__) && !defined(__x86_64__)
static int resetcard = 0 ;
static int videoram = 0 ;
# endif
static int __init sisfb_init_module ( void )
{
sisfb_setdefaultparms ( ) ;
if ( rate )
sisfb_parm_rate = rate ;
if ( ( scalelcd = = 0 ) | | ( scalelcd = = 1 ) )
sisfb_scalelcd = scalelcd ^ 1 ;
/* Need to check crt2 type first for fstn/dstn */
if ( forcecrt2type )
sisfb_search_crt2type ( forcecrt2type ) ;
if ( tvstandard )
sisfb_search_tvstd ( tvstandard ) ;
if ( mode )
2007-02-12 11:55:06 +03:00
sisfb_search_mode ( mode , false ) ;
2005-09-10 00:04:45 +04:00
else if ( vesa ! = - 1 )
2007-02-12 11:55:06 +03:00
sisfb_search_vesamode ( vesa , false ) ;
2005-09-10 00:04:45 +04:00
sisfb_crt1off = ( crt1off = = 0 ) ? 1 : 0 ;
sisfb_forcecrt1 = forcecrt1 ;
if ( forcecrt1 = = 1 )
sisfb_crt1off = 0 ;
else if ( forcecrt1 = = 0 )
sisfb_crt1off = 1 ;
if ( noaccel = = 1 )
sisfb_accel = 0 ;
else if ( noaccel = = 0 )
sisfb_accel = 1 ;
if ( noypan = = 1 )
sisfb_ypan = 0 ;
else if ( noypan = = 0 )
sisfb_ypan = 1 ;
if ( nomax = = 1 )
sisfb_max = 0 ;
else if ( nomax = = 0 )
sisfb_max = 1 ;
if ( mem )
sisfb_parm_mem = mem ;
if ( userom ! = - 1 )
sisfb_userom = userom ;
if ( useoem ! = - 1 )
sisfb_useoem = useoem ;
if ( pdc ! = - 1 )
sisfb_pdc = ( pdc & 0x7f ) ;
if ( pdc1 ! = - 1 )
sisfb_pdca = ( pdc1 & 0x1f ) ;
sisfb_nocrt2rate = nocrt2rate ;
if ( specialtiming )
sisfb_search_specialtiming ( specialtiming ) ;
if ( ( lvdshl > = 0 ) & & ( lvdshl < = 3 ) )
sisfb_lvdshl = lvdshl ;
sisfb_tvxposoffset = tvxposoffset ;
sisfb_tvyposoffset = tvyposoffset ;
2005-04-17 02:20:36 +04:00
# if !defined(__i386__) && !defined(__x86_64__)
2005-09-10 00:04:45 +04:00
sisfb_resetcard = ( resetcard ) ? 1 : 0 ;
if ( videoram )
sisfb_videoram = videoram ;
2005-04-17 02:20:36 +04:00
# endif
2005-09-10 00:04:45 +04:00
return sisfb_init ( ) ;
}
static void __exit sisfb_remove_module ( void )
{
pci_unregister_driver ( & sisfb_driver ) ;
printk ( KERN_DEBUG " sisfb: Module unloaded \n " ) ;
}
module_init ( sisfb_init_module ) ;
module_exit ( sisfb_remove_module ) ;
MODULE_DESCRIPTION ( " SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver " ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Thomas Winischhofer <thomas@winischhofer.net>, Others " ) ;
module_param ( mem , int , 0 ) ;
module_param ( noaccel , int , 0 ) ;
module_param ( noypan , int , 0 ) ;
module_param ( nomax , int , 0 ) ;
module_param ( userom , int , 0 ) ;
module_param ( useoem , int , 0 ) ;
module_param ( mode , charp , 0 ) ;
module_param ( vesa , int , 0 ) ;
module_param ( rate , int , 0 ) ;
module_param ( forcecrt1 , int , 0 ) ;
module_param ( forcecrt2type , charp , 0 ) ;
module_param ( scalelcd , int , 0 ) ;
module_param ( pdc , int , 0 ) ;
module_param ( pdc1 , int , 0 ) ;
module_param ( specialtiming , charp , 0 ) ;
module_param ( lvdshl , int , 0 ) ;
module_param ( tvstandard , charp , 0 ) ;
module_param ( tvxposoffset , int , 0 ) ;
module_param ( tvyposoffset , int , 0 ) ;
module_param ( nocrt2rate , int , 0 ) ;
# if !defined(__i386__) && !defined(__x86_64__)
module_param ( resetcard , int , 0 ) ;
module_param ( videoram , int , 0 ) ;
# endif
2005-09-10 00:04:45 +04:00
MODULE_PARM_DESC ( mem ,
" \n Determines the beginning of the video memory heap in KB. This heap is used \n "
" for video RAM management for eg. DRM/DRI. On 300 series, the default depends \n "
" on the amount of video RAM available. If 8MB of video RAM or less is available, \n "
" the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB, \n "
" otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default. \n "
" The value is to be specified without 'KB'. \n " ) ;
2005-04-17 02:20:36 +04:00
MODULE_PARM_DESC ( noaccel ,
2005-09-10 00:04:45 +04:00
" \n If set to anything other than 0, 2D acceleration will be disabled. \n "
2005-04-17 02:20:36 +04:00
" (default: 0) \n " ) ;
MODULE_PARM_DESC ( noypan ,
2005-09-10 00:04:45 +04:00
" \n If set to anything other than 0, y-panning will be disabled and scrolling \n "
" will be performed by redrawing the screen. (default: 0) \n " ) ;
2005-04-17 02:20:36 +04:00
MODULE_PARM_DESC ( nomax ,
2005-09-10 00:04:45 +04:00
" \n If y-panning is enabled, sisfb will by default use the entire available video \n "
2005-04-17 02:20:36 +04:00
" memory for the virtual screen in order to optimize scrolling performance. If \n "
" this is set to anything other than 0, sisfb will not do this and thereby \n "
" enable the user to positively specify a virtual Y size of the screen using \n "
" fbset. (default: 0) \n " ) ;
MODULE_PARM_DESC ( mode ,
2005-09-10 00:04:45 +04:00
" \n Selects the desired default display mode in the format XxYxDepth, \n "
" eg. 1024x768x16. Other formats supported include XxY-Depth and \n "
2005-04-17 02:20:36 +04:00
" XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal) \n "
" number, it will be interpreted as a VESA mode number. (default: 800x600x8) \n " ) ;
MODULE_PARM_DESC ( vesa ,
2005-09-10 00:04:45 +04:00
" \n Selects the desired default display mode by VESA defined mode number, eg. \n "
" 0x117 (default: 0x0103) \n " ) ;
2005-04-17 02:20:36 +04:00
MODULE_PARM_DESC ( rate ,
" \n Selects the desired vertical refresh rate for CRT1 (external VGA) in Hz. \n "
" If the mode is specified in the format XxY-Depth@Rate, this parameter \n "
" will be ignored (default: 60) \n " ) ;
MODULE_PARM_DESC ( forcecrt1 ,
" \n Normally, the driver autodetects whether or not CRT1 (external VGA) is \n "
" connected. With this option, the detection can be overridden (1=CRT1 ON, \n "
" 0=CRT1 OFF) (default: [autodetected]) \n " ) ;
MODULE_PARM_DESC ( forcecrt2type ,
" \n If this option is omitted, the driver autodetects CRT2 output devices, such as \n "
" LCD, TV or secondary VGA. With this option, this autodetection can be \n "
" overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2. \n "
" On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can \n "
" be used instead of TV to override the TV detection. Furthermore, on systems \n "
" with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P, \n "
" YPBPR720P and YPBPR1080I are understood. However, whether or not these work \n "
" depends on the very hardware in use. (default: [autodetected]) \n " ) ;
MODULE_PARM_DESC ( scalelcd ,
" \n Setting this to 1 will force the driver to scale the LCD image to the panel's \n "
" native resolution. Setting it to 0 will disable scaling; LVDS panels will \n "
" show black bars around the image, TMDS panels will probably do the scaling \n "
" themselves. Default: 1 on LVDS panels, 0 on TMDS panels \n " ) ;
MODULE_PARM_DESC ( pdc ,
2005-09-10 00:04:45 +04:00
" \n This is for manually selecting the LCD panel delay compensation. The driver \n "
2005-04-17 02:20:36 +04:00
" should detect this correctly in most cases; however, sometimes this is not \n "
" possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24 \n "
2005-09-10 00:04:45 +04:00
" on a 300 series chipset; 6 on other chipsets. If the problem persists, try \n "
" other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any \n "
" value from 0 to 31). (default: autodetected, if LCD is active during start) \n " ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_FB_SIS_315
MODULE_PARM_DESC ( pdc1 ,
2005-09-10 00:04:45 +04:00
" \n This is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340 \n "
2005-04-17 02:20:36 +04:00
" series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during \n "
" startup) - Note: currently, this has no effect because LCD-via-CRT1 is not \n "
" implemented yet. \n " ) ;
# endif
MODULE_PARM_DESC ( specialtiming ,
" \n Please refer to documentation for more information on this option. \n " ) ;
MODULE_PARM_DESC ( lvdshl ,
" \n Please refer to documentation for more information on this option. \n " ) ;
MODULE_PARM_DESC ( tvstandard ,
" \n This allows overriding the BIOS default for the TV standard. Valid choices are \n "
" pal, ntsc, palm and paln. (default: [auto; pal or ntsc only]) \n " ) ;
MODULE_PARM_DESC ( tvxposoffset ,
" \n Relocate TV output horizontally. Possible parameters: -32 through 32. \n "
" Default: 0 \n " ) ;
MODULE_PARM_DESC ( tvyposoffset ,
" \n Relocate TV output vertically. Possible parameters: -32 through 32. \n "
" Default: 0 \n " ) ;
MODULE_PARM_DESC ( nocrt2rate ,
" \n Setting this to 1 will force the driver to use the default refresh rate for \n "
" CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1) \n " ) ;
# if !defined(__i386__) && !defined(__x86_64__)
# ifdef CONFIG_FB_SIS_300
MODULE_PARM_DESC ( resetcard ,
" \n Set this to 1 in order to reset (POST) the card on non-x86 machines where \n "
2005-09-10 00:04:45 +04:00
" the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards \n "
" currently). Default: 0 \n " ) ;
2005-04-17 02:20:36 +04:00
MODULE_PARM_DESC ( videoram ,
" \n Set this to the amount of video RAM (in kilobyte) the card has. Required on \n "
" some non-x86 architectures where the memory auto detection fails. Only \n "
2005-09-10 00:04:45 +04:00
" relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect] \n " ) ;
2005-04-17 02:20:36 +04:00
# endif
# endif
# endif /* /MODULE */
2005-09-10 00:04:45 +04:00
/* _GPL only for new symbols. */
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( sis_malloc ) ;
EXPORT_SYMBOL ( sis_free ) ;
2005-09-10 00:04:45 +04:00
EXPORT_SYMBOL_GPL ( sis_malloc_new ) ;
EXPORT_SYMBOL_GPL ( sis_free_new ) ;
2005-04-17 02:20:36 +04:00