2005-11-07 14:15:40 +03:00
/* linux/drivers/mtd/maps/scx200_docflash.c
2005-04-17 02:20:36 +04:00
Copyright ( c ) 2001 , 2002 Christer Weinigel < wingel @ nano - system . com >
2005-11-07 14:15:40 +03:00
$ Id : scx200_docflash . c , v 1.12 2005 / 11 / 07 11 : 14 : 28 gleixner Exp $
2005-04-17 02:20:36 +04:00
National Semiconductor SCx200 flash mapped with DOCCS
*/
# include <linux/module.h>
# include <linux/config.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <asm/io.h>
# include <linux/mtd/mtd.h>
# include <linux/mtd/map.h>
# include <linux/mtd/partitions.h>
# include <linux/pci.h>
# include <linux/scx200.h>
# define NAME "scx200_docflash"
MODULE_AUTHOR ( " Christer Weinigel <wingel@hack.org> " ) ;
MODULE_DESCRIPTION ( " NatSemi SCx200 DOCCS Flash Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
static int probe = 0 ; /* Don't autoprobe */
static unsigned size = 0x1000000 ; /* 16 MiB the whole ISA address space */
static unsigned width = 8 ; /* Default to 8 bits wide */
static char * flashtype = " cfi_probe " ;
module_param ( probe , int , 0 ) ;
MODULE_PARM_DESC ( probe , " Probe for a BIOS mapping " ) ;
module_param ( size , int , 0 ) ;
MODULE_PARM_DESC ( size , " Size of the flash mapping " ) ;
module_param ( width , int , 0 ) ;
MODULE_PARM_DESC ( width , " Data width of the flash mapping (8/16) " ) ;
module_param ( flashtype , charp , 0 ) ;
MODULE_PARM_DESC ( flashtype , " Type of MTD probe to do " ) ;
static struct resource docmem = {
. flags = IORESOURCE_MEM ,
. name = " NatSemi SCx200 DOCCS Flash " ,
} ;
static struct mtd_info * mymtd ;
# ifdef CONFIG_MTD_PARTITIONS
static struct mtd_partition partition_info [ ] = {
2005-11-07 14:15:40 +03:00
{
. name = " DOCCS Boot kernel " ,
. offset = 0 ,
2005-04-17 02:20:36 +04:00
. size = 0xc0000
} ,
2005-11-07 14:15:40 +03:00
{
. name = " DOCCS Low BIOS " ,
. offset = 0xc0000 ,
2005-04-17 02:20:36 +04:00
. size = 0x40000
} ,
2005-11-07 14:15:40 +03:00
{
. name = " DOCCS File system " ,
. offset = 0x100000 ,
2005-04-17 02:20:36 +04:00
. size = ~ 0 /* calculate from flash size */
} ,
2005-11-07 14:15:40 +03:00
{
. name = " DOCCS High BIOS " ,
2005-04-17 02:20:36 +04:00
. offset = ~ 0 , /* calculate from flash size */
. size = 0x80000
} ,
} ;
# define NUM_PARTITIONS (sizeof(partition_info) / sizeof(partition_info[0]))
# endif
static struct map_info scx200_docflash_map = {
. name = " NatSemi SCx200 DOCCS Flash " ,
} ;
static int __init init_scx200_docflash ( void )
{
unsigned u ;
unsigned base ;
unsigned ctrl ;
unsigned pmr ;
struct pci_dev * bridge ;
printk ( KERN_DEBUG NAME " : NatSemi SCx200 DOCCS Flash Driver \n " ) ;
2005-11-07 14:15:40 +03:00
if ( ( bridge = pci_find_device ( PCI_VENDOR_ID_NS ,
2005-04-17 02:20:36 +04:00
PCI_DEVICE_ID_NS_SCx200_BRIDGE ,
NULL ) ) = = NULL )
return - ENODEV ;
/* check that we have found the configuration block */
if ( ! scx200_cb_present ( ) )
return - ENODEV ;
if ( probe ) {
/* Try to use the present flash mapping if any */
pci_read_config_dword ( bridge , SCx200_DOCCS_BASE , & base ) ;
pci_read_config_dword ( bridge , SCx200_DOCCS_CTRL , & ctrl ) ;
pmr = inl ( scx200_cb_base + SCx200_PMR ) ;
if ( base = = 0
| | ( ctrl & 0x07000000 ) ! = 0x07000000
| | ( ctrl & 0x0007ffff ) = = 0 )
return - ENODEV ;
size = ( ( ctrl & 0x1fff ) < < 13 ) + ( 1 < < 13 ) ;
for ( u = size ; u > 1 ; u > > = 1 )
;
if ( u ! = 1 )
return - ENODEV ;
if ( pmr & ( 1 < < 6 ) )
width = 16 ;
else
width = 8 ;
docmem . start = base ;
docmem . end = base + size ;
if ( request_resource ( & iomem_resource , & docmem ) ) {
printk ( KERN_ERR NAME " : unable to allocate memory for flash mapping \n " ) ;
return - ENOMEM ;
}
} else {
for ( u = size ; u > 1 ; u > > = 1 )
;
if ( u ! = 1 ) {
printk ( KERN_ERR NAME " : invalid size for flash mapping \n " ) ;
return - EINVAL ;
}
2005-11-07 14:15:40 +03:00
2005-04-17 02:20:36 +04:00
if ( width ! = 8 & & width ! = 16 ) {
printk ( KERN_ERR NAME " : invalid bus width for flash mapping \n " ) ;
return - EINVAL ;
}
2005-11-07 14:15:40 +03:00
if ( allocate_resource ( & iomem_resource , & docmem ,
2005-04-17 02:20:36 +04:00
size ,
2005-11-07 14:15:40 +03:00
0xc0000000 , 0xffffffff ,
2005-04-17 02:20:36 +04:00
size , NULL , NULL ) ) {
printk ( KERN_ERR NAME " : unable to allocate memory for flash mapping \n " ) ;
return - ENOMEM ;
}
2005-11-07 14:15:40 +03:00
2005-04-17 02:20:36 +04:00
ctrl = 0x07000000 | ( ( size - 1 ) > > 13 ) ;
printk ( KERN_INFO " DOCCS BASE=0x%08lx, CTRL=0x%08lx \n " , ( long ) docmem . start , ( long ) ctrl ) ;
2005-11-07 14:15:40 +03:00
2005-04-17 02:20:36 +04:00
pci_write_config_dword ( bridge , SCx200_DOCCS_BASE , docmem . start ) ;
pci_write_config_dword ( bridge , SCx200_DOCCS_CTRL , ctrl ) ;
pmr = inl ( scx200_cb_base + SCx200_PMR ) ;
2005-11-07 14:15:40 +03:00
2005-04-17 02:20:36 +04:00
if ( width = = 8 ) {
pmr & = ~ ( 1 < < 6 ) ;
} else {
pmr | = ( 1 < < 6 ) ;
}
outl ( pmr , scx200_cb_base + SCx200_PMR ) ;
}
2005-11-07 14:15:40 +03:00
printk ( KERN_INFO NAME " : DOCCS mapped at 0x%lx-0x%lx, width %d \n " ,
2005-04-17 02:20:36 +04:00
docmem . start , docmem . end , width ) ;
scx200_docflash_map . size = size ;
if ( width = = 8 )
scx200_docflash_map . bankwidth = 1 ;
else
scx200_docflash_map . bankwidth = 2 ;
simple_map_init ( & scx200_docflash_map ) ;
scx200_docflash_map . phys = docmem . start ;
scx200_docflash_map . virt = ioremap ( docmem . start , scx200_docflash_map . size ) ;
if ( ! scx200_docflash_map . virt ) {
printk ( KERN_ERR NAME " : failed to ioremap the flash \n " ) ;
release_resource ( & docmem ) ;
return - EIO ;
}
mymtd = do_map_probe ( flashtype , & scx200_docflash_map ) ;
if ( ! mymtd ) {
printk ( KERN_ERR NAME " : unable to detect flash \n " ) ;
iounmap ( scx200_docflash_map . virt ) ;
release_resource ( & docmem ) ;
return - ENXIO ;
}
if ( size < mymtd - > size )
printk ( KERN_WARNING NAME " : warning, flash mapping is smaller than flash size \n " ) ;
mymtd - > owner = THIS_MODULE ;
# ifdef CONFIG_MTD_PARTITIONS
partition_info [ 3 ] . offset = mymtd - > size - partition_info [ 3 ] . size ;
partition_info [ 2 ] . size = partition_info [ 3 ] . offset - partition_info [ 2 ] . offset ;
add_mtd_partitions ( mymtd , partition_info , NUM_PARTITIONS ) ;
# else
add_mtd_device ( mymtd ) ;
# endif
return 0 ;
}
static void __exit cleanup_scx200_docflash ( void )
{
if ( mymtd ) {
# ifdef CONFIG_MTD_PARTITIONS
del_mtd_partitions ( mymtd ) ;
# else
del_mtd_device ( mymtd ) ;
# endif
map_destroy ( mymtd ) ;
}
if ( scx200_docflash_map . virt ) {
iounmap ( scx200_docflash_map . virt ) ;
release_resource ( & docmem ) ;
}
}
module_init ( init_scx200_docflash ) ;
module_exit ( cleanup_scx200_docflash ) ;
/*
Local variables :
compile - command : " make -k -C ../../.. SUBDIRS=drivers/mtd/maps modules "
c - basic - offset : 8
End :
*/