2016-02-22 06:13:12 +03:00
/* sunxvr2500.c: Sun 3DLABS XVR-2500 et al. fb driver for sparc64 systems
*
* License : GPL
2007-05-07 09:45:50 +04:00
*
* Copyright ( C ) 2007 David S . Miller ( davem @ davemloft . net )
*/
2022-07-18 10:23:17 +03:00
# include <linux/aperture.h>
2007-05-07 09:45:50 +04:00
# include <linux/kernel.h>
# include <linux/fb.h>
# include <linux/pci.h>
# include <linux/init.h>
2008-05-09 08:37:30 +04:00
# include <linux/of_device.h>
2007-05-07 09:45:50 +04:00
# include <asm/io.h>
struct s3d_info {
struct fb_info * info ;
struct pci_dev * pdev ;
char __iomem * fb_base ;
unsigned long fb_base_phys ;
struct device_node * of_node ;
unsigned int width ;
unsigned int height ;
unsigned int depth ;
unsigned int fb_size ;
2007-06-06 00:15:01 +04:00
u32 pseudo_palette [ 16 ] ;
2007-05-07 09:45:50 +04:00
} ;
2012-12-22 01:07:39 +04:00
static int s3d_get_props ( struct s3d_info * sp )
2007-05-07 09:45:50 +04:00
{
sp - > width = of_getintprop_default ( sp - > of_node , " width " , 0 ) ;
sp - > height = of_getintprop_default ( sp - > of_node , " height " , 0 ) ;
sp - > depth = of_getintprop_default ( sp - > of_node , " depth " , 8 ) ;
if ( ! sp - > width | | ! sp - > height ) {
printk ( KERN_ERR " s3d: Critical properties missing for %s \n " ,
pci_name ( sp - > pdev ) ) ;
return - EINVAL ;
}
return 0 ;
}
static int s3d_setcolreg ( unsigned regno ,
unsigned red , unsigned green , unsigned blue ,
unsigned transp , struct fb_info * info )
{
u32 value ;
2007-06-06 00:15:01 +04:00
if ( regno < 16 ) {
red > > = 8 ;
green > > = 8 ;
blue > > = 8 ;
2007-05-07 09:45:50 +04:00
2007-06-06 00:15:01 +04:00
value = ( blue < < 24 ) | ( green < < 16 ) | ( red < < 8 ) ;
( ( u32 * ) info - > pseudo_palette ) [ regno ] = value ;
}
2007-05-07 09:45:50 +04:00
return 0 ;
}
2019-12-03 19:38:50 +03:00
static const struct fb_ops s3d_ops = {
2007-05-07 09:45:50 +04:00
. owner = THIS_MODULE ,
. fb_setcolreg = s3d_setcolreg ,
. fb_fillrect = cfb_fillrect ,
. fb_copyarea = cfb_copyarea ,
. fb_imageblit = cfb_imageblit ,
} ;
2012-12-22 01:07:39 +04:00
static int s3d_set_fbinfo ( struct s3d_info * sp )
2007-05-07 09:45:50 +04:00
{
struct fb_info * info = sp - > info ;
struct fb_var_screeninfo * var = & info - > var ;
info - > flags = FBINFO_DEFAULT ;
info - > fbops = & s3d_ops ;
info - > screen_base = sp - > fb_base ;
info - > screen_size = sp - > fb_size ;
info - > pseudo_palette = sp - > pseudo_palette ;
/* Fill fix common fields */
2022-08-19 00:01:17 +03:00
strscpy ( info - > fix . id , " s3d " , sizeof ( info - > fix . id ) ) ;
2007-05-07 09:45:50 +04:00
info - > fix . smem_start = sp - > fb_base_phys ;
info - > fix . smem_len = sp - > fb_size ;
info - > fix . type = FB_TYPE_PACKED_PIXELS ;
if ( sp - > depth = = 32 | | sp - > depth = = 24 )
info - > fix . visual = FB_VISUAL_TRUECOLOR ;
else
info - > fix . visual = FB_VISUAL_PSEUDOCOLOR ;
var - > xres = sp - > width ;
var - > yres = sp - > height ;
var - > xres_virtual = var - > xres ;
var - > yres_virtual = var - > yres ;
var - > bits_per_pixel = sp - > depth ;
var - > red . offset = 8 ;
var - > red . length = 8 ;
var - > green . offset = 16 ;
var - > green . length = 8 ;
var - > blue . offset = 24 ;
var - > blue . length = 8 ;
var - > transp . offset = 0 ;
var - > transp . length = 0 ;
if ( fb_alloc_cmap ( & info - > cmap , 256 , 0 ) ) {
printk ( KERN_ERR " s3d: Cannot allocate color map. \n " ) ;
return - ENOMEM ;
}
return 0 ;
}
2012-12-22 01:07:39 +04:00
static int s3d_pci_register ( struct pci_dev * pdev ,
const struct pci_device_id * ent )
2007-05-07 09:45:50 +04:00
{
struct fb_info * info ;
struct s3d_info * sp ;
int err ;
2022-07-18 10:23:17 +03:00
err = aperture_remove_conflicting_pci_devices ( pdev , " s3dfb " ) ;
if ( err )
return err ;
2007-05-07 09:45:50 +04:00
err = pci_enable_device ( pdev ) ;
if ( err < 0 ) {
printk ( KERN_ERR " s3d: Cannot enable PCI device %s \n " ,
pci_name ( pdev ) ) ;
goto err_out ;
}
info = framebuffer_alloc ( sizeof ( struct s3d_info ) , & pdev - > dev ) ;
if ( ! info ) {
err = - ENOMEM ;
goto err_disable ;
}
sp = info - > par ;
sp - > info = info ;
sp - > pdev = pdev ;
sp - > of_node = pci_device_to_OF_node ( pdev ) ;
if ( ! sp - > of_node ) {
printk ( KERN_ERR " s3d: Cannot find OF node of %s \n " ,
pci_name ( pdev ) ) ;
err = - ENODEV ;
goto err_release_fb ;
}
sp - > fb_base_phys = pci_resource_start ( pdev , 1 ) ;
err = pci_request_region ( pdev , 1 , " s3d framebuffer " ) ;
if ( err < 0 ) {
printk ( " s3d: Cannot request region 1 for %s \n " ,
pci_name ( pdev ) ) ;
goto err_release_fb ;
}
err = s3d_get_props ( sp ) ;
if ( err )
goto err_release_pci ;
/* XXX 'linebytes' is often wrong, it is equal to the width
* XXX with depth of 32 on my XVR - 2500 which is clearly not
* XXX right . So we don ' t try to use it .
*/
switch ( sp - > depth ) {
case 8 :
info - > fix . line_length = sp - > width ;
break ;
case 16 :
info - > fix . line_length = sp - > width * 2 ;
break ;
case 24 :
info - > fix . line_length = sp - > width * 3 ;
break ;
case 32 :
info - > fix . line_length = sp - > width * 4 ;
break ;
}
sp - > fb_size = info - > fix . line_length * sp - > height ;
sp - > fb_base = ioremap ( sp - > fb_base_phys , sp - > fb_size ) ;
2012-08-19 12:44:24 +04:00
if ( ! sp - > fb_base ) {
err = - ENOMEM ;
2007-05-07 09:45:50 +04:00
goto err_release_pci ;
2012-08-19 12:44:24 +04:00
}
2007-05-07 09:45:50 +04:00
err = s3d_set_fbinfo ( sp ) ;
if ( err )
goto err_unmap_fb ;
pci_set_drvdata ( pdev , info ) ;
printk ( " s3d: Found device at %s \n " , pci_name ( pdev ) ) ;
err = register_framebuffer ( info ) ;
if ( err < 0 ) {
printk ( KERN_ERR " s3d: Could not register framebuffer %s \n " ,
pci_name ( pdev ) ) ;
goto err_unmap_fb ;
}
return 0 ;
err_unmap_fb :
iounmap ( sp - > fb_base ) ;
err_release_pci :
pci_release_region ( pdev , 1 ) ;
err_release_fb :
framebuffer_release ( info ) ;
err_disable :
pci_disable_device ( pdev ) ;
err_out :
return err ;
}
2017-08-01 18:20:41 +03:00
static const struct pci_device_id s3d_pci_table [ ] = {
2007-05-08 01:02:51 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_3DLABS , 0x002c ) , } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_3DLABS , 0x002d ) , } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_3DLABS , 0x002e ) , } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_3DLABS , 0x002f ) , } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_3DLABS , 0x0030 ) , } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_3DLABS , 0x0031 ) , } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_3DLABS , 0x0032 ) , } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_3DLABS , 0x0033 ) , } ,
2007-05-07 09:45:50 +04:00
{ 0 , }
} ;
static struct pci_driver s3d_driver = {
2016-02-22 06:13:12 +03:00
. driver = {
. suppress_bind_attrs = true ,
} ,
2007-05-07 09:45:50 +04:00
. name = " s3d " ,
. id_table = s3d_pci_table ,
. probe = s3d_pci_register ,
} ;
static int __init s3d_init ( void )
{
if ( fb_get_options ( " s3d " , NULL ) )
return - ENODEV ;
return pci_register_driver ( & s3d_driver ) ;
}
2016-02-22 06:13:12 +03:00
device_initcall ( s3d_init ) ;