2005-04-16 15:20:36 -07:00
/*
2005-11-07 11:15:40 +00:00
* Handle mapping of the flash memory access routines
2005-04-16 15:20:36 -07:00
* on TQM8xxL based devices .
*
2005-11-07 11:15:40 +00:00
* $ Id : tqm8xxl . c , v 1.15 2005 / 11 / 07 11 : 14 : 28 gleixner Exp $
2005-04-16 15:20:36 -07:00
*
* based on rpxlite . c
*
* Copyright ( C ) 2001 Kirk Lee < kirk @ hpc . ee . ntu . edu . tw >
*
* This code is GPLed
2005-11-07 11:15:40 +00:00
*
2005-04-16 15:20:36 -07:00
*/
/*
* According to TQM8xxL hardware manual , TQM8xxL series have
* following flash memory organisations :
* | capacity | | chip type | | bank0 | | bank1 |
* 2 MiB 512 Kx16 2 MiB 0
* 4 MiB 1 Mx16 4 MiB 0
* 8 MiB 1 Mx16 4 MiB 4 MiB
2005-11-07 11:15:40 +00:00
* Thus , we choose CONFIG_MTD_CFI_I2 & CONFIG_MTD_CFI_B4 at
2005-04-16 15:20:36 -07:00
* kernel configuration .
*/
# include <linux/module.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/init.h>
2005-10-30 15:03:48 -08:00
# include <linux/slab.h>
2005-04-16 15:20:36 -07:00
# include <linux/mtd/mtd.h>
# include <linux/mtd/map.h>
# include <linux/mtd/partitions.h>
2005-10-30 15:03:48 -08:00
# include <asm/io.h>
2005-04-16 15:20:36 -07:00
# define FLASH_ADDR 0x40000000
# define FLASH_SIZE 0x00800000
# define FLASH_BANK_MAX 4
// trivial struct to describe partition information
struct mtd_part_def
{
int nums ;
unsigned char * type ;
struct mtd_partition * mtd_part ;
} ;
//static struct mtd_info *mymtd;
static struct mtd_info * mtd_banks [ FLASH_BANK_MAX ] ;
static struct map_info * map_banks [ FLASH_BANK_MAX ] ;
static struct mtd_part_def part_banks [ FLASH_BANK_MAX ] ;
static unsigned long num_banks ;
static void __iomem * start_scan_addr ;
/*
* Here are partition information for all known TQM8xxL series devices .
* See include / linux / mtd / partitions . h for definition of the mtd_partition
* structure .
2005-11-07 11:15:40 +00:00
*
2005-04-16 15:20:36 -07:00
* The * _max_flash_size is the maximum possible mapped flash size which
2005-11-07 11:15:40 +00:00
* is not necessarily the actual flash size . It must correspond to the
2005-04-16 15:20:36 -07:00
* value specified in the mapping definition defined by the
* " struct map_desc *_io_desc " for the corresponding machine .
*/
# ifdef CONFIG_MTD_PARTITIONS
/* Currently, TQM8xxL has upto 8MiB flash */
static unsigned long tqm8xxl_max_flash_size = 0x00800000 ;
/* partition definition for first flash bank
* ( cf . " drivers/char/flash_config.c " )
*/
static struct mtd_partition tqm8xxl_partitions [ ] = {
{
. name = " ppcboot " ,
. offset = 0x00000000 ,
. size = 0x00020000 , /* 128KB */
. mask_flags = MTD_WRITEABLE , /* force read-only */
} ,
{
. name = " kernel " , /* default kernel image */
. offset = 0x00020000 ,
. size = 0x000e0000 ,
. mask_flags = MTD_WRITEABLE , /* force read-only */
} ,
{
. name = " user " ,
. offset = 0x00100000 ,
. size = 0x00100000 ,
} ,
{
. name = " initrd " ,
. offset = 0x00200000 ,
. size = 0x00200000 ,
}
} ;
/* partition definition for second flash bank */
static struct mtd_partition tqm8xxl_fs_partitions [ ] = {
{
. name = " cramfs " ,
. offset = 0x00000000 ,
. size = 0x00200000 ,
} ,
{
. name = " jffs " ,
. offset = 0x00200000 ,
. size = 0x00200000 ,
//.size = MTDPART_SIZ_FULL,
}
} ;
# endif
int __init init_tqm_mtd ( void )
{
int idx = 0 , ret = 0 ;
unsigned long flash_addr , flash_size , mtd_size = 0 ;
/* pointer to TQM8xxL board info data */
bd_t * bd = ( bd_t * ) __res ;
flash_addr = bd - > bi_flashstart ;
flash_size = bd - > bi_flashsize ;
//request maximum flash size address space
start_scan_addr = ioremap ( flash_addr , flash_size ) ;
if ( ! start_scan_addr ) {
printk ( KERN_WARNING " %s:Failed to ioremap address:0x%x \n " , __FUNCTION__ , flash_addr ) ;
return - EIO ;
}
for ( idx = 0 ; idx < FLASH_BANK_MAX ; idx + + ) {
if ( mtd_size > = flash_size )
break ;
2005-11-07 11:15:40 +00:00
2005-04-16 15:20:36 -07:00
printk ( KERN_INFO " %s: chip probing count %d \n " , __FUNCTION__ , idx ) ;
2005-11-07 11:15:40 +00:00
2005-04-16 15:20:36 -07:00
map_banks [ idx ] = ( struct map_info * ) kmalloc ( sizeof ( struct map_info ) , GFP_KERNEL ) ;
if ( map_banks [ idx ] = = NULL ) {
ret = - ENOMEM ;
/* FIXME: What if some MTD devices were probed already? */
goto error_mem ;
}
memset ( ( void * ) map_banks [ idx ] , 0 , sizeof ( struct map_info ) ) ;
map_banks [ idx ] - > name = ( char * ) kmalloc ( 16 , GFP_KERNEL ) ;
if ( ! map_banks [ idx ] - > name ) {
ret = - ENOMEM ;
/* FIXME: What if some MTD devices were probed already? */
goto error_mem ;
}
sprintf ( map_banks [ idx ] - > name , " TQM8xxL%d " , idx ) ;
map_banks [ idx ] - > size = flash_size ;
map_banks [ idx ] - > bankwidth = 4 ;
simple_map_init ( map_banks [ idx ] ) ;
map_banks [ idx ] - > virt = start_scan_addr ;
map_banks [ idx ] - > phys = flash_addr ;
/* FIXME: This looks utterly bogus, but I'm trying to
preserve the behaviour of the original ( shown here ) . . .
map_banks [ idx ] - > map_priv_1 =
start_scan_addr + ( ( idx > 0 ) ?
( mtd_banks [ idx - 1 ] ? mtd_banks [ idx - 1 ] - > size : 0 ) : 0 ) ;
*/
if ( idx & & mtd_banks [ idx - 1 ] ) {
map_banks [ idx ] - > virt + = mtd_banks [ idx - 1 ] - > size ;
map_banks [ idx ] - > phys + = mtd_banks [ idx - 1 ] - > size ;
}
//start to probe flash chips
mtd_banks [ idx ] = do_map_probe ( " cfi_probe " , map_banks [ idx ] ) ;
if ( mtd_banks [ idx ] ) {
mtd_banks [ idx ] - > owner = THIS_MODULE ;
mtd_size + = mtd_banks [ idx ] - > size ;
num_banks + + ;
2005-11-07 11:15:40 +00:00
printk ( KERN_INFO " %s: bank%d, name:%s, size:%dbytes \n " , __FUNCTION__ , num_banks ,
2005-04-16 15:20:36 -07:00
mtd_banks [ idx ] - > name , mtd_banks [ idx ] - > size ) ;
}
}
/* no supported flash chips found */
if ( ! num_banks ) {
printk ( KERN_NOTICE " TQM8xxL: No support flash chips found! \n " ) ;
ret = - ENXIO ;
goto error_mem ;
}
# ifdef CONFIG_MTD_PARTITIONS
/*
* Select Static partition definitions
*/
part_banks [ 0 ] . mtd_part = tqm8xxl_partitions ;
part_banks [ 0 ] . type = " Static image " ;
part_banks [ 0 ] . nums = ARRAY_SIZE ( tqm8xxl_partitions ) ;
part_banks [ 1 ] . mtd_part = tqm8xxl_fs_partitions ;
part_banks [ 1 ] . type = " Static file system " ;
part_banks [ 1 ] . nums = ARRAY_SIZE ( tqm8xxl_fs_partitions ) ;
for ( idx = 0 ; idx < num_banks ; idx + + ) {
if ( part_banks [ idx ] . nums = = 0 ) {
printk ( KERN_NOTICE " TQM flash%d: no partition info available, registering whole flash at once \n " , idx ) ;
add_mtd_device ( mtd_banks [ idx ] ) ;
} else {
printk ( KERN_NOTICE " TQM flash%d: Using %s partition definition \n " ,
idx , part_banks [ idx ] . type ) ;
2005-11-07 11:15:40 +00:00
add_mtd_partitions ( mtd_banks [ idx ] , part_banks [ idx ] . mtd_part ,
2005-04-16 15:20:36 -07:00
part_banks [ idx ] . nums ) ;
}
}
# else
printk ( KERN_NOTICE " TQM flash: registering %d whole flash banks at once \n " , num_banks ) ;
for ( idx = 0 ; idx < num_banks ; idx + + )
add_mtd_device ( mtd_banks [ idx ] ) ;
# endif
return 0 ;
error_mem :
for ( idx = 0 ; idx < FLASH_BANK_MAX ; idx + + ) {
if ( map_banks [ idx ] ! = NULL ) {
2005-11-07 01:01:27 -08:00
kfree ( map_banks [ idx ] - > name ) ;
map_banks [ idx ] - > name = NULL ;
2005-04-16 15:20:36 -07:00
kfree ( map_banks [ idx ] ) ;
map_banks [ idx ] = NULL ;
}
}
error :
iounmap ( start_scan_addr ) ;
return ret ;
}
static void __exit cleanup_tqm_mtd ( void )
{
unsigned int idx = 0 ;
for ( idx = 0 ; idx < num_banks ; idx + + ) {
/* destroy mtd_info previously allocated */
if ( mtd_banks [ idx ] ) {
del_mtd_partitions ( mtd_banks [ idx ] ) ;
map_destroy ( mtd_banks [ idx ] ) ;
}
/* release map_info not used anymore */
kfree ( map_banks [ idx ] - > name ) ;
kfree ( map_banks [ idx ] ) ;
}
if ( start_scan_addr ) {
iounmap ( start_scan_addr ) ;
start_scan_addr = 0 ;
}
}
module_init ( init_tqm_mtd ) ;
module_exit ( cleanup_tqm_mtd ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Kirk Lee <kirk@hpc.ee.ntu.edu.tw> " ) ;
MODULE_DESCRIPTION ( " MTD map driver for TQM8xxL boards " ) ;