2005-04-17 02:20:36 +04:00
/*
2005-09-04 02:56:09 +04:00
* linux / drivers / video / pmag - ba - fb . c
2005-04-17 02:20:36 +04:00
*
2005-09-04 02:56:09 +04:00
* PMAG - BA TURBOchannel Color Frame Buffer ( CFB ) card support ,
* derived from :
2005-04-17 02:20:36 +04:00
* " HP300 Topcat framebuffer support (derived from macfb of all things)
* Phil Blundell < philb @ gnu . org > 1998 " , the original code can be
2005-09-04 02:56:09 +04:00
* found in the file hpfb . c in the same directory .
2005-04-17 02:20:36 +04:00
*
* Based on digital document :
* " PMAG-BA TURBOchannel Color Frame Buffer
* Functional Specification " , Revision 1.2, August 27, 1990
*
2005-09-04 02:56:09 +04:00
* DECstation related code Copyright ( C ) 1999 , 2000 , 2001 by
* Michael Engel < engel @ unix - ag . org > ,
* Karsten Merker < merker @ linuxtag . org > and
2005-04-17 02:20:36 +04:00
* Harald Koerfgen .
2007-02-06 03:28:28 +03:00
* Copyright ( c ) 2005 , 2006 Maciej W . Rozycki
* Copyright ( c ) 2005 James Simmons
2005-04-17 02:20:36 +04:00
*
2005-09-04 02:56:09 +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 .
2005-04-17 02:20:36 +04:00
*/
2005-09-04 02:56:09 +04:00
# include <linux/compiler.h>
2005-04-17 02:20:36 +04:00
# include <linux/errno.h>
# include <linux/fb.h>
2005-09-04 02:56:09 +04:00
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
2007-02-06 03:28:28 +03:00
# include <linux/tc.h>
2005-09-04 02:56:09 +04:00
# include <linux/types.h>
# include <asm/io.h>
# include <asm/system.h>
2005-04-17 02:20:36 +04:00
# include <video/pmag-ba-fb.h>
2005-09-04 02:56:09 +04:00
struct pmagbafb_par {
volatile void __iomem * mmio ;
volatile u32 __iomem * dac ;
2005-04-17 02:20:36 +04:00
} ;
2010-07-26 22:08:14 +04:00
static struct fb_var_screeninfo pmagbafb_defined __devinitdata = {
2005-04-17 02:20:36 +04:00
. xres = 1024 ,
. yres = 864 ,
. xres_virtual = 1024 ,
. yres_virtual = 864 ,
. bits_per_pixel = 8 ,
. red . length = 8 ,
. green . length = 8 ,
. blue . length = 8 ,
. activate = FB_ACTIVATE_NOW ,
2005-09-04 02:56:09 +04:00
. height = - 1 ,
. width = - 1 ,
. accel_flags = FB_ACCEL_NONE ,
. pixclock = 14452 ,
. left_margin = 116 ,
. right_margin = 12 ,
. upper_margin = 34 ,
. lower_margin = 12 ,
. hsync_len = 128 ,
. vsync_len = 3 ,
. sync = FB_SYNC_ON_GREEN ,
2005-04-17 02:20:36 +04:00
. vmode = FB_VMODE_NONINTERLACED ,
} ;
2010-07-26 22:08:14 +04:00
static struct fb_fix_screeninfo pmagbafb_fix __devinitdata = {
2005-04-17 02:20:36 +04:00
. id = " PMAG-BA " ,
2005-09-04 02:56:09 +04:00
. smem_len = ( 1024 * 1024 ) ,
2005-04-17 02:20:36 +04:00
. type = FB_TYPE_PACKED_PIXELS ,
. visual = FB_VISUAL_PSEUDOCOLOR ,
. line_length = 1024 ,
2005-09-04 02:56:09 +04:00
. mmio_len = PMAG_BA_SIZE - PMAG_BA_BT459 ,
2005-04-17 02:20:36 +04:00
} ;
2005-09-04 02:56:09 +04:00
static inline void dac_write ( struct pmagbafb_par * par , unsigned int reg , u8 v )
2005-04-17 02:20:36 +04:00
{
2005-09-04 02:56:09 +04:00
writeb ( v , par - > dac + reg / 4 ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-04 02:56:09 +04:00
static inline u8 dac_read ( struct pmagbafb_par * par , unsigned int reg )
{
return readb ( par - > dac + reg / 4 ) ;
}
2005-04-17 02:20:36 +04:00
/*
2005-09-04 02:56:09 +04:00
* Set the palette .
2005-04-17 02:20:36 +04:00
*/
2005-09-04 02:56:09 +04:00
static int pmagbafb_setcolreg ( unsigned int regno , unsigned int red ,
unsigned int green , unsigned int blue ,
unsigned int transp , struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
2005-09-04 02:56:09 +04:00
struct pmagbafb_par * par = info - > par ;
2005-04-17 02:20:36 +04:00
2009-12-16 03:46:25 +03:00
if ( regno > = info - > cmap . len )
return 1 ;
2005-04-17 02:20:36 +04:00
red > > = 8 ; /* The cmap fields are 16 bits */
2005-09-04 02:56:09 +04:00
green > > = 8 ; /* wide, but the hardware colormap */
2005-04-17 02:20:36 +04:00
blue > > = 8 ; /* registers are only 8 bits wide */
2005-09-04 02:56:09 +04:00
mb ( ) ;
dac_write ( par , BT459_ADDR_LO , regno ) ;
dac_write ( par , BT459_ADDR_HI , 0x00 ) ;
wmb ( ) ;
dac_write ( par , BT459_CMAP , red ) ;
wmb ( ) ;
dac_write ( par , BT459_CMAP , green ) ;
wmb ( ) ;
dac_write ( par , BT459_CMAP , blue ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static struct fb_ops pmagbafb_ops = {
. owner = THIS_MODULE ,
. fb_setcolreg = pmagbafb_setcolreg ,
. fb_fillrect = cfb_fillrect ,
. fb_copyarea = cfb_copyarea ,
. fb_imageblit = cfb_imageblit ,
} ;
2005-09-04 02:56:09 +04:00
/*
* Turn the hardware cursor off .
*/
static void __init pmagbafb_erase_cursor ( struct fb_info * info )
{
struct pmagbafb_par * par = info - > par ;
mb ( ) ;
dac_write ( par , BT459_ADDR_LO , 0x00 ) ;
dac_write ( par , BT459_ADDR_HI , 0x03 ) ;
wmb ( ) ;
dac_write ( par , BT459_DATA , 0x00 ) ;
}
2010-07-26 22:08:14 +04:00
static int __devinit pmagbafb_probe ( struct device * dev )
2005-04-17 02:20:36 +04:00
{
2007-02-06 03:28:28 +03:00
struct tc_dev * tdev = to_tc_dev ( dev ) ;
resource_size_t start , len ;
2005-09-04 02:56:09 +04:00
struct fb_info * info ;
struct pmagbafb_par * par ;
2007-10-16 12:29:30 +04:00
int err ;
2005-09-04 02:56:09 +04:00
2007-02-06 03:28:28 +03:00
info = framebuffer_alloc ( sizeof ( struct pmagbafb_par ) , dev ) ;
2007-10-16 12:29:30 +04:00
if ( ! info ) {
2009-03-25 02:38:21 +03:00
printk ( KERN_ERR " %s: Cannot allocate memory \n " , dev_name ( dev ) ) ;
2005-09-04 02:56:09 +04:00
return - ENOMEM ;
2007-10-16 12:29:30 +04:00
}
2005-09-04 02:56:09 +04:00
par = info - > par ;
2007-02-06 03:28:28 +03:00
dev_set_drvdata ( dev , info ) ;
2005-09-04 02:56:09 +04:00
2007-10-16 12:29:30 +04:00
if ( fb_alloc_cmap ( & info - > cmap , 256 , 0 ) < 0 ) {
printk ( KERN_ERR " %s: Cannot allocate color map \n " ,
2009-03-25 02:38:21 +03:00
dev_name ( dev ) ) ;
2007-10-16 12:29:30 +04:00
err = - ENOMEM ;
2005-09-04 02:56:09 +04:00
goto err_alloc ;
2007-10-16 12:29:30 +04:00
}
2005-09-04 02:56:09 +04:00
2005-04-17 02:20:36 +04:00
info - > fbops = & pmagbafb_ops ;
2005-09-04 02:56:09 +04:00
info - > fix = pmagbafb_fix ;
2005-04-17 02:20:36 +04:00
info - > var = pmagbafb_defined ;
info - > flags = FBINFO_DEFAULT ;
2007-02-06 03:28:28 +03:00
/* Request the I/O MEM resource. */
start = tdev - > resource . start ;
len = tdev - > resource . end - start + 1 ;
2009-03-25 02:38:21 +03:00
if ( ! request_mem_region ( start , len , dev_name ( dev ) ) ) {
printk ( KERN_ERR " %s: Cannot reserve FB region \n " ,
dev_name ( dev ) ) ;
2007-10-16 12:29:30 +04:00
err = - EBUSY ;
2007-02-06 03:28:28 +03:00
goto err_cmap ;
2007-10-16 12:29:30 +04:00
}
2007-02-06 03:28:28 +03:00
2005-09-04 02:56:09 +04:00
/* MMIO mapping setup. */
2007-02-06 03:28:28 +03:00
info - > fix . mmio_start = start ;
2005-09-04 02:56:09 +04:00
par - > mmio = ioremap_nocache ( info - > fix . mmio_start , info - > fix . mmio_len ) ;
2007-10-16 12:29:30 +04:00
if ( ! par - > mmio ) {
2009-03-25 02:38:21 +03:00
printk ( KERN_ERR " %s: Cannot map MMIO \n " , dev_name ( dev ) ) ;
2007-10-16 12:29:30 +04:00
err = - ENOMEM ;
2007-02-06 03:28:28 +03:00
goto err_resource ;
2007-10-16 12:29:30 +04:00
}
2005-09-04 02:56:09 +04:00
par - > dac = par - > mmio + PMAG_BA_BT459 ;
/* Frame buffer mapping setup. */
2007-02-06 03:28:28 +03:00
info - > fix . smem_start = start + PMAG_BA_FBMEM ;
2005-09-04 02:56:09 +04:00
info - > screen_base = ioremap_nocache ( info - > fix . smem_start ,
info - > fix . smem_len ) ;
2007-10-16 12:29:30 +04:00
if ( ! info - > screen_base ) {
2009-03-25 02:38:21 +03:00
printk ( KERN_ERR " %s: Cannot map FB \n " , dev_name ( dev ) ) ;
2007-10-16 12:29:30 +04:00
err = - ENOMEM ;
2005-09-04 02:56:09 +04:00
goto err_mmio_map ;
2007-10-16 12:29:30 +04:00
}
2005-09-04 02:56:09 +04:00
info - > screen_size = info - > fix . smem_len ;
pmagbafb_erase_cursor ( info ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:30 +04:00
err = register_framebuffer ( info ) ;
if ( err < 0 ) {
printk ( KERN_ERR " %s: Cannot register framebuffer \n " ,
2009-03-25 02:38:21 +03:00
dev_name ( dev ) ) ;
2005-09-04 02:56:09 +04:00
goto err_smem_map ;
2007-10-16 12:29:30 +04:00
}
2005-09-04 02:56:09 +04:00
2007-02-06 03:28:28 +03:00
get_device ( dev ) ;
pr_info ( " fb%d: %s frame buffer device at %s \n " ,
2009-03-25 02:38:21 +03:00
info - > node , info - > fix . id , dev_name ( dev ) ) ;
2005-09-04 02:56:09 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
2005-09-04 02:56:09 +04:00
err_smem_map :
iounmap ( info - > screen_base ) ;
err_mmio_map :
iounmap ( par - > mmio ) ;
2007-02-06 03:28:28 +03:00
err_resource :
release_mem_region ( start , len ) ;
2005-09-04 02:56:09 +04:00
err_cmap :
fb_dealloc_cmap ( & info - > cmap ) ;
err_alloc :
framebuffer_release ( info ) ;
2007-10-16 12:29:30 +04:00
return err ;
2005-04-17 02:20:36 +04:00
}
2007-02-06 03:28:28 +03:00
static int __exit pmagbafb_remove ( struct device * dev )
2005-09-04 02:56:09 +04:00
{
2007-02-06 03:28:28 +03:00
struct tc_dev * tdev = to_tc_dev ( dev ) ;
struct fb_info * info = dev_get_drvdata ( dev ) ;
2005-09-04 02:56:09 +04:00
struct pmagbafb_par * par = info - > par ;
2007-02-06 03:28:28 +03:00
resource_size_t start , len ;
2005-04-17 02:20:36 +04:00
2007-02-06 03:28:28 +03:00
put_device ( dev ) ;
2005-09-04 02:56:09 +04:00
unregister_framebuffer ( info ) ;
iounmap ( info - > screen_base ) ;
iounmap ( par - > mmio ) ;
2007-02-06 03:28:28 +03:00
start = tdev - > resource . start ;
len = tdev - > resource . end - start + 1 ;
release_mem_region ( start , len ) ;
2005-09-04 02:56:09 +04:00
fb_dealloc_cmap ( & info - > cmap ) ;
framebuffer_release ( info ) ;
2007-02-06 03:28:28 +03:00
return 0 ;
2005-09-04 02:56:09 +04:00
}
/*
2007-02-06 03:28:28 +03:00
* Initialize the framebuffer .
2005-09-04 02:56:09 +04:00
*/
2007-02-06 03:28:28 +03:00
static const struct tc_device_id pmagbafb_tc_table [ ] = {
{ " DEC " , " PMAG-BA " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( tc , pmagbafb_tc_table ) ;
static struct tc_driver pmagbafb_driver = {
. id_table = pmagbafb_tc_table ,
. driver = {
. name = " pmagbafb " ,
. bus = & tc_bus_type ,
. probe = pmagbafb_probe ,
. remove = __exit_p ( pmagbafb_remove ) ,
} ,
} ;
2005-09-04 02:56:09 +04:00
static int __init pmagbafb_init ( void )
2005-04-17 02:20:36 +04:00
{
2007-02-06 03:28:28 +03:00
# ifndef MODULE
2005-04-17 02:20:36 +04:00
if ( fb_get_options ( " pmagbafb " , NULL ) )
2005-09-04 02:56:09 +04:00
return - ENXIO ;
2007-02-06 03:28:28 +03:00
# endif
return tc_register_driver ( & pmagbafb_driver ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-04 02:56:09 +04:00
static void __exit pmagbafb_exit ( void )
{
2007-02-06 03:28:28 +03:00
tc_unregister_driver ( & pmagbafb_driver ) ;
2005-09-04 02:56:09 +04:00
}
2005-04-17 02:20:36 +04:00
module_init ( pmagbafb_init ) ;
2005-09-04 02:56:09 +04:00
module_exit ( pmagbafb_exit ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;