2007-02-12 11:54:49 +03:00
/*
* Common utility functions for VGA - based graphics cards .
*
* Copyright ( c ) 2006 - 2007 Ondrej Zajicek < santiago @ crfreenet . org >
*
* 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 .
*
* Some parts are based on David Boucher ' s viafb ( http : //davesdomain.org.uk/viafb/)
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/string.h>
# include <linux/fb.h>
# include <linux/svga.h>
# include <asm/types.h>
# include <asm/io.h>
/* Write a CRT register value spread across multiple registers */
void svga_wcrt_multi ( const struct vga_regset * regset , u32 value ) {
u8 regval , bitval , bitnum ;
while ( regset - > regnum ! = VGA_REGSET_END_VAL ) {
regval = vga_rcrt ( NULL , regset - > regnum ) ;
bitnum = regset - > lowbit ;
while ( bitnum < = regset - > highbit ) {
bitval = 1 < < bitnum ;
regval = regval & ~ bitval ;
if ( value & 1 ) regval = regval | bitval ;
bitnum + + ;
value = value > > 1 ;
}
vga_wcrt ( NULL , regset - > regnum , regval ) ;
regset + + ;
}
}
/* Write a sequencer register value spread across multiple registers */
void svga_wseq_multi ( const struct vga_regset * regset , u32 value ) {
u8 regval , bitval , bitnum ;
while ( regset - > regnum ! = VGA_REGSET_END_VAL ) {
regval = vga_rseq ( NULL , regset - > regnum ) ;
bitnum = regset - > lowbit ;
while ( bitnum < = regset - > highbit ) {
bitval = 1 < < bitnum ;
regval = regval & ~ bitval ;
if ( value & 1 ) regval = regval | bitval ;
bitnum + + ;
value = value > > 1 ;
}
vga_wseq ( NULL , regset - > regnum , regval ) ;
regset + + ;
}
}
static unsigned int svga_regset_size ( const struct vga_regset * regset )
{
u8 count = 0 ;
while ( regset - > regnum ! = VGA_REGSET_END_VAL ) {
count + = regset - > highbit - regset - > lowbit + 1 ;
regset + + ;
}
return 1 < < count ;
}
/* ------------------------------------------------------------------------- */
/* Set graphics controller registers to sane values */
void svga_set_default_gfx_regs ( void )
{
/* All standard GFX registers (GR00 - GR08) */
vga_wgfx ( NULL , VGA_GFX_SR_VALUE , 0x00 ) ;
vga_wgfx ( NULL , VGA_GFX_SR_ENABLE , 0x00 ) ;
vga_wgfx ( NULL , VGA_GFX_COMPARE_VALUE , 0x00 ) ;
vga_wgfx ( NULL , VGA_GFX_DATA_ROTATE , 0x00 ) ;
vga_wgfx ( NULL , VGA_GFX_PLANE_READ , 0x00 ) ;
vga_wgfx ( NULL , VGA_GFX_MODE , 0x00 ) ;
/* vga_wgfx(NULL, VGA_GFX_MODE, 0x20); */
/* vga_wgfx(NULL, VGA_GFX_MODE, 0x40); */
vga_wgfx ( NULL , VGA_GFX_MISC , 0x05 ) ;
/* vga_wgfx(NULL, VGA_GFX_MISC, 0x01); */
vga_wgfx ( NULL , VGA_GFX_COMPARE_MASK , 0x0F ) ;
vga_wgfx ( NULL , VGA_GFX_BIT_MASK , 0xFF ) ;
}
/* Set attribute controller registers to sane values */
void svga_set_default_atc_regs ( void )
{
u8 count ;
vga_r ( NULL , 0x3DA ) ;
vga_w ( NULL , VGA_ATT_W , 0x00 ) ;
/* All standard ATC registers (AR00 - AR14) */
for ( count = 0 ; count < = 0xF ; count + + )
svga_wattr ( count , count ) ;
svga_wattr ( VGA_ATC_MODE , 0x01 ) ;
/* svga_wattr(VGA_ATC_MODE, 0x41); */
svga_wattr ( VGA_ATC_OVERSCAN , 0x00 ) ;
svga_wattr ( VGA_ATC_PLANE_ENABLE , 0x0F ) ;
svga_wattr ( VGA_ATC_PEL , 0x00 ) ;
svga_wattr ( VGA_ATC_COLOR_PAGE , 0x00 ) ;
vga_r ( NULL , 0x3DA ) ;
vga_w ( NULL , VGA_ATT_W , 0x20 ) ;
}
/* Set sequencer registers to sane values */
void svga_set_default_seq_regs ( void )
{
/* Standard sequencer registers (SR01 - SR04), SR00 is not set */
vga_wseq ( NULL , VGA_SEQ_CLOCK_MODE , VGA_SR01_CHAR_CLK_8DOTS ) ;
vga_wseq ( NULL , VGA_SEQ_PLANE_WRITE , VGA_SR02_ALL_PLANES ) ;
vga_wseq ( NULL , VGA_SEQ_CHARACTER_MAP , 0x00 ) ;
/* vga_wseq(NULL, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM | VGA_SR04_SEQ_MODE | VGA_SR04_CHN_4M); */
vga_wseq ( NULL , VGA_SEQ_MEMORY_MODE , VGA_SR04_EXT_MEM | VGA_SR04_SEQ_MODE ) ;
}
/* Set CRTC registers to sane values */
void svga_set_default_crt_regs ( void )
{
/* Standard CRT registers CR03 CR08 CR09 CR14 CR17 */
svga_wcrt_mask ( 0x03 , 0x80 , 0x80 ) ; /* Enable vertical retrace EVRA */
vga_wcrt ( NULL , VGA_CRTC_PRESET_ROW , 0 ) ;
svga_wcrt_mask ( VGA_CRTC_MAX_SCAN , 0 , 0x1F ) ;
vga_wcrt ( NULL , VGA_CRTC_UNDERLINE , 0 ) ;
vga_wcrt ( NULL , VGA_CRTC_MODE , 0xE3 ) ;
}
void svga_set_textmode_vga_regs ( void )
{
/* svga_wseq_mask(0x1, 0x00, 0x01); */ /* Switch 8/9 pixel per char */
vga_wseq ( NULL , VGA_SEQ_MEMORY_MODE , VGA_SR04_EXT_MEM ) ;
vga_wseq ( NULL , VGA_SEQ_PLANE_WRITE , 0x03 ) ;
vga_wcrt ( NULL , VGA_CRTC_MAX_SCAN , 0x0f ) ; /* 0x4f */
vga_wcrt ( NULL , VGA_CRTC_UNDERLINE , 0x1f ) ;
svga_wcrt_mask ( VGA_CRTC_MODE , 0x23 , 0x7f ) ;
vga_wcrt ( NULL , VGA_CRTC_CURSOR_START , 0x0d ) ;
vga_wcrt ( NULL , VGA_CRTC_CURSOR_END , 0x0e ) ;
vga_wcrt ( NULL , VGA_CRTC_CURSOR_HI , 0x00 ) ;
vga_wcrt ( NULL , VGA_CRTC_CURSOR_LO , 0x00 ) ;
vga_wgfx ( NULL , VGA_GFX_MODE , 0x10 ) ; /* Odd/even memory mode */
vga_wgfx ( NULL , VGA_GFX_MISC , 0x0E ) ; /* Misc graphics register - text mode enable */
vga_wgfx ( NULL , VGA_GFX_COMPARE_MASK , 0x00 ) ;
vga_r ( NULL , 0x3DA ) ;
vga_w ( NULL , VGA_ATT_W , 0x00 ) ;
svga_wattr ( 0x10 , 0x0C ) ; /* Attribute Mode Control Register - text mode, blinking and line graphics */
svga_wattr ( 0x13 , 0x08 ) ; /* Horizontal Pixel Panning Register */
vga_r ( NULL , 0x3DA ) ;
vga_w ( NULL , VGA_ATT_W , 0x20 ) ;
}
#if 0
void svga_dump_var ( struct fb_var_screeninfo * var , int node )
{
pr_debug ( " fb%d: var.vmode : 0x%X \n " , node , var - > vmode ) ;
pr_debug ( " fb%d: var.xres : %d \n " , node , var - > xres ) ;
pr_debug ( " fb%d: var.yres : %d \n " , node , var - > yres ) ;
pr_debug ( " fb%d: var.bits_per_pixel: %d \n " , node , var - > bits_per_pixel ) ;
pr_debug ( " fb%d: var.xres_virtual : %d \n " , node , var - > xres_virtual ) ;
pr_debug ( " fb%d: var.yres_virtual : %d \n " , node , var - > yres_virtual ) ;
pr_debug ( " fb%d: var.left_margin : %d \n " , node , var - > left_margin ) ;
pr_debug ( " fb%d: var.right_margin : %d \n " , node , var - > right_margin ) ;
pr_debug ( " fb%d: var.upper_margin : %d \n " , node , var - > upper_margin ) ;
pr_debug ( " fb%d: var.lower_margin : %d \n " , node , var - > lower_margin ) ;
pr_debug ( " fb%d: var.hsync_len : %d \n " , node , var - > hsync_len ) ;
pr_debug ( " fb%d: var.vsync_len : %d \n " , node , var - > vsync_len ) ;
pr_debug ( " fb%d: var.sync : 0x%X \n " , node , var - > sync ) ;
pr_debug ( " fb%d: var.pixclock : %d \n \n " , node , var - > pixclock ) ;
}
# endif /* 0 */
/* ------------------------------------------------------------------------- */
void svga_settile ( struct fb_info * info , struct fb_tilemap * map )
{
const u8 * font = map - > data ;
2007-05-08 11:38:46 +04:00
u8 __iomem * fb = ( u8 __iomem * ) info - > screen_base ;
2007-02-12 11:54:49 +03:00
int i , c ;
if ( ( map - > width ! = 8 ) | | ( map - > height ! = 16 ) | |
( map - > depth ! = 1 ) | | ( map - > length ! = 256 ) ) {
printk ( KERN_ERR " fb%d: unsupported font parameters: width %d, height %d, depth %d, length %d \n " ,
info - > node , map - > width , map - > height , map - > depth , map - > length ) ;
return ;
}
fb + = 2 ;
for ( c = 0 ; c < map - > length ; c + + ) {
for ( i = 0 ; i < map - > height ; i + + ) {
2007-05-08 11:38:46 +04:00
fb_writeb ( font [ i ] , fb + i * 4 ) ;
// fb[i * 4] = font[i];
2007-02-12 11:54:49 +03:00
}
fb + = 128 ;
font + = map - > height ;
}
}
/* Copy area in text (tileblit) mode */
void svga_tilecopy ( struct fb_info * info , struct fb_tilearea * area )
{
int dx , dy ;
/* colstride is halved in this function because u16 are used */
int colstride = 1 < < ( info - > fix . type_aux & FB_AUX_TEXT_SVGA_MASK ) ;
int rowstride = colstride * ( info - > var . xres_virtual / 8 ) ;
2007-05-08 11:38:46 +04:00
u16 __iomem * fb = ( u16 __iomem * ) info - > screen_base ;
u16 __iomem * src , * dst ;
2007-02-12 11:54:49 +03:00
if ( ( area - > sy > area - > dy ) | |
( ( area - > sy = = area - > dy ) & & ( area - > sx > area - > dx ) ) ) {
src = fb + area - > sx * colstride + area - > sy * rowstride ;
dst = fb + area - > dx * colstride + area - > dy * rowstride ;
} else {
src = fb + ( area - > sx + area - > width - 1 ) * colstride
+ ( area - > sy + area - > height - 1 ) * rowstride ;
dst = fb + ( area - > dx + area - > width - 1 ) * colstride
+ ( area - > dy + area - > height - 1 ) * rowstride ;
colstride = - colstride ;
rowstride = - rowstride ;
}
for ( dy = 0 ; dy < area - > height ; dy + + ) {
2007-05-08 11:38:46 +04:00
u16 __iomem * src2 = src ;
u16 __iomem * dst2 = dst ;
2007-02-12 11:54:49 +03:00
for ( dx = 0 ; dx < area - > width ; dx + + ) {
2007-05-08 11:38:46 +04:00
fb_writew ( fb_readw ( src2 ) , dst2 ) ;
// *dst2 = *src2;
2007-02-12 11:54:49 +03:00
src2 + = colstride ;
dst2 + = colstride ;
}
src + = rowstride ;
dst + = rowstride ;
}
}
/* Fill area in text (tileblit) mode */
void svga_tilefill ( struct fb_info * info , struct fb_tilerect * rect )
{
int dx , dy ;
int colstride = 2 < < ( info - > fix . type_aux & FB_AUX_TEXT_SVGA_MASK ) ;
int rowstride = colstride * ( info - > var . xres_virtual / 8 ) ;
int attr = ( 0x0F & rect - > bg ) < < 4 | ( 0x0F & rect - > fg ) ;
2007-05-08 11:38:46 +04:00
u8 __iomem * fb = ( u8 __iomem * ) info - > screen_base ;
2007-02-12 11:54:49 +03:00
fb + = rect - > sx * colstride + rect - > sy * rowstride ;
for ( dy = 0 ; dy < rect - > height ; dy + + ) {
2007-05-08 11:38:46 +04:00
u8 __iomem * fb2 = fb ;
2007-02-12 11:54:49 +03:00
for ( dx = 0 ; dx < rect - > width ; dx + + ) {
2007-05-08 11:38:46 +04:00
fb_writeb ( rect - > index , fb2 ) ;
fb_writeb ( attr , fb2 + 1 ) ;
2007-02-12 11:54:49 +03:00
fb2 + = colstride ;
}
fb + = rowstride ;
}
}
/* Write text in text (tileblit) mode */
void svga_tileblit ( struct fb_info * info , struct fb_tileblit * blit )
{
int dx , dy , i ;
int colstride = 2 < < ( info - > fix . type_aux & FB_AUX_TEXT_SVGA_MASK ) ;
int rowstride = colstride * ( info - > var . xres_virtual / 8 ) ;
int attr = ( 0x0F & blit - > bg ) < < 4 | ( 0x0F & blit - > fg ) ;
2007-05-08 11:38:46 +04:00
u8 __iomem * fb = ( u8 __iomem * ) info - > screen_base ;
2007-02-12 11:54:49 +03:00
fb + = blit - > sx * colstride + blit - > sy * rowstride ;
i = 0 ;
for ( dy = 0 ; dy < blit - > height ; dy + + ) {
2007-05-08 11:38:46 +04:00
u8 __iomem * fb2 = fb ;
2007-02-12 11:54:49 +03:00
for ( dx = 0 ; dx < blit - > width ; dx + + ) {
2007-05-08 11:38:46 +04:00
fb_writeb ( blit - > indices [ i ] , fb2 ) ;
fb_writeb ( attr , fb2 + 1 ) ;
2007-02-12 11:54:49 +03:00
fb2 + = colstride ;
i + + ;
if ( i = = blit - > length ) return ;
}
fb + = rowstride ;
}
}
/* Set cursor in text (tileblit) mode */
void svga_tilecursor ( struct fb_info * info , struct fb_tilecursor * cursor )
{
u8 cs = 0x0d ;
u8 ce = 0x0e ;
u16 pos = cursor - > sx + ( info - > var . xoffset / 8 )
+ ( cursor - > sy + ( info - > var . yoffset / 16 ) )
* ( info - > var . xres_virtual / 8 ) ;
if ( ! cursor - > mode )
return ;
svga_wcrt_mask ( 0x0A , 0x20 , 0x20 ) ; /* disable cursor */
if ( cursor - > shape = = FB_TILE_CURSOR_NONE )
return ;
switch ( cursor - > shape ) {
case FB_TILE_CURSOR_UNDERLINE :
cs = 0x0d ;
break ;
case FB_TILE_CURSOR_LOWER_THIRD :
cs = 0x09 ;
break ;
case FB_TILE_CURSOR_LOWER_HALF :
cs = 0x07 ;
break ;
case FB_TILE_CURSOR_TWO_THIRDS :
cs = 0x05 ;
break ;
case FB_TILE_CURSOR_BLOCK :
cs = 0x01 ;
break ;
}
/* set cursor position */
vga_wcrt ( NULL , 0x0E , pos > > 8 ) ;
vga_wcrt ( NULL , 0x0F , pos & 0xFF ) ;
vga_wcrt ( NULL , 0x0B , ce ) ; /* set cursor end */
vga_wcrt ( NULL , 0x0A , cs ) ; /* set cursor start and enable it */
}
2007-05-08 11:40:00 +04:00
int svga_get_tilemax ( struct fb_info * info )
{
return 256 ;
}
2007-05-09 13:35:32 +04:00
/* Get capabilities of accelerator based on the mode */
void svga_get_caps ( struct fb_info * info , struct fb_blit_caps * caps ,
struct fb_var_screeninfo * var )
{
if ( var - > bits_per_pixel = = 0 ) {
/* can only support 256 8x16 bitmap */
caps - > x = 1 < < ( 8 - 1 ) ;
caps - > y = 1 < < ( 16 - 1 ) ;
caps - > len = 256 ;
} else {
caps - > x = ( var - > bits_per_pixel = = 4 ) ? 1 < < ( 8 - 1 ) : ~ ( u32 ) 0 ;
caps - > y = ~ ( u32 ) 0 ;
caps - > len = ~ ( u32 ) 0 ;
}
}
EXPORT_SYMBOL ( svga_get_caps ) ;
2007-02-12 11:54:49 +03:00
/* ------------------------------------------------------------------------- */
/*
* Compute PLL settings ( M , N , R )
* F_VCO = ( F_BASE * M ) / N
* F_OUT = F_VCO / ( 2 ^ R )
*/
static inline u32 abs_diff ( u32 a , u32 b )
{
return ( a > b ) ? ( a - b ) : ( b - a ) ;
}
int svga_compute_pll ( const struct svga_pll * pll , u32 f_wanted , u16 * m , u16 * n , u16 * r , int node )
{
u16 am , an , ar ;
u32 f_vco , f_current , delta_current , delta_best ;
pr_debug ( " fb%d: ideal frequency: %d kHz \n " , node , ( unsigned int ) f_wanted ) ;
ar = pll - > r_max ;
f_vco = f_wanted < < ar ;
/* overflow check */
if ( ( f_vco > > ar ) ! = f_wanted )
return - EINVAL ;
/* It is usually better to have greater VCO clock
because of better frequency stability .
So first try r_max , then r smaller . */
while ( ( ar > pll - > r_min ) & & ( f_vco > pll - > f_vco_max ) ) {
ar - - ;
f_vco = f_vco > > 1 ;
}
/* VCO bounds check */
if ( ( f_vco < pll - > f_vco_min ) | | ( f_vco > pll - > f_vco_max ) )
return - EINVAL ;
delta_best = 0xFFFFFFFF ;
* m = 0 ;
* n = 0 ;
* r = ar ;
am = pll - > m_min ;
an = pll - > n_min ;
while ( ( am < = pll - > m_max ) & & ( an < = pll - > n_max ) ) {
f_current = ( pll - > f_base * am ) / an ;
delta_current = abs_diff ( f_current , f_vco ) ;
if ( delta_current < delta_best ) {
delta_best = delta_current ;
* m = am ;
* n = an ;
}
if ( f_current < = f_vco ) {
am + + ;
} else {
an + + ;
}
}
f_current = ( pll - > f_base * * m ) / * n ;
pr_debug ( " fb%d: found frequency: %d kHz (VCO %d kHz) \n " , node , ( int ) ( f_current > > ar ) , ( int ) f_current ) ;
pr_debug ( " fb%d: m = %d n = %d r = %d \n " , node , ( unsigned int ) * m , ( unsigned int ) * n , ( unsigned int ) * r ) ;
return 0 ;
}
/* ------------------------------------------------------------------------- */
/* Check CRT timing values */
int svga_check_timings ( const struct svga_timing_regs * tm , struct fb_var_screeninfo * var , int node )
{
u32 value ;
var - > xres = ( var - > xres + 7 ) & ~ 7 ;
var - > left_margin = ( var - > left_margin + 7 ) & ~ 7 ;
var - > right_margin = ( var - > right_margin + 7 ) & ~ 7 ;
var - > hsync_len = ( var - > hsync_len + 7 ) & ~ 7 ;
/* Check horizontal total */
value = var - > xres + var - > left_margin + var - > right_margin + var - > hsync_len ;
if ( ( ( value / 8 ) - 5 ) > = svga_regset_size ( tm - > h_total_regs ) )
return - EINVAL ;
/* Check horizontal display and blank start */
value = var - > xres ;
if ( ( ( value / 8 ) - 1 ) > = svga_regset_size ( tm - > h_display_regs ) )
return - EINVAL ;
if ( ( ( value / 8 ) - 1 ) > = svga_regset_size ( tm - > h_blank_start_regs ) )
return - EINVAL ;
/* Check horizontal sync start */
value = var - > xres + var - > right_margin ;
if ( ( ( value / 8 ) - 1 ) > = svga_regset_size ( tm - > h_sync_start_regs ) )
return - EINVAL ;
/* Check horizontal blank end (or length) */
value = var - > left_margin + var - > right_margin + var - > hsync_len ;
if ( ( value = = 0 ) | | ( ( value / 8 ) > = svga_regset_size ( tm - > h_blank_end_regs ) ) )
return - EINVAL ;
/* Check horizontal sync end (or length) */
value = var - > hsync_len ;
if ( ( value = = 0 ) | | ( ( value / 8 ) > = svga_regset_size ( tm - > h_sync_end_regs ) ) )
return - EINVAL ;
/* Check vertical total */
value = var - > yres + var - > upper_margin + var - > lower_margin + var - > vsync_len ;
if ( ( value - 1 ) > = svga_regset_size ( tm - > v_total_regs ) )
return - EINVAL ;
/* Check vertical display and blank start */
value = var - > yres ;
if ( ( value - 1 ) > = svga_regset_size ( tm - > v_display_regs ) )
return - EINVAL ;
if ( ( value - 1 ) > = svga_regset_size ( tm - > v_blank_start_regs ) )
return - EINVAL ;
/* Check vertical sync start */
value = var - > yres + var - > lower_margin ;
if ( ( value - 1 ) > = svga_regset_size ( tm - > v_sync_start_regs ) )
return - EINVAL ;
/* Check vertical blank end (or length) */
value = var - > upper_margin + var - > lower_margin + var - > vsync_len ;
if ( ( value = = 0 ) | | ( value > = svga_regset_size ( tm - > v_blank_end_regs ) ) )
return - EINVAL ;
/* Check vertical sync end (or length) */
value = var - > vsync_len ;
if ( ( value = = 0 ) | | ( value > = svga_regset_size ( tm - > v_sync_end_regs ) ) )
return - EINVAL ;
return 0 ;
}
/* Set CRT timing registers */
void svga_set_timings ( const struct svga_timing_regs * tm , struct fb_var_screeninfo * var ,
u32 hmul , u32 hdiv , u32 vmul , u32 vdiv , u32 hborder , int node )
{
u8 regval ;
u32 value ;
value = var - > xres + var - > left_margin + var - > right_margin + var - > hsync_len ;
value = ( value * hmul ) / hdiv ;
pr_debug ( " fb%d: horizontal total : %d \n " , node , value ) ;
svga_wcrt_multi ( tm - > h_total_regs , ( value / 8 ) - 5 ) ;
value = var - > xres ;
value = ( value * hmul ) / hdiv ;
pr_debug ( " fb%d: horizontal display : %d \n " , node , value ) ;
svga_wcrt_multi ( tm - > h_display_regs , ( value / 8 ) - 1 ) ;
value = var - > xres ;
value = ( value * hmul ) / hdiv ;
pr_debug ( " fb%d: horizontal blank start: %d \n " , node , value ) ;
svga_wcrt_multi ( tm - > h_blank_start_regs , ( value / 8 ) - 1 + hborder ) ;
value = var - > xres + var - > left_margin + var - > right_margin + var - > hsync_len ;
value = ( value * hmul ) / hdiv ;
pr_debug ( " fb%d: horizontal blank end : %d \n " , node , value ) ;
svga_wcrt_multi ( tm - > h_blank_end_regs , ( value / 8 ) - 1 - hborder ) ;
value = var - > xres + var - > right_margin ;
value = ( value * hmul ) / hdiv ;
pr_debug ( " fb%d: horizontal sync start : %d \n " , node , value ) ;
svga_wcrt_multi ( tm - > h_sync_start_regs , ( value / 8 ) ) ;
value = var - > xres + var - > right_margin + var - > hsync_len ;
value = ( value * hmul ) / hdiv ;
pr_debug ( " fb%d: horizontal sync end : %d \n " , node , value ) ;
svga_wcrt_multi ( tm - > h_sync_end_regs , ( value / 8 ) ) ;
value = var - > yres + var - > upper_margin + var - > lower_margin + var - > vsync_len ;
value = ( value * vmul ) / vdiv ;
pr_debug ( " fb%d: vertical total : %d \n " , node , value ) ;
svga_wcrt_multi ( tm - > v_total_regs , value - 2 ) ;
value = var - > yres ;
value = ( value * vmul ) / vdiv ;
pr_debug ( " fb%d: vertical display : %d \n " , node , value ) ;
svga_wcrt_multi ( tm - > v_display_regs , value - 1 ) ;
value = var - > yres ;
value = ( value * vmul ) / vdiv ;
pr_debug ( " fb%d: vertical blank start : %d \n " , node , value ) ;
svga_wcrt_multi ( tm - > v_blank_start_regs , value ) ;
value = var - > yres + var - > upper_margin + var - > lower_margin + var - > vsync_len ;
value = ( value * vmul ) / vdiv ;
pr_debug ( " fb%d: vertical blank end : %d \n " , node , value ) ;
svga_wcrt_multi ( tm - > v_blank_end_regs , value - 2 ) ;
value = var - > yres + var - > lower_margin ;
value = ( value * vmul ) / vdiv ;
pr_debug ( " fb%d: vertical sync start : %d \n " , node , value ) ;
svga_wcrt_multi ( tm - > v_sync_start_regs , value ) ;
value = var - > yres + var - > lower_margin + var - > vsync_len ;
value = ( value * vmul ) / vdiv ;
pr_debug ( " fb%d: vertical sync end : %d \n " , node , value ) ;
svga_wcrt_multi ( tm - > v_sync_end_regs , value ) ;
/* Set horizontal and vertical sync pulse polarity in misc register */
regval = vga_r ( NULL , VGA_MIS_R ) ;
if ( var - > sync & FB_SYNC_HOR_HIGH_ACT ) {
pr_debug ( " fb%d: positive horizontal sync \n " , node ) ;
regval = regval & ~ 0x80 ;
} else {
pr_debug ( " fb%d: negative horizontal sync \n " , node ) ;
regval = regval | 0x80 ;
}
if ( var - > sync & FB_SYNC_VERT_HIGH_ACT ) {
pr_debug ( " fb%d: positive vertical sync \n " , node ) ;
regval = regval & ~ 0x40 ;
} else {
pr_debug ( " fb%d: negative vertical sync \n \n " , node ) ;
regval = regval | 0x40 ;
}
vga_w ( NULL , VGA_MIS_W , regval ) ;
}
/* ------------------------------------------------------------------------- */
2007-10-16 12:29:52 +04:00
static inline int match_format ( const struct svga_fb_format * frm ,
struct fb_var_screeninfo * var )
2007-02-12 11:54:49 +03:00
{
int i = 0 ;
2007-10-16 12:29:52 +04:00
int stored = - EINVAL ;
2007-02-12 11:54:49 +03:00
while ( frm - > bits_per_pixel ! = SVGA_FORMAT_END_VAL )
{
if ( ( var - > bits_per_pixel = = frm - > bits_per_pixel ) & &
( var - > red . length < = frm - > red . length ) & &
( var - > green . length < = frm - > green . length ) & &
( var - > blue . length < = frm - > blue . length ) & &
( var - > transp . length < = frm - > transp . length ) & &
2007-10-16 12:29:52 +04:00
( var - > nonstd = = frm - > nonstd ) )
2007-02-12 11:54:49 +03:00
return i ;
2007-10-16 12:29:52 +04:00
if ( var - > bits_per_pixel = = frm - > bits_per_pixel )
stored = i ;
2007-02-12 11:54:49 +03:00
i + + ;
frm + + ;
}
2007-10-16 12:29:52 +04:00
return stored ;
}
int svga_match_format ( const struct svga_fb_format * frm ,
struct fb_var_screeninfo * var ,
struct fb_fix_screeninfo * fix )
{
int i = match_format ( frm , var ) ;
if ( i > = 0 ) {
var - > bits_per_pixel = frm [ i ] . bits_per_pixel ;
var - > red = frm [ i ] . red ;
var - > green = frm [ i ] . green ;
var - > blue = frm [ i ] . blue ;
var - > transp = frm [ i ] . transp ;
var - > nonstd = frm [ i ] . nonstd ;
if ( fix ! = NULL ) {
fix - > type = frm [ i ] . type ;
fix - > type_aux = frm [ i ] . type_aux ;
fix - > visual = frm [ i ] . visual ;
fix - > xpanstep = frm [ i ] . xpanstep ;
}
}
return i ;
2007-02-12 11:54:49 +03:00
}
EXPORT_SYMBOL ( svga_wcrt_multi ) ;
EXPORT_SYMBOL ( svga_wseq_multi ) ;
EXPORT_SYMBOL ( svga_set_default_gfx_regs ) ;
EXPORT_SYMBOL ( svga_set_default_atc_regs ) ;
EXPORT_SYMBOL ( svga_set_default_seq_regs ) ;
EXPORT_SYMBOL ( svga_set_default_crt_regs ) ;
EXPORT_SYMBOL ( svga_set_textmode_vga_regs ) ;
EXPORT_SYMBOL ( svga_settile ) ;
EXPORT_SYMBOL ( svga_tilecopy ) ;
EXPORT_SYMBOL ( svga_tilefill ) ;
EXPORT_SYMBOL ( svga_tileblit ) ;
EXPORT_SYMBOL ( svga_tilecursor ) ;
2007-05-08 11:40:00 +04:00
EXPORT_SYMBOL ( svga_get_tilemax ) ;
2007-02-12 11:54:49 +03:00
EXPORT_SYMBOL ( svga_compute_pll ) ;
EXPORT_SYMBOL ( svga_check_timings ) ;
EXPORT_SYMBOL ( svga_set_timings ) ;
EXPORT_SYMBOL ( svga_match_format ) ;
MODULE_AUTHOR ( " Ondrej Zajicek <santiago@crfreenet.org> " ) ;
MODULE_DESCRIPTION ( " Common utility functions for VGA-based graphics cards " ) ;
MODULE_LICENSE ( " GPL " ) ;