2005-11-07 08:33:38 +00:00
/*
* drivers / mtd / maps / tqm834x . c
*
* MTD mapping driver for TQM834x boards
*
* Copyright 2005 Wolfgang Denk , DENX Software Engineering , < wd @ denx . de > .
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed " as is " without any warranty of any
* kind , whether express or implied .
*
*/
# include <linux/config.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/slab.h>
# include <asm/io.h>
# include <asm/ppcboot.h>
# include <linux/mtd/mtd.h>
# include <linux/mtd/map.h>
# include <linux/mtd/partitions.h>
# define FLASH_BANK_MAX 2
extern unsigned char __res [ ] ;
/* trivial struct to describe partition information */
struct mtd_part_def
{
int nums ;
unsigned char * type ;
struct mtd_partition * mtd_part ;
} ;
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 unsigned long start_scan_addr ;
# ifdef CONFIG_MTD_PARTITIONS
/*
* The following defines the partition layout of TQM834x boards .
*
* See include / linux / mtd / partitions . h for definition of the
* mtd_partition structure .
*
* Assume minimal initial size of 4 MiB per bank , will be updated
* later in init_tqm834x_mtd ( ) routine .
*/
/* Partition definition for the first flash bank which is always present. */
static struct mtd_partition tqm834x_partitions_bank1 [ ] = {
{
. name = " u-boot " , /* u-boot firmware */
. offset = 0x00000000 ,
. size = 0x00040000 , /* 256 KiB */
/*mask_flags: MTD_WRITEABLE, * force read-only */
} ,
{
. name = " env " , /* u-boot environment */
. offset = 0x00040000 ,
. size = 0x00020000 , /* 128 KiB */
/*mask_flags: MTD_WRITEABLE, * force read-only */
} ,
{
. name = " kernel " , /* linux kernel image */
. offset = 0x00060000 ,
. size = 0x00100000 , /* 1 MiB */
/*mask_flags: MTD_WRITEABLE, * force read-only */
} ,
{
. name = " initrd " , /* ramdisk image */
. offset = 0x00160000 ,
. size = 0x00200000 , /* 2 MiB */
} ,
{
. name = " user " , /* user data */
. offset = 0x00360000 ,
. size = 0x000a0000 , /* remaining space */
/* NOTE: this parttion size is re-calcated in */
/* init_tqm834x_mtd() to cover actual remaining space. */
} ,
} ;
/* Partition definition for the second flash bank which may be present on some
* TQM834x boards .
*/
static struct mtd_partition tqm834x_partitions_bank2 [ ] = {
{
. name = " jffs2 " , /* jffs2 filesystem */
. offset = 0x00000000 ,
. size = 0x00400000 , /* whole device */
/* NOTE: this parttion size is re-calcated in */
/* init_tqm834x_mtd() to cover actual device size. */
} ,
} ;
# endif /* CONFIG_MTD_PARTITIONS */
static int __init init_tqm834x_mtd ( void )
{
int idx = 0 , ret = 0 ;
unsigned long flash_addr , flash_size , mtd_size = 0 ;
/* pointer to TQM834x board info data */
bd_t * bd = ( bd_t * ) __res ;
# ifdef CONFIG_MTD_CMDLINE_PARTS
int n ;
char mtdid [ 4 ] ;
const char * part_probes [ ] = { " cmdlinepart " , NULL } ;
# endif
flash_addr = bd - > bi_flashstart ;
flash_size = bd - > bi_flashsize ;
/* request maximum flash size address space */
start_scan_addr = ( unsigned long ) ioremap ( flash_addr , flash_size ) ;
if ( ! start_scan_addr ) {
printk ( " %s: Failed to ioremap address: 0x%lx \n " ,
__FUNCTION__ , flash_addr ) ;
return - EIO ;
}
for ( idx = 0 ; idx < FLASH_BANK_MAX ; idx + + ) {
if ( mtd_size > = flash_size )
break ;
pr_debug ( " %s: chip probing count %d \n " , __FUNCTION__ , idx ) ;
2005-11-07 11:15:40 +00:00
map_banks [ idx ] =
2005-11-07 08:33:38 +00:00
( struct map_info * ) kmalloc ( sizeof ( struct map_info ) ,
GFP_KERNEL ) ;
if ( map_banks [ idx ] = = NULL ) {
ret = - ENOMEM ;
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 = = NULL ) {
ret = - ENOMEM ;
goto error_mem ;
}
memset ( ( void * ) map_banks [ idx ] - > name , 0 , 16 ) ;
sprintf ( map_banks [ idx ] - > name , " TQM834x-%d " , idx ) ;
map_banks [ idx ] - > size = flash_size ;
map_banks [ idx ] - > bankwidth = 4 ;
simple_map_init ( map_banks [ idx ] ) ;
map_banks [ idx ] - > virt = ( void __iomem * )
( start_scan_addr + ( ( idx > 0 ) ?
( mtd_banks [ idx - 1 ] ? mtd_banks [ idx - 1 ] - > size : 0 ) : 0 ) ) ;
map_banks [ idx ] - > phys =
flash_addr + ( ( idx > 0 ) ?
( mtd_banks [ idx - 1 ] ? mtd_banks [ idx - 1 ] - > size : 0 ) : 0 ) ;
/* 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 + + ;
pr_debug ( " %s: bank %ld, name: %s, size: %d bytes \n " ,
__FUNCTION__ , num_banks ,
mtd_banks [ idx ] - > name , mtd_banks [ idx ] - > size ) ;
}
}
/* no supported flash chips found */
if ( ! num_banks ) {
printk ( " TQM834x: No supported flash chips found! \n " ) ;
ret = - ENXIO ;
goto error_mem ;
}
# ifdef CONFIG_MTD_PARTITIONS
/*
* Select static partition definitions
*/
n = ARRAY_SIZE ( tqm834x_partitions_bank1 ) ;
part_banks [ 0 ] . mtd_part = tqm834x_partitions_bank1 ;
part_banks [ 0 ] . type = " static image bank1 " ;
part_banks [ 0 ] . nums = n ;
/* update last partition size to cover actual remaining space */
tqm834x_partitions_bank1 [ n - 1 ] . size =
mtd_banks [ 0 ] - > size -
tqm834x_partitions_bank1 [ n - 1 ] . offset ;
2005-11-07 11:15:40 +00:00
2005-11-07 08:33:38 +00:00
/* check if we have second bank? */
if ( num_banks = = 2 ) {
n = ARRAY_SIZE ( tqm834x_partitions_bank2 ) ;
part_banks [ 1 ] . mtd_part = tqm834x_partitions_bank2 ;
part_banks [ 1 ] . type = " static image bank2 " ;
part_banks [ 1 ] . nums = n ;
/* update last partition size to cover actual remaining space */
tqm834x_partitions_bank2 [ n - 1 ] . size =
mtd_banks [ 1 ] - > size -
tqm834x_partitions_bank2 [ n - 1 ] . offset ;
}
for ( idx = 0 ; idx < num_banks ; idx + + ) {
# ifdef CONFIG_MTD_CMDLINE_PARTS
sprintf ( mtdid , " %d " , idx ) ;
n = parse_mtd_partitions ( mtd_banks [ idx ] ,
part_probes ,
& part_banks [ idx ] . mtd_part ,
0 ) ;
pr_debug ( " %s: %d command line partitions on bank %s \n " ,
__FUNCTION__ , n , mtdid ) ;
if ( n > 0 ) {
part_banks [ idx ] . type = " command line " ;
part_banks [ idx ] . nums = n ;
}
# endif /* CONFIG_MTD_CMDLINE_PARTS */
if ( part_banks [ idx ] . nums = = 0 ) {
printk ( KERN_NOTICE
" TQM834x flash bank %d: no partition info "
" available, registering whole device \n " , idx ) ;
add_mtd_device ( mtd_banks [ idx ] ) ;
} else {
2005-11-07 11:15:40 +00:00
printk ( KERN_NOTICE
2005-11-07 08:33:38 +00:00
" TQM834x flash bank %d: Using %s partition "
" definition \n " , idx , part_banks [ idx ] . type ) ;
add_mtd_partitions ( mtd_banks [ idx ] ,
2005-11-07 11:15:40 +00:00
part_banks [ idx ] . mtd_part ,
2005-11-07 08:33:38 +00:00
part_banks [ idx ] . nums ) ;
}
}
# else /* ! CONFIG_MTD_PARTITIONS */
printk ( KERN_NOTICE " TQM834x flash: registering %d flash banks "
" at once \n " , num_banks ) ;
for ( idx = 0 ; idx < num_banks ; idx + + )
add_mtd_device ( mtd_banks [ idx ] ) ;
# endif /* CONFIG_MTD_PARTITIONS */
return 0 ;
error_mem :
for ( idx = 0 ; idx < FLASH_BANK_MAX ; idx + + ) {
if ( map_banks [ idx ] ! = NULL ) {
if ( map_banks [ idx ] - > name ! = NULL ) {
kfree ( map_banks [ idx ] - > name ) ;
map_banks [ idx ] - > name = NULL ;
}
kfree ( map_banks [ idx ] ) ;
map_banks [ idx ] = NULL ;
}
}
iounmap ( ( void * ) start_scan_addr ) ;
return ret ;
}
static void __exit cleanup_tqm834x_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 ( ( void * ) start_scan_addr ) ;
start_scan_addr = 0 ;
}
}
module_init ( init_tqm834x_mtd ) ;
module_exit ( cleanup_tqm834x_mtd ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Wolfgang Denk <wd@denx.de> " ) ;
MODULE_DESCRIPTION ( " MTD map driver for TQM834x boards " ) ;