2005-04-17 02:20:36 +04:00
/*
2008-07-24 08:31:02 +04:00
* Frame buffer driver for Trident TGUI , Blade and Image series
2005-04-17 02:20:36 +04:00
*
2007-10-16 12:28:42 +04:00
* Copyright 2001 , 2002 - Jani Monoses < jani @ iv . ro >
2005-04-17 02:20:36 +04:00
*
*
* CREDITS : ( in order of appearance )
2007-10-16 12:28:42 +04:00
* skeletonfb . c by Geert Uytterhoeven and other fb code in drivers / video
* Special thanks ; ) to Mattia Crivellini < tia @ mclink . it >
* much inspired by the XFree86 4. x Trident driver sources
* by Alan Hourihane the FreeVGA project
* Francesco Salvestrini < salvestrini @ users . sf . net > XP support ,
* code , suggestions
2005-04-17 02:20:36 +04:00
* TODO :
2007-10-16 12:28:42 +04:00
* timing value tweaking so it looks good on every monitor in every mode
2005-04-17 02:20:36 +04:00
*/
# include <linux/module.h>
# include <linux/fb.h>
# include <linux/init.h>
# include <linux/pci.h>
# include <linux/delay.h>
2008-07-24 08:30:54 +04:00
# include <video/vga.h>
2005-04-17 02:20:36 +04:00
# include <video/trident.h>
struct tridentfb_par {
2007-10-16 12:28:42 +04:00
void __iomem * io_virt ; /* iospace virtual memory address */
2008-07-24 08:30:51 +04:00
u32 pseudo_pal [ 16 ] ;
2008-07-24 08:30:52 +04:00
int chip_id ;
2008-07-24 08:30:53 +04:00
int flatpanel ;
2008-07-24 08:30:54 +04:00
void ( * init_accel ) ( struct tridentfb_par * , int , int ) ;
void ( * wait_engine ) ( struct tridentfb_par * ) ;
void ( * fill_rect )
( struct tridentfb_par * par , u32 , u32 , u32 , u32 , u32 , u32 ) ;
void ( * copy_rect )
( struct tridentfb_par * par , u32 , u32 , u32 , u32 , u32 , u32 ) ;
2008-07-24 08:31:05 +04:00
unsigned char eng_oper ; /* engine operation... */
2005-04-17 02:20:36 +04:00
} ;
static struct fb_ops tridentfb_ops ;
static struct fb_fix_screeninfo tridentfb_fix = {
2007-10-16 12:28:42 +04:00
. id = " Trident " ,
2005-04-17 02:20:36 +04:00
. type = FB_TYPE_PACKED_PIXELS ,
. ypanstep = 1 ,
. visual = FB_VISUAL_PSEUDOCOLOR ,
. accel = FB_ACCEL_NONE ,
} ;
/* defaults which are normally overriden by user values */
/* video mode */
2008-07-24 08:31:05 +04:00
static char * mode_option __devinitdata = " 640x480-8@60 " ;
2008-07-24 08:30:53 +04:00
static int bpp __devinitdata = 8 ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:53 +04:00
static int noaccel __devinitdata ;
2005-04-17 02:20:36 +04:00
static int center ;
static int stretch ;
2008-07-24 08:30:53 +04:00
static int fp __devinitdata ;
static int crt __devinitdata ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:53 +04:00
static int memsize __devinitdata ;
static int memdiff __devinitdata ;
2005-04-17 02:20:36 +04:00
static int nativex ;
2008-04-28 13:15:06 +04:00
module_param ( mode_option , charp , 0 ) ;
MODULE_PARM_DESC ( mode_option , " Initial video mode e.g. '648x480-8@60' " ) ;
2008-04-28 13:15:10 +04:00
module_param_named ( mode , mode_option , charp , 0 ) ;
MODULE_PARM_DESC ( mode , " Initial video mode e.g. '648x480-8@60' (deprecated) " ) ;
2005-04-17 02:20:36 +04:00
module_param ( bpp , int , 0 ) ;
module_param ( center , int , 0 ) ;
module_param ( stretch , int , 0 ) ;
module_param ( noaccel , int , 0 ) ;
module_param ( memsize , int , 0 ) ;
module_param ( memdiff , int , 0 ) ;
module_param ( nativex , int , 0 ) ;
module_param ( fp , int , 0 ) ;
2008-07-24 08:30:53 +04:00
MODULE_PARM_DESC ( fp , " Define if flatpanel is connected " ) ;
2005-04-17 02:20:36 +04:00
module_param ( crt , int , 0 ) ;
2008-07-24 08:30:53 +04:00
MODULE_PARM_DESC ( crt , " Define if CRT is connected " ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:31:05 +04:00
static inline int is_oldclock ( int id )
2008-07-24 08:30:56 +04:00
{
2008-07-24 08:30:58 +04:00
return ( id = = TGUI9440 ) | |
( id = = TGUI9660 ) | |
2008-07-24 08:30:58 +04:00
( id = = CYBER9320 ) ;
}
2008-07-24 08:31:05 +04:00
static inline int is_oldprotect ( int id )
2008-07-24 08:30:58 +04:00
{
2008-07-24 08:31:05 +04:00
return is_oldclock ( id ) | |
2008-07-24 08:30:58 +04:00
( id = = PROVIDIA9685 ) | |
( id = = CYBER9382 ) | |
( id = = CYBER9385 ) ;
2008-07-24 08:30:56 +04:00
}
2008-07-24 08:31:05 +04:00
static inline int is_blade ( int id )
2008-07-24 08:30:53 +04:00
{
return ( id = = BLADE3D ) | |
( id = = CYBERBLADEE4 ) | |
( id = = CYBERBLADEi7 ) | |
( id = = CYBERBLADEi7D ) | |
( id = = CYBERBLADEi1 ) | |
( id = = CYBERBLADEi1D ) | |
( id = = CYBERBLADEAi1 ) | |
( id = = CYBERBLADEAi1D ) ;
}
2008-07-24 08:31:05 +04:00
static inline int is_xp ( int id )
2008-07-24 08:30:53 +04:00
{
return ( id = = CYBERBLADEXPAi1 ) | |
( id = = CYBERBLADEXPm8 ) | |
( id = = CYBERBLADEXPm16 ) ;
}
2008-07-24 08:31:05 +04:00
static inline int is3Dchip ( int id )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:31:05 +04:00
return is_blade ( id ) | | is_xp ( id ) | |
2007-10-16 12:28:42 +04:00
( id = = CYBER9397 ) | | ( id = = CYBER9397DVD ) | |
( id = = CYBER9520 ) | | ( id = = CYBER9525DVD ) | |
2008-07-24 08:31:05 +04:00
( id = = IMAGE975 ) | | ( id = = IMAGE985 ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:31:05 +04:00
static inline int iscyber ( int id )
2005-04-17 02:20:36 +04:00
{
switch ( id ) {
2007-10-16 12:28:42 +04:00
case CYBER9388 :
case CYBER9382 :
case CYBER9385 :
case CYBER9397 :
case CYBER9397DVD :
case CYBER9520 :
case CYBER9525DVD :
case CYBERBLADEE4 :
case CYBERBLADEi7D :
case CYBERBLADEi1 :
case CYBERBLADEi1D :
case CYBERBLADEAi1 :
case CYBERBLADEAi1D :
case CYBERBLADEXPAi1 :
return 1 ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:28:42 +04:00
case CYBER9320 :
case CYBERBLADEi7 : /* VIA MPV4 integrated version */
default :
/* case CYBERBLDAEXPm8: Strange */
/* case CYBERBLDAEXPm16: Strange */
return 0 ;
2005-04-17 02:20:36 +04:00
}
}
2008-07-24 08:30:50 +04:00
static inline void t_outb ( struct tridentfb_par * p , u8 val , u16 reg )
{
fb_writeb ( val , p - > io_virt + reg ) ;
}
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:50 +04:00
static inline u8 t_inb ( struct tridentfb_par * p , u16 reg )
{
return fb_readb ( p - > io_virt + reg ) ;
}
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:50 +04:00
static inline void writemmr ( struct tridentfb_par * par , u16 r , u32 v )
{
fb_writel ( v , par - > io_virt + r ) ;
}
static inline u32 readmmr ( struct tridentfb_par * par , u16 r )
{
return fb_readl ( par - > io_virt + r ) ;
}
2005-04-17 02:20:36 +04:00
/*
* Blade specific acceleration .
*/
2007-10-16 12:28:42 +04:00
# define point(x, y) ((y) << 16 | (x))
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:50 +04:00
static void blade_init_accel ( struct tridentfb_par * par , int pitch , int bpp )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:28:42 +04:00
int v1 = ( pitch > > 3 ) < < 20 ;
2008-07-24 08:31:02 +04:00
int tmp = bpp = = 24 ? 2 : ( bpp > > 4 ) ;
int v2 = v1 | ( tmp < < 29 ) ;
2008-07-24 08:30:50 +04:00
writemmr ( par , 0x21C0 , v2 ) ;
writemmr ( par , 0x21C4 , v2 ) ;
writemmr ( par , 0x21B8 , v2 ) ;
writemmr ( par , 0x21BC , v2 ) ;
writemmr ( par , 0x21D0 , v1 ) ;
writemmr ( par , 0x21D4 , v1 ) ;
writemmr ( par , 0x21C8 , v1 ) ;
writemmr ( par , 0x21CC , v1 ) ;
writemmr ( par , 0x216C , 0 ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:30:50 +04:00
static void blade_wait_engine ( struct tridentfb_par * par )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:31:02 +04:00
while ( readmmr ( par , STATUS ) & 0xFA800000 )
cpu_relax ( ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:30:50 +04:00
static void blade_fill_rect ( struct tridentfb_par * par ,
u32 x , u32 y , u32 w , u32 h , u32 c , u32 rop )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:31:02 +04:00
writemmr ( par , COLOR , c ) ;
writemmr ( par , ROP , rop ? ROP_X : ROP_S ) ;
2008-07-24 08:30:50 +04:00
writemmr ( par , CMD , 0x20000000 | 1 < < 19 | 1 < < 4 | 2 < < 2 ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:31:02 +04:00
writemmr ( par , DST1 , point ( x , y ) ) ;
writemmr ( par , DST2 , point ( x + w - 1 , y + h - 1 ) ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:30:50 +04:00
static void blade_copy_rect ( struct tridentfb_par * par ,
u32 x1 , u32 y1 , u32 x2 , u32 y2 , u32 w , u32 h )
2005-04-17 02:20:36 +04:00
{
int direction = 2 ;
2008-07-24 08:31:02 +04:00
u32 s1 = point ( x1 , y1 ) ;
u32 s2 = point ( x1 + w - 1 , y1 + h - 1 ) ;
u32 d1 = point ( x2 , y2 ) ;
u32 d2 = point ( x2 + w - 1 , y2 + h - 1 ) ;
2005-04-17 02:20:36 +04:00
if ( ( y1 > y2 ) | | ( ( y1 = = y2 ) & & ( x1 > x2 ) ) )
2007-10-16 12:28:42 +04:00
direction = 0 ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:50 +04:00
writemmr ( par , ROP , ROP_S ) ;
writemmr ( par , CMD , 0xE0000000 | 1 < < 19 | 1 < < 4 | 1 < < 2 | direction ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:31:02 +04:00
writemmr ( par , SRC1 , direction ? s2 : s1 ) ;
writemmr ( par , SRC2 , direction ? s1 : s2 ) ;
writemmr ( par , DST1 , direction ? d2 : d1 ) ;
writemmr ( par , DST2 , direction ? d1 : d2 ) ;
2005-04-17 02:20:36 +04:00
}
/*
* BladeXP specific acceleration functions
*/
2008-07-24 08:30:50 +04:00
static void xp_init_accel ( struct tridentfb_par * par , int pitch , int bpp )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:31:02 +04:00
unsigned char x = bpp = = 24 ? 3 : ( bpp > > 4 ) ;
int v1 = pitch < < ( bpp = = 24 ? 20 : ( 18 + x ) ) ;
2005-04-17 02:20:36 +04:00
switch ( pitch < < ( bpp > > 3 ) ) {
2007-10-16 12:28:42 +04:00
case 8192 :
case 512 :
x | = 0x00 ;
break ;
case 1024 :
x | = 0x04 ;
break ;
case 2048 :
x | = 0x08 ;
break ;
case 4096 :
x | = 0x0C ;
break ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:30:50 +04:00
t_outb ( par , x , 0x2125 ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:31:05 +04:00
par - > eng_oper = x | 0x40 ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:50 +04:00
writemmr ( par , 0x2154 , v1 ) ;
writemmr ( par , 0x2150 , v1 ) ;
t_outb ( par , 3 , 0x2126 ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:30:50 +04:00
static void xp_wait_engine ( struct tridentfb_par * par )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:31:05 +04:00
int count = 0 ;
int timeout = 0 ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:31:02 +04:00
while ( t_inb ( par , STATUS ) & 0x80 ) {
2005-04-17 02:20:36 +04:00
count + + ;
if ( count = = 10000000 ) {
/* Timeout */
count = 9990000 ;
timeout + + ;
if ( timeout = = 8 ) {
/* Reset engine */
2008-07-24 08:31:02 +04:00
t_outb ( par , 0x00 , STATUS ) ;
2005-04-17 02:20:36 +04:00
return ;
}
}
2008-07-24 08:31:02 +04:00
cpu_relax ( ) ;
2005-04-17 02:20:36 +04:00
}
}
2008-07-24 08:30:50 +04:00
static void xp_fill_rect ( struct tridentfb_par * par ,
u32 x , u32 y , u32 w , u32 h , u32 c , u32 rop )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:30:50 +04:00
writemmr ( par , 0x2127 , ROP_P ) ;
writemmr ( par , 0x2158 , c ) ;
2008-07-24 08:31:02 +04:00
writemmr ( par , DRAWFL , 0x4000 ) ;
writemmr ( par , OLDDIM , point ( h , w ) ) ;
writemmr ( par , OLDDST , point ( y , x ) ) ;
t_outb ( par , 0x01 , OLDCMD ) ;
2008-07-24 08:31:05 +04:00
t_outb ( par , par - > eng_oper , 0x2125 ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:30:50 +04:00
static void xp_copy_rect ( struct tridentfb_par * par ,
u32 x1 , u32 y1 , u32 x2 , u32 y2 , u32 w , u32 h )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:28:42 +04:00
u32 x1_tmp , x2_tmp , y1_tmp , y2_tmp ;
2008-07-24 08:31:05 +04:00
int direction = 0x0004 ;
2007-10-16 12:28:42 +04:00
2005-04-17 02:20:36 +04:00
if ( ( x1 < x2 ) & & ( y1 = = y2 ) ) {
direction | = 0x0200 ;
x1_tmp = x1 + w - 1 ;
x2_tmp = x2 + w - 1 ;
} else {
x1_tmp = x1 ;
x2_tmp = x2 ;
}
2007-10-16 12:28:42 +04:00
2005-04-17 02:20:36 +04:00
if ( y1 < y2 ) {
direction | = 0x0100 ;
y1_tmp = y1 + h - 1 ;
y2_tmp = y2 + h - 1 ;
2007-10-16 12:28:42 +04:00
} else {
2005-04-17 02:20:36 +04:00
y1_tmp = y1 ;
y2_tmp = y2 ;
}
2008-07-24 08:31:02 +04:00
writemmr ( par , DRAWFL , direction ) ;
2008-07-24 08:30:50 +04:00
t_outb ( par , ROP_S , 0x2127 ) ;
2008-07-24 08:31:02 +04:00
writemmr ( par , OLDSRC , point ( y1_tmp , x1_tmp ) ) ;
writemmr ( par , OLDDST , point ( y2_tmp , x2_tmp ) ) ;
writemmr ( par , OLDDIM , point ( h , w ) ) ;
t_outb ( par , 0x01 , OLDCMD ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Image specific acceleration functions
*/
2008-07-24 08:30:50 +04:00
static void image_init_accel ( struct tridentfb_par * par , int pitch , int bpp )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:31:02 +04:00
int tmp = bpp = = 24 ? 2 : ( bpp > > 4 ) ;
2008-07-24 08:30:50 +04:00
writemmr ( par , 0x2120 , 0xF0000000 ) ;
writemmr ( par , 0x2120 , 0x40000000 | tmp ) ;
writemmr ( par , 0x2120 , 0x80000000 ) ;
writemmr ( par , 0x2144 , 0x00000000 ) ;
writemmr ( par , 0x2148 , 0x00000000 ) ;
writemmr ( par , 0x2150 , 0x00000000 ) ;
writemmr ( par , 0x2154 , 0x00000000 ) ;
writemmr ( par , 0x2120 , 0x60000000 | ( pitch < < 16 ) | pitch ) ;
writemmr ( par , 0x216C , 0x00000000 ) ;
writemmr ( par , 0x2170 , 0x00000000 ) ;
writemmr ( par , 0x217C , 0x00000000 ) ;
writemmr ( par , 0x2120 , 0x10000000 ) ;
writemmr ( par , 0x2130 , ( 2047 < < 16 ) | 2047 ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:30:50 +04:00
static void image_wait_engine ( struct tridentfb_par * par )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:31:02 +04:00
while ( readmmr ( par , 0x2164 ) & 0xF0000000 )
cpu_relax ( ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:30:50 +04:00
static void image_fill_rect ( struct tridentfb_par * par ,
u32 x , u32 y , u32 w , u32 h , u32 c , u32 rop )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:30:50 +04:00
writemmr ( par , 0x2120 , 0x80000000 ) ;
writemmr ( par , 0x2120 , 0x90000000 | ROP_S ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:50 +04:00
writemmr ( par , 0x2144 , c ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:31:02 +04:00
writemmr ( par , DST1 , point ( x , y ) ) ;
writemmr ( par , DST2 , point ( x + w - 1 , y + h - 1 ) ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:50 +04:00
writemmr ( par , 0x2124 , 0x80000000 | 3 < < 22 | 1 < < 10 | 1 < < 9 ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:30:50 +04:00
static void image_copy_rect ( struct tridentfb_par * par ,
u32 x1 , u32 y1 , u32 x2 , u32 y2 , u32 w , u32 h )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:31:03 +04:00
int direction = 0x4 ;
2008-07-24 08:31:02 +04:00
u32 s1 = point ( x1 , y1 ) ;
u32 s2 = point ( x1 + w - 1 , y1 + h - 1 ) ;
u32 d1 = point ( x2 , y2 ) ;
u32 d2 = point ( x2 + w - 1 , y2 + h - 1 ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:28:42 +04:00
if ( ( y1 > y2 ) | | ( ( y1 = = y2 ) & & ( x1 > x2 ) ) )
direction = 0 ;
2008-07-24 08:30:50 +04:00
writemmr ( par , 0x2120 , 0x80000000 ) ;
writemmr ( par , 0x2120 , 0x90000000 | ROP_S ) ;
2007-10-16 12:28:42 +04:00
2008-07-24 08:31:02 +04:00
writemmr ( par , SRC1 , direction ? s2 : s1 ) ;
writemmr ( par , SRC2 , direction ? s1 : s2 ) ;
writemmr ( par , DST1 , direction ? d2 : d1 ) ;
writemmr ( par , DST2 , direction ? d1 : d2 ) ;
2008-07-24 08:30:50 +04:00
writemmr ( par , 0x2124 ,
0x80000000 | 1 < < 22 | 1 < < 10 | 1 < < 7 | direction ) ;
2007-10-16 12:28:42 +04:00
}
2005-04-17 02:20:36 +04:00
2008-07-24 08:31:01 +04:00
/*
* TGUI 9440 / 96 XX acceleration
*/
static void tgui_init_accel ( struct tridentfb_par * par , int pitch , int bpp )
{
2008-07-24 08:31:02 +04:00
unsigned char x = bpp = = 24 ? 3 : ( bpp > > 4 ) ;
2008-07-24 08:31:01 +04:00
/* disable clipping */
writemmr ( par , 0x2148 , 0 ) ;
writemmr ( par , 0x214C , point ( 4095 , 2047 ) ) ;
switch ( ( pitch * bpp ) / 8 ) {
case 8192 :
case 512 :
x | = 0x00 ;
break ;
case 1024 :
x | = 0x04 ;
break ;
case 2048 :
x | = 0x08 ;
break ;
case 4096 :
x | = 0x0C ;
break ;
}
fb_writew ( x , par - > io_virt + 0x2122 ) ;
}
static void tgui_fill_rect ( struct tridentfb_par * par ,
u32 x , u32 y , u32 w , u32 h , u32 c , u32 rop )
{
t_outb ( par , ROP_P , 0x2127 ) ;
2008-07-24 08:31:02 +04:00
writemmr ( par , OLDCLR , c ) ;
writemmr ( par , DRAWFL , 0x4020 ) ;
writemmr ( par , OLDDIM , point ( w - 1 , h - 1 ) ) ;
writemmr ( par , OLDDST , point ( x , y ) ) ;
t_outb ( par , 1 , OLDCMD ) ;
2008-07-24 08:31:01 +04:00
}
static void tgui_copy_rect ( struct tridentfb_par * par ,
u32 x1 , u32 y1 , u32 x2 , u32 y2 , u32 w , u32 h )
{
int flags = 0 ;
u16 x1_tmp , x2_tmp , y1_tmp , y2_tmp ;
if ( ( x1 < x2 ) & & ( y1 = = y2 ) ) {
flags | = 0x0200 ;
x1_tmp = x1 + w - 1 ;
x2_tmp = x2 + w - 1 ;
} else {
x1_tmp = x1 ;
x2_tmp = x2 ;
}
if ( y1 < y2 ) {
flags | = 0x0100 ;
y1_tmp = y1 + h - 1 ;
y2_tmp = y2 + h - 1 ;
} else {
y1_tmp = y1 ;
y2_tmp = y2 ;
}
2008-07-24 08:31:02 +04:00
writemmr ( par , DRAWFL , 0x4 | flags ) ;
2008-07-24 08:31:01 +04:00
t_outb ( par , ROP_S , 0x2127 ) ;
2008-07-24 08:31:02 +04:00
writemmr ( par , OLDSRC , point ( x1_tmp , y1_tmp ) ) ;
writemmr ( par , OLDDST , point ( x2_tmp , y2_tmp ) ) ;
writemmr ( par , OLDDIM , point ( w - 1 , h - 1 ) ) ;
t_outb ( par , 1 , OLDCMD ) ;
2008-07-24 08:31:01 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* Accel functions called by the upper layers
*/
# ifdef CONFIG_FB_TRIDENT_ACCEL
2007-10-16 12:28:42 +04:00
static void tridentfb_fillrect ( struct fb_info * info ,
const struct fb_fillrect * fr )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:30:50 +04:00
struct tridentfb_par * par = info - > par ;
2008-07-24 08:31:02 +04:00
int col ;
2007-10-16 12:28:42 +04:00
2008-07-24 08:31:04 +04:00
if ( info - > flags & FBINFO_HWACCEL_DISABLED ) {
cfb_fillrect ( info , fr ) ;
return ;
}
2008-07-24 08:31:02 +04:00
if ( info - > var . bits_per_pixel = = 8 ) {
col = fr - > color ;
2007-10-16 12:28:42 +04:00
col | = col < < 8 ;
col | = col < < 16 ;
2008-07-24 08:31:02 +04:00
} else
2007-10-16 12:28:42 +04:00
col = ( ( u32 * ) ( info - > pseudo_palette ) ) [ fr - > color ] ;
2008-07-24 08:31:02 +04:00
par - > wait_engine ( par ) ;
2008-07-24 08:30:54 +04:00
par - > fill_rect ( par , fr - > dx , fr - > dy , fr - > width ,
2008-07-24 08:30:50 +04:00
fr - > height , col , fr - > rop ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:31:02 +04:00
2007-10-16 12:28:42 +04:00
static void tridentfb_copyarea ( struct fb_info * info ,
const struct fb_copyarea * ca )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:30:50 +04:00
struct tridentfb_par * par = info - > par ;
2008-07-24 08:31:04 +04:00
if ( info - > flags & FBINFO_HWACCEL_DISABLED ) {
cfb_copyarea ( info , ca ) ;
return ;
}
2008-07-24 08:31:02 +04:00
par - > wait_engine ( par ) ;
2008-07-24 08:30:54 +04:00
par - > copy_rect ( par , ca - > sx , ca - > sy , ca - > dx , ca - > dy ,
2008-07-24 08:30:50 +04:00
ca - > width , ca - > height ) ;
2008-07-24 08:31:02 +04:00
}
static int tridentfb_sync ( struct fb_info * info )
{
struct tridentfb_par * par = info - > par ;
2008-07-24 08:31:04 +04:00
if ( ! ( info - > flags & FBINFO_HWACCEL_DISABLED ) )
par - > wait_engine ( par ) ;
2008-07-24 08:31:02 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:31:02 +04:00
# else
# define tridentfb_fillrect cfb_fillrect
# define tridentfb_copyarea cfb_copyarea
2005-04-17 02:20:36 +04:00
# endif /* CONFIG_FB_TRIDENT_ACCEL */
/*
* Hardware access functions
*/
2008-07-24 08:30:50 +04:00
static inline unsigned char read3X4 ( struct tridentfb_par * par , int reg )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:30:54 +04:00
return vga_mm_rcrt ( par - > io_virt , reg ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:30:50 +04:00
static inline void write3X4 ( struct tridentfb_par * par , int reg ,
unsigned char val )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:30:54 +04:00
vga_mm_wcrt ( par - > io_virt , reg , val ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:30:54 +04:00
static inline unsigned char read3CE ( struct tridentfb_par * par ,
unsigned char reg )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:30:54 +04:00
return vga_mm_rgfx ( par - > io_virt , reg ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:30:50 +04:00
static inline void writeAttr ( struct tridentfb_par * par , int reg ,
unsigned char val )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:30:54 +04:00
fb_readb ( par - > io_virt + VGA_IS1_RC ) ; /* flip-flop to index */
vga_mm_wattr ( par - > io_virt , reg , val ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:30:50 +04:00
static inline void write3CE ( struct tridentfb_par * par , int reg ,
unsigned char val )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:30:54 +04:00
vga_mm_wgfx ( par - > io_virt , reg , val ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:31:06 +04:00
static void enable_mmio ( struct tridentfb_par * par )
2005-04-17 02:20:36 +04:00
{
/* Goto New Mode */
2008-07-24 08:30:54 +04:00
vga_io_rseq ( 0x0B ) ;
2005-04-17 02:20:36 +04:00
/* Unprotect registers */
2008-07-24 08:30:54 +04:00
vga_io_wseq ( NewMode1 , 0x80 ) ;
2008-07-24 08:31:06 +04:00
if ( ! is_oldprotect ( par - > chip_id ) )
vga_io_wseq ( Protection , 0x92 ) ;
2007-10-16 12:28:42 +04:00
2005-04-17 02:20:36 +04:00
/* Enable MMIO */
2007-10-16 12:28:42 +04:00
outb ( PCIReg , 0x3D4 ) ;
2005-04-17 02:20:36 +04:00
outb ( inb ( 0x3D5 ) | 0x01 , 0x3D5 ) ;
2008-03-05 01:28:39 +03:00
}
2008-07-24 08:30:50 +04:00
static void disable_mmio ( struct tridentfb_par * par )
2008-03-05 01:28:39 +03:00
{
/* Goto New Mode */
2008-07-24 08:30:54 +04:00
vga_mm_rseq ( par - > io_virt , 0x0B ) ;
2008-03-05 01:28:39 +03:00
/* Unprotect registers */
2008-07-24 08:30:54 +04:00
vga_mm_wseq ( par - > io_virt , NewMode1 , 0x80 ) ;
2008-07-24 08:31:06 +04:00
if ( ! is_oldprotect ( par - > chip_id ) )
vga_mm_wseq ( par - > io_virt , Protection , 0x92 ) ;
2008-03-05 01:28:39 +03:00
/* Disable MMIO */
2008-07-24 08:30:50 +04:00
t_outb ( par , PCIReg , 0x3D4 ) ;
t_outb ( par , t_inb ( par , 0x3D5 ) & ~ 0x01 , 0x3D5 ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:31:05 +04:00
static inline void crtc_unlock ( struct tridentfb_par * par )
2008-07-24 08:30:50 +04:00
{
2008-07-24 08:30:54 +04:00
write3X4 ( par , VGA_CRTC_V_SYNC_END ,
read3X4 ( par , VGA_CRTC_V_SYNC_END ) & 0x7F ) ;
2008-07-24 08:30:50 +04:00
}
2005-04-17 02:20:36 +04:00
/* Return flat panel's maximum x resolution */
2008-07-24 08:30:50 +04:00
static int __devinit get_nativex ( struct tridentfb_par * par )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:28:42 +04:00
int x , y , tmp ;
2005-04-17 02:20:36 +04:00
if ( nativex )
return nativex ;
2008-07-24 08:30:50 +04:00
tmp = ( read3CE ( par , VertStretch ) > > 4 ) & 3 ;
2005-04-17 02:20:36 +04:00
switch ( tmp ) {
2007-10-16 12:28:42 +04:00
case 0 :
x = 1280 ; y = 1024 ;
break ;
case 2 :
x = 1024 ; y = 768 ;
break ;
case 3 :
x = 800 ; y = 600 ;
break ;
case 4 :
x = 1400 ; y = 1050 ;
break ;
case 1 :
default :
x = 640 ; y = 480 ;
break ;
2005-04-17 02:20:36 +04:00
}
output ( " %dx%d flat panel found \n " , x , y ) ;
return x ;
}
/* Set pitch */
2008-07-24 08:31:05 +04:00
static inline void set_lwidth ( struct tridentfb_par * par , int width )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:30:54 +04:00
write3X4 ( par , VGA_CRTC_OFFSET , width & 0xFF ) ;
2008-07-24 08:30:50 +04:00
write3X4 ( par , AddColReg ,
( read3X4 ( par , AddColReg ) & 0xCF ) | ( ( width & 0x300 ) > > 4 ) ) ;
2005-04-17 02:20:36 +04:00
}
/* For resolutions smaller than FP resolution stretch */
2008-07-24 08:30:50 +04:00
static void screen_stretch ( struct tridentfb_par * par )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:30:52 +04:00
if ( par - > chip_id ! = CYBERBLADEXPAi1 )
2008-07-24 08:30:50 +04:00
write3CE ( par , BiosReg , 0 ) ;
2007-10-16 12:28:42 +04:00
else
2008-07-24 08:30:50 +04:00
write3CE ( par , BiosReg , 8 ) ;
write3CE ( par , VertStretch , ( read3CE ( par , VertStretch ) & 0x7C ) | 1 ) ;
write3CE ( par , HorStretch , ( read3CE ( par , HorStretch ) & 0x7C ) | 1 ) ;
2005-04-17 02:20:36 +04:00
}
/* For resolutions smaller than FP resolution center */
2008-07-24 08:31:05 +04:00
static inline void screen_center ( struct tridentfb_par * par )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:30:50 +04:00
write3CE ( par , VertStretch , ( read3CE ( par , VertStretch ) & 0x7C ) | 0x80 ) ;
write3CE ( par , HorStretch , ( read3CE ( par , HorStretch ) & 0x7C ) | 0x80 ) ;
2005-04-17 02:20:36 +04:00
}
/* Address of first shown pixel in display memory */
2008-07-24 08:30:50 +04:00
static void set_screen_start ( struct tridentfb_par * par , int base )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:30:50 +04:00
u8 tmp ;
2008-07-24 08:30:54 +04:00
write3X4 ( par , VGA_CRTC_START_LO , base & 0xFF ) ;
write3X4 ( par , VGA_CRTC_START_HI , ( base & 0xFF00 ) > > 8 ) ;
2008-07-24 08:30:50 +04:00
tmp = read3X4 ( par , CRTCModuleTest ) & 0xDF ;
write3X4 ( par , CRTCModuleTest , tmp | ( ( base & 0x10000 ) > > 11 ) ) ;
tmp = read3X4 ( par , CRTHiOrd ) & 0xF8 ;
write3X4 ( par , CRTHiOrd , tmp | ( ( base & 0xE0000 ) > > 17 ) ) ;
2005-04-17 02:20:36 +04:00
}
/* Set dotclock frequency */
2008-07-24 08:30:50 +04:00
static void set_vclk ( struct tridentfb_par * par , unsigned long freq )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:28:42 +04:00
int m , n , k ;
2008-07-24 08:30:56 +04:00
unsigned long fi , d , di ;
unsigned char best_m = 0 , best_n = 0 , best_k = 0 ;
unsigned char hi , lo ;
2005-04-17 02:20:36 +04:00
2008-05-13 01:02:11 +04:00
d = 20000 ;
2008-07-24 08:30:56 +04:00
for ( k = 1 ; k > = 0 ; k - - )
2008-07-24 08:31:04 +04:00
for ( m = 0 ; m < 32 ; m + + ) {
n = 2 * ( m + 2 ) - 8 ;
for ( n = ( n < 0 ? 0 : n ) ; n < 122 ; n + + ) {
2008-05-13 01:02:11 +04:00
fi = ( ( 14318l * ( n + 8 ) ) / ( m + 2 ) ) > > k ;
2008-07-24 08:31:04 +04:00
di = abs ( fi - freq ) ;
if ( di < = d ) {
2007-10-16 12:28:42 +04:00
d = di ;
2008-07-24 08:30:56 +04:00
best_n = n ;
best_m = m ;
best_k = k ;
2007-10-16 12:28:42 +04:00
}
2008-05-13 01:02:11 +04:00
if ( fi > freq )
break ;
2007-10-16 12:28:42 +04:00
}
2008-07-24 08:31:04 +04:00
}
2008-07-24 08:30:56 +04:00
if ( is_oldclock ( par - > chip_id ) ) {
lo = best_n | ( best_m < < 7 ) ;
hi = ( best_m > > 1 ) | ( best_k < < 4 ) ;
} else {
lo = best_n ;
hi = best_m | ( best_k < < 6 ) ;
}
2008-07-24 08:30:52 +04:00
if ( is3Dchip ( par - > chip_id ) ) {
2008-07-24 08:30:54 +04:00
vga_mm_wseq ( par - > io_virt , ClockHigh , hi ) ;
vga_mm_wseq ( par - > io_virt , ClockLow , lo ) ;
2005-04-17 02:20:36 +04:00
} else {
2008-07-24 08:30:56 +04:00
t_outb ( par , lo , 0x43C8 ) ;
t_outb ( par , hi , 0x43C9 ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:28:42 +04:00
debug ( " VCLK = %X %X \n " , hi , lo ) ;
2005-04-17 02:20:36 +04:00
}
/* Set number of lines for flat panels*/
2008-07-24 08:30:50 +04:00
static void set_number_of_lines ( struct tridentfb_par * par , int lines )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:30:50 +04:00
int tmp = read3CE ( par , CyberEnhance ) & 0x8F ;
2005-04-17 02:20:36 +04:00
if ( lines > 1024 )
tmp | = 0x50 ;
else if ( lines > 768 )
tmp | = 0x30 ;
else if ( lines > 600 )
tmp | = 0x20 ;
else if ( lines > 480 )
tmp | = 0x10 ;
2008-07-24 08:30:50 +04:00
write3CE ( par , CyberEnhance , tmp ) ;
2005-04-17 02:20:36 +04:00
}
/*
* If we see that FP is active we assume we have one .
2008-07-24 08:30:53 +04:00
* Otherwise we have a CRT display . User can override .
2005-04-17 02:20:36 +04:00
*/
2008-07-24 08:30:53 +04:00
static int __devinit is_flatpanel ( struct tridentfb_par * par )
2005-04-17 02:20:36 +04:00
{
if ( fp )
2008-07-24 08:30:53 +04:00
return 1 ;
2008-07-24 08:30:52 +04:00
if ( crt | | ! iscyber ( par - > chip_id ) )
2008-07-24 08:30:53 +04:00
return 0 ;
return ( read3CE ( par , FPConfig ) & 0x10 ) ? 1 : 0 ;
2005-04-17 02:20:36 +04:00
}
/* Try detecting the video memory size */
2008-07-24 08:30:50 +04:00
static unsigned int __devinit get_memsize ( struct tridentfb_par * par )
2005-04-17 02:20:36 +04:00
{
unsigned char tmp , tmp2 ;
unsigned int k ;
/* If memory size provided by user */
if ( memsize )
k = memsize * Kb ;
else
2008-07-24 08:30:52 +04:00
switch ( par - > chip_id ) {
2007-10-16 12:28:42 +04:00
case CYBER9525DVD :
k = 2560 * Kb ;
break ;
2005-04-17 02:20:36 +04:00
default :
2008-07-24 08:30:50 +04:00
tmp = read3X4 ( par , SPR ) & 0x0F ;
2005-04-17 02:20:36 +04:00
switch ( tmp ) {
2007-10-16 12:28:42 +04:00
case 0x01 :
2008-03-10 21:43:37 +03:00
k = 512 * Kb ;
2007-10-16 12:28:42 +04:00
break ;
case 0x02 :
k = 6 * Mb ; /* XP */
break ;
case 0x03 :
k = 1 * Mb ;
break ;
case 0x04 :
k = 8 * Mb ;
break ;
case 0x06 :
k = 10 * Mb ; /* XP */
break ;
case 0x07 :
k = 2 * Mb ;
break ;
case 0x08 :
k = 12 * Mb ; /* XP */
break ;
case 0x0A :
k = 14 * Mb ; /* XP */
break ;
case 0x0C :
k = 16 * Mb ; /* XP */
break ;
case 0x0E : /* XP */
2008-07-24 08:30:54 +04:00
tmp2 = vga_mm_rseq ( par - > io_virt , 0xC1 ) ;
2007-10-16 12:28:42 +04:00
switch ( tmp2 ) {
case 0x00 :
k = 20 * Mb ;
break ;
case 0x01 :
k = 24 * Mb ;
break ;
case 0x10 :
k = 28 * Mb ;
break ;
case 0x11 :
k = 32 * Mb ;
break ;
default :
k = 1 * Mb ;
break ;
}
break ;
case 0x0F :
k = 4 * Mb ;
break ;
default :
k = 1 * Mb ;
2005-04-17 02:20:36 +04:00
break ;
}
2007-10-16 12:28:42 +04:00
}
2005-04-17 02:20:36 +04:00
k - = memdiff * Kb ;
2007-10-16 12:28:42 +04:00
output ( " framebuffer size = %d Kb \n " , k / Kb ) ;
2005-04-17 02:20:36 +04:00
return k ;
}
/* See if we can handle the video mode described in var */
2007-10-16 12:28:42 +04:00
static int tridentfb_check_var ( struct fb_var_screeninfo * var ,
struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:30:53 +04:00
struct tridentfb_par * par = info - > par ;
2005-04-17 02:20:36 +04:00
int bpp = var - > bits_per_pixel ;
2008-07-24 08:31:01 +04:00
int line_length ;
2008-07-24 08:31:00 +04:00
int ramdac = 230000 ; /* 230MHz for most 3D chips */
2005-04-17 02:20:36 +04:00
debug ( " enter \n " ) ;
/* check color depth */
2007-10-16 12:28:42 +04:00
if ( bpp = = 24 )
2005-04-17 02:20:36 +04:00
bpp = var - > bits_per_pixel = 32 ;
2008-07-24 08:31:02 +04:00
if ( bpp ! = 8 & & bpp ! = 16 & & bpp ! = 32 )
return - EINVAL ;
2008-07-24 08:31:01 +04:00
if ( par - > chip_id = = TGUI9440 & & bpp = = 32 )
return - EINVAL ;
2007-10-16 12:28:42 +04:00
/* check whether resolution fits on panel and in memory */
2008-07-24 08:30:53 +04:00
if ( par - > flatpanel & & nativex & & var - > xres > nativex )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2008-07-24 08:31:00 +04:00
/* various resolution checks */
var - > xres = ( var - > xres + 7 ) & ~ 0x7 ;
2008-07-24 08:31:02 +04:00
if ( var - > xres > var - > xres_virtual )
2008-07-24 08:31:00 +04:00
var - > xres_virtual = var - > xres ;
2008-07-24 08:31:02 +04:00
if ( var - > yres > var - > yres_virtual )
var - > yres_virtual = var - > yres ;
if ( var - > xres_virtual > 4095 | | var - > yres > 2048 )
return - EINVAL ;
/* prevent from position overflow for acceleration */
if ( var - > yres_virtual > 0xffff )
return - EINVAL ;
2008-07-24 08:31:01 +04:00
line_length = var - > xres_virtual * bpp / 8 ;
2008-07-24 08:31:04 +04:00
if ( ! is3Dchip ( par - > chip_id ) & &
! ( info - > flags & FBINFO_HWACCEL_DISABLED ) ) {
2008-07-24 08:31:01 +04:00
/* acceleration requires line length to be power of 2 */
if ( line_length < = 512 )
var - > xres_virtual = 512 * 8 / bpp ;
else if ( line_length < = 1024 )
var - > xres_virtual = 1024 * 8 / bpp ;
else if ( line_length < = 2048 )
var - > xres_virtual = 2048 * 8 / bpp ;
else if ( line_length < = 4096 )
var - > xres_virtual = 4096 * 8 / bpp ;
else if ( line_length < = 8192 )
var - > xres_virtual = 8192 * 8 / bpp ;
2008-07-24 08:31:02 +04:00
else
return - EINVAL ;
2008-07-24 08:31:01 +04:00
line_length = var - > xres_virtual * bpp / 8 ;
}
2008-07-24 08:31:04 +04:00
2008-07-24 08:31:00 +04:00
if ( var - > yres > var - > yres_virtual )
var - > yres_virtual = var - > yres ;
2008-07-24 08:31:01 +04:00
if ( line_length * var - > yres_virtual > info - > fix . smem_len )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
switch ( bpp ) {
2007-10-16 12:28:42 +04:00
case 8 :
var - > red . offset = 0 ;
2008-07-24 08:31:06 +04:00
var - > red . length = 8 ;
var - > green = var - > red ;
var - > blue = var - > red ;
2007-10-16 12:28:42 +04:00
break ;
case 16 :
var - > red . offset = 11 ;
var - > green . offset = 5 ;
var - > blue . offset = 0 ;
var - > red . length = 5 ;
var - > green . length = 6 ;
var - > blue . length = 5 ;
break ;
case 32 :
var - > red . offset = 16 ;
var - > green . offset = 8 ;
var - > blue . offset = 0 ;
var - > red . length = 8 ;
var - > green . length = 8 ;
var - > blue . length = 8 ;
break ;
default :
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:31:00 +04:00
if ( is_xp ( par - > chip_id ) )
ramdac = 350000 ;
switch ( par - > chip_id ) {
case TGUI9440 :
2008-07-24 08:31:01 +04:00
ramdac = ( bpp > = 16 ) ? 45000 : 90000 ;
2008-07-24 08:31:00 +04:00
break ;
case CYBER9320 :
case TGUI9660 :
ramdac = 135000 ;
break ;
case PROVIDIA9685 :
case CYBER9388 :
case CYBER9382 :
case CYBER9385 :
ramdac = 170000 ;
break ;
}
/* The clock is doubled for 32 bpp */
if ( bpp = = 32 )
ramdac / = 2 ;
if ( PICOS2KHZ ( var - > pixclock ) > ramdac )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
debug ( " exit \n " ) ;
return 0 ;
}
2007-10-16 12:28:42 +04:00
2005-04-17 02:20:36 +04:00
/* Pan the display */
static int tridentfb_pan_display ( struct fb_var_screeninfo * var ,
2007-10-16 12:28:42 +04:00
struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:30:50 +04:00
struct tridentfb_par * par = info - > par ;
2005-04-17 02:20:36 +04:00
unsigned int offset ;
debug ( " enter \n " ) ;
2008-07-24 08:31:01 +04:00
offset = ( var - > xoffset + ( var - > yoffset * var - > xres_virtual ) )
2007-10-16 12:28:42 +04:00
* var - > bits_per_pixel / 32 ;
2005-04-17 02:20:36 +04:00
info - > var . xoffset = var - > xoffset ;
info - > var . yoffset = var - > yoffset ;
2008-07-24 08:30:50 +04:00
set_screen_start ( par , offset ) ;
2005-04-17 02:20:36 +04:00
debug ( " exit \n " ) ;
return 0 ;
}
2008-07-24 08:31:05 +04:00
static inline void shadowmode_on ( struct tridentfb_par * par )
2008-07-24 08:30:50 +04:00
{
write3CE ( par , CyberControl , read3CE ( par , CyberControl ) | 0x81 ) ;
}
2008-07-24 08:31:05 +04:00
static inline void shadowmode_off ( struct tridentfb_par * par )
2008-07-24 08:30:50 +04:00
{
write3CE ( par , CyberControl , read3CE ( par , CyberControl ) & 0x7E ) ;
}
2005-04-17 02:20:36 +04:00
/* Set the hardware to the requested video mode */
static int tridentfb_set_par ( struct fb_info * info )
{
2008-07-24 08:31:05 +04:00
struct tridentfb_par * par = info - > par ;
2007-10-16 12:28:42 +04:00
u32 htotal , hdispend , hsyncstart , hsyncend , hblankstart , hblankend ;
u32 vtotal , vdispend , vsyncstart , vsyncend , vblankstart , vblankend ;
struct fb_var_screeninfo * var = & info - > var ;
2005-04-17 02:20:36 +04:00
int bpp = var - > bits_per_pixel ;
unsigned char tmp ;
2008-05-13 01:02:11 +04:00
unsigned long vclk ;
2005-04-17 02:20:36 +04:00
debug ( " enter \n " ) ;
2007-10-16 12:28:42 +04:00
hdispend = var - > xres / 8 - 1 ;
2008-07-24 08:31:04 +04:00
hsyncstart = ( var - > xres + var - > right_margin ) / 8 ;
hsyncend = ( var - > xres + var - > right_margin + var - > hsync_len ) / 8 ;
2008-07-24 08:30:55 +04:00
htotal = ( var - > xres + var - > left_margin + var - > right_margin +
var - > hsync_len ) / 8 - 5 ;
2008-07-24 08:30:58 +04:00
hblankstart = hdispend + 1 ;
2008-07-24 08:30:55 +04:00
hblankend = htotal + 3 ;
2005-04-17 02:20:36 +04:00
vdispend = var - > yres - 1 ;
vsyncstart = var - > yres + var - > lower_margin ;
2008-07-24 08:30:55 +04:00
vsyncend = vsyncstart + var - > vsync_len ;
vtotal = var - > upper_margin + vsyncend - 2 ;
2008-07-24 08:30:58 +04:00
vblankstart = vdispend + 1 ;
2008-07-24 08:30:55 +04:00
vblankend = vtotal ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:31:04 +04:00
if ( info - > var . vmode & FB_VMODE_INTERLACED ) {
vtotal / = 2 ;
vdispend / = 2 ;
vsyncstart / = 2 ;
vsyncend / = 2 ;
vblankstart / = 2 ;
vblankend / = 2 ;
}
2008-07-24 08:31:06 +04:00
enable_mmio ( par ) ;
2008-07-24 08:30:50 +04:00
crtc_unlock ( par ) ;
write3CE ( par , CyberControl , 8 ) ;
2008-07-24 08:31:04 +04:00
tmp = 0xEB ;
if ( var - > sync & FB_SYNC_HOR_HIGH_ACT )
tmp & = ~ 0x40 ;
if ( var - > sync & FB_SYNC_VERT_HIGH_ACT )
tmp & = ~ 0x80 ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:53 +04:00
if ( par - > flatpanel & & var - > xres < nativex ) {
2005-04-17 02:20:36 +04:00
/*
* on flat panels with native size larger
* than requested resolution decide whether
* we stretch or center
*/
2008-07-24 08:31:04 +04:00
t_outb ( par , tmp | 0xC0 , VGA_MIS_W ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:50 +04:00
shadowmode_on ( par ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:28:42 +04:00
if ( center )
2008-07-24 08:30:50 +04:00
screen_center ( par ) ;
2005-04-17 02:20:36 +04:00
else if ( stretch )
2008-07-24 08:30:50 +04:00
screen_stretch ( par ) ;
2005-04-17 02:20:36 +04:00
} else {
2008-07-24 08:31:04 +04:00
t_outb ( par , tmp , VGA_MIS_W ) ;
2008-07-24 08:30:50 +04:00
write3CE ( par , CyberControl , 8 ) ;
2005-04-17 02:20:36 +04:00
}
/* vertical timing values */
2008-07-24 08:30:54 +04:00
write3X4 ( par , VGA_CRTC_V_TOTAL , vtotal & 0xFF ) ;
write3X4 ( par , VGA_CRTC_V_DISP_END , vdispend & 0xFF ) ;
write3X4 ( par , VGA_CRTC_V_SYNC_START , vsyncstart & 0xFF ) ;
write3X4 ( par , VGA_CRTC_V_SYNC_END , ( vsyncend & 0x0F ) ) ;
write3X4 ( par , VGA_CRTC_V_BLANK_START , vblankstart & 0xFF ) ;
2008-07-24 08:30:55 +04:00
write3X4 ( par , VGA_CRTC_V_BLANK_END , vblankend & 0xFF ) ;
2005-04-17 02:20:36 +04:00
/* horizontal timing values */
2008-07-24 08:30:54 +04:00
write3X4 ( par , VGA_CRTC_H_TOTAL , htotal & 0xFF ) ;
write3X4 ( par , VGA_CRTC_H_DISP , hdispend & 0xFF ) ;
write3X4 ( par , VGA_CRTC_H_SYNC_START , hsyncstart & 0xFF ) ;
write3X4 ( par , VGA_CRTC_H_SYNC_END ,
2008-07-24 08:30:50 +04:00
( hsyncend & 0x1F ) | ( ( hblankend & 0x20 ) < < 2 ) ) ;
2008-07-24 08:30:54 +04:00
write3X4 ( par , VGA_CRTC_H_BLANK_START , hblankstart & 0xFF ) ;
2008-07-24 08:30:55 +04:00
write3X4 ( par , VGA_CRTC_H_BLANK_END , hblankend & 0x1F ) ;
2005-04-17 02:20:36 +04:00
/* higher bits of vertical timing values */
tmp = 0x10 ;
if ( vtotal & 0x100 ) tmp | = 0x01 ;
if ( vdispend & 0x100 ) tmp | = 0x02 ;
if ( vsyncstart & 0x100 ) tmp | = 0x04 ;
if ( vblankstart & 0x100 ) tmp | = 0x08 ;
if ( vtotal & 0x200 ) tmp | = 0x20 ;
if ( vdispend & 0x200 ) tmp | = 0x40 ;
if ( vsyncstart & 0x200 ) tmp | = 0x80 ;
2008-07-24 08:30:54 +04:00
write3X4 ( par , VGA_CRTC_OVERFLOW , tmp ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:55 +04:00
tmp = read3X4 ( par , CRTHiOrd ) & 0x07 ;
tmp | = 0x08 ; /* line compare bit 10 */
2005-04-17 02:20:36 +04:00
if ( vtotal & 0x400 ) tmp | = 0x80 ;
if ( vblankstart & 0x400 ) tmp | = 0x40 ;
if ( vsyncstart & 0x400 ) tmp | = 0x20 ;
if ( vdispend & 0x400 ) tmp | = 0x10 ;
2008-07-24 08:30:50 +04:00
write3X4 ( par , CRTHiOrd , tmp ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:55 +04:00
tmp = ( htotal > > 8 ) & 0x01 ;
tmp | = ( hdispend > > 7 ) & 0x02 ;
tmp | = ( hsyncstart > > 5 ) & 0x08 ;
tmp | = ( hblankstart > > 4 ) & 0x10 ;
2008-07-24 08:30:50 +04:00
write3X4 ( par , HorizOverflow , tmp ) ;
2007-10-16 12:28:42 +04:00
2005-04-17 02:20:36 +04:00
tmp = 0x40 ;
if ( vblankstart & 0x200 ) tmp | = 0x20 ;
2007-10-16 12:28:42 +04:00
//FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; /* double scan for 200 line modes */
2008-07-24 08:30:54 +04:00
write3X4 ( par , VGA_CRTC_MAX_SCAN , tmp ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:54 +04:00
write3X4 ( par , VGA_CRTC_LINE_COMPARE , 0xFF ) ;
write3X4 ( par , VGA_CRTC_PRESET_ROW , 0 ) ;
write3X4 ( par , VGA_CRTC_MODE , 0xC3 ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:50 +04:00
write3X4 ( par , LinearAddReg , 0x20 ) ; /* enable linear addressing */
2005-04-17 02:20:36 +04:00
2007-10-16 12:28:42 +04:00
tmp = ( info - > var . vmode & FB_VMODE_INTERLACED ) ? 0x84 : 0x80 ;
2008-07-24 08:30:50 +04:00
/* enable access extended memory */
write3X4 ( par , CRTCModuleTest , tmp ) ;
2008-07-24 08:31:04 +04:00
tmp = read3CE ( par , MiscIntContReg ) & ~ 0x4 ;
if ( info - > var . vmode & FB_VMODE_INTERLACED )
tmp | = 0x4 ;
write3CE ( par , MiscIntContReg , tmp ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:50 +04:00
/* enable GE for text acceleration */
write3X4 ( par , GraphEngReg , 0x80 ) ;
2005-04-17 02:20:36 +04:00
switch ( bpp ) {
2007-10-16 12:28:42 +04:00
case 8 :
tmp = 0x00 ;
break ;
case 16 :
tmp = 0x05 ;
break ;
case 24 :
tmp = 0x29 ;
break ;
case 32 :
tmp = 0x09 ;
break ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:30:50 +04:00
write3X4 ( par , PixelBusReg , tmp ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:58 +04:00
tmp = read3X4 ( par , DRAMControl ) ;
if ( ! is_oldprotect ( par - > chip_id ) )
tmp | = 0x10 ;
2008-07-24 08:30:52 +04:00
if ( iscyber ( par - > chip_id ) )
2007-10-16 12:28:42 +04:00
tmp | = 0x20 ;
2008-07-24 08:30:50 +04:00
write3X4 ( par , DRAMControl , tmp ) ; /* both IO, linear enable */
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:50 +04:00
write3X4 ( par , InterfaceSel , read3X4 ( par , InterfaceSel ) | 0x40 ) ;
2008-07-24 08:30:58 +04:00
if ( ! is_xp ( par - > chip_id ) )
write3X4 ( par , Performance , read3X4 ( par , Performance ) | 0x10 ) ;
2008-07-24 08:30:50 +04:00
/* MMIO & PCI read and write burst enable */
2008-07-24 08:31:06 +04:00
if ( par - > chip_id ! = TGUI9440 & & par - > chip_id ! = IMAGE975 )
2008-07-24 08:30:58 +04:00
write3X4 ( par , PCIReg , read3X4 ( par , PCIReg ) | 0x06 ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:54 +04:00
vga_mm_wseq ( par - > io_virt , 0 , 3 ) ;
vga_mm_wseq ( par - > io_virt , 1 , 1 ) ; /* set char clock 8 dots wide */
2008-07-24 08:30:50 +04:00
/* enable 4 maps because needed in chain4 mode */
2008-07-24 08:30:54 +04:00
vga_mm_wseq ( par - > io_virt , 2 , 0x0F ) ;
vga_mm_wseq ( par - > io_virt , 3 , 0 ) ;
vga_mm_wseq ( par - > io_virt , 4 , 0x0E ) ; /* memory mode enable bitmaps ?? */
2005-04-17 02:20:36 +04:00
2008-07-24 08:31:01 +04:00
/* convert from picoseconds to kHz */
vclk = PICOS2KHZ ( info - > var . pixclock ) ;
2008-07-24 08:30:50 +04:00
/* divide clock by 2 if 32bpp chain4 mode display and CPU path */
2008-07-24 08:31:00 +04:00
tmp = read3CE ( par , MiscExtFunc ) & 0xF0 ;
2008-07-24 08:31:01 +04:00
if ( bpp = = 32 | | ( par - > chip_id = = TGUI9440 & & bpp = = 16 ) ) {
2008-07-24 08:31:00 +04:00
tmp | = 8 ;
2008-07-24 08:31:01 +04:00
vclk * = 2 ;
}
set_vclk ( par , vclk ) ;
2008-07-24 08:31:00 +04:00
write3CE ( par , MiscExtFunc , tmp | 0x12 ) ;
2008-07-24 08:30:50 +04:00
write3CE ( par , 0x5 , 0x40 ) ; /* no CGA compat, allow 256 col */
write3CE ( par , 0x6 , 0x05 ) ; /* graphics mode */
write3CE ( par , 0x7 , 0x0F ) ; /* planes? */
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:50 +04:00
/* graphics mode and support 256 color modes */
writeAttr ( par , 0x10 , 0x41 ) ;
writeAttr ( par , 0x12 , 0x0F ) ; /* planes */
writeAttr ( par , 0x13 , 0 ) ; /* horizontal pel panning */
2005-04-17 02:20:36 +04:00
2007-10-16 12:28:42 +04:00
/* colors */
for ( tmp = 0 ; tmp < 0x10 ; tmp + + )
2008-07-24 08:30:50 +04:00
writeAttr ( par , tmp , tmp ) ;
2008-07-24 08:30:54 +04:00
fb_readb ( par - > io_virt + VGA_IS1_RC ) ; /* flip-flop to index */
t_outb ( par , 0x20 , VGA_ATT_W ) ; /* enable attr */
2005-04-17 02:20:36 +04:00
switch ( bpp ) {
2007-10-16 12:28:42 +04:00
case 8 :
tmp = 0 ;
break ;
case 16 :
tmp = 0x30 ;
break ;
case 24 :
case 32 :
tmp = 0xD0 ;
break ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:30:54 +04:00
t_inb ( par , VGA_PEL_IW ) ;
t_inb ( par , VGA_PEL_MSK ) ;
t_inb ( par , VGA_PEL_MSK ) ;
t_inb ( par , VGA_PEL_MSK ) ;
t_inb ( par , VGA_PEL_MSK ) ;
t_outb ( par , tmp , VGA_PEL_MSK ) ;
t_inb ( par , VGA_PEL_IW ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:53 +04:00
if ( par - > flatpanel )
2008-07-24 08:30:50 +04:00
set_number_of_lines ( par , info - > var . yres ) ;
2008-07-24 08:31:01 +04:00
info - > fix . line_length = info - > var . xres_virtual * bpp / 8 ;
set_lwidth ( par , info - > fix . line_length / 8 ) ;
2008-07-24 08:31:04 +04:00
if ( ! ( info - > flags & FBINFO_HWACCEL_DISABLED ) )
par - > init_accel ( par , info - > var . xres_virtual , bpp ) ;
2008-07-24 08:31:03 +04:00
2005-04-17 02:20:36 +04:00
info - > fix . visual = ( bpp = = 8 ) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR ;
2007-10-16 12:28:42 +04:00
info - > cmap . len = ( bpp = = 8 ) ? 256 : 16 ;
2005-04-17 02:20:36 +04:00
debug ( " exit \n " ) ;
return 0 ;
}
/* Set one color register */
static int tridentfb_setcolreg ( unsigned regno , unsigned red , unsigned green ,
2007-10-16 12:28:42 +04:00
unsigned blue , unsigned transp ,
struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
int bpp = info - > var . bits_per_pixel ;
2008-07-24 08:30:50 +04:00
struct tridentfb_par * par = info - > par ;
2005-04-17 02:20:36 +04:00
if ( regno > = info - > cmap . len )
return 1 ;
2007-07-17 15:05:41 +04:00
if ( bpp = = 8 ) {
2008-07-24 08:30:54 +04:00
t_outb ( par , 0xFF , VGA_PEL_MSK ) ;
t_outb ( par , regno , VGA_PEL_IW ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:54 +04:00
t_outb ( par , red > > 10 , VGA_PEL_D ) ;
t_outb ( par , green > > 10 , VGA_PEL_D ) ;
t_outb ( par , blue > > 10 , VGA_PEL_D ) ;
2005-04-17 02:20:36 +04:00
2007-07-17 15:05:41 +04:00
} else if ( regno < 16 ) {
if ( bpp = = 16 ) { /* RGB 565 */
u32 col ;
col = ( red & 0xF800 ) | ( ( green & 0xFC00 ) > > 5 ) |
( ( blue & 0xF800 ) > > 11 ) ;
col | = col < < 16 ;
( ( u32 * ) ( info - > pseudo_palette ) ) [ regno ] = col ;
} else if ( bpp = = 32 ) /* ARGB 8888 */
2008-07-24 08:31:05 +04:00
( ( u32 * ) info - > pseudo_palette ) [ regno ] =
2007-10-16 12:28:42 +04:00
( ( transp & 0xFF00 ) < < 16 ) |
( ( red & 0xFF00 ) < < 8 ) |
2007-07-17 15:05:41 +04:00
( ( green & 0xFF00 ) ) |
2007-10-16 12:28:42 +04:00
( ( blue & 0xFF00 ) > > 8 ) ;
2007-07-17 15:05:41 +04:00
}
2005-04-17 02:20:36 +04:00
2007-10-16 12:28:42 +04:00
/* debug("exit\n"); */
2005-04-17 02:20:36 +04:00
return 0 ;
}
2008-07-24 08:31:05 +04:00
/* Try blanking the screen. For flat panels it does nothing */
2005-04-17 02:20:36 +04:00
static int tridentfb_blank ( int blank_mode , struct fb_info * info )
{
2007-10-16 12:28:42 +04:00
unsigned char PMCont , DPMSCont ;
2008-07-24 08:30:50 +04:00
struct tridentfb_par * par = info - > par ;
2005-04-17 02:20:36 +04:00
debug ( " enter \n " ) ;
2008-07-24 08:30:53 +04:00
if ( par - > flatpanel )
2005-04-17 02:20:36 +04:00
return 0 ;
2008-07-24 08:30:50 +04:00
t_outb ( par , 0x04 , 0x83C8 ) ; /* Read DPMS Control */
PMCont = t_inb ( par , 0x83C6 ) & 0xFC ;
DPMSCont = read3CE ( par , PowerStatus ) & 0xFC ;
2007-10-16 12:28:42 +04:00
switch ( blank_mode ) {
2005-04-17 02:20:36 +04:00
case FB_BLANK_UNBLANK :
/* Screen: On, HSync: On, VSync: On */
case FB_BLANK_NORMAL :
/* Screen: Off, HSync: On, VSync: On */
PMCont | = 0x03 ;
DPMSCont | = 0x00 ;
break ;
case FB_BLANK_HSYNC_SUSPEND :
/* Screen: Off, HSync: Off, VSync: On */
PMCont | = 0x02 ;
DPMSCont | = 0x01 ;
break ;
case FB_BLANK_VSYNC_SUSPEND :
/* Screen: Off, HSync: On, VSync: Off */
PMCont | = 0x02 ;
DPMSCont | = 0x02 ;
break ;
case FB_BLANK_POWERDOWN :
/* Screen: Off, HSync: Off, VSync: Off */
PMCont | = 0x00 ;
DPMSCont | = 0x03 ;
break ;
2007-10-16 12:28:42 +04:00
}
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:50 +04:00
write3CE ( par , PowerStatus , DPMSCont ) ;
t_outb ( par , 4 , 0x83C8 ) ;
t_outb ( par , PMCont , 0x83C6 ) ;
2005-04-17 02:20:36 +04:00
debug ( " exit \n " ) ;
/* let fbcon do a softblank for us */
return ( blank_mode = = FB_BLANK_NORMAL ) ? 1 : 0 ;
}
2007-10-16 12:28:42 +04:00
static struct fb_ops tridentfb_ops = {
. owner = THIS_MODULE ,
. fb_setcolreg = tridentfb_setcolreg ,
. fb_pan_display = tridentfb_pan_display ,
. fb_blank = tridentfb_blank ,
. fb_check_var = tridentfb_check_var ,
. fb_set_par = tridentfb_set_par ,
. fb_fillrect = tridentfb_fillrect ,
. fb_copyarea = tridentfb_copyarea ,
. fb_imageblit = cfb_imageblit ,
2008-07-24 08:31:02 +04:00
# ifdef CONFIG_FB_TRIDENT_ACCEL
. fb_sync = tridentfb_sync ,
2008-07-24 08:31:01 +04:00
# endif
2007-10-16 12:28:42 +04:00
} ;
2008-07-24 08:30:51 +04:00
static int __devinit trident_pci_probe ( struct pci_dev * dev ,
const struct pci_device_id * id )
2005-04-17 02:20:36 +04:00
{
int err ;
unsigned char revision ;
2008-07-24 08:30:51 +04:00
struct fb_info * info ;
struct tridentfb_par * default_par ;
2008-07-24 08:30:52 +04:00
int chip3D ;
int chip_id ;
2005-04-17 02:20:36 +04:00
err = pci_enable_device ( dev ) ;
if ( err )
return err ;
2008-07-24 08:30:51 +04:00
info = framebuffer_alloc ( sizeof ( struct tridentfb_par ) , & dev - > dev ) ;
if ( ! info )
return - ENOMEM ;
default_par = info - > par ;
2005-04-17 02:20:36 +04:00
chip_id = id - > device ;
2007-10-16 12:28:42 +04:00
if ( chip_id = = CYBERBLADEi1 )
2005-09-10 00:04:56 +04:00
output ( " *** Please do use cyblafb, Cyberblade/i1 support "
" will soon be removed from tridentfb! \n " ) ;
2008-07-24 08:31:04 +04:00
# ifndef CONFIG_FB_TRIDENT_ACCEL
noaccel = 1 ;
# endif
2005-09-10 00:04:56 +04:00
2005-04-17 02:20:36 +04:00
/* If PCI id is 0x9660 then further detect chip type */
2007-10-16 12:28:42 +04:00
2005-04-17 02:20:36 +04:00
if ( chip_id = = TGUI9660 ) {
2008-07-24 08:30:54 +04:00
revision = vga_io_rseq ( RevisionID ) ;
2007-10-16 12:28:42 +04:00
2005-04-17 02:20:36 +04:00
switch ( revision ) {
2008-07-24 08:30:58 +04:00
case 0x21 :
chip_id = PROVIDIA9685 ;
break ;
2007-10-16 12:28:42 +04:00
case 0x22 :
case 0x23 :
chip_id = CYBER9397 ;
break ;
case 0x2A :
chip_id = CYBER9397DVD ;
break ;
case 0x30 :
case 0x33 :
case 0x34 :
case 0x35 :
case 0x38 :
case 0x3A :
case 0xB3 :
chip_id = CYBER9385 ;
break ;
case 0x40 . . . 0x43 :
chip_id = CYBER9382 ;
break ;
case 0x4A :
chip_id = CYBER9388 ;
break ;
default :
break ;
2005-04-17 02:20:36 +04:00
}
}
chip3D = is3Dchip ( chip_id ) ;
if ( is_xp ( chip_id ) ) {
2008-07-24 08:30:54 +04:00
default_par - > init_accel = xp_init_accel ;
default_par - > wait_engine = xp_wait_engine ;
default_par - > fill_rect = xp_fill_rect ;
default_par - > copy_rect = xp_copy_rect ;
2008-07-24 08:31:04 +04:00
tridentfb_fix . accel = FB_ACCEL_TRIDENT_BLADEXP ;
2007-10-16 12:28:42 +04:00
} else if ( is_blade ( chip_id ) ) {
2008-07-24 08:30:54 +04:00
default_par - > init_accel = blade_init_accel ;
default_par - > wait_engine = blade_wait_engine ;
default_par - > fill_rect = blade_fill_rect ;
default_par - > copy_rect = blade_copy_rect ;
2008-07-24 08:31:04 +04:00
tridentfb_fix . accel = FB_ACCEL_TRIDENT_BLADE3D ;
2008-07-24 08:31:01 +04:00
} else if ( chip3D ) { /* 3DImage family left */
2008-07-24 08:30:54 +04:00
default_par - > init_accel = image_init_accel ;
default_par - > wait_engine = image_wait_engine ;
default_par - > fill_rect = image_fill_rect ;
default_par - > copy_rect = image_copy_rect ;
2008-07-24 08:31:04 +04:00
tridentfb_fix . accel = FB_ACCEL_TRIDENT_3DIMAGE ;
2008-07-24 08:31:01 +04:00
} else { /* TGUI 9440/96XX family */
default_par - > init_accel = tgui_init_accel ;
default_par - > wait_engine = xp_wait_engine ;
default_par - > fill_rect = tgui_fill_rect ;
default_par - > copy_rect = tgui_copy_rect ;
2008-07-24 08:31:04 +04:00
tridentfb_fix . accel = FB_ACCEL_TRIDENT_TGUI ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:30:52 +04:00
default_par - > chip_id = chip_id ;
2005-04-17 02:20:36 +04:00
/* setup MMIO region */
2007-10-16 12:28:42 +04:00
tridentfb_fix . mmio_start = pci_resource_start ( dev , 1 ) ;
2008-07-24 08:31:05 +04:00
tridentfb_fix . mmio_len = pci_resource_len ( dev , 1 ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:31:05 +04:00
if ( ! request_mem_region ( tridentfb_fix . mmio_start ,
tridentfb_fix . mmio_len , " tridentfb " ) ) {
2005-04-17 02:20:36 +04:00
debug ( " request_region failed! \n " ) ;
2008-07-24 08:30:57 +04:00
framebuffer_release ( info ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
2008-07-24 08:30:51 +04:00
default_par - > io_virt = ioremap_nocache ( tridentfb_fix . mmio_start ,
tridentfb_fix . mmio_len ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:51 +04:00
if ( ! default_par - > io_virt ) {
2005-04-17 02:20:36 +04:00
debug ( " ioremap failed \n " ) ;
2008-03-05 01:28:39 +03:00
err = - 1 ;
goto out_unmap1 ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:31:06 +04:00
enable_mmio ( default_par ) ;
2008-07-24 08:31:01 +04:00
2005-04-17 02:20:36 +04:00
/* setup framebuffer memory */
2007-10-16 12:28:42 +04:00
tridentfb_fix . smem_start = pci_resource_start ( dev , 0 ) ;
2008-07-24 08:30:51 +04:00
tridentfb_fix . smem_len = get_memsize ( default_par ) ;
2007-10-16 12:28:42 +04:00
2008-07-24 08:31:05 +04:00
if ( ! request_mem_region ( tridentfb_fix . smem_start ,
tridentfb_fix . smem_len , " tridentfb " ) ) {
2005-04-17 02:20:36 +04:00
debug ( " request_mem_region failed! \n " ) ;
2008-07-24 08:30:51 +04:00
disable_mmio ( info - > par ) ;
2006-12-08 13:40:03 +03:00
err = - 1 ;
2008-03-05 01:28:39 +03:00
goto out_unmap1 ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:30:51 +04:00
info - > screen_base = ioremap_nocache ( tridentfb_fix . smem_start ,
tridentfb_fix . smem_len ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:51 +04:00
if ( ! info - > screen_base ) {
2005-04-17 02:20:36 +04:00
debug ( " ioremap failed \n " ) ;
2006-12-08 13:40:03 +03:00
err = - 1 ;
2008-03-05 01:28:39 +03:00
goto out_unmap2 ;
2005-04-17 02:20:36 +04:00
}
2008-07-24 08:30:53 +04:00
default_par - > flatpanel = is_flatpanel ( default_par ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:53 +04:00
if ( default_par - > flatpanel )
2008-07-24 08:30:51 +04:00
nativex = get_nativex ( default_par ) ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:51 +04:00
info - > fix = tridentfb_fix ;
info - > fbops = & tridentfb_ops ;
2008-07-24 08:30:59 +04:00
info - > pseudo_palette = default_par - > pseudo_pal ;
2005-04-17 02:20:36 +04:00
2008-07-24 08:30:51 +04:00
info - > flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN ;
2008-07-24 08:31:04 +04:00
if ( ! noaccel & & default_par - > init_accel ) {
info - > flags & = ~ FBINFO_HWACCEL_DISABLED ;
info - > flags | = FBINFO_HWACCEL_COPYAREA ;
info - > flags | = FBINFO_HWACCEL_FILLRECT ;
} else
info - > flags | = FBINFO_HWACCEL_DISABLED ;
2008-07-24 08:30:51 +04:00
if ( ! fb_find_mode ( & info - > var , info ,
2008-04-28 13:15:06 +04:00
mode_option , NULL , 0 , NULL , bpp ) ) {
2006-12-08 13:40:03 +03:00
err = - EINVAL ;
2008-03-05 01:28:39 +03:00
goto out_unmap2 ;
2006-12-08 13:40:03 +03:00
}
2008-07-24 08:30:51 +04:00
err = fb_alloc_cmap ( & info - > cmap , 256 , 0 ) ;
2008-03-05 01:28:39 +03:00
if ( err < 0 )
goto out_unmap2 ;
2008-07-24 08:30:51 +04:00
info - > var . activate | = FB_ACTIVATE_NOW ;
2008-07-24 08:30:51 +04:00
info - > device = & dev - > dev ;
if ( register_framebuffer ( info ) < 0 ) {
2008-07-24 08:31:05 +04:00
printk ( KERN_ERR " tridentfb: could not register framebuffer \n " ) ;
2008-07-24 08:30:51 +04:00
fb_dealloc_cmap ( & info - > cmap ) ;
2006-12-08 13:40:03 +03:00
err = - EINVAL ;
2008-03-05 01:28:39 +03:00
goto out_unmap2 ;
2005-04-17 02:20:36 +04:00
}
output ( " fb%d: %s frame buffer device %dx%d-%dbpp \n " ,
2008-07-24 08:30:51 +04:00
info - > node , info - > fix . id , info - > var . xres ,
info - > var . yres , info - > var . bits_per_pixel ) ;
2008-07-24 08:30:51 +04:00
pci_set_drvdata ( dev , info ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
2006-12-08 13:40:03 +03:00
2008-03-05 01:28:39 +03:00
out_unmap2 :
2008-07-24 08:30:51 +04:00
if ( info - > screen_base )
iounmap ( info - > screen_base ) ;
2008-03-05 01:28:39 +03:00
release_mem_region ( tridentfb_fix . smem_start , tridentfb_fix . smem_len ) ;
2008-07-24 08:30:51 +04:00
disable_mmio ( info - > par ) ;
2008-03-05 01:28:39 +03:00
out_unmap1 :
2008-07-24 08:30:51 +04:00
if ( default_par - > io_virt )
iounmap ( default_par - > io_virt ) ;
2008-03-05 01:28:39 +03:00
release_mem_region ( tridentfb_fix . mmio_start , tridentfb_fix . mmio_len ) ;
2008-07-24 08:30:51 +04:00
framebuffer_release ( info ) ;
2006-12-08 13:40:03 +03:00
return err ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:28:42 +04:00
static void __devexit trident_pci_remove ( struct pci_dev * dev )
2005-04-17 02:20:36 +04:00
{
2008-07-24 08:30:51 +04:00
struct fb_info * info = pci_get_drvdata ( dev ) ;
struct tridentfb_par * par = info - > par ;
unregister_framebuffer ( info ) ;
2005-04-17 02:20:36 +04:00
iounmap ( par - > io_virt ) ;
2008-07-24 08:30:51 +04:00
iounmap ( info - > screen_base ) ;
2005-04-17 02:20:36 +04:00
release_mem_region ( tridentfb_fix . smem_start , tridentfb_fix . smem_len ) ;
2008-03-05 01:28:39 +03:00
release_mem_region ( tridentfb_fix . mmio_start , tridentfb_fix . mmio_len ) ;
2008-07-24 08:30:51 +04:00
pci_set_drvdata ( dev , NULL ) ;
framebuffer_release ( info ) ;
2005-04-17 02:20:36 +04:00
}
/* List of boards that we are trying to support */
static struct pci_device_id trident_devices [ ] = {
2007-10-16 12:28:42 +04:00
{ PCI_VENDOR_ID_TRIDENT , BLADE3D , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_TRIDENT , CYBERBLADEi7 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_TRIDENT , CYBERBLADEi7D , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_TRIDENT , CYBERBLADEi1 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_TRIDENT , CYBERBLADEi1D , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_TRIDENT , CYBERBLADEAi1 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_TRIDENT , CYBERBLADEAi1D , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_TRIDENT , CYBERBLADEE4 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
2008-07-24 08:30:58 +04:00
{ PCI_VENDOR_ID_TRIDENT , TGUI9440 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
2007-10-16 12:28:42 +04:00
{ PCI_VENDOR_ID_TRIDENT , TGUI9660 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_TRIDENT , IMAGE975 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_TRIDENT , IMAGE985 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_TRIDENT , CYBER9320 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_TRIDENT , CYBER9388 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_TRIDENT , CYBER9520 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_TRIDENT , CYBER9525DVD , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_TRIDENT , CYBER9397 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_TRIDENT , CYBER9397DVD , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_TRIDENT , CYBERBLADEXPAi1 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_TRIDENT , CYBERBLADEXPm8 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_TRIDENT , CYBERBLADEXPm16 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
2005-04-17 02:20:36 +04:00
{ 0 , }
2007-10-16 12:28:42 +04:00
} ;
MODULE_DEVICE_TABLE ( pci , trident_devices ) ;
2005-04-17 02:20:36 +04:00
static struct pci_driver tridentfb_pci_driver = {
2007-10-16 12:28:42 +04:00
. name = " tridentfb " ,
. id_table = trident_devices ,
. probe = trident_pci_probe ,
. remove = __devexit_p ( trident_pci_remove )
2005-04-17 02:20:36 +04:00
} ;
/*
* Parse user specified options ( ` video = trident : ' )
* example :
2007-10-16 12:28:42 +04:00
* video = trident : 800 x600 , bpp = 16 , noaccel
2005-04-17 02:20:36 +04:00
*/
# ifndef MODULE
2008-04-28 13:15:06 +04:00
static int __init tridentfb_setup ( char * options )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:28:42 +04:00
char * opt ;
2005-04-17 02:20:36 +04:00
if ( ! options | | ! * options )
return 0 ;
2007-10-16 12:28:42 +04:00
while ( ( opt = strsep ( & options , " , " ) ) ! = NULL ) {
if ( ! * opt )
continue ;
if ( ! strncmp ( opt , " noaccel " , 7 ) )
2005-04-17 02:20:36 +04:00
noaccel = 1 ;
2007-10-16 12:28:42 +04:00
else if ( ! strncmp ( opt , " fp " , 2 ) )
2008-07-24 08:30:53 +04:00
fp = 1 ;
2007-10-16 12:28:42 +04:00
else if ( ! strncmp ( opt , " crt " , 3 ) )
2008-07-24 08:30:53 +04:00
fp = 0 ;
2007-10-16 12:28:42 +04:00
else if ( ! strncmp ( opt , " bpp= " , 4 ) )
bpp = simple_strtoul ( opt + 4 , NULL , 0 ) ;
else if ( ! strncmp ( opt , " center " , 6 ) )
2005-04-17 02:20:36 +04:00
center = 1 ;
2007-10-16 12:28:42 +04:00
else if ( ! strncmp ( opt , " stretch " , 7 ) )
2005-04-17 02:20:36 +04:00
stretch = 1 ;
2007-10-16 12:28:42 +04:00
else if ( ! strncmp ( opt , " memsize= " , 8 ) )
memsize = simple_strtoul ( opt + 8 , NULL , 0 ) ;
else if ( ! strncmp ( opt , " memdiff= " , 8 ) )
memdiff = simple_strtoul ( opt + 8 , NULL , 0 ) ;
else if ( ! strncmp ( opt , " nativex= " , 8 ) )
nativex = simple_strtoul ( opt + 8 , NULL , 0 ) ;
2005-04-17 02:20:36 +04:00
else
2008-04-28 13:15:06 +04:00
mode_option = opt ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
# endif
static int __init tridentfb_init ( void )
{
# ifndef MODULE
char * option = NULL ;
if ( fb_get_options ( " tridentfb " , & option ) )
return - ENODEV ;
tridentfb_setup ( option ) ;
# endif
return pci_register_driver ( & tridentfb_pci_driver ) ;
}
static void __exit tridentfb_exit ( void )
{
pci_unregister_driver ( & tridentfb_pci_driver ) ;
}
module_init ( tridentfb_init ) ;
module_exit ( tridentfb_exit ) ;
MODULE_AUTHOR ( " Jani Monoses <jani@iv.ro> " ) ;
MODULE_DESCRIPTION ( " Framebuffer driver for Trident cards " ) ;
MODULE_LICENSE ( " GPL " ) ;