2005-04-17 02:20:36 +04:00
/*
* linux / drivers / video / pm3fb . c - - 3 DLabs Permedia3 frame buffer device
2007-05-11 09:23:25 +04:00
*
* Copyright ( C ) 2001 Romain Dolbeau < romain @ dolbeau . org > .
*
* Ported to 2.6 kernel on 1 May 2007 by Krzysztof Helt < krzysztof . h1 @ wp . pl >
* based on pm2fb . c
*
2005-04-17 02:20:36 +04:00
* Based on code written by :
2007-05-11 09:23:25 +04:00
* Sven Luther , < luther @ dpt - info . u - strasbg . fr >
* Alan Hourihane , < alanh @ fairlite . demon . co . uk >
* Russell King , < rmk @ arm . linux . org . uk >
2005-04-17 02:20:36 +04:00
* Based on linux / drivers / video / skeletonfb . c :
* Copyright ( C ) 1997 Geert Uytterhoeven
* Based on linux / driver / video / pm2fb . c :
2007-05-11 09:23:25 +04:00
* Copyright ( C ) 1998 - 1999 Ilario Nardinocchi ( nardinoc @ CS . UniBO . IT )
* Copyright ( C ) 1999 Jakub Jelinek ( jakub @ redhat . com )
2005-04-17 02:20:36 +04:00
*
* 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 .
*
*/
# include <linux/module.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
2007-05-11 09:23:25 +04:00
# include <video/pm3fb.h>
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
# if !defined(CONFIG_PCI)
# error "Only generic PCI cards supported."
2005-04-17 02:20:36 +04:00
# endif
2007-05-11 09:23:25 +04:00
# undef PM3FB_MASTER_DEBUG
# ifdef PM3FB_MASTER_DEBUG
2007-10-16 12:28:51 +04:00
# define DPRINTK(a, b...) \
2008-04-28 13:15:47 +04:00
printk ( KERN_DEBUG " pm3fb: %s: " a , __func__ , # # b )
2007-05-11 09:23:25 +04:00
# else
2007-10-16 12:28:51 +04:00
# define DPRINTK(a, b...)
2005-04-17 02:20:36 +04:00
# endif
2007-10-16 12:28:31 +04:00
# define PM3_PIXMAP_SIZE (2048 * 4)
2007-05-11 09:23:25 +04:00
/*
* Driver data
*/
2007-10-16 12:28:54 +04:00
static int hwcursor = 1 ;
2007-05-11 09:23:25 +04:00
static char * mode_option __devinitdata ;
2007-10-16 12:28:51 +04:00
static int noaccel __devinitdata ;
2007-10-16 12:28:33 +04:00
/* mtrr option */
# ifdef CONFIG_MTRR
2007-10-16 12:28:51 +04:00
static int nomtrr __devinitdata ;
2007-10-16 12:28:33 +04:00
# endif
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
/*
* This structure defines the hardware state of the graphics card . Normally
* you place this in a header file in linux / include / video . This file usually
* also includes register information . That allows other driver subsystems
* and userland applications the ability to use the same header file to
* avoid duplicate work and easy porting of software .
*/
struct pm3_par {
unsigned char __iomem * v_regs ; /* virtual address of p_regs */
u32 video ; /* video flags before blanking */
2007-10-16 12:28:51 +04:00
u32 base ; /* screen base in 128 bits unit */
2007-05-24 00:57:48 +04:00
u32 palette [ 16 ] ;
2007-10-16 12:28:33 +04:00
int mtrr_handle ;
2005-04-17 02:20:36 +04:00
} ;
2007-05-11 09:23:25 +04:00
/*
* Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
* if we don ' t use modedb . If we do use modedb see pm3fb_init how to use it
* to get a fb_var_screeninfo . Otherwise define a default var as well .
*/
static struct fb_fix_screeninfo pm3fb_fix __devinitdata = {
. id = " Permedia3 " ,
. type = FB_TYPE_PACKED_PIXELS ,
. visual = FB_VISUAL_PSEUDOCOLOR ,
. xpanstep = 1 ,
. ypanstep = 1 ,
. ywrapstep = 0 ,
2007-07-17 15:05:46 +04:00
. accel = FB_ACCEL_3DLABS_PERMEDIA3 ,
2005-04-17 02:20:36 +04:00
} ;
2007-05-11 09:23:25 +04:00
/*
* Utility functions
*/
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
static inline u32 PM3_READ_REG ( struct pm3_par * par , s32 off )
{
return fb_readl ( par - > v_regs + off ) ;
}
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
static inline void PM3_WRITE_REG ( struct pm3_par * par , s32 off , u32 v )
{
fb_writel ( v , par - > v_regs + off ) ;
}
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
static inline void PM3_WAIT ( struct pm3_par * par , u32 n )
{
2007-10-16 12:29:27 +04:00
while ( PM3_READ_REG ( par , PM3InFIFOSpace ) < n )
cpu_relax ( ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
static inline void PM3_WRITE_DAC_REG ( struct pm3_par * par , unsigned r , u8 v )
2005-04-17 02:20:36 +04:00
{
2007-05-24 00:57:48 +04:00
PM3_WAIT ( par , 3 ) ;
PM3_WRITE_REG ( par , PM3RD_IndexHigh , ( r > > 8 ) & 0xff ) ;
PM3_WRITE_REG ( par , PM3RD_IndexLow , r & 0xff ) ;
2007-05-11 09:23:25 +04:00
wmb ( ) ;
PM3_WRITE_REG ( par , PM3RD_IndexedData , v ) ;
2007-05-24 00:57:48 +04:00
wmb ( ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
static inline void pm3fb_set_color ( struct pm3_par * par , unsigned char regno ,
unsigned char r , unsigned char g , unsigned char b )
2005-04-17 02:20:36 +04:00
{
2007-05-24 00:57:48 +04:00
PM3_WAIT ( par , 4 ) ;
PM3_WRITE_REG ( par , PM3RD_PaletteWriteAddress , regno ) ;
wmb ( ) ;
PM3_WRITE_REG ( par , PM3RD_PaletteData , r ) ;
wmb ( ) ;
PM3_WRITE_REG ( par , PM3RD_PaletteData , g ) ;
wmb ( ) ;
PM3_WRITE_REG ( par , PM3RD_PaletteData , b ) ;
wmb ( ) ;
2007-05-11 09:23:25 +04:00
}
static void pm3fb_clear_colormap ( struct pm3_par * par ,
unsigned char r , unsigned char g , unsigned char b )
{
int i ;
2007-05-24 00:57:48 +04:00
for ( i = 0 ; i < 256 ; i + + )
2007-05-11 09:23:25 +04:00
pm3fb_set_color ( par , i , r , g , b ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:28:32 +04:00
/* Calculating various clock parameters */
2007-05-11 09:23:25 +04:00
static void pm3fb_calculate_clock ( unsigned long reqclock ,
unsigned char * prescale ,
unsigned char * feedback ,
unsigned char * postscale )
2005-04-17 02:20:36 +04:00
{
int f , pre , post ;
unsigned long freq ;
long freqerr = 1000 ;
2007-05-11 09:23:25 +04:00
long currerr ;
2005-04-17 02:20:36 +04:00
for ( f = 1 ; f < 256 ; f + + ) {
for ( pre = 1 ; pre < 256 ; pre + + ) {
for ( post = 0 ; post < 5 ; post + + ) {
2007-05-11 09:23:25 +04:00
freq = ( ( 2 * PM3_REF_CLOCK * f ) > > post ) / pre ;
currerr = ( reqclock > freq )
? reqclock - freq
: freq - reqclock ;
if ( currerr < freqerr ) {
freqerr = currerr ;
2005-04-17 02:20:36 +04:00
* feedback = f ;
* prescale = pre ;
* postscale = post ;
}
}
}
}
}
2007-05-24 00:57:48 +04:00
static inline int pm3fb_depth ( const struct fb_var_screeninfo * var )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:28:32 +04:00
if ( var - > bits_per_pixel = = 16 )
2007-05-24 00:57:48 +04:00
return var - > red . length + var - > green . length
+ var - > blue . length ;
return var - > bits_per_pixel ;
}
static inline int pm3fb_shift_bpp ( unsigned bpp , int v )
{
switch ( bpp ) {
2005-04-17 02:20:36 +04:00
case 8 :
return ( v > > 4 ) ;
case 16 :
return ( v > > 3 ) ;
case 32 :
return ( v > > 2 ) ;
}
2007-05-24 00:57:48 +04:00
DPRINTK ( " Unsupported depth %u \n " , bpp ) ;
2007-05-11 09:23:25 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-07-17 15:05:46 +04:00
/* acceleration */
static int pm3fb_sync ( struct fb_info * info )
{
struct pm3_par * par = info - > par ;
PM3_WAIT ( par , 2 ) ;
PM3_WRITE_REG ( par , PM3FilterMode , PM3FilterModeSync ) ;
PM3_WRITE_REG ( par , PM3Sync , 0 ) ;
mb ( ) ;
do {
2007-10-16 12:29:27 +04:00
while ( ( PM3_READ_REG ( par , PM3OutFIFOWords ) ) = = 0 )
cpu_relax ( ) ;
2007-07-17 15:05:46 +04:00
} while ( ( PM3_READ_REG ( par , PM3OutputFifo ) ) ! = PM3Sync_Tag ) ;
return 0 ;
}
static void pm3fb_init_engine ( struct fb_info * info )
{
struct pm3_par * par = info - > par ;
const u32 width = ( info - > var . xres_virtual + 7 ) & ~ 7 ;
PM3_WAIT ( par , 50 ) ;
PM3_WRITE_REG ( par , PM3FilterMode , PM3FilterModeSync ) ;
PM3_WRITE_REG ( par , PM3StatisticMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3DeltaMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3RasterizerMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3ScissorMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3LineStippleMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3AreaStippleMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3GIDMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3DepthMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3StencilMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3StencilData , 0x0 ) ;
PM3_WRITE_REG ( par , PM3ColorDDAMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3TextureCoordMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3TextureIndexMode0 , 0x0 ) ;
PM3_WRITE_REG ( par , PM3TextureIndexMode1 , 0x0 ) ;
PM3_WRITE_REG ( par , PM3TextureReadMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3LUTMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3TextureFilterMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3TextureCompositeMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3TextureApplicationMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3TextureCompositeColorMode1 , 0x0 ) ;
PM3_WRITE_REG ( par , PM3TextureCompositeAlphaMode1 , 0x0 ) ;
PM3_WRITE_REG ( par , PM3TextureCompositeColorMode0 , 0x0 ) ;
PM3_WRITE_REG ( par , PM3TextureCompositeAlphaMode0 , 0x0 ) ;
PM3_WRITE_REG ( par , PM3FogMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3ChromaTestMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3AlphaTestMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3AntialiasMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3YUVMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3AlphaBlendColorMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3AlphaBlendAlphaMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3DitherMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3LogicalOpMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3RouterMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3Window , 0x0 ) ;
PM3_WRITE_REG ( par , PM3Config2D , 0x0 ) ;
PM3_WRITE_REG ( par , PM3SpanColorMask , 0xffffffff ) ;
PM3_WRITE_REG ( par , PM3XBias , 0x0 ) ;
PM3_WRITE_REG ( par , PM3YBias , 0x0 ) ;
PM3_WRITE_REG ( par , PM3DeltaControl , 0x0 ) ;
PM3_WRITE_REG ( par , PM3BitMaskPattern , 0xffffffff ) ;
PM3_WRITE_REG ( par , PM3FBDestReadEnables ,
PM3FBDestReadEnables_E ( 0xff ) |
PM3FBDestReadEnables_R ( 0xff ) |
PM3FBDestReadEnables_ReferenceAlpha ( 0xff ) ) ;
PM3_WRITE_REG ( par , PM3FBDestReadBufferAddr0 , 0x0 ) ;
PM3_WRITE_REG ( par , PM3FBDestReadBufferOffset0 , 0x0 ) ;
PM3_WRITE_REG ( par , PM3FBDestReadBufferWidth0 ,
PM3FBDestReadBufferWidth_Width ( width ) ) ;
PM3_WRITE_REG ( par , PM3FBDestReadMode ,
PM3FBDestReadMode_ReadEnable |
PM3FBDestReadMode_Enable0 ) ;
PM3_WRITE_REG ( par , PM3FBSourceReadBufferAddr , 0x0 ) ;
PM3_WRITE_REG ( par , PM3FBSourceReadBufferOffset , 0x0 ) ;
PM3_WRITE_REG ( par , PM3FBSourceReadBufferWidth ,
PM3FBSourceReadBufferWidth_Width ( width ) ) ;
PM3_WRITE_REG ( par , PM3FBSourceReadMode ,
PM3FBSourceReadMode_Blocking |
PM3FBSourceReadMode_ReadEnable ) ;
PM3_WAIT ( par , 2 ) ;
{
2007-10-16 12:28:29 +04:00
/* invert bits in bitmask */
unsigned long rm = 1 | ( 3 < < 7 ) ;
2007-07-17 15:05:46 +04:00
switch ( info - > var . bits_per_pixel ) {
case 8 :
PM3_WRITE_REG ( par , PM3PixelSize ,
PM3PixelSize_GLOBAL_8BIT ) ;
2007-10-16 12:28:29 +04:00
# ifdef __BIG_ENDIAN
rm | = 3 < < 15 ;
# endif
2007-07-17 15:05:46 +04:00
break ;
case 16 :
PM3_WRITE_REG ( par , PM3PixelSize ,
PM3PixelSize_GLOBAL_16BIT ) ;
2007-10-16 12:28:29 +04:00
# ifdef __BIG_ENDIAN
rm | = 2 < < 15 ;
# endif
2007-07-17 15:05:46 +04:00
break ;
case 32 :
PM3_WRITE_REG ( par , PM3PixelSize ,
PM3PixelSize_GLOBAL_32BIT ) ;
break ;
default :
DPRINTK ( 1 , " Unsupported depth %d \n " ,
info - > var . bits_per_pixel ) ;
break ;
}
PM3_WRITE_REG ( par , PM3RasterizerMode , rm ) ;
}
PM3_WAIT ( par , 20 ) ;
PM3_WRITE_REG ( par , PM3FBSoftwareWriteMask , 0xffffffff ) ;
PM3_WRITE_REG ( par , PM3FBHardwareWriteMask , 0xffffffff ) ;
PM3_WRITE_REG ( par , PM3FBWriteMode ,
PM3FBWriteMode_WriteEnable |
PM3FBWriteMode_OpaqueSpan |
PM3FBWriteMode_Enable0 ) ;
PM3_WRITE_REG ( par , PM3FBWriteBufferAddr0 , 0x0 ) ;
PM3_WRITE_REG ( par , PM3FBWriteBufferOffset0 , 0x0 ) ;
PM3_WRITE_REG ( par , PM3FBWriteBufferWidth0 ,
PM3FBWriteBufferWidth_Width ( width ) ) ;
PM3_WRITE_REG ( par , PM3SizeOfFramebuffer , 0x0 ) ;
{
/* size in lines of FB */
unsigned long sofb = info - > screen_size /
info - > fix . line_length ;
if ( sofb > 4095 )
PM3_WRITE_REG ( par , PM3SizeOfFramebuffer , 4095 ) ;
else
PM3_WRITE_REG ( par , PM3SizeOfFramebuffer , sofb ) ;
switch ( info - > var . bits_per_pixel ) {
case 8 :
PM3_WRITE_REG ( par , PM3DitherMode ,
( 1 < < 10 ) | ( 2 < < 3 ) ) ;
break ;
case 16 :
PM3_WRITE_REG ( par , PM3DitherMode ,
( 1 < < 10 ) | ( 1 < < 3 ) ) ;
break ;
case 32 :
PM3_WRITE_REG ( par , PM3DitherMode ,
( 1 < < 10 ) | ( 0 < < 3 ) ) ;
break ;
default :
DPRINTK ( 1 , " Unsupported depth %d \n " ,
info - > current_par - > depth ) ;
break ;
}
}
PM3_WRITE_REG ( par , PM3dXDom , 0x0 ) ;
PM3_WRITE_REG ( par , PM3dXSub , 0x0 ) ;
2007-10-16 12:28:32 +04:00
PM3_WRITE_REG ( par , PM3dY , 1 < < 16 ) ;
2007-07-17 15:05:46 +04:00
PM3_WRITE_REG ( par , PM3StartXDom , 0x0 ) ;
PM3_WRITE_REG ( par , PM3StartXSub , 0x0 ) ;
PM3_WRITE_REG ( par , PM3StartY , 0x0 ) ;
PM3_WRITE_REG ( par , PM3Count , 0x0 ) ;
/* Disable LocalBuffer. better safe than sorry */
PM3_WRITE_REG ( par , PM3LBDestReadMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3LBDestReadEnables , 0x0 ) ;
PM3_WRITE_REG ( par , PM3LBSourceReadMode , 0x0 ) ;
PM3_WRITE_REG ( par , PM3LBWriteMode , 0x0 ) ;
pm3fb_sync ( info ) ;
}
2007-10-16 12:28:51 +04:00
static void pm3fb_fillrect ( struct fb_info * info ,
2007-07-17 15:05:46 +04:00
const struct fb_fillrect * region )
{
struct pm3_par * par = info - > par ;
struct fb_fillrect modded ;
int vxres , vyres ;
2007-10-16 12:28:32 +04:00
int rop ;
2007-07-17 15:05:46 +04:00
u32 color = ( info - > fix . visual = = FB_VISUAL_TRUECOLOR ) ?
2007-10-16 12:28:51 +04:00
( ( u32 * ) info - > pseudo_palette ) [ region - > color ] : region - > color ;
2007-07-17 15:05:46 +04:00
if ( info - > state ! = FBINFO_STATE_RUNNING )
return ;
2007-10-16 12:28:32 +04:00
if ( info - > flags & FBINFO_HWACCEL_DISABLED ) {
2007-07-17 15:05:46 +04:00
cfb_fillrect ( info , region ) ;
return ;
}
2007-10-16 12:28:32 +04:00
if ( region - > rop = = ROP_COPY )
rop = PM3Config2D_ForegroundROP ( 0x3 ) ; /* GXcopy */
else
rop = PM3Config2D_ForegroundROP ( 0x6 ) | /* GXxor */
PM3Config2D_FBDestReadEnable ;
2007-07-17 15:05:46 +04:00
vxres = info - > var . xres_virtual ;
vyres = info - > var . yres_virtual ;
memcpy ( & modded , region , sizeof ( struct fb_fillrect ) ) ;
2007-10-16 12:28:51 +04:00
if ( ! modded . width | | ! modded . height | |
modded . dx > = vxres | | modded . dy > = vyres )
2007-07-17 15:05:46 +04:00
return ;
2007-10-16 12:28:51 +04:00
if ( modded . dx + modded . width > vxres )
2007-07-17 15:05:46 +04:00
modded . width = vxres - modded . dx ;
2007-10-16 12:28:51 +04:00
if ( modded . dy + modded . height > vyres )
2007-07-17 15:05:46 +04:00
modded . height = vyres - modded . dy ;
2007-10-16 12:28:51 +04:00
if ( info - > var . bits_per_pixel = = 8 )
2007-07-17 15:05:46 +04:00
color | = color < < 8 ;
2007-10-16 12:28:51 +04:00
if ( info - > var . bits_per_pixel < = 16 )
2007-07-17 15:05:46 +04:00
color | = color < < 16 ;
PM3_WAIT ( par , 4 ) ;
2007-10-16 12:28:29 +04:00
/* ROP Ox3 is GXcopy */
2007-07-17 15:05:46 +04:00
PM3_WRITE_REG ( par , PM3Config2D ,
2007-10-16 12:28:29 +04:00
PM3Config2D_UseConstantSource |
PM3Config2D_ForegroundROPEnable |
2007-10-16 12:28:32 +04:00
rop |
2007-10-16 12:28:29 +04:00
PM3Config2D_FBWriteEnable ) ;
2007-07-17 15:05:46 +04:00
PM3_WRITE_REG ( par , PM3ForegroundColor , color ) ;
PM3_WRITE_REG ( par , PM3RectanglePosition ,
2007-10-16 12:28:32 +04:00
PM3RectanglePosition_XOffset ( modded . dx ) |
PM3RectanglePosition_YOffset ( modded . dy ) ) ;
2007-07-17 15:05:46 +04:00
PM3_WRITE_REG ( par , PM3Render2D ,
PM3Render2D_XPositive |
PM3Render2D_YPositive |
PM3Render2D_Operation_Normal |
PM3Render2D_SpanOperation |
2007-10-16 12:28:32 +04:00
PM3Render2D_Width ( modded . width ) |
PM3Render2D_Height ( modded . height ) ) ;
2007-07-17 15:05:46 +04:00
}
2007-10-16 12:28:29 +04:00
static void pm3fb_copyarea ( struct fb_info * info ,
const struct fb_copyarea * area )
{
struct pm3_par * par = info - > par ;
struct fb_copyarea modded ;
u32 vxres , vyres ;
int x_align , o_x , o_y ;
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:51 +04:00
if ( ! modded . width | | ! modded . height | |
modded . sx > = vxres | | modded . sy > = vyres | |
modded . dx > = vxres | | modded . dy > = vyres )
2007-10-16 12:28:29 +04:00
return ;
2007-10-16 12:28:51 +04:00
if ( modded . sx + modded . width > vxres )
2007-10-16 12:28:29 +04:00
modded . width = vxres - modded . sx ;
2007-10-16 12:28:51 +04:00
if ( modded . dx + modded . width > vxres )
2007-10-16 12:28:29 +04:00
modded . width = vxres - modded . dx ;
2007-10-16 12:28:51 +04:00
if ( modded . sy + modded . height > vyres )
2007-10-16 12:28:29 +04:00
modded . height = vyres - modded . sy ;
2007-10-16 12:28:51 +04:00
if ( modded . dy + modded . height > vyres )
2007-10-16 12:28:29 +04:00
modded . height = vyres - modded . dy ;
o_x = modded . sx - modded . dx ; /*(sx > dx ) ? (sx - dx) : (dx - sx); */
o_y = modded . sy - modded . dy ; /*(sy > dy ) ? (sy - dy) : (dy - sy); */
x_align = ( modded . sx & 0x1f ) ;
PM3_WAIT ( par , 6 ) ;
PM3_WRITE_REG ( par , PM3Config2D ,
PM3Config2D_UserScissorEnable |
PM3Config2D_ForegroundROPEnable |
PM3Config2D_Blocking |
2007-10-16 12:28:32 +04:00
PM3Config2D_ForegroundROP ( 0x3 ) | /* Ox3 is GXcopy */
2007-10-16 12:28:29 +04:00
PM3Config2D_FBWriteEnable ) ;
PM3_WRITE_REG ( par , PM3ScissorMinXY ,
( ( modded . dy & 0x0fff ) < < 16 ) | ( modded . dx & 0x0fff ) ) ;
PM3_WRITE_REG ( par , PM3ScissorMaxXY ,
( ( ( modded . dy + modded . height ) & 0x0fff ) < < 16 ) |
( ( modded . dx + modded . width ) & 0x0fff ) ) ;
PM3_WRITE_REG ( par , PM3FBSourceReadBufferOffset ,
PM3FBSourceReadBufferOffset_XOffset ( o_x ) |
PM3FBSourceReadBufferOffset_YOffset ( o_y ) ) ;
PM3_WRITE_REG ( par , PM3RectanglePosition ,
2007-10-16 12:28:32 +04:00
PM3RectanglePosition_XOffset ( modded . dx - x_align ) |
PM3RectanglePosition_YOffset ( modded . dy ) ) ;
2007-10-16 12:28:29 +04:00
PM3_WRITE_REG ( par , PM3Render2D ,
( ( modded . sx > modded . dx ) ? PM3Render2D_XPositive : 0 ) |
( ( modded . sy > modded . dy ) ? PM3Render2D_YPositive : 0 ) |
PM3Render2D_Operation_Normal |
PM3Render2D_SpanOperation |
PM3Render2D_FBSourceReadEnable |
2007-10-16 12:28:32 +04:00
PM3Render2D_Width ( modded . width + x_align ) |
PM3Render2D_Height ( modded . height ) ) ;
2007-10-16 12:28:29 +04:00
}
static void pm3fb_imageblit ( struct fb_info * info , const struct fb_image * image )
{
struct pm3_par * par = info - > par ;
u32 height = image - > height ;
u32 fgx , bgx ;
2007-10-16 12:28:51 +04:00
const u32 * src = ( const u32 * ) image - > data ;
2007-10-16 12:28:29 +04:00
2007-10-16 12:28:32 +04:00
if ( info - > state ! = FBINFO_STATE_RUNNING )
return ;
if ( info - > flags & FBINFO_HWACCEL_DISABLED ) {
cfb_imageblit ( info , image ) ;
return ;
}
2007-10-16 12:28:29 +04:00
switch ( info - > fix . visual ) {
2007-10-16 12:28:51 +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:29 +04:00
}
2009-01-07 01:42:33 +03:00
if ( image - > depth ! = 1 ) {
cfb_imageblit ( info , image ) ;
return ;
}
2007-10-16 12:28:51 +04:00
2007-10-16 12:28:29 +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 ;
}
2007-10-16 12:28:31 +04:00
PM3_WAIT ( par , 7 ) ;
2007-10-16 12:28:29 +04:00
PM3_WRITE_REG ( par , PM3ForegroundColor , fgx ) ;
PM3_WRITE_REG ( par , PM3BackgroundColor , bgx ) ;
/* ROP Ox3 is GXcopy */
PM3_WRITE_REG ( par , PM3Config2D ,
2007-10-16 12:28:31 +04:00
PM3Config2D_UserScissorEnable |
2007-10-16 12:28:29 +04:00
PM3Config2D_UseConstantSource |
PM3Config2D_ForegroundROPEnable |
2007-10-16 12:28:32 +04:00
PM3Config2D_ForegroundROP ( 0x3 ) |
2007-10-16 12:28:29 +04:00
PM3Config2D_OpaqueSpan |
PM3Config2D_FBWriteEnable ) ;
2007-10-16 12:28:31 +04:00
PM3_WRITE_REG ( par , PM3ScissorMinXY ,
( ( image - > dy & 0x0fff ) < < 16 ) | ( image - > dx & 0x0fff ) ) ;
PM3_WRITE_REG ( par , PM3ScissorMaxXY ,
( ( ( image - > dy + image - > height ) & 0x0fff ) < < 16 ) |
( ( image - > dx + image - > width ) & 0x0fff ) ) ;
2007-10-16 12:28:29 +04:00
PM3_WRITE_REG ( par , PM3RectanglePosition ,
2007-10-16 12:28:32 +04:00
PM3RectanglePosition_XOffset ( image - > dx ) |
PM3RectanglePosition_YOffset ( image - > dy ) ) ;
2007-10-16 12:28:29 +04:00
PM3_WRITE_REG ( par , PM3Render2D ,
PM3Render2D_XPositive |
PM3Render2D_YPositive |
PM3Render2D_Operation_SyncOnBitMask |
PM3Render2D_SpanOperation |
2007-10-16 12:28:32 +04:00
PM3Render2D_Width ( image - > width ) |
PM3Render2D_Height ( image - > height ) ) ;
2007-10-16 12:28:29 +04:00
while ( height - - ) {
2007-10-16 12:28:32 +04:00
int width = ( ( image - > width + 7 ) > > 3 )
+ info - > pixmap . scan_align - 1 ;
2007-10-16 12:28:31 +04:00
width > > = 2 ;
2007-10-16 12:28:29 +04:00
while ( width > = PM3_FIFO_SIZE ) {
int i = PM3_FIFO_SIZE - 1 ;
PM3_WAIT ( par , PM3_FIFO_SIZE ) ;
while ( i - - ) {
PM3_WRITE_REG ( par , PM3BitMaskPattern , * src ) ;
src + + ;
}
width - = PM3_FIFO_SIZE - 1 ;
}
PM3_WAIT ( par , width + 1 ) ;
while ( width - - ) {
PM3_WRITE_REG ( par , PM3BitMaskPattern , * src ) ;
src + + ;
}
}
}
2007-07-17 15:05:46 +04:00
/* end of acceleration functions */
2007-10-16 12:28:54 +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 pm3fb_cursor ( struct fb_info * info , struct fb_cursor * cursor )
{
struct pm3_par * par = info - > par ;
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 ;
mode = PM3RD_CursorMode_TYPE_X ;
if ( cursor - > enable )
mode | = PM3RD_CursorMode_CURSOR_ENABLE ;
PM3_WRITE_DAC_REG ( par , PM3RD_CursorMode , 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 ) {
int x = cursor - > image . dx - info - > var . xoffset ;
int y = cursor - > image . dy - info - > var . yoffset ;
PM3_WRITE_DAC_REG ( par , PM3RD_CursorXLow , x & 0xff ) ;
PM3_WRITE_DAC_REG ( par , PM3RD_CursorXHigh , ( x > > 8 ) & 0xf ) ;
PM3_WRITE_DAC_REG ( par , PM3RD_CursorYLow , y & 0xff ) ;
PM3_WRITE_DAC_REG ( par , PM3RD_CursorYHigh , ( y > > 8 ) & 0xf ) ;
}
if ( cursor - > set & FB_CUR_SETHOT ) {
PM3_WRITE_DAC_REG ( par , PM3RD_CursorHotSpotX ,
cursor - > hot . x & 0x3f ) ;
PM3_WRITE_DAC_REG ( par , PM3RD_CursorHotSpotY ,
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 */
PM3_WRITE_DAC_REG ( par , PM3RD_CursorPalette ( 39 ) ,
cmap . red [ fg_idx ] > > 8 ) ;
PM3_WRITE_DAC_REG ( par , PM3RD_CursorPalette ( 40 ) ,
cmap . green [ fg_idx ] > > 8 ) ;
PM3_WRITE_DAC_REG ( par , PM3RD_CursorPalette ( 41 ) ,
cmap . blue [ fg_idx ] > > 8 ) ;
PM3_WRITE_DAC_REG ( par , PM3RD_CursorPalette ( 42 ) ,
cmap . red [ bg_idx ] > > 8 ) ;
PM3_WRITE_DAC_REG ( par , PM3RD_CursorPalette ( 43 ) ,
cmap . green [ bg_idx ] > > 8 ) ;
PM3_WRITE_DAC_REG ( par , PM3RD_CursorPalette ( 44 ) ,
cmap . blue [ bg_idx ] > > 8 ) ;
}
if ( cursor - > set & ( FB_CUR_SETSHAPE | FB_CUR_SETIMAGE ) ) {
u8 * bitmap = ( u8 * ) cursor - > image . data ;
u8 * mask = ( u8 * ) cursor - > mask ;
int i ;
int pos = PM3RD_CursorPattern ( 0 ) ;
for ( i = 0 ; i < cursor - > image . height ; i + + ) {
int j = ( cursor - > image . width + 7 ) > > 3 ;
int k = 8 - j ;
for ( ; j > 0 ; j - - ) {
u8 data = * bitmap ^ * mask ;
if ( cursor - > rop = = ROP_COPY )
data = * mask & * bitmap ;
/* Upper 4 bits of bitmap data */
PM3_WRITE_DAC_REG ( par , pos + + ,
cursor_bits_lookup [ data > > 4 ] |
( cursor_bits_lookup [ * mask > > 4 ] < < 1 ) ) ;
/* Lower 4 bits of bitmap */
PM3_WRITE_DAC_REG ( par , pos + + ,
cursor_bits_lookup [ data & 0xf ] |
( cursor_bits_lookup [ * mask & 0xf ] < < 1 ) ) ;
bitmap + + ;
mask + + ;
}
for ( ; k > 0 ; k - - ) {
PM3_WRITE_DAC_REG ( par , pos + + , 0 ) ;
PM3_WRITE_DAC_REG ( par , pos + + , 0 ) ;
}
}
while ( pos < PM3RD_CursorPattern ( 1024 ) )
PM3_WRITE_DAC_REG ( par , pos + + , 0 ) ;
}
return 0 ;
}
2005-04-17 02:20:36 +04:00
/* write the mode to registers */
2007-05-11 09:23:25 +04:00
static void pm3fb_write_mode ( struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
2007-05-11 09:23:25 +04:00
struct pm3_par * par = info - > par ;
2007-10-16 12:28:51 +04:00
char tempsync = 0x00 ;
char tempmisc = 0x00 ;
2007-05-11 09:23:25 +04:00
const u32 hsstart = info - > var . right_margin ;
const u32 hsend = hsstart + info - > var . hsync_len ;
const u32 hbend = hsend + info - > var . left_margin ;
const u32 xres = ( info - > var . xres + 31 ) & ~ 31 ;
const u32 htotal = xres + hbend ;
const u32 vsstart = info - > var . lower_margin ;
const u32 vsend = vsstart + info - > var . vsync_len ;
const u32 vbend = vsend + info - > var . upper_margin ;
const u32 vtotal = info - > var . yres + vbend ;
const u32 width = ( info - > var . xres_virtual + 7 ) & ~ 7 ;
2007-05-24 00:57:48 +04:00
const unsigned bpp = info - > var . bits_per_pixel ;
PM3_WAIT ( par , 20 ) ;
PM3_WRITE_REG ( par , PM3MemBypassWriteMask , 0xffffffff ) ;
PM3_WRITE_REG ( par , PM3Aperture0 , 0x00000000 ) ;
PM3_WRITE_REG ( par , PM3Aperture1 , 0x00000000 ) ;
PM3_WRITE_REG ( par , PM3FIFODis , 0x00000007 ) ;
PM3_WRITE_REG ( par , PM3HTotal ,
pm3fb_shift_bpp ( bpp , htotal - 1 ) ) ;
PM3_WRITE_REG ( par , PM3HsEnd ,
pm3fb_shift_bpp ( bpp , hsend ) ) ;
PM3_WRITE_REG ( par , PM3HsStart ,
pm3fb_shift_bpp ( bpp , hsstart ) ) ;
PM3_WRITE_REG ( par , PM3HbEnd ,
pm3fb_shift_bpp ( bpp , hbend ) ) ;
PM3_WRITE_REG ( par , PM3HgEnd ,
pm3fb_shift_bpp ( bpp , hbend ) ) ;
PM3_WRITE_REG ( par , PM3ScreenStride ,
pm3fb_shift_bpp ( bpp , width ) ) ;
PM3_WRITE_REG ( par , PM3VTotal , vtotal - 1 ) ;
PM3_WRITE_REG ( par , PM3VsEnd , vsend - 1 ) ;
PM3_WRITE_REG ( par , PM3VsStart , vsstart - 1 ) ;
PM3_WRITE_REG ( par , PM3VbEnd , vbend ) ;
switch ( bpp ) {
2005-04-17 02:20:36 +04:00
case 8 :
2007-05-24 00:57:48 +04:00
PM3_WRITE_REG ( par , PM3ByAperture1Mode ,
2005-04-17 02:20:36 +04:00
PM3ByApertureMode_PIXELSIZE_8BIT ) ;
2007-05-24 00:57:48 +04:00
PM3_WRITE_REG ( par , PM3ByAperture2Mode ,
2005-04-17 02:20:36 +04:00
PM3ByApertureMode_PIXELSIZE_8BIT ) ;
break ;
case 16 :
# ifndef __BIG_ENDIAN
2007-05-24 00:57:48 +04:00
PM3_WRITE_REG ( par , PM3ByAperture1Mode ,
2005-04-17 02:20:36 +04:00
PM3ByApertureMode_PIXELSIZE_16BIT ) ;
2007-05-24 00:57:48 +04:00
PM3_WRITE_REG ( par , PM3ByAperture2Mode ,
2005-04-17 02:20:36 +04:00
PM3ByApertureMode_PIXELSIZE_16BIT ) ;
# else
2007-05-24 00:57:48 +04:00
PM3_WRITE_REG ( par , PM3ByAperture1Mode ,
2005-04-17 02:20:36 +04:00
PM3ByApertureMode_PIXELSIZE_16BIT |
PM3ByApertureMode_BYTESWAP_BADC ) ;
2007-05-24 00:57:48 +04:00
PM3_WRITE_REG ( par , PM3ByAperture2Mode ,
2005-04-17 02:20:36 +04:00
PM3ByApertureMode_PIXELSIZE_16BIT |
PM3ByApertureMode_BYTESWAP_BADC ) ;
# endif /* ! __BIG_ENDIAN */
break ;
case 32 :
# ifndef __BIG_ENDIAN
2007-05-24 00:57:48 +04:00
PM3_WRITE_REG ( par , PM3ByAperture1Mode ,
2005-04-17 02:20:36 +04:00
PM3ByApertureMode_PIXELSIZE_32BIT ) ;
2007-05-24 00:57:48 +04:00
PM3_WRITE_REG ( par , PM3ByAperture2Mode ,
2005-04-17 02:20:36 +04:00
PM3ByApertureMode_PIXELSIZE_32BIT ) ;
# else
2007-05-24 00:57:48 +04:00
PM3_WRITE_REG ( par , PM3ByAperture1Mode ,
2005-04-17 02:20:36 +04:00
PM3ByApertureMode_PIXELSIZE_32BIT |
PM3ByApertureMode_BYTESWAP_DCBA ) ;
2007-05-24 00:57:48 +04:00
PM3_WRITE_REG ( par , PM3ByAperture2Mode ,
2005-04-17 02:20:36 +04:00
PM3ByApertureMode_PIXELSIZE_32BIT |
PM3ByApertureMode_BYTESWAP_DCBA ) ;
# endif /* ! __BIG_ENDIAN */
break ;
default :
2007-05-24 00:57:48 +04:00
DPRINTK ( " Unsupported depth %d \n " , bpp ) ;
2005-04-17 02:20:36 +04:00
break ;
}
/*
* Oxygen VX1 - it appears that setting PM3VideoControl and
* then PM3RD_SyncControl to the same SYNC settings undoes
* any net change - they seem to xor together . Only set the
* sync options in PM3RD_SyncControl . - - rmk
*/
{
2007-05-11 09:23:25 +04:00
unsigned int video = par - > video ;
2005-04-17 02:20:36 +04:00
video & = ~ ( PM3VideoControl_HSYNC_MASK |
PM3VideoControl_VSYNC_MASK ) ;
video | = PM3VideoControl_HSYNC_ACTIVE_HIGH |
PM3VideoControl_VSYNC_ACTIVE_HIGH ;
2007-05-24 00:57:48 +04:00
PM3_WRITE_REG ( par , PM3VideoControl , video ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-24 00:57:48 +04:00
PM3_WRITE_REG ( par , PM3VClkCtl ,
2007-05-11 09:23:25 +04:00
( PM3_READ_REG ( par , PM3VClkCtl ) & 0xFFFFFFFC ) ) ;
2007-05-24 00:57:48 +04:00
PM3_WRITE_REG ( par , PM3ScreenBase , par - > base ) ;
PM3_WRITE_REG ( par , PM3ChipConfig ,
2007-05-11 09:23:25 +04:00
( PM3_READ_REG ( par , PM3ChipConfig ) & 0xFFFFFFFD ) ) ;
2005-04-17 02:20:36 +04:00
2007-05-24 00:57:48 +04:00
wmb ( ) ;
2005-04-17 02:20:36 +04:00
{
2007-05-11 09:23:25 +04:00
unsigned char uninitialized_var ( m ) ; /* ClkPreScale */
unsigned char uninitialized_var ( n ) ; /* ClkFeedBackScale */
unsigned char uninitialized_var ( p ) ; /* ClkPostScale */
unsigned long pixclock = PICOS2KHZ ( info - > var . pixclock ) ;
( void ) pm3fb_calculate_clock ( pixclock , & m , & n , & p ) ;
DPRINTK ( " Pixclock: %ld, Pre: %d, Feedback: %d, Post: %d \n " ,
pixclock , ( int ) m , ( int ) n , ( int ) p ) ;
PM3_WRITE_DAC_REG ( par , PM3RD_DClk0PreScale , m ) ;
PM3_WRITE_DAC_REG ( par , PM3RD_DClk0FeedbackScale , n ) ;
PM3_WRITE_DAC_REG ( par , PM3RD_DClk0PostScale , p ) ;
2005-04-17 02:20:36 +04:00
}
/*
2007-05-11 09:23:25 +04:00
PM3_WRITE_DAC_REG ( par , PM3RD_IndexControl , 0x00 ) ;
2005-04-17 02:20:36 +04:00
*/
/*
2007-05-11 09:23:25 +04:00
PM3_SLOW_WRITE_REG ( par , PM3RD_IndexControl , 0x00 ) ;
2005-04-17 02:20:36 +04:00
*/
2007-05-11 09:23:25 +04:00
if ( ( par - > video & PM3VideoControl_HSYNC_MASK ) = =
2005-04-17 02:20:36 +04:00
PM3VideoControl_HSYNC_ACTIVE_HIGH )
tempsync | = PM3RD_SyncControl_HSYNC_ACTIVE_HIGH ;
2007-05-11 09:23:25 +04:00
if ( ( par - > video & PM3VideoControl_VSYNC_MASK ) = =
2005-04-17 02:20:36 +04:00
PM3VideoControl_VSYNC_ACTIVE_HIGH )
tempsync | = PM3RD_SyncControl_VSYNC_ACTIVE_HIGH ;
2007-05-11 09:23:25 +04:00
PM3_WRITE_DAC_REG ( par , PM3RD_SyncControl , tempsync ) ;
DPRINTK ( " PM3RD_SyncControl: %d \n " , tempsync ) ;
PM3_WRITE_DAC_REG ( par , PM3RD_DACControl , 0x00 ) ;
2007-05-24 00:57:48 +04:00
switch ( pm3fb_depth ( & info - > var ) ) {
2005-04-17 02:20:36 +04:00
case 8 :
2007-05-11 09:23:25 +04:00
PM3_WRITE_DAC_REG ( par , PM3RD_PixelSize ,
2005-04-17 02:20:36 +04:00
PM3RD_PixelSize_8_BIT_PIXELS ) ;
2007-05-11 09:23:25 +04:00
PM3_WRITE_DAC_REG ( par , PM3RD_ColorFormat ,
2005-04-17 02:20:36 +04:00
PM3RD_ColorFormat_CI8_COLOR |
PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW ) ;
tempmisc | = PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE ;
break ;
case 12 :
2007-05-11 09:23:25 +04:00
PM3_WRITE_DAC_REG ( par , PM3RD_PixelSize ,
2005-04-17 02:20:36 +04:00
PM3RD_PixelSize_16_BIT_PIXELS ) ;
2007-05-11 09:23:25 +04:00
PM3_WRITE_DAC_REG ( par , PM3RD_ColorFormat ,
2005-04-17 02:20:36 +04:00
PM3RD_ColorFormat_4444_COLOR |
PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE ) ;
tempmisc | = PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE ;
2007-05-11 09:23:25 +04:00
break ;
2005-04-17 02:20:36 +04:00
case 15 :
2007-05-11 09:23:25 +04:00
PM3_WRITE_DAC_REG ( par , PM3RD_PixelSize ,
2005-04-17 02:20:36 +04:00
PM3RD_PixelSize_16_BIT_PIXELS ) ;
2007-05-11 09:23:25 +04:00
PM3_WRITE_DAC_REG ( par , PM3RD_ColorFormat ,
2005-04-17 02:20:36 +04:00
PM3RD_ColorFormat_5551_FRONT_COLOR |
PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE ) ;
tempmisc | = PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE ;
2007-05-11 09:23:25 +04:00
break ;
2005-04-17 02:20:36 +04:00
case 16 :
2007-05-11 09:23:25 +04:00
PM3_WRITE_DAC_REG ( par , PM3RD_PixelSize ,
2005-04-17 02:20:36 +04:00
PM3RD_PixelSize_16_BIT_PIXELS ) ;
2007-05-11 09:23:25 +04:00
PM3_WRITE_DAC_REG ( par , PM3RD_ColorFormat ,
2005-04-17 02:20:36 +04:00
PM3RD_ColorFormat_565_FRONT_COLOR |
PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE ) ;
tempmisc | = PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE ;
break ;
case 32 :
2007-05-11 09:23:25 +04:00
PM3_WRITE_DAC_REG ( par , PM3RD_PixelSize ,
2005-04-17 02:20:36 +04:00
PM3RD_PixelSize_32_BIT_PIXELS ) ;
2007-05-11 09:23:25 +04:00
PM3_WRITE_DAC_REG ( par , PM3RD_ColorFormat ,
2005-04-17 02:20:36 +04:00
PM3RD_ColorFormat_8888_COLOR |
PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW ) ;
tempmisc | = PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE ;
break ;
}
2007-05-11 09:23:25 +04:00
PM3_WRITE_DAC_REG ( par , PM3RD_MiscControl , tempmisc ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
/*
* hardware independent functions
*/
static int pm3fb_check_var ( struct fb_var_screeninfo * var , struct fb_info * info )
{
u32 lpitch ;
2007-05-24 00:57:48 +04:00
unsigned bpp = var - > red . length + var - > green . length
+ var - > blue . length + var - > transp . length ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:28:32 +04:00
if ( bpp ! = var - > bits_per_pixel ) {
2007-05-24 00:57:48 +04:00
/* set predefined mode for bits_per_pixel settings */
2007-10-16 12:28:51 +04:00
switch ( var - > bits_per_pixel ) {
2007-05-24 00:57:48 +04:00
case 8 :
2007-10-16 12:28:51 +04:00
var - > red . length = 8 ;
var - > green . length = 8 ;
var - > blue . length = 8 ;
var - > red . offset = 0 ;
var - > green . offset = 0 ;
var - > blue . offset = 0 ;
2007-05-24 00:57:48 +04:00
var - > transp . offset = 0 ;
var - > transp . length = 0 ;
break ;
case 16 :
2007-10-16 12:28:51 +04:00
var - > red . length = 5 ;
var - > blue . length = 5 ;
2007-05-24 00:57:48 +04:00
var - > green . length = 6 ;
var - > transp . length = 0 ;
break ;
case 32 :
2007-10-16 12:28:51 +04:00
var - > red . length = 8 ;
var - > green . length = 8 ;
var - > blue . length = 8 ;
2007-05-24 00:57:48 +04:00
var - > transp . length = 8 ;
break ;
default :
2007-10-16 12:28:51 +04:00
DPRINTK ( " depth not supported: %u \n " ,
var - > bits_per_pixel ) ;
2007-05-24 00:57:48 +04:00
return - EINVAL ;
}
}
/* it is assumed BGRA order */
2007-10-16 12:28:51 +04:00
if ( var - > bits_per_pixel > 8 ) {
2007-05-24 00:57:48 +04:00
var - > blue . offset = 0 ;
var - > green . offset = var - > blue . length ;
var - > red . offset = var - > green . offset + var - > green . length ;
var - > transp . offset = var - > red . offset + var - > red . length ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:28:51 +04:00
var - > height = - 1 ;
var - > width = - 1 ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
if ( var - > xres ! = var - > xres_virtual ) {
2007-10-16 12:28:51 +04:00
DPRINTK ( " virtual x resolution != "
" physical x resolution not supported \n " ) ;
2007-05-11 09:23:25 +04:00
return - EINVAL ;
}
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
if ( var - > yres > var - > yres_virtual ) {
2007-10-16 12:28:51 +04:00
DPRINTK ( " virtual y resolution < "
" physical y resolution not possible \n " ) ;
2007-05-11 09:23:25 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
if ( var - > xoffset ) {
DPRINTK ( " xoffset not supported \n " ) ;
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
if ( ( var - > vmode & FB_VMODE_MASK ) = = FB_VMODE_INTERLACED ) {
DPRINTK ( " interlace not supported \n " ) ;
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
var - > xres = ( var - > xres + 31 ) & ~ 31 ; /* could sometimes be 8 */
2007-10-16 12:28:32 +04:00
lpitch = var - > xres * ( ( var - > bits_per_pixel + 7 ) > > 3 ) ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
if ( var - > xres < 200 | | var - > xres > 2048 ) {
DPRINTK ( " width not supported: %u \n " , var - > xres ) ;
return - EINVAL ;
}
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
if ( var - > yres < 200 | | var - > yres > 4095 ) {
DPRINTK ( " height not supported: %u \n " , var - > yres ) ;
return - EINVAL ;
}
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +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 ;
}
if ( PICOS2KHZ ( var - > pixclock ) > PM3_MAX_PIXCLOCK ) {
2007-10-16 12:28:51 +04:00
DPRINTK ( " pixclock too high (%ldKHz) \n " ,
PICOS2KHZ ( var - > pixclock ) ) ;
2007-05-11 09:23:25 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
var - > accel_flags = 0 ; /* Can't mmap if this is on */
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
DPRINTK ( " Checking graphics mode at %dx%d depth %d \n " ,
var - > xres , var - > yres , var - > bits_per_pixel ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
static int pm3fb_set_par ( struct fb_info * info )
{
struct pm3_par * par = info - > par ;
const u32 xres = ( info - > var . xres + 31 ) & ~ 31 ;
2007-05-24 00:57:48 +04:00
const unsigned bpp = info - > var . bits_per_pixel ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:28:51 +04:00
par - > base = pm3fb_shift_bpp ( bpp , ( info - > var . yoffset * xres )
2007-05-11 09:23:25 +04:00
+ info - > var . xoffset ) ;
par - > video = 0 ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
if ( info - > var . sync & FB_SYNC_HOR_HIGH_ACT )
par - > video | = PM3VideoControl_HSYNC_ACTIVE_HIGH ;
else
par - > video | = PM3VideoControl_HSYNC_ACTIVE_LOW ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
if ( info - > var . sync & FB_SYNC_VERT_HIGH_ACT )
par - > video | = PM3VideoControl_VSYNC_ACTIVE_HIGH ;
else
par - > video | = PM3VideoControl_VSYNC_ACTIVE_LOW ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
if ( ( info - > var . vmode & FB_VMODE_MASK ) = = FB_VMODE_DOUBLE )
par - > video | = PM3VideoControl_LINE_DOUBLE_ON ;
2005-04-17 02:20:36 +04:00
2007-06-01 11:47:09 +04:00
if ( ( info - > var . activate & FB_ACTIVATE_MASK ) = = FB_ACTIVATE_NOW )
2007-05-11 09:23:25 +04:00
par - > video | = PM3VideoControl_ENABLE ;
2007-10-16 12:28:32 +04:00
else
2007-05-11 09:23:25 +04:00
DPRINTK ( " PM3Video disabled \n " ) ;
2007-10-16 12:28:32 +04:00
2007-05-24 00:57:48 +04:00
switch ( bpp ) {
2007-05-11 09:23:25 +04:00
case 8 :
par - > video | = PM3VideoControl_PIXELSIZE_8BIT ;
break ;
case 16 :
par - > video | = PM3VideoControl_PIXELSIZE_16BIT ;
break ;
case 32 :
par - > video | = PM3VideoControl_PIXELSIZE_32BIT ;
break ;
default :
DPRINTK ( " Unsupported depth \n " ) ;
break ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
info - > fix . visual =
2007-05-24 00:57:48 +04:00
( bpp = = 8 ) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR ;
2007-10-16 12:28:32 +04:00
info - > fix . line_length = ( ( info - > var . xres_virtual + 7 ) > > 3 ) * bpp ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
/* pm3fb_clear_memory(info, 0);*/
pm3fb_clear_colormap ( par , 0 , 0 , 0 ) ;
2007-10-16 12:28:31 +04:00
PM3_WRITE_DAC_REG ( par , PM3RD_CursorMode , 0 ) ;
2007-07-17 15:05:46 +04:00
pm3fb_init_engine ( info ) ;
2007-05-11 09:23:25 +04:00
pm3fb_write_mode ( info ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
static int pm3fb_setcolreg ( unsigned regno , unsigned red , unsigned green ,
unsigned blue , unsigned transp ,
struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
2007-05-11 09:23:25 +04:00
struct pm3_par * par = info - > par ;
if ( regno > = 256 ) /* no. of hw registers */
return - EINVAL ;
/* grayscale works only partially under directcolor */
2007-10-16 12:28:51 +04:00
/* grayscale = 0.30*R + 0.59*G + 0.11*B */
if ( info - > var . grayscale )
2007-05-11 09:23:25 +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
* pseudo_palette [ X ] is programmed to ( X < < red . offset ) |
2007-05-24 00:57:48 +04:00
* ( X < < green . offset ) |
* ( X < < blue . offset )
2007-05-11 09:23:25 +04:00
* RAMDAC [ X ] is programmed to ( red , green , blue )
* color depth = SUM ( var - > { color } . length )
*
* Pseudocolor :
* var - > { color } . offset is 0
2007-10-16 12:28:51 +04:00
* var - > { color } . length contains width of DAC or the number
* of unique colors available ( color depth )
2007-05-11 09:23:25 +04:00
* pseudo_palette is not used
* RAMDAC [ X ] is programmed to ( red , green , blue )
* color depth = var - > { color } . length
*/
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
/*
* This is the point where the color is converted to something that
* is acceptable by the hardware .
*/
2007-10-16 12:28:51 +04:00
# define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)
2007-05-11 09:23:25 +04:00
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 ) ;
# undef CNVT_TOHW
if ( info - > fix . visual = = FB_VISUAL_TRUECOLOR | |
info - > fix . visual = = FB_VISUAL_DIRECTCOLOR ) {
u32 v ;
if ( regno > = 16 )
return - EINVAL ;
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 :
break ;
case 16 :
case 32 :
2007-10-16 12:28:51 +04:00
( ( u32 * ) ( info - > pseudo_palette ) ) [ regno ] = v ;
2007-05-11 09:23:25 +04:00
break ;
}
return 0 ;
2007-10-16 12:28:51 +04:00
} else if ( info - > fix . visual = = FB_VISUAL_PSEUDOCOLOR )
2007-05-11 09:23:25 +04:00
pm3fb_set_color ( par , regno , red , green , blue ) ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
static int pm3fb_pan_display ( struct fb_var_screeninfo * var ,
struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
2007-05-11 09:23:25 +04:00
struct pm3_par * par = info - > par ;
const u32 xres = ( var - > xres + 31 ) & ~ 31 ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
par - > base = pm3fb_shift_bpp ( var - > bits_per_pixel ,
( var - > yoffset * xres )
+ var - > xoffset ) ;
2007-05-24 00:57:48 +04:00
PM3_WAIT ( par , 1 ) ;
PM3_WRITE_REG ( par , PM3ScreenBase , par - > base ) ;
2007-05-11 09:23:25 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
static int pm3fb_blank ( int blank_mode , struct fb_info * info )
{
struct pm3_par * par = info - > par ;
u32 video = par - > video ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
/*
* Oxygen VX1 - it appears that setting PM3VideoControl and
* then PM3RD_SyncControl to the same SYNC settings undoes
* any net change - they seem to xor together . Only set the
* sync options in PM3RD_SyncControl . - - rmk
*/
video & = ~ ( PM3VideoControl_HSYNC_MASK |
PM3VideoControl_VSYNC_MASK ) ;
video | = PM3VideoControl_HSYNC_ACTIVE_HIGH |
PM3VideoControl_VSYNC_ACTIVE_HIGH ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
switch ( blank_mode ) {
case FB_BLANK_UNBLANK :
2007-05-24 00:57:48 +04:00
video | = PM3VideoControl_ENABLE ;
2007-05-11 09:23:25 +04:00
break ;
2007-05-24 00:57:48 +04:00
case FB_BLANK_NORMAL :
2007-10-16 12:28:32 +04:00
video & = ~ PM3VideoControl_ENABLE ;
2007-05-11 09:23:25 +04:00
break ;
case FB_BLANK_HSYNC_SUSPEND :
2007-05-24 00:57:48 +04:00
video & = ~ ( PM3VideoControl_HSYNC_MASK |
PM3VideoControl_BLANK_ACTIVE_LOW ) ;
2007-05-11 09:23:25 +04:00
break ;
case FB_BLANK_VSYNC_SUSPEND :
2007-05-24 00:57:48 +04:00
video & = ~ ( PM3VideoControl_VSYNC_MASK |
PM3VideoControl_BLANK_ACTIVE_LOW ) ;
2007-05-11 09:23:25 +04:00
break ;
case FB_BLANK_POWERDOWN :
2007-05-24 00:57:48 +04:00
video & = ~ ( PM3VideoControl_HSYNC_MASK |
PM3VideoControl_VSYNC_MASK |
PM3VideoControl_BLANK_ACTIVE_LOW ) ;
2007-05-11 09:23:25 +04:00
break ;
default :
DPRINTK ( " Unsupported blanking %d \n " , blank_mode ) ;
return 1 ;
2005-04-17 02:20:36 +04:00
}
2007-05-24 00:57:48 +04:00
PM3_WAIT ( par , 1 ) ;
2007-10-16 12:28:51 +04:00
PM3_WRITE_REG ( par , PM3VideoControl , video ) ;
2007-05-11 09:23:25 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
/*
* Frame buffer operations
*/
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
static struct fb_ops pm3fb_ops = {
. owner = THIS_MODULE ,
. fb_check_var = pm3fb_check_var ,
. fb_set_par = pm3fb_set_par ,
. fb_setcolreg = pm3fb_setcolreg ,
. fb_pan_display = pm3fb_pan_display ,
2007-07-17 15:05:46 +04:00
. fb_fillrect = pm3fb_fillrect ,
2007-10-16 12:28:29 +04:00
. fb_copyarea = pm3fb_copyarea ,
. fb_imageblit = pm3fb_imageblit ,
2007-05-11 09:23:25 +04:00
. fb_blank = pm3fb_blank ,
2007-07-17 15:05:46 +04:00
. fb_sync = pm3fb_sync ,
2007-10-16 12:28:54 +04:00
. fb_cursor = pm3fb_cursor ,
2007-05-11 09:23:25 +04:00
} ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
/* ------------------------------------------------------------------------- */
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
/*
* Initialization
*/
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
/* mmio register are already mapped when this function is called */
/* the pm3fb_fix.smem_start is also set */
2008-02-06 12:39:15 +03:00
static unsigned long __devinit pm3fb_size_memory ( struct pm3_par * par )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:28:51 +04:00
unsigned long memsize = 0 ;
unsigned long tempBypass , i , temp1 , temp2 ;
2007-05-11 09:23:25 +04:00
unsigned char __iomem * screen_mem ;
2005-04-17 02:20:36 +04:00
2007-05-24 00:57:48 +04:00
pm3fb_fix . smem_len = 64 * 1024l * 1024 ; /* request full aperture size */
2007-05-11 09:23:25 +04:00
/* Linear frame buffer - request region and map it. */
if ( ! request_mem_region ( pm3fb_fix . smem_start , pm3fb_fix . smem_len ,
" pm3fb smem " ) ) {
printk ( KERN_WARNING " pm3fb: Can't reserve smem. \n " ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
screen_mem =
ioremap_nocache ( pm3fb_fix . smem_start , pm3fb_fix . smem_len ) ;
if ( ! screen_mem ) {
printk ( KERN_WARNING " pm3fb: Can't ioremap smem area. \n " ) ;
release_mem_region ( pm3fb_fix . smem_start , pm3fb_fix . smem_len ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
/* TODO: card-specific stuff, *before* accessing *any* FB memory */
/* For Appian Jeronimo 2000 board second head */
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
tempBypass = PM3_READ_REG ( par , PM3MemBypassWriteMask ) ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
DPRINTK ( " PM3MemBypassWriteMask was: 0x%08lx \n " , tempBypass ) ;
2005-04-17 02:20:36 +04:00
2007-05-24 00:57:48 +04:00
PM3_WAIT ( par , 1 ) ;
PM3_WRITE_REG ( par , PM3MemBypassWriteMask , 0xFFFFFFFF ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:28:51 +04:00
/* pm3 split up memory, replicates, and do a lot of
* nasty stuff IMHO ; - )
*/
2007-05-11 09:23:25 +04:00
for ( i = 0 ; i < 32 ; i + + ) {
fb_writel ( i * 0x00345678 ,
( screen_mem + ( i * 1048576 ) ) ) ;
mb ( ) ;
temp1 = fb_readl ( ( screen_mem + ( i * 1048576 ) ) ) ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
/* Let's check for wrapover, write will fail at 16MB boundary */
if ( temp1 = = ( i * 0x00345678 ) )
memsize = i ;
2005-04-17 02:20:36 +04:00
else
2007-05-11 09:23:25 +04:00
break ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
DPRINTK ( " First detect pass already got %ld MB \n " , memsize + 1 ) ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
if ( memsize + 1 = = i ) {
for ( i = 0 ; i < 32 ; i + + ) {
/* Clear first 32MB ; 0 is 0, no need to byteswap */
2007-05-24 00:57:48 +04:00
writel ( 0x0000000 , ( screen_mem + ( i * 1048576 ) ) ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-24 00:57:48 +04:00
wmb ( ) ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
for ( i = 32 ; i < 64 ; i + + ) {
fb_writel ( i * 0x00345678 ,
( screen_mem + ( i * 1048576 ) ) ) ;
mb ( ) ;
temp1 =
fb_readl ( ( screen_mem + ( i * 1048576 ) ) ) ;
temp2 =
fb_readl ( ( screen_mem + ( ( i - 32 ) * 1048576 ) ) ) ;
/* different value, different RAM... */
if ( ( temp1 = = ( i * 0x00345678 ) ) & & ( temp2 = = 0 ) )
memsize = i ;
else
break ;
2005-04-17 02:20:36 +04:00
}
}
2007-05-11 09:23:25 +04:00
DPRINTK ( " Second detect pass got %ld MB \n " , memsize + 1 ) ;
2005-04-17 02:20:36 +04:00
2007-05-24 00:57:48 +04:00
PM3_WAIT ( par , 1 ) ;
PM3_WRITE_REG ( par , PM3MemBypassWriteMask , tempBypass ) ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
iounmap ( screen_mem ) ;
release_mem_region ( pm3fb_fix . smem_start , pm3fb_fix . smem_len ) ;
memsize = 1048576 * ( memsize + 1 ) ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
DPRINTK ( " Returning 0x%08lx bytes \n " , memsize ) ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
return memsize ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
static int __devinit pm3fb_probe ( struct pci_dev * dev ,
const struct pci_device_id * ent )
2005-04-17 02:20:36 +04:00
{
2007-05-11 09:23:25 +04:00
struct fb_info * info ;
struct pm3_par * par ;
2007-10-16 12:28:51 +04:00
struct device * device = & dev - > dev ; /* for pci drivers */
int err ;
int retval = - ENXIO ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
err = pci_enable_device ( dev ) ;
if ( err ) {
printk ( KERN_WARNING " pm3fb: Can't enable PCI dev: %d \n " , err ) ;
return err ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
/*
* Dynamically allocate info and par
*/
info = framebuffer_alloc ( sizeof ( struct pm3_par ) , device ) ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
if ( ! info )
return - ENOMEM ;
par = info - > par ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
/*
* Here we set the screen_base to the virtual memory address
* for the framebuffer .
*/
pm3fb_fix . mmio_start = pci_resource_start ( dev , 0 ) ;
pm3fb_fix . mmio_len = PM3_REGS_SIZE ;
2007-10-16 12:28:32 +04:00
# if defined(__BIG_ENDIAN)
pm3fb_fix . mmio_start + = PM3_REGS_SIZE ;
DPRINTK ( " Adjusting register base for big-endian. \n " ) ;
# endif
2007-05-11 09:23:25 +04:00
/* Registers - request region and map it. */
if ( ! request_mem_region ( pm3fb_fix . mmio_start , pm3fb_fix . mmio_len ,
" pm3fb regbase " ) ) {
printk ( KERN_WARNING " pm3fb: Can't reserve regbase. \n " ) ;
goto err_exit_neither ;
}
par - > v_regs =
ioremap_nocache ( pm3fb_fix . mmio_start , pm3fb_fix . mmio_len ) ;
if ( ! par - > v_regs ) {
printk ( KERN_WARNING " pm3fb: Can't remap %s register area. \n " ,
pm3fb_fix . id ) ;
release_mem_region ( pm3fb_fix . mmio_start , pm3fb_fix . mmio_len ) ;
goto err_exit_neither ;
}
/* Linear frame buffer - request region and map it. */
pm3fb_fix . smem_start = pci_resource_start ( dev , 1 ) ;
pm3fb_fix . smem_len = pm3fb_size_memory ( par ) ;
2007-10-16 12:28:51 +04:00
if ( ! pm3fb_fix . smem_len ) {
2007-05-11 09:23:25 +04:00
printk ( KERN_WARNING " pm3fb: Can't find memory on board. \n " ) ;
goto err_exit_mmio ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
if ( ! request_mem_region ( pm3fb_fix . smem_start , pm3fb_fix . smem_len ,
" pm3fb smem " ) ) {
printk ( KERN_WARNING " pm3fb: Can't reserve smem. \n " ) ;
goto err_exit_mmio ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
info - > screen_base =
ioremap_nocache ( pm3fb_fix . smem_start , pm3fb_fix . smem_len ) ;
if ( ! info - > screen_base ) {
printk ( KERN_WARNING " pm3fb: Can't ioremap smem area. \n " ) ;
release_mem_region ( pm3fb_fix . smem_start , pm3fb_fix . smem_len ) ;
goto err_exit_mmio ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
info - > screen_size = pm3fb_fix . smem_len ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:28:33 +04:00
# ifdef CONFIG_MTRR
2007-10-16 12:28:51 +04:00
if ( ! nomtrr )
2007-10-16 12:28:33 +04:00
par - > mtrr_handle = mtrr_add ( pm3fb_fix . smem_start ,
pm3fb_fix . smem_len ,
MTRR_TYPE_WRCOMB , 1 ) ;
# endif
2007-05-11 09:23:25 +04:00
info - > fbops = & pm3fb_ops ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
par - > video = PM3_READ_REG ( par , PM3VideoControl ) ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
info - > fix = pm3fb_fix ;
info - > pseudo_palette = par - > palette ;
2007-07-17 15:05:46 +04:00
info - > flags = FBINFO_DEFAULT |
2007-10-16 12:28:32 +04:00
FBINFO_HWACCEL_XPAN |
FBINFO_HWACCEL_YPAN |
2007-10-16 12:28:29 +04:00
FBINFO_HWACCEL_COPYAREA |
FBINFO_HWACCEL_IMAGEBLIT |
FBINFO_HWACCEL_FILLRECT ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:28:33 +04:00
if ( noaccel ) {
2007-10-16 12:28:51 +04:00
printk ( KERN_DEBUG " disabling acceleration \n " ) ;
info - > flags | = FBINFO_HWACCEL_DISABLED ;
2007-10-16 12:28:33 +04:00
}
2007-10-16 12:28:31 +04:00
info - > pixmap . addr = kmalloc ( PM3_PIXMAP_SIZE , GFP_KERNEL ) ;
if ( ! info - > pixmap . addr ) {
retval = - ENOMEM ;
goto err_exit_pixmap ;
}
info - > pixmap . size = PM3_PIXMAP_SIZE ;
info - > pixmap . buf_align = 4 ;
info - > pixmap . scan_align = 4 ;
info - > pixmap . access_align = 32 ;
info - > pixmap . flags = FB_PIXMAP_SYSTEM ;
2007-05-11 09:23:25 +04:00
/*
* This should give a reasonable default video mode . The following is
* done when we can set a video mode .
*/
if ( ! mode_option )
mode_option = " 640x480@60 " ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
retval = fb_find_mode ( & info - > var , info , mode_option , NULL , 0 , NULL , 8 ) ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
if ( ! retval | | retval = = 4 ) {
retval = - EINVAL ;
goto err_exit_both ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
if ( fb_alloc_cmap ( & info - > cmap , 256 , 0 ) < 0 ) {
retval = - ENOMEM ;
goto err_exit_both ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
/*
* For drivers that can . . .
*/
pm3fb_check_var ( & info - > var , info ) ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
if ( register_framebuffer ( info ) < 0 ) {
retval = - EINVAL ;
goto err_exit_all ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
printk ( KERN_INFO " fb%d: %s frame buffer device \n " , info - > node ,
info - > fix . id ) ;
2007-05-24 00:57:48 +04:00
pci_set_drvdata ( dev , info ) ;
2007-05-11 09:23:25 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
err_exit_all :
fb_dealloc_cmap ( & info - > cmap ) ;
err_exit_both :
2007-10-16 12:28:31 +04:00
kfree ( info - > pixmap . addr ) ;
err_exit_pixmap :
2007-05-11 09:23:25 +04:00
iounmap ( info - > screen_base ) ;
release_mem_region ( pm3fb_fix . smem_start , pm3fb_fix . smem_len ) ;
err_exit_mmio :
iounmap ( par - > v_regs ) ;
release_mem_region ( pm3fb_fix . mmio_start , pm3fb_fix . mmio_len ) ;
err_exit_neither :
framebuffer_release ( info ) ;
return retval ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
/*
* Cleanup
*/
static void __devexit pm3fb_remove ( struct pci_dev * dev )
2005-04-17 02:20:36 +04:00
{
2007-05-11 09:23:25 +04:00
struct fb_info * info = pci_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
if ( info ) {
struct fb_fix_screeninfo * fix = & info - > fix ;
struct pm3_par * par = info - > par ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
unregister_framebuffer ( info ) ;
fb_dealloc_cmap ( & info - > cmap ) ;
2005-04-17 02:20:36 +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 */
2007-05-11 09:23:25 +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 ) ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
pci_set_drvdata ( dev , NULL ) ;
2007-10-16 12:28:31 +04:00
kfree ( info - > pixmap . addr ) ;
2007-05-11 09:23:25 +04:00
framebuffer_release ( info ) ;
2005-04-17 02:20:36 +04:00
}
}
2007-05-11 09:23:25 +04:00
static struct pci_device_id pm3fb_id_table [ ] = {
{ PCI_VENDOR_ID_3DLABS , 0x0a ,
2007-05-24 00:57:48 +04:00
PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
2007-05-11 09:23:25 +04:00
{ 0 , }
} ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
/* For PCI drivers */
static struct pci_driver pm3fb_driver = {
. name = " pm3fb " ,
. id_table = pm3fb_id_table ,
. probe = pm3fb_probe ,
. remove = __devexit_p ( pm3fb_remove ) ,
} ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:23:25 +04:00
MODULE_DEVICE_TABLE ( pci , pm3fb_id_table ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:28:33 +04:00
# ifndef MODULE
/*
* Setup
*/
/*
* Only necessary if your driver takes special options ,
* otherwise we fall back on the generic fb_setup ( ) .
*/
static int __init pm3fb_setup ( char * options )
{
char * this_opt ;
/* Parse user speficied options (`video=pm3fb:') */
if ( ! options | | ! * options )
return 0 ;
while ( ( this_opt = strsep ( & options , " , " ) ) ! = NULL ) {
if ( ! * this_opt )
continue ;
2007-10-16 12:28:51 +04:00
else if ( ! strncmp ( this_opt , " noaccel " , 7 ) )
2007-10-16 12:28:33 +04:00
noaccel = 1 ;
2007-10-16 12:28:54 +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:51 +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:51 +04:00
else
2007-10-16 12:28:33 +04:00
mode_option = this_opt ;
}
return 0 ;
}
# endif /* MODULE */
2007-07-17 15:05:46 +04:00
static int __init pm3fb_init ( void )
2007-05-24 00:57:48 +04:00
{
2007-10-16 12:28:33 +04:00
/*
* For kernel boot options ( in ' video = pm3fb : < options > ' format )
*/
2007-05-11 09:23:25 +04:00
# ifndef MODULE
2007-10-16 12:28:33 +04:00
char * option = NULL ;
if ( fb_get_options ( " pm3fb " , & option ) )
2007-05-11 09:23:25 +04:00
return - ENODEV ;
2007-10-16 12:28:33 +04:00
pm3fb_setup ( option ) ;
2005-04-17 02:20:36 +04:00
# endif
2007-10-16 12:28:33 +04:00
2007-05-11 09:23:25 +04:00
return pci_register_driver ( & pm3fb_driver ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:28:33 +04:00
# ifdef MODULE
2007-05-11 09:23:25 +04:00
static void __exit pm3fb_exit ( void )
2005-04-17 02:20:36 +04:00
{
2007-05-11 09:23:25 +04:00
pci_unregister_driver ( & pm3fb_driver ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-11 09:23:25 +04:00
module_exit ( pm3fb_exit ) ;
2007-10-16 12:28:33 +04:00
# endif
module_init ( pm3fb_init ) ;
2008-04-28 13:15:07 +04:00
module_param ( mode_option , charp , 0 ) ;
MODULE_PARM_DESC ( mode_option , " Initial video mode e.g. '648x480-8@60' " ) ;
2007-10-16 12:28:33 +04:00
module_param ( noaccel , bool , 0 ) ;
MODULE_PARM_DESC ( noaccel , " Disable acceleration " ) ;
2007-10-16 12:28:54 +04:00
module_param ( hwcursor , int , 0644 ) ;
MODULE_PARM_DESC ( hwcursor , " Enable hardware cursor "
" (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
2007-05-11 09:23:25 +04:00
2007-10-16 12:28:32 +04:00
MODULE_DESCRIPTION ( " Permedia3 framebuffer device driver " ) ;
2007-05-11 09:23:25 +04:00
MODULE_LICENSE ( " GPL " ) ;