2005-04-17 02:20:36 +04:00
/*
* Permedia2 framebuffer driver .
*
* 2.5 / 2.6 driver :
* Copyright ( c ) 2003 Jim Hague ( jim . hague @ acm . org )
*
* based on 2.4 driver :
* Copyright ( c ) 1998 - 2000 Ilario Nardinocchi ( nardinoc @ CS . UniBO . IT )
* Copyright ( c ) 1999 Jakub Jelinek ( jakub @ redhat . com )
*
* and additional input from James Simmon ' s port of Hannu Mallat ' s tdfx
* driver .
*
2007-10-16 12:28:34 +04:00
* I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86 . I
2005-04-17 02:20:36 +04:00
* have no access to other pm2fb implementations . Sparc ( and thus
* hopefully other big - endian ) devices now work , thanks to a lot of
* testing work by Ron Murray . I have no access to CVision hardware ,
* and therefore for now I am omitting the CVision code .
*
* Multiple boards support has been on the TODO list for ages .
* Don ' t expect this to change .
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file COPYING in the main directory of this archive for
* more details .
*
2007-07-17 15:05:31 +04:00
*
2005-04-17 02:20:36 +04:00
*/
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/string.h>
# include <linux/mm.h>
# include <linux/slab.h>
# include <linux/delay.h>
# include <linux/fb.h>
# include <linux/init.h>
# include <linux/pci.h>
2007-10-16 12:28:33 +04:00
# ifdef CONFIG_MTRR
# include <asm/mtrr.h>
# endif
2005-04-17 02:20:36 +04:00
# include <video/permedia2.h>
# include <video/cvisionppc.h>
# if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
# error "The endianness of the target host has not been defined."
# endif
# if !defined(CONFIG_PCI)
# error "Only generic PCI cards supported."
# endif
# undef PM2FB_MASTER_DEBUG
# ifdef PM2FB_MASTER_DEBUG
2007-10-16 12:28:50 +04:00
# define DPRINTK(a, b...) \
2008-04-28 13:15:47 +04:00
printk ( KERN_DEBUG " pm2fb: %s: " a , __func__ , # # b )
2005-04-17 02:20:36 +04:00
# else
2007-10-16 12:28:50 +04:00
# define DPRINTK(a, b...)
2005-04-17 02:20:36 +04:00
# endif
2007-10-16 12:28:34 +04:00
# define PM2_PIXMAP_SIZE (1600 * 4)
2005-04-17 02:20:36 +04:00
/*
2007-07-17 15:05:31 +04:00
* Driver data
2005-04-17 02:20:36 +04:00
*/
2007-10-16 12:29:16 +04:00
static int hwcursor = 1 ;
2008-04-28 13:15:05 +04:00
static char * mode_option __devinitdata ;
2005-04-17 02:20:36 +04:00
/*
* The XFree GLINT driver will ( I think to implement hardware cursor
* support on TVP4010 and similar where there is no RAMDAC - see
* comment in set_video ) always request + ve sync regardless of what
* the mode requires . This screws me because I have a Sun
* fixed - frequency monitor which absolutely has to have - ve sync . So
* these flags allow the user to specify that requests for + ve sync
* should be silently turned in - ve sync .
*/
2006-04-20 13:43:13 +04:00
static int lowhsync ;
static int lowvsync ;
2007-10-16 12:28:33 +04:00
static int noaccel __devinitdata ;
/* mtrr option */
# ifdef CONFIG_MTRR
static int nomtrr __devinitdata ;
# endif
2005-04-17 02:20:36 +04:00
/*
* The hardware state of the graphics card that isn ' t part of the
* screeninfo .
*/
struct pm2fb_par
{
pm2type_t type ; /* Board type */
unsigned char __iomem * v_regs ; /* virtual address of p_regs */
2007-07-17 15:05:31 +04:00
u32 memclock ; /* memclock */
2005-04-17 02:20:36 +04:00
u32 video ; /* video flags before blanking */
u32 mem_config ; /* MemConfig reg at probe */
u32 mem_control ; /* MemControl reg at probe */
u32 boot_address ; /* BootAddress reg at probe */
2007-07-17 15:05:31 +04:00
u32 palette [ 16 ] ;
2007-10-16 12:28:33 +04:00
int mtrr_handle ;
2005-04-17 02:20:36 +04:00
} ;
/*
* Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
* if we don ' t use modedb .
*/
static struct fb_fix_screeninfo pm2fb_fix __devinitdata = {
2007-07-17 15:05:31 +04:00
. id = " " ,
2005-04-17 02:20:36 +04:00
. type = FB_TYPE_PACKED_PIXELS ,
. visual = FB_VISUAL_PSEUDOCOLOR ,
. xpanstep = 1 ,
. ypanstep = 1 ,
2007-07-17 15:05:31 +04:00
. ywrapstep = 0 ,
2007-05-08 11:40:02 +04:00
. accel = FB_ACCEL_3DLABS_PERMEDIA2 ,
2005-04-17 02:20:36 +04:00
} ;
/*
* Default video mode . In case the modedb doesn ' t work .
*/
static struct fb_var_screeninfo pm2fb_var __devinitdata = {
/* "640x480, 8 bpp @ 60 Hz */
2007-07-17 15:05:31 +04:00
. xres = 640 ,
. yres = 480 ,
. xres_virtual = 640 ,
. yres_virtual = 480 ,
. bits_per_pixel = 8 ,
. red = { 0 , 8 , 0 } ,
. blue = { 0 , 8 , 0 } ,
. green = { 0 , 8 , 0 } ,
. activate = FB_ACTIVATE_NOW ,
. height = - 1 ,
. width = - 1 ,
. accel_flags = 0 ,
. pixclock = 39721 ,
. left_margin = 40 ,
. right_margin = 24 ,
. upper_margin = 32 ,
. lower_margin = 11 ,
. hsync_len = 96 ,
. vsync_len = 2 ,
. vmode = FB_VMODE_NONINTERLACED
2005-04-17 02:20:36 +04:00
} ;
/*
* Utility functions
*/
2007-10-16 12:28:50 +04:00
static inline u32 pm2_RD ( struct pm2fb_par * p , s32 off )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:28:34 +04:00
return fb_readl ( p - > v_regs + off ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:28:50 +04:00
static inline void pm2_WR ( struct pm2fb_par * p , s32 off , u32 v )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:28:34 +04:00
fb_writel ( v , p - > v_regs + off ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:28:50 +04:00
static inline u32 pm2_RDAC_RD ( struct pm2fb_par * p , s32 idx )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:28:34 +04:00
pm2_WR ( p , PM2R_RD_PALETTE_WRITE_ADDRESS , idx ) ;
2005-04-17 02:20:36 +04:00
mb ( ) ;
2007-10-16 12:28:34 +04:00
return pm2_RD ( p , PM2R_RD_INDEXED_DATA ) ;
}
2007-10-16 12:28:50 +04:00
static inline u32 pm2v_RDAC_RD ( struct pm2fb_par * p , s32 idx )
2007-10-16 12:28:34 +04:00
{
pm2_WR ( p , PM2VR_RD_INDEX_LOW , idx & 0xff ) ;
mb ( ) ;
return pm2_RD ( p , PM2VR_RD_INDEXED_DATA ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:28:50 +04:00
static inline void pm2_RDAC_WR ( struct pm2fb_par * p , s32 idx , u32 v )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:28:34 +04:00
pm2_WR ( p , PM2R_RD_PALETTE_WRITE_ADDRESS , idx ) ;
2007-05-24 00:57:47 +04:00
wmb ( ) ;
2007-10-16 12:28:34 +04:00
pm2_WR ( p , PM2R_RD_INDEXED_DATA , v ) ;
2007-05-24 00:57:47 +04:00
wmb ( ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:28:50 +04:00
static inline void pm2v_RDAC_WR ( struct pm2fb_par * p , s32 idx , u32 v )
2005-04-17 02:20:36 +04:00
{
pm2_WR ( p , PM2VR_RD_INDEX_LOW , idx & 0xff ) ;
2007-05-24 00:57:47 +04:00
wmb ( ) ;
2005-04-17 02:20:36 +04:00
pm2_WR ( p , PM2VR_RD_INDEXED_DATA , v ) ;
2007-05-24 00:57:47 +04:00
wmb ( ) ;
2005-04-17 02:20:36 +04:00
}
# ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
2007-07-17 15:05:31 +04:00
# define WAIT_FIFO(p, a)
2005-04-17 02:20:36 +04:00
# else
2007-10-16 12:28:50 +04:00
static inline void WAIT_FIFO ( struct pm2fb_par * p , u32 a )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:29:27 +04:00
while ( pm2_RD ( p , PM2R_IN_FIFO_SPACE ) < a )
cpu_relax ( ) ;
2005-04-17 02:20:36 +04:00
}
# endif
/*
* partial products for the supported horizontal resolutions .
*/
2007-07-17 15:05:31 +04:00
# define PACKPP(p0, p1, p2) (((p2) << 6) | ((p1) << 3) | (p0))
2005-04-17 02:20:36 +04:00
static const struct {
u16 width ;
u16 pp ;
} pp_table [ ] = {
{ 32 , PACKPP ( 1 , 0 , 0 ) } , { 64 , PACKPP ( 1 , 1 , 0 ) } ,
{ 96 , PACKPP ( 1 , 1 , 1 ) } , { 128 , PACKPP ( 2 , 1 , 1 ) } ,
{ 160 , PACKPP ( 2 , 2 , 1 ) } , { 192 , PACKPP ( 2 , 2 , 2 ) } ,
{ 224 , PACKPP ( 3 , 2 , 1 ) } , { 256 , PACKPP ( 3 , 2 , 2 ) } ,
{ 288 , PACKPP ( 3 , 3 , 1 ) } , { 320 , PACKPP ( 3 , 3 , 2 ) } ,
{ 384 , PACKPP ( 3 , 3 , 3 ) } , { 416 , PACKPP ( 4 , 3 , 1 ) } ,
{ 448 , PACKPP ( 4 , 3 , 2 ) } , { 512 , PACKPP ( 4 , 3 , 3 ) } ,
{ 544 , PACKPP ( 4 , 4 , 1 ) } , { 576 , PACKPP ( 4 , 4 , 2 ) } ,
{ 640 , PACKPP ( 4 , 4 , 3 ) } , { 768 , PACKPP ( 4 , 4 , 4 ) } ,
{ 800 , PACKPP ( 5 , 4 , 1 ) } , { 832 , PACKPP ( 5 , 4 , 2 ) } ,
{ 896 , PACKPP ( 5 , 4 , 3 ) } , { 1024 , PACKPP ( 5 , 4 , 4 ) } ,
{ 1056 , PACKPP ( 5 , 5 , 1 ) } , { 1088 , PACKPP ( 5 , 5 , 2 ) } ,
{ 1152 , PACKPP ( 5 , 5 , 3 ) } , { 1280 , PACKPP ( 5 , 5 , 4 ) } ,
{ 1536 , PACKPP ( 5 , 5 , 5 ) } , { 1568 , PACKPP ( 6 , 5 , 1 ) } ,
{ 1600 , PACKPP ( 6 , 5 , 2 ) } , { 1664 , PACKPP ( 6 , 5 , 3 ) } ,
{ 1792 , PACKPP ( 6 , 5 , 4 ) } , { 2048 , PACKPP ( 6 , 5 , 5 ) } ,
{ 0 , 0 } } ;
static u32 partprod ( u32 xres )
{
int i ;
for ( i = 0 ; pp_table [ i ] . width & & pp_table [ i ] . width ! = xres ; i + + )
;
2007-10-16 12:28:34 +04:00
if ( pp_table [ i ] . width = = 0 )
2005-04-17 02:20:36 +04:00
DPRINTK ( " invalid width %u \n " , xres ) ;
return pp_table [ i ] . pp ;
}
static u32 to3264 ( u32 timing , int bpp , int is64 )
{
switch ( bpp ) {
2007-10-16 12:28:34 +04:00
case 24 :
timing * = 3 ;
2005-04-17 02:20:36 +04:00
case 8 :
2007-10-16 12:28:34 +04:00
timing > > = 1 ;
2005-04-17 02:20:36 +04:00
case 16 :
2007-10-16 12:28:34 +04:00
timing > > = 1 ;
2005-04-17 02:20:36 +04:00
case 32 :
break ;
}
2007-10-16 12:28:34 +04:00
if ( is64 )
timing > > = 1 ;
2005-04-17 02:20:36 +04:00
return timing ;
}
2007-10-16 12:28:50 +04:00
static void pm2_mnp ( u32 clk , unsigned char * mm , unsigned char * nn ,
unsigned char * pp )
2005-04-17 02:20:36 +04:00
{
unsigned char m ;
unsigned char n ;
unsigned char p ;
u32 f ;
s32 curr ;
s32 delta = 100000 ;
* mm = * nn = * pp = 0 ;
for ( n = 2 ; n < 15 ; n + + ) {
for ( m = 2 ; m ; m + + ) {
f = PM2_REFERENCE_CLOCK * m / n ;
if ( f > = 150000 & & f < = 300000 ) {
2007-10-16 12:28:34 +04:00
for ( p = 0 ; p < 5 ; p + + , f > > = 1 ) {
curr = ( clk > f ) ? clk - f : f - clk ;
if ( curr < delta ) {
delta = curr ;
* mm = m ;
* nn = n ;
* pp = p ;
2005-04-17 02:20:36 +04:00
}
}
}
}
}
}
2007-10-16 12:28:50 +04:00
static void pm2v_mnp ( u32 clk , unsigned char * mm , unsigned char * nn ,
unsigned char * pp )
2005-04-17 02:20:36 +04:00
{
unsigned char m ;
unsigned char n ;
unsigned char p ;
u32 f ;
s32 delta = 1000 ;
* mm = * nn = * pp = 0 ;
2007-10-16 12:28:34 +04:00
for ( m = 1 ; m < 128 ; m + + ) {
2007-05-08 11:39:33 +04:00
for ( n = 2 * m + 1 ; n ; n + + ) {
2007-10-16 12:28:34 +04:00
for ( p = 0 ; p < 2 ; p + + ) {
f = ( PM2_REFERENCE_CLOCK > > ( p + 1 ) ) * n / m ;
if ( clk > f - delta & & clk < f + delta ) {
delta = ( clk > f ) ? clk - f : f - clk ;
* mm = m ;
* nn = n ;
* pp = p ;
2005-04-17 02:20:36 +04:00
}
}
}
}
}
2007-10-16 12:28:50 +04:00
static void clear_palette ( struct pm2fb_par * p )
{
2007-10-16 12:28:34 +04:00
int i = 256 ;
2005-04-17 02:20:36 +04:00
WAIT_FIFO ( p , 1 ) ;
pm2_WR ( p , PM2R_RD_PALETTE_WRITE_ADDRESS , 0 ) ;
wmb ( ) ;
while ( i - - ) {
WAIT_FIFO ( p , 3 ) ;
pm2_WR ( p , PM2R_RD_PALETTE_DATA , 0 ) ;
pm2_WR ( p , PM2R_RD_PALETTE_DATA , 0 ) ;
pm2_WR ( p , PM2R_RD_PALETTE_DATA , 0 ) ;
}
}
2007-10-16 12:28:50 +04:00
static void reset_card ( struct pm2fb_par * p )
2005-04-17 02:20:36 +04:00
{
if ( p - > type = = PM2_TYPE_PERMEDIA2V )
pm2_WR ( p , PM2VR_RD_INDEX_HIGH , 0 ) ;
pm2_WR ( p , PM2R_RESET_STATUS , 0 ) ;
mb ( ) ;
while ( pm2_RD ( p , PM2R_RESET_STATUS ) & PM2F_BEING_RESET )
2007-10-16 12:29:27 +04:00
cpu_relax ( ) ;
2005-04-17 02:20:36 +04:00
mb ( ) ;
# ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
DPRINTK ( " FIFO disconnect enabled \n " ) ;
pm2_WR ( p , PM2R_FIFO_DISCON , 1 ) ;
mb ( ) ;
# endif
/* Restore stashed memory config information from probe */
WAIT_FIFO ( p , 3 ) ;
pm2_WR ( p , PM2R_MEM_CONTROL , p - > mem_control ) ;
pm2_WR ( p , PM2R_BOOT_ADDRESS , p - > boot_address ) ;
wmb ( ) ;
pm2_WR ( p , PM2R_MEM_CONFIG , p - > mem_config ) ;
}
2007-10-16 12:28:50 +04:00
static void reset_config ( struct pm2fb_par * p )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:28:36 +04:00
WAIT_FIFO ( p , 53 ) ;
2007-07-17 15:05:31 +04:00
pm2_WR ( p , PM2R_CHIP_CONFIG , pm2_RD ( p , PM2R_CHIP_CONFIG ) &
2007-10-16 12:28:34 +04:00
~ ( PM2F_VGA_ENABLE | PM2F_VGA_FIXED ) ) ;
2005-04-17 02:20:36 +04:00
pm2_WR ( p , PM2R_BYPASS_WRITE_MASK , ~ ( 0L ) ) ;
pm2_WR ( p , PM2R_FRAMEBUFFER_WRITE_MASK , ~ ( 0L ) ) ;
pm2_WR ( p , PM2R_FIFO_CONTROL , 0 ) ;
pm2_WR ( p , PM2R_APERTURE_ONE , 0 ) ;
pm2_WR ( p , PM2R_APERTURE_TWO , 0 ) ;
pm2_WR ( p , PM2R_RASTERIZER_MODE , 0 ) ;
pm2_WR ( p , PM2R_DELTA_MODE , PM2F_DELTA_ORDER_RGB ) ;
pm2_WR ( p , PM2R_LB_READ_FORMAT , 0 ) ;
2007-07-17 15:05:31 +04:00
pm2_WR ( p , PM2R_LB_WRITE_FORMAT , 0 ) ;
2005-04-17 02:20:36 +04:00
pm2_WR ( p , PM2R_LB_READ_MODE , 0 ) ;
pm2_WR ( p , PM2R_LB_SOURCE_OFFSET , 0 ) ;
pm2_WR ( p , PM2R_FB_SOURCE_OFFSET , 0 ) ;
pm2_WR ( p , PM2R_FB_PIXEL_OFFSET , 0 ) ;
pm2_WR ( p , PM2R_FB_WINDOW_BASE , 0 ) ;
pm2_WR ( p , PM2R_LB_WINDOW_BASE , 0 ) ;
pm2_WR ( p , PM2R_FB_SOFT_WRITE_MASK , ~ ( 0L ) ) ;
pm2_WR ( p , PM2R_FB_HARD_WRITE_MASK , ~ ( 0L ) ) ;
pm2_WR ( p , PM2R_FB_READ_PIXEL , 0 ) ;
pm2_WR ( p , PM2R_DITHER_MODE , 0 ) ;
pm2_WR ( p , PM2R_AREA_STIPPLE_MODE , 0 ) ;
pm2_WR ( p , PM2R_DEPTH_MODE , 0 ) ;
pm2_WR ( p , PM2R_STENCIL_MODE , 0 ) ;
pm2_WR ( p , PM2R_TEXTURE_ADDRESS_MODE , 0 ) ;
pm2_WR ( p , PM2R_TEXTURE_READ_MODE , 0 ) ;
pm2_WR ( p , PM2R_TEXEL_LUT_MODE , 0 ) ;
pm2_WR ( p , PM2R_YUV_MODE , 0 ) ;
pm2_WR ( p , PM2R_COLOR_DDA_MODE , 0 ) ;
pm2_WR ( p , PM2R_TEXTURE_COLOR_MODE , 0 ) ;
pm2_WR ( p , PM2R_FOG_MODE , 0 ) ;
pm2_WR ( p , PM2R_ALPHA_BLEND_MODE , 0 ) ;
pm2_WR ( p , PM2R_LOGICAL_OP_MODE , 0 ) ;
pm2_WR ( p , PM2R_STATISTICS_MODE , 0 ) ;
pm2_WR ( p , PM2R_SCISSOR_MODE , 0 ) ;
pm2_WR ( p , PM2R_FILTER_MODE , PM2F_SYNCHRONIZATION ) ;
2007-10-16 12:28:36 +04:00
pm2_WR ( p , PM2R_RD_PIXEL_MASK , 0xff ) ;
2005-04-17 02:20:36 +04:00
switch ( p - > type ) {
case PM2_TYPE_PERMEDIA2 :
pm2_RDAC_WR ( p , PM2I_RD_MODE_CONTROL , 0 ) ; /* no overlay */
pm2_RDAC_WR ( p , PM2I_RD_CURSOR_CONTROL , 0 ) ;
pm2_RDAC_WR ( p , PM2I_RD_MISC_CONTROL , PM2F_RD_PALETTE_WIDTH_8 ) ;
2007-10-16 12:28:34 +04:00
pm2_RDAC_WR ( p , PM2I_RD_COLOR_KEY_CONTROL , 0 ) ;
pm2_RDAC_WR ( p , PM2I_RD_OVERLAY_KEY , 0 ) ;
pm2_RDAC_WR ( p , PM2I_RD_RED_KEY , 0 ) ;
pm2_RDAC_WR ( p , PM2I_RD_GREEN_KEY , 0 ) ;
pm2_RDAC_WR ( p , PM2I_RD_BLUE_KEY , 0 ) ;
2005-04-17 02:20:36 +04:00
break ;
case PM2_TYPE_PERMEDIA2V :
pm2v_RDAC_WR ( p , PM2VI_RD_MISC_CONTROL , 1 ) ; /* 8bit */
break ;
}
}
2007-10-16 12:28:50 +04:00
static void set_aperture ( struct pm2fb_par * p , u32 depth )
2005-04-17 02:20:36 +04:00
{
/*
* The hardware is little - endian . When used in big - endian
* hosts , the on - chip aperture settings are used where
* possible to translate from host to card byte order .
*/
2007-10-16 12:28:34 +04:00
WAIT_FIFO ( p , 2 ) ;
2005-04-17 02:20:36 +04:00
# ifdef __LITTLE_ENDIAN
pm2_WR ( p , PM2R_APERTURE_ONE , PM2F_APERTURE_STANDARD ) ;
# else
switch ( depth ) {
case 24 : /* RGB->BGR */
/*
* We can ' t use the aperture to translate host to
* card byte order here , so we switch to BGR mode
* in pm2fb_set_par ( ) .
*/
case 8 : /* B->B */
pm2_WR ( p , PM2R_APERTURE_ONE , PM2F_APERTURE_STANDARD ) ;
break ;
case 16 : /* HL->LH */
pm2_WR ( p , PM2R_APERTURE_ONE , PM2F_APERTURE_HALFWORDSWAP ) ;
break ;
case 32 : /* RGBA->ABGR */
pm2_WR ( p , PM2R_APERTURE_ONE , PM2F_APERTURE_BYTESWAP ) ;
break ;
}
# endif
2007-10-16 12:28:50 +04:00
/* We don't use aperture two, so this may be superflous */
2005-04-17 02:20:36 +04:00
pm2_WR ( p , PM2R_APERTURE_TWO , PM2F_APERTURE_STANDARD ) ;
}
2007-10-16 12:28:50 +04:00
static void set_color ( struct pm2fb_par * p , unsigned char regno ,
2005-04-17 02:20:36 +04:00
unsigned char r , unsigned char g , unsigned char b )
{
WAIT_FIFO ( p , 4 ) ;
pm2_WR ( p , PM2R_RD_PALETTE_WRITE_ADDRESS , regno ) ;
wmb ( ) ;
pm2_WR ( p , PM2R_RD_PALETTE_DATA , r ) ;
wmb ( ) ;
pm2_WR ( p , PM2R_RD_PALETTE_DATA , g ) ;
wmb ( ) ;
pm2_WR ( p , PM2R_RD_PALETTE_DATA , b ) ;
}
2007-10-16 12:28:50 +04:00
static void set_memclock ( struct pm2fb_par * par , u32 clk )
2005-04-17 02:20:36 +04:00
{
int i ;
unsigned char m , n , p ;
2007-05-08 11:39:32 +04:00
switch ( par - > type ) {
case PM2_TYPE_PERMEDIA2V :
pm2v_mnp ( clk / 2 , & m , & n , & p ) ;
2007-10-16 12:28:34 +04:00
WAIT_FIFO ( par , 12 ) ;
2007-05-08 11:39:32 +04:00
pm2_WR ( par , PM2VR_RD_INDEX_HIGH , PM2VI_RD_MCLK_CONTROL > > 8 ) ;
pm2v_RDAC_WR ( par , PM2VI_RD_MCLK_CONTROL , 0 ) ;
pm2v_RDAC_WR ( par , PM2VI_RD_MCLK_PRESCALE , m ) ;
pm2v_RDAC_WR ( par , PM2VI_RD_MCLK_FEEDBACK , n ) ;
pm2v_RDAC_WR ( par , PM2VI_RD_MCLK_POSTSCALE , p ) ;
pm2v_RDAC_WR ( par , PM2VI_RD_MCLK_CONTROL , 1 ) ;
rmb ( ) ;
2007-10-16 12:28:34 +04:00
for ( i = 256 ; i ; i - - )
if ( pm2v_RDAC_RD ( par , PM2VI_RD_MCLK_CONTROL ) & 2 )
break ;
2007-05-08 11:39:32 +04:00
pm2_WR ( par , PM2VR_RD_INDEX_HIGH , 0 ) ;
break ;
case PM2_TYPE_PERMEDIA2 :
pm2_mnp ( clk , & m , & n , & p ) ;
WAIT_FIFO ( par , 10 ) ;
pm2_RDAC_WR ( par , PM2I_RD_MEMORY_CLOCK_3 , 6 ) ;
pm2_RDAC_WR ( par , PM2I_RD_MEMORY_CLOCK_1 , m ) ;
pm2_RDAC_WR ( par , PM2I_RD_MEMORY_CLOCK_2 , n ) ;
pm2_RDAC_WR ( par , PM2I_RD_MEMORY_CLOCK_3 , 8 | p ) ;
pm2_RDAC_RD ( par , PM2I_RD_MEMORY_CLOCK_STATUS ) ;
rmb ( ) ;
2007-10-16 12:28:34 +04:00
for ( i = 256 ; i ; i - - )
if ( pm2_RD ( par , PM2R_RD_INDEXED_DATA ) & PM2F_PLL_LOCKED )
break ;
2007-05-08 11:39:32 +04:00
break ;
}
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:28:50 +04:00
static void set_pixclock ( struct pm2fb_par * par , u32 clk )
2005-04-17 02:20:36 +04:00
{
int i ;
unsigned char m , n , p ;
switch ( par - > type ) {
case PM2_TYPE_PERMEDIA2 :
pm2_mnp ( clk , & m , & n , & p ) ;
2007-10-16 12:28:34 +04:00
WAIT_FIFO ( par , 10 ) ;
2005-04-17 02:20:36 +04:00
pm2_RDAC_WR ( par , PM2I_RD_PIXEL_CLOCK_A3 , 0 ) ;
pm2_RDAC_WR ( par , PM2I_RD_PIXEL_CLOCK_A1 , m ) ;
pm2_RDAC_WR ( par , PM2I_RD_PIXEL_CLOCK_A2 , n ) ;
pm2_RDAC_WR ( par , PM2I_RD_PIXEL_CLOCK_A3 , 8 | p ) ;
pm2_RDAC_RD ( par , PM2I_RD_PIXEL_CLOCK_STATUS ) ;
rmb ( ) ;
2007-10-16 12:28:34 +04:00
for ( i = 256 ; i ; i - - )
if ( pm2_RD ( par , PM2R_RD_INDEXED_DATA ) & PM2F_PLL_LOCKED )
break ;
2005-04-17 02:20:36 +04:00
break ;
case PM2_TYPE_PERMEDIA2V :
pm2v_mnp ( clk / 2 , & m , & n , & p ) ;
WAIT_FIFO ( par , 8 ) ;
pm2_WR ( par , PM2VR_RD_INDEX_HIGH , PM2VI_RD_CLK0_PRESCALE > > 8 ) ;
pm2v_RDAC_WR ( par , PM2VI_RD_CLK0_PRESCALE , m ) ;
pm2v_RDAC_WR ( par , PM2VI_RD_CLK0_FEEDBACK , n ) ;
pm2v_RDAC_WR ( par , PM2VI_RD_CLK0_POSTSCALE , p ) ;
pm2_WR ( par , PM2VR_RD_INDEX_HIGH , 0 ) ;
break ;
}
}
2007-10-16 12:28:50 +04:00
static void set_video ( struct pm2fb_par * p , u32 video )
{
2005-04-17 02:20:36 +04:00
u32 tmp ;
2007-10-16 12:28:34 +04:00
u32 vsync = video ;
2005-04-17 02:20:36 +04:00
DPRINTK ( " video = 0x%x \n " , video ) ;
2007-07-17 15:05:31 +04:00
2005-04-17 02:20:36 +04:00
/*
* The hardware cursor needs + vsync to recognise vert retrace .
* We may not be using the hardware cursor , but the X Glint
* driver may well . So always set + hsync / + vsync and then set
* the RAMDAC to invert the sync if necessary .
*/
2007-10-16 12:28:34 +04:00
vsync & = ~ ( PM2F_HSYNC_MASK | PM2F_VSYNC_MASK ) ;
vsync | = PM2F_HSYNC_ACT_HIGH | PM2F_VSYNC_ACT_HIGH ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:28:36 +04:00
WAIT_FIFO ( p , 3 ) ;
2005-04-17 02:20:36 +04:00
pm2_WR ( p , PM2R_VIDEO_CONTROL , vsync ) ;
switch ( p - > type ) {
case PM2_TYPE_PERMEDIA2 :
tmp = PM2F_RD_PALETTE_WIDTH_8 ;
if ( ( video & PM2F_HSYNC_MASK ) = = PM2F_HSYNC_ACT_LOW )
tmp | = 4 ; /* invert hsync */
if ( ( video & PM2F_VSYNC_MASK ) = = PM2F_VSYNC_ACT_LOW )
tmp | = 8 ; /* invert vsync */
pm2_RDAC_WR ( p , PM2I_RD_MISC_CONTROL , tmp ) ;
break ;
case PM2_TYPE_PERMEDIA2V :
tmp = 0 ;
if ( ( video & PM2F_HSYNC_MASK ) = = PM2F_HSYNC_ACT_LOW )
tmp | = 1 ; /* invert hsync */
if ( ( video & PM2F_VSYNC_MASK ) = = PM2F_VSYNC_ACT_LOW )
tmp | = 4 ; /* invert vsync */
pm2v_RDAC_WR ( p , PM2VI_RD_SYNC_CONTROL , tmp ) ;
break ;
}
}
/*
2007-07-17 15:05:31 +04:00
* pm2fb_check_var - Optional function . Validates a var passed in .
* @ var : frame buffer variable screen structure
* @ info : frame buffer structure that represents a single frame buffer
2005-04-17 02:20:36 +04:00
*
* Checks to see if the hardware supports the state requested by
* var passed in .
*
* Returns negative errno on error , or zero on success .
*/
static int pm2fb_check_var ( struct fb_var_screeninfo * var , struct fb_info * info )
{
u32 lpitch ;
if ( var - > bits_per_pixel ! = 8 & & var - > bits_per_pixel ! = 16 & &
var - > bits_per_pixel ! = 24 & & var - > bits_per_pixel ! = 32 ) {
DPRINTK ( " depth not supported: %u \n " , var - > bits_per_pixel ) ;
return - EINVAL ;
}
if ( var - > xres ! = var - > xres_virtual ) {
2007-10-16 12:28:50 +04:00
DPRINTK ( " virtual x resolution != "
" physical x resolution not supported \n " ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
if ( var - > yres > var - > yres_virtual ) {
2007-10-16 12:28:50 +04:00
DPRINTK ( " virtual y resolution < "
" physical y resolution not possible \n " ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
2007-10-16 12:29:16 +04:00
/* permedia cannot blit over 2048 */
if ( var - > yres_virtual > 2047 ) {
var - > yres_virtual = 2047 ;
}
2005-04-17 02:20:36 +04:00
if ( var - > xoffset ) {
DPRINTK ( " xoffset not supported \n " ) ;
return - EINVAL ;
}
if ( ( var - > vmode & FB_VMODE_MASK ) = = FB_VMODE_INTERLACED ) {
DPRINTK ( " interlace not supported \n " ) ;
return - EINVAL ;
}
var - > xres = ( var - > xres + 15 ) & ~ 15 ; /* could sometimes be 8 */
2007-10-16 12:28:34 +04:00
lpitch = var - > xres * ( ( var - > bits_per_pixel + 7 ) > > 3 ) ;
2007-07-17 15:05:31 +04:00
2005-04-17 02:20:36 +04:00
if ( var - > xres < 320 | | var - > xres > 1600 ) {
DPRINTK ( " width not supported: %u \n " , var - > xres ) ;
return - EINVAL ;
}
2007-07-17 15:05:31 +04:00
2005-04-17 02:20:36 +04:00
if ( var - > yres < 200 | | var - > yres > 1200 ) {
DPRINTK ( " height not supported: %u \n " , var - > yres ) ;
return - EINVAL ;
}
2007-07-17 15:05:31 +04:00
2005-04-17 02:20:36 +04:00
if ( lpitch * var - > yres_virtual > info - > fix . smem_len ) {
DPRINTK ( " no memory for screen (%ux%ux%u) \n " ,
var - > xres , var - > yres_virtual , var - > bits_per_pixel ) ;
return - EINVAL ;
}
2007-07-17 15:05:31 +04:00
2005-04-17 02:20:36 +04:00
if ( PICOS2KHZ ( var - > pixclock ) > PM2_MAX_PIXCLOCK ) {
2007-10-16 12:28:50 +04:00
DPRINTK ( " pixclock too high (%ldKHz) \n " ,
PICOS2KHZ ( var - > pixclock ) ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
2007-05-08 11:39:56 +04:00
var - > transp . offset = 0 ;
var - > transp . length = 0 ;
2007-10-16 12:28:50 +04:00
switch ( var - > bits_per_pixel ) {
2005-04-17 02:20:36 +04:00
case 8 :
2007-10-16 12:28:50 +04:00
var - > red . length = 8 ;
var - > green . length = 8 ;
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 ;
break ;
case 32 :
var - > transp . offset = 24 ;
var - > transp . length = 8 ;
var - > red . offset = 16 ;
var - > green . offset = 8 ;
var - > blue . offset = 0 ;
2007-10-16 12:28:50 +04:00
var - > red . length = 8 ;
var - > green . length = 8 ;
var - > blue . length = 8 ;
2005-04-17 02:20:36 +04:00
break ;
case 24 :
# ifdef __BIG_ENDIAN
var - > red . offset = 0 ;
var - > blue . offset = 16 ;
# else
var - > red . offset = 16 ;
var - > blue . offset = 0 ;
# endif
var - > green . offset = 8 ;
2007-10-16 12:28:50 +04:00
var - > red . length = 8 ;
var - > green . length = 8 ;
var - > blue . length = 8 ;
2005-04-17 02:20:36 +04:00
break ;
}
2007-10-16 12:28:50 +04:00
var - > height = - 1 ;
var - > width = - 1 ;
2007-07-17 15:05:31 +04:00
2005-04-17 02:20:36 +04:00
var - > accel_flags = 0 ; /* Can't mmap if this is on */
2007-07-17 15:05:31 +04:00
2005-04-17 02:20:36 +04:00
DPRINTK ( " Checking graphics mode at %dx%d depth %d \n " ,
var - > xres , var - > yres , var - > bits_per_pixel ) ;
return 0 ;
}
/**
2007-07-17 15:05:31 +04:00
* pm2fb_set_par - Alters the hardware state .
* @ info : frame buffer structure that represents a single frame buffer
2005-04-17 02:20:36 +04:00
*
* Using the fb_var_screeninfo in fb_info we set the resolution of the
* this particular framebuffer .
*/
static int pm2fb_set_par ( struct fb_info * info )
{
2006-01-10 07:53:10 +03:00
struct pm2fb_par * par = info - > par ;
2005-04-17 02:20:36 +04:00
u32 pixclock ;
2007-10-16 12:28:34 +04:00
u32 width = ( info - > var . xres_virtual + 7 ) & ~ 7 ;
u32 height = info - > var . yres_virtual ;
u32 depth = ( info - > var . bits_per_pixel + 7 ) & ~ 7 ;
2005-04-17 02:20:36 +04:00
u32 hsstart , hsend , hbend , htotal ;
u32 vsstart , vsend , vbend , vtotal ;
u32 stride ;
u32 base ;
u32 video = 0 ;
u32 clrmode = PM2F_RD_COLOR_MODE_RGB | PM2F_RD_GUI_ACTIVE ;
u32 txtmap = 0 ;
u32 pixsize = 0 ;
u32 clrformat = 0 ;
2007-10-16 12:28:36 +04:00
u32 misc = 1 ; /* 8-bit DAC */
2007-10-16 12:28:34 +04:00
u32 xres = ( info - > var . xres + 31 ) & ~ 31 ;
2005-04-17 02:20:36 +04:00
int data64 ;
reset_card ( par ) ;
reset_config ( par ) ;
clear_palette ( par ) ;
2007-10-16 12:28:34 +04:00
if ( par - > memclock )
2005-04-17 02:20:36 +04:00
set_memclock ( par , par - > memclock ) ;
2007-07-17 15:05:31 +04:00
2005-04-17 02:20:36 +04:00
depth = ( depth > 32 ) ? 32 : depth ;
data64 = depth > 8 | | par - > type = = PM2_TYPE_PERMEDIA2V ;
pixclock = PICOS2KHZ ( info - > var . pixclock ) ;
if ( pixclock > PM2_MAX_PIXCLOCK ) {
DPRINTK ( " pixclock too high (%uKHz) \n " , pixclock ) ;
return - EINVAL ;
}
2007-07-17 15:05:31 +04:00
2005-04-17 02:20:36 +04:00
hsstart = to3264 ( info - > var . right_margin , depth , data64 ) ;
hsend = hsstart + to3264 ( info - > var . hsync_len , depth , data64 ) ;
hbend = hsend + to3264 ( info - > var . left_margin , depth , data64 ) ;
htotal = to3264 ( xres , depth , data64 ) + hbend - 1 ;
vsstart = ( info - > var . lower_margin )
? info - > var . lower_margin - 1
: 0 ; /* FIXME! */
vsend = info - > var . lower_margin + info - > var . vsync_len - 1 ;
2007-10-16 12:28:50 +04:00
vbend = info - > var . lower_margin + info - > var . vsync_len +
info - > var . upper_margin ;
2005-04-17 02:20:36 +04:00
vtotal = info - > var . yres + vbend - 1 ;
stride = to3264 ( width , depth , 1 ) ;
base = to3264 ( info - > var . yoffset * xres + info - > var . xoffset , depth , 1 ) ;
if ( data64 )
video | = PM2F_DATA_64_ENABLE ;
2007-07-17 15:05:31 +04:00
2005-04-17 02:20:36 +04:00
if ( info - > var . sync & FB_SYNC_HOR_HIGH_ACT ) {
if ( lowhsync ) {
DPRINTK ( " ignoring +hsync, using -hsync. \n " ) ;
video | = PM2F_HSYNC_ACT_LOW ;
} else
video | = PM2F_HSYNC_ACT_HIGH ;
2007-10-16 12:28:50 +04:00
} else
2005-04-17 02:20:36 +04:00
video | = PM2F_HSYNC_ACT_LOW ;
2007-10-16 12:28:50 +04:00
2005-04-17 02:20:36 +04:00
if ( info - > var . sync & FB_SYNC_VERT_HIGH_ACT ) {
if ( lowvsync ) {
DPRINTK ( " ignoring +vsync, using -vsync. \n " ) ;
video | = PM2F_VSYNC_ACT_LOW ;
} else
video | = PM2F_VSYNC_ACT_HIGH ;
2007-10-16 12:28:50 +04:00
} else
2005-04-17 02:20:36 +04:00
video | = PM2F_VSYNC_ACT_LOW ;
2007-10-16 12:28:50 +04:00
2007-10-16 12:28:34 +04:00
if ( ( info - > var . vmode & FB_VMODE_MASK ) = = FB_VMODE_INTERLACED ) {
2005-04-17 02:20:36 +04:00
DPRINTK ( " interlaced not supported \n " ) ;
return - EINVAL ;
}
2007-10-16 12:28:34 +04:00
if ( ( info - > var . vmode & FB_VMODE_MASK ) = = FB_VMODE_DOUBLE )
2005-04-17 02:20:36 +04:00
video | = PM2F_LINE_DOUBLE ;
2007-10-16 12:28:34 +04:00
if ( ( info - > var . activate & FB_ACTIVATE_MASK ) = = FB_ACTIVATE_NOW )
2005-04-17 02:20:36 +04:00
video | = PM2F_VIDEO_ENABLE ;
par - > video = video ;
info - > fix . visual =
( depth = = 8 ) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR ;
info - > fix . line_length = info - > var . xres * depth / 8 ;
info - > cmap . len = 256 ;
/*
* Settings calculated . Now write them out .
*/
if ( par - > type = = PM2_TYPE_PERMEDIA2V ) {
WAIT_FIFO ( par , 1 ) ;
pm2_WR ( par , PM2VR_RD_INDEX_HIGH , 0 ) ;
}
2007-07-17 15:05:31 +04:00
2005-04-17 02:20:36 +04:00
set_aperture ( par , depth ) ;
2007-07-17 15:05:31 +04:00
2005-04-17 02:20:36 +04:00
mb ( ) ;
WAIT_FIFO ( par , 19 ) ;
switch ( depth ) {
case 8 :
pm2_WR ( par , PM2R_FB_READ_PIXEL , 0 ) ;
2007-10-16 12:28:36 +04:00
clrformat = 0x2e ;
2005-04-17 02:20:36 +04:00
break ;
case 16 :
pm2_WR ( par , PM2R_FB_READ_PIXEL , 1 ) ;
clrmode | = PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGB565 ;
txtmap = PM2F_TEXTEL_SIZE_16 ;
pixsize = 1 ;
clrformat = 0x70 ;
2007-10-16 12:28:36 +04:00
misc | = 8 ;
2005-04-17 02:20:36 +04:00
break ;
case 32 :
pm2_WR ( par , PM2R_FB_READ_PIXEL , 2 ) ;
clrmode | = PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGBA8888 ;
txtmap = PM2F_TEXTEL_SIZE_32 ;
pixsize = 2 ;
clrformat = 0x20 ;
2007-10-16 12:28:36 +04:00
misc | = 8 ;
2005-04-17 02:20:36 +04:00
break ;
case 24 :
pm2_WR ( par , PM2R_FB_READ_PIXEL , 4 ) ;
clrmode | = PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGB888 ;
txtmap = PM2F_TEXTEL_SIZE_24 ;
pixsize = 4 ;
clrformat = 0x20 ;
2007-10-16 12:28:36 +04:00
misc | = 8 ;
2005-04-17 02:20:36 +04:00
break ;
}
pm2_WR ( par , PM2R_FB_WRITE_MODE , PM2F_FB_WRITE_ENABLE ) ;
pm2_WR ( par , PM2R_FB_READ_MODE , partprod ( xres ) ) ;
pm2_WR ( par , PM2R_LB_READ_MODE , partprod ( xres ) ) ;
pm2_WR ( par , PM2R_TEXTURE_MAP_FORMAT , txtmap | partprod ( xres ) ) ;
pm2_WR ( par , PM2R_H_TOTAL , htotal ) ;
pm2_WR ( par , PM2R_HS_START , hsstart ) ;
pm2_WR ( par , PM2R_HS_END , hsend ) ;
pm2_WR ( par , PM2R_HG_END , hbend ) ;
pm2_WR ( par , PM2R_HB_END , hbend ) ;
pm2_WR ( par , PM2R_V_TOTAL , vtotal ) ;
pm2_WR ( par , PM2R_VS_START , vsstart ) ;
pm2_WR ( par , PM2R_VS_END , vsend ) ;
pm2_WR ( par , PM2R_VB_END , vbend ) ;
pm2_WR ( par , PM2R_SCREEN_STRIDE , stride ) ;
wmb ( ) ;
pm2_WR ( par , PM2R_WINDOW_ORIGIN , 0 ) ;
pm2_WR ( par , PM2R_SCREEN_SIZE , ( height < < 16 ) | width ) ;
pm2_WR ( par , PM2R_SCISSOR_MODE , PM2F_SCREEN_SCISSOR_ENABLE ) ;
wmb ( ) ;
pm2_WR ( par , PM2R_SCREEN_BASE , base ) ;
wmb ( ) ;
set_video ( par , video ) ;
2007-10-16 12:28:36 +04:00
WAIT_FIFO ( par , 10 ) ;
2005-04-17 02:20:36 +04:00
switch ( par - > type ) {
case PM2_TYPE_PERMEDIA2 :
pm2_RDAC_WR ( par , PM2I_RD_COLOR_MODE , clrmode ) ;
2007-10-16 12:28:34 +04:00
pm2_RDAC_WR ( par , PM2I_RD_COLOR_KEY_CONTROL ,
2007-10-16 12:28:50 +04:00
( depth = = 8 ) ? 0 : PM2F_COLOR_KEY_TEST_OFF ) ;
2005-04-17 02:20:36 +04:00
break ;
case PM2_TYPE_PERMEDIA2V :
2007-10-16 12:28:36 +04:00
pm2v_RDAC_WR ( par , PM2VI_RD_DAC_CONTROL , 0 ) ;
2005-04-17 02:20:36 +04:00
pm2v_RDAC_WR ( par , PM2VI_RD_PIXEL_SIZE , pixsize ) ;
pm2v_RDAC_WR ( par , PM2VI_RD_COLOR_FORMAT , clrformat ) ;
2007-10-16 12:28:36 +04:00
pm2v_RDAC_WR ( par , PM2VI_RD_MISC_CONTROL , misc ) ;
pm2v_RDAC_WR ( par , PM2VI_RD_OVERLAY_KEY , 0 ) ;
2005-04-17 02:20:36 +04:00
break ;
}
set_pixclock ( par , pixclock ) ;
DPRINTK ( " Setting graphics mode at %dx%d depth %d \n " ,
info - > var . xres , info - > var . yres , info - > var . bits_per_pixel ) ;
2007-07-17 15:05:31 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/**
2007-07-17 15:05:31 +04:00
* pm2fb_setcolreg - Sets a color register .
* @ regno : boolean , 0 copy local , 1 get_user ( ) function
* @ red : frame buffer colormap structure
* @ green : The green value which can be up to 16 bits wide
2005-04-17 02:20:36 +04:00
* @ blue : The blue value which can be up to 16 bits wide .
2007-07-17 15:05:31 +04:00
* @ transp : If supported the alpha value which can be up to 16 bits wide .
* @ info : frame buffer info structure
*
* Set a single color register . The values supplied have a 16 bit
* magnitude which needs to be scaled in this function for the hardware .
2005-04-17 02:20:36 +04:00
* Pretty much a direct lift from tdfxfb . c .
2007-07-17 15:05:31 +04:00
*
2005-04-17 02:20:36 +04:00
* Returns negative errno on error , or zero on success .
*/
static int pm2fb_setcolreg ( unsigned regno , unsigned red , unsigned green ,
unsigned blue , unsigned transp ,
struct fb_info * info )
{
2006-01-10 07:53:10 +03:00
struct pm2fb_par * par = info - > par ;
2005-04-17 02:20:36 +04:00
if ( regno > = info - > cmap . len ) /* no. of hw registers */
2007-10-16 12:28:36 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
/*
* Program hardware . . . do anything you want with transp
*/
/* grayscale works only partially under directcolor */
2007-10-16 12:28:50 +04:00
/* grayscale = 0.30*R + 0.59*G + 0.11*B */
if ( info - > var . grayscale )
2005-04-17 02:20:36 +04:00
red = green = blue = ( red * 77 + green * 151 + blue * 28 ) > > 8 ;
/* Directcolor:
* var - > { color } . offset contains start of bitfield
* var - > { color } . length contains length of bitfield
* { hardwarespecific } contains width of DAC
* cmap [ X ] is programmed to
* ( X < < red . offset ) | ( X < < green . offset ) | ( X < < blue . offset )
* RAMDAC [ X ] is programmed to ( red , green , blue )
*
* Pseudocolor :
* uses offset = 0 & & length = DAC register width .
* var - > { color } . offset is 0
2010-01-28 11:11:51 +03:00
* var - > { color } . length contains width of DAC
2005-04-17 02:20:36 +04:00
* cmap is not used
* DAC [ X ] is programmed to ( red , green , blue )
* Truecolor :
* does not use RAMDAC ( usually has 3 of them ) .
* var - > { color } . offset contains start of bitfield
* var - > { color } . length contains length of bitfield
* cmap is programmed to
* ( red < < red . offset ) | ( green < < green . offset ) |
* ( blue < < blue . offset ) | ( transp < < transp . offset )
* RAMDAC does not exist
*/
2007-07-17 15:05:31 +04:00
# define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF -(val)) >> 16)
2005-04-17 02:20:36 +04:00
switch ( info - > fix . visual ) {
case FB_VISUAL_TRUECOLOR :
case FB_VISUAL_PSEUDOCOLOR :
red = CNVT_TOHW ( red , info - > var . red . length ) ;
green = CNVT_TOHW ( green , info - > var . green . length ) ;
blue = CNVT_TOHW ( blue , info - > var . blue . length ) ;
transp = CNVT_TOHW ( transp , info - > var . transp . length ) ;
break ;
case FB_VISUAL_DIRECTCOLOR :
2007-07-17 15:05:31 +04:00
/* example here assumes 8 bit DAC. Might be different
* for your hardware */
red = CNVT_TOHW ( red , 8 ) ;
2005-04-17 02:20:36 +04:00
green = CNVT_TOHW ( green , 8 ) ;
blue = CNVT_TOHW ( blue , 8 ) ;
/* hey, there is bug in transp handling... */
transp = CNVT_TOHW ( transp , 8 ) ;
break ;
}
# undef CNVT_TOHW
/* Truecolor has hardware independent palette */
if ( info - > fix . visual = = FB_VISUAL_TRUECOLOR ) {
u32 v ;
if ( regno > = 16 )
2007-10-16 12:28:36 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
v = ( red < < info - > var . red . offset ) |
( green < < info - > var . green . offset ) |
( blue < < info - > var . blue . offset ) |
( transp < < info - > var . transp . offset ) ;
switch ( info - > var . bits_per_pixel ) {
case 8 :
2007-07-17 15:05:31 +04:00
break ;
case 16 :
2005-04-17 02:20:36 +04:00
case 24 :
2007-07-17 15:05:31 +04:00
case 32 :
par - > palette [ regno ] = v ;
2005-04-17 02:20:36 +04:00
break ;
}
return 0 ;
2007-10-16 12:28:50 +04:00
} else if ( info - > fix . visual = = FB_VISUAL_PSEUDOCOLOR )
2005-04-17 02:20:36 +04:00
set_color ( par , regno , red , green , blue ) ;
return 0 ;
}
/**
2007-07-17 15:05:31 +04:00
* pm2fb_pan_display - Pans the display .
* @ var : frame buffer variable screen structure
* @ info : frame buffer structure that represents a single frame buffer
2005-04-17 02:20:36 +04:00
*
* Pan ( or wrap , depending on the ` vmode ' field ) the display using the
2007-07-17 15:05:31 +04:00
* ` xoffset ' and ` yoffset ' fields of the ` var ' structure .
* If the values don ' t fit , return - EINVAL .
2005-04-17 02:20:36 +04:00
*
2007-07-17 15:05:31 +04:00
* Returns negative errno on error , or zero on success .
2005-04-17 02:20:36 +04:00
*
*/
static int pm2fb_pan_display ( struct fb_var_screeninfo * var ,
struct fb_info * info )
{
2006-01-10 07:53:10 +03:00
struct pm2fb_par * p = info - > par ;
2005-04-17 02:20:36 +04:00
u32 base ;
2007-10-16 12:28:34 +04:00
u32 depth = ( var - > bits_per_pixel + 7 ) & ~ 7 ;
u32 xres = ( var - > xres + 31 ) & ~ 31 ;
2005-04-17 02:20:36 +04:00
depth = ( depth > 32 ) ? 32 : depth ;
base = to3264 ( var - > yoffset * xres + var - > xoffset , depth , 1 ) ;
WAIT_FIFO ( p , 1 ) ;
2007-07-17 15:05:31 +04:00
pm2_WR ( p , PM2R_SCREEN_BASE , base ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/**
2007-07-17 15:05:31 +04:00
* pm2fb_blank - Blanks the display .
* @ blank_mode : the blank mode we want .
* @ info : frame buffer structure that represents a single frame buffer
2005-04-17 02:20:36 +04:00
*
2007-07-17 15:05:31 +04:00
* Blank the screen if blank_mode ! = 0 , else unblank . Return 0 if
* blanking succeeded , ! = 0 if un - / blanking failed due to e . g . a
* video mode which doesn ' t support it . Implements VESA suspend
* and powerdown modes on hardware that supports disabling hsync / vsync :
* blank_mode = = 2 : suspend vsync
* blank_mode = = 3 : suspend hsync
* blank_mode = = 4 : powerdown
2005-04-17 02:20:36 +04:00
*
2007-07-17 15:05:31 +04:00
* Returns negative errno on error , or zero on success .
2005-04-17 02:20:36 +04:00
*
*/
static int pm2fb_blank ( int blank_mode , struct fb_info * info )
{
2006-01-10 07:53:10 +03:00
struct pm2fb_par * par = info - > par ;
2005-04-17 02:20:36 +04:00
u32 video = par - > video ;
DPRINTK ( " blank_mode %d \n " , blank_mode ) ;
switch ( blank_mode ) {
case FB_BLANK_UNBLANK :
/* Screen: On */
video | = PM2F_VIDEO_ENABLE ;
break ;
case FB_BLANK_NORMAL :
/* Screen: Off */
video & = ~ PM2F_VIDEO_ENABLE ;
break ;
case FB_BLANK_VSYNC_SUSPEND :
/* VSync: Off */
2007-10-16 12:28:34 +04:00
video & = ~ ( PM2F_VSYNC_MASK | PM2F_BLANK_LOW ) ;
2005-04-17 02:20:36 +04:00
break ;
case FB_BLANK_HSYNC_SUSPEND :
/* HSync: Off */
2007-10-16 12:28:34 +04:00
video & = ~ ( PM2F_HSYNC_MASK | PM2F_BLANK_LOW ) ;
2005-04-17 02:20:36 +04:00
break ;
case FB_BLANK_POWERDOWN :
/* HSync: Off, VSync: Off */
2007-10-16 12:28:50 +04:00
video & = ~ ( PM2F_VSYNC_MASK | PM2F_HSYNC_MASK | PM2F_BLANK_LOW ) ;
2005-04-17 02:20:36 +04:00
break ;
}
set_video ( par , video ) ;
return 0 ;
}
2007-05-11 09:23:29 +04:00
static int pm2fb_sync ( struct fb_info * info )
{
struct pm2fb_par * par = info - > par ;
WAIT_FIFO ( par , 1 ) ;
pm2_WR ( par , PM2R_SYNC , 0 ) ;
mb ( ) ;
do {
while ( pm2_RD ( par , PM2R_OUT_FIFO_WORDS ) = = 0 )
2007-10-16 12:29:27 +04:00
cpu_relax ( ) ;
2007-05-11 09:23:29 +04:00
} while ( pm2_RD ( par , PM2R_OUT_FIFO ) ! = PM2TAG ( PM2R_SYNC ) ) ;
return 0 ;
}
2007-10-16 12:28:50 +04:00
static void pm2fb_fillrect ( struct fb_info * info ,
2007-05-08 11:40:02 +04:00
const struct fb_fillrect * region )
{
2007-10-16 12:28:50 +04:00
struct pm2fb_par * par = info - > par ;
2007-05-08 11:40:02 +04:00
struct fb_fillrect modded ;
int vxres , vyres ;
u32 color = ( info - > fix . visual = = FB_VISUAL_TRUECOLOR ) ?
2007-10-16 12:28:50 +04:00
( ( u32 * ) info - > pseudo_palette ) [ region - > color ] : region - > color ;
2007-05-08 11:40:02 +04:00
if ( info - > state ! = FBINFO_STATE_RUNNING )
return ;
if ( ( info - > flags & FBINFO_HWACCEL_DISABLED ) | |
region - > rop ! = ROP_COPY ) {
cfb_fillrect ( info , region ) ;
return ;
}
vxres = info - > var . xres_virtual ;
vyres = info - > var . yres_virtual ;
memcpy ( & modded , region , sizeof ( struct fb_fillrect ) ) ;
2007-10-16 12:28:34 +04:00
if ( ! modded . width | | ! modded . height | |
modded . dx > = vxres | | modded . dy > = vyres )
2007-05-08 11:40:02 +04:00
return ;
2007-10-16 12:28:34 +04:00
if ( modded . dx + modded . width > vxres )
2007-05-08 11:40:02 +04:00
modded . width = vxres - modded . dx ;
2007-10-16 12:28:34 +04:00
if ( modded . dy + modded . height > vyres )
2007-05-08 11:40:02 +04:00
modded . height = vyres - modded . dy ;
2007-10-16 12:28:34 +04:00
if ( info - > var . bits_per_pixel = = 8 )
2007-05-08 11:40:02 +04:00
color | = color < < 8 ;
2007-10-16 12:28:34 +04:00
if ( info - > var . bits_per_pixel < = 16 )
2007-05-08 11:40:02 +04:00
color | = color < < 16 ;
2007-10-16 12:28:34 +04:00
WAIT_FIFO ( par , 3 ) ;
pm2_WR ( par , PM2R_CONFIG , PM2F_CONFIG_FB_WRITE_ENABLE ) ;
pm2_WR ( par , PM2R_RECTANGLE_ORIGIN , ( modded . dy < < 16 ) | modded . dx ) ;
pm2_WR ( par , PM2R_RECTANGLE_SIZE , ( modded . height < < 16 ) | modded . width ) ;
if ( info - > var . bits_per_pixel ! = 24 ) {
WAIT_FIFO ( par , 2 ) ;
pm2_WR ( par , PM2R_FB_BLOCK_COLOR , color ) ;
wmb ( ) ;
pm2_WR ( par , PM2R_RENDER ,
PM2F_RENDER_RECTANGLE | PM2F_RENDER_FASTFILL ) ;
} else {
2007-10-16 12:28:36 +04:00
WAIT_FIFO ( par , 4 ) ;
pm2_WR ( par , PM2R_COLOR_DDA_MODE , 1 ) ;
pm2_WR ( par , PM2R_CONSTANT_COLOR , color ) ;
wmb ( ) ;
pm2_WR ( par , PM2R_RENDER ,
2007-10-16 12:28:50 +04:00
PM2F_RENDER_RECTANGLE |
PM2F_INCREASE_X | PM2F_INCREASE_Y ) ;
2007-10-16 12:28:36 +04:00
pm2_WR ( par , PM2R_COLOR_DDA_MODE , 0 ) ;
2007-10-16 12:28:34 +04:00
}
2007-05-08 11:40:02 +04:00
}
static void pm2fb_copyarea ( struct fb_info * info ,
const struct fb_copyarea * area )
{
2007-10-16 12:28:34 +04:00
struct pm2fb_par * par = info - > par ;
2007-05-08 11:40:02 +04:00
struct fb_copyarea modded ;
u32 vxres , vyres ;
if ( info - > state ! = FBINFO_STATE_RUNNING )
return ;
if ( info - > flags & FBINFO_HWACCEL_DISABLED ) {
cfb_copyarea ( info , area ) ;
return ;
}
memcpy ( & modded , area , sizeof ( struct fb_copyarea ) ) ;
vxres = info - > var . xres_virtual ;
vyres = info - > var . yres_virtual ;
2007-10-16 12:28:34 +04:00
if ( ! modded . width | | ! modded . height | |
modded . sx > = vxres | | modded . sy > = vyres | |
modded . dx > = vxres | | modded . dy > = vyres )
2007-05-08 11:40:02 +04:00
return ;
2007-10-16 12:28:34 +04:00
if ( modded . sx + modded . width > vxres )
2007-05-08 11:40:02 +04:00
modded . width = vxres - modded . sx ;
2007-10-16 12:28:34 +04:00
if ( modded . dx + modded . width > vxres )
2007-05-08 11:40:02 +04:00
modded . width = vxres - modded . dx ;
2007-10-16 12:28:34 +04:00
if ( modded . sy + modded . height > vyres )
2007-05-08 11:40:02 +04:00
modded . height = vyres - modded . sy ;
2007-10-16 12:28:34 +04:00
if ( modded . dy + modded . height > vyres )
2007-05-08 11:40:02 +04:00
modded . height = vyres - modded . dy ;
2007-10-16 12:28:34 +04:00
WAIT_FIFO ( par , 5 ) ;
pm2_WR ( par , PM2R_CONFIG , PM2F_CONFIG_FB_WRITE_ENABLE |
PM2F_CONFIG_FB_READ_SOURCE_ENABLE ) ;
pm2_WR ( par , PM2R_FB_SOURCE_DELTA ,
2007-10-16 12:28:50 +04:00
( ( modded . sy - modded . dy ) & 0xfff ) < < 16 |
( ( modded . sx - modded . dx ) & 0xfff ) ) ;
2007-10-16 12:28:34 +04:00
pm2_WR ( par , PM2R_RECTANGLE_ORIGIN , ( modded . dy < < 16 ) | modded . dx ) ;
pm2_WR ( par , PM2R_RECTANGLE_SIZE , ( modded . height < < 16 ) | modded . width ) ;
wmb ( ) ;
pm2_WR ( par , PM2R_RENDER , PM2F_RENDER_RECTANGLE |
2007-10-16 12:28:50 +04:00
( modded . dx < modded . sx ? PM2F_INCREASE_X : 0 ) |
( modded . dy < modded . sy ? PM2F_INCREASE_Y : 0 ) ) ;
2007-05-08 11:40:02 +04:00
}
2007-10-16 12:28:34 +04:00
static void pm2fb_imageblit ( struct fb_info * info , const struct fb_image * image )
{
struct pm2fb_par * par = info - > par ;
u32 height = image - > height ;
u32 fgx , bgx ;
2007-10-16 12:28:50 +04:00
const u32 * src = ( const u32 * ) image - > data ;
2007-10-16 12:28:34 +04:00
u32 xres = ( info - > var . xres + 31 ) & ~ 31 ;
2008-02-06 12:39:37 +03:00
int raster_mode = 1 ; /* invert bits */
# ifdef __LITTLE_ENDIAN
raster_mode | = 3 < < 7 ; /* reverse byte order */
# endif
2007-10-16 12:28:34 +04:00
if ( info - > state ! = FBINFO_STATE_RUNNING )
return ;
if ( info - > flags & FBINFO_HWACCEL_DISABLED | | image - > depth ! = 1 ) {
cfb_imageblit ( info , image ) ;
return ;
}
switch ( info - > fix . visual ) {
2007-10-16 12:28:34 +04:00
case FB_VISUAL_PSEUDOCOLOR :
fgx = image - > fg_color ;
bgx = image - > bg_color ;
break ;
case FB_VISUAL_TRUECOLOR :
default :
fgx = par - > palette [ image - > fg_color ] ;
bgx = par - > palette [ image - > bg_color ] ;
break ;
2007-10-16 12:28:34 +04:00
}
if ( info - > var . bits_per_pixel = = 8 ) {
fgx | = fgx < < 8 ;
bgx | = bgx < < 8 ;
}
if ( info - > var . bits_per_pixel < = 16 ) {
fgx | = fgx < < 16 ;
bgx | = bgx < < 16 ;
}
WAIT_FIFO ( par , 13 ) ;
pm2_WR ( par , PM2R_FB_READ_MODE , partprod ( xres ) ) ;
pm2_WR ( par , PM2R_SCISSOR_MIN_XY ,
( ( image - > dy & 0xfff ) < < 16 ) | ( image - > dx & 0x0fff ) ) ;
pm2_WR ( par , PM2R_SCISSOR_MAX_XY ,
( ( ( image - > dy + image - > height ) & 0x0fff ) < < 16 ) |
( ( image - > dx + image - > width ) & 0x0fff ) ) ;
pm2_WR ( par , PM2R_SCISSOR_MODE , 1 ) ;
/* GXcopy & UNIT_ENABLE */
2007-10-16 12:28:34 +04:00
pm2_WR ( par , PM2R_LOGICAL_OP_MODE , ( 0x3 < < 1 ) | 1 ) ;
2007-10-16 12:28:34 +04:00
pm2_WR ( par , PM2R_RECTANGLE_ORIGIN ,
( ( image - > dy & 0xfff ) < < 16 ) | ( image - > dx & 0x0fff ) ) ;
pm2_WR ( par , PM2R_RECTANGLE_SIZE ,
( ( image - > height & 0x0fff ) < < 16 ) |
( ( image - > width ) & 0x0fff ) ) ;
if ( info - > var . bits_per_pixel = = 24 ) {
pm2_WR ( par , PM2R_COLOR_DDA_MODE , 1 ) ;
/* clear area */
pm2_WR ( par , PM2R_CONSTANT_COLOR , bgx ) ;
pm2_WR ( par , PM2R_RENDER ,
PM2F_RENDER_RECTANGLE |
2007-10-16 12:28:34 +04:00
PM2F_INCREASE_X | PM2F_INCREASE_Y ) ;
2008-02-06 12:39:37 +03:00
/* BitMapPackEachScanline */
pm2_WR ( par , PM2R_RASTERIZER_MODE , raster_mode | ( 1 < < 9 ) ) ;
2007-10-16 12:28:34 +04:00
pm2_WR ( par , PM2R_CONSTANT_COLOR , fgx ) ;
pm2_WR ( par , PM2R_RENDER ,
PM2F_RENDER_RECTANGLE |
PM2F_INCREASE_X | PM2F_INCREASE_Y |
PM2F_RENDER_SYNC_ON_BIT_MASK ) ;
} else {
pm2_WR ( par , PM2R_COLOR_DDA_MODE , 0 ) ;
/* clear area */
pm2_WR ( par , PM2R_FB_BLOCK_COLOR , bgx ) ;
pm2_WR ( par , PM2R_RENDER ,
PM2F_RENDER_RECTANGLE |
PM2F_RENDER_FASTFILL |
2007-10-16 12:28:34 +04:00
PM2F_INCREASE_X | PM2F_INCREASE_Y ) ;
2008-02-06 12:39:37 +03:00
pm2_WR ( par , PM2R_RASTERIZER_MODE , raster_mode ) ;
2007-10-16 12:28:34 +04:00
pm2_WR ( par , PM2R_FB_BLOCK_COLOR , fgx ) ;
pm2_WR ( par , PM2R_RENDER ,
PM2F_RENDER_RECTANGLE |
PM2F_INCREASE_X | PM2F_INCREASE_Y |
PM2F_RENDER_FASTFILL |
PM2F_RENDER_SYNC_ON_BIT_MASK ) ;
}
while ( height - - ) {
int width = ( ( image - > width + 7 ) > > 3 )
+ info - > pixmap . scan_align - 1 ;
width > > = 2 ;
WAIT_FIFO ( par , width ) ;
while ( width - - ) {
pm2_WR ( par , PM2R_BIT_MASK_PATTERN , * src ) ;
src + + ;
}
}
WAIT_FIFO ( par , 3 ) ;
pm2_WR ( par , PM2R_RASTERIZER_MODE , 0 ) ;
pm2_WR ( par , PM2R_COLOR_DDA_MODE , 0 ) ;
pm2_WR ( par , PM2R_SCISSOR_MODE , 0 ) ;
}
2007-10-16 12:28:53 +04:00
/*
* Hardware cursor support .
*/
static const u8 cursor_bits_lookup [ 16 ] = {
0x00 , 0x40 , 0x10 , 0x50 , 0x04 , 0x44 , 0x14 , 0x54 ,
0x01 , 0x41 , 0x11 , 0x51 , 0x05 , 0x45 , 0x15 , 0x55
} ;
static int pm2vfb_cursor ( struct fb_info * info , struct fb_cursor * cursor )
{
struct pm2fb_par * par = info - > par ;
2007-10-16 12:29:16 +04:00
u8 mode = PM2F_CURSORMODE_TYPE_X ;
2007-10-16 12:29:16 +04:00
int x = cursor - > image . dx - info - > var . xoffset ;
int y = cursor - > image . dy - info - > var . yoffset ;
2007-10-16 12:28:53 +04:00
if ( cursor - > enable )
mode | = PM2F_CURSORMODE_CURSOR_ENABLE ;
pm2v_RDAC_WR ( par , PM2VI_RD_CURSOR_MODE , mode ) ;
2007-10-16 12:29:16 +04:00
if ( ! cursor - > enable )
x = 2047 ; /* push it outside display */
pm2v_RDAC_WR ( par , PM2VI_RD_CURSOR_X_LOW , x & 0xff ) ;
pm2v_RDAC_WR ( par , PM2VI_RD_CURSOR_X_HIGH , ( x > > 8 ) & 0xf ) ;
pm2v_RDAC_WR ( par , PM2VI_RD_CURSOR_Y_LOW , y & 0xff ) ;
pm2v_RDAC_WR ( par , PM2VI_RD_CURSOR_Y_HIGH , ( y > > 8 ) & 0xf ) ;
2007-10-16 12:28:53 +04:00
/*
* If the cursor is not be changed this means either we want the
* current cursor state ( if enable is set ) or we want to query what
* we can do with the cursor ( if enable is not set )
*/
if ( ! cursor - > set )
return 0 ;
if ( cursor - > set & FB_CUR_SETHOT ) {
pm2v_RDAC_WR ( par , PM2VI_RD_CURSOR_X_HOT ,
cursor - > hot . x & 0x3f ) ;
pm2v_RDAC_WR ( par , PM2VI_RD_CURSOR_Y_HOT ,
cursor - > hot . y & 0x3f ) ;
}
if ( cursor - > set & FB_CUR_SETCMAP ) {
u32 fg_idx = cursor - > image . fg_color ;
u32 bg_idx = cursor - > image . bg_color ;
struct fb_cmap cmap = info - > cmap ;
/* the X11 driver says one should use these color registers */
pm2_WR ( par , PM2VR_RD_INDEX_HIGH , PM2VI_RD_CURSOR_PALETTE > > 8 ) ;
pm2v_RDAC_WR ( par , PM2VI_RD_CURSOR_PALETTE + 0 ,
cmap . red [ bg_idx ] > > 8 ) ;
pm2v_RDAC_WR ( par , PM2VI_RD_CURSOR_PALETTE + 1 ,
cmap . green [ bg_idx ] > > 8 ) ;
pm2v_RDAC_WR ( par , PM2VI_RD_CURSOR_PALETTE + 2 ,
cmap . blue [ bg_idx ] > > 8 ) ;
pm2v_RDAC_WR ( par , PM2VI_RD_CURSOR_PALETTE + 3 ,
cmap . red [ fg_idx ] > > 8 ) ;
pm2v_RDAC_WR ( par , PM2VI_RD_CURSOR_PALETTE + 4 ,
cmap . green [ fg_idx ] > > 8 ) ;
pm2v_RDAC_WR ( par , PM2VI_RD_CURSOR_PALETTE + 5 ,
cmap . blue [ fg_idx ] > > 8 ) ;
pm2_WR ( par , PM2VR_RD_INDEX_HIGH , 0 ) ;
}
if ( cursor - > set & ( FB_CUR_SETSHAPE | FB_CUR_SETIMAGE ) ) {
u8 * bitmap = ( u8 * ) cursor - > image . data ;
u8 * mask = ( u8 * ) cursor - > mask ;
int i ;
int pos = PM2VI_RD_CURSOR_PATTERN ;
for ( i = 0 ; i < cursor - > image . height ; i + + ) {
int j = ( cursor - > image . width + 7 ) > > 3 ;
int k = 8 - j ;
pm2_WR ( par , PM2VR_RD_INDEX_HIGH , pos > > 8 ) ;
for ( ; j > 0 ; j - - ) {
u8 data = * bitmap ^ * mask ;
if ( cursor - > rop = = ROP_COPY )
data = * mask & * bitmap ;
/* Upper 4 bits of bitmap data */
pm2v_RDAC_WR ( par , pos + + ,
cursor_bits_lookup [ data > > 4 ] |
( cursor_bits_lookup [ * mask > > 4 ] < < 1 ) ) ;
/* Lower 4 bits of bitmap */
pm2v_RDAC_WR ( par , pos + + ,
cursor_bits_lookup [ data & 0xf ] |
( cursor_bits_lookup [ * mask & 0xf ] < < 1 ) ) ;
bitmap + + ;
mask + + ;
}
for ( ; k > 0 ; k - - ) {
pm2v_RDAC_WR ( par , pos + + , 0 ) ;
pm2v_RDAC_WR ( par , pos + + , 0 ) ;
}
}
while ( pos < ( 1024 + PM2VI_RD_CURSOR_PATTERN ) ) {
pm2_WR ( par , PM2VR_RD_INDEX_HIGH , pos > > 8 ) ;
pm2v_RDAC_WR ( par , pos + + , 0 ) ;
}
pm2_WR ( par , PM2VR_RD_INDEX_HIGH , 0 ) ;
}
return 0 ;
}
static int pm2fb_cursor ( struct fb_info * info , struct fb_cursor * cursor )
{
struct pm2fb_par * par = info - > par ;
2007-10-16 12:29:16 +04:00
u8 mode ;
if ( ! hwcursor )
return - EINVAL ; /* just to force soft_cursor() call */
/* Too large of a cursor or wrong bpp :-( */
if ( cursor - > image . width > 64 | |
cursor - > image . height > 64 | |
cursor - > image . depth > 1 )
return - EINVAL ;
2007-10-16 12:28:53 +04:00
if ( par - > type = = PM2_TYPE_PERMEDIA2V )
return pm2vfb_cursor ( info , cursor ) ;
2007-10-16 12:29:16 +04:00
mode = 0x40 ;
2007-10-16 12:29:16 +04:00
if ( cursor - > enable )
mode = 0x43 ;
pm2_RDAC_WR ( par , PM2I_RD_CURSOR_CONTROL , mode ) ;
/*
* If the cursor is not be changed this means either we want the
* current cursor state ( if enable is set ) or we want to query what
* we can do with the cursor ( if enable is not set )
*/
if ( ! cursor - > set )
return 0 ;
if ( cursor - > set & FB_CUR_SETPOS ) {
2007-10-16 12:29:16 +04:00
int x = cursor - > image . dx - info - > var . xoffset + 63 ;
int y = cursor - > image . dy - info - > var . yoffset + 63 ;
2007-10-16 12:29:16 +04:00
WAIT_FIFO ( par , 4 ) ;
pm2_WR ( par , PM2R_RD_CURSOR_X_LSB , x & 0xff ) ;
pm2_WR ( par , PM2R_RD_CURSOR_X_MSB , ( x > > 8 ) & 0x7 ) ;
pm2_WR ( par , PM2R_RD_CURSOR_Y_LSB , y & 0xff ) ;
pm2_WR ( par , PM2R_RD_CURSOR_Y_MSB , ( y > > 8 ) & 0x7 ) ;
}
if ( cursor - > set & FB_CUR_SETCMAP ) {
u32 fg_idx = cursor - > image . fg_color ;
u32 bg_idx = cursor - > image . bg_color ;
WAIT_FIFO ( par , 7 ) ;
pm2_WR ( par , PM2R_RD_CURSOR_COLOR_ADDRESS , 1 ) ;
pm2_WR ( par , PM2R_RD_CURSOR_COLOR_DATA ,
info - > cmap . red [ bg_idx ] > > 8 ) ;
pm2_WR ( par , PM2R_RD_CURSOR_COLOR_DATA ,
info - > cmap . green [ bg_idx ] > > 8 ) ;
pm2_WR ( par , PM2R_RD_CURSOR_COLOR_DATA ,
info - > cmap . blue [ bg_idx ] > > 8 ) ;
pm2_WR ( par , PM2R_RD_CURSOR_COLOR_DATA ,
info - > cmap . red [ fg_idx ] > > 8 ) ;
pm2_WR ( par , PM2R_RD_CURSOR_COLOR_DATA ,
info - > cmap . green [ fg_idx ] > > 8 ) ;
pm2_WR ( par , PM2R_RD_CURSOR_COLOR_DATA ,
info - > cmap . blue [ fg_idx ] > > 8 ) ;
}
if ( cursor - > set & ( FB_CUR_SETSHAPE | FB_CUR_SETIMAGE ) ) {
u8 * bitmap = ( u8 * ) cursor - > image . data ;
u8 * mask = ( u8 * ) cursor - > mask ;
int i ;
WAIT_FIFO ( par , 1 ) ;
pm2_WR ( par , PM2R_RD_PALETTE_WRITE_ADDRESS , 0 ) ;
for ( i = 0 ; i < cursor - > image . height ; i + + ) {
int j = ( cursor - > image . width + 7 ) > > 3 ;
int k = 8 - j ;
WAIT_FIFO ( par , 8 ) ;
for ( ; j > 0 ; j - - ) {
u8 data = * bitmap ^ * mask ;
if ( cursor - > rop = = ROP_COPY )
data = * mask & * bitmap ;
/* bitmap data */
pm2_WR ( par , PM2R_RD_CURSOR_DATA , data ) ;
bitmap + + ;
mask + + ;
}
for ( ; k > 0 ; k - - )
pm2_WR ( par , PM2R_RD_CURSOR_DATA , 0 ) ;
}
for ( ; i < 64 ; i + + ) {
int j = 8 ;
WAIT_FIFO ( par , 8 ) ;
while ( j - - > 0 )
pm2_WR ( par , PM2R_RD_CURSOR_DATA , 0 ) ;
}
mask = ( u8 * ) cursor - > mask ;
for ( i = 0 ; i < cursor - > image . height ; i + + ) {
int j = ( cursor - > image . width + 7 ) > > 3 ;
int k = 8 - j ;
WAIT_FIFO ( par , 8 ) ;
for ( ; j > 0 ; j - - ) {
/* mask */
pm2_WR ( par , PM2R_RD_CURSOR_DATA , * mask ) ;
mask + + ;
}
for ( ; k > 0 ; k - - )
pm2_WR ( par , PM2R_RD_CURSOR_DATA , 0 ) ;
}
for ( ; i < 64 ; i + + ) {
int j = 8 ;
WAIT_FIFO ( par , 8 ) ;
while ( j - - > 0 )
pm2_WR ( par , PM2R_RD_CURSOR_DATA , 0 ) ;
}
}
return 0 ;
2007-10-16 12:28:53 +04:00
}
2005-04-17 02:20:36 +04:00
/* ------------ Hardware Independent Functions ------------ */
/*
* Frame buffer operations
*/
static struct fb_ops pm2fb_ops = {
. owner = THIS_MODULE ,
. fb_check_var = pm2fb_check_var ,
. fb_set_par = pm2fb_set_par ,
. fb_setcolreg = pm2fb_setcolreg ,
. fb_blank = pm2fb_blank ,
. fb_pan_display = pm2fb_pan_display ,
2007-05-08 11:40:02 +04:00
. fb_fillrect = pm2fb_fillrect ,
. fb_copyarea = pm2fb_copyarea ,
2007-10-16 12:28:34 +04:00
. fb_imageblit = pm2fb_imageblit ,
2007-05-11 09:23:29 +04:00
. fb_sync = pm2fb_sync ,
2007-10-16 12:28:53 +04:00
. fb_cursor = pm2fb_cursor ,
2005-04-17 02:20:36 +04:00
} ;
/*
* PCI stuff
*/
/**
* Device initialisation
*
* Initialise and allocate resource for PCI device .
*
* @ param pdev PCI device .
* @ param id PCI device ID .
*/
static int __devinit pm2fb_probe ( struct pci_dev * pdev ,
const struct pci_device_id * id )
{
struct pm2fb_par * default_par ;
struct fb_info * info ;
2007-10-16 12:28:50 +04:00
int err ;
int retval = - ENXIO ;
2005-04-17 02:20:36 +04:00
err = pci_enable_device ( pdev ) ;
2007-10-16 12:28:34 +04:00
if ( err ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_WARNING " pm2fb: Can't enable pdev: %d \n " , err ) ;
return err ;
}
2006-01-10 07:53:10 +03:00
info = framebuffer_alloc ( sizeof ( struct pm2fb_par ) , & pdev - > dev ) ;
2007-10-16 12:28:34 +04:00
if ( ! info )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2006-01-10 07:53:10 +03:00
default_par = info - > par ;
2005-04-17 02:20:36 +04:00
switch ( pdev - > device ) {
case PCI_DEVICE_ID_TI_TVP4020 :
strcpy ( pm2fb_fix . id , " TVP4020 " ) ;
default_par - > type = PM2_TYPE_PERMEDIA2 ;
break ;
case PCI_DEVICE_ID_3DLABS_PERMEDIA2 :
strcpy ( pm2fb_fix . id , " Permedia2 " ) ;
default_par - > type = PM2_TYPE_PERMEDIA2 ;
break ;
case PCI_DEVICE_ID_3DLABS_PERMEDIA2V :
strcpy ( pm2fb_fix . id , " Permedia2v " ) ;
default_par - > type = PM2_TYPE_PERMEDIA2V ;
break ;
}
pm2fb_fix . mmio_start = pci_resource_start ( pdev , 0 ) ;
pm2fb_fix . mmio_len = PM2_REGS_SIZE ;
# if defined(__BIG_ENDIAN)
/*
* PM2 has a 64 k register file , mapped twice in 128 k . Lower
* map is little - endian , upper map is big - endian .
*/
pm2fb_fix . mmio_start + = PM2_REGS_SIZE ;
DPRINTK ( " Adjusting register base for big-endian. \n " ) ;
# endif
DPRINTK ( " Register base at 0x%lx \n " , pm2fb_fix . mmio_start ) ;
2007-07-17 15:05:31 +04:00
2005-04-17 02:20:36 +04:00
/* Registers - request region and map it. */
2007-10-16 12:28:34 +04:00
if ( ! request_mem_region ( pm2fb_fix . mmio_start , pm2fb_fix . mmio_len ,
" pm2fb regbase " ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_WARNING " pm2fb: Can't reserve regbase. \n " ) ;
goto err_exit_neither ;
}
default_par - > v_regs =
ioremap_nocache ( pm2fb_fix . mmio_start , pm2fb_fix . mmio_len ) ;
2007-10-16 12:28:34 +04:00
if ( ! default_par - > v_regs ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_WARNING " pm2fb: Can't remap %s register area. \n " ,
pm2fb_fix . id ) ;
release_mem_region ( pm2fb_fix . mmio_start , pm2fb_fix . mmio_len ) ;
goto err_exit_neither ;
}
/* Stash away memory register info for use when we reset the board */
default_par - > mem_control = pm2_RD ( default_par , PM2R_MEM_CONTROL ) ;
default_par - > boot_address = pm2_RD ( default_par , PM2R_BOOT_ADDRESS ) ;
default_par - > mem_config = pm2_RD ( default_par , PM2R_MEM_CONFIG ) ;
DPRINTK ( " MemControl 0x%x BootAddress 0x%x MemConfig 0x%x \n " ,
default_par - > mem_control , default_par - > boot_address ,
default_par - > mem_config ) ;
2007-10-16 12:28:34 +04:00
if ( default_par - > mem_control = = 0 & &
2005-11-07 12:00:42 +03:00
default_par - > boot_address = = 0x31 & &
2007-05-08 11:39:30 +04:00
default_par - > mem_config = = 0x259fffff ) {
2007-05-08 11:39:57 +04:00
default_par - > memclock = CVPPC_MEMCLOCK ;
2007-10-16 12:28:34 +04:00
default_par - > mem_control = 0 ;
default_par - > boot_address = 0x20 ;
default_par - > mem_config = 0xe6002021 ;
2007-05-08 11:39:30 +04:00
if ( pdev - > subsystem_vendor = = 0x1048 & &
pdev - > subsystem_device = = 0x0a31 ) {
2007-10-16 12:28:50 +04:00
DPRINTK ( " subsystem_vendor: %04x, "
" subsystem_device: %04x \n " ,
2007-05-08 11:39:30 +04:00
pdev - > subsystem_vendor , pdev - > subsystem_device ) ;
2007-10-16 12:28:50 +04:00
DPRINTK ( " We have not been initialized by VGA BIOS and "
" are running on an Elsa Winner 2000 Office \n " ) ;
2007-05-08 11:39:30 +04:00
DPRINTK ( " Initializing card timings manually... \n " ) ;
2007-10-16 12:28:36 +04:00
default_par - > memclock = 100000 ;
2007-05-08 11:39:30 +04:00
}
if ( pdev - > subsystem_vendor = = 0x3d3d & &
pdev - > subsystem_device = = 0x0100 ) {
2007-10-16 12:28:50 +04:00
DPRINTK ( " subsystem_vendor: %04x, "
" subsystem_device: %04x \n " ,
2007-05-08 11:39:30 +04:00
pdev - > subsystem_vendor , pdev - > subsystem_device ) ;
2007-10-16 12:28:50 +04:00
DPRINTK ( " We have not been initialized by VGA BIOS and "
" are running on an 3dlabs reference board \n " ) ;
2007-05-08 11:39:30 +04:00
DPRINTK ( " Initializing card timings manually... \n " ) ;
2007-10-16 12:28:34 +04:00
default_par - > memclock = 74894 ;
2007-05-08 11:39:30 +04:00
}
2005-11-07 12:00:42 +03:00
}
2005-04-17 02:20:36 +04:00
/* Now work out how big lfb is going to be. */
2007-10-16 12:28:50 +04:00
switch ( default_par - > mem_config & PM2F_MEM_CONFIG_RAM_MASK ) {
2005-04-17 02:20:36 +04:00
case PM2F_MEM_BANKS_1 :
2007-10-16 12:28:34 +04:00
pm2fb_fix . smem_len = 0x200000 ;
2005-04-17 02:20:36 +04:00
break ;
case PM2F_MEM_BANKS_2 :
2007-10-16 12:28:34 +04:00
pm2fb_fix . smem_len = 0x400000 ;
2005-04-17 02:20:36 +04:00
break ;
case PM2F_MEM_BANKS_3 :
2007-10-16 12:28:34 +04:00
pm2fb_fix . smem_len = 0x600000 ;
2005-04-17 02:20:36 +04:00
break ;
case PM2F_MEM_BANKS_4 :
2007-10-16 12:28:34 +04:00
pm2fb_fix . smem_len = 0x800000 ;
2005-04-17 02:20:36 +04:00
break ;
}
pm2fb_fix . smem_start = pci_resource_start ( pdev , 1 ) ;
/* Linear frame buffer - request region and map it. */
2007-10-16 12:28:34 +04:00
if ( ! request_mem_region ( pm2fb_fix . smem_start , pm2fb_fix . smem_len ,
" pm2fb smem " ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_WARNING " pm2fb: Can't reserve smem. \n " ) ;
goto err_exit_mmio ;
}
2007-05-08 11:40:12 +04:00
info - > screen_base =
2005-04-17 02:20:36 +04:00
ioremap_nocache ( pm2fb_fix . smem_start , pm2fb_fix . smem_len ) ;
2007-10-16 12:28:34 +04:00
if ( ! info - > screen_base ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_WARNING " pm2fb: Can't ioremap smem area. \n " ) ;
release_mem_region ( pm2fb_fix . smem_start , pm2fb_fix . smem_len ) ;
goto err_exit_mmio ;
}
2007-10-16 12:28:33 +04:00
# ifdef CONFIG_MTRR
default_par - > mtrr_handle = - 1 ;
if ( ! nomtrr )
default_par - > mtrr_handle =
mtrr_add ( pm2fb_fix . smem_start ,
pm2fb_fix . smem_len ,
MTRR_TYPE_WRCOMB , 1 ) ;
# endif
2005-04-17 02:20:36 +04:00
info - > fbops = & pm2fb_ops ;
2007-07-17 15:05:31 +04:00
info - > fix = pm2fb_fix ;
2006-01-10 07:53:10 +03:00
info - > pseudo_palette = default_par - > palette ;
2005-04-17 02:20:36 +04:00
info - > flags = FBINFO_DEFAULT |
2007-07-17 15:05:31 +04:00
FBINFO_HWACCEL_YPAN |
FBINFO_HWACCEL_COPYAREA |
2007-10-16 12:28:34 +04:00
FBINFO_HWACCEL_IMAGEBLIT |
2007-07-17 15:05:31 +04:00
FBINFO_HWACCEL_FILLRECT ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:28:34 +04:00
info - > pixmap . addr = kmalloc ( PM2_PIXMAP_SIZE , GFP_KERNEL ) ;
if ( ! info - > pixmap . addr ) {
2007-10-16 12:28:50 +04:00
retval = - ENOMEM ;
2007-10-16 12:28:34 +04:00
goto err_exit_pixmap ;
}
info - > pixmap . size = PM2_PIXMAP_SIZE ;
info - > pixmap . buf_align = 4 ;
info - > pixmap . scan_align = 4 ;
info - > pixmap . access_align = 32 ;
info - > pixmap . flags = FB_PIXMAP_SYSTEM ;
2007-10-16 12:28:33 +04:00
if ( noaccel ) {
2007-10-16 12:28:34 +04:00
printk ( KERN_DEBUG " disabling acceleration \n " ) ;
info - > flags | = FBINFO_HWACCEL_DISABLED ;
info - > pixmap . scan_align = 1 ;
2007-10-16 12:28:33 +04:00
}
2008-04-28 13:15:05 +04:00
if ( ! mode_option )
mode_option = " 640x480@60 " ;
2007-07-17 15:05:31 +04:00
2008-04-28 13:15:05 +04:00
err = fb_find_mode ( & info - > var , info , mode_option , NULL , 0 , NULL , 8 ) ;
2005-04-17 02:20:36 +04:00
if ( ! err | | err = = 4 )
info - > var = pm2fb_var ;
2008-04-28 13:14:51 +04:00
retval = fb_alloc_cmap ( & info - > cmap , 256 , 0 ) ;
if ( retval < 0 )
2007-05-08 11:40:16 +04:00
goto err_exit_both ;
2005-04-17 02:20:36 +04:00
2008-04-28 13:14:51 +04:00
retval = register_framebuffer ( info ) ;
if ( retval < 0 )
2007-05-08 11:40:16 +04:00
goto err_exit_all ;
2005-04-17 02:20:36 +04:00
printk ( KERN_INFO " fb%d: %s frame buffer device, memory = %dK. \n " ,
2007-05-08 11:40:12 +04:00
info - > node , info - > fix . id , pm2fb_fix . smem_len / 1024 ) ;
2005-04-17 02:20:36 +04:00
/*
* Our driver data
*/
pci_set_drvdata ( pdev , info ) ;
return 0 ;
err_exit_all :
2007-07-17 15:05:31 +04:00
fb_dealloc_cmap ( & info - > cmap ) ;
err_exit_both :
2007-10-16 12:28:34 +04:00
kfree ( info - > pixmap . addr ) ;
err_exit_pixmap :
2005-04-17 02:20:36 +04:00
iounmap ( info - > screen_base ) ;
release_mem_region ( pm2fb_fix . smem_start , pm2fb_fix . smem_len ) ;
err_exit_mmio :
iounmap ( default_par - > v_regs ) ;
release_mem_region ( pm2fb_fix . mmio_start , pm2fb_fix . mmio_len ) ;
err_exit_neither :
framebuffer_release ( info ) ;
2007-10-16 12:28:50 +04:00
return retval ;
2005-04-17 02:20:36 +04:00
}
/**
* Device removal .
*
* Release all device resources .
*
* @ param pdev PCI device to clean up .
*/
static void __devexit pm2fb_remove ( struct pci_dev * pdev )
{
2007-10-16 12:28:50 +04:00
struct fb_info * info = pci_get_drvdata ( pdev ) ;
struct fb_fix_screeninfo * fix = & info - > fix ;
2005-04-17 02:20:36 +04:00
struct pm2fb_par * par = info - > par ;
unregister_framebuffer ( info ) ;
2007-07-17 15:05:31 +04:00
2007-10-16 12:28:33 +04:00
# ifdef CONFIG_MTRR
if ( par - > mtrr_handle > = 0 )
mtrr_del ( par - > mtrr_handle , info - > fix . smem_start ,
info - > fix . smem_len ) ;
# endif /* CONFIG_MTRR */
2005-04-17 02:20:36 +04:00
iounmap ( info - > screen_base ) ;
release_mem_region ( fix - > smem_start , fix - > smem_len ) ;
iounmap ( par - > v_regs ) ;
release_mem_region ( fix - > mmio_start , fix - > mmio_len ) ;
pci_set_drvdata ( pdev , NULL ) ;
2008-08-21 01:09:11 +04:00
fb_dealloc_cmap ( & info - > cmap ) ;
2007-10-16 12:28:50 +04:00
kfree ( info - > pixmap . addr ) ;
2009-06-17 02:34:36 +04:00
framebuffer_release ( info ) ;
2005-04-17 02:20:36 +04:00
}
static struct pci_device_id pm2fb_id_table [ ] = {
{ PCI_VENDOR_ID_TI , PCI_DEVICE_ID_TI_TVP4020 ,
2007-10-16 12:28:36 +04:00
PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
2005-04-17 02:20:36 +04:00
{ PCI_VENDOR_ID_3DLABS , PCI_DEVICE_ID_3DLABS_PERMEDIA2 ,
2007-10-16 12:28:36 +04:00
PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
2007-05-08 11:39:30 +04:00
{ PCI_VENDOR_ID_3DLABS , PCI_DEVICE_ID_3DLABS_PERMEDIA2V ,
2007-10-16 12:28:36 +04:00
PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
2005-04-17 02:20:36 +04:00
{ 0 , }
} ;
static struct pci_driver pm2fb_driver = {
. name = " pm2fb " ,
2007-07-17 15:05:31 +04:00
. id_table = pm2fb_id_table ,
. probe = pm2fb_probe ,
. remove = __devexit_p ( pm2fb_remove ) ,
2005-04-17 02:20:36 +04:00
} ;
MODULE_DEVICE_TABLE ( pci , pm2fb_id_table ) ;
# ifndef MODULE
/**
* Parse user speficied options .
*
* This is , comma - separated options following ` video = pm2fb : ' .
*/
static int __init pm2fb_setup ( char * options )
{
2007-10-16 12:28:50 +04:00
char * this_opt ;
2005-04-17 02:20:36 +04:00
if ( ! options | | ! * options )
return 0 ;
2007-07-17 15:05:31 +04:00
while ( ( this_opt = strsep ( & options , " , " ) ) ! = NULL ) {
2005-04-17 02:20:36 +04:00
if ( ! * this_opt )
continue ;
2007-10-16 12:28:50 +04:00
if ( ! strcmp ( this_opt , " lowhsync " ) )
2005-04-17 02:20:36 +04:00
lowhsync = 1 ;
2007-10-16 12:28:50 +04:00
else if ( ! strcmp ( this_opt , " lowvsync " ) )
2005-04-17 02:20:36 +04:00
lowvsync = 1 ;
2007-10-16 12:28:53 +04:00
else if ( ! strncmp ( this_opt , " hwcursor= " , 9 ) )
hwcursor = simple_strtoul ( this_opt + 9 , NULL , 0 ) ;
2007-10-16 12:28:33 +04:00
# ifdef CONFIG_MTRR
2007-10-16 12:28:50 +04:00
else if ( ! strncmp ( this_opt , " nomtrr " , 6 ) )
2007-10-16 12:28:33 +04:00
nomtrr = 1 ;
# endif
2007-10-16 12:28:50 +04:00
else if ( ! strncmp ( this_opt , " noaccel " , 7 ) )
2007-10-16 12:28:33 +04:00
noaccel = 1 ;
2007-10-16 12:28:50 +04:00
else
2008-04-28 13:15:05 +04:00
mode_option = this_opt ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
# endif
static int __init pm2fb_init ( void )
{
# ifndef MODULE
char * option = NULL ;
if ( fb_get_options ( " pm2fb " , & option ) )
return - ENODEV ;
pm2fb_setup ( option ) ;
# endif
return pci_register_driver ( & pm2fb_driver ) ;
}
module_init ( pm2fb_init ) ;
# ifdef MODULE
/*
* Cleanup
*/
static void __exit pm2fb_exit ( void )
{
pci_unregister_driver ( & pm2fb_driver ) ;
}
# endif
# ifdef MODULE
module_exit ( pm2fb_exit ) ;
2008-04-28 13:15:05 +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 ( lowhsync , bool , 0 ) ;
MODULE_PARM_DESC ( lowhsync , " Force horizontal sync low regardless of mode " ) ;
module_param ( lowvsync , bool , 0 ) ;
MODULE_PARM_DESC ( lowvsync , " Force vertical sync low regardless of mode " ) ;
2007-10-16 12:28:33 +04:00
module_param ( noaccel , bool , 0 ) ;
MODULE_PARM_DESC ( noaccel , " Disable acceleration " ) ;
2007-10-16 12:28:53 +04:00
module_param ( hwcursor , int , 0644 ) ;
MODULE_PARM_DESC ( hwcursor , " Enable hardware cursor "
2007-10-16 12:29:16 +04:00
" (1=enable, 0=disable, default=1) " ) ;
2007-10-16 12:28:33 +04:00
# ifdef CONFIG_MTRR
module_param ( nomtrr , bool , 0 ) ;
MODULE_PARM_DESC ( nomtrr , " Disable MTRR support (0 or 1=disabled) (default=0) " ) ;
# endif
2005-04-17 02:20:36 +04:00
MODULE_AUTHOR ( " Jim Hague <jim.hague@acm.org> " ) ;
MODULE_DESCRIPTION ( " Permedia2 framebuffer device driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
# endif