2005-04-17 02:20:36 +04:00
/*
* Linux driver for Disk - On - Chip 2000 and Millennium
* ( c ) 1999 Machine Vision Holdings , Inc .
* ( c ) 1999 , 2000 David Woodhouse < dwmw2 @ infradead . org >
*
2005-11-07 14:15:40 +03:00
* $ Id : doc2000 . c , v 1.67 2005 / 11 / 07 11 : 14 : 24 gleixner Exp $
2005-04-17 02:20:36 +04:00
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <asm/errno.h>
# include <asm/io.h>
# include <asm/uaccess.h>
# include <linux/miscdevice.h>
# include <linux/pci.h>
# include <linux/delay.h>
# include <linux/slab.h>
# include <linux/sched.h>
# include <linux/init.h>
# include <linux/types.h>
# include <linux/bitops.h>
2006-03-31 14:29:40 +04:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
# include <linux/mtd/mtd.h>
# include <linux/mtd/nand.h>
# include <linux/mtd/doc2000.h>
# define DOC_SUPPORT_2000
# define DOC_SUPPORT_2000TSOP
# define DOC_SUPPORT_MILLENNIUM
# ifdef DOC_SUPPORT_2000
# define DoC_is_2000(doc) (doc->ChipID == DOC_ChipID_Doc2k)
# else
# define DoC_is_2000(doc) (0)
# endif
# if defined(DOC_SUPPORT_2000TSOP) || defined(DOC_SUPPORT_MILLENNIUM)
# define DoC_is_Millennium(doc) (doc->ChipID == DOC_ChipID_DocMil)
# else
# define DoC_is_Millennium(doc) (0)
# endif
/* #define ECC_DEBUG */
/* I have no idea why some DoC chips can not use memcpy_from|to_io().
* This may be due to the different revisions of the ASIC controller built - in or
* simplily a QA / Bug issue . Who knows ? ? If you have trouble , please uncomment
* this :
# undef USE_MEMCPY
*/
static int doc_read ( struct mtd_info * mtd , loff_t from , size_t len ,
size_t * retlen , u_char * buf ) ;
static int doc_write ( struct mtd_info * mtd , loff_t to , size_t len ,
size_t * retlen , const u_char * buf ) ;
2006-05-29 05:26:58 +04:00
static int doc_read_oob ( struct mtd_info * mtd , loff_t ofs ,
struct mtd_oob_ops * ops ) ;
static int doc_write_oob ( struct mtd_info * mtd , loff_t ofs ,
struct mtd_oob_ops * ops ) ;
2005-04-17 02:20:36 +04:00
static int doc_write_oob_nolock ( struct mtd_info * mtd , loff_t ofs , size_t len ,
size_t * retlen , const u_char * buf ) ;
static int doc_erase ( struct mtd_info * mtd , struct erase_info * instr ) ;
static struct mtd_info * doc2klist = NULL ;
/* Perform the required delay cycles by reading from the appropriate register */
static void DoC_Delay ( struct DiskOnChip * doc , unsigned short cycles )
{
volatile char dummy ;
int i ;
2005-11-07 14:15:40 +03:00
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < cycles ; i + + ) {
if ( DoC_is_Millennium ( doc ) )
dummy = ReadDOC ( doc - > virtadr , NOP ) ;
else
dummy = ReadDOC ( doc - > virtadr , DOCStatus ) ;
}
2005-11-07 14:15:40 +03:00
2005-04-17 02:20:36 +04:00
}
/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
static int _DoC_WaitReady ( struct DiskOnChip * doc )
{
void __iomem * docptr = doc - > virtadr ;
unsigned long timeo = jiffies + ( HZ * 10 ) ;
DEBUG ( MTD_DEBUG_LEVEL3 ,
" _DoC_WaitReady called for out-of-line wait \n " ) ;
/* Out-of-line routine to wait for chip response */
while ( ! ( ReadDOC ( docptr , CDSNControl ) & CDSN_CTRL_FR_B ) ) {
/* issue 2 read from NOP register after reading from CDSNControl register
see Software Requirement 11.4 item 2. */
DoC_Delay ( doc , 2 ) ;
if ( time_after ( jiffies , timeo ) ) {
DEBUG ( MTD_DEBUG_LEVEL2 , " _DoC_WaitReady timed out. \n " ) ;
return - EIO ;
}
udelay ( 1 ) ;
cond_resched ( ) ;
}
return 0 ;
}
static inline int DoC_WaitReady ( struct DiskOnChip * doc )
{
void __iomem * docptr = doc - > virtadr ;
/* This is inline, to optimise the common case, where it's ready instantly */
int ret = 0 ;
/* 4 read form NOP register should be issued in prior to the read from CDSNControl
see Software Requirement 11.4 item 2. */
DoC_Delay ( doc , 4 ) ;
if ( ! ( ReadDOC ( docptr , CDSNControl ) & CDSN_CTRL_FR_B ) )
/* Call the out-of-line routine to wait */
ret = _DoC_WaitReady ( doc ) ;
/* issue 2 read from NOP register after reading from CDSNControl register
see Software Requirement 11.4 item 2. */
DoC_Delay ( doc , 2 ) ;
return ret ;
}
/* DoC_Command: Send a flash command to the flash chip through the CDSN Slow IO register to
bypass the internal pipeline . Each of 4 delay cycles ( read from the NOP register ) is
required after writing to CDSN Control register , see Software Requirement 11.4 item 3. */
2006-01-15 00:20:43 +03:00
static int DoC_Command ( struct DiskOnChip * doc , unsigned char command ,
2005-04-17 02:20:36 +04:00
unsigned char xtraflags )
{
void __iomem * docptr = doc - > virtadr ;
if ( DoC_is_2000 ( doc ) )
xtraflags | = CDSN_CTRL_FLASH_IO ;
/* Assert the CLE (Command Latch Enable) line to the flash chip */
WriteDOC ( xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE , docptr , CDSNControl ) ;
DoC_Delay ( doc , 4 ) ; /* Software requirement 11.4.3 for Millennium */
if ( DoC_is_Millennium ( doc ) )
WriteDOC ( command , docptr , CDSNSlowIO ) ;
/* Send the command */
WriteDOC_ ( command , docptr , doc - > ioreg ) ;
if ( DoC_is_Millennium ( doc ) )
WriteDOC ( command , docptr , WritePipeTerm ) ;
/* Lower the CLE line */
WriteDOC ( xtraflags | CDSN_CTRL_CE , docptr , CDSNControl ) ;
DoC_Delay ( doc , 4 ) ; /* Software requirement 11.4.3 for Millennium */
/* Wait for the chip to respond - Software requirement 11.4.1 (extended for any command) */
return DoC_WaitReady ( doc ) ;
}
/* DoC_Address: Set the current address for the flash chip through the CDSN Slow IO register to
bypass the internal pipeline . Each of 4 delay cycles ( read from the NOP register ) is
required after writing to CDSN Control register , see Software Requirement 11.4 item 3. */
static int DoC_Address ( struct DiskOnChip * doc , int numbytes , unsigned long ofs ,
unsigned char xtraflags1 , unsigned char xtraflags2 )
{
int i ;
void __iomem * docptr = doc - > virtadr ;
if ( DoC_is_2000 ( doc ) )
xtraflags1 | = CDSN_CTRL_FLASH_IO ;
/* Assert the ALE (Address Latch Enable) line to the flash chip */
WriteDOC ( xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE , docptr , CDSNControl ) ;
DoC_Delay ( doc , 4 ) ; /* Software requirement 11.4.3 for Millennium */
/* Send the address */
/* Devices with 256-byte page are addressed as:
Column ( bits 0 - 7 ) , Page ( bits 8 - 15 , 16 - 23 , 24 - 31 )
* there is no device on the market with page256
and more than 24 bits .
Devices with 512 - byte page are addressed as :
Column ( bits 0 - 7 ) , Page ( bits 9 - 16 , 17 - 24 , 25 - 31 )
* 25 - 31 is sent only if the chip support it .
* bit 8 changes the read command to be sent
( NAND_CMD_READ0 or NAND_CMD_READ1 ) .
*/
if ( numbytes = = ADDR_COLUMN | | numbytes = = ADDR_COLUMN_PAGE ) {
if ( DoC_is_Millennium ( doc ) )
WriteDOC ( ofs & 0xff , docptr , CDSNSlowIO ) ;
WriteDOC_ ( ofs & 0xff , docptr , doc - > ioreg ) ;
}
if ( doc - > page256 ) {
ofs = ofs > > 8 ;
} else {
ofs = ofs > > 9 ;
}
if ( numbytes = = ADDR_PAGE | | numbytes = = ADDR_COLUMN_PAGE ) {
for ( i = 0 ; i < doc - > pageadrlen ; i + + , ofs = ofs > > 8 ) {
if ( DoC_is_Millennium ( doc ) )
WriteDOC ( ofs & 0xff , docptr , CDSNSlowIO ) ;
WriteDOC_ ( ofs & 0xff , docptr , doc - > ioreg ) ;
}
}
if ( DoC_is_Millennium ( doc ) )
WriteDOC ( ofs & 0xff , docptr , WritePipeTerm ) ;
DoC_Delay ( doc , 2 ) ; /* Needed for some slow flash chips. mf. */
2005-11-07 14:15:40 +03:00
/* FIXME: The SlowIO's for millennium could be replaced by
2005-04-17 02:20:36 +04:00
a single WritePipeTerm here . mf . */
/* Lower the ALE line */
WriteDOC ( xtraflags1 | xtraflags2 | CDSN_CTRL_CE , docptr ,
CDSNControl ) ;
DoC_Delay ( doc , 4 ) ; /* Software requirement 11.4.3 for Millennium */
/* Wait for the chip to respond - Software requirement 11.4.1 */
return DoC_WaitReady ( doc ) ;
}
/* Read a buffer from DoC, taking care of Millennium odditys */
static void DoC_ReadBuf ( struct DiskOnChip * doc , u_char * buf , int len )
{
volatile int dummy ;
int modulus = 0xffff ;
void __iomem * docptr = doc - > virtadr ;
int i ;
if ( len < = 0 )
return ;
if ( DoC_is_Millennium ( doc ) ) {
/* Read the data via the internal pipeline through CDSN IO register,
see Pipelined Read Operations 11.3 */
dummy = ReadDOC ( docptr , ReadPipeInit ) ;
/* Millennium should use the LastDataRead register - Pipeline Reads */
len - - ;
/* This is needed for correctly ECC calculation */
modulus = 0xff ;
}
for ( i = 0 ; i < len ; i + + )
buf [ i ] = ReadDOC_ ( docptr , doc - > ioreg + ( i & modulus ) ) ;
if ( DoC_is_Millennium ( doc ) ) {
buf [ i ] = ReadDOC ( docptr , LastDataRead ) ;
}
}
/* Write a buffer to DoC, taking care of Millennium odditys */
static void DoC_WriteBuf ( struct DiskOnChip * doc , const u_char * buf , int len )
{
void __iomem * docptr = doc - > virtadr ;
int i ;
if ( len < = 0 )
return ;
for ( i = 0 ; i < len ; i + + )
WriteDOC_ ( buf [ i ] , docptr , doc - > ioreg + i ) ;
if ( DoC_is_Millennium ( doc ) ) {
WriteDOC ( 0x00 , docptr , WritePipeTerm ) ;
}
}
/* DoC_SelectChip: Select a given flash chip within the current floor */
static inline int DoC_SelectChip ( struct DiskOnChip * doc , int chip )
{
void __iomem * docptr = doc - > virtadr ;
/* Software requirement 11.4.4 before writing DeviceSelect */
/* Deassert the CE line to eliminate glitches on the FCE# outputs */
WriteDOC ( CDSN_CTRL_WP , docptr , CDSNControl ) ;
DoC_Delay ( doc , 4 ) ; /* Software requirement 11.4.3 for Millennium */
/* Select the individual flash chip requested */
WriteDOC ( chip , docptr , CDSNDeviceSelect ) ;
DoC_Delay ( doc , 4 ) ;
/* Reassert the CE line */
WriteDOC ( CDSN_CTRL_CE | CDSN_CTRL_FLASH_IO | CDSN_CTRL_WP , docptr ,
CDSNControl ) ;
DoC_Delay ( doc , 4 ) ; /* Software requirement 11.4.3 for Millennium */
/* Wait for it to be ready */
return DoC_WaitReady ( doc ) ;
}
/* DoC_SelectFloor: Select a given floor (bank of flash chips) */
static inline int DoC_SelectFloor ( struct DiskOnChip * doc , int floor )
{
void __iomem * docptr = doc - > virtadr ;
/* Select the floor (bank) of chips required */
WriteDOC ( floor , docptr , FloorSelect ) ;
/* Wait for the chip to be ready */
return DoC_WaitReady ( doc ) ;
}
/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */
static int DoC_IdentChip ( struct DiskOnChip * doc , int floor , int chip )
{
int mfr , id , i , j ;
volatile char dummy ;
/* Page in the required floor/chip */
DoC_SelectFloor ( doc , floor ) ;
DoC_SelectChip ( doc , chip ) ;
/* Reset the chip */
if ( DoC_Command ( doc , NAND_CMD_RESET , CDSN_CTRL_WP ) ) {
DEBUG ( MTD_DEBUG_LEVEL2 ,
" DoC_Command (reset) for %d,%d returned true \n " ,
floor , chip ) ;
return 0 ;
}
/* Read the NAND chip ID: 1. Send ReadID command */
if ( DoC_Command ( doc , NAND_CMD_READID , CDSN_CTRL_WP ) ) {
DEBUG ( MTD_DEBUG_LEVEL2 ,
" DoC_Command (ReadID) for %d,%d returned true \n " ,
floor , chip ) ;
return 0 ;
}
/* Read the NAND chip ID: 2. Send address byte zero */
DoC_Address ( doc , ADDR_COLUMN , 0 , CDSN_CTRL_WP , 0 ) ;
/* Read the manufacturer and device id codes from the device */
if ( DoC_is_Millennium ( doc ) ) {
DoC_Delay ( doc , 2 ) ;
dummy = ReadDOC ( doc - > virtadr , ReadPipeInit ) ;
mfr = ReadDOC ( doc - > virtadr , LastDataRead ) ;
DoC_Delay ( doc , 2 ) ;
dummy = ReadDOC ( doc - > virtadr , ReadPipeInit ) ;
id = ReadDOC ( doc - > virtadr , LastDataRead ) ;
} else {
/* CDSN Slow IO register see Software Req 11.4 item 5. */
dummy = ReadDOC ( doc - > virtadr , CDSNSlowIO ) ;
DoC_Delay ( doc , 2 ) ;
mfr = ReadDOC_ ( doc - > virtadr , doc - > ioreg ) ;
/* CDSN Slow IO register see Software Req 11.4 item 5. */
dummy = ReadDOC ( doc - > virtadr , CDSNSlowIO ) ;
DoC_Delay ( doc , 2 ) ;
id = ReadDOC_ ( doc - > virtadr , doc - > ioreg ) ;
}
/* No response - return failure */
if ( mfr = = 0xff | | mfr = = 0 )
return 0 ;
2005-11-07 14:15:40 +03:00
/* Check it's the same as the first chip we identified.
2005-04-17 02:20:36 +04:00
* M - Systems say that any given DiskOnChip device should only
2005-11-07 14:15:40 +03:00
* contain _one_ type of flash part , although that ' s not a
2005-04-17 02:20:36 +04:00
* hardware restriction . */
if ( doc - > mfr ) {
if ( doc - > mfr = = mfr & & doc - > id = = id )
return 1 ; /* This is another the same the first */
else
printk ( KERN_WARNING
" Flash chip at floor %d, chip %d is different: \n " ,
floor , chip ) ;
}
/* Print and store the manufacturer and ID codes. */
for ( i = 0 ; nand_flash_ids [ i ] . name ! = NULL ; i + + ) {
if ( id = = nand_flash_ids [ i ] . id ) {
/* Try to identify manufacturer */
for ( j = 0 ; nand_manuf_ids [ j ] . id ! = 0x0 ; j + + ) {
if ( nand_manuf_ids [ j ] . id = = mfr )
break ;
2005-11-07 14:15:40 +03:00
}
2005-04-17 02:20:36 +04:00
printk ( KERN_INFO
" Flash chip found: Manufacturer ID: %2.2X, "
" Chip ID: %2.2X (%s:%s) \n " , mfr , id ,
nand_manuf_ids [ j ] . name , nand_flash_ids [ i ] . name ) ;
if ( ! doc - > mfr ) {
doc - > mfr = mfr ;
doc - > id = id ;
2005-11-07 14:15:40 +03:00
doc - > chipshift =
2005-04-17 02:20:36 +04:00
ffs ( ( nand_flash_ids [ i ] . chipsize < < 20 ) ) - 1 ;
doc - > page256 = ( nand_flash_ids [ i ] . pagesize = = 256 ) ? 1 : 0 ;
doc - > pageadrlen = doc - > chipshift > 25 ? 3 : 2 ;
doc - > erasesize =
nand_flash_ids [ i ] . erasesize ;
return 1 ;
}
return 0 ;
}
}
/* We haven't fully identified the chip. Print as much as we know. */
printk ( KERN_WARNING " Unknown flash chip found: %2.2X %2.2X \n " ,
id , mfr ) ;
printk ( KERN_WARNING " Please report to dwmw2@infradead.org \n " ) ;
return 0 ;
}
/* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */
static void DoC_ScanChips ( struct DiskOnChip * this , int maxchips )
{
int floor , chip ;
int numchips [ MAX_FLOORS ] ;
int ret = 1 ;
this - > numchips = 0 ;
this - > mfr = 0 ;
this - > id = 0 ;
/* For each floor, find the number of valid chips it contains */
for ( floor = 0 ; floor < MAX_FLOORS ; floor + + ) {
ret = 1 ;
numchips [ floor ] = 0 ;
for ( chip = 0 ; chip < maxchips & & ret ! = 0 ; chip + + ) {
ret = DoC_IdentChip ( this , floor , chip ) ;
if ( ret ) {
numchips [ floor ] + + ;
this - > numchips + + ;
}
}
}
/* If there are none at all that we recognise, bail */
if ( ! this - > numchips ) {
printk ( KERN_NOTICE " No flash chips recognised. \n " ) ;
return ;
}
/* Allocate an array to hold the information for each chip */
this - > chips = kmalloc ( sizeof ( struct Nand ) * this - > numchips , GFP_KERNEL ) ;
if ( ! this - > chips ) {
printk ( KERN_NOTICE " No memory for allocating chip info structures \n " ) ;
return ;
}
ret = 0 ;
2005-11-07 14:15:40 +03:00
/* Fill out the chip array with {floor, chipno} for each
2005-04-17 02:20:36 +04:00
* detected chip in the device . */
for ( floor = 0 ; floor < MAX_FLOORS ; floor + + ) {
for ( chip = 0 ; chip < numchips [ floor ] ; chip + + ) {
this - > chips [ ret ] . floor = floor ;
this - > chips [ ret ] . chip = chip ;
this - > chips [ ret ] . curadr = 0 ;
this - > chips [ ret ] . curmode = 0x50 ;
ret + + ;
}
}
/* Calculate and print the total size of the device */
this - > totlen = this - > numchips * ( 1 < < this - > chipshift ) ;
printk ( KERN_INFO " %d flash chips found. Total DiskOnChip size: %ld MiB \n " ,
this - > numchips , this - > totlen > > 20 ) ;
}
static int DoC2k_is_alias ( struct DiskOnChip * doc1 , struct DiskOnChip * doc2 )
{
int tmp1 , tmp2 , retval ;
if ( doc1 - > physadr = = doc2 - > physadr )
return 1 ;
/* Use the alias resolution register which was set aside for this
* purpose . If it ' s value is the same on both chips , they might
* be the same chip , and we write to one and check for a change in
* the other . It ' s unclear if this register is usuable in the
* DoC 2000 ( it ' s in the Millennium docs ) , but it seems to work . */
tmp1 = ReadDOC ( doc1 - > virtadr , AliasResolution ) ;
tmp2 = ReadDOC ( doc2 - > virtadr , AliasResolution ) ;
if ( tmp1 ! = tmp2 )
return 0 ;
WriteDOC ( ( tmp1 + 1 ) % 0xff , doc1 - > virtadr , AliasResolution ) ;
tmp2 = ReadDOC ( doc2 - > virtadr , AliasResolution ) ;
if ( tmp2 = = ( tmp1 + 1 ) % 0xff )
retval = 1 ;
else
retval = 0 ;
/* Restore register contents. May not be necessary, but do it just to
* be safe . */
WriteDOC ( tmp1 , doc1 - > virtadr , AliasResolution ) ;
return retval ;
}
2006-05-08 17:05:05 +04:00
/* This routine is found from the docprobe code by symbol_get(),
* which will bump the use count of this module . */
void DoC2k_init ( struct mtd_info * mtd )
2005-04-17 02:20:36 +04:00
{
struct DiskOnChip * this = mtd - > priv ;
struct DiskOnChip * old = NULL ;
int maxchips ;
/* We must avoid being called twice for the same device. */
if ( doc2klist )
old = doc2klist - > priv ;
while ( old ) {
if ( DoC2k_is_alias ( old , this ) ) {
printk ( KERN_NOTICE
" Ignoring DiskOnChip 2000 at 0x%lX - already configured \n " ,
this - > physadr ) ;
iounmap ( this - > virtadr ) ;
kfree ( mtd ) ;
return ;
}
if ( old - > nextdoc )
old = old - > nextdoc - > priv ;
else
old = NULL ;
}
switch ( this - > ChipID ) {
case DOC_ChipID_Doc2kTSOP :
mtd - > name = " DiskOnChip 2000 TSOP " ;
this - > ioreg = DoC_Mil_CDSN_IO ;
/* Pretend it's a Millennium */
this - > ChipID = DOC_ChipID_DocMil ;
maxchips = MAX_CHIPS ;
break ;
case DOC_ChipID_Doc2k :
mtd - > name = " DiskOnChip 2000 " ;
this - > ioreg = DoC_2k_CDSN_IO ;
maxchips = MAX_CHIPS ;
break ;
case DOC_ChipID_DocMil :
mtd - > name = " DiskOnChip Millennium " ;
this - > ioreg = DoC_Mil_CDSN_IO ;
maxchips = MAX_CHIPS_MIL ;
break ;
default :
printk ( " Unknown ChipID 0x%02x \n " , this - > ChipID ) ;
kfree ( mtd ) ;
iounmap ( this - > virtadr ) ;
return ;
}
printk ( KERN_NOTICE " %s found at address 0x%lX \n " , mtd - > name ,
this - > physadr ) ;
mtd - > type = MTD_NANDFLASH ;
mtd - > flags = MTD_CAP_NANDFLASH ;
mtd - > ecctype = MTD_ECC_RS_DiskOnChip ;
mtd - > size = 0 ;
mtd - > erasesize = 0 ;
2006-05-23 01:18:05 +04:00
mtd - > writesize = 512 ;
2005-04-17 02:20:36 +04:00
mtd - > oobsize = 16 ;
mtd - > owner = THIS_MODULE ;
mtd - > erase = doc_erase ;
mtd - > point = NULL ;
mtd - > unpoint = NULL ;
mtd - > read = doc_read ;
mtd - > write = doc_write ;
mtd - > read_oob = doc_read_oob ;
mtd - > write_oob = doc_write_oob ;
mtd - > sync = NULL ;
this - > totlen = 0 ;
this - > numchips = 0 ;
this - > curfloor = - 1 ;
this - > curchip = - 1 ;
2006-03-31 14:29:41 +04:00
mutex_init ( & this - > lock ) ;
2005-04-17 02:20:36 +04:00
/* Ident all the chips present. */
DoC_ScanChips ( this , maxchips ) ;
if ( ! this - > totlen ) {
kfree ( mtd ) ;
iounmap ( this - > virtadr ) ;
} else {
this - > nextdoc = doc2klist ;
doc2klist = mtd ;
mtd - > size = this - > totlen ;
mtd - > erasesize = this - > erasesize ;
add_mtd_device ( mtd ) ;
return ;
}
}
2006-05-08 17:05:05 +04:00
EXPORT_SYMBOL_GPL ( DoC2k_init ) ;
2005-04-17 02:20:36 +04:00
static int doc_read ( struct mtd_info * mtd , loff_t from , size_t len ,
size_t * retlen , u_char * buf )
{
struct DiskOnChip * this = mtd - > priv ;
void __iomem * docptr = this - > virtadr ;
struct Nand * mychip ;
2006-06-28 12:11:33 +04:00
unsigned char syndrome [ 6 ] , eccbuf [ 6 ] ;
2005-04-17 02:20:36 +04:00
volatile char dummy ;
int i , len256 = 0 , ret = 0 ;
size_t left = len ;
/* Don't allow read past end of device */
if ( from > = this - > totlen )
return - EINVAL ;
2006-03-31 14:29:41 +04:00
mutex_lock ( & this - > lock ) ;
2005-04-17 02:20:36 +04:00
* retlen = 0 ;
while ( left ) {
len = left ;
/* Don't allow a single read to cross a 512-byte block boundary */
if ( from + len > ( ( from | 0x1ff ) + 1 ) )
len = ( ( from | 0x1ff ) + 1 ) - from ;
/* The ECC will not be calculated correctly if less than 512 is read */
if ( len ! = 0x200 & & eccbuf )
printk ( KERN_WARNING
" ECC needs a full sector read (adr: %lx size %lx) \n " ,
( long ) from , ( long ) len ) ;
/* printk("DoC_Read (adr: %lx size %lx)\n", (long) from, (long) len); */
/* Find the chip which is to be used and select it */
mychip = & this - > chips [ from > > ( this - > chipshift ) ] ;
if ( this - > curfloor ! = mychip - > floor ) {
DoC_SelectFloor ( this , mychip - > floor ) ;
DoC_SelectChip ( this , mychip - > chip ) ;
} else if ( this - > curchip ! = mychip - > chip ) {
DoC_SelectChip ( this , mychip - > chip ) ;
}
this - > curfloor = mychip - > floor ;
this - > curchip = mychip - > chip ;
DoC_Command ( this ,
( ! this - > page256
& & ( from & 0x100 ) ) ? NAND_CMD_READ1 : NAND_CMD_READ0 ,
CDSN_CTRL_WP ) ;
DoC_Address ( this , ADDR_COLUMN_PAGE , from , CDSN_CTRL_WP ,
CDSN_CTRL_ECC_IO ) ;
2006-06-28 12:11:33 +04:00
/* Prime the ECC engine */
WriteDOC ( DOC_ECC_RESET , docptr , ECCConf ) ;
WriteDOC ( DOC_ECC_EN , docptr , ECCConf ) ;
2005-04-17 02:20:36 +04:00
/* treat crossing 256-byte sector for 2M x 8bits devices */
if ( this - > page256 & & from + len > ( from | 0xff ) + 1 ) {
len256 = ( from | 0xff ) + 1 - from ;
DoC_ReadBuf ( this , buf , len256 ) ;
DoC_Command ( this , NAND_CMD_READ0 , CDSN_CTRL_WP ) ;
DoC_Address ( this , ADDR_COLUMN_PAGE , from + len256 ,
CDSN_CTRL_WP , CDSN_CTRL_ECC_IO ) ;
}
DoC_ReadBuf ( this , & buf [ len256 ] , len - len256 ) ;
/* Let the caller know we completed it */
* retlen + = len ;
2006-06-28 12:11:33 +04:00
/* Read the ECC data through the DiskOnChip ECC logic */
/* Note: this will work even with 2M x 8bit devices as */
/* they have 8 bytes of OOB per 256 page. mf. */
DoC_ReadBuf ( this , eccbuf , 6 ) ;
/* Flush the pipeline */
if ( DoC_is_Millennium ( this ) ) {
dummy = ReadDOC ( docptr , ECCConf ) ;
dummy = ReadDOC ( docptr , ECCConf ) ;
i = ReadDOC ( docptr , ECCConf ) ;
} else {
dummy = ReadDOC ( docptr , 2 k_ECCStatus ) ;
dummy = ReadDOC ( docptr , 2 k_ECCStatus ) ;
i = ReadDOC ( docptr , 2 k_ECCStatus ) ;
}
2005-04-17 02:20:36 +04:00
2006-06-28 12:11:33 +04:00
/* Check the ECC Status */
if ( i & 0x80 ) {
int nb_errors ;
/* There was an ECC error */
2005-04-17 02:20:36 +04:00
# ifdef ECC_DEBUG
2006-06-28 12:11:33 +04:00
printk ( KERN_ERR " DiskOnChip ECC Error: Read at %lx \n " , ( long ) from ) ;
2005-04-17 02:20:36 +04:00
# endif
2006-06-28 12:11:33 +04:00
/* Read the ECC syndrom through the DiskOnChip ECC
logic . These syndrome will be all ZERO when there
is no error */
for ( i = 0 ; i < 6 ; i + + ) {
syndrome [ i ] =
ReadDOC ( docptr , ECCSyndrome0 + i ) ;
}
nb_errors = doc_decode_ecc ( buf , syndrome ) ;
2005-04-17 02:20:36 +04:00
# ifdef ECC_DEBUG
2006-06-28 12:11:33 +04:00
printk ( KERN_ERR " Errors corrected: %x \n " , nb_errors ) ;
2005-04-17 02:20:36 +04:00
# endif
2006-06-28 12:11:33 +04:00
if ( nb_errors < 0 ) {
/* We return error, but have actually done the
read . Not that this can be told to
user - space , via sys_read ( ) , but at least
MTD - aware stuff can know about it by
checking * retlen */
ret = - EIO ;
2005-04-17 02:20:36 +04:00
}
2006-06-28 12:11:33 +04:00
}
2005-04-17 02:20:36 +04:00
# ifdef PSYCHO_DEBUG
2006-06-28 12:11:33 +04:00
printk ( KERN_DEBUG " ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X \n " ,
( long ) from , eccbuf [ 0 ] , eccbuf [ 1 ] , eccbuf [ 2 ] ,
eccbuf [ 3 ] , eccbuf [ 4 ] , eccbuf [ 5 ] ) ;
2005-04-17 02:20:36 +04:00
# endif
2005-11-07 14:15:40 +03:00
2006-06-28 12:11:33 +04:00
/* disable the ECC engine */
WriteDOC ( DOC_ECC_DIS , docptr , ECCConf ) ;
2005-04-17 02:20:36 +04:00
2005-11-07 14:15:40 +03:00
/* according to 11.4.1, we need to wait for the busy line
2005-04-17 02:20:36 +04:00
* drop if we read to the end of the page . */
if ( 0 = = ( ( from + len ) & 0x1ff ) )
{
DoC_WaitReady ( this ) ;
}
from + = len ;
left - = len ;
buf + = len ;
}
2006-03-31 14:29:41 +04:00
mutex_unlock ( & this - > lock ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
static int doc_write ( struct mtd_info * mtd , loff_t to , size_t len ,
size_t * retlen , const u_char * buf )
{
struct DiskOnChip * this = mtd - > priv ;
int di ; /* Yes, DI is a hangover from when I was disassembling the binary driver */
void __iomem * docptr = this - > virtadr ;
2006-06-28 12:11:33 +04:00
unsigned char eccbuf [ 6 ] ;
2005-04-17 02:20:36 +04:00
volatile char dummy ;
int len256 = 0 ;
struct Nand * mychip ;
size_t left = len ;
int status ;
/* Don't allow write past end of device */
if ( to > = this - > totlen )
return - EINVAL ;
2006-03-31 14:29:41 +04:00
mutex_lock ( & this - > lock ) ;
2005-04-17 02:20:36 +04:00
* retlen = 0 ;
while ( left ) {
len = left ;
/* Don't allow a single write to cross a 512-byte block boundary */
if ( to + len > ( ( to | 0x1ff ) + 1 ) )
len = ( ( to | 0x1ff ) + 1 ) - to ;
/* The ECC will not be calculated correctly if less than 512 is written */
/* DBB-
if ( len ! = 0x200 & & eccbuf )
printk ( KERN_WARNING
" ECC needs a full sector write (adr: %lx size %lx) \n " ,
( long ) to , ( long ) len ) ;
- DBB */
/* printk("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */
/* Find the chip which is to be used and select it */
mychip = & this - > chips [ to > > ( this - > chipshift ) ] ;
if ( this - > curfloor ! = mychip - > floor ) {
DoC_SelectFloor ( this , mychip - > floor ) ;
DoC_SelectChip ( this , mychip - > chip ) ;
} else if ( this - > curchip ! = mychip - > chip ) {
DoC_SelectChip ( this , mychip - > chip ) ;
}
this - > curfloor = mychip - > floor ;
this - > curchip = mychip - > chip ;
/* Set device to main plane of flash */
DoC_Command ( this , NAND_CMD_RESET , CDSN_CTRL_WP ) ;
DoC_Command ( this ,
( ! this - > page256
& & ( to & 0x100 ) ) ? NAND_CMD_READ1 : NAND_CMD_READ0 ,
CDSN_CTRL_WP ) ;
DoC_Command ( this , NAND_CMD_SEQIN , 0 ) ;
DoC_Address ( this , ADDR_COLUMN_PAGE , to , 0 , CDSN_CTRL_ECC_IO ) ;
2006-06-28 12:11:33 +04:00
/* Prime the ECC engine */
WriteDOC ( DOC_ECC_RESET , docptr , ECCConf ) ;
WriteDOC ( DOC_ECC_EN | DOC_ECC_RW , docptr , ECCConf ) ;
2005-04-17 02:20:36 +04:00
/* treat crossing 256-byte sector for 2M x 8bits devices */
if ( this - > page256 & & to + len > ( to | 0xff ) + 1 ) {
len256 = ( to | 0xff ) + 1 - to ;
DoC_WriteBuf ( this , buf , len256 ) ;
DoC_Command ( this , NAND_CMD_PAGEPROG , 0 ) ;
DoC_Command ( this , NAND_CMD_STATUS , CDSN_CTRL_WP ) ;
/* There's an implicit DoC_WaitReady() in DoC_Command */
dummy = ReadDOC ( docptr , CDSNSlowIO ) ;
DoC_Delay ( this , 2 ) ;
if ( ReadDOC_ ( docptr , this - > ioreg ) & 1 ) {
printk ( KERN_ERR " Error programming flash \n " ) ;
/* Error in programming */
* retlen = 0 ;
2006-03-31 14:29:41 +04:00
mutex_unlock ( & this - > lock ) ;
2005-04-17 02:20:36 +04:00
return - EIO ;
}
DoC_Command ( this , NAND_CMD_SEQIN , 0 ) ;
DoC_Address ( this , ADDR_COLUMN_PAGE , to + len256 , 0 ,
CDSN_CTRL_ECC_IO ) ;
}
DoC_WriteBuf ( this , & buf [ len256 ] , len - len256 ) ;
2006-06-28 12:11:33 +04:00
WriteDOC ( CDSN_CTRL_ECC_IO | CDSN_CTRL_CE , docptr , CDSNControl ) ;
2005-04-17 02:20:36 +04:00
2006-06-28 12:11:33 +04:00
if ( DoC_is_Millennium ( this ) ) {
WriteDOC ( 0 , docptr , NOP ) ;
WriteDOC ( 0 , docptr , NOP ) ;
WriteDOC ( 0 , docptr , NOP ) ;
} else {
WriteDOC_ ( 0 , docptr , this - > ioreg ) ;
WriteDOC_ ( 0 , docptr , this - > ioreg ) ;
WriteDOC_ ( 0 , docptr , this - > ioreg ) ;
}
2005-04-17 02:20:36 +04:00
2006-06-28 12:11:33 +04:00
WriteDOC ( CDSN_CTRL_ECC_IO | CDSN_CTRL_FLASH_IO | CDSN_CTRL_CE , docptr ,
CDSNControl ) ;
/* Read the ECC data through the DiskOnChip ECC logic */
for ( di = 0 ; di < 6 ; di + + ) {
eccbuf [ di ] = ReadDOC ( docptr , ECCSyndrome0 + di ) ;
}
2005-04-17 02:20:36 +04:00
2006-06-28 12:11:33 +04:00
/* Reset the ECC engine */
WriteDOC ( DOC_ECC_DIS , docptr , ECCConf ) ;
2005-04-17 02:20:36 +04:00
# ifdef PSYCHO_DEBUG
2006-06-28 12:11:33 +04:00
printk
( " OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X \n " ,
( long ) to , eccbuf [ 0 ] , eccbuf [ 1 ] , eccbuf [ 2 ] , eccbuf [ 3 ] ,
eccbuf [ 4 ] , eccbuf [ 5 ] ) ;
2005-04-17 02:20:36 +04:00
# endif
DoC_Command ( this , NAND_CMD_PAGEPROG , 0 ) ;
DoC_Command ( this , NAND_CMD_STATUS , CDSN_CTRL_WP ) ;
/* There's an implicit DoC_WaitReady() in DoC_Command */
if ( DoC_is_Millennium ( this ) ) {
ReadDOC ( docptr , ReadPipeInit ) ;
status = ReadDOC ( docptr , LastDataRead ) ;
} else {
dummy = ReadDOC ( docptr , CDSNSlowIO ) ;
DoC_Delay ( this , 2 ) ;
status = ReadDOC_ ( docptr , this - > ioreg ) ;
}
if ( status & 1 ) {
printk ( KERN_ERR " Error programming flash \n " ) ;
/* Error in programming */
* retlen = 0 ;
2006-03-31 14:29:41 +04:00
mutex_unlock ( & this - > lock ) ;
2005-04-17 02:20:36 +04:00
return - EIO ;
}
/* Let the caller know we completed it */
* retlen + = len ;
2005-11-07 14:15:40 +03:00
2005-04-17 02:20:36 +04:00
if ( eccbuf ) {
unsigned char x [ 8 ] ;
size_t dummy ;
int ret ;
/* Write the ECC data to flash */
for ( di = 0 ; di < 6 ; di + + )
x [ di ] = eccbuf [ di ] ;
2005-11-07 14:15:40 +03:00
2005-04-17 02:20:36 +04:00
x [ 6 ] = 0x55 ;
x [ 7 ] = 0x55 ;
2005-11-07 14:15:40 +03:00
2005-04-17 02:20:36 +04:00
ret = doc_write_oob_nolock ( mtd , to , 8 , & dummy , x ) ;
if ( ret ) {
2006-03-31 14:29:41 +04:00
mutex_unlock ( & this - > lock ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
}
to + = len ;
left - = len ;
buf + = len ;
}
2006-03-31 14:29:41 +04:00
mutex_unlock ( & this - > lock ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2006-05-29 05:26:58 +04:00
static int doc_read_oob ( struct mtd_info * mtd , loff_t ofs ,
struct mtd_oob_ops * ops )
2005-04-17 02:20:36 +04:00
{
struct DiskOnChip * this = mtd - > priv ;
int len256 = 0 , ret ;
struct Nand * mychip ;
2006-05-29 05:26:58 +04:00
uint8_t * buf = ops - > oobbuf ;
size_t len = ops - > len ;
BUG_ON ( ops - > mode ! = MTD_OOB_PLACE ) ;
ofs + = ops - > ooboffs ;
2005-04-17 02:20:36 +04:00
2006-03-31 14:29:41 +04:00
mutex_lock ( & this - > lock ) ;
2005-04-17 02:20:36 +04:00
mychip = & this - > chips [ ofs > > this - > chipshift ] ;
if ( this - > curfloor ! = mychip - > floor ) {
DoC_SelectFloor ( this , mychip - > floor ) ;
DoC_SelectChip ( this , mychip - > chip ) ;
} else if ( this - > curchip ! = mychip - > chip ) {
DoC_SelectChip ( this , mychip - > chip ) ;
}
this - > curfloor = mychip - > floor ;
this - > curchip = mychip - > chip ;
/* update address for 2M x 8bit devices. OOB starts on the second */
/* page to maintain compatibility with doc_read_ecc. */
if ( this - > page256 ) {
if ( ! ( ofs & 0x8 ) )
ofs + = 0x100 ;
else
ofs - = 0x8 ;
}
DoC_Command ( this , NAND_CMD_READOOB , CDSN_CTRL_WP ) ;
DoC_Address ( this , ADDR_COLUMN_PAGE , ofs , CDSN_CTRL_WP , 0 ) ;
/* treat crossing 8-byte OOB data for 2M x 8bit devices */
/* Note: datasheet says it should automaticaly wrap to the */
/* next OOB block, but it didn't work here. mf. */
if ( this - > page256 & & ofs + len > ( ofs | 0x7 ) + 1 ) {
len256 = ( ofs | 0x7 ) + 1 - ofs ;
DoC_ReadBuf ( this , buf , len256 ) ;
DoC_Command ( this , NAND_CMD_READOOB , CDSN_CTRL_WP ) ;
DoC_Address ( this , ADDR_COLUMN_PAGE , ofs & ( ~ 0x1ff ) ,
CDSN_CTRL_WP , 0 ) ;
}
DoC_ReadBuf ( this , & buf [ len256 ] , len - len256 ) ;
2006-05-29 05:26:58 +04:00
ops - > retlen = len ;
2005-04-17 02:20:36 +04:00
/* Reading the full OOB data drops us off of the end of the page,
* causing the flash device to go into busy mode , so we need
* to wait until ready 11.4 .1 and Toshiba TC58256FT docs */
2005-11-07 14:15:40 +03:00
2005-04-17 02:20:36 +04:00
ret = DoC_WaitReady ( this ) ;
2006-03-31 14:29:41 +04:00
mutex_unlock ( & this - > lock ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
static int doc_write_oob_nolock ( struct mtd_info * mtd , loff_t ofs , size_t len ,
size_t * retlen , const u_char * buf )
{
struct DiskOnChip * this = mtd - > priv ;
int len256 = 0 ;
void __iomem * docptr = this - > virtadr ;
struct Nand * mychip = & this - > chips [ ofs > > this - > chipshift ] ;
volatile int dummy ;
int status ;
// printk("doc_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",(long)ofs, len,
// buf[0], buf[1], buf[2], buf[3], buf[8], buf[9], buf[14],buf[15]);
/* Find the chip which is to be used and select it */
if ( this - > curfloor ! = mychip - > floor ) {
DoC_SelectFloor ( this , mychip - > floor ) ;
DoC_SelectChip ( this , mychip - > chip ) ;
} else if ( this - > curchip ! = mychip - > chip ) {
DoC_SelectChip ( this , mychip - > chip ) ;
}
this - > curfloor = mychip - > floor ;
this - > curchip = mychip - > chip ;
/* disable the ECC engine */
WriteDOC ( DOC_ECC_RESET , docptr , ECCConf ) ;
WriteDOC ( DOC_ECC_DIS , docptr , ECCConf ) ;
/* Reset the chip, see Software Requirement 11.4 item 1. */
DoC_Command ( this , NAND_CMD_RESET , CDSN_CTRL_WP ) ;
/* issue the Read2 command to set the pointer to the Spare Data Area. */
DoC_Command ( this , NAND_CMD_READOOB , CDSN_CTRL_WP ) ;
/* update address for 2M x 8bit devices. OOB starts on the second */
/* page to maintain compatibility with doc_read_ecc. */
if ( this - > page256 ) {
if ( ! ( ofs & 0x8 ) )
ofs + = 0x100 ;
else
ofs - = 0x8 ;
}
/* issue the Serial Data In command to initial the Page Program process */
DoC_Command ( this , NAND_CMD_SEQIN , 0 ) ;
DoC_Address ( this , ADDR_COLUMN_PAGE , ofs , 0 , 0 ) ;
/* treat crossing 8-byte OOB data for 2M x 8bit devices */
/* Note: datasheet says it should automaticaly wrap to the */
/* next OOB block, but it didn't work here. mf. */
if ( this - > page256 & & ofs + len > ( ofs | 0x7 ) + 1 ) {
len256 = ( ofs | 0x7 ) + 1 - ofs ;
DoC_WriteBuf ( this , buf , len256 ) ;
DoC_Command ( this , NAND_CMD_PAGEPROG , 0 ) ;
DoC_Command ( this , NAND_CMD_STATUS , 0 ) ;
/* DoC_WaitReady() is implicit in DoC_Command */
if ( DoC_is_Millennium ( this ) ) {
ReadDOC ( docptr , ReadPipeInit ) ;
status = ReadDOC ( docptr , LastDataRead ) ;
} else {
dummy = ReadDOC ( docptr , CDSNSlowIO ) ;
DoC_Delay ( this , 2 ) ;
status = ReadDOC_ ( docptr , this - > ioreg ) ;
}
if ( status & 1 ) {
printk ( KERN_ERR " Error programming oob data \n " ) ;
/* There was an error */
* retlen = 0 ;
return - EIO ;
}
DoC_Command ( this , NAND_CMD_SEQIN , 0 ) ;
DoC_Address ( this , ADDR_COLUMN_PAGE , ofs & ( ~ 0x1ff ) , 0 , 0 ) ;
}
DoC_WriteBuf ( this , & buf [ len256 ] , len - len256 ) ;
DoC_Command ( this , NAND_CMD_PAGEPROG , 0 ) ;
DoC_Command ( this , NAND_CMD_STATUS , 0 ) ;
/* DoC_WaitReady() is implicit in DoC_Command */
if ( DoC_is_Millennium ( this ) ) {
ReadDOC ( docptr , ReadPipeInit ) ;
status = ReadDOC ( docptr , LastDataRead ) ;
} else {
dummy = ReadDOC ( docptr , CDSNSlowIO ) ;
DoC_Delay ( this , 2 ) ;
status = ReadDOC_ ( docptr , this - > ioreg ) ;
}
if ( status & 1 ) {
printk ( KERN_ERR " Error programming oob data \n " ) ;
/* There was an error */
* retlen = 0 ;
return - EIO ;
}
* retlen = len ;
return 0 ;
}
2005-11-07 14:15:40 +03:00
2006-05-29 05:26:58 +04:00
static int doc_write_oob ( struct mtd_info * mtd , loff_t ofs ,
struct mtd_oob_ops * ops )
2005-04-17 02:20:36 +04:00
{
2006-05-29 05:26:58 +04:00
struct DiskOnChip * this = mtd - > priv ;
int ret ;
2005-04-17 02:20:36 +04:00
2006-05-29 05:26:58 +04:00
BUG_ON ( ops - > mode ! = MTD_OOB_PLACE ) ;
2005-04-17 02:20:36 +04:00
2006-05-29 05:26:58 +04:00
mutex_lock ( & this - > lock ) ;
ret = doc_write_oob_nolock ( mtd , ofs + ops - > ooboffs , ops - > len ,
& ops - > retlen , ops - > oobbuf ) ;
mutex_unlock ( & this - > lock ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
static int doc_erase ( struct mtd_info * mtd , struct erase_info * instr )
{
struct DiskOnChip * this = mtd - > priv ;
__u32 ofs = instr - > addr ;
__u32 len = instr - > len ;
volatile int dummy ;
void __iomem * docptr = this - > virtadr ;
struct Nand * mychip ;
int status ;
2006-03-31 14:29:41 +04:00
mutex_lock ( & this - > lock ) ;
2005-04-17 02:20:36 +04:00
if ( ofs & ( mtd - > erasesize - 1 ) | | len & ( mtd - > erasesize - 1 ) ) {
2006-03-31 14:29:41 +04:00
mutex_unlock ( & this - > lock ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
instr - > state = MTD_ERASING ;
2005-11-07 14:15:40 +03:00
2005-04-17 02:20:36 +04:00
/* FIXME: Do this in the background. Use timers or schedule_task() */
while ( len ) {
mychip = & this - > chips [ ofs > > this - > chipshift ] ;
if ( this - > curfloor ! = mychip - > floor ) {
DoC_SelectFloor ( this , mychip - > floor ) ;
DoC_SelectChip ( this , mychip - > chip ) ;
} else if ( this - > curchip ! = mychip - > chip ) {
DoC_SelectChip ( this , mychip - > chip ) ;
}
this - > curfloor = mychip - > floor ;
this - > curchip = mychip - > chip ;
DoC_Command ( this , NAND_CMD_ERASE1 , 0 ) ;
DoC_Address ( this , ADDR_PAGE , ofs , 0 , 0 ) ;
DoC_Command ( this , NAND_CMD_ERASE2 , 0 ) ;
DoC_Command ( this , NAND_CMD_STATUS , CDSN_CTRL_WP ) ;
if ( DoC_is_Millennium ( this ) ) {
ReadDOC ( docptr , ReadPipeInit ) ;
status = ReadDOC ( docptr , LastDataRead ) ;
} else {
dummy = ReadDOC ( docptr , CDSNSlowIO ) ;
DoC_Delay ( this , 2 ) ;
status = ReadDOC_ ( docptr , this - > ioreg ) ;
}
if ( status & 1 ) {
printk ( KERN_ERR " Error erasing at 0x%x \n " , ofs ) ;
/* There was an error */
instr - > state = MTD_ERASE_FAILED ;
goto callback ;
}
ofs + = mtd - > erasesize ;
len - = mtd - > erasesize ;
}
instr - > state = MTD_ERASE_DONE ;
callback :
mtd_erase_callback ( instr ) ;
2006-03-31 14:29:41 +04:00
mutex_unlock ( & this - > lock ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/****************************************************************************
*
* Module stuff
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void __exit cleanup_doc2000 ( void )
{
struct mtd_info * mtd ;
struct DiskOnChip * this ;
while ( ( mtd = doc2klist ) ) {
this = mtd - > priv ;
doc2klist = this - > nextdoc ;
del_mtd_device ( mtd ) ;
iounmap ( this - > virtadr ) ;
kfree ( this - > chips ) ;
kfree ( mtd ) ;
}
}
module_exit ( cleanup_doc2000 ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " David Woodhouse <dwmw2@infradead.org> et al. " ) ;
MODULE_DESCRIPTION ( " MTD driver for DiskOnChip 2000 and Millennium " ) ;