2005-04-17 02:20:36 +04:00
/*
* drivers / mtd / nand . c
*
* Overview :
* This is the generic MTD driver for NAND flash devices . It should be
* capable of working with almost all NAND chips currently available .
* Basic support for AG - AND chips is provided .
2005-11-07 14:15:49 +03:00
*
2005-04-17 02:20:36 +04:00
* Additional technical information is available on
* http : //www.linux-mtd.infradead.org/tech/nand.html
2005-11-07 14:15:49 +03:00
*
2005-04-17 02:20:36 +04:00
* Copyright ( C ) 2000 Steven J . Hill ( sjhill @ realitydiluted . com )
2006-05-23 13:50:56 +04:00
* 2002 Thomas Gleixner ( tglx @ linutronix . de )
2005-04-17 02:20:36 +04:00
*
2005-11-07 14:15:49 +03:00
* 02 - 08 - 2004 tglx : support for strange chips , which cannot auto increment
2005-04-17 02:20:36 +04:00
* pages on read / read_oob
*
* 03 - 17 - 2004 tglx : Check ready before auto increment check . Simon Bayes
* pointed this out , as he marked an auto increment capable chip
* as NOAUTOINCR in the board driver .
* Make reads over block boundaries work too
*
* 04 - 14 - 2004 tglx : first working version for 2 k page size chips
2005-11-07 14:15:49 +03:00
*
2005-04-17 02:20:36 +04:00
* 05 - 19 - 2004 tglx : Basic support for Renesas AG - AND chips
*
* 09 - 24 - 2004 tglx : add support for hardware controllers ( e . g . ECC ) shared
2006-05-23 13:50:56 +04:00
* among multiple independend devices . Suggestions and initial
* patch from Ben Dooks < ben - mtd @ fluff . org >
*
* 12 - 05 - 2004 dmarlin : add workaround for Renesas AG - AND chips " disturb "
* issue . Basically , any block not rewritten may lose data when
* surrounding blocks are rewritten many times . JFFS2 ensures
* this doesn ' t happen for blocks it uses , but the Bad Block
* Table ( s ) may not be rewritten . To ensure they do not lose
* data , force them to be rewritten when some of the surrounding
* blocks are erased . Rather than tracking a specific nearby
* block ( which could itself go bad ) , use a page address ' mask ' to
* select several blocks in the same area , and rewrite the BBT
* when any of them are erased .
*
* 01 - 03 - 2005 dmarlin : added support for the device recovery command sequence
* for Renesas AG - AND chips . If there was a sudden loss of power
* during an erase operation , a " device recovery " operation must
* be performed when power is restored to ensure correct
* operation .
*
* 01 - 20 - 2005 dmarlin : added support for optional hardware specific callback
* routine to perform extra error status checks on erase and write
* failures . This required adding a wrapper function for
* nand_read_ecc .
2005-01-24 06:07:46 +03:00
*
2005-09-15 17:58:53 +04:00
* 08 - 20 - 2005 vwool : suspend / resume added
*
2005-04-17 02:20:36 +04:00
* Credits :
2005-11-07 14:15:49 +03:00
* David Woodhouse for adding multichip support
*
2005-04-17 02:20:36 +04:00
* Aleph One Ltd . and Toby Churchill Ltd . for supporting the
* rework for 2 K page size chips
*
* TODO :
* Enable cached programming for 2 k page size chips
* Check , if mtd - > ecctype should be set to MTD_ECC_HW
* if we have HW ecc support .
* The AG - AND chips have nice features for speed improvement ,
* which are not supported yet . Read / program 4 pages in one go .
*
2005-09-15 17:58:53 +04:00
* $ Id : nand_base . c , v 1.150 2005 / 09 / 15 13 : 58 : 48 vwool Exp $
2005-04-17 02:20:36 +04:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
*/
2006-05-14 04:20:46 +04:00
# include <linux/module.h>
2005-04-17 02:20:36 +04:00
# include <linux/delay.h>
# include <linux/errno.h>
2006-05-23 13:54:38 +04:00
# include <linux/err.h>
2005-04-17 02:20:36 +04:00
# include <linux/sched.h>
# include <linux/slab.h>
# include <linux/types.h>
# include <linux/mtd/mtd.h>
# include <linux/mtd/nand.h>
# include <linux/mtd/nand_ecc.h>
# include <linux/mtd/compatmac.h>
# include <linux/interrupt.h>
# include <linux/bitops.h>
2006-03-31 14:31:14 +04:00
# include <linux/leds.h>
2005-04-17 02:20:36 +04:00
# include <asm/io.h>
# ifdef CONFIG_MTD_PARTITIONS
# include <linux/mtd/partitions.h>
# endif
/* Define default oob placement schemes for large and small page devices */
static struct nand_oobinfo nand_oob_8 = {
. useecc = MTD_NANDECC_AUTOPLACE ,
. eccbytes = 3 ,
. eccpos = { 0 , 1 , 2 } ,
2006-05-13 21:07:53 +04:00
. oobfree = { { 3 , 2 } , { 6 , 2 } }
2005-04-17 02:20:36 +04:00
} ;
static struct nand_oobinfo nand_oob_16 = {
. useecc = MTD_NANDECC_AUTOPLACE ,
. eccbytes = 6 ,
. eccpos = { 0 , 1 , 2 , 3 , 6 , 7 } ,
2006-05-13 21:07:53 +04:00
. oobfree = { { 8 , 8 } }
2005-04-17 02:20:36 +04:00
} ;
static struct nand_oobinfo nand_oob_64 = {
. useecc = MTD_NANDECC_AUTOPLACE ,
. eccbytes = 24 ,
. eccpos = {
2006-05-13 21:07:53 +04:00
40 , 41 , 42 , 43 , 44 , 45 , 46 , 47 ,
48 , 49 , 50 , 51 , 52 , 53 , 54 , 55 ,
56 , 57 , 58 , 59 , 60 , 61 , 62 , 63 } ,
. oobfree = { { 2 , 38 } }
2005-04-17 02:20:36 +04:00
} ;
/* This is used for padding purposes in nand_write_oob */
2006-05-23 13:52:35 +04:00
static uint8_t ffchars [ ] = {
2005-04-17 02:20:36 +04:00
0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff ,
0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff ,
0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff ,
0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff ,
0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff ,
0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff ,
0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff ,
0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff ,
} ;
/*
* NAND low - level MTD interface functions
*/
2006-05-23 13:52:35 +04:00
static void nand_write_buf ( struct mtd_info * mtd , const uint8_t * buf , int len ) ;
static void nand_read_buf ( struct mtd_info * mtd , uint8_t * buf , int len ) ;
static int nand_verify_buf ( struct mtd_info * mtd , const uint8_t * buf , int len ) ;
2005-04-17 02:20:36 +04:00
2006-05-23 13:50:56 +04:00
static int nand_read ( struct mtd_info * mtd , loff_t from , size_t len ,
2006-05-23 13:52:35 +04:00
size_t * retlen , uint8_t * buf ) ;
2006-05-13 21:07:53 +04:00
static int nand_read_ecc ( struct mtd_info * mtd , loff_t from , size_t len ,
2006-05-23 13:52:35 +04:00
size_t * retlen , uint8_t * buf , uint8_t * eccbuf ,
2006-05-23 13:50:56 +04:00
struct nand_oobinfo * oobsel ) ;
static int nand_read_oob ( struct mtd_info * mtd , loff_t from , size_t len ,
2006-05-23 13:52:35 +04:00
size_t * retlen , uint8_t * buf ) ;
2006-05-23 13:50:56 +04:00
static int nand_write ( struct mtd_info * mtd , loff_t to , size_t len ,
2006-05-23 13:52:35 +04:00
size_t * retlen , const uint8_t * buf ) ;
2006-05-13 21:07:53 +04:00
static int nand_write_ecc ( struct mtd_info * mtd , loff_t to , size_t len ,
2006-05-23 13:52:35 +04:00
size_t * retlen , const uint8_t * buf , uint8_t * eccbuf ,
2006-05-23 13:50:56 +04:00
struct nand_oobinfo * oobsel ) ;
static int nand_write_oob ( struct mtd_info * mtd , loff_t to , size_t len ,
2006-05-23 13:52:35 +04:00
size_t * retlen , const uint8_t * buf ) ;
2006-05-23 13:50:56 +04:00
static int nand_writev ( struct mtd_info * mtd , const struct kvec * vecs ,
unsigned long count , loff_t to , size_t * retlen ) ;
2006-05-13 21:07:53 +04:00
static int nand_writev_ecc ( struct mtd_info * mtd , const struct kvec * vecs ,
2006-05-23 13:50:56 +04:00
unsigned long count , loff_t to , size_t * retlen ,
2006-05-23 13:52:35 +04:00
uint8_t * eccbuf , struct nand_oobinfo * oobsel ) ;
2006-05-13 21:07:53 +04:00
static int nand_erase ( struct mtd_info * mtd , struct erase_info * instr ) ;
static void nand_sync ( struct mtd_info * mtd ) ;
2005-04-17 02:20:36 +04:00
/* Some internal functions */
2006-05-23 13:50:56 +04:00
static int nand_write_page ( struct mtd_info * mtd , struct nand_chip * this ,
2006-05-23 13:52:35 +04:00
int page , uint8_t * oob_buf ,
2006-05-13 21:07:53 +04:00
struct nand_oobinfo * oobsel , int mode ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_MTD_NAND_VERIFY_WRITE
2006-05-23 13:50:56 +04:00
static int nand_verify_pages ( struct mtd_info * mtd , struct nand_chip * this ,
2006-05-23 13:52:35 +04:00
int page , int numpages , uint8_t * oob_buf ,
2006-05-23 13:50:56 +04:00
struct nand_oobinfo * oobsel , int chipnr ,
int oobmode ) ;
2005-04-17 02:20:36 +04:00
# else
# define nand_verify_pages(...) (0)
# endif
2005-11-07 14:15:49 +03:00
2006-05-23 13:50:56 +04:00
static int nand_get_device ( struct nand_chip * this , struct mtd_info * mtd ,
int new_state ) ;
2005-04-17 02:20:36 +04:00
/**
* nand_release_device - [ GENERIC ] release chip
* @ mtd : MTD device structure
2005-11-07 14:15:49 +03:00
*
* Deselect , release chip lock and wake up anyone waiting on the device
2005-04-17 02:20:36 +04:00
*/
2006-05-13 21:07:53 +04:00
static void nand_release_device ( struct mtd_info * mtd )
2005-04-17 02:20:36 +04:00
{
struct nand_chip * this = mtd - > priv ;
/* De-select the NAND device */
this - > select_chip ( mtd , - 1 ) ;
2005-05-31 23:39:20 +04:00
2006-05-23 13:37:03 +04:00
/* Release the controller and the chip */
spin_lock ( & this - > controller - > lock ) ;
this - > controller - > active = NULL ;
this - > state = FL_READY ;
wake_up ( & this - > controller - > wq ) ;
spin_unlock ( & this - > controller - > lock ) ;
2005-04-17 02:20:36 +04:00
}
/**
* nand_read_byte - [ DEFAULT ] read one byte from the chip
* @ mtd : MTD device structure
*
* Default read function for 8 bit buswith
*/
2006-05-23 13:52:35 +04:00
static uint8_t nand_read_byte ( struct mtd_info * mtd )
2005-04-17 02:20:36 +04:00
{
struct nand_chip * this = mtd - > priv ;
return readb ( this - > IO_ADDR_R ) ;
}
/**
* nand_write_byte - [ DEFAULT ] write one byte to the chip
* @ mtd : MTD device structure
* @ byte : pointer to data byte to write
*
* Default write function for 8 it buswith
*/
2006-05-23 13:52:35 +04:00
static void nand_write_byte ( struct mtd_info * mtd , uint8_t byte )
2005-04-17 02:20:36 +04:00
{
struct nand_chip * this = mtd - > priv ;
writeb ( byte , this - > IO_ADDR_W ) ;
}
/**
* nand_read_byte16 - [ DEFAULT ] read one byte endianess aware from the chip
* @ mtd : MTD device structure
*
2005-11-07 14:15:49 +03:00
* Default read function for 16 bit buswith with
2005-04-17 02:20:36 +04:00
* endianess conversion
*/
2006-05-23 13:52:35 +04:00
static uint8_t nand_read_byte16 ( struct mtd_info * mtd )
2005-04-17 02:20:36 +04:00
{
struct nand_chip * this = mtd - > priv ;
2006-05-23 13:52:35 +04:00
return ( uint8_t ) cpu_to_le16 ( readw ( this - > IO_ADDR_R ) ) ;
2005-04-17 02:20:36 +04:00
}
/**
* nand_write_byte16 - [ DEFAULT ] write one byte endianess aware to the chip
* @ mtd : MTD device structure
* @ byte : pointer to data byte to write
*
* Default write function for 16 bit buswith with
* endianess conversion
*/
2006-05-23 13:52:35 +04:00
static void nand_write_byte16 ( struct mtd_info * mtd , uint8_t byte )
2005-04-17 02:20:36 +04:00
{
struct nand_chip * this = mtd - > priv ;
writew ( le16_to_cpu ( ( u16 ) byte ) , this - > IO_ADDR_W ) ;
}
/**
* nand_read_word - [ DEFAULT ] read one word from the chip
* @ mtd : MTD device structure
*
2005-11-07 14:15:49 +03:00
* Default read function for 16 bit buswith without
2005-04-17 02:20:36 +04:00
* endianess conversion
*/
static u16 nand_read_word ( struct mtd_info * mtd )
{
struct nand_chip * this = mtd - > priv ;
return readw ( this - > IO_ADDR_R ) ;
}
/**
* nand_write_word - [ DEFAULT ] write one word to the chip
* @ mtd : MTD device structure
* @ word : data word to write
*
2005-11-07 14:15:49 +03:00
* Default write function for 16 bit buswith without
2005-04-17 02:20:36 +04:00
* endianess conversion
*/
static void nand_write_word ( struct mtd_info * mtd , u16 word )
{
struct nand_chip * this = mtd - > priv ;
writew ( word , this - > IO_ADDR_W ) ;
}
/**
* nand_select_chip - [ DEFAULT ] control CE line
* @ mtd : MTD device structure
* @ chip : chipnumber to select , - 1 for deselect
*
* Default select function for 1 chip devices .
*/
static void nand_select_chip ( struct mtd_info * mtd , int chip )
{
struct nand_chip * this = mtd - > priv ;
2006-05-13 21:07:53 +04:00
switch ( chip ) {
2005-04-17 02:20:36 +04:00
case - 1 :
2005-11-07 14:15:49 +03:00
this - > hwcontrol ( mtd , NAND_CTL_CLRNCE ) ;
2005-04-17 02:20:36 +04:00
break ;
case 0 :
this - > hwcontrol ( mtd , NAND_CTL_SETNCE ) ;
break ;
default :
BUG ( ) ;
}
}
/**
* nand_write_buf - [ DEFAULT ] write buffer to chip
* @ mtd : MTD device structure
* @ buf : data buffer
* @ len : number of bytes to write
*
* Default write function for 8 bit buswith
*/
2006-05-23 13:52:35 +04:00
static void nand_write_buf ( struct mtd_info * mtd , const uint8_t * buf , int len )
2005-04-17 02:20:36 +04:00
{
int i ;
struct nand_chip * this = mtd - > priv ;
2006-05-13 21:07:53 +04:00
for ( i = 0 ; i < len ; i + + )
2005-04-17 02:20:36 +04:00
writeb ( buf [ i ] , this - > IO_ADDR_W ) ;
}
/**
2005-11-07 14:15:49 +03:00
* nand_read_buf - [ DEFAULT ] read chip data into buffer
2005-04-17 02:20:36 +04:00
* @ mtd : MTD device structure
* @ buf : buffer to store date
* @ len : number of bytes to read
*
* Default read function for 8 bit buswith
*/
2006-05-23 13:52:35 +04:00
static void nand_read_buf ( struct mtd_info * mtd , uint8_t * buf , int len )
2005-04-17 02:20:36 +04:00
{
int i ;
struct nand_chip * this = mtd - > priv ;
2006-05-13 21:07:53 +04:00
for ( i = 0 ; i < len ; i + + )
2005-04-17 02:20:36 +04:00
buf [ i ] = readb ( this - > IO_ADDR_R ) ;
}
/**
2005-11-07 14:15:49 +03:00
* nand_verify_buf - [ DEFAULT ] Verify chip data against buffer
2005-04-17 02:20:36 +04:00
* @ mtd : MTD device structure
* @ buf : buffer containing the data to compare
* @ len : number of bytes to compare
*
* Default verify function for 8 bit buswith
*/
2006-05-23 13:52:35 +04:00
static int nand_verify_buf ( struct mtd_info * mtd , const uint8_t * buf , int len )
2005-04-17 02:20:36 +04:00
{
int i ;
struct nand_chip * this = mtd - > priv ;
2006-05-13 21:07:53 +04:00
for ( i = 0 ; i < len ; i + + )
2005-04-17 02:20:36 +04:00
if ( buf [ i ] ! = readb ( this - > IO_ADDR_R ) )
return - EFAULT ;
return 0 ;
}
/**
* nand_write_buf16 - [ DEFAULT ] write buffer to chip
* @ mtd : MTD device structure
* @ buf : data buffer
* @ len : number of bytes to write
*
* Default write function for 16 bit buswith
*/
2006-05-23 13:52:35 +04:00
static void nand_write_buf16 ( struct mtd_info * mtd , const uint8_t * buf , int len )
2005-04-17 02:20:36 +04:00
{
int i ;
struct nand_chip * this = mtd - > priv ;
u16 * p = ( u16 * ) buf ;
len > > = 1 ;
2005-11-07 14:15:49 +03:00
2006-05-13 21:07:53 +04:00
for ( i = 0 ; i < len ; i + + )
2005-04-17 02:20:36 +04:00
writew ( p [ i ] , this - > IO_ADDR_W ) ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
}
/**
2005-11-07 14:15:49 +03:00
* nand_read_buf16 - [ DEFAULT ] read chip data into buffer
2005-04-17 02:20:36 +04:00
* @ mtd : MTD device structure
* @ buf : buffer to store date
* @ len : number of bytes to read
*
* Default read function for 16 bit buswith
*/
2006-05-23 13:52:35 +04:00
static void nand_read_buf16 ( struct mtd_info * mtd , uint8_t * buf , int len )
2005-04-17 02:20:36 +04:00
{
int i ;
struct nand_chip * this = mtd - > priv ;
u16 * p = ( u16 * ) buf ;
len > > = 1 ;
2006-05-13 21:07:53 +04:00
for ( i = 0 ; i < len ; i + + )
2005-04-17 02:20:36 +04:00
p [ i ] = readw ( this - > IO_ADDR_R ) ;
}
/**
2005-11-07 14:15:49 +03:00
* nand_verify_buf16 - [ DEFAULT ] Verify chip data against buffer
2005-04-17 02:20:36 +04:00
* @ mtd : MTD device structure
* @ buf : buffer containing the data to compare
* @ len : number of bytes to compare
*
* Default verify function for 16 bit buswith
*/
2006-05-23 13:52:35 +04:00
static int nand_verify_buf16 ( struct mtd_info * mtd , const uint8_t * buf , int len )
2005-04-17 02:20:36 +04:00
{
int i ;
struct nand_chip * this = mtd - > priv ;
u16 * p = ( u16 * ) buf ;
len > > = 1 ;
2006-05-13 21:07:53 +04:00
for ( i = 0 ; i < len ; i + + )
2005-04-17 02:20:36 +04:00
if ( p [ i ] ! = readw ( this - > IO_ADDR_R ) )
return - EFAULT ;
return 0 ;
}
/**
* nand_block_bad - [ DEFAULT ] Read bad block marker from the chip
* @ mtd : MTD device structure
* @ ofs : offset from device start
* @ getchip : 0 , if the chip is already selected
*
2005-11-07 14:15:49 +03:00
* Check , if the block is bad .
2005-04-17 02:20:36 +04:00
*/
static int nand_block_bad ( struct mtd_info * mtd , loff_t ofs , int getchip )
{
int page , chipnr , res = 0 ;
struct nand_chip * this = mtd - > priv ;
u16 bad ;
if ( getchip ) {
page = ( int ) ( ofs > > this - > page_shift ) ;
chipnr = ( int ) ( ofs > > this - > chip_shift ) ;
/* Grab the lock and see if the device is available */
2006-05-13 21:07:53 +04:00
nand_get_device ( this , mtd , FL_READING ) ;
2005-04-17 02:20:36 +04:00
/* Select the NAND device */
this - > select_chip ( mtd , chipnr ) ;
2005-11-07 14:15:49 +03:00
} else
2006-05-13 21:07:53 +04:00
page = ( int ) ofs ;
2005-04-17 02:20:36 +04:00
if ( this - > options & NAND_BUSWIDTH_16 ) {
2006-05-23 13:50:56 +04:00
this - > cmdfunc ( mtd , NAND_CMD_READOOB , this - > badblockpos & 0xFE ,
page & this - > pagemask ) ;
2005-04-17 02:20:36 +04:00
bad = cpu_to_le16 ( this - > read_word ( mtd ) ) ;
if ( this - > badblockpos & 0x1 )
2005-11-02 19:54:46 +03:00
bad > > = 8 ;
2005-04-17 02:20:36 +04:00
if ( ( bad & 0xFF ) ! = 0xff )
res = 1 ;
} else {
2006-05-23 13:50:56 +04:00
this - > cmdfunc ( mtd , NAND_CMD_READOOB , this - > badblockpos ,
page & this - > pagemask ) ;
2005-04-17 02:20:36 +04:00
if ( this - > read_byte ( mtd ) ! = 0xff )
res = 1 ;
}
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
if ( getchip ) {
/* Deselect and wake up anyone waiting on the device */
nand_release_device ( mtd ) ;
2005-11-07 14:15:49 +03:00
}
2005-04-17 02:20:36 +04:00
return res ;
}
/**
* nand_default_block_markbad - [ DEFAULT ] mark a block bad
* @ mtd : MTD device structure
* @ ofs : offset from device start
*
* This is the default implementation , which can be overridden by
* a hardware specific driver .
*/
static int nand_default_block_markbad ( struct mtd_info * mtd , loff_t ofs )
{
struct nand_chip * this = mtd - > priv ;
2006-05-23 13:52:35 +04:00
uint8_t buf [ 2 ] = { 0 , 0 } ;
2006-05-13 21:07:53 +04:00
size_t retlen ;
2005-04-17 02:20:36 +04:00
int block ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
/* Get block number */
2006-05-13 21:07:53 +04:00
block = ( ( int ) ofs ) > > this - > bbt_erase_shift ;
2005-02-09 17:50:00 +03:00
if ( this - > bbt )
this - > bbt [ block > > 2 ] | = 0x01 < < ( ( block & 0x03 ) < < 1 ) ;
2005-04-17 02:20:36 +04:00
/* Do we have a flash based bad block table ? */
if ( this - > options & NAND_USE_FLASH_BBT )
2006-05-13 21:07:53 +04:00
return nand_update_bbt ( mtd , ofs ) ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
/* We write two bytes, so we dont have to mess with 16 bit access */
ofs + = mtd - > oobsize + ( this - > badblockpos & ~ 0x01 ) ;
2006-05-13 21:07:53 +04:00
return nand_write_oob ( mtd , ofs , 2 , & retlen , buf ) ;
2005-04-17 02:20:36 +04:00
}
2005-11-07 14:15:49 +03:00
/**
2005-04-17 02:20:36 +04:00
* nand_check_wp - [ GENERIC ] check if the chip is write protected
* @ mtd : MTD device structure
2005-11-07 14:15:49 +03:00
* Check , if the device is write protected
2005-04-17 02:20:36 +04:00
*
2005-11-07 14:15:49 +03:00
* The function expects , that the device is already selected
2005-04-17 02:20:36 +04:00
*/
2006-05-13 21:07:53 +04:00
static int nand_check_wp ( struct mtd_info * mtd )
2005-04-17 02:20:36 +04:00
{
struct nand_chip * this = mtd - > priv ;
/* Check the WP bit */
2006-05-13 21:07:53 +04:00
this - > cmdfunc ( mtd , NAND_CMD_STATUS , - 1 , - 1 ) ;
2005-11-07 14:15:49 +03:00
return ( this - > read_byte ( mtd ) & NAND_STATUS_WP ) ? 0 : 1 ;
2005-04-17 02:20:36 +04:00
}
/**
* nand_block_checkbad - [ GENERIC ] Check if a block is marked bad
* @ mtd : MTD device structure
* @ ofs : offset from device start
* @ getchip : 0 , if the chip is already selected
* @ allowbbt : 1 , if its allowed to access the bbt area
*
* Check , if the block is bad . Either by reading the bad block table or
* calling of the scan function .
*/
2006-05-23 13:50:56 +04:00
static int nand_block_checkbad ( struct mtd_info * mtd , loff_t ofs , int getchip ,
int allowbbt )
2005-04-17 02:20:36 +04:00
{
struct nand_chip * this = mtd - > priv ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
if ( ! this - > bbt )
return this - > block_bad ( mtd , ofs , getchip ) ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
/* Return info from the table */
2006-05-13 21:07:53 +04:00
return nand_isbad_bbt ( mtd , ofs , allowbbt ) ;
2005-04-17 02:20:36 +04:00
}
2006-03-31 14:31:14 +04:00
DEFINE_LED_TRIGGER ( nand_led_trigger ) ;
2005-11-07 14:15:49 +03:00
/*
2005-02-23 00:56:49 +03:00
* Wait for the ready pin , after a command
* The timeout is catched later .
*/
static void nand_wait_ready ( struct mtd_info * mtd )
{
struct nand_chip * this = mtd - > priv ;
2006-05-13 21:07:53 +04:00
unsigned long timeo = jiffies + 2 ;
2005-02-23 00:56:49 +03:00
2006-03-31 14:31:14 +04:00
led_trigger_event ( nand_led_trigger , LED_FULL ) ;
2005-02-23 00:56:49 +03:00
/* wait until command is processed or timeout occures */
do {
if ( this - > dev_ready ( mtd ) )
2006-03-31 14:31:14 +04:00
break ;
2005-09-07 02:16:27 +04:00
touch_softlockup_watchdog ( ) ;
2005-11-07 14:15:49 +03:00
} while ( time_before ( jiffies , timeo ) ) ;
2006-03-31 14:31:14 +04:00
led_trigger_event ( nand_led_trigger , LED_OFF ) ;
2005-02-23 00:56:49 +03:00
}
2005-04-17 02:20:36 +04:00
/**
* nand_command - [ DEFAULT ] Send command to NAND device
* @ mtd : MTD device structure
* @ command : the command to be sent
* @ column : the column address for this command , - 1 if none
* @ page_addr : the page address for this command , - 1 if none
*
* Send command to NAND device . This function is used for small page
* devices ( 256 / 512 Bytes per page )
*/
2006-05-23 13:50:56 +04:00
static void nand_command ( struct mtd_info * mtd , unsigned command , int column ,
int page_addr )
2005-04-17 02:20:36 +04:00
{
register struct nand_chip * this = mtd - > priv ;
/* Begin command latch cycle */
this - > hwcontrol ( mtd , NAND_CTL_SETCLE ) ;
/*
* Write out the command to the device .
*/
if ( command = = NAND_CMD_SEQIN ) {
int readcmd ;
2006-05-23 01:18:05 +04:00
if ( column > = mtd - > writesize ) {
2005-04-17 02:20:36 +04:00
/* OOB area */
2006-05-23 01:18:05 +04:00
column - = mtd - > writesize ;
2005-04-17 02:20:36 +04:00
readcmd = NAND_CMD_READOOB ;
} else if ( column < 256 ) {
/* First 256 bytes --> READ0 */
readcmd = NAND_CMD_READ0 ;
} else {
column - = 256 ;
readcmd = NAND_CMD_READ1 ;
}
this - > write_byte ( mtd , readcmd ) ;
}
this - > write_byte ( mtd , command ) ;
/* Set ALE and clear CLE to start address cycle */
this - > hwcontrol ( mtd , NAND_CTL_CLRCLE ) ;
if ( column ! = - 1 | | page_addr ! = - 1 ) {
this - > hwcontrol ( mtd , NAND_CTL_SETALE ) ;
/* Serially input address */
if ( column ! = - 1 ) {
/* Adjust columns for 16 bit buswidth */
if ( this - > options & NAND_BUSWIDTH_16 )
column > > = 1 ;
this - > write_byte ( mtd , column ) ;
}
if ( page_addr ! = - 1 ) {
2006-05-23 13:52:35 +04:00
this - > write_byte ( mtd , ( uint8_t ) ( page_addr & 0xff ) ) ;
this - > write_byte ( mtd , ( uint8_t ) ( ( page_addr > > 8 ) & 0xff ) ) ;
2005-04-17 02:20:36 +04:00
/* One more address cycle for devices > 32MiB */
if ( this - > chipsize > ( 32 < < 20 ) )
2006-05-23 13:52:35 +04:00
this - > write_byte ( mtd , ( uint8_t ) ( ( page_addr > > 16 ) & 0x0f ) ) ;
2005-04-17 02:20:36 +04:00
}
/* Latch in address */
this - > hwcontrol ( mtd , NAND_CTL_CLRALE ) ;
}
2005-11-07 14:15:49 +03:00
/*
* program and erase have their own busy handlers
2005-04-17 02:20:36 +04:00
* status and sequential in needs no delay
2006-05-13 21:07:53 +04:00
*/
2005-04-17 02:20:36 +04:00
switch ( command ) {
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
case NAND_CMD_PAGEPROG :
case NAND_CMD_ERASE1 :
case NAND_CMD_ERASE2 :
case NAND_CMD_SEQIN :
case NAND_CMD_STATUS :
return ;
case NAND_CMD_RESET :
2005-11-07 14:15:49 +03:00
if ( this - > dev_ready )
2005-04-17 02:20:36 +04:00
break ;
udelay ( this - > chip_delay ) ;
this - > hwcontrol ( mtd , NAND_CTL_SETCLE ) ;
this - > write_byte ( mtd , NAND_CMD_STATUS ) ;
this - > hwcontrol ( mtd , NAND_CTL_CLRCLE ) ;
2006-05-13 21:07:53 +04:00
while ( ! ( this - > read_byte ( mtd ) & NAND_STATUS_READY ) ) ;
2005-04-17 02:20:36 +04:00
return ;
2006-05-13 21:07:53 +04:00
/* This applies to read commands */
2005-04-17 02:20:36 +04:00
default :
2005-11-07 14:15:49 +03:00
/*
2005-04-17 02:20:36 +04:00
* If we don ' t have access to the busy pin , we apply the given
* command delay
2006-05-13 21:07:53 +04:00
*/
2005-04-17 02:20:36 +04:00
if ( ! this - > dev_ready ) {
2006-05-13 21:07:53 +04:00
udelay ( this - > chip_delay ) ;
2005-04-17 02:20:36 +04:00
return ;
2005-11-07 14:15:49 +03:00
}
2005-04-17 02:20:36 +04:00
}
/* Apply this short delay always to ensure that we do wait tWB in
* any case on any machine . */
2006-05-13 21:07:53 +04:00
ndelay ( 100 ) ;
2005-02-23 00:56:49 +03:00
nand_wait_ready ( mtd ) ;
2005-04-17 02:20:36 +04:00
}
/**
* nand_command_lp - [ DEFAULT ] Send command to NAND large page device
* @ mtd : MTD device structure
* @ command : the command to be sent
* @ column : the column address for this command , - 1 if none
* @ page_addr : the page address for this command , - 1 if none
*
* Send command to NAND device . This is the version for the new large page devices
2006-05-13 21:07:53 +04:00
* We dont have the separate regions as we have in the small page devices .
2005-04-17 02:20:36 +04:00
* We must emulate NAND_CMD_READOOB to keep the code compatible .
*
*/
2006-05-13 21:07:53 +04:00
static void nand_command_lp ( struct mtd_info * mtd , unsigned command , int column , int page_addr )
2005-04-17 02:20:36 +04:00
{
register struct nand_chip * this = mtd - > priv ;
/* Emulate NAND_CMD_READOOB */
if ( command = = NAND_CMD_READOOB ) {
2006-05-23 01:18:05 +04:00
column + = mtd - > writesize ;
2005-04-17 02:20:36 +04:00
command = NAND_CMD_READ0 ;
}
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
/* Begin command latch cycle */
this - > hwcontrol ( mtd , NAND_CTL_SETCLE ) ;
/* Write out the command to the device. */
2005-01-17 21:35:25 +03:00
this - > write_byte ( mtd , ( command & 0xff ) ) ;
2005-04-17 02:20:36 +04:00
/* End command latch cycle */
this - > hwcontrol ( mtd , NAND_CTL_CLRCLE ) ;
if ( column ! = - 1 | | page_addr ! = - 1 ) {
this - > hwcontrol ( mtd , NAND_CTL_SETALE ) ;
/* Serially input address */
if ( column ! = - 1 ) {
/* Adjust columns for 16 bit buswidth */
if ( this - > options & NAND_BUSWIDTH_16 )
column > > = 1 ;
this - > write_byte ( mtd , column & 0xff ) ;
this - > write_byte ( mtd , column > > 8 ) ;
2005-11-07 14:15:49 +03:00
}
2005-04-17 02:20:36 +04:00
if ( page_addr ! = - 1 ) {
2006-05-23 13:52:35 +04:00
this - > write_byte ( mtd , ( uint8_t ) ( page_addr & 0xff ) ) ;
this - > write_byte ( mtd , ( uint8_t ) ( ( page_addr > > 8 ) & 0xff ) ) ;
2005-04-17 02:20:36 +04:00
/* One more address cycle for devices > 128MiB */
if ( this - > chipsize > ( 128 < < 20 ) )
2006-05-23 13:52:35 +04:00
this - > write_byte ( mtd , ( uint8_t ) ( ( page_addr > > 16 ) & 0xff ) ) ;
2005-04-17 02:20:36 +04:00
}
/* Latch in address */
this - > hwcontrol ( mtd , NAND_CTL_CLRALE ) ;
}
2005-11-07 14:15:49 +03:00
/*
* program and erase have their own busy handlers
2005-01-17 21:35:25 +03:00
* status , sequential in , and deplete1 need no delay
*/
2005-04-17 02:20:36 +04:00
switch ( command ) {
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
case NAND_CMD_CACHEDPROG :
case NAND_CMD_PAGEPROG :
case NAND_CMD_ERASE1 :
case NAND_CMD_ERASE2 :
case NAND_CMD_SEQIN :
case NAND_CMD_STATUS :
2005-01-17 21:35:25 +03:00
case NAND_CMD_DEPLETE1 :
2005-04-17 02:20:36 +04:00
return ;
2006-05-13 21:07:53 +04:00
/*
* read error status commands require only a short delay
*/
2005-01-17 21:35:25 +03:00
case NAND_CMD_STATUS_ERROR :
case NAND_CMD_STATUS_ERROR0 :
case NAND_CMD_STATUS_ERROR1 :
case NAND_CMD_STATUS_ERROR2 :
case NAND_CMD_STATUS_ERROR3 :
udelay ( this - > chip_delay ) ;
return ;
2005-04-17 02:20:36 +04:00
case NAND_CMD_RESET :
2005-11-07 14:15:49 +03:00
if ( this - > dev_ready )
2005-04-17 02:20:36 +04:00
break ;
udelay ( this - > chip_delay ) ;
this - > hwcontrol ( mtd , NAND_CTL_SETCLE ) ;
this - > write_byte ( mtd , NAND_CMD_STATUS ) ;
this - > hwcontrol ( mtd , NAND_CTL_CLRCLE ) ;
2006-05-13 21:07:53 +04:00
while ( ! ( this - > read_byte ( mtd ) & NAND_STATUS_READY ) ) ;
2005-04-17 02:20:36 +04:00
return ;
case NAND_CMD_READ0 :
/* Begin command latch cycle */
this - > hwcontrol ( mtd , NAND_CTL_SETCLE ) ;
/* Write out the start read command */
this - > write_byte ( mtd , NAND_CMD_READSTART ) ;
/* End command latch cycle */
this - > hwcontrol ( mtd , NAND_CTL_CLRCLE ) ;
/* Fall through into ready check */
2005-11-07 14:15:49 +03:00
2006-05-13 21:07:53 +04:00
/* This applies to read commands */
2005-04-17 02:20:36 +04:00
default :
2005-11-07 14:15:49 +03:00
/*
2005-04-17 02:20:36 +04:00
* If we don ' t have access to the busy pin , we apply the given
* command delay
2006-05-13 21:07:53 +04:00
*/
2005-04-17 02:20:36 +04:00
if ( ! this - > dev_ready ) {
2006-05-13 21:07:53 +04:00
udelay ( this - > chip_delay ) ;
2005-04-17 02:20:36 +04:00
return ;
2005-11-07 14:15:49 +03:00
}
2005-04-17 02:20:36 +04:00
}
2005-02-23 00:56:49 +03:00
2005-04-17 02:20:36 +04:00
/* Apply this short delay always to ensure that we do wait tWB in
* any case on any machine . */
2006-05-13 21:07:53 +04:00
ndelay ( 100 ) ;
2005-02-23 00:56:49 +03:00
nand_wait_ready ( mtd ) ;
2005-04-17 02:20:36 +04:00
}
/**
* nand_get_device - [ GENERIC ] Get chip for selected access
* @ this : the nand chip descriptor
* @ mtd : MTD device structure
2005-11-07 14:15:49 +03:00
* @ new_state : the state which is requested
2005-04-17 02:20:36 +04:00
*
* Get the device and lock it for exclusive access
*/
2006-05-23 13:50:56 +04:00
static int
nand_get_device ( struct nand_chip * this , struct mtd_info * mtd , int new_state )
2005-04-17 02:20:36 +04:00
{
2006-05-23 13:37:03 +04:00
spinlock_t * lock = & this - > controller - > lock ;
wait_queue_head_t * wq = & this - > controller - > wq ;
2006-05-13 21:07:53 +04:00
DECLARE_WAITQUEUE ( wait , current ) ;
retry :
2005-05-31 23:39:20 +04:00
spin_lock ( lock ) ;
2005-04-17 02:20:36 +04:00
/* Hardware controller shared among independend devices */
2006-05-23 13:37:03 +04:00
/* Hardware controller shared among independend devices */
if ( ! this - > controller - > active )
this - > controller - > active = this ;
if ( this - > controller - > active = = this & & this - > state = = FL_READY ) {
2005-05-31 23:39:20 +04:00
this - > state = new_state ;
spin_unlock ( lock ) ;
2005-09-15 17:58:53 +04:00
return 0 ;
}
if ( new_state = = FL_PM_SUSPENDED ) {
spin_unlock ( lock ) ;
return ( this - > state = = FL_PM_SUSPENDED ) ? 0 : - EAGAIN ;
2005-05-31 23:39:20 +04:00
}
set_current_state ( TASK_UNINTERRUPTIBLE ) ;
add_wait_queue ( wq , & wait ) ;
spin_unlock ( lock ) ;
schedule ( ) ;
remove_wait_queue ( wq , & wait ) ;
2005-04-17 02:20:36 +04:00
goto retry ;
}
/**
* nand_wait - [ DEFAULT ] wait until the command is done
* @ mtd : MTD device structure
* @ this : NAND chip structure
* @ state : state to select the max . timeout value
*
* Wait for command done . This applies to erase and program only
2005-11-07 14:15:49 +03:00
* Erase can take up to 400 ms and program up to 20 ms according to
2005-04-17 02:20:36 +04:00
* general NAND and SmartMedia specs
*
*/
static int nand_wait ( struct mtd_info * mtd , struct nand_chip * this , int state )
{
2006-05-13 21:07:53 +04:00
unsigned long timeo = jiffies ;
int status ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
if ( state = = FL_ERASING )
2006-05-13 21:07:53 +04:00
timeo + = ( HZ * 400 ) / 1000 ;
2005-04-17 02:20:36 +04:00
else
2006-05-13 21:07:53 +04:00
timeo + = ( HZ * 20 ) / 1000 ;
2005-04-17 02:20:36 +04:00
2006-03-31 14:31:14 +04:00
led_trigger_event ( nand_led_trigger , LED_FULL ) ;
2005-04-17 02:20:36 +04:00
/* Apply this short delay always to ensure that we do wait tWB in
* any case on any machine . */
2006-05-13 21:07:53 +04:00
ndelay ( 100 ) ;
2005-04-17 02:20:36 +04:00
if ( ( state = = FL_ERASING ) & & ( this - > options & NAND_IS_AND ) )
2006-05-13 21:07:53 +04:00
this - > cmdfunc ( mtd , NAND_CMD_STATUS_MULTI , - 1 , - 1 ) ;
2005-11-07 14:15:49 +03:00
else
2006-05-13 21:07:53 +04:00
this - > cmdfunc ( mtd , NAND_CMD_STATUS , - 1 , - 1 ) ;
2005-04-17 02:20:36 +04:00
2005-11-07 14:15:49 +03:00
while ( time_before ( jiffies , timeo ) ) {
2005-04-17 02:20:36 +04:00
/* Check, if we were interrupted */
if ( this - > state ! = state )
return 0 ;
if ( this - > dev_ready ) {
if ( this - > dev_ready ( mtd ) )
2005-11-07 14:15:49 +03:00
break ;
2005-04-17 02:20:36 +04:00
} else {
if ( this - > read_byte ( mtd ) & NAND_STATUS_READY )
break ;
}
2005-03-01 12:32:48 +03:00
cond_resched ( ) ;
2005-04-17 02:20:36 +04:00
}
2006-03-31 14:31:14 +04:00
led_trigger_event ( nand_led_trigger , LED_OFF ) ;
2006-05-13 21:07:53 +04:00
status = ( int ) this - > read_byte ( mtd ) ;
2005-04-17 02:20:36 +04:00
return status ;
}
/**
* nand_write_page - [ GENERIC ] write one page
* @ mtd : MTD device structure
* @ this : NAND chip structure
* @ page : startpage inside the chip , must be called with ( page & this - > pagemask )
* @ oob_buf : out of band data buffer
* @ oobsel : out of band selecttion structre
* @ cached : 1 = enable cached programming if supported by chip
*
* Nand_page_program function is used for write and writev !
* This function will always program a full page of data
* If you call it with a non page aligned buffer , you ' re lost : )
*
* Cached programming is not supported yet .
*/
2006-05-13 21:07:53 +04:00
static int nand_write_page ( struct mtd_info * mtd , struct nand_chip * this , int page ,
2006-05-23 13:52:35 +04:00
uint8_t * oob_buf , struct nand_oobinfo * oobsel , int cached )
2005-04-17 02:20:36 +04:00
{
2006-05-13 21:07:53 +04:00
int i , status ;
2006-05-23 13:52:35 +04:00
uint8_t ecc_code [ 32 ] ;
2006-05-23 14:00:46 +04:00
int eccmode = oobsel - > useecc ? this - > ecc . mode : NAND_ECC_NONE ;
2006-05-13 21:07:53 +04:00
int * oob_config = oobsel - > eccpos ;
2006-05-23 14:00:46 +04:00
int datidx = 0 , eccidx = 0 , eccsteps = this - > ecc . steps ;
2006-05-13 21:07:53 +04:00
int eccbytes = 0 ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
/* FIXME: Enable cached programming */
cached = 0 ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
/* Send command to begin auto page programming */
2006-05-13 21:07:53 +04:00
this - > cmdfunc ( mtd , NAND_CMD_SEQIN , 0x00 , page ) ;
2005-04-17 02:20:36 +04:00
/* Write out complete page of data, take care of eccmode */
switch ( eccmode ) {
2006-05-13 21:07:53 +04:00
/* No ecc, write all */
2005-04-17 02:20:36 +04:00
case NAND_ECC_NONE :
2006-05-13 21:07:53 +04:00
printk ( KERN_WARNING " Writing data without ECC to NAND-FLASH is not recommended \n " ) ;
2006-05-23 01:18:05 +04:00
this - > write_buf ( mtd , this - > data_poi , mtd - > writesize ) ;
2005-04-17 02:20:36 +04:00
break ;
2005-11-07 14:15:49 +03:00
2006-05-13 21:07:53 +04:00
/* Software ecc 3/256, write all */
2005-04-17 02:20:36 +04:00
case NAND_ECC_SOFT :
for ( ; eccsteps ; eccsteps - - ) {
2006-05-23 14:00:46 +04:00
this - > ecc . calculate ( mtd , & this - > data_poi [ datidx ] , ecc_code ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < 3 ; i + + , eccidx + + )
oob_buf [ oob_config [ eccidx ] ] = ecc_code [ i ] ;
2006-05-23 14:00:46 +04:00
datidx + = this - > ecc . size ;
2005-04-17 02:20:36 +04:00
}
2006-05-23 01:18:05 +04:00
this - > write_buf ( mtd , this - > data_poi , mtd - > writesize ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
2006-05-23 14:00:46 +04:00
eccbytes = this - > ecc . bytes ;
2005-04-17 02:20:36 +04:00
for ( ; eccsteps ; eccsteps - - ) {
/* enable hardware ecc logic for write */
2006-05-23 14:00:46 +04:00
this - > ecc . hwctl ( mtd , NAND_ECC_WRITE ) ;
this - > write_buf ( mtd , & this - > data_poi [ datidx ] , this - > ecc . size ) ;
this - > ecc . calculate ( mtd , & this - > data_poi [ datidx ] , ecc_code ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < eccbytes ; i + + , eccidx + + )
oob_buf [ oob_config [ eccidx ] ] = ecc_code [ i ] ;
/* If the hardware ecc provides syndromes then
* the ecc code must be written immidiately after
* the data bytes ( words ) */
if ( this - > options & NAND_HWECC_SYNDROME )
this - > write_buf ( mtd , ecc_code , eccbytes ) ;
2006-05-23 14:00:46 +04:00
datidx + = this - > ecc . size ;
2005-04-17 02:20:36 +04:00
}
break ;
}
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
/* Write out OOB data */
if ( this - > options & NAND_HWECC_SYNDROME )
this - > write_buf ( mtd , & oob_buf [ oobsel - > eccbytes ] , mtd - > oobsize - oobsel - > eccbytes ) ;
2005-11-07 14:15:49 +03:00
else
2005-04-17 02:20:36 +04:00
this - > write_buf ( mtd , oob_buf , mtd - > oobsize ) ;
/* Send command to actually program the data */
2006-05-13 21:07:53 +04:00
this - > cmdfunc ( mtd , cached ? NAND_CMD_CACHEDPROG : NAND_CMD_PAGEPROG , - 1 , - 1 ) ;
2005-04-17 02:20:36 +04:00
if ( ! cached ) {
/* call wait ready function */
2006-05-13 21:07:53 +04:00
status = this - > waitfunc ( mtd , this , FL_WRITING ) ;
2005-01-24 06:07:46 +03:00
/* See if operation failed and additional status checks are available */
if ( ( status & NAND_STATUS_FAIL ) & & ( this - > errstat ) ) {
status = this - > errstat ( mtd , this , FL_WRITING , status , page ) ;
}
2005-04-17 02:20:36 +04:00
/* See if device thinks it succeeded */
2005-01-23 21:30:53 +03:00
if ( status & NAND_STATUS_FAIL ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " %s: " " Failed write, page 0x%08x, " , __FUNCTION__ , page ) ;
2005-04-17 02:20:36 +04:00
return - EIO ;
}
} else {
/* FIXME: Implement cached programming ! */
2006-05-13 21:07:53 +04:00
/* wait until cache is ready */
2005-04-17 02:20:36 +04:00
// status = this->waitfunc (mtd, this, FL_CACHEDRPG);
}
2005-11-07 14:15:49 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
# ifdef CONFIG_MTD_NAND_VERIFY_WRITE
/**
* nand_verify_pages - [ GENERIC ] verify the chip contents after a write
* @ mtd : MTD device structure
* @ this : NAND chip structure
2006-05-23 13:50:56 +04:00
* @ page : startpage inside the chip , must be called with ( page & this - > pagemask )
2005-04-17 02:20:36 +04:00
* @ numpages : number of pages to verify
* @ oob_buf : out of band data buffer
* @ oobsel : out of band selecttion structre
* @ chipnr : number of the current chip
* @ oobmode : 1 = full buffer verify , 0 = ecc only
*
* The NAND device assumes that it is always writing to a cleanly erased page .
2005-11-07 14:15:49 +03:00
* Hence , it performs its internal write verification only on bits that
2005-04-17 02:20:36 +04:00
* transitioned from 1 to 0. The device does NOT verify the whole page on a
2005-11-07 14:15:49 +03:00
* byte by byte basis . It is possible that the page was not completely erased
* or the page is becoming unusable due to wear . The read with ECC would catch
* the error later when the ECC page check fails , but we would rather catch
2005-04-17 02:20:36 +04:00
* it early in the page write stage . Better to write no data than invalid data .
*/
2006-05-13 21:07:53 +04:00
static int nand_verify_pages ( struct mtd_info * mtd , struct nand_chip * this , int page , int numpages ,
2006-05-23 13:52:35 +04:00
uint8_t * oob_buf , struct nand_oobinfo * oobsel , int chipnr , int oobmode )
2005-04-17 02:20:36 +04:00
{
2006-05-13 21:07:53 +04:00
int i , j , datidx = 0 , oobofs = 0 , res = - EIO ;
int eccsteps = this - > eccsteps ;
int hweccbytes ;
2006-05-23 13:52:35 +04:00
uint8_t oobdata [ 64 ] ;
2005-04-17 02:20:36 +04:00
hweccbytes = ( this - > options & NAND_HWECC_SYNDROME ) ? ( oobsel - > eccbytes / eccsteps ) : 0 ;
/* Send command to read back the first page */
2006-05-13 21:07:53 +04:00
this - > cmdfunc ( mtd , NAND_CMD_READ0 , 0 , page ) ;
2005-04-17 02:20:36 +04:00
2006-05-13 21:07:53 +04:00
for ( ; ; ) {
2005-04-17 02:20:36 +04:00
for ( j = 0 ; j < eccsteps ; j + + ) {
/* Loop through and verify the data */
if ( this - > verify_buf ( mtd , & this - > data_poi [ datidx ] , mtd - > eccsize ) ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " %s: " " Failed write verify, page 0x%08x " , __FUNCTION__ , page ) ;
2005-04-17 02:20:36 +04:00
goto out ;
}
datidx + = mtd - > eccsize ;
/* Have we a hw generator layout ? */
if ( ! hweccbytes )
continue ;
if ( this - > verify_buf ( mtd , & this - > oob_buf [ oobofs ] , hweccbytes ) ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " %s: " " Failed write verify, page 0x%08x " , __FUNCTION__ , page ) ;
2005-04-17 02:20:36 +04:00
goto out ;
}
oobofs + = hweccbytes ;
}
/* check, if we must compare all data or if we just have to
* compare the ecc bytes
*/
if ( oobmode ) {
if ( this - > verify_buf ( mtd , & oob_buf [ oobofs ] , mtd - > oobsize - hweccbytes * eccsteps ) ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " %s: " " Failed write verify, page 0x%08x " , __FUNCTION__ , page ) ;
2005-04-17 02:20:36 +04:00
goto out ;
}
} else {
/* Read always, else autoincrement fails */
this - > read_buf ( mtd , oobdata , mtd - > oobsize - hweccbytes * eccsteps ) ;
if ( oobsel - > useecc ! = MTD_NANDECC_OFF & & ! hweccbytes ) {
int ecccnt = oobsel - > eccbytes ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < ecccnt ; i + + ) {
int idx = oobsel - > eccpos [ i ] ;
2006-05-13 21:07:53 +04:00
if ( oobdata [ idx ] ! = oob_buf [ oobofs + idx ] ) {
DEBUG ( MTD_DEBUG_LEVEL0 , " %s: Failed ECC write verify, page 0x%08x, %6i bytes were succesful \n " ,
__FUNCTION__ , page , i ) ;
2005-04-17 02:20:36 +04:00
goto out ;
}
}
2005-11-07 14:15:49 +03:00
}
2005-04-17 02:20:36 +04:00
}
oobofs + = mtd - > oobsize - hweccbytes * eccsteps ;
page + + ;
numpages - - ;
2005-11-07 14:15:49 +03:00
/* Apply delay or wait for ready/busy pin
2005-04-17 02:20:36 +04:00
* Do this before the AUTOINCR check , so no problems
* arise if a chip which does auto increment
* is marked as NOAUTOINCR by the board driver .
* Do this also before returning , so the chip is
* ready for the next command .
2006-05-13 21:07:53 +04:00
*/
2005-11-07 14:15:49 +03:00
if ( ! this - > dev_ready )
2006-05-13 21:07:53 +04:00
udelay ( this - > chip_delay ) ;
2005-04-17 02:20:36 +04:00
else
2005-02-23 00:56:49 +03:00
nand_wait_ready ( mtd ) ;
2005-04-17 02:20:36 +04:00
/* All done, return happy */
if ( ! numpages )
return 0 ;
2005-11-07 14:15:49 +03:00
/* Check, if the chip supports auto page increment */
2005-04-17 02:20:36 +04:00
if ( ! NAND_CANAUTOINCR ( this ) )
2006-05-13 21:07:53 +04:00
this - > cmdfunc ( mtd , NAND_CMD_READ0 , 0x00 , page ) ;
2005-04-17 02:20:36 +04:00
}
2005-11-07 14:15:49 +03:00
/*
2005-04-17 02:20:36 +04:00
* Terminate the read command . We come here in case of an error
* So we must issue a reset command .
*/
2006-05-13 21:07:53 +04:00
out :
this - > cmdfunc ( mtd , NAND_CMD_RESET , - 1 , - 1 ) ;
2005-04-17 02:20:36 +04:00
return res ;
}
# endif
/**
2005-01-24 06:07:46 +03:00
* nand_read - [ MTD Interface ] MTD compability function for nand_do_read_ecc
2005-04-17 02:20:36 +04:00
* @ mtd : MTD device structure
* @ from : offset to read from
* @ len : number of bytes to read
* @ retlen : pointer to variable to store the number of read bytes
* @ buf : the databuffer to put data
*
2005-01-24 06:07:46 +03:00
* This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL
* and flags = 0xff
*/
2006-05-23 13:52:35 +04:00
static int nand_read ( struct mtd_info * mtd , loff_t from , size_t len , size_t * retlen , uint8_t * buf )
2005-04-17 02:20:36 +04:00
{
2006-05-13 21:07:53 +04:00
return nand_do_read_ecc ( mtd , from , len , retlen , buf , NULL , & mtd - > oobinfo , 0xff ) ;
2005-04-04 22:56:32 +04:00
}
2005-04-17 02:20:36 +04:00
/**
2005-01-24 06:07:46 +03:00
* nand_read_ecc - [ MTD Interface ] MTD compability function for nand_do_read_ecc
2005-04-17 02:20:36 +04:00
* @ mtd : MTD device structure
* @ from : offset to read from
* @ len : number of bytes to read
* @ retlen : pointer to variable to store the number of read bytes
* @ buf : the databuffer to put data
* @ oob_buf : filesystem supplied oob data buffer
* @ oobsel : oob selection structure
*
2005-01-24 06:07:46 +03:00
* This function simply calls nand_do_read_ecc with flags = 0xff
2005-04-17 02:20:36 +04:00
*/
2006-05-13 21:07:53 +04:00
static int nand_read_ecc ( struct mtd_info * mtd , loff_t from , size_t len ,
2006-05-23 13:52:35 +04:00
size_t * retlen , uint8_t * buf , uint8_t * oob_buf , struct nand_oobinfo * oobsel )
2005-01-24 06:07:46 +03:00
{
2005-04-04 22:56:32 +04:00
/* use userspace supplied oobinfo, if zero */
if ( oobsel = = NULL )
oobsel = & mtd - > oobinfo ;
2005-01-24 06:07:46 +03:00
return nand_do_read_ecc ( mtd , from , len , retlen , buf , oob_buf , oobsel , 0xff ) ;
}
/**
* nand_do_read_ecc - [ MTD Interface ] Read data with ECC
* @ mtd : MTD device structure
* @ from : offset to read from
* @ len : number of bytes to read
* @ retlen : pointer to variable to store the number of read bytes
* @ buf : the databuffer to put data
2005-04-04 22:02:26 +04:00
* @ oob_buf : filesystem supplied oob data buffer ( can be NULL )
2005-04-04 22:56:32 +04:00
* @ oobsel : oob selection structure
2005-01-24 06:07:46 +03:00
* @ flags : flag to indicate if nand_get_device / nand_release_device should be preformed
* and how many corrected error bits are acceptable :
* bits 0. .7 - number of tolerable errors
* bit 8 - 0 = = do not get / release chip , 1 = = get / release chip
*
* NAND read with ECC
*/
2006-05-13 21:07:53 +04:00
int nand_do_read_ecc ( struct mtd_info * mtd , loff_t from , size_t len ,
2006-05-23 13:52:35 +04:00
size_t * retlen , uint8_t * buf , uint8_t * oob_buf , struct nand_oobinfo * oobsel , int flags )
2005-04-17 02:20:36 +04:00
{
2005-04-04 22:56:32 +04:00
2005-04-17 02:20:36 +04:00
int i , j , col , realpage , page , end , ecc , chipnr , sndcmd = 1 ;
int read = 0 , oob = 0 , ecc_status = 0 , ecc_failed = 0 ;
struct nand_chip * this = mtd - > priv ;
2006-05-23 13:52:35 +04:00
uint8_t * data_poi , * oob_data = oob_buf ;
uint8_t ecc_calc [ 32 ] ;
uint8_t ecc_code [ 32 ] ;
2006-05-13 21:07:53 +04:00
int eccmode , eccsteps ;
int * oob_config , datidx ;
int blockcheck = ( 1 < < ( this - > phys_erase_shift - this - > page_shift ) ) - 1 ;
int eccbytes ;
int compareecc = 1 ;
int oobreadlen ;
2005-04-17 02:20:36 +04:00
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL3 , " nand_read_ecc: from = 0x%08x, len = %i \n " , ( unsigned int ) from , ( int ) len ) ;
2005-04-17 02:20:36 +04:00
/* Do not allow reads past end of device */
if ( ( from + len ) > mtd - > size ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " nand_read_ecc: Attempt read beyond end of device \n " ) ;
2005-04-17 02:20:36 +04:00
* retlen = 0 ;
return - EINVAL ;
}
/* Grab the lock and see if the device is available */
2005-01-24 06:07:46 +03:00
if ( flags & NAND_GET_DEVICE )
2006-05-13 21:07:53 +04:00
nand_get_device ( this , mtd , FL_READING ) ;
2005-04-17 02:20:36 +04:00
/* Autoplace of oob data ? Use the default placement scheme */
if ( oobsel - > useecc = = MTD_NANDECC_AUTOPLACE )
oobsel = this - > autooob ;
2005-11-07 14:15:49 +03:00
2006-05-23 14:00:46 +04:00
eccmode = oobsel - > useecc ? this - > ecc . mode : NAND_ECC_NONE ;
2005-04-17 02:20:36 +04:00
oob_config = oobsel - > eccpos ;
/* Select the NAND device */
chipnr = ( int ) ( from > > this - > chip_shift ) ;
this - > select_chip ( mtd , chipnr ) ;
/* First we calculate the starting page */
2006-05-13 21:07:53 +04:00
realpage = ( int ) ( from > > this - > page_shift ) ;
2005-04-17 02:20:36 +04:00
page = realpage & this - > pagemask ;
/* Get raw starting column */
2006-05-23 01:18:05 +04:00
col = from & ( mtd - > writesize - 1 ) ;
2005-04-17 02:20:36 +04:00
2006-05-23 01:18:05 +04:00
end = mtd - > writesize ;
2006-05-23 14:00:46 +04:00
ecc = this - > ecc . size ;
eccbytes = this - > ecc . bytes ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
if ( ( eccmode = = NAND_ECC_NONE ) | | ( this - > options & NAND_HWECC_SYNDROME ) )
compareecc = 0 ;
oobreadlen = mtd - > oobsize ;
2005-11-07 14:15:49 +03:00
if ( this - > options & NAND_HWECC_SYNDROME )
2005-04-17 02:20:36 +04:00
oobreadlen - = oobsel - > eccbytes ;
/* Loop until all data read */
while ( read < len ) {
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
int aligned = ( ! col & & ( len - read ) > = end ) ;
2005-11-07 14:15:49 +03:00
/*
2005-04-17 02:20:36 +04:00
* If the read is not page aligned , we have to read into data buffer
* due to ecc , else we read into return buffer direct
*/
if ( aligned )
data_poi = & buf [ read ] ;
2005-11-07 14:15:49 +03:00
else
2005-04-17 02:20:36 +04:00
data_poi = this - > data_buf ;
2005-11-07 14:15:49 +03:00
/* Check, if we have this page in the buffer
2005-04-17 02:20:36 +04:00
*
* FIXME : Make it work when we must provide oob data too ,
* check the usage of data_buf oob field
*/
if ( realpage = = this - > pagebuf & & ! oob_buf ) {
/* aligned read ? */
if ( aligned )
2006-05-13 21:07:53 +04:00
memcpy ( data_poi , this - > data_buf , end ) ;
2005-04-17 02:20:36 +04:00
goto readdata ;
}
/* Check, if we must send the read command */
if ( sndcmd ) {
2006-05-13 21:07:53 +04:00
this - > cmdfunc ( mtd , NAND_CMD_READ0 , 0x00 , page ) ;
2005-04-17 02:20:36 +04:00
sndcmd = 0 ;
2005-11-07 14:15:49 +03:00
}
2005-04-17 02:20:36 +04:00
/* get oob area, if we have no oob buffer from fs-driver */
2005-05-19 20:10:26 +04:00
if ( ! oob_buf | | oobsel - > useecc = = MTD_NANDECC_AUTOPLACE | |
oobsel - > useecc = = MTD_NANDECC_AUTOPL_USR )
2005-04-17 02:20:36 +04:00
oob_data = & this - > data_buf [ end ] ;
2006-05-23 14:00:46 +04:00
eccsteps = this - > ecc . steps ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
switch ( eccmode ) {
2006-05-13 21:07:53 +04:00
case NAND_ECC_NONE : {
/* No ECC, Read in a page */
static unsigned long lastwhinge = 0 ;
if ( ( lastwhinge / HZ ) ! = ( jiffies / HZ ) ) {
printk ( KERN_WARNING
" Reading data from NAND FLASH without ECC is not recommended \n " ) ;
lastwhinge = jiffies ;
}
this - > read_buf ( mtd , data_poi , end ) ;
break ;
2005-04-17 02:20:36 +04:00
}
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
case NAND_ECC_SOFT : /* Software ECC 3/256: Read in a page + oob data */
this - > read_buf ( mtd , data_poi , end ) ;
2006-05-13 21:07:53 +04:00
for ( i = 0 , datidx = 0 ; eccsteps ; eccsteps - - , i + = 3 , datidx + = ecc )
2006-05-23 14:00:46 +04:00
this - > ecc . calculate ( mtd , & data_poi [ datidx ] , & ecc_calc [ i ] ) ;
2005-11-07 14:15:49 +03:00
break ;
2005-04-17 02:20:36 +04:00
default :
2006-05-13 21:07:53 +04:00
for ( i = 0 , datidx = 0 ; eccsteps ; eccsteps - - , i + = eccbytes , datidx + = ecc ) {
2006-05-23 14:00:46 +04:00
this - > ecc . hwctl ( mtd , NAND_ECC_READ ) ;
2005-04-17 02:20:36 +04:00
this - > read_buf ( mtd , & data_poi [ datidx ] , ecc ) ;
/* HW ecc with syndrome calculation must read the
* syndrome from flash immidiately after the data */
if ( ! compareecc ) {
/* Some hw ecc generators need to know when the
* syndrome is read from flash */
2006-05-23 14:00:46 +04:00
this - > ecc . hwctl ( mtd , NAND_ECC_READSYN ) ;
2005-04-17 02:20:36 +04:00
this - > read_buf ( mtd , & oob_data [ i ] , eccbytes ) ;
/* We calc error correction directly, it checks the hw
* generator for an error , reads back the syndrome and
* does the error correction on the fly */
2006-05-23 14:00:46 +04:00
ecc_status = this - > ecc . correct ( mtd , & data_poi [ datidx ] , & oob_data [ i ] , & ecc_code [ i ] ) ;
2005-01-24 06:07:46 +03:00
if ( ( ecc_status = = - 1 ) | | ( ecc_status > ( flags & & 0xff ) ) ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " nand_read_ecc: "
" Failed ECC read, page 0x%08x on chip %d \n " , page , chipnr ) ;
2005-04-17 02:20:36 +04:00
ecc_failed + + ;
}
} else {
2006-05-23 14:00:46 +04:00
this - > ecc . calculate ( mtd , & data_poi [ datidx ] , & ecc_calc [ i ] ) ;
2005-11-07 14:15:49 +03:00
}
2005-04-17 02:20:36 +04:00
}
2005-11-07 14:15:49 +03:00
break ;
2005-04-17 02:20:36 +04:00
}
/* read oobdata */
this - > read_buf ( mtd , & oob_data [ mtd - > oobsize - oobreadlen ] , oobreadlen ) ;
/* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */
if ( ! compareecc )
2005-11-07 14:15:49 +03:00
goto readoob ;
2005-04-17 02:20:36 +04:00
/* Pick the ECC bytes out of the oob data */
for ( j = 0 ; j < oobsel - > eccbytes ; j + + )
ecc_code [ j ] = oob_data [ oob_config [ j ] ] ;
2006-05-13 21:07:53 +04:00
/* correct data, if necessary */
2006-05-23 14:00:46 +04:00
for ( i = 0 , j = 0 , datidx = 0 ; i < this - > ecc . steps ; i + + , datidx + = ecc ) {
ecc_status = this - > ecc . correct ( mtd , & data_poi [ datidx ] , & ecc_code [ j ] , & ecc_calc [ j ] ) ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
/* Get next chunk of ecc bytes */
j + = eccbytes ;
2005-11-07 14:15:49 +03:00
/* Check, if we have a fs supplied oob-buffer,
2005-04-17 02:20:36 +04:00
* This is the legacy mode . Used by YAFFS1
* Should go away some day
*/
2005-11-07 14:15:49 +03:00
if ( oob_buf & & oobsel - > useecc = = MTD_NANDECC_PLACE ) {
2005-04-17 02:20:36 +04:00
int * p = ( int * ) ( & oob_data [ mtd - > oobsize ] ) ;
p [ i ] = ecc_status ;
}
2005-11-07 14:15:49 +03:00
if ( ( ecc_status = = - 1 ) | | ( ecc_status > ( flags & & 0xff ) ) ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " nand_read_ecc: " " Failed ECC read, page 0x%08x \n " , page ) ;
2005-04-17 02:20:36 +04:00
ecc_failed + + ;
}
2005-11-07 14:15:49 +03:00
}
2005-04-17 02:20:36 +04:00
2006-05-13 21:07:53 +04:00
readoob :
2005-04-17 02:20:36 +04:00
/* check, if we have a fs supplied oob-buffer */
if ( oob_buf ) {
/* without autoplace. Legacy mode used by YAFFS1 */
2006-05-13 21:07:53 +04:00
switch ( oobsel - > useecc ) {
2005-04-17 02:20:36 +04:00
case MTD_NANDECC_AUTOPLACE :
2005-05-19 20:10:26 +04:00
case MTD_NANDECC_AUTOPL_USR :
2005-04-17 02:20:36 +04:00
/* Walk through the autoplace chunks */
2005-04-07 00:13:09 +04:00
for ( i = 0 ; oobsel - > oobfree [ i ] [ 1 ] ; i + + ) {
2005-04-17 02:20:36 +04:00
int from = oobsel - > oobfree [ i ] [ 0 ] ;
int num = oobsel - > oobfree [ i ] [ 1 ] ;
memcpy ( & oob_buf [ oob ] , & oob_data [ from ] , num ) ;
2005-04-07 00:13:09 +04:00
oob + = num ;
2005-04-17 02:20:36 +04:00
}
break ;
case MTD_NANDECC_PLACE :
/* YAFFS1 legacy mode */
2006-05-23 14:00:46 +04:00
oob_data + = this - > ecc . steps * sizeof ( int ) ;
2005-04-17 02:20:36 +04:00
default :
oob_data + = mtd - > oobsize ;
}
}
readdata :
/* Partial page read, transfer data into fs buffer */
2005-11-07 14:15:49 +03:00
if ( ! aligned ) {
2005-04-17 02:20:36 +04:00
for ( j = col ; j < end & & read < len ; j + + )
buf [ read + + ] = data_poi [ j ] ;
2005-11-07 14:15:49 +03:00
this - > pagebuf = realpage ;
} else
2006-05-23 01:18:05 +04:00
read + = mtd - > writesize ;
2005-04-17 02:20:36 +04:00
2005-11-07 14:15:49 +03:00
/* Apply delay or wait for ready/busy pin
2005-04-17 02:20:36 +04:00
* Do this before the AUTOINCR check , so no problems
* arise if a chip which does auto increment
* is marked as NOAUTOINCR by the board driver .
2006-05-13 21:07:53 +04:00
*/
2005-11-07 14:15:49 +03:00
if ( ! this - > dev_ready )
2006-05-13 21:07:53 +04:00
udelay ( this - > chip_delay ) ;
2005-04-17 02:20:36 +04:00
else
2005-02-23 00:56:49 +03:00
nand_wait_ready ( mtd ) ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
if ( read = = len )
2005-11-07 14:15:49 +03:00
break ;
2005-04-17 02:20:36 +04:00
/* For subsequent reads align to page boundary. */
col = 0 ;
/* Increment page address */
realpage + + ;
page = realpage & this - > pagemask ;
/* Check, if we cross a chip boundary */
if ( ! page ) {
chipnr + + ;
this - > select_chip ( mtd , - 1 ) ;
this - > select_chip ( mtd , chipnr ) ;
}
2005-11-07 14:15:49 +03:00
/* Check, if the chip supports auto page increment
* or if we have hit a block boundary .
2006-05-13 21:07:53 +04:00
*/
2005-04-17 02:20:36 +04:00
if ( ! NAND_CANAUTOINCR ( this ) | | ! ( page & blockcheck ) )
2005-11-07 14:15:49 +03:00
sndcmd = 1 ;
2005-04-17 02:20:36 +04:00
}
/* Deselect and wake up anyone waiting on the device */
2005-01-24 06:07:46 +03:00
if ( flags & NAND_GET_DEVICE )
nand_release_device ( mtd ) ;
2005-04-17 02:20:36 +04:00
/*
* Return success , if no ECC failures , else - EBADMSG
* fs driver will take care of that , because
* retlen = = desired len and result = = - EBADMSG
*/
* retlen = read ;
return ecc_failed ? - EBADMSG : 0 ;
}
/**
* nand_read_oob - [ MTD Interface ] NAND read out - of - band
* @ mtd : MTD device structure
* @ from : offset to read from
* @ len : number of bytes to read
* @ retlen : pointer to variable to store the number of read bytes
* @ buf : the databuffer to put data
*
* NAND read out - of - band data from the spare area
*/
2006-05-23 13:52:35 +04:00
static int nand_read_oob ( struct mtd_info * mtd , loff_t from , size_t len , size_t * retlen , uint8_t * buf )
2005-04-17 02:20:36 +04:00
{
int i , col , page , chipnr ;
struct nand_chip * this = mtd - > priv ;
2006-05-13 21:07:53 +04:00
int blockcheck = ( 1 < < ( this - > phys_erase_shift - this - > page_shift ) ) - 1 ;
2005-04-17 02:20:36 +04:00
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL3 , " nand_read_oob: from = 0x%08x, len = %i \n " , ( unsigned int ) from , ( int ) len ) ;
2005-04-17 02:20:36 +04:00
/* Shift to get page */
page = ( int ) ( from > > this - > page_shift ) ;
chipnr = ( int ) ( from > > this - > chip_shift ) ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
/* Mask to get column */
col = from & ( mtd - > oobsize - 1 ) ;
/* Initialize return length value */
* retlen = 0 ;
/* Do not allow reads past end of device */
if ( ( from + len ) > mtd - > size ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " nand_read_oob: Attempt read beyond end of device \n " ) ;
2005-04-17 02:20:36 +04:00
* retlen = 0 ;
return - EINVAL ;
}
/* Grab the lock and see if the device is available */
2006-05-13 21:07:53 +04:00
nand_get_device ( this , mtd , FL_READING ) ;
2005-04-17 02:20:36 +04:00
/* Select the NAND device */
this - > select_chip ( mtd , chipnr ) ;
/* Send the read command */
2006-05-13 21:07:53 +04:00
this - > cmdfunc ( mtd , NAND_CMD_READOOB , col , page & this - > pagemask ) ;
2005-11-07 14:15:49 +03:00
/*
2005-04-17 02:20:36 +04:00
* Read the data , if we read more than one page
* oob data , let the device transfer the data !
*/
i = 0 ;
while ( i < len ) {
int thislen = mtd - > oobsize - col ;
thislen = min_t ( int , thislen , len ) ;
this - > read_buf ( mtd , & buf [ i ] , thislen ) ;
i + = thislen ;
/* Read more ? */
if ( i < len ) {
page + + ;
col = 0 ;
/* Check, if we cross a chip boundary */
if ( ! ( page & this - > pagemask ) ) {
chipnr + + ;
this - > select_chip ( mtd , - 1 ) ;
this - > select_chip ( mtd , chipnr ) ;
}
2005-11-07 14:15:49 +03:00
/* Apply delay or wait for ready/busy pin
2005-07-15 17:53:51 +04:00
* Do this before the AUTOINCR check , so no problems
* arise if a chip which does auto increment
* is marked as NOAUTOINCR by the board driver .
*/
2005-11-07 14:15:49 +03:00
if ( ! this - > dev_ready )
2006-05-13 21:07:53 +04:00
udelay ( this - > chip_delay ) ;
2005-07-15 17:53:51 +04:00
else
nand_wait_ready ( mtd ) ;
2005-11-07 14:15:49 +03:00
/* Check, if the chip supports auto page increment
* or if we have hit a block boundary .
2006-05-13 21:07:53 +04:00
*/
2005-04-17 02:20:36 +04:00
if ( ! NAND_CANAUTOINCR ( this ) | | ! ( page & blockcheck ) ) {
/* For subsequent page reads set offset to 0 */
2006-05-13 21:07:53 +04:00
this - > cmdfunc ( mtd , NAND_CMD_READOOB , 0x0 , page & this - > pagemask ) ;
2005-04-17 02:20:36 +04:00
}
}
}
/* Deselect and wake up anyone waiting on the device */
nand_release_device ( mtd ) ;
/* Return happy */
* retlen = len ;
return 0 ;
}
/**
* nand_read_raw - [ GENERIC ] Read raw data including oob into buffer
* @ mtd : MTD device structure
* @ buf : temporary buffer
* @ from : offset to read from
* @ len : number of bytes to read
* @ ooblen : number of oob data bytes to read
*
* Read raw data including oob into buffer
*/
2006-05-13 21:07:53 +04:00
int nand_read_raw ( struct mtd_info * mtd , uint8_t * buf , loff_t from , size_t len , size_t ooblen )
2005-04-17 02:20:36 +04:00
{
struct nand_chip * this = mtd - > priv ;
2006-05-13 21:07:53 +04:00
int page = ( int ) ( from > > this - > page_shift ) ;
int chip = ( int ) ( from > > this - > chip_shift ) ;
2005-04-17 02:20:36 +04:00
int sndcmd = 1 ;
int cnt = 0 ;
2006-05-23 01:18:05 +04:00
int pagesize = mtd - > writesize + mtd - > oobsize ;
2006-05-13 21:07:53 +04:00
int blockcheck = ( 1 < < ( this - > phys_erase_shift - this - > page_shift ) ) - 1 ;
2005-04-17 02:20:36 +04:00
/* Do not allow reads past end of device */
if ( ( from + len ) > mtd - > size ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " nand_read_raw: Attempt read beyond end of device \n " ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
/* Grab the lock and see if the device is available */
2006-05-13 21:07:53 +04:00
nand_get_device ( this , mtd , FL_READING ) ;
2005-04-17 02:20:36 +04:00
2006-05-13 21:07:53 +04:00
this - > select_chip ( mtd , chip ) ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
/* Add requested oob length */
len + = ooblen ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
while ( len ) {
if ( sndcmd )
2006-05-13 21:07:53 +04:00
this - > cmdfunc ( mtd , NAND_CMD_READ0 , 0 , page & this - > pagemask ) ;
2005-11-07 14:15:49 +03:00
sndcmd = 0 ;
2005-04-17 02:20:36 +04:00
2006-05-13 21:07:53 +04:00
this - > read_buf ( mtd , & buf [ cnt ] , pagesize ) ;
2005-04-17 02:20:36 +04:00
len - = pagesize ;
cnt + = pagesize ;
page + + ;
2005-11-07 14:15:49 +03:00
if ( ! this - > dev_ready )
2006-05-13 21:07:53 +04:00
udelay ( this - > chip_delay ) ;
2005-04-17 02:20:36 +04:00
else
2005-02-23 00:56:49 +03:00
nand_wait_ready ( mtd ) ;
2005-11-07 14:15:49 +03:00
/* Check, if the chip supports auto page increment */
2005-04-17 02:20:36 +04:00
if ( ! NAND_CANAUTOINCR ( this ) | | ! ( page & blockcheck ) )
sndcmd = 1 ;
}
/* Deselect and wake up anyone waiting on the device */
nand_release_device ( mtd ) ;
return 0 ;
}
2005-11-07 14:15:49 +03:00
/**
* nand_prepare_oobbuf - [ GENERIC ] Prepare the out of band buffer
2005-04-17 02:20:36 +04:00
* @ mtd : MTD device structure
* @ fsbuf : buffer given by fs driver
* @ oobsel : out of band selection structre
* @ autoplace : 1 = place given buffer into the oob bytes
* @ numpages : number of pages to prepare
*
* Return :
* 1. Filesystem buffer available and autoplacement is off ,
* return filesystem buffer
* 2. No filesystem buffer or autoplace is off , return internal
* buffer
* 3. Filesystem buffer is given and autoplace selected
* put data from fs buffer into internal buffer and
* retrun internal buffer
*
* Note : The internal buffer is filled with 0xff . This must
* be done only once , when no autoplacement happens
* Autoplacement sets the buffer dirty flag , which
* forces the 0xff fill before using the buffer again .
*
*/
2006-05-23 13:52:35 +04:00
static uint8_t * nand_prepare_oobbuf ( struct mtd_info * mtd , uint8_t * fsbuf , struct nand_oobinfo * oobsel ,
2006-05-13 21:07:53 +04:00
int autoplace , int numpages )
2005-04-17 02:20:36 +04:00
{
struct nand_chip * this = mtd - > priv ;
int i , len , ofs ;
/* Zero copy fs supplied buffer */
2005-11-07 14:15:49 +03:00
if ( fsbuf & & ! autoplace )
2005-04-17 02:20:36 +04:00
return fsbuf ;
/* Check, if the buffer must be filled with ff again */
2005-11-07 14:15:49 +03:00
if ( this - > oobdirty ) {
2006-05-13 21:07:53 +04:00
memset ( this - > oob_buf , 0xff , mtd - > oobsize < < ( this - > phys_erase_shift - this - > page_shift ) ) ;
2005-04-17 02:20:36 +04:00
this - > oobdirty = 0 ;
2005-11-07 14:15:49 +03:00
}
2005-04-17 02:20:36 +04:00
/* If we have no autoplacement or no fs buffer use the internal one */
if ( ! autoplace | | ! fsbuf )
return this - > oob_buf ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
/* Walk through the pages and place the data */
this - > oobdirty = 1 ;
ofs = 0 ;
while ( numpages - - ) {
for ( i = 0 , len = 0 ; len < mtd - > oobavail ; i + + ) {
int to = ofs + oobsel - > oobfree [ i ] [ 0 ] ;
int num = oobsel - > oobfree [ i ] [ 1 ] ;
2006-05-13 21:07:53 +04:00
memcpy ( & this - > oob_buf [ to ] , fsbuf , num ) ;
2005-04-17 02:20:36 +04:00
len + = num ;
fsbuf + = num ;
}
ofs + = mtd - > oobavail ;
}
return this - > oob_buf ;
}
2006-05-23 01:18:05 +04:00
# define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0
2005-04-17 02:20:36 +04:00
/**
* nand_write - [ MTD Interface ] compability function for nand_write_ecc
* @ mtd : MTD device structure
* @ to : offset to write to
* @ len : number of bytes to write
* @ retlen : pointer to variable to store the number of written bytes
* @ buf : the data to write
*
* This function simply calls nand_write_ecc with oob buffer and oobsel = NULL
*
*/
2006-05-23 13:52:35 +04:00
static int nand_write ( struct mtd_info * mtd , loff_t to , size_t len , size_t * retlen , const uint8_t * buf )
2005-04-17 02:20:36 +04:00
{
2006-05-13 21:07:53 +04:00
return ( nand_write_ecc ( mtd , to , len , retlen , buf , NULL , NULL ) ) ;
2005-04-17 02:20:36 +04:00
}
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
/**
* nand_write_ecc - [ MTD Interface ] NAND write with ECC
* @ mtd : MTD device structure
* @ to : offset to write to
* @ len : number of bytes to write
* @ retlen : pointer to variable to store the number of written bytes
* @ buf : the data to write
* @ eccbuf : filesystem supplied oob data buffer
* @ oobsel : oob selection structure
*
* NAND write with ECC
*/
2006-05-13 21:07:53 +04:00
static int nand_write_ecc ( struct mtd_info * mtd , loff_t to , size_t len ,
2006-05-23 13:52:35 +04:00
size_t * retlen , const uint8_t * buf , uint8_t * eccbuf ,
2006-05-13 21:07:53 +04:00
struct nand_oobinfo * oobsel )
2005-04-17 02:20:36 +04:00
{
int startpage , page , ret = - EIO , oob = 0 , written = 0 , chipnr ;
int autoplace = 0 , numpages , totalpages ;
struct nand_chip * this = mtd - > priv ;
2006-05-23 13:52:35 +04:00
uint8_t * oobbuf , * bufstart ;
2006-05-13 21:07:53 +04:00
int ppblock = ( 1 < < ( this - > phys_erase_shift - this - > page_shift ) ) ;
2005-04-17 02:20:36 +04:00
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL3 , " nand_write_ecc: to = 0x%08x, len = %i \n " , ( unsigned int ) to , ( int ) len ) ;
2005-04-17 02:20:36 +04:00
/* Initialize retlen, in case of early exit */
* retlen = 0 ;
/* Do not allow write past end of device */
if ( ( to + len ) > mtd - > size ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " nand_write_ecc: Attempt to write past end of page \n " ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
2005-11-07 14:15:49 +03:00
/* reject writes, which are not page aligned */
2006-05-13 21:07:53 +04:00
if ( NOTALIGNED ( to ) | | NOTALIGNED ( len ) ) {
printk ( KERN_NOTICE " nand_write_ecc: Attempt to write not page aligned data \n " ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
/* Grab the lock and see if the device is available */
2006-05-13 21:07:53 +04:00
nand_get_device ( this , mtd , FL_WRITING ) ;
2005-04-17 02:20:36 +04:00
/* Calculate chipnr */
chipnr = ( int ) ( to > > this - > chip_shift ) ;
/* Select the NAND device */
this - > select_chip ( mtd , chipnr ) ;
/* Check, if it is write protected */
if ( nand_check_wp ( mtd ) )
goto out ;
/* if oobsel is NULL, use chip defaults */
2005-11-07 14:15:49 +03:00
if ( oobsel = = NULL )
oobsel = & mtd - > oobinfo ;
2005-04-17 02:20:36 +04:00
/* Autoplace of oob data ? Use the default placement scheme */
if ( oobsel - > useecc = = MTD_NANDECC_AUTOPLACE ) {
oobsel = this - > autooob ;
autoplace = 1 ;
2005-11-07 14:15:49 +03:00
}
2005-05-19 20:10:26 +04:00
if ( oobsel - > useecc = = MTD_NANDECC_AUTOPL_USR )
autoplace = 1 ;
2005-04-17 02:20:36 +04:00
/* Setup variables and oob buffer */
totalpages = len > > this - > page_shift ;
2006-05-13 21:07:53 +04:00
page = ( int ) ( to > > this - > page_shift ) ;
2005-04-17 02:20:36 +04:00
/* Invalidate the page cache, if we write to the cached page */
2005-11-07 14:15:49 +03:00
if ( page < = this - > pagebuf & & this - > pagebuf < ( page + totalpages ) )
2005-04-17 02:20:36 +04:00
this - > pagebuf = - 1 ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
/* Set it relative to chip */
page & = this - > pagemask ;
startpage = page ;
/* Calc number of pages we can write in one go */
2006-05-13 21:07:53 +04:00
numpages = min ( ppblock - ( startpage & ( ppblock - 1 ) ) , totalpages ) ;
oobbuf = nand_prepare_oobbuf ( mtd , eccbuf , oobsel , autoplace , numpages ) ;
2006-05-23 13:52:35 +04:00
bufstart = ( uint8_t * ) buf ;
2005-04-17 02:20:36 +04:00
/* Loop until all data is written */
while ( written < len ) {
2006-05-23 13:52:35 +04:00
this - > data_poi = ( uint8_t * ) & buf [ written ] ;
2005-04-17 02:20:36 +04:00
/* Write one page. If this is the last page to write
* or the last page in this block , then use the
* real pageprogram command , else select cached programming
* if supported by the chip .
*/
2006-05-13 21:07:53 +04:00
ret = nand_write_page ( mtd , this , page , & oobbuf [ oob ] , oobsel , ( - - numpages > 0 ) ) ;
2005-04-17 02:20:36 +04:00
if ( ret ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " nand_write_ecc: write_page failed %d \n " , ret ) ;
2005-04-17 02:20:36 +04:00
goto out ;
2005-11-07 14:15:49 +03:00
}
2005-04-17 02:20:36 +04:00
/* Next oob page */
oob + = mtd - > oobsize ;
/* Update written bytes count */
2006-05-23 01:18:05 +04:00
written + = mtd - > writesize ;
2005-11-07 14:15:49 +03:00
if ( written = = len )
2005-04-17 02:20:36 +04:00
goto cmp ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
/* Increment page address */
page + + ;
/* Have we hit a block boundary ? Then we have to verify and
* if verify is ok , we have to setup the oob buffer for
* the next pages .
2006-05-13 21:07:53 +04:00
*/
if ( ! ( page & ( ppblock - 1 ) ) ) {
2005-04-17 02:20:36 +04:00
int ofs ;
this - > data_poi = bufstart ;
2006-05-13 21:07:53 +04:00
ret = nand_verify_pages ( mtd , this , startpage , page - startpage ,
oobbuf , oobsel , chipnr , ( eccbuf ! = NULL ) ) ;
2005-04-17 02:20:36 +04:00
if ( ret ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " nand_write_ecc: verify_pages failed %d \n " , ret ) ;
2005-04-17 02:20:36 +04:00
goto out ;
2005-11-07 14:15:49 +03:00
}
2005-04-17 02:20:36 +04:00
* retlen = written ;
ofs = autoplace ? mtd - > oobavail : mtd - > oobsize ;
if ( eccbuf )
eccbuf + = ( page - startpage ) * ofs ;
totalpages - = page - startpage ;
2006-05-13 21:07:53 +04:00
numpages = min ( totalpages , ppblock ) ;
2005-04-17 02:20:36 +04:00
page & = this - > pagemask ;
startpage = page ;
2006-05-13 21:07:53 +04:00
oobbuf = nand_prepare_oobbuf ( mtd , eccbuf , oobsel , autoplace , numpages ) ;
2005-11-05 06:21:15 +03:00
oob = 0 ;
2005-04-17 02:20:36 +04:00
/* Check, if we cross a chip boundary */
if ( ! page ) {
chipnr + + ;
this - > select_chip ( mtd , - 1 ) ;
this - > select_chip ( mtd , chipnr ) ;
}
}
}
/* Verify the remaining pages */
2006-05-13 21:07:53 +04:00
cmp :
2005-04-17 02:20:36 +04:00
this - > data_poi = bufstart ;
2006-05-13 21:07:53 +04:00
ret = nand_verify_pages ( mtd , this , startpage , totalpages , oobbuf , oobsel , chipnr , ( eccbuf ! = NULL ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! ret )
* retlen = written ;
2005-11-07 14:15:49 +03:00
else
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " nand_write_ecc: verify_pages failed %d \n " , ret ) ;
2005-04-17 02:20:36 +04:00
2006-05-13 21:07:53 +04:00
out :
2005-04-17 02:20:36 +04:00
/* Deselect and wake up anyone waiting on the device */
nand_release_device ( mtd ) ;
return ret ;
}
/**
* nand_write_oob - [ MTD Interface ] NAND write out - of - band
* @ mtd : MTD device structure
* @ to : offset to write to
* @ len : number of bytes to write
* @ retlen : pointer to variable to store the number of written bytes
* @ buf : the data to write
*
* NAND write out - of - band
*/
2006-05-23 13:52:35 +04:00
static int nand_write_oob ( struct mtd_info * mtd , loff_t to , size_t len , size_t * retlen , const uint8_t * buf )
2005-04-17 02:20:36 +04:00
{
int column , page , status , ret = - EIO , chipnr ;
struct nand_chip * this = mtd - > priv ;
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL3 , " nand_write_oob: to = 0x%08x, len = %i \n " , ( unsigned int ) to , ( int ) len ) ;
2005-04-17 02:20:36 +04:00
/* Shift to get page */
2006-05-13 21:07:53 +04:00
page = ( int ) ( to > > this - > page_shift ) ;
chipnr = ( int ) ( to > > this - > chip_shift ) ;
2005-04-17 02:20:36 +04:00
/* Mask to get column */
column = to & ( mtd - > oobsize - 1 ) ;
/* Initialize return length value */
* retlen = 0 ;
/* Do not allow write past end of page */
if ( ( column + len ) > mtd - > oobsize ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " nand_write_oob: Attempt to write past end of page \n " ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
/* Grab the lock and see if the device is available */
2006-05-13 21:07:53 +04:00
nand_get_device ( this , mtd , FL_WRITING ) ;
2005-04-17 02:20:36 +04:00
/* Select the NAND device */
this - > select_chip ( mtd , chipnr ) ;
/* Reset the chip. Some chips (like the Toshiba TC5832DC found
in one of my DiskOnChip 2000 test units ) will clear the whole
data page too if we don ' t do this . I have no clue why , but
I seem to have ' fixed ' it in the doc2000 driver in
August 1999. dwmw2 . */
this - > cmdfunc ( mtd , NAND_CMD_RESET , - 1 , - 1 ) ;
/* Check, if it is write protected */
if ( nand_check_wp ( mtd ) )
goto out ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
/* Invalidate the page cache, if we write to the cached page */
if ( page = = this - > pagebuf )
this - > pagebuf = - 1 ;
if ( NAND_MUST_PAD ( this ) ) {
/* Write out desired data */
2006-05-23 01:18:05 +04:00
this - > cmdfunc ( mtd , NAND_CMD_SEQIN , mtd - > writesize , page & this - > pagemask ) ;
2005-04-17 02:20:36 +04:00
/* prepad 0xff for partial programming */
this - > write_buf ( mtd , ffchars , column ) ;
/* write data */
this - > write_buf ( mtd , buf , len ) ;
/* postpad 0xff for partial programming */
2006-05-13 21:07:53 +04:00
this - > write_buf ( mtd , ffchars , mtd - > oobsize - ( len + column ) ) ;
2005-04-17 02:20:36 +04:00
} else {
/* Write out desired data */
2006-05-23 01:18:05 +04:00
this - > cmdfunc ( mtd , NAND_CMD_SEQIN , mtd - > writesize + column , page & this - > pagemask ) ;
2005-04-17 02:20:36 +04:00
/* write data */
this - > write_buf ( mtd , buf , len ) ;
}
/* Send command to program the OOB data */
2006-05-13 21:07:53 +04:00
this - > cmdfunc ( mtd , NAND_CMD_PAGEPROG , - 1 , - 1 ) ;
2005-04-17 02:20:36 +04:00
2006-05-13 21:07:53 +04:00
status = this - > waitfunc ( mtd , this , FL_WRITING ) ;
2005-04-17 02:20:36 +04:00
/* See if device thinks it succeeded */
2005-01-23 21:30:53 +03:00
if ( status & NAND_STATUS_FAIL ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " nand_write_oob: " " Failed write, page 0x%08x \n " , page ) ;
2005-04-17 02:20:36 +04:00
ret = - EIO ;
goto out ;
}
/* Return happy */
* retlen = len ;
# ifdef CONFIG_MTD_NAND_VERIFY_WRITE
/* Send command to read back the data */
2006-05-13 21:07:53 +04:00
this - > cmdfunc ( mtd , NAND_CMD_READOOB , column , page & this - > pagemask ) ;
2005-04-17 02:20:36 +04:00
if ( this - > verify_buf ( mtd , buf , len ) ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " nand_write_oob: " " Failed write verify, page 0x%08x \n " , page ) ;
2005-04-17 02:20:36 +04:00
ret = - EIO ;
goto out ;
}
# endif
ret = 0 ;
2006-05-13 21:07:53 +04:00
out :
2005-04-17 02:20:36 +04:00
/* Deselect and wake up anyone waiting on the device */
nand_release_device ( mtd ) ;
return ret ;
}
/**
* nand_writev - [ MTD Interface ] compabilty function for nand_writev_ecc
* @ mtd : MTD device structure
* @ vecs : the iovectors to write
* @ count : number of vectors
* @ to : offset to write to
* @ retlen : pointer to variable to store the number of written bytes
*
* NAND write with kvec . This just calls the ecc function
*/
2006-05-13 21:07:53 +04:00
static int nand_writev ( struct mtd_info * mtd , const struct kvec * vecs , unsigned long count ,
loff_t to , size_t * retlen )
2005-04-17 02:20:36 +04:00
{
2006-05-13 21:07:53 +04:00
return ( nand_writev_ecc ( mtd , vecs , count , to , retlen , NULL , NULL ) ) ;
2005-04-17 02:20:36 +04:00
}
/**
* nand_writev_ecc - [ MTD Interface ] write with iovec with ecc
* @ mtd : MTD device structure
* @ vecs : the iovectors to write
* @ count : number of vectors
* @ to : offset to write to
* @ retlen : pointer to variable to store the number of written bytes
* @ eccbuf : filesystem supplied oob data buffer
* @ oobsel : oob selection structure
*
* NAND write with iovec with ecc
*/
2006-05-13 21:07:53 +04:00
static int nand_writev_ecc ( struct mtd_info * mtd , const struct kvec * vecs , unsigned long count ,
2006-05-23 13:52:35 +04:00
loff_t to , size_t * retlen , uint8_t * eccbuf , struct nand_oobinfo * oobsel )
2005-04-17 02:20:36 +04:00
{
int i , page , len , total_len , ret = - EIO , written = 0 , chipnr ;
int oob , numpages , autoplace = 0 , startpage ;
struct nand_chip * this = mtd - > priv ;
2006-05-13 21:07:53 +04:00
int ppblock = ( 1 < < ( this - > phys_erase_shift - this - > page_shift ) ) ;
2006-05-23 13:52:35 +04:00
uint8_t * oobbuf , * bufstart ;
2005-04-17 02:20:36 +04:00
/* Preset written len for early exit */
* retlen = 0 ;
/* Calculate total length of data */
total_len = 0 ;
for ( i = 0 ; i < count ; i + + )
2006-05-13 21:07:53 +04:00
total_len + = ( int ) vecs [ i ] . iov_len ;
2005-04-17 02:20:36 +04:00
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL3 , " nand_writev: to = 0x%08x, len = %i, count = %ld \n " , ( unsigned int ) to , ( unsigned int ) total_len , count ) ;
2005-04-17 02:20:36 +04:00
/* Do not allow write past end of page */
if ( ( to + total_len ) > mtd - > size ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " nand_writev: Attempted write past end of device \n " ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
2005-11-07 14:15:49 +03:00
/* reject writes, which are not page aligned */
2006-05-13 21:07:53 +04:00
if ( NOTALIGNED ( to ) | | NOTALIGNED ( total_len ) ) {
printk ( KERN_NOTICE " nand_write_ecc: Attempt to write not page aligned data \n " ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
/* Grab the lock and see if the device is available */
2006-05-13 21:07:53 +04:00
nand_get_device ( this , mtd , FL_WRITING ) ;
2005-04-17 02:20:36 +04:00
/* Get the current chip-nr */
2006-05-13 21:07:53 +04:00
chipnr = ( int ) ( to > > this - > chip_shift ) ;
2005-04-17 02:20:36 +04:00
/* Select the NAND device */
this - > select_chip ( mtd , chipnr ) ;
/* Check, if it is write protected */
if ( nand_check_wp ( mtd ) )
goto out ;
/* if oobsel is NULL, use chip defaults */
2005-11-07 14:15:49 +03:00
if ( oobsel = = NULL )
oobsel = & mtd - > oobinfo ;
2005-04-17 02:20:36 +04:00
/* Autoplace of oob data ? Use the default placement scheme */
if ( oobsel - > useecc = = MTD_NANDECC_AUTOPLACE ) {
oobsel = this - > autooob ;
autoplace = 1 ;
2005-11-07 14:15:49 +03:00
}
2005-05-19 20:10:26 +04:00
if ( oobsel - > useecc = = MTD_NANDECC_AUTOPL_USR )
autoplace = 1 ;
2005-04-17 02:20:36 +04:00
/* Setup start page */
2006-05-13 21:07:53 +04:00
page = ( int ) ( to > > this - > page_shift ) ;
2005-04-17 02:20:36 +04:00
/* Invalidate the page cache, if we write to the cached page */
2005-11-07 14:15:49 +03:00
if ( page < = this - > pagebuf & & this - > pagebuf < ( ( to + total_len ) > > this - > page_shift ) )
2005-04-17 02:20:36 +04:00
this - > pagebuf = - 1 ;
startpage = page & this - > pagemask ;
/* Loop until all kvec' data has been written */
len = 0 ;
while ( count ) {
/* If the given tuple is >= pagesize then
* write it out from the iov
*/
2006-05-23 01:18:05 +04:00
if ( ( vecs - > iov_len - len ) > = mtd - > writesize ) {
2005-04-17 02:20:36 +04:00
/* Calc number of pages we can write
* out of this iov in one go */
numpages = ( vecs - > iov_len - len ) > > this - > page_shift ;
/* Do not cross block boundaries */
2006-05-13 21:07:53 +04:00
numpages = min ( ppblock - ( startpage & ( ppblock - 1 ) ) , numpages ) ;
oobbuf = nand_prepare_oobbuf ( mtd , NULL , oobsel , autoplace , numpages ) ;
2006-05-23 13:52:35 +04:00
bufstart = ( uint8_t * ) vecs - > iov_base ;
2005-04-17 02:20:36 +04:00
bufstart + = len ;
this - > data_poi = bufstart ;
oob = 0 ;
for ( i = 1 ; i < = numpages ; i + + ) {
/* Write one page. If this is the last page to write
2005-11-07 14:15:49 +03:00
* then use the real pageprogram command , else select
2005-04-17 02:20:36 +04:00
* cached programming if supported by the chip .
*/
2006-05-13 21:07:53 +04:00
ret = nand_write_page ( mtd , this , page & this - > pagemask ,
& oobbuf [ oob ] , oobsel , i ! = numpages ) ;
2005-04-17 02:20:36 +04:00
if ( ret )
goto out ;
2006-05-23 01:18:05 +04:00
this - > data_poi + = mtd - > writesize ;
len + = mtd - > writesize ;
2005-04-17 02:20:36 +04:00
oob + = mtd - > oobsize ;
page + + ;
}
/* Check, if we have to switch to the next tuple */
2006-05-13 21:07:53 +04:00
if ( len > = ( int ) vecs - > iov_len ) {
2005-04-17 02:20:36 +04:00
vecs + + ;
len = 0 ;
count - - ;
}
} else {
2005-11-07 14:15:49 +03:00
/* We must use the internal buffer, read data out of each
2005-04-17 02:20:36 +04:00
* tuple until we have a full page to write
*/
int cnt = 0 ;
2006-05-23 01:18:05 +04:00
while ( cnt < mtd - > writesize ) {
2005-11-07 14:15:49 +03:00
if ( vecs - > iov_base ! = NULL & & vecs - > iov_len )
2006-05-23 13:52:35 +04:00
this - > data_buf [ cnt + + ] = ( ( uint8_t * ) vecs - > iov_base ) [ len + + ] ;
2005-04-17 02:20:36 +04:00
/* Check, if we have to switch to the next tuple */
2006-05-13 21:07:53 +04:00
if ( len > = ( int ) vecs - > iov_len ) {
2005-04-17 02:20:36 +04:00
vecs + + ;
len = 0 ;
count - - ;
}
}
2005-11-07 14:15:49 +03:00
this - > pagebuf = page ;
this - > data_poi = this - > data_buf ;
2005-04-17 02:20:36 +04:00
bufstart = this - > data_poi ;
2005-11-07 14:15:49 +03:00
numpages = 1 ;
2006-05-13 21:07:53 +04:00
oobbuf = nand_prepare_oobbuf ( mtd , NULL , oobsel , autoplace , numpages ) ;
ret = nand_write_page ( mtd , this , page & this - > pagemask , oobbuf , oobsel , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( ret )
goto out ;
page + + ;
}
this - > data_poi = bufstart ;
2006-05-13 21:07:53 +04:00
ret = nand_verify_pages ( mtd , this , startpage , numpages , oobbuf , oobsel , chipnr , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( ret )
goto out ;
2005-11-07 14:15:49 +03:00
2006-05-23 01:18:05 +04:00
written + = mtd - > writesize * numpages ;
2005-04-17 02:20:36 +04:00
/* All done ? */
if ( ! count )
break ;
startpage = page & this - > pagemask ;
/* Check, if we cross a chip boundary */
if ( ! startpage ) {
chipnr + + ;
this - > select_chip ( mtd , - 1 ) ;
this - > select_chip ( mtd , chipnr ) ;
}
}
ret = 0 ;
2006-05-13 21:07:53 +04:00
out :
2005-04-17 02:20:36 +04:00
/* Deselect and wake up anyone waiting on the device */
nand_release_device ( mtd ) ;
* retlen = written ;
return ret ;
}
/**
* single_erease_cmd - [ GENERIC ] NAND standard block erase command function
* @ mtd : MTD device structure
* @ page : the page address of the block which will be erased
*
* Standard erase command for NAND chips
*/
2006-05-13 21:07:53 +04:00
static void single_erase_cmd ( struct mtd_info * mtd , int page )
2005-04-17 02:20:36 +04:00
{
struct nand_chip * this = mtd - > priv ;
/* Send commands to erase a block */
2006-05-13 21:07:53 +04:00
this - > cmdfunc ( mtd , NAND_CMD_ERASE1 , - 1 , page ) ;
this - > cmdfunc ( mtd , NAND_CMD_ERASE2 , - 1 , - 1 ) ;
2005-04-17 02:20:36 +04:00
}
/**
* multi_erease_cmd - [ GENERIC ] AND specific block erase command function
* @ mtd : MTD device structure
* @ page : the page address of the block which will be erased
*
* AND multi block erase command function
* Erase 4 consecutive blocks
*/
2006-05-13 21:07:53 +04:00
static void multi_erase_cmd ( struct mtd_info * mtd , int page )
2005-04-17 02:20:36 +04:00
{
struct nand_chip * this = mtd - > priv ;
/* Send commands to erase a block */
2006-05-13 21:07:53 +04:00
this - > cmdfunc ( mtd , NAND_CMD_ERASE1 , - 1 , page + + ) ;
this - > cmdfunc ( mtd , NAND_CMD_ERASE1 , - 1 , page + + ) ;
this - > cmdfunc ( mtd , NAND_CMD_ERASE1 , - 1 , page + + ) ;
this - > cmdfunc ( mtd , NAND_CMD_ERASE1 , - 1 , page ) ;
this - > cmdfunc ( mtd , NAND_CMD_ERASE2 , - 1 , - 1 ) ;
2005-04-17 02:20:36 +04:00
}
/**
* nand_erase - [ MTD Interface ] erase block ( s )
* @ mtd : MTD device structure
* @ instr : erase instruction
*
* Erase one ore more blocks
*/
2006-05-13 21:07:53 +04:00
static int nand_erase ( struct mtd_info * mtd , struct erase_info * instr )
2005-04-17 02:20:36 +04:00
{
2006-05-13 21:07:53 +04:00
return nand_erase_nand ( mtd , instr , 0 ) ;
2005-04-17 02:20:36 +04:00
}
2005-11-07 14:15:49 +03:00
2005-01-17 21:35:25 +03:00
# define BBT_PAGE_MASK 0xffffff3f
2005-04-17 02:20:36 +04:00
/**
* nand_erase_intern - [ NAND Interface ] erase block ( s )
* @ mtd : MTD device structure
* @ instr : erase instruction
* @ allowbbt : allow erasing the bbt area
*
* Erase one ore more blocks
*/
2006-05-13 21:07:53 +04:00
int nand_erase_nand ( struct mtd_info * mtd , struct erase_info * instr , int allowbbt )
2005-04-17 02:20:36 +04:00
{
int page , len , status , pages_per_block , ret , chipnr ;
struct nand_chip * this = mtd - > priv ;
2005-01-17 21:35:25 +03:00
int rewrite_bbt [ NAND_MAX_CHIPS ] = { 0 } ; /* flags to indicate the page, if bbt needs to be rewritten. */
unsigned int bbt_masked_page ; /* bbt mask to compare to page being erased. */
/* It is used to see if the current page is in the same */
/* 256 block group and the same bank as the bbt. */
2005-04-17 02:20:36 +04:00
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL3 , " nand_erase: start = 0x%08x, len = %i \n " , ( unsigned int ) instr - > addr , ( unsigned int ) instr - > len ) ;
2005-04-17 02:20:36 +04:00
/* Start address must align on block boundary */
if ( instr - > addr & ( ( 1 < < this - > phys_erase_shift ) - 1 ) ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " nand_erase: Unaligned address \n " ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
/* Length must align on block boundary */
if ( instr - > len & ( ( 1 < < this - > phys_erase_shift ) - 1 ) ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " nand_erase: Length not block aligned \n " ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
/* Do not allow erase past end of device */
if ( ( instr - > len + instr - > addr ) > mtd - > size ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " nand_erase: Erase past end of device \n " ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
instr - > fail_addr = 0xffffffff ;
/* Grab the lock and see if the device is available */
2006-05-13 21:07:53 +04:00
nand_get_device ( this , mtd , FL_ERASING ) ;
2005-04-17 02:20:36 +04:00
/* Shift to get first page */
2006-05-13 21:07:53 +04:00
page = ( int ) ( instr - > addr > > this - > page_shift ) ;
chipnr = ( int ) ( instr - > addr > > this - > chip_shift ) ;
2005-04-17 02:20:36 +04:00
/* Calculate pages in each block */
pages_per_block = 1 < < ( this - > phys_erase_shift - this - > page_shift ) ;
/* Select the NAND device */
this - > select_chip ( mtd , chipnr ) ;
/* Check the WP bit */
/* Check, if it is write protected */
if ( nand_check_wp ( mtd ) ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " nand_erase: Device is write protected!!! \n " ) ;
2005-04-17 02:20:36 +04:00
instr - > state = MTD_ERASE_FAILED ;
goto erase_exit ;
}
2005-01-17 21:35:25 +03:00
/* if BBT requires refresh, set the BBT page mask to see if the BBT should be rewritten */
if ( this - > options & BBT_AUTO_REFRESH ) {
bbt_masked_page = this - > bbt_td - > pages [ chipnr ] & BBT_PAGE_MASK ;
} else {
bbt_masked_page = 0xffffffff ; /* should not match anything */
}
2005-04-17 02:20:36 +04:00
/* Loop through the pages */
len = instr - > len ;
instr - > state = MTD_ERASING ;
while ( len ) {
/* Check if we have a bad block, we do not erase bad blocks ! */
if ( nand_block_checkbad ( mtd , ( ( loff_t ) page ) < < this - > page_shift , 0 , allowbbt ) ) {
2006-05-13 21:07:53 +04:00
printk ( KERN_WARNING " nand_erase: attempt to erase a bad block at page 0x%08x \n " , page ) ;
2005-04-17 02:20:36 +04:00
instr - > state = MTD_ERASE_FAILED ;
goto erase_exit ;
}
2005-11-07 14:15:49 +03:00
/* Invalidate the page cache, if we erase the block which contains
2005-04-17 02:20:36 +04:00
the current cached page */
if ( page < = this - > pagebuf & & this - > pagebuf < ( page + pages_per_block ) )
this - > pagebuf = - 1 ;
2006-05-13 21:07:53 +04:00
this - > erase_cmd ( mtd , page & this - > pagemask ) ;
2005-11-07 14:15:49 +03:00
2006-05-13 21:07:53 +04:00
status = this - > waitfunc ( mtd , this , FL_ERASING ) ;
2005-04-17 02:20:36 +04:00
2005-01-24 06:07:46 +03:00
/* See if operation failed and additional status checks are available */
if ( ( status & NAND_STATUS_FAIL ) & & ( this - > errstat ) ) {
status = this - > errstat ( mtd , this , FL_ERASING , status , page ) ;
}
2005-04-17 02:20:36 +04:00
/* See if block erase succeeded */
2005-01-23 21:30:53 +03:00
if ( status & NAND_STATUS_FAIL ) {
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " nand_erase: " " Failed erase, page 0x%08x \n " , page ) ;
2005-04-17 02:20:36 +04:00
instr - > state = MTD_ERASE_FAILED ;
instr - > fail_addr = ( page < < this - > page_shift ) ;
goto erase_exit ;
}
2005-01-17 21:35:25 +03:00
/* if BBT requires refresh, set the BBT rewrite flag to the page being erased */
if ( this - > options & BBT_AUTO_REFRESH ) {
2005-11-07 14:15:49 +03:00
if ( ( ( page & BBT_PAGE_MASK ) = = bbt_masked_page ) & &
2005-01-17 21:35:25 +03:00
( page ! = this - > bbt_td - > pages [ chipnr ] ) ) {
rewrite_bbt [ chipnr ] = ( page < < this - > page_shift ) ;
}
}
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
/* Increment page address and decrement length */
len - = ( 1 < < this - > phys_erase_shift ) ;
page + = pages_per_block ;
/* Check, if we cross a chip boundary */
if ( len & & ! ( page & this - > pagemask ) ) {
chipnr + + ;
this - > select_chip ( mtd , - 1 ) ;
this - > select_chip ( mtd , chipnr ) ;
2005-01-17 21:35:25 +03:00
2005-11-07 14:15:49 +03:00
/* if BBT requires refresh and BBT-PERCHIP,
2005-01-17 21:35:25 +03:00
* set the BBT page mask to see if this BBT should be rewritten */
if ( ( this - > options & BBT_AUTO_REFRESH ) & & ( this - > bbt_td - > options & NAND_BBT_PERCHIP ) ) {
bbt_masked_page = this - > bbt_td - > pages [ chipnr ] & BBT_PAGE_MASK ;
}
2005-04-17 02:20:36 +04:00
}
}
instr - > state = MTD_ERASE_DONE ;
2006-05-13 21:07:53 +04:00
erase_exit :
2005-04-17 02:20:36 +04:00
ret = instr - > state = = MTD_ERASE_DONE ? 0 : - EIO ;
/* Do call back function */
if ( ! ret )
mtd_erase_callback ( instr ) ;
/* Deselect and wake up anyone waiting on the device */
nand_release_device ( mtd ) ;
2005-01-17 21:35:25 +03:00
/* if BBT requires refresh and erase was successful, rewrite any selected bad block tables */
if ( ( this - > options & BBT_AUTO_REFRESH ) & & ( ! ret ) ) {
for ( chipnr = 0 ; chipnr < this - > numchips ; chipnr + + ) {
if ( rewrite_bbt [ chipnr ] ) {
/* update the BBT for chip */
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL0 , " nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x) \n " ,
chipnr , rewrite_bbt [ chipnr ] , this - > bbt_td - > pages [ chipnr ] ) ;
nand_update_bbt ( mtd , rewrite_bbt [ chipnr ] ) ;
2005-01-17 21:35:25 +03:00
}
}
}
2005-04-17 02:20:36 +04:00
/* Return more or less happy */
return ret ;
}
/**
* nand_sync - [ MTD Interface ] sync
* @ mtd : MTD device structure
*
* Sync is actually a wait for chip ready function
*/
2006-05-13 21:07:53 +04:00
static void nand_sync ( struct mtd_info * mtd )
2005-04-17 02:20:36 +04:00
{
struct nand_chip * this = mtd - > priv ;
2006-05-13 21:07:53 +04:00
DEBUG ( MTD_DEBUG_LEVEL3 , " nand_sync: called \n " ) ;
2005-04-17 02:20:36 +04:00
/* Grab the lock and see if the device is available */
2006-05-13 21:07:53 +04:00
nand_get_device ( this , mtd , FL_SYNCING ) ;
2005-04-17 02:20:36 +04:00
/* Release it and go back */
2006-05-13 21:07:53 +04:00
nand_release_device ( mtd ) ;
2005-04-17 02:20:36 +04:00
}
/**
* nand_block_isbad - [ MTD Interface ] Check whether the block at the given offset is bad
* @ mtd : MTD device structure
* @ ofs : offset relative to mtd start
*/
2006-05-13 21:07:53 +04:00
static int nand_block_isbad ( struct mtd_info * mtd , loff_t ofs )
2005-04-17 02:20:36 +04:00
{
/* Check for invalid offset */
2005-11-07 14:15:49 +03:00
if ( ofs > mtd - > size )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2005-11-07 14:15:49 +03:00
2006-05-13 21:07:53 +04:00
return nand_block_checkbad ( mtd , ofs , 1 , 0 ) ;
2005-04-17 02:20:36 +04:00
}
/**
* nand_block_markbad - [ MTD Interface ] Mark the block at the given offset as bad
* @ mtd : MTD device structure
* @ ofs : offset relative to mtd start
*/
2006-05-13 21:07:53 +04:00
static int nand_block_markbad ( struct mtd_info * mtd , loff_t ofs )
2005-04-17 02:20:36 +04:00
{
struct nand_chip * this = mtd - > priv ;
int ret ;
2006-05-13 21:07:53 +04:00
if ( ( ret = nand_block_isbad ( mtd , ofs ) ) ) {
/* If it was bad already, return success and do nothing. */
2005-04-17 02:20:36 +04:00
if ( ret > 0 )
return 0 ;
2006-05-13 21:07:53 +04:00
return ret ;
}
2005-04-17 02:20:36 +04:00
return this - > block_markbad ( mtd , ofs ) ;
}
2005-09-15 17:58:53 +04:00
/**
* nand_suspend - [ MTD Interface ] Suspend the NAND flash
* @ mtd : MTD device structure
*/
static int nand_suspend ( struct mtd_info * mtd )
{
struct nand_chip * this = mtd - > priv ;
2006-05-13 21:07:53 +04:00
return nand_get_device ( this , mtd , FL_PM_SUSPENDED ) ;
2005-09-15 17:58:53 +04:00
}
/**
* nand_resume - [ MTD Interface ] Resume the NAND flash
* @ mtd : MTD device structure
*/
static void nand_resume ( struct mtd_info * mtd )
{
struct nand_chip * this = mtd - > priv ;
if ( this - > state = = FL_PM_SUSPENDED )
nand_release_device ( mtd ) ;
else
2006-05-23 13:50:56 +04:00
printk ( KERN_ERR " nand_resume() called for a chip which is not "
" in suspended state \n " ) ;
2005-09-15 17:58:53 +04:00
}
2006-05-23 13:37:03 +04:00
/*
* Free allocated data structures
*/
static void nand_free_kmem ( struct nand_chip * this )
{
/* Buffer allocated by nand_scan ? */
if ( this - > options & NAND_OOBBUF_ALLOC )
kfree ( this - > oob_buf ) ;
/* Buffer allocated by nand_scan ? */
if ( this - > options & NAND_DATABUF_ALLOC )
kfree ( this - > data_buf ) ;
/* Controller allocated by nand_scan ? */
if ( this - > options & NAND_CONTROLLER_ALLOC )
kfree ( this - > controller ) ;
}
2006-05-23 13:54:38 +04:00
/*
* Allocate buffers and data structures
2005-04-17 02:20:36 +04:00
*/
2006-05-23 13:54:38 +04:00
static int nand_allocate_kmem ( struct mtd_info * mtd , struct nand_chip * this )
2005-04-17 02:20:36 +04:00
{
2006-05-23 13:54:38 +04:00
size_t len ;
2005-04-17 02:20:36 +04:00
2006-05-23 13:54:38 +04:00
if ( ! this - > oob_buf ) {
len = mtd - > oobsize < <
( this - > phys_erase_shift - this - > page_shift ) ;
this - > oob_buf = kmalloc ( len , GFP_KERNEL ) ;
if ( ! this - > oob_buf )
goto outerr ;
this - > options | = NAND_OOBBUF_ALLOC ;
2006-05-14 04:20:46 +04:00
}
2006-05-23 13:54:38 +04:00
if ( ! this - > data_buf ) {
2006-05-23 14:37:31 +04:00
len = mtd - > writesize + mtd - > oobsize ;
2006-05-23 13:54:38 +04:00
this - > data_buf = kmalloc ( len , GFP_KERNEL ) ;
if ( ! this - > data_buf )
goto outerr ;
this - > options | = NAND_DATABUF_ALLOC ;
}
if ( ! this - > controller ) {
this - > controller = kzalloc ( sizeof ( struct nand_hw_control ) ,
GFP_KERNEL ) ;
if ( ! this - > controller )
goto outerr ;
this - > options | = NAND_CONTROLLER_ALLOC ;
}
return 0 ;
2005-04-17 02:20:36 +04:00
2006-05-23 13:54:38 +04:00
outerr :
printk ( KERN_ERR " nand_scan(): Cannot allocate buffers \n " ) ;
nand_free_kmem ( this ) ;
return - ENOMEM ;
}
/*
* Set default functions
*/
static void nand_set_defaults ( struct nand_chip * this , int busw )
{
2005-04-17 02:20:36 +04:00
/* check for proper chip_delay setup, set 20us if not */
if ( ! this - > chip_delay )
this - > chip_delay = 20 ;
/* check, if a user supplied command function given */
if ( this - > cmdfunc = = NULL )
this - > cmdfunc = nand_command ;
/* check, if a user supplied wait function given */
if ( this - > waitfunc = = NULL )
this - > waitfunc = nand_wait ;
if ( ! this - > select_chip )
this - > select_chip = nand_select_chip ;
if ( ! this - > write_byte )
this - > write_byte = busw ? nand_write_byte16 : nand_write_byte ;
if ( ! this - > read_byte )
this - > read_byte = busw ? nand_read_byte16 : nand_read_byte ;
if ( ! this - > write_word )
this - > write_word = nand_write_word ;
if ( ! this - > read_word )
this - > read_word = nand_read_word ;
if ( ! this - > block_bad )
this - > block_bad = nand_block_bad ;
if ( ! this - > block_markbad )
this - > block_markbad = nand_default_block_markbad ;
if ( ! this - > write_buf )
this - > write_buf = busw ? nand_write_buf16 : nand_write_buf ;
if ( ! this - > read_buf )
this - > read_buf = busw ? nand_read_buf16 : nand_read_buf ;
if ( ! this - > verify_buf )
this - > verify_buf = busw ? nand_verify_buf16 : nand_verify_buf ;
if ( ! this - > scan_bbt )
this - > scan_bbt = nand_default_bbt ;
2006-05-23 13:54:38 +04:00
}
/*
* Get the flash and manufacturer id and lookup if the typ is supported
*/
static struct nand_flash_dev * nand_get_flash_type ( struct mtd_info * mtd ,
struct nand_chip * this ,
int busw , int * maf_id )
{
struct nand_flash_dev * type = NULL ;
int i , dev_id , maf_idx ;
2005-04-17 02:20:36 +04:00
/* Select the device */
this - > select_chip ( mtd , 0 ) ;
/* Send the command for reading device ID */
2006-05-13 21:07:53 +04:00
this - > cmdfunc ( mtd , NAND_CMD_READID , 0x00 , - 1 ) ;
2005-04-17 02:20:36 +04:00
/* Read manufacturer and device IDs */
2006-05-23 13:54:38 +04:00
* maf_id = this - > read_byte ( mtd ) ;
dev_id = this - > read_byte ( mtd ) ;
2005-04-17 02:20:36 +04:00
2006-05-23 13:54:38 +04:00
/* Lookup the flash id */
2005-04-17 02:20:36 +04:00
for ( i = 0 ; nand_flash_ids [ i ] . name ! = NULL ; i + + ) {
2006-05-23 13:54:38 +04:00
if ( dev_id = = nand_flash_ids [ i ] . id ) {
type = & nand_flash_ids [ i ] ;
break ;
}
}
2005-11-07 14:15:49 +03:00
2006-05-23 13:54:38 +04:00
if ( ! type )
return ERR_PTR ( - ENODEV ) ;
this - > chipsize = nand_flash_ids [ i ] . chipsize < < 20 ;
/* Newer devices have all the information in additional id bytes */
if ( ! nand_flash_ids [ i ] . pagesize ) {
int extid ;
/* The 3rd id byte contains non relevant data ATM */
extid = this - > read_byte ( mtd ) ;
/* The 4th id byte is the important one */
extid = this - > read_byte ( mtd ) ;
/* Calc pagesize */
2006-05-23 14:37:31 +04:00
mtd - > writesize = 1024 < < ( extid & 0x3 ) ;
2006-05-23 13:54:38 +04:00
extid > > = 2 ;
/* Calc oobsize */
2006-05-23 14:37:31 +04:00
mtd - > oobsize = ( 8 < < ( extid & 0x01 ) ) * ( mtd - > writesize > > 9 ) ;
2006-05-23 13:54:38 +04:00
extid > > = 2 ;
/* Calc blocksize. Blocksize is multiples of 64KiB */
mtd - > erasesize = ( 64 * 1024 ) < < ( extid & 0x03 ) ;
extid > > = 2 ;
/* Get buswidth information */
busw = ( extid & 0x01 ) ? NAND_BUSWIDTH_16 : 0 ;
2005-11-07 14:15:49 +03:00
2006-05-23 13:54:38 +04:00
} else {
/*
* Old devices have this data hardcoded in the device id table
*/
mtd - > erasesize = nand_flash_ids [ i ] . erasesize ;
2006-05-23 14:37:31 +04:00
mtd - > writesize = nand_flash_ids [ i ] . pagesize ;
mtd - > oobsize = mtd - > writesize / 32 ;
2006-05-23 13:54:38 +04:00
busw = nand_flash_ids [ i ] . options & NAND_BUSWIDTH_16 ;
}
2005-04-17 02:20:36 +04:00
2006-05-23 13:54:38 +04:00
/* Try to identify manufacturer */
for ( maf_idx = 0 ; nand_manuf_ids [ maf_idx ] . id ! = 0x0 ; maf_id + + ) {
if ( nand_manuf_ids [ maf_idx ] . id = = * maf_id )
break ;
}
2005-02-16 12:39:39 +03:00
2006-05-23 13:54:38 +04:00
/*
* Check , if buswidth is correct . Hardware drivers should set
* this correct !
*/
if ( busw ! = ( this - > options & NAND_BUSWIDTH_16 ) ) {
printk ( KERN_INFO " NAND device: Manufacturer ID: "
" 0x%02x, Chip ID: 0x%02x (%s %s) \n " , * maf_id ,
dev_id , nand_manuf_ids [ maf_idx ] . name , mtd - > name ) ;
printk ( KERN_WARNING " NAND bus width %d instead %d bit \n " ,
( this - > options & NAND_BUSWIDTH_16 ) ? 16 : 8 ,
busw ? 16 : 8 ) ;
return ERR_PTR ( - EINVAL ) ;
}
2005-11-07 14:15:49 +03:00
2006-05-23 13:54:38 +04:00
/* Calculate the address shift from the page size */
2006-05-23 14:37:31 +04:00
this - > page_shift = ffs ( mtd - > writesize ) - 1 ;
2006-05-23 13:54:38 +04:00
/* Convert chipsize to number of pages per chip -1. */
this - > pagemask = ( this - > chipsize > > this - > page_shift ) - 1 ;
2005-11-07 14:15:49 +03:00
2006-05-23 13:54:38 +04:00
this - > bbt_erase_shift = this - > phys_erase_shift =
ffs ( mtd - > erasesize ) - 1 ;
this - > chip_shift = ffs ( this - > chipsize ) - 1 ;
2005-04-17 02:20:36 +04:00
2006-05-23 13:54:38 +04:00
/* Set the bad block position */
2006-05-23 14:37:31 +04:00
this - > badblockpos = mtd - > writesize > 512 ?
2006-05-23 13:54:38 +04:00
NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS ;
2005-11-07 14:15:49 +03:00
2006-05-23 13:54:38 +04:00
/* Get chip options, preserve non chip based options */
this - > options & = ~ NAND_CHIPOPTIONS_MSK ;
this - > options | = nand_flash_ids [ i ] . options & NAND_CHIPOPTIONS_MSK ;
/*
* Set this as a default . Board drivers can override it , if necessary
*/
this - > options | = NAND_NO_AUTOINCR ;
/* Check if this is a not a samsung device. Do not clear the
* options for chips which are not having an extended id .
*/
if ( * maf_id ! = NAND_MFR_SAMSUNG & & ! nand_flash_ids [ i ] . pagesize )
this - > options & = ~ NAND_SAMSUNG_LP_OPTIONS ;
/* Check for AND chips with 4 page planes */
if ( this - > options & NAND_4PAGE_ARRAY )
this - > erase_cmd = multi_erase_cmd ;
else
this - > erase_cmd = single_erase_cmd ;
/* Do not replace user supplied command function ! */
2006-05-23 14:37:31 +04:00
if ( mtd - > writesize > 512 & & this - > cmdfunc = = nand_command )
2006-05-23 13:54:38 +04:00
this - > cmdfunc = nand_command_lp ;
printk ( KERN_INFO " NAND device: Manufacturer ID: "
" 0x%02x, Chip ID: 0x%02x (%s %s) \n " , * maf_id , dev_id ,
nand_manuf_ids [ maf_idx ] . name , type - > name ) ;
return type ;
}
/* module_text_address() isn't exported, and it's mostly a pointless
test if this is a module _anyway_ - - they ' d have to try _really_ hard
to call us from in - kernel code if the core NAND support is modular . */
# ifdef MODULE
# define caller_is_module() (1)
# else
# define caller_is_module() \
module_text_address ( ( unsigned long ) __builtin_return_address ( 0 ) )
# endif
/**
* nand_scan - [ NAND Interface ] Scan for the NAND device
* @ mtd : MTD device structure
* @ maxchips : Number of chips to scan for
*
* This fills out all the uninitialized function pointers
* with the defaults .
* The flash ID is read and the mtd / chip structures are
* filled with the appropriate values . Buffers are allocated if
* they are not provided by the board driver
* The mtd - > owner field must be set to the module of the caller
*
*/
int nand_scan ( struct mtd_info * mtd , int maxchips )
{
int i , busw , nand_maf_id ;
struct nand_chip * this = mtd - > priv ;
struct nand_flash_dev * type ;
/* Many callers got this wrong, so check for it for a while... */
if ( ! mtd - > owner & & caller_is_module ( ) ) {
printk ( KERN_CRIT " nand_scan() called with NULL mtd->owner! \n " ) ;
BUG ( ) ;
2005-04-17 02:20:36 +04:00
}
2006-05-23 13:54:38 +04:00
/* Get buswidth to select the correct functions */
busw = this - > options & NAND_BUSWIDTH_16 ;
/* Set the default functions */
nand_set_defaults ( this , busw ) ;
/* Read the flash type */
type = nand_get_flash_type ( mtd , this , busw , & nand_maf_id ) ;
if ( IS_ERR ( type ) ) {
2006-05-13 21:07:53 +04:00
printk ( KERN_WARNING " No NAND device found!!! \n " ) ;
2005-04-17 02:20:36 +04:00
this - > select_chip ( mtd , - 1 ) ;
2006-05-23 13:54:38 +04:00
return PTR_ERR ( type ) ;
2005-04-17 02:20:36 +04:00
}
2006-05-23 13:54:38 +04:00
/* Check for a chip array */
2006-05-13 21:07:53 +04:00
for ( i = 1 ; i < maxchips ; i + + ) {
2005-04-17 02:20:36 +04:00
this - > select_chip ( mtd , i ) ;
/* Send the command for reading device ID */
2006-05-13 21:07:53 +04:00
this - > cmdfunc ( mtd , NAND_CMD_READID , 0x00 , - 1 ) ;
2005-04-17 02:20:36 +04:00
/* Read manufacturer and device IDs */
if ( nand_maf_id ! = this - > read_byte ( mtd ) | |
2006-05-23 13:54:38 +04:00
type - > id ! = this - > read_byte ( mtd ) )
2005-04-17 02:20:36 +04:00
break ;
}
if ( i > 1 )
printk ( KERN_INFO " %d NAND chips detected \n " , i ) ;
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
/* Store the number of chips and calc total size for mtd */
this - > numchips = i ;
mtd - > size = i * this - > chipsize ;
2006-05-23 13:54:38 +04:00
/* Allocate buffers and data structures */
if ( nand_allocate_kmem ( mtd , this ) )
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
/* Preset the internal oob buffer */
2006-05-23 13:54:38 +04:00
memset ( this - > oob_buf , 0xff ,
mtd - > oobsize < < ( this - > phys_erase_shift - this - > page_shift ) ) ;
2005-04-17 02:20:36 +04:00
2006-05-23 13:54:38 +04:00
/*
* If no default placement scheme is given , select an appropriate one
*/
2005-04-17 02:20:36 +04:00
if ( ! this - > autooob ) {
2005-11-07 14:15:49 +03:00
switch ( mtd - > oobsize ) {
2005-04-17 02:20:36 +04:00
case 8 :
this - > autooob = & nand_oob_8 ;
break ;
case 16 :
this - > autooob = & nand_oob_16 ;
break ;
case 64 :
this - > autooob = & nand_oob_64 ;
break ;
default :
2006-05-23 13:54:38 +04:00
printk ( KERN_WARNING " No oob scheme defined for "
" oobsize %d \n " , mtd - > oobsize ) ;
2005-04-17 02:20:36 +04:00
BUG ( ) ;
}
}
2005-11-07 14:15:49 +03:00
2006-05-23 13:54:38 +04:00
/*
* The number of bytes available for the filesystem to place fs
* dependend oob data
*/
2005-04-01 11:21:48 +04:00
mtd - > oobavail = 0 ;
for ( i = 0 ; this - > autooob - > oobfree [ i ] [ 1 ] ; i + + )
mtd - > oobavail + = this - > autooob - > oobfree [ i ] [ 1 ] ;
2005-04-17 02:20:36 +04:00
2005-11-07 14:15:49 +03:00
/*
2006-05-23 13:54:38 +04:00
* check ECC mode , default to software if 3 byte / 512 byte hardware ECC is
* selected and we have 256 byte pagesize fallback to software ECC
2006-05-13 21:07:53 +04:00
*/
2006-05-23 14:00:46 +04:00
switch ( this - > ecc . mode ) {
case NAND_ECC_HW :
case NAND_ECC_HW_SYNDROME :
if ( ! this - > ecc . calculate | | ! this - > ecc . correct | |
! this - > ecc . hwctl ) {
printk ( KERN_WARNING " No ECC functions supplied, "
" Hardware ECC not possible \n " ) ;
BUG ( ) ;
}
2006-05-23 14:37:31 +04:00
if ( mtd - > writesize > = this - > ecc . size )
2006-05-23 14:00:46 +04:00
break ;
printk ( KERN_WARNING " %d byte HW ECC not possible on "
" %d byte page size, fallback to SW ECC \n " ,
2006-05-23 14:37:31 +04:00
this - > ecc . size , mtd - > writesize ) ;
2006-05-23 14:00:46 +04:00
this - > ecc . mode = NAND_ECC_SOFT ;
2005-11-07 14:15:49 +03:00
2006-05-23 14:00:46 +04:00
case NAND_ECC_SOFT :
this - > ecc . calculate = nand_calculate_ecc ;
this - > ecc . correct = nand_correct_data ;
this - > ecc . size = 256 ;
this - > ecc . bytes = 3 ;
2005-04-17 02:20:36 +04:00
break ;
2005-11-07 14:15:49 +03:00
case NAND_ECC_NONE :
2006-05-23 13:54:38 +04:00
printk ( KERN_WARNING " NAND_ECC_NONE selected by board driver. "
" This is not recommended !! \n " ) ;
2006-05-23 14:37:31 +04:00
this - > ecc . size = mtd - > writesize ;
2006-05-23 14:00:46 +04:00
this - > ecc . bytes = 0 ;
2005-04-17 02:20:36 +04:00
break ;
default :
2006-05-23 13:54:38 +04:00
printk ( KERN_WARNING " Invalid NAND_ECC_MODE %d \n " ,
2006-05-23 14:00:46 +04:00
this - > ecc . mode ) ;
2005-11-07 14:15:49 +03:00
BUG ( ) ;
2005-04-17 02:20:36 +04:00
}
2005-11-07 14:15:49 +03:00
2006-05-23 13:54:38 +04:00
/*
* Set the number of read / write steps for one page depending on ECC
* mode
*/
2006-05-23 14:37:31 +04:00
this - > ecc . steps = mtd - > writesize / this - > ecc . size ;
if ( this - > ecc . steps * this - > ecc . size ! = mtd - > writesize ) {
2006-05-23 14:00:46 +04:00
printk ( KERN_WARNING " Invalid ecc parameters \n " ) ;
BUG ( ) ;
2005-04-17 02:20:36 +04:00
}
2005-11-07 14:15:49 +03:00
2005-04-17 02:20:36 +04:00
/* Initialize state, waitqueue and spinlock */
this - > state = FL_READY ;
2006-05-23 13:37:03 +04:00
init_waitqueue_head ( & this - > controller - > wq ) ;
spin_lock_init ( & this - > controller - > lock ) ;
2005-04-17 02:20:36 +04:00
/* De-select the device */
this - > select_chip ( mtd , - 1 ) ;
/* Invalidate the pagebuffer reference */
this - > pagebuf = - 1 ;
/* Fill in remaining MTD driver data */
mtd - > type = MTD_NANDFLASH ;
2006-05-23 01:18:29 +04:00
mtd - > flags = MTD_CAP_NANDFLASH ;
2005-04-17 02:20:36 +04:00
mtd - > ecctype = MTD_ECC_SW ;
mtd - > erase = nand_erase ;
mtd - > point = NULL ;
mtd - > unpoint = NULL ;
mtd - > read = nand_read ;
mtd - > write = nand_write ;
mtd - > read_ecc = nand_read_ecc ;
mtd - > write_ecc = nand_write_ecc ;
mtd - > read_oob = nand_read_oob ;
mtd - > write_oob = nand_write_oob ;
mtd - > readv = NULL ;
mtd - > writev = nand_writev ;
mtd - > writev_ecc = nand_writev_ecc ;
mtd - > sync = nand_sync ;
mtd - > lock = NULL ;
mtd - > unlock = NULL ;
2005-09-15 17:58:53 +04:00
mtd - > suspend = nand_suspend ;
mtd - > resume = nand_resume ;
2005-04-17 02:20:36 +04:00
mtd - > block_isbad = nand_block_isbad ;
mtd - > block_markbad = nand_block_markbad ;
/* and make the autooob the default one */
memcpy ( & mtd - > oobinfo , this - > autooob , sizeof ( mtd - > oobinfo ) ) ;
2005-02-09 15:20:00 +03:00
/* Check, if we should skip the bad block table scan */
if ( this - > options & NAND_SKIP_BBTSCAN )
return 0 ;
2005-04-17 02:20:36 +04:00
/* Build bad block table */
2006-05-13 21:07:53 +04:00
return this - > scan_bbt ( mtd ) ;
2005-04-17 02:20:36 +04:00
}
/**
2005-11-07 14:15:49 +03:00
* nand_release - [ NAND Interface ] Free resources held by the NAND device
2005-04-17 02:20:36 +04:00
* @ mtd : MTD device structure
*/
2006-05-13 21:07:53 +04:00
void nand_release ( struct mtd_info * mtd )
2005-04-17 02:20:36 +04:00
{
struct nand_chip * this = mtd - > priv ;
# ifdef CONFIG_MTD_PARTITIONS
/* Deregister partitions */
2006-05-13 21:07:53 +04:00
del_mtd_partitions ( mtd ) ;
2005-04-17 02:20:36 +04:00
# endif
/* Deregister the device */
2006-05-13 21:07:53 +04:00
del_mtd_device ( mtd ) ;
2005-04-17 02:20:36 +04:00
2005-11-07 12:01:27 +03:00
/* Free bad block table memory */
2006-05-13 21:07:53 +04:00
kfree ( this - > bbt ) ;
2006-05-23 13:37:03 +04:00
/* Free buffers */
nand_free_kmem ( this ) ;
2005-04-17 02:20:36 +04:00
}
2006-05-13 21:07:53 +04:00
EXPORT_SYMBOL_GPL ( nand_scan ) ;
EXPORT_SYMBOL_GPL ( nand_release ) ;
2006-03-31 14:31:14 +04:00
static int __init nand_base_init ( void )
{
led_trigger_register_simple ( " nand-disk " , & nand_led_trigger ) ;
return 0 ;
}
static void __exit nand_base_exit ( void )
{
led_trigger_unregister_simple ( nand_led_trigger ) ;
}
module_init ( nand_base_init ) ;
module_exit ( nand_base_exit ) ;
2006-05-13 21:07:53 +04:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de> " ) ;
MODULE_DESCRIPTION ( " Generic NAND flash driver code " ) ;