2005-09-10 00:04:56 +04:00
/*
* Frame buffer driver for Trident Cyberblade / i1 graphics core
*
* Copyright 2005 Knut Petersen < Knut_Petersen @ t - online . de >
*
* CREDITS :
* tridentfb . c by Jani Monoses
* see files above for further credits
*
* TODO :
*
*/
# define CYBLAFB_DEBUG 0
# include <linux/config.h>
# include <linux/module.h>
# include <linux/string.h>
# include <linux/fb.h>
# include <linux/init.h>
# include <linux/pci.h>
# include <asm/types.h>
# include <video/cyblafb.h>
# define VERSION "0.54"
struct cyblafb_par {
u32 pseudo_pal [ 16 ] ;
struct fb_ops ops ;
} ;
static struct fb_fix_screeninfo cyblafb_fix __devinitdata = {
. id = " CyBla " ,
. type = FB_TYPE_PACKED_PIXELS ,
. ypanstep = 1 ,
. visual = FB_VISUAL_PSEUDOCOLOR ,
. accel = FB_ACCEL_NONE ,
} ;
static char * mode __devinitdata = NULL ;
static int bpp __devinitdata = 8 ;
static int ref __devinitdata = 75 ;
static int fp __devinitdata ;
static int crt __devinitdata ;
static int memsize __devinitdata ;
static int vesafb __devinitdata ;
static int nativex ;
static int center ;
static int stretch ;
static int pciwb = 1 ;
static int pcirb = 1 ;
static int pciwr = 1 ;
static int pcirr = 1 ;
static int verbosity ;
static int displaytype ;
static void __iomem * io_virt ; // iospace virtual memory address
module_param ( mode , charp , 0 ) ;
module_param ( bpp , int , 0 ) ;
module_param ( ref , int , 0 ) ;
module_param ( fp , int , 0 ) ;
module_param ( crt , int , 0 ) ;
module_param ( nativex , int , 0 ) ;
module_param ( center , int , 0 ) ;
module_param ( stretch , int , 0 ) ;
module_param ( pciwb , int , 0 ) ;
module_param ( pcirb , int , 0 ) ;
module_param ( pciwr , int , 0 ) ;
module_param ( pcirr , int , 0 ) ;
module_param ( memsize , int , 0 ) ;
module_param ( verbosity , int , 0 ) ;
module_param ( vesafb , int , 0 ) ;
//=========================================
//
// Port access macros for memory mapped io
//
//=========================================
# define out8(r,v) writeb(v,io_virt+r)
# define out32(r,v) writel(v,io_virt+r)
# define in8(r) readb(io_virt+r)
# define in32(r) readl(io_virt+r)
//======================================
//
// Hardware access inline functions
//
//======================================
static inline unsigned char read3X4 ( int reg )
{
out8 ( 0x3D4 , reg ) ;
return in8 ( 0x3D5 ) ;
}
static inline unsigned char read3C4 ( int reg )
{
out8 ( 0x3C4 , reg ) ;
return in8 ( 0x3C5 ) ;
}
static inline unsigned char read3CE ( int reg )
{
out8 ( 0x3CE , reg ) ;
return in8 ( 0x3CF ) ;
}
static inline void write3X4 ( int reg , unsigned char val )
{
out8 ( 0x3D4 , reg ) ;
out8 ( 0x3D5 , val ) ;
}
static inline void write3C4 ( int reg , unsigned char val )
{
out8 ( 0x3C4 , reg ) ;
out8 ( 0x3C5 , val ) ;
}
static inline void write3CE ( int reg , unsigned char val )
{
out8 ( 0x3CE , reg ) ;
out8 ( 0x3CF , val ) ;
}
static inline void write3C0 ( int reg , unsigned char val )
{
in8 ( 0x3DA ) ; // read to reset index
out8 ( 0x3C0 , reg ) ;
out8 ( 0x3C0 , val ) ;
}
//=================================================
//
// Enable memory mapped io and unprotect registers
//
//=================================================
static inline void enable_mmio ( void )
{
int tmp ;
outb ( 0x0B , 0x3C4 ) ;
inb ( 0x3C5 ) ; // Set NEW mode
outb ( SR0E , 0x3C4 ) ; // write enable a lot of extended ports
outb ( 0x80 , 0x3C5 ) ;
outb ( SR11 , 0x3C4 ) ; // write enable those extended ports that
outb ( 0x87 , 0x3C5 ) ; // are not affected by SR0E_New
outb ( CR1E , 0x3d4 ) ; // clear write protect bit for port 0x3c2
tmp = inb ( 0x3d5 ) & 0xBF ;
outb ( CR1E , 0x3d4 ) ;
outb ( tmp , 0x3d5 ) ;
outb ( CR39 , 0x3D4 ) ;
outb ( inb ( 0x3D5 ) | 0x01 , 0x3D5 ) ; // Enable mmio, everything else untouched
}
//=================================================
//
// Set pixel clock VCLK1
// - multipliers set elswhere
// - freq in units of 0.01 MHz
//
//=================================================
static void set_vclk ( struct cyblafb_par * par , int freq )
{
u32 m , n , k ;
int f , fi , d , di ;
u8 lo = 0 , hi = 0 ;
d = 2000 ;
k = freq > = 10000 ? 0 : freq > = 5000 ? 1 : freq > = 2500 ? 2 : 3 ;
for ( m = 0 ; m < 64 ; m + + )
for ( n = 0 ; n < 250 ; n + + ) { // max 249 is a hardware limit for cybla/i1 !
fi = ( int ) ( ( ( 5864727 * ( n + 8 ) ) / ( ( m + 2 ) * ( 1 < < k ) ) ) > > 12 ) ;
if ( ( di = abs ( fi - freq ) ) < d ) {
d = di ;
f = fi ;
lo = ( u8 ) n ;
hi = ( u8 ) ( ( k < < 6 ) | m ) ;
}
}
write3C4 ( SR19 , hi ) ;
write3C4 ( SR18 , lo ) ;
if ( verbosity > 1 )
output ( " pixclock = %d.%02d MHz, k/m/n %x %x %x \n " ,
freq / 100 , freq % 100 , ( hi & 0xc0 ) > > 6 , hi & 0x3f , lo ) ;
}
//================================================
//
// Cyberblade specific Graphics Engine (GE) setup
//
//================================================
static void cyblafb_setup_GE ( int pitch , int bpp )
{
int base = ( pitch > > 3 ) < < 20 ;
switch ( bpp ) {
case 8 : base | = ( 0 < < 29 ) ; break ;
case 15 : base | = ( 5 < < 29 ) ; break ;
case 16 : base | = ( 1 < < 29 ) ; break ;
case 24 :
case 32 : base | = ( 2 < < 29 ) ; break ;
}
write3X4 ( CR36 , 0x90 ) ; // reset GE
write3X4 ( CR36 , 0x80 ) ; // enable GE
out32 ( GE24 , 1 < < 7 ) ; // reset all GE pointers
out32 ( GE24 , 0 ) ;
write3X4 ( CR2D , 0x00 ) ; // GE Timinigs, no delays
out32 ( GEB8 , base ) ; // Destination Stride / Buffer Base 0, p 133
out32 ( GEBC , base ) ; // Destination Stride / Buffer Base 1, p 133
out32 ( GEC0 , base ) ; // Destination Stride / Buffer Base 2, p 133
out32 ( GEC4 , base ) ; // Destination Stride / Buffer Base 3, p 133
out32 ( GEC8 , base ) ; // Source Stride / Buffer Base 0, p 133
out32 ( GECC , base ) ; // Source Stride / Buffer Base 1, p 133
out32 ( GED0 , base ) ; // Source Stride / Buffer Base 2, p 133
out32 ( GED4 , base ) ; // Source Stride / Buffer Base 3, p 133
out32 ( GE6C , 0 ) ; // Pattern and Style, p 129, ok
}
//=====================================================================
//
// Although this is a .fb_sync function that could be enabled in
// cyblafb_ops, we do not include it there. We sync immediately before
// new GE operations to improve performance.
//
//=====================================================================
static int cyblafb_sync ( struct fb_info * info )
{
int status , i = 100000 ;
while ( ( ( status = in32 ( GE20 ) ) & 0xFA800000 ) & & i ! = 0 )
i - - ;
if ( i = = 0 ) {
// The timeout might be caused by disabled mmio.
// Cause:
// - bit CR39 & 1 == 0 upon return, X trident driver bug
// - kdm bug (KD_GRAPHICS not set on first switch)
// - kernel design flaw (it believes in the correctness
// of kdm/X
// So we make sure that mmio is enabled first ...
enable_mmio ( ) ;
// show_trace(NULL,&status);
i = 1000000 ;
while ( ( ( status = in32 ( GE20 ) ) & 0xFA800000 ) & & i ! = 0 )
i - - ;
if ( i = = 0 ) {
output ( " GE Timeout, status: %x \n " , status ) ;
if ( status & 0x80000000 )
output ( " Bresenham Engine : Busy \n " ) ;
if ( status & 0x40000000 )
output ( " Setup Engine : Busy \n " ) ;
if ( status & 0x20000000 )
output ( " SP / DPE : Busy \n " ) ;
if ( status & 0x10000000 )
output ( " Memory Interface : Busy \n " ) ;
if ( status & 0x08000000 )
output ( " Com Lst Proc : Busy \n " ) ;
if ( status & 0x04000000 )
output ( " Block Write : Busy \n " ) ;
if ( status & 0x02000000 )
output ( " Command Buffer : Full \n " ) ;
if ( status & 0x01000000 )
output ( " RESERVED : Busy \n " ) ;
if ( status & 0x00800000 )
output ( " PCI Write Buffer : Busy \n " ) ;
cyblafb_setup_GE ( info - > var . xres ,
info - > var . bits_per_pixel ) ;
}
}
return 0 ;
}
//==============================
//
// Cyberblade specific fillrect
//
//==============================
static void cyblafb_fillrect ( struct fb_info * info ,
const struct fb_fillrect * fr )
{
int bpp = info - > var . bits_per_pixel ;
int col ;
switch ( bpp ) {
default :
case 8 : col = fr - > color ;
col | = col < < 8 ;
col | = col < < 16 ;
break ;
case 16 : col = ( ( u32 * ) ( info - > pseudo_palette ) ) [ fr - > color ] ;
col | = col < < 16 ;
break ;
case 32 : col = ( ( u32 * ) ( info - > pseudo_palette ) ) [ fr - > color ] ;
break ;
}
cyblafb_sync ( info ) ;
out32 ( GE60 , col ) ;
out32 ( GE48 , fr - > rop ? 0x66 : ROP_S ) ;
out32 ( GE44 , 0x20000000 | 1 < < 19 | 1 < < 4 | 2 < < 2 ) ;
out32 ( GE08 , point ( fr - > dx , fr - > dy ) ) ;
out32 ( GE0C , point ( fr - > dx + fr - > width - 1 , fr - > dy + fr - > height - 1 ) ) ;
}
//==============================
//
// Cyberblade specific copyarea
//
//==============================
static void cyblafb_copyarea ( struct fb_info * info ,
const struct fb_copyarea * ca )
{
__u32 s1 , s2 , d1 , d2 ;
int direction ;
s1 = point ( ca - > sx , ca - > sy ) ;
s2 = point ( ca - > sx + ca - > width - 1 , ca - > sy + ca - > height - 1 ) ;
d1 = point ( ca - > dx , ca - > dy ) ;
d2 = point ( ca - > dx + ca - > width - 1 , ca - > dy + ca - > height - 1 ) ;
if ( ( ca - > sy > ca - > dy ) | | ( ( ca - > sy = = ca - > dy ) & & ( ca - > sx > ca - > dx ) ) )
direction = 0 ;
else
direction = 2 ;
cyblafb_sync ( info ) ;
out32 ( GE44 , 0xa0000000 | 1 < < 19 | 1 < < 2 | direction ) ;
out32 ( GE00 , direction ? s2 : s1 ) ;
out32 ( GE04 , direction ? s1 : s2 ) ;
out32 ( GE08 , direction ? d2 : d1 ) ;
out32 ( GE0C , direction ? d1 : d2 ) ;
}
//=======================================================================
//
// Cyberblade specific imageblit
//
// Accelerated for the most usual case, blitting 1-bit deep character
// character images. Everything else is passed to the generic imageblit.
//
//=======================================================================
static void cyblafb_imageblit ( struct fb_info * info ,
const struct fb_image * image )
{
u32 fgcol , bgcol ;
int i ;
int bpp = info - > var . bits_per_pixel ;
int index = 0 ;
int index_end = image - > height * image - > width / 8 ;
int width_dds = image - > width / 32 ;
int width_dbs = image - > width % 32 ;
if ( image - > depth ! = 1 | | bpp < 8 | | bpp > 32 | | bpp % 8 ! = 0 | |
image - > width % 8 ! = 0 | | image - > width = = 0 | | image - > height = = 0 ) {
cfb_imageblit ( info , image ) ;
return ;
}
if ( info - > fix . visual = = FB_VISUAL_TRUECOLOR | |
info - > fix . visual = = FB_VISUAL_DIRECTCOLOR ) {
fgcol = ( ( u32 * ) ( info - > pseudo_palette ) ) [ image - > fg_color ] ;
bgcol = ( ( u32 * ) ( info - > pseudo_palette ) ) [ image - > bg_color ] ;
} else {
fgcol = image - > fg_color ;
bgcol = image - > bg_color ;
}
switch ( bpp ) {
case 8 :
fgcol | = fgcol < < 8 ; fgcol | = fgcol < < 16 ;
bgcol | = bgcol < < 8 ; bgcol | = bgcol < < 16 ;
break ;
case 16 :
fgcol | = fgcol < < 16 ;
bgcol | = bgcol < < 16 ;
break ;
default :
break ;
}
cyblafb_sync ( info ) ;
out32 ( GE60 , fgcol ) ;
out32 ( GE64 , bgcol ) ;
out32 ( GE44 , 0xa0000000 | 1 < < 20 | 1 < < 19 ) ;
out32 ( GE08 , point ( image - > dx , image - > dy ) ) ;
out32 ( GE0C , point ( image - > dx + image - > width - 1 , image - > dy + image - > height - 1 ) ) ;
while ( index < index_end ) {
2005-09-29 03:07:29 +04:00
const char * p = image - > data + index ;
2005-09-10 00:04:56 +04:00
for ( i = 0 ; i < width_dds ; i + + ) {
2005-09-29 03:07:29 +04:00
out32 ( GE9C , * ( u32 * ) p ) ;
p + = 4 ;
2005-09-10 00:04:56 +04:00
index + = 4 ;
}
switch ( width_dbs ) {
case 0 : break ;
2005-09-29 03:07:29 +04:00
case 8 : out32 ( GE9C , * ( u8 * ) p ) ;
2005-09-10 00:04:56 +04:00
index + = 1 ;
break ;
2005-09-29 03:07:29 +04:00
case 16 : out32 ( GE9C , * ( u16 * ) p ) ;
2005-09-10 00:04:56 +04:00
index + = 2 ;
break ;
2005-09-29 03:07:29 +04:00
case 24 : out32 ( GE9C , * ( u16 * ) p | * ( u8 * ) ( p + 2 ) < < 16 ) ;
2005-09-10 00:04:56 +04:00
index + = 3 ;
break ;
}
}
}
//==========================================================
//
// Check if video mode is acceptable. We change var->??? if
// video mode is slightly off or return error otherwise.
// info->??? must not be changed!
//
//==========================================================
static int cyblafb_check_var ( struct fb_var_screeninfo * var ,
struct fb_info * info )
{
int bpp = var - > bits_per_pixel ;
int s , t , maxvyres ;
//
// we try to support 8, 16, 24 and 32 bpp modes,
// default to 8
//
// there is a 24 bpp mode, but for now we change requests to 32 bpp
// (This is what tridentfb does ... will be changed in the future)
//
//
if ( bpp % 8 ! = 0 | | bpp < 8 | | bpp > 32 )
bpp = 8 ;
if ( bpp = = 24 )
bpp = var - > bits_per_pixel = 32 ;
//
// interlaced modes are broken, fail if one is requested
//
if ( var - > vmode & FB_VMODE_INTERLACED )
return - EINVAL ;
//
// fail if requested resolution is higher than physical
// flatpanel resolution
//
if ( ( displaytype = = DISPLAY_FP ) & & nativex & & var - > xres > nativex )
return - EINVAL ;
//
// xres != xres_virtual is broken, fail if such an
// unusual mode is requested
//
if ( var - > xres ! = var - > xres_virtual )
return - EINVAL ;
//
// we do not allow vclk to exceed 230 MHz
//
if ( ( bpp = = 32 ? 200000000 : 100000000 ) / var - > pixclock > 23000 )
return - EINVAL ;
//
// calc max yres_virtual that would fit in memory
// and max yres_virtual that could be used for scrolling
// and use minimum of the results as maxvyres
//
// adjust vyres_virtual to maxvyres if necessary
// fail if requested yres is bigger than maxvyres
//
s = ( 0x1fffff / ( var - > xres * bpp / 8 ) ) + var - > yres ;
t = info - > fix . smem_len / ( var - > xres * bpp / 8 ) ;
maxvyres = t < s ? t : s ;
if ( maxvyres < var - > yres_virtual )
var - > yres_virtual = maxvyres ;
if ( maxvyres < var - > yres )
return - EINVAL ;
switch ( bpp ) {
case 8 :
var - > red . offset = 0 ;
var - > green . offset = 0 ;
var - > blue . offset = 0 ;
var - > red . length = 6 ;
var - > green . length = 6 ;
var - > blue . length = 6 ;
break ;
case 16 :
var - > red . offset = 11 ;
var - > green . offset = 5 ;
var - > blue . offset = 0 ;
var - > red . length = 5 ;
var - > green . length = 6 ;
var - > blue . length = 5 ;
break ;
case 32 :
var - > red . offset = 16 ;
var - > green . offset = 8 ;
var - > blue . offset = 0 ;
var - > red . length = 8 ;
var - > green . length = 8 ;
var - > blue . length = 8 ;
break ;
default :
return - EINVAL ;
}
return 0 ;
}
//=====================================================================
//
// Pan the display
//
// The datasheets defines crt start address to be 20 bits wide and
// to be programmed to CR0C, CR0D, CR1E and CR27. Actually there is
// CR2B[5] as an undocumented extension bit. Epia BIOS 2.07 does use
// it, so it is also safe to be used here. BTW: datasheet CR0E on page
// 90 really is CR1E, the real CRE is documented on page 72.
//
//=====================================================================
static int cyblafb_pan_display ( struct fb_var_screeninfo * var ,
struct fb_info * info )
{
unsigned int offset ;
offset = ( var - > xoffset + ( var - > yoffset * var - > xres ) ) * var - > bits_per_pixel / 32 ;
info - > var . xoffset = var - > xoffset ;
info - > var . yoffset = var - > yoffset ;
write3X4 ( CR0D , offset & 0xFF ) ;
write3X4 ( CR0C , ( offset & 0xFF00 ) > > 8 ) ;
write3X4 ( CR1E , ( read3X4 ( CR1E ) & 0xDF ) | ( ( offset & 0x10000 ) > > 11 ) ) ;
write3X4 ( CR27 , ( read3X4 ( CR27 ) & 0xF8 ) | ( ( offset & 0xE0000 ) > > 17 ) ) ;
write3X4 ( CR2B , ( read3X4 ( CR2B ) & 0xDF ) | ( ( offset & 0x100000 ) > > 15 ) ) ;
return 0 ;
}
//============================================
//
// This will really help in case of a bug ...
// dump most gaphics core registers.
//
//============================================
static void regdump ( struct cyblafb_par * par )
{
int i ;
if ( verbosity < 2 )
return ;
printk ( " \n " ) ;
for ( i = 0 ; i < = 0xff ; i + + ) {
outb ( i , 0x3d4 ) ;
printk ( " CR%02x=%02x " , i , inb ( 0x3d5 ) ) ;
if ( i % 16 = = 15 )
printk ( " \n " ) ;
}
outb ( 0x30 , 0x3ce ) ;
outb ( inb ( 0x3cf ) | 0x40 , 0x3cf ) ;
for ( i = 0 ; i < = 0x1f ; i + + ) {
if ( i = = 0 | | ( i > 2 & & i < 8 ) | | i = = 0x10 | | i = = 0x11 | | i = = 0x16 ) {
outb ( i , 0x3d4 ) ;
printk ( " CR%02x=%02x " , i , inb ( 0x3d5 ) ) ;
} else
printk ( " ------- " ) ;
if ( i % 16 = = 15 )
printk ( " \n " ) ;
}
outb ( 0x30 , 0x3ce ) ;
outb ( inb ( 0x3cf ) & 0xbf , 0x3cf ) ;
printk ( " \n " ) ;
for ( i = 0 ; i < = 0x7f ; i + + ) {
outb ( i , 0x3ce ) ;
printk ( " GR%02x=%02x " , i , inb ( 0x3cf ) ) ;
if ( i % 16 = = 15 )
printk ( " \n " ) ;
}
printk ( " \n " ) ;
for ( i = 0 ; i < = 0xff ; i + + ) {
outb ( i , 0x3c4 ) ;
printk ( " SR%02x=%02x " , i , inb ( 0x3c5 ) ) ;
if ( i % 16 = = 15 )
printk ( " \n " ) ;
}
printk ( " \n " ) ;
for ( i = 0 ; i < = 0x1F ; i + + ) {
inb ( 0x3da ) ; // next access is index!
outb ( i , 0x3c0 ) ;
printk ( " AR%02x=%02x " , i , inb ( 0x3c1 ) ) ;
if ( i % 16 = = 15 )
printk ( " \n " ) ;
}
printk ( " \n " ) ;
inb ( 0x3DA ) ; // reset internal flag to 3c0 index
outb ( 0x20 , 0x3C0 ) ; // enable attr
return ;
}
//======================================
//
// Set hardware to requested video mode
//
//======================================
static int cyblafb_set_par ( struct fb_info * info )
{
struct cyblafb_par * par = info - > par ;
u32
htotal , hdispend , hsyncstart , hsyncend , hblankstart , hblankend , preendfetch ,
vtotal , vdispend , vsyncstart , vsyncend , vblankstart , vblankend ;
struct fb_var_screeninfo * var = & info - > var ;
int bpp = var - > bits_per_pixel ;
int i ;
if ( verbosity > 0 )
output ( " Switching to new mode: "
" fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d \n " ,
var - > xres , var - > yres , var - > xres_virtual ,
var - > yres_virtual , var - > bits_per_pixel , var - > pixclock ,
var - > left_margin , var - > right_margin , var - > upper_margin ,
var - > lower_margin , var - > hsync_len , var - > vsync_len ) ;
htotal = ( var - > xres + var - > left_margin + var - > right_margin +
var - > hsync_len ) / 8 - 5 ;
hdispend = var - > xres / 8 - 1 ;
hsyncstart = ( var - > xres + var - > right_margin ) / 8 ;
hsyncend = var - > hsync_len / 8 ;
hblankstart = hdispend + 1 ;
hblankend = htotal + 3 ; // should be htotal + 5, bios does it this way
preendfetch = ( ( var - > xres > > 3 ) + 1 ) * ( ( bpp + 1 ) > > 3 ) ;
vtotal = var - > yres + var - > upper_margin + var - > lower_margin +
var - > vsync_len - 2 ;
vdispend = var - > yres - 1 ;
vsyncstart = var - > yres + var - > lower_margin ;
vblankstart = var - > yres ;
vblankend = vtotal ; // should be vtotal + 2, but bios does it this way
vsyncend = var - > vsync_len ;
enable_mmio ( ) ; // necessary! ... check X ...
write3X4 ( CR11 , read3X4 ( CR11 ) & 0x7F ) ; // unlock cr00 .. cr07
write3CE ( GR30 , 8 ) ;
if ( ( displaytype = = DISPLAY_FP ) & & var - > xres < nativex ) {
// stretch or center ?
out8 ( 0x3C2 , 0xEB ) ;
write3CE ( GR30 , read3CE ( GR30 ) | 0x81 ) ; // shadow mode on
if ( center ) {
write3CE ( GR52 , ( read3CE ( GR52 ) & 0x7C ) | 0x80 ) ;
write3CE ( GR53 , ( read3CE ( GR53 ) & 0x7C ) | 0x80 ) ;
}
else if ( stretch ) {
write3CE ( GR5D , 0 ) ;
write3CE ( GR52 , ( read3CE ( GR52 ) & 0x7C ) | 1 ) ;
write3CE ( GR53 , ( read3CE ( GR53 ) & 0x7C ) | 1 ) ;
}
} else {
out8 ( 0x3C2 , 0x2B ) ;
write3CE ( GR30 , 8 ) ;
}
//
// Setup CRxx regs
//
write3X4 ( CR00 , htotal & 0xFF ) ;
write3X4 ( CR01 , hdispend & 0xFF ) ;
write3X4 ( CR02 , hblankstart & 0xFF ) ;
write3X4 ( CR03 , hblankend & 0x1F ) ;
write3X4 ( CR04 , hsyncstart & 0xFF ) ;
write3X4 ( CR05 , ( hsyncend & 0x1F ) | ( ( hblankend & 0x20 ) < < 2 ) ) ;
write3X4 ( CR06 , vtotal & 0xFF ) ;
write3X4 ( CR07 , ( vtotal & 0x100 ) > > 8 |
( vdispend & 0x100 ) > > 7 |
( vsyncstart & 0x100 ) > > 6 |
( vblankstart & 0x100 ) > > 5 |
0x10 |
( vtotal & 0x200 ) > > 4 |
( vdispend & 0x200 ) > > 3 |
( vsyncstart & 0x200 ) > > 2 ) ;
write3X4 ( CR08 , 0 ) ;
write3X4 ( CR09 , ( vblankstart & 0x200 ) > > 4 | 0x40 | // FIX !!!
( ( info - > var . vmode & FB_VMODE_DOUBLE ) ? 0x80 : 0 ) ) ;
write3X4 ( CR0A , 0 ) ; // Init to some reasonable default
write3X4 ( CR0B , 0 ) ; // Init to some reasonable default
write3X4 ( CR0C , 0 ) ; // Offset 0
write3X4 ( CR0D , 0 ) ; // Offset 0
write3X4 ( CR0E , 0 ) ; // Init to some reasonable default
write3X4 ( CR0F , 0 ) ; // Init to some reasonable default
write3X4 ( CR10 , vsyncstart & 0xFF ) ;
write3X4 ( CR11 , ( vsyncend & 0x0F ) ) ;
write3X4 ( CR12 , vdispend & 0xFF ) ;
write3X4 ( CR13 , ( ( info - > var . xres * bpp ) / ( 4 * 16 ) ) & 0xFF ) ;
write3X4 ( CR14 , 0x40 ) ; // double word mode
write3X4 ( CR15 , vblankstart & 0xFF ) ;
write3X4 ( CR16 , vblankend & 0xFF ) ;
write3X4 ( CR17 , 0xC3 ) ;
write3X4 ( CR18 , 0xFF ) ;
// CR19: needed for interlaced modes ... ignore it for now
write3X4 ( CR1A , 0x07 ) ; // Arbitration Control Counter 1
write3X4 ( CR1B , 0x07 ) ; // Arbitration Control Counter 2
write3X4 ( CR1C , 0x07 ) ; // Arbitration Control Counter 3
write3X4 ( CR1D , 0x00 ) ; // Don't know, doesn't hurt ;-)
write3X4 ( CR1E , ( info - > var . vmode & FB_VMODE_INTERLACED ) ? 0x84 : 0x80 ) ;
// CR1F: do not set, contains BIOS info about memsize
write3X4 ( CR20 , 0x20 ) ; // enabe wr buf, disable 16bit planar mode
write3X4 ( CR21 , 0x20 ) ; // enable linear memory access
// CR22: RO cpu latch readback
// CR23: ???
// CR24: RO AR flag state
// CR25: RAMDAC rw timing, pclk buffer tristate control ????
// CR26: ???
write3X4 ( CR27 , ( vdispend & 0x400 ) > > 6 |
( vsyncstart & 0x400 ) > > 5 |
( vblankstart & 0x400 ) > > 4 |
( vtotal & 0x400 ) > > 3 |
0x8 ) ;
// CR28: ???
write3X4 ( CR29 , ( read3X4 ( CR29 ) & 0xCF ) |
( ( ( ( info - > var . xres * bpp ) / ( 4 * 16 ) ) & 0x300 ) > > 4 ) ) ;
write3X4 ( CR2A , read3X4 ( CR2A ) | 0x40 ) ;
write3X4 ( CR2B , ( htotal & 0x100 ) > > 8 |
( hdispend & 0x100 ) > > 7 |
// (0x00 & 0x100) >> 6 | hinterlace para bit 8 ???
( hsyncstart & 0x100 ) > > 5 |
( hblankstart & 0x100 ) > > 4 ) ;
// CR2C: ???
// CR2D: initialized in cyblafb_setup_GE()
write3X4 ( CR2F , 0x92 ) ; // conservative, better signal quality
// CR30: reserved
// CR31: reserved
// CR32: reserved
// CR33: reserved
// CR34: disabled in CR36
// CR35: disabled in CR36
// CR36: initialized in cyblafb_setup_GE
// CR37: i2c, ignore for now
write3X4 ( CR38 , ( bpp = = 8 ) ? 0x00 : //
( bpp = = 16 ) ? 0x05 : // highcolor
( bpp = = 24 ) ? 0x29 : // packed 24bit truecolor
( bpp = = 32 ) ? 0x09 : 0 ) ; // truecolor, 16 bit pixelbus
write3X4 ( CR39 , 0x01 | // MMIO enable
( pcirb ? 0x02 : 0 ) | // pci read burst enable
( pciwb ? 0x04 : 0 ) ) ; // pci write burst enable
write3X4 ( CR55 , 0x1F | // pci clocks * 2 for STOP# during 1st data phase
( pcirr ? 0x40 : 0 ) | // pci read retry enable
( pciwr ? 0x80 : 0 ) ) ; // pci write retry enable
write3X4 ( CR56 , preendfetch > > 8 < 2 ? ( preendfetch > > 8 & 0x01 ) | 2 : 0 ) ;
write3X4 ( CR57 , preendfetch > > 8 < 2 ? preendfetch & 0xff : 0 ) ;
write3X4 ( CR58 , 0x82 ) ; // Bios does this .... don't know more
//
// Setup SRxx regs
//
write3C4 ( SR00 , 3 ) ;
write3C4 ( SR01 , 1 ) ; //set char clock 8 dots wide
write3C4 ( SR02 , 0x0F ) ; //enable 4 maps needed in chain4 mode
write3C4 ( SR03 , 0 ) ; //no character map select
write3C4 ( SR04 , 0x0E ) ; //memory mode: ext mem, even, chain4
out8 ( 0x3C4 , 0x0b ) ;
in8 ( 0x3C5 ) ; // Set NEW mode
write3C4 ( SR0D , 0x00 ) ; // test ... check
set_vclk ( par , ( bpp = = 32 ? 200000000 : 100000000 ) /
info - > var . pixclock ) ; //SR18,SR19
//
// Setup GRxx regs
//
write3CE ( GR00 , 0x00 ) ; // test ... check
write3CE ( GR01 , 0x00 ) ; // test ... check
write3CE ( GR02 , 0x00 ) ; // test ... check
write3CE ( GR03 , 0x00 ) ; // test ... check
write3CE ( GR04 , 0x00 ) ; // test ... check
write3CE ( GR05 , 0x40 ) ; // no CGA compat,allow 256 col
write3CE ( GR06 , 0x05 ) ; // graphics mode
write3CE ( GR07 , 0x0F ) ; // planes?
write3CE ( GR08 , 0xFF ) ; // test ... check
write3CE ( GR0F , ( bpp = = 32 ) ? 0x1A : 0x12 ) ; // div vclk by 2 if 32bpp, chain4
write3CE ( GR20 , 0xC0 ) ; // test ... check
write3CE ( GR2F , 0xA0 ) ; // PCLK = VCLK, no skew,
//
// Setup ARxx regs
//
for ( i = 0 ; i < 0x10 ; i + + ) // set AR00 .. AR0f
write3C0 ( i , i ) ;
write3C0 ( AR10 , 0x41 ) ; // graphics mode and support 256 color modes
write3C0 ( AR12 , 0x0F ) ; // planes
write3C0 ( AR13 , 0 ) ; // horizontal pel panning
in8 ( 0x3DA ) ; // reset internal flag to 3c0 index
out8 ( 0x3C0 , 0x20 ) ; // enable attr
//
// Setup hidden RAMDAC command register
//
in8 ( 0x3C8 ) ; // these reads are
in8 ( 0x3C6 ) ; // necessary to
in8 ( 0x3C6 ) ; // unmask the RAMDAC
in8 ( 0x3C6 ) ; // command reg, otherwise
in8 ( 0x3C6 ) ; // we would write the pixelmask reg!
out8 ( 0x3C6 , ( bpp = = 8 ) ? 0x00 : // 256 colors
( bpp = = 15 ) ? 0x10 : //
( bpp = = 16 ) ? 0x30 : // hicolor
( bpp = = 24 ) ? 0xD0 : // truecolor
( bpp = = 32 ) ? 0xD0 : 0 ) ; // truecolor
in8 ( 0x3C8 ) ;
//
// GR31 is not mentioned in the datasheet
//
if ( displaytype = = DISPLAY_FP )
write3CE ( GR31 , ( read3CE ( GR31 ) & 0x8F ) |
( ( info - > var . yres > 1024 ) ? 0x50 :
( info - > var . yres > 768 ) ? 0x30 :
( info - > var . yres > 600 ) ? 0x20 :
( info - > var . yres > 480 ) ? 0x10 : 0 ) ) ;
info - > fix . visual = ( bpp = = 8 ) ? FB_VISUAL_PSEUDOCOLOR
: FB_VISUAL_TRUECOLOR ;
info - > fix . line_length = info - > var . xres * ( bpp > > 3 ) ;
info - > cmap . len = ( bpp = = 8 ) ? 256 : 16 ;
//
// init acceleration engine
//
cyblafb_setup_GE ( info - > var . xres , info - > var . bits_per_pixel ) ;
regdump ( par ) ;
return 0 ;
}
//========================
//
// Set one color register
//
//========================
static int cyblafb_setcolreg ( unsigned regno , unsigned red , unsigned green ,
unsigned blue , unsigned transp ,
struct fb_info * info )
{
int bpp = info - > var . bits_per_pixel ;
if ( regno > = info - > cmap . len )
return 1 ;
if ( bpp = = 8 ) {
out8 ( 0x3C6 , 0xFF ) ;
out8 ( 0x3C8 , regno ) ;
out8 ( 0x3C9 , red > > 10 ) ;
out8 ( 0x3C9 , green > > 10 ) ;
out8 ( 0x3C9 , blue > > 10 ) ;
} else if ( bpp = = 16 ) // RGB 565
( ( u32 * ) info - > pseudo_palette ) [ regno ] =
( red & 0xF800 ) |
( ( green & 0xFC00 ) > > 5 ) |
( ( blue & 0xF800 ) > > 11 ) ;
else if ( bpp = = 32 ) // ARGB 8888
( ( u32 * ) info - > pseudo_palette ) [ regno ] =
( ( transp & 0xFF00 ) < < 16 ) |
( ( red & 0xFF00 ) < < 8 ) |
( ( green & 0xFF00 ) ) |
( ( blue & 0xFF00 ) > > 8 ) ;
return 0 ;
}
//==========================================================
//
// Try blanking the screen. For flat panels it does nothing
//
//==========================================================
static int cyblafb_blank ( int blank_mode , struct fb_info * info )
{
unsigned char PMCont , DPMSCont ;
if ( displaytype = = DISPLAY_FP )
return 0 ;
out8 ( 0x83C8 , 0x04 ) ; // DPMS Control
PMCont = in8 ( 0x83C6 ) & 0xFC ;
DPMSCont = read3CE ( GR23 ) & 0xFC ;
switch ( blank_mode )
{
case FB_BLANK_UNBLANK : // Screen: On, HSync: On, VSync: On
case FB_BLANK_NORMAL : // Screen: Off, HSync: On, VSync: On
PMCont | = 0x03 ;
DPMSCont | = 0x00 ;
break ;
case FB_BLANK_HSYNC_SUSPEND : // Screen: Off, HSync: Off, VSync: On
PMCont | = 0x02 ;
DPMSCont | = 0x01 ;
break ;
case FB_BLANK_VSYNC_SUSPEND : // Screen: Off, HSync: On, VSync: Off
PMCont | = 0x02 ;
DPMSCont | = 0x02 ;
break ;
case FB_BLANK_POWERDOWN : // Screen: Off, HSync: Off, VSync: Off
PMCont | = 0x00 ;
DPMSCont | = 0x03 ;
break ;
}
write3CE ( GR23 , DPMSCont ) ;
out8 ( 0x83C8 , 4 ) ;
out8 ( 0x83C6 , PMCont ) ;
//
// let fbcon do a softblank for us
//
return ( blank_mode = = FB_BLANK_NORMAL ) ? 1 : 0 ;
}
static struct fb_ops cyblafb_ops __devinitdata = {
. owner = THIS_MODULE ,
. fb_setcolreg = cyblafb_setcolreg ,
. fb_pan_display = cyblafb_pan_display ,
. fb_blank = cyblafb_blank ,
. fb_check_var = cyblafb_check_var ,
. fb_set_par = cyblafb_set_par ,
. fb_fillrect = cyblafb_fillrect ,
. fb_copyarea = cyblafb_copyarea ,
. fb_imageblit = cyblafb_imageblit ,
} ;
//==========================================================================
//
// getstartupmode() decides about the inital video mode
//
// There is no reason to use modedb, a lot of video modes there would
// need altered timings to display correctly. So I decided that it is much
// better to provide a limited optimized set of modes plus the option of
// using the mode in effect at startup time (might be selected using the
// vga=??? paramter). After that the user might use fbset to select any
// mode he likes, check_var will not try to alter geometry parameters as
// it would be necessary otherwise.
//
//==========================================================================
static int __devinit getstartupmode ( struct fb_info * info )
{
u32 htotal , hdispend , hsyncstart , hsyncend , hblankstart , hblankend ,
vtotal , vdispend , vsyncstart , vsyncend , vblankstart , vblankend ,
cr00 , cr01 , cr02 , cr03 , cr04 , cr05 , cr2b ,
cr06 , cr07 , cr09 , cr10 , cr11 , cr12 , cr15 , cr16 , cr27 ,
cr38 ,
sr0d , sr18 , sr19 ,
gr0f ,
fi , pxclkdiv , vclkdiv , tmp , i ;
struct modus {
int xres ; int yres ; int vyres ; int bpp ; int pxclk ;
int left_margin ; int right_margin ; int upper_margin ;
int lower_margin ; int hsync_len ; int vsync_len ;
} modedb [ 5 ] = {
{ 0 , 0 , 8000 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ 640 , 480 , 3756 , 0 , 0 , - 40 , 24 , 17 , 0 , 216 , 3 } ,
{ 800 , 600 , 3221 , 0 , 0 , 96 , 24 , 14 , 0 , 136 , 11 } ,
{ 1024 , 768 , 2815 , 0 , 0 , 144 , 24 , 29 , 0 , 120 , 3 } ,
{ 1280 , 1024 , 2662 , 0 , 0 , 232 , 16 , 39 , 0 , 160 , 3 }
} ;
outb ( 0x00 , 0x3d4 ) ; cr00 = inb ( 0x3d5 ) ; outb ( 0x01 , 0x3d4 ) ; cr01 = inb ( 0x3d5 ) ;
outb ( 0x02 , 0x3d4 ) ; cr02 = inb ( 0x3d5 ) ; outb ( 0x03 , 0x3d4 ) ; cr03 = inb ( 0x3d5 ) ;
outb ( 0x04 , 0x3d4 ) ; cr04 = inb ( 0x3d5 ) ; outb ( 0x05 , 0x3d4 ) ; cr05 = inb ( 0x3d5 ) ;
outb ( 0x06 , 0x3d4 ) ; cr06 = inb ( 0x3d5 ) ; outb ( 0x07 , 0x3d4 ) ; cr07 = inb ( 0x3d5 ) ;
outb ( 0x09 , 0x3d4 ) ; cr09 = inb ( 0x3d5 ) ; outb ( 0x10 , 0x3d4 ) ; cr10 = inb ( 0x3d5 ) ;
outb ( 0x11 , 0x3d4 ) ; cr11 = inb ( 0x3d5 ) ; outb ( 0x12 , 0x3d4 ) ; cr12 = inb ( 0x3d5 ) ;
outb ( 0x15 , 0x3d4 ) ; cr15 = inb ( 0x3d5 ) ; outb ( 0x16 , 0x3d4 ) ; cr16 = inb ( 0x3d5 ) ;
outb ( 0x27 , 0x3d4 ) ; cr27 = inb ( 0x3d5 ) ; outb ( 0x2b , 0x3d4 ) ; cr2b = inb ( 0x3d5 ) ;
outb ( 0x38 , 0x3d4 ) ; cr38 = inb ( 0x3d5 ) ; outb ( 0x0b , 0x3c4 ) ; inb ( 0x3c5 ) ;
outb ( 0x0d , 0x3c4 ) ; sr0d = inb ( 0x3c5 ) ; outb ( 0x18 , 0x3c4 ) ; sr18 = inb ( 0x3c5 ) ;
outb ( 0x19 , 0x3c4 ) ; sr19 = inb ( 0x3c5 ) ; outb ( 0x0f , 0x3ce ) ; gr0f = inb ( 0x3cf ) ;
htotal = cr00 | ( cr2b & 0x01 ) < < 8 ;
hdispend = cr01 | ( cr2b & 0x02 ) < < 7 ;
hblankstart = cr02 | ( cr2b & 0x10 ) < < 4 ;
hblankend = ( cr03 & 0x1f ) | ( cr05 & 0x80 ) > > 2 ;
hsyncstart = cr04 | ( cr2b & 0x08 ) < < 5 ;
hsyncend = cr05 & 0x1f ;
modedb [ 0 ] . xres = hblankstart * 8 ;
modedb [ 0 ] . hsync_len = hsyncend * 8 ;
modedb [ 0 ] . right_margin = hsyncstart * 8 - modedb [ 0 ] . xres ;
modedb [ 0 ] . left_margin = ( htotal + 5 ) * 8 - modedb [ 0 ] . xres -
modedb [ 0 ] . right_margin - modedb [ 0 ] . hsync_len ;
vtotal = cr06 | ( cr07 & 0x01 ) < < 8 | ( cr07 & 0x20 ) < < 4
| ( cr27 & 0x80 ) < < 3 ;
vdispend = cr12 | ( cr07 & 0x02 ) < < 7 | ( cr07 & 0x40 ) < < 3
| ( cr27 & 0x10 ) < < 6 ;
vsyncstart = cr10 | ( cr07 & 0x04 ) < < 6 | ( cr07 & 0x80 ) < < 2
| ( cr27 & 0x20 ) < < 5 ;
vsyncend = cr11 & 0x0f ;
vblankstart = cr15 | ( cr07 & 0x08 ) < < 5 | ( cr09 & 0x20 ) < < 4
| ( cr27 & 0x40 ) < < 4 ;
vblankend = cr16 ;
modedb [ 0 ] . yres = vdispend + 1 ;
modedb [ 0 ] . vsync_len = vsyncend ;
modedb [ 0 ] . lower_margin = vsyncstart - modedb [ 0 ] . yres ;
modedb [ 0 ] . upper_margin = vtotal - modedb [ 0 ] . yres -
modedb [ 0 ] . lower_margin - modedb [ 0 ] . vsync_len + 2 ;
tmp = cr38 & 0x3c ;
modedb [ 0 ] . bpp = tmp = = 0 ? 8 : tmp = = 4 ? 16 : tmp = = 28 ? 24 :
tmp = = 8 ? 32 : 8 ;
fi = ( ( 5864727 * ( sr18 + 8 ) ) / ( ( ( sr19 & 0x3f ) + 2 ) * ( 1 < < ( ( sr19 & 0xc0 ) > > 6 ) ) ) ) > > 12 ;
pxclkdiv = ( ( gr0f & 0x08 ) > > 3 | ( gr0f & 0x40 ) > > 5 ) + 1 ;
tmp = sr0d & 0x06 ;
vclkdiv = tmp = = 0 ? 2 : tmp = = 2 ? 4 : tmp = = 4 ? 8 : 3 ; // * 2 !
modedb [ 0 ] . pxclk = ( ( 100000000 * pxclkdiv * vclkdiv ) > > 1 ) / fi ;
if ( verbosity > 0 )
output ( " detected startup mode: "
" fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d \n " ,
modedb [ 0 ] . xres , modedb [ 0 ] . yres , modedb [ 0 ] . xres ,
modedb [ 0 ] . bpp , modedb [ 0 ] . pxclk , modedb [ 0 ] . left_margin ,
modedb [ 0 ] . right_margin , modedb [ 0 ] . upper_margin ,
modedb [ 0 ] . lower_margin , modedb [ 0 ] . hsync_len ,
modedb [ 0 ] . vsync_len ) ;
//
// We use this goto target in case of a failed check_var. No, I really
// do not want to do it in another way!
//
tryagain :
i = ( mode = = NULL ) ? 0 :
! strncmp ( mode , " 640x480 " , 7 ) ? 1 :
! strncmp ( mode , " 800x600 " , 7 ) ? 2 :
! strncmp ( mode , " 1024x768 " , 8 ) ? 3 :
! strncmp ( mode , " 1280x1024 " , 9 ) ? 4 : 0 ;
ref = ( ref < 50 ) ? 50 : ( ref > 85 ) ? 85 : ref ;
if ( i = = 0 ) {
info - > var . pixclock = modedb [ i ] . pxclk ;
info - > var . bits_per_pixel = modedb [ i ] . bpp ;
} else {
info - > var . pixclock = ( 100000000 /
( ( modedb [ i ] . left_margin + modedb [ i ] . xres +
modedb [ i ] . right_margin + modedb [ i ] . hsync_len
) * (
modedb [ i ] . upper_margin + modedb [ i ] . yres +
modedb [ i ] . lower_margin + modedb [ i ] . vsync_len
) *
ref / 10000
) ) ;
info - > var . bits_per_pixel = bpp ;
}
info - > var . left_margin = modedb [ i ] . left_margin ;
info - > var . right_margin = modedb [ i ] . right_margin ;
info - > var . xres = modedb [ i ] . xres ;
info - > var . xres_virtual = modedb [ i ] . xres ;
info - > var . xoffset = 0 ;
info - > var . hsync_len = modedb [ i ] . hsync_len ;
info - > var . upper_margin = modedb [ i ] . upper_margin ;
info - > var . yres = modedb [ i ] . yres ;
info - > var . yres_virtual = modedb [ i ] . vyres ;
info - > var . yoffset = 0 ;
info - > var . lower_margin = modedb [ i ] . lower_margin ;
info - > var . vsync_len = modedb [ i ] . vsync_len ;
info - > var . sync = 0 ;
info - > var . vmode = FB_VMODE_NONINTERLACED ;
if ( cyblafb_check_var ( & info - > var , info ) ) {
// 640x480-8@75 should really never fail. One case would
// be fp == 1 and nativex < 640 ... give up then
if ( i = = 1 & & bpp = = 8 & & ref = = 75 ) {
output ( " Can't find a valid mode :-( \n " ) ;
return - EINVAL ;
}
// Our detected mode is unlikely to fail. If it does,
// try 640x480-8@75 ...
if ( i = = 0 ) {
mode = " 640x480 " ;
bpp = 8 ;
ref = 75 ;
output ( " Detected mode failed check_var! "
" Trying 640x480-8@75 \n " ) ;
goto tryagain ;
}
// A specified video mode failed for some reason.
// Try the startup mode first
output ( " Specified mode '%s' failed check! "
" Falling back to startup mode. \n " , mode ) ;
mode = NULL ;
goto tryagain ;
}
return 0 ;
}
//========================================================
//
// Detect activated memory size. Undefined values require
// memsize parameter.
//
//========================================================
static unsigned int __devinit get_memsize ( void )
{
unsigned char tmp ;
unsigned int k ;
if ( memsize )
k = memsize * Kb ;
else {
tmp = read3X4 ( CR1F ) & 0x0F ;
switch ( tmp ) {
case 0x03 : k = 1 * Mb ; break ;
case 0x07 : k = 2 * Mb ; break ;
case 0x0F : k = 4 * Mb ; break ;
case 0x04 : k = 8 * Mb ; break ;
default :
k = 1 * Mb ;
output ( " Unknown memory size code %x in CR1F. "
" We default to 1 Mb for now, please "
" do provide a memsize parameter! \n " ,
tmp ) ;
}
}
if ( verbosity > 0 )
output ( " framebuffer size = %d Kb \n " , k / Kb ) ;
return k ;
}
//=========================================================
//
// Detect if a flat panel monitor connected to the special
// interface is active. Override is possible by fp and crt
// parameters.
//
//=========================================================
static unsigned int __devinit get_displaytype ( void )
{
if ( fp )
return DISPLAY_FP ;
if ( crt )
return DISPLAY_CRT ;
return ( read3CE ( GR33 ) & 0x10 ) ? DISPLAY_FP : DISPLAY_CRT ;
}
//=====================================
//
// Get native resolution of flat panel
//
//=====================================
static int __devinit get_nativex ( void )
{
int x , y , tmp ;
if ( nativex )
return nativex ;
tmp = ( read3CE ( GR52 ) > > 4 ) & 3 ;
switch ( tmp ) {
case 0 : x = 1280 ; y = 1024 ; break ;
case 2 : x = 1024 ; y = 768 ; break ;
case 3 : x = 800 ; y = 600 ; break ;
case 4 : x = 1400 ; y = 1050 ; break ;
case 1 :
default : x = 640 ; y = 480 ; break ;
}
if ( verbosity > 0 )
output ( " %dx%d flat panel found \n " , x , y ) ;
return x ;
}
static int __devinit cybla_pci_probe ( struct pci_dev * dev ,
const struct pci_device_id * id )
{
struct fb_info * info ;
struct cyblafb_par * par ;
info = framebuffer_alloc ( sizeof ( struct cyblafb_par ) , & dev - > dev ) ;
if ( ! info )
goto errout_alloc ;
par = info - > par ;
par - > ops = cyblafb_ops ;
info - > fix = cyblafb_fix ;
info - > fbops = & par - > ops ;
info - > fix = cyblafb_fix ;
if ( pci_enable_device ( dev ) ) {
output ( " could not enable device! \n " ) ;
goto errout_enable ;
}
// might already be requested by vga console or vesafb,
// so we do care about success
request_region ( 0x3c0 , 32 , " cyblafb " ) ;
//
// Graphics Engine Registers
//
request_region ( GEBase , 0x100 , " cyblafb " ) ;
regdump ( par ) ;
enable_mmio ( ) ;
// setup MMIO region
info - > fix . mmio_start = pci_resource_start ( dev , 1 ) ;
info - > fix . mmio_len = 0x20000 ;
if ( ! request_mem_region ( info - > fix . mmio_start ,
info - > fix . mmio_len , " cyblafb " ) ) {
output ( " request_mem_region failed for mmio region! \n " ) ;
goto errout_mmio_reqmem ;
}
io_virt = ioremap_nocache ( info - > fix . mmio_start , info - > fix . mmio_len ) ;
if ( ! io_virt ) {
output ( " ioremap failed for mmio region \n " ) ;
goto errout_mmio_remap ;
}
// setup framebuffer memory ... might already be requested
// by vesafb. Not to fail in case of an unsuccessful request
// is useful for the development cycle
info - > fix . smem_start = pci_resource_start ( dev , 0 ) ;
info - > fix . smem_len = get_memsize ( ) ;
if ( ! request_mem_region ( info - > fix . smem_start ,
info - > fix . smem_len , " cyblafb " ) ) {
output ( " request_mem_region failed for smem region! \n " ) ;
if ( ! vesafb )
goto errout_smem_req ;
}
info - > screen_base = ioremap_nocache ( info - > fix . smem_start ,
info - > fix . smem_len ) ;
if ( ! info - > screen_base ) {
output ( " ioremap failed for smem region \n " ) ;
goto errout_smem_remap ;
}
displaytype = get_displaytype ( ) ;
if ( displaytype = = DISPLAY_FP )
nativex = get_nativex ( ) ;
//
// FBINFO_HWACCEL_YWRAP .... does not work (could be made to work?)
// FBINFO_PARTIAL_PAN_OK .... is not ok
// FBINFO_READS_FAST .... is necessary for optimal scrolling
//
info - > flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN
| FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT
| FBINFO_HWACCEL_IMAGEBLIT | FBINFO_READS_FAST ;
info - > pseudo_palette = par - > pseudo_pal ;
if ( getstartupmode ( info ) )
goto errout_findmode ;
fb_alloc_cmap ( & info - > cmap , 256 , 0 ) ;
if ( register_framebuffer ( info ) ) {
output ( " Could not register CyBla framebuffer \n " ) ;
goto errout_register ;
}
pci_set_drvdata ( dev , info ) ;
//
// normal exit and error paths
//
return 0 ;
errout_register :
errout_findmode :
iounmap ( info - > screen_base ) ;
errout_smem_remap :
release_mem_region ( info - > fix . smem_start ,
info - > fix . smem_len ) ;
errout_smem_req :
iounmap ( io_virt ) ;
errout_mmio_remap :
release_mem_region ( info - > fix . mmio_start ,
info - > fix . mmio_len ) ;
errout_mmio_reqmem :
// release_region(0x3c0,32);
errout_enable :
framebuffer_release ( info ) ;
errout_alloc :
output ( " CyblaFB version %s aborting init. \n " , VERSION ) ;
return - ENODEV ;
}
static void __devexit cybla_pci_remove ( struct pci_dev * dev )
{
struct fb_info * info = pci_get_drvdata ( dev ) ;
unregister_framebuffer ( info ) ;
iounmap ( io_virt ) ;
iounmap ( info - > screen_base ) ;
release_mem_region ( info - > fix . smem_start , info - > fix . smem_len ) ;
release_mem_region ( info - > fix . mmio_start , info - > fix . mmio_len ) ;
fb_dealloc_cmap ( & info - > cmap ) ;
framebuffer_release ( info ) ;
output ( " CyblaFB version %s normal exit. \n " , VERSION ) ;
}
//
// List of boards that we are trying to support
//
static struct pci_device_id cybla_devices [ ] = {
{ PCI_VENDOR_ID_TRIDENT , CYBERBLADEi1 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ 0 , }
} ;
MODULE_DEVICE_TABLE ( pci , cybla_devices ) ;
static struct pci_driver cyblafb_pci_driver = {
. name = " cyblafb " ,
. id_table = cybla_devices ,
. probe = cybla_pci_probe ,
. remove = __devexit_p ( cybla_pci_remove )
} ;
//=============================================================
//
// kernel command line example:
//
// video=cyblafb:1280x1024,bpp=16,ref=50 ...
//
// modprobe command line example:
//
// modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ...
//
//=============================================================
static int __devinit cyblafb_init ( void )
{
# ifndef MODULE
char * options = NULL ;
char * opt ;
if ( fb_get_options ( " cyblafb " , & options ) )
return - ENODEV ;
if ( options & & * options )
while ( ( opt = strsep ( & options , " , " ) ) ! = NULL ) {
if ( ! * opt ) continue ;
else if ( ! strncmp ( opt , " bpp= " , 4 ) )
bpp = simple_strtoul ( opt + 4 , NULL , 0 ) ;
else if ( ! strncmp ( opt , " ref= " , 4 ) )
ref = simple_strtoul ( opt + 4 , NULL , 0 ) ;
else if ( ! strncmp ( opt , " fp " , 2 ) )
displaytype = DISPLAY_FP ;
else if ( ! strncmp ( opt , " crt " , 3 ) )
displaytype = DISPLAY_CRT ;
else if ( ! strncmp ( opt , " nativex= " , 8 ) )
nativex = simple_strtoul ( opt + 8 , NULL , 0 ) ;
else if ( ! strncmp ( opt , " center " , 6 ) )
center = 1 ;
else if ( ! strncmp ( opt , " stretch " , 7 ) )
stretch = 1 ;
else if ( ! strncmp ( opt , " pciwb= " , 6 ) )
pciwb = simple_strtoul ( opt + 6 , NULL , 0 ) ;
else if ( ! strncmp ( opt , " pcirb= " , 6 ) )
pcirb = simple_strtoul ( opt + 6 , NULL , 0 ) ;
else if ( ! strncmp ( opt , " pciwr= " , 6 ) )
pciwr = simple_strtoul ( opt + 6 , NULL , 0 ) ;
else if ( ! strncmp ( opt , " pcirr= " , 6 ) )
pcirr = simple_strtoul ( opt + 6 , NULL , 0 ) ;
else if ( ! strncmp ( opt , " memsize= " , 8 ) )
memsize = simple_strtoul ( opt + 8 , NULL , 0 ) ;
else if ( ! strncmp ( opt , " verbosity= " , 10 ) )
verbosity = simple_strtoul ( opt + 10 , NULL , 0 ) ;
else if ( ! strncmp ( opt , " vesafb " , 6 ) )
vesafb = 1 ;
else
mode = opt ;
}
# endif
output ( " CyblaFB version %s initializing \n " , VERSION ) ;
return pci_module_init ( & cyblafb_pci_driver ) ;
}
static void __exit cyblafb_exit ( void )
{
pci_unregister_driver ( & cyblafb_pci_driver ) ;
}
module_init ( cyblafb_init ) ;
module_exit ( cyblafb_exit ) ;
MODULE_AUTHOR ( " Knut Petersen <knut_petersen@t-online.de> " ) ;
MODULE_DESCRIPTION ( " Framebuffer driver for Cyberblade/i1 graphics core " ) ;
MODULE_LICENSE ( " GPL " ) ;