2005-04-17 02:20:36 +04:00
/*
* linux / drivers / video / pmag - aa - fb . c
* Copyright 2002 Karsten Merker < merker @ debian . org >
*
* PMAG - AA TurboChannel framebuffer card support . . . derived from
* pmag - ba - fb . c , which is Copyright ( C ) 1999 , 2000 , 2001 by
* Michael Engel < engel @ unix - ag . org > , Karsten Merker < merker @ debian . org >
* and Harald Koerfgen < hkoerfg @ web . de > , which itself is derived from
* " HP300 Topcat framebuffer support (derived from macfb of all things)
* Phil Blundell < philb @ gnu . org > 1998 "
2016-02-22 04:54:59 +03:00
* Copyright ( c ) 2016 Maciej W . Rozycki
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 .
*
* 2002 - 09 - 28 Karsten Merker < merker @ linuxtag . org >
* Version 0.01 : First try to get a PMAG - AA running .
*
* 2003 - 02 - 24 Thiemo Seufer < seufer @ csv . ica . uni - stuttgart . de >
* Version 0.02 : Major code cleanup .
*
* 2003 - 09 - 21 Thiemo Seufer < seufer @ csv . ica . uni - stuttgart . de >
* Hardware cursor support .
2016-02-22 04:54:59 +03:00
*
* 2016 - 02 - 21 Maciej W . Rozycki < macro @ linux - mips . org >
* Version 0.03 : Rewritten for the new FB and TC APIs .
2005-04-17 02:20:36 +04:00
*/
2016-02-22 04:54:59 +03:00
# include <linux/compiler.h>
2005-04-17 02:20:36 +04:00
# include <linux/errno.h>
# include <linux/fb.h>
2016-02-22 04:54:59 +03:00
# include <linux/init.h>
# include <linux/io.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/tc.h>
# include <linux/timer.h>
2005-04-17 02:20:36 +04:00
# include "bt455.h"
# include "bt431.h"
/* Version information */
2016-02-22 04:54:59 +03:00
# define DRIVER_VERSION "0.03"
2005-04-17 02:20:36 +04:00
# define DRIVER_AUTHOR "Karsten Merker <merker@linuxtag.org>"
# define DRIVER_DESCRIPTION "PMAG-AA Framebuffer Driver"
/*
* Bt455 RAM DAC register base offset ( rel . to TC slot base address ) .
*/
# define PMAG_AA_BT455_OFFSET 0x100000
/*
* Bt431 cursor generator offset ( rel . to TC slot base address ) .
*/
# define PMAG_AA_BT431_OFFSET 0x180000
/*
* Begin of PMAG - AA framebuffer memory relative to TC slot address ,
* resolution is 1280 x1024x1 ( 8 bits deep , but only LSB is used ) .
*/
# define PMAG_AA_ONBOARD_FBMEM_OFFSET 0x200000
2016-02-22 04:54:59 +03:00
struct aafb_par {
void __iomem * mmio ;
struct bt455_regs __iomem * bt455 ;
struct bt431_regs __iomem * bt431 ;
2005-04-17 02:20:36 +04:00
} ;
2016-02-22 04:54:59 +03:00
static struct fb_var_screeninfo aafb_defined = {
. xres = 1280 ,
. yres = 1024 ,
. xres_virtual = 2048 ,
. yres_virtual = 1024 ,
. bits_per_pixel = 8 ,
. grayscale = 1 ,
. red . length = 0 ,
. green . length = 1 ,
. blue . length = 0 ,
. activate = FB_ACTIVATE_NOW ,
. accel_flags = FB_ACCEL_NONE ,
. sync = FB_SYNC_ON_GREEN ,
. vmode = FB_VMODE_NONINTERLACED ,
2005-04-17 02:20:36 +04:00
} ;
2016-02-22 04:54:59 +03:00
static struct fb_fix_screeninfo aafb_fix = {
. id = " PMAG-AA " ,
. smem_len = ( 2048 * 1024 ) ,
. type = FB_TYPE_PACKED_PIXELS ,
. visual = FB_VISUAL_MONO10 ,
. ypanstep = 1 ,
. ywrapstep = 1 ,
. line_length = 2048 ,
. mmio_len = PMAG_AA_ONBOARD_FBMEM_OFFSET - PMAG_AA_BT455_OFFSET ,
} ;
2005-04-17 02:20:36 +04:00
2016-02-22 04:54:59 +03:00
static int aafb_cursor ( struct fb_info * info , struct fb_cursor * cursor )
2005-04-17 02:20:36 +04:00
{
2016-02-22 04:54:59 +03:00
struct aafb_par * par = info - > par ;
2005-04-17 02:20:36 +04:00
2016-02-22 04:54:59 +03:00
if ( cursor - > image . height > BT431_CURSOR_SIZE | |
cursor - > image . width > BT431_CURSOR_SIZE ) {
bt431_erase_cursor ( par - > bt431 ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
2016-02-22 04:54:59 +03:00
if ( ! cursor - > enable )
bt431_erase_cursor ( par - > bt431 ) ;
2005-04-17 02:20:36 +04:00
2016-02-22 04:54:59 +03:00
if ( cursor - > set & FB_CUR_SETPOS )
bt431_position_cursor ( par - > bt431 ,
cursor - > image . dx , cursor - > image . dy ) ;
if ( cursor - > set & FB_CUR_SETCMAP ) {
u8 fg = cursor - > image . fg_color ? 0xf : 0x0 ;
u8 bg = cursor - > image . bg_color ? 0xf : 0x0 ;
2005-04-17 02:20:36 +04:00
2016-02-22 04:54:59 +03:00
bt455_write_cmap_entry ( par - > bt455 , 8 , 0 , bg , 0 ) ;
bt455_write_cmap_entry ( par - > bt455 , 9 , 0 , bg , 0 ) ;
bt455_write_ovly_entry ( par - > bt455 , 0 , 0 , fg , 0 ) ;
}
if ( cursor - > set & ( FB_CUR_SETSIZE | FB_CUR_SETSHAPE | FB_CUR_SETIMAGE ) )
bt431_set_cursor ( par - > bt431 ,
cursor - > image . data , cursor - > mask , cursor - > rop ,
cursor - > image . width , cursor - > image . height ) ;
2005-04-17 02:20:36 +04:00
2016-02-22 04:54:59 +03:00
if ( cursor - > enable )
bt431_enable_cursor ( par - > bt431 ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2016-02-22 04:54:59 +03:00
/* 0 unblanks, any other blanks. */
2005-04-17 02:20:36 +04:00
2016-02-22 04:54:59 +03:00
static int aafb_blank ( int blank , struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
2016-02-22 04:54:59 +03:00
struct aafb_par * par = info - > par ;
u8 val = blank ? 0x00 : 0x0f ;
2005-04-17 02:20:36 +04:00
2016-02-22 04:54:59 +03:00
bt455_write_cmap_entry ( par - > bt455 , 1 , val , val , val ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2016-02-22 04:54:59 +03:00
static struct fb_ops aafb_ops = {
. owner = THIS_MODULE ,
. fb_blank = aafb_blank ,
. fb_fillrect = cfb_fillrect ,
. fb_copyarea = cfb_copyarea ,
. fb_imageblit = cfb_imageblit ,
. fb_cursor = aafb_cursor ,
} ;
2005-04-17 02:20:36 +04:00
2016-02-22 04:54:59 +03:00
static int pmagaafb_probe ( struct device * dev )
2005-04-17 02:20:36 +04:00
{
2016-02-22 04:54:59 +03:00
struct tc_dev * tdev = to_tc_dev ( dev ) ;
resource_size_t start , len ;
struct fb_info * info ;
struct aafb_par * par ;
int err ;
info = framebuffer_alloc ( sizeof ( struct aafb_par ) , dev ) ;
if ( ! info ) {
printk ( KERN_ERR " %s: Cannot allocate memory \n " , dev_name ( dev ) ) ;
return - ENOMEM ;
}
2005-04-17 02:20:36 +04:00
2016-02-22 04:54:59 +03:00
par = info - > par ;
dev_set_drvdata ( dev , info ) ;
info - > fbops = & aafb_ops ;
info - > fix = aafb_fix ;
info - > var = aafb_defined ;
info - > flags = FBINFO_DEFAULT ;
/* Request the I/O MEM resource. */
start = tdev - > resource . start ;
len = tdev - > resource . end - start + 1 ;
if ( ! request_mem_region ( start , len , dev_name ( dev ) ) ) {
printk ( KERN_ERR " %s: Cannot reserve FB region \n " ,
dev_name ( dev ) ) ;
err = - EBUSY ;
goto err_alloc ;
}
2005-04-17 02:20:36 +04:00
2016-02-22 04:54:59 +03:00
/* MMIO mapping setup. */
info - > fix . mmio_start = start + PMAG_AA_BT455_OFFSET ;
par - > mmio = ioremap_nocache ( info - > fix . mmio_start , info - > fix . mmio_len ) ;
if ( ! par - > mmio ) {
printk ( KERN_ERR " %s: Cannot map MMIO \n " , dev_name ( dev ) ) ;
err = - ENOMEM ;
goto err_resource ;
}
par - > bt455 = par - > mmio - PMAG_AA_BT455_OFFSET + PMAG_AA_BT455_OFFSET ;
par - > bt431 = par - > mmio - PMAG_AA_BT455_OFFSET + PMAG_AA_BT431_OFFSET ;
/* Frame buffer mapping setup. */
info - > fix . smem_start = start + PMAG_AA_ONBOARD_FBMEM_OFFSET ;
info - > screen_base = ioremap_nocache ( info - > fix . smem_start ,
info - > fix . smem_len ) ;
if ( ! info - > screen_base ) {
printk ( KERN_ERR " %s: Cannot map FB \n " , dev_name ( dev ) ) ;
err = - ENOMEM ;
goto err_mmio_map ;
}
info - > screen_size = info - > fix . smem_len ;
2005-04-17 02:20:36 +04:00
2016-02-22 04:54:59 +03:00
/* Init colormap. */
bt455_write_cmap_entry ( par - > bt455 , 0 , 0x00 , 0x00 , 0x00 ) ;
bt455_write_cmap_entry ( par - > bt455 , 1 , 0x0f , 0x0f , 0x0f ) ;
2005-04-17 02:20:36 +04:00
2016-02-22 04:54:59 +03:00
/* Init hardware cursor. */
bt431_erase_cursor ( par - > bt431 ) ;
bt431_init_cursor ( par - > bt431 ) ;
err = register_framebuffer ( info ) ;
if ( err < 0 ) {
printk ( KERN_ERR " %s: Cannot register framebuffer \n " ,
dev_name ( dev ) ) ;
goto err_smem_map ;
}
2005-04-17 02:20:36 +04:00
2016-02-22 04:54:59 +03:00
get_device ( dev ) ;
2005-04-17 02:20:36 +04:00
2016-02-22 04:54:59 +03:00
pr_info ( " fb%d: %s frame buffer device at %s \n " ,
info - > node , info - > fix . id , dev_name ( dev ) ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
2016-02-22 04:54:59 +03:00
err_smem_map :
iounmap ( info - > screen_base ) ;
2005-04-17 02:20:36 +04:00
2016-02-22 04:54:59 +03:00
err_mmio_map :
iounmap ( par - > mmio ) ;
2005-04-17 02:20:36 +04:00
2016-02-22 04:54:59 +03:00
err_resource :
release_mem_region ( start , len ) ;
2005-04-17 02:20:36 +04:00
2016-02-22 04:54:59 +03:00
err_alloc :
framebuffer_release ( info ) ;
return err ;
2005-04-17 02:20:36 +04:00
}
2016-02-22 04:54:59 +03:00
static int __exit pmagaafb_remove ( struct device * dev )
2005-04-17 02:20:36 +04:00
{
2016-02-22 04:54:59 +03:00
struct tc_dev * tdev = to_tc_dev ( dev ) ;
struct fb_info * info = dev_get_drvdata ( dev ) ;
struct aafb_par * par = info - > par ;
resource_size_t start , len ;
put_device ( dev ) ;
unregister_framebuffer ( info ) ;
iounmap ( info - > screen_base ) ;
iounmap ( par - > mmio ) ;
start = tdev - > resource . start ;
len = tdev - > resource . end - start + 1 ;
release_mem_region ( start , len ) ;
framebuffer_release ( info ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
* Initialise the framebuffer .
*/
2016-02-22 04:54:59 +03:00
static const struct tc_device_id pmagaafb_tc_table [ ] = {
{ " DEC " , " PMAG-AA " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( tc , pmagaafb_tc_table ) ;
static struct tc_driver pmagaafb_driver = {
. id_table = pmagaafb_tc_table ,
. driver = {
. name = " pmagaafb " ,
. bus = & tc_bus_type ,
. probe = pmagaafb_probe ,
. remove = __exit_p ( pmagaafb_remove ) ,
} ,
} ;
2005-04-17 02:20:36 +04:00
2016-02-22 04:54:59 +03:00
static int __init pmagaafb_init ( void )
{
# ifndef MODULE
if ( fb_get_options ( " pmagaafb " , NULL ) )
return - ENXIO ;
# endif
return tc_register_driver ( & pmagaafb_driver ) ;
2005-04-17 02:20:36 +04:00
}
static void __exit pmagaafb_exit ( void )
{
2016-02-22 04:54:59 +03:00
tc_unregister_driver ( & pmagaafb_driver ) ;
2005-04-17 02:20:36 +04:00
}
2016-02-22 04:54:59 +03:00
module_init ( pmagaafb_init ) ;
module_exit ( pmagaafb_exit ) ;
2005-04-17 02:20:36 +04:00
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESCRIPTION ) ;
MODULE_LICENSE ( " GPL " ) ;