2005-04-17 02:20:36 +04:00
/*
* Generic fillrect for frame buffers with packed pixels of any depth .
*
* Copyright ( C ) 2000 James Simmons ( jsimmons @ linux - fbdev . 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 .
*
* NOTES :
*
* Also need to add code to deal with cards endians that are different than
* the native cpu endians . I also need to deal with MSB position in the word .
*
*/
# include <linux/module.h>
# include <linux/string.h>
# include <linux/fb.h>
# include <asm/types.h>
2007-05-08 11:39:08 +04:00
# include "fb_draw.h"
2005-04-17 02:20:36 +04:00
# if BITS_PER_LONG == 32
# define FB_WRITEL fb_writel
# define FB_READL fb_readl
# else
# define FB_WRITEL fb_writeq
# define FB_READL fb_readq
# endif
/*
* Aligned pattern fill using 32 / 64 - bit memory accesses
*/
static void
2008-04-28 13:14:49 +04:00
bitfill_aligned ( struct fb_info * p , unsigned long __iomem * dst , int dst_idx ,
unsigned long pat , unsigned n , int bits , u32 bswapmask )
2005-04-17 02:20:36 +04:00
{
unsigned long first , last ;
if ( ! n )
return ;
2008-04-28 13:14:49 +04:00
first = fb_shifted_pixels_mask_long ( p , dst_idx , bswapmask ) ;
last = ~ fb_shifted_pixels_mask_long ( p , ( dst_idx + n ) % bits , bswapmask ) ;
2005-04-17 02:20:36 +04:00
if ( dst_idx + n < = bits ) {
// Single word
if ( last )
first & = last ;
FB_WRITEL ( comp ( pat , FB_READL ( dst ) , first ) , dst ) ;
} else {
// Multiple destination words
// Leading bits
if ( first ! = ~ 0UL ) {
FB_WRITEL ( comp ( pat , FB_READL ( dst ) , first ) , dst ) ;
dst + + ;
n - = bits - dst_idx ;
}
// Main chunk
n / = bits ;
while ( n > = 8 ) {
FB_WRITEL ( pat , dst + + ) ;
FB_WRITEL ( pat , dst + + ) ;
FB_WRITEL ( pat , dst + + ) ;
FB_WRITEL ( pat , dst + + ) ;
FB_WRITEL ( pat , dst + + ) ;
FB_WRITEL ( pat , dst + + ) ;
FB_WRITEL ( pat , dst + + ) ;
FB_WRITEL ( pat , dst + + ) ;
n - = 8 ;
}
while ( n - - )
FB_WRITEL ( pat , dst + + ) ;
// Trailing bits
if ( last )
FB_WRITEL ( comp ( pat , FB_READL ( dst ) , last ) , dst ) ;
}
}
/*
* Unaligned generic pattern fill using 32 / 64 - bit memory accesses
* The pattern must have been expanded to a full 32 / 64 - bit value
* Left / right are the appropriate shifts to convert to the pattern to be
* used for the next 32 / 64 - bit word
*/
static void
2008-04-28 13:14:49 +04:00
bitfill_unaligned ( struct fb_info * p , unsigned long __iomem * dst , int dst_idx ,
unsigned long pat , int left , int right , unsigned n , int bits )
2005-04-17 02:20:36 +04:00
{
unsigned long first , last ;
if ( ! n )
return ;
2008-04-28 13:14:49 +04:00
first = FB_SHIFT_HIGH ( p , ~ 0UL , dst_idx ) ;
last = ~ ( FB_SHIFT_HIGH ( p , ~ 0UL , ( dst_idx + n ) % bits ) ) ;
2005-04-17 02:20:36 +04:00
if ( dst_idx + n < = bits ) {
// Single word
if ( last )
first & = last ;
FB_WRITEL ( comp ( pat , FB_READL ( dst ) , first ) , dst ) ;
} else {
// Multiple destination words
// Leading bits
if ( first ) {
FB_WRITEL ( comp ( pat , FB_READL ( dst ) , first ) , dst ) ;
dst + + ;
pat = pat < < left | pat > > right ;
n - = bits - dst_idx ;
}
// Main chunk
n / = bits ;
while ( n > = 4 ) {
FB_WRITEL ( pat , dst + + ) ;
pat = pat < < left | pat > > right ;
FB_WRITEL ( pat , dst + + ) ;
pat = pat < < left | pat > > right ;
FB_WRITEL ( pat , dst + + ) ;
pat = pat < < left | pat > > right ;
FB_WRITEL ( pat , dst + + ) ;
pat = pat < < left | pat > > right ;
n - = 4 ;
}
while ( n - - ) {
FB_WRITEL ( pat , dst + + ) ;
pat = pat < < left | pat > > right ;
}
// Trailing bits
if ( last )
2009-05-07 03:02:56 +04:00
FB_WRITEL ( comp ( pat , FB_READL ( dst ) , last ) , dst ) ;
2005-04-17 02:20:36 +04:00
}
}
/*
* Aligned pattern invert using 32 / 64 - bit memory accesses
*/
static void
2008-04-28 13:14:49 +04:00
bitfill_aligned_rev ( struct fb_info * p , unsigned long __iomem * dst ,
int dst_idx , unsigned long pat , unsigned n , int bits ,
u32 bswapmask )
2005-04-17 02:20:36 +04:00
{
unsigned long val = pat , dat ;
unsigned long first , last ;
if ( ! n )
return ;
2008-04-28 13:14:49 +04:00
first = fb_shifted_pixels_mask_long ( p , dst_idx , bswapmask ) ;
last = ~ fb_shifted_pixels_mask_long ( p , ( dst_idx + n ) % bits , bswapmask ) ;
2005-04-17 02:20:36 +04:00
if ( dst_idx + n < = bits ) {
// Single word
if ( last )
first & = last ;
dat = FB_READL ( dst ) ;
FB_WRITEL ( comp ( dat ^ val , dat , first ) , dst ) ;
} else {
// Multiple destination words
// Leading bits
if ( first ! = 0UL ) {
dat = FB_READL ( dst ) ;
FB_WRITEL ( comp ( dat ^ val , dat , first ) , dst ) ;
dst + + ;
n - = bits - dst_idx ;
}
// Main chunk
n / = bits ;
while ( n > = 8 ) {
FB_WRITEL ( FB_READL ( dst ) ^ val , dst ) ;
dst + + ;
FB_WRITEL ( FB_READL ( dst ) ^ val , dst ) ;
dst + + ;
FB_WRITEL ( FB_READL ( dst ) ^ val , dst ) ;
dst + + ;
FB_WRITEL ( FB_READL ( dst ) ^ val , dst ) ;
dst + + ;
FB_WRITEL ( FB_READL ( dst ) ^ val , dst ) ;
dst + + ;
FB_WRITEL ( FB_READL ( dst ) ^ val , dst ) ;
dst + + ;
FB_WRITEL ( FB_READL ( dst ) ^ val , dst ) ;
dst + + ;
FB_WRITEL ( FB_READL ( dst ) ^ val , dst ) ;
dst + + ;
n - = 8 ;
}
while ( n - - ) {
FB_WRITEL ( FB_READL ( dst ) ^ val , dst ) ;
dst + + ;
}
// Trailing bits
if ( last ) {
dat = FB_READL ( dst ) ;
FB_WRITEL ( comp ( dat ^ val , dat , last ) , dst ) ;
}
}
}
/*
* Unaligned generic pattern invert using 32 / 64 - bit memory accesses
* The pattern must have been expanded to a full 32 / 64 - bit value
* Left / right are the appropriate shifts to convert to the pattern to be
* used for the next 32 / 64 - bit word
*/
static void
2008-04-28 13:14:49 +04:00
bitfill_unaligned_rev ( struct fb_info * p , unsigned long __iomem * dst ,
int dst_idx , unsigned long pat , int left , int right ,
unsigned n , int bits )
2005-04-17 02:20:36 +04:00
{
unsigned long first , last , dat ;
if ( ! n )
return ;
2008-04-28 13:14:49 +04:00
first = FB_SHIFT_HIGH ( p , ~ 0UL , dst_idx ) ;
last = ~ ( FB_SHIFT_HIGH ( p , ~ 0UL , ( dst_idx + n ) % bits ) ) ;
2005-04-17 02:20:36 +04:00
if ( dst_idx + n < = bits ) {
// Single word
if ( last )
first & = last ;
dat = FB_READL ( dst ) ;
FB_WRITEL ( comp ( dat ^ pat , dat , first ) , dst ) ;
} else {
// Multiple destination words
// Leading bits
if ( first ! = 0UL ) {
dat = FB_READL ( dst ) ;
FB_WRITEL ( comp ( dat ^ pat , dat , first ) , dst ) ;
dst + + ;
pat = pat < < left | pat > > right ;
n - = bits - dst_idx ;
}
// Main chunk
n / = bits ;
while ( n > = 4 ) {
FB_WRITEL ( FB_READL ( dst ) ^ pat , dst ) ;
dst + + ;
pat = pat < < left | pat > > right ;
FB_WRITEL ( FB_READL ( dst ) ^ pat , dst ) ;
dst + + ;
pat = pat < < left | pat > > right ;
FB_WRITEL ( FB_READL ( dst ) ^ pat , dst ) ;
dst + + ;
pat = pat < < left | pat > > right ;
FB_WRITEL ( FB_READL ( dst ) ^ pat , dst ) ;
dst + + ;
pat = pat < < left | pat > > right ;
n - = 4 ;
}
while ( n - - ) {
FB_WRITEL ( FB_READL ( dst ) ^ pat , dst ) ;
dst + + ;
pat = pat < < left | pat > > right ;
}
// Trailing bits
if ( last ) {
dat = FB_READL ( dst ) ;
FB_WRITEL ( comp ( dat ^ pat , dat , last ) , dst ) ;
}
}
}
void cfb_fillrect ( struct fb_info * p , const struct fb_fillrect * rect )
{
2009-05-07 03:02:56 +04:00
unsigned long pat , pat2 , fg ;
2005-11-07 12:00:39 +03:00
unsigned long width = rect - > width , height = rect - > height ;
2005-04-17 02:20:36 +04:00
int bits = BITS_PER_LONG , bytes = bits > > 3 ;
u32 bpp = p - > var . bits_per_pixel ;
unsigned long __iomem * dst ;
int dst_idx , left ;
if ( p - > state ! = FBINFO_STATE_RUNNING )
return ;
if ( p - > fix . visual = = FB_VISUAL_TRUECOLOR | |
p - > fix . visual = = FB_VISUAL_DIRECTCOLOR )
fg = ( ( u32 * ) ( p - > pseudo_palette ) ) [ rect - > color ] ;
else
fg = rect - > color ;
2009-05-07 03:02:56 +04:00
pat = pixel_to_pat ( bpp , fg ) ;
2005-04-17 02:20:36 +04:00
dst = ( unsigned long __iomem * ) ( ( unsigned long ) p - > screen_base & ~ ( bytes - 1 ) ) ;
dst_idx = ( ( unsigned long ) p - > screen_base & ( bytes - 1 ) ) * 8 ;
dst_idx + = rect - > dy * p - > fix . line_length * 8 + rect - > dx * bpp ;
/* FIXME For now we support 1-32 bpp only */
left = bits % bpp ;
if ( p - > fbops - > fb_sync )
p - > fbops - > fb_sync ( p ) ;
if ( ! left ) {
2007-10-16 12:29:21 +04:00
u32 bswapmask = fb_compute_bswapmask ( p ) ;
2008-04-28 13:14:49 +04:00
void ( * fill_op32 ) ( struct fb_info * p ,
unsigned long __iomem * dst , int dst_idx ,
2007-10-16 12:29:21 +04:00
unsigned long pat , unsigned n , int bits ,
u32 bswapmask ) = NULL ;
2005-04-17 02:20:36 +04:00
switch ( rect - > rop ) {
case ROP_XOR :
fill_op32 = bitfill_aligned_rev ;
break ;
case ROP_COPY :
fill_op32 = bitfill_aligned ;
break ;
default :
printk ( KERN_ERR " cfb_fillrect(): unknown rop, defaulting to ROP_COPY \n " ) ;
fill_op32 = bitfill_aligned ;
break ;
}
while ( height - - ) {
dst + = dst_idx > > ( ffs ( bits ) - 1 ) ;
dst_idx & = ( bits - 1 ) ;
2008-04-28 13:14:49 +04:00
fill_op32 ( p , dst , dst_idx , pat , width * bpp , bits ,
bswapmask ) ;
2005-04-17 02:20:36 +04:00
dst_idx + = p - > fix . line_length * 8 ;
}
} else {
2009-05-07 03:02:56 +04:00
int right , r ;
2008-04-28 13:14:49 +04:00
void ( * fill_op ) ( struct fb_info * p , unsigned long __iomem * dst ,
int dst_idx , unsigned long pat , int left ,
int right , unsigned n , int bits ) = NULL ;
2009-05-07 03:02:56 +04:00
# ifdef __LITTLE_ENDIAN
right = left ;
left = bpp - right ;
# else
right = bpp - left ;
# endif
2005-04-17 02:20:36 +04:00
switch ( rect - > rop ) {
case ROP_XOR :
fill_op = bitfill_unaligned_rev ;
break ;
case ROP_COPY :
fill_op = bitfill_unaligned ;
break ;
default :
2009-05-07 03:02:56 +04:00
printk ( KERN_ERR " cfb_fillrect(): unknown rop, defaulting to ROP_COPY \n " ) ;
2005-04-17 02:20:36 +04:00
fill_op = bitfill_unaligned ;
break ;
}
while ( height - - ) {
2009-05-07 03:02:56 +04:00
dst + = dst_idx / bits ;
2005-04-17 02:20:36 +04:00
dst_idx & = ( bits - 1 ) ;
2009-05-07 03:02:56 +04:00
r = dst_idx % bpp ;
/* rotate pattern to the correct start position */
pat2 = le_long_to_cpu ( rolx ( cpu_to_le_long ( pat ) , r , bpp ) ) ;
fill_op ( p , dst , dst_idx , pat2 , left , right ,
2005-04-17 02:20:36 +04:00
width * bpp , bits ) ;
dst_idx + = p - > fix . line_length * 8 ;
}
}
}
EXPORT_SYMBOL ( cfb_fillrect ) ;
MODULE_AUTHOR ( " James Simmons <jsimmons@users.sf.net> " ) ;
MODULE_DESCRIPTION ( " Generic software accelerated fill rectangle " ) ;
MODULE_LICENSE ( " GPL " ) ;