2008-02-07 00:36:21 +03:00
/* Freescale Enhanced Local Bus Controller NAND driver
*
2010-10-18 11:22:31 +04:00
* Copyright © 2006 - 2007 , 2010 Freescale Semiconductor
2008-02-07 00:36:21 +03:00
*
* Authors : Nick Spence < nick . spence @ freescale . com > ,
* Scott Wood < scottwood @ freescale . com >
2010-10-18 11:22:31 +04:00
* Jack Lan < jack . lan @ freescale . com >
* Roy Zang < tie - fei . zang @ freescale . com >
2008-02-07 00:36:21 +03:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/module.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/string.h>
# include <linux/ioport.h>
2013-09-17 23:28:33 +04:00
# include <linux/of_address.h>
2008-02-07 00:36:21 +03:00
# include <linux/of_platform.h>
2010-10-18 11:22:31 +04:00
# include <linux/platform_device.h>
2008-02-07 00:36:21 +03:00
# include <linux/slab.h>
# include <linux/interrupt.h>
# include <linux/mtd/mtd.h>
# include <linux/mtd/nand.h>
# include <linux/mtd/nand_ecc.h>
# include <linux/mtd/partitions.h>
# include <asm/io.h>
2008-03-11 20:23:28 +03:00
# include <asm/fsl_lbc.h>
2008-02-07 00:36:21 +03:00
# define MAX_BANKS 8
# define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */
# define FCM_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait for FCM */
/* mtd information per set */
struct fsl_elbc_mtd {
struct nand_chip chip ;
2010-10-18 11:22:31 +04:00
struct fsl_lbc_ctrl * ctrl ;
2008-02-07 00:36:21 +03:00
struct device * dev ;
int bank ; /* Chip select bank number */
u8 __iomem * vbase ; /* Chip select base virtual address */
int page_size ; /* NAND page size (0=512, 1=2048) */
unsigned int fmr ; /* FCM Flash Mode Register value */
} ;
2011-03-31 05:57:33 +04:00
/* Freescale eLBC FCM controller information */
2008-02-07 00:36:21 +03:00
2010-10-18 11:22:31 +04:00
struct fsl_elbc_fcm_ctrl {
2008-02-07 00:36:21 +03:00
struct nand_hw_control controller ;
struct fsl_elbc_mtd * chips [ MAX_BANKS ] ;
u8 __iomem * addr ; /* Address of assigned FCM buffer */
unsigned int page ; /* Last page written to / read from */
unsigned int read_bytes ; /* Number of bytes read during command */
unsigned int column ; /* Saved column from SEQIN */
unsigned int index ; /* Pointer to next byte to 'read' */
unsigned int status ; /* status read from LTESR after last op */
unsigned int mdr ; /* UPM/FCM Data Register value */
unsigned int use_mdr ; /* Non zero if the MDR is to be set */
unsigned int oob ; /* Non zero if operating on OOB data */
2010-10-18 11:22:31 +04:00
unsigned int counter ; /* counter for the initializations */
2012-04-25 23:06:09 +04:00
unsigned int max_bitflips ; /* Saved during READ0 cmd */
2008-02-07 00:36:21 +03:00
} ;
/* These map to the positions used by the FCM hardware ECC generator */
2016-02-03 22:01:04 +03:00
static int fsl_elbc_ooblayout_ecc ( struct mtd_info * mtd , int section ,
struct mtd_oob_region * oobregion )
{
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
struct fsl_elbc_mtd * priv = nand_get_controller_data ( chip ) ;
2008-02-07 00:36:21 +03:00
2016-02-03 22:01:04 +03:00
if ( section > = chip - > ecc . steps )
return - ERANGE ;
2008-02-07 00:36:21 +03:00
2016-02-03 22:01:04 +03:00
oobregion - > offset = ( 16 * section ) + 6 ;
if ( priv - > fmr & FMR_ECCM )
oobregion - > offset + = 2 ;
2008-02-07 00:36:21 +03:00
2016-02-03 22:01:04 +03:00
oobregion - > length = chip - > ecc . bytes ;
return 0 ;
}
static int fsl_elbc_ooblayout_free ( struct mtd_info * mtd , int section ,
struct mtd_oob_region * oobregion )
{
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
struct fsl_elbc_mtd * priv = nand_get_controller_data ( chip ) ;
if ( section > chip - > ecc . steps )
return - ERANGE ;
if ( ! section ) {
oobregion - > offset = 0 ;
if ( mtd - > writesize > 512 )
oobregion - > offset + + ;
oobregion - > length = ( priv - > fmr & FMR_ECCM ) ? 7 : 5 ;
} else {
oobregion - > offset = ( 16 * section ) -
( ( priv - > fmr & FMR_ECCM ) ? 5 : 7 ) ;
if ( section < chip - > ecc . steps )
oobregion - > length = 13 ;
else
oobregion - > length = mtd - > oobsize - oobregion - > offset ;
}
return 0 ;
}
static const struct mtd_ooblayout_ops fsl_elbc_ooblayout_ops = {
. ecc = fsl_elbc_ooblayout_ecc ,
. free = fsl_elbc_ooblayout_free ,
2008-02-07 00:36:21 +03:00
} ;
2008-06-27 23:04:13 +04:00
/*
* ELBC may use HW ECC , so that OOB offsets , that NAND core uses for bbt ,
* interfere with ECC positions , that ' s why we implement our own descriptors .
* OOB { 11 , 5 } , works for both SP and LP chips , with ECCM = 1 and ECCM = 0.
*/
static u8 bbt_pattern [ ] = { ' B ' , ' b ' , ' t ' , ' 0 ' } ;
static u8 mirror_pattern [ ] = { ' 1 ' , ' t ' , ' b ' , ' B ' } ;
static struct nand_bbt_descr bbt_main_descr = {
. options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
NAND_BBT_2BIT | NAND_BBT_VERSION ,
. offs = 11 ,
. len = 4 ,
. veroffs = 15 ,
. maxblocks = 4 ,
. pattern = bbt_pattern ,
} ;
static struct nand_bbt_descr bbt_mirror_descr = {
. options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
NAND_BBT_2BIT | NAND_BBT_VERSION ,
. offs = 11 ,
. len = 4 ,
. veroffs = 15 ,
. maxblocks = 4 ,
. pattern = mirror_pattern ,
} ;
2008-02-07 00:36:21 +03:00
/*=================================*/
/*
* Set up the FCM hardware block and page address fields , and the fcm
* structure addr field to point to the correct FCM buffer in memory
*/
static void set_addr ( struct mtd_info * mtd , int column , int page_addr , int oob )
{
2015-12-01 14:03:04 +03:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2015-12-10 11:00:41 +03:00
struct fsl_elbc_mtd * priv = nand_get_controller_data ( chip ) ;
2010-10-18 11:22:31 +04:00
struct fsl_lbc_ctrl * ctrl = priv - > ctrl ;
2008-03-11 20:23:28 +03:00
struct fsl_lbc_regs __iomem * lbc = ctrl - > regs ;
2010-10-18 11:22:31 +04:00
struct fsl_elbc_fcm_ctrl * elbc_fcm_ctrl = ctrl - > nand ;
2008-02-07 00:36:21 +03:00
int buf_num ;
2010-10-18 11:22:31 +04:00
elbc_fcm_ctrl - > page = page_addr ;
2008-02-07 00:36:21 +03:00
if ( priv - > page_size ) {
2011-12-09 13:42:54 +04:00
/*
* large page size chip : FPAR [ PI ] save the lowest 6 bits ,
* FBAR [ BLK ] save the other bits .
*/
out_be32 ( & lbc - > fbar , page_addr > > 6 ) ;
2008-02-07 00:36:21 +03:00
out_be32 ( & lbc - > fpar ,
( ( page_addr < < FPAR_LP_PI_SHIFT ) & FPAR_LP_PI ) |
( oob ? FPAR_LP_MS : 0 ) | column ) ;
buf_num = ( page_addr & 1 ) < < 2 ;
} else {
2011-12-09 13:42:54 +04:00
/*
* small page size chip : FPAR [ PI ] save the lowest 5 bits ,
* FBAR [ BLK ] save the other bits .
*/
out_be32 ( & lbc - > fbar , page_addr > > 5 ) ;
2008-02-07 00:36:21 +03:00
out_be32 ( & lbc - > fpar ,
( ( page_addr < < FPAR_SP_PI_SHIFT ) & FPAR_SP_PI ) |
( oob ? FPAR_SP_MS : 0 ) | column ) ;
buf_num = page_addr & 7 ;
}
2010-10-18 11:22:31 +04:00
elbc_fcm_ctrl - > addr = priv - > vbase + buf_num * 1024 ;
elbc_fcm_ctrl - > index = column ;
2008-02-07 00:36:21 +03:00
/* for OOB data point to the second half of the buffer */
if ( oob )
2010-10-18 11:22:31 +04:00
elbc_fcm_ctrl - > index + = priv - > page_size ? 2048 : 512 ;
2008-02-07 00:36:21 +03:00
2010-10-18 11:22:31 +04:00
dev_vdbg ( priv - > dev , " set_addr: bank=%d, "
" elbc_fcm_ctrl->addr=0x%p (0x%p), "
2008-02-07 00:36:21 +03:00
" index %x, pes %d ps %d \n " ,
2010-10-18 11:22:31 +04:00
buf_num , elbc_fcm_ctrl - > addr , priv - > vbase ,
elbc_fcm_ctrl - > index ,
2008-02-07 00:36:21 +03:00
chip - > phys_erase_shift , chip - > page_shift ) ;
}
/*
* execute FCM command and wait for it to complete
*/
static int fsl_elbc_run_command ( struct mtd_info * mtd )
{
2015-12-01 14:03:04 +03:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2015-12-10 11:00:41 +03:00
struct fsl_elbc_mtd * priv = nand_get_controller_data ( chip ) ;
2010-10-18 11:22:31 +04:00
struct fsl_lbc_ctrl * ctrl = priv - > ctrl ;
struct fsl_elbc_fcm_ctrl * elbc_fcm_ctrl = ctrl - > nand ;
2008-03-11 20:23:28 +03:00
struct fsl_lbc_regs __iomem * lbc = ctrl - > regs ;
2008-02-07 00:36:21 +03:00
/* Setup the FMR[OP] to execute without write protection */
out_be32 ( & lbc - > fmr , priv - > fmr | 3 ) ;
2010-10-18 11:22:31 +04:00
if ( elbc_fcm_ctrl - > use_mdr )
out_be32 ( & lbc - > mdr , elbc_fcm_ctrl - > mdr ) ;
2008-02-07 00:36:21 +03:00
2010-10-18 11:22:31 +04:00
dev_vdbg ( priv - > dev ,
2008-02-07 00:36:21 +03:00
" fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x \n " ,
in_be32 ( & lbc - > fmr ) , in_be32 ( & lbc - > fir ) , in_be32 ( & lbc - > fcr ) ) ;
2010-10-18 11:22:31 +04:00
dev_vdbg ( priv - > dev ,
2008-02-07 00:36:21 +03:00
" fsl_elbc_run_command: fbar=%08x fpar=%08x "
" fbcr=%08x bank=%d \n " ,
in_be32 ( & lbc - > fbar ) , in_be32 ( & lbc - > fpar ) ,
in_be32 ( & lbc - > fbcr ) , priv - > bank ) ;
2008-03-19 20:40:15 +03:00
ctrl - > irq_status = 0 ;
2008-02-07 00:36:21 +03:00
/* execute special operation */
out_be32 ( & lbc - > lsor , priv - > bank ) ;
/* wait for FCM complete flag or timeout */
wait_event_timeout ( ctrl - > irq_wait , ctrl - > irq_status ,
FCM_TIMEOUT_MSECS * HZ / 1000 ) ;
2010-10-18 11:22:31 +04:00
elbc_fcm_ctrl - > status = ctrl - > irq_status ;
2008-02-07 00:36:21 +03:00
/* store mdr value in case it was needed */
2010-10-18 11:22:31 +04:00
if ( elbc_fcm_ctrl - > use_mdr )
elbc_fcm_ctrl - > mdr = in_be32 ( & lbc - > mdr ) ;
2008-02-07 00:36:21 +03:00
2010-10-18 11:22:31 +04:00
elbc_fcm_ctrl - > use_mdr = 0 ;
2008-02-07 00:36:21 +03:00
2010-10-18 11:22:31 +04:00
if ( elbc_fcm_ctrl - > status ! = LTESR_CC ) {
dev_info ( priv - > dev ,
2009-11-13 23:14:15 +03:00
" command failed: fir %x fcr %x status %x mdr %x \n " ,
in_be32 ( & lbc - > fir ) , in_be32 ( & lbc - > fcr ) ,
2010-10-18 11:22:31 +04:00
elbc_fcm_ctrl - > status , elbc_fcm_ctrl - > mdr ) ;
2009-11-13 23:14:15 +03:00
return - EIO ;
}
2008-02-07 00:36:21 +03:00
2011-07-27 00:07:42 +04:00
if ( chip - > ecc . mode ! = NAND_ECC_HW )
return 0 ;
2012-04-25 23:06:09 +04:00
elbc_fcm_ctrl - > max_bitflips = 0 ;
2011-07-27 00:07:42 +04:00
if ( elbc_fcm_ctrl - > read_bytes = = mtd - > writesize + mtd - > oobsize ) {
uint32_t lteccr = in_be32 ( & lbc - > lteccr ) ;
/*
* if command was a full page read and the ELBC
* has the LTECCR register , then bits 12 - 15 ( ppc order ) of
* LTECCR indicates which 512 byte sub - pages had fixed errors .
* bits 28 - 31 are uncorrectable errors , marked elsewhere .
* for small page nand only 1 bit is used .
* if the ELBC doesn ' t have the lteccr register it reads 0
2012-04-25 23:06:09 +04:00
* FIXME : 4 bits can be corrected on NANDs with 2 k pages , so
* count the number of sub - pages with bitflips and update
* ecc_stats . corrected accordingly .
2011-07-27 00:07:42 +04:00
*/
if ( lteccr & 0x000F000F )
out_be32 ( & lbc - > lteccr , 0x000F000F ) ; /* clear lteccr */
2012-04-25 23:06:09 +04:00
if ( lteccr & 0x000F0000 ) {
2011-07-27 00:07:42 +04:00
mtd - > ecc_stats . corrected + + ;
2012-04-25 23:06:09 +04:00
elbc_fcm_ctrl - > max_bitflips = 1 ;
}
2011-07-27 00:07:42 +04:00
}
2009-11-13 23:14:15 +03:00
return 0 ;
2008-02-07 00:36:21 +03:00
}
static void fsl_elbc_do_read ( struct nand_chip * chip , int oob )
{
2015-12-10 11:00:41 +03:00
struct fsl_elbc_mtd * priv = nand_get_controller_data ( chip ) ;
2010-10-18 11:22:31 +04:00
struct fsl_lbc_ctrl * ctrl = priv - > ctrl ;
2008-03-11 20:23:28 +03:00
struct fsl_lbc_regs __iomem * lbc = ctrl - > regs ;
2008-02-07 00:36:21 +03:00
if ( priv - > page_size ) {
out_be32 ( & lbc - > fir ,
2009-11-13 23:13:01 +03:00
( FIR_OP_CM0 < < FIR_OP0_SHIFT ) |
2008-02-07 00:36:21 +03:00
( FIR_OP_CA < < FIR_OP1_SHIFT ) |
( FIR_OP_PA < < FIR_OP2_SHIFT ) |
2009-11-13 23:13:01 +03:00
( FIR_OP_CM1 < < FIR_OP3_SHIFT ) |
2008-02-07 00:36:21 +03:00
( FIR_OP_RBW < < FIR_OP4_SHIFT ) ) ;
out_be32 ( & lbc - > fcr , ( NAND_CMD_READ0 < < FCR_CMD0_SHIFT ) |
( NAND_CMD_READSTART < < FCR_CMD1_SHIFT ) ) ;
} else {
out_be32 ( & lbc - > fir ,
2009-11-13 23:13:01 +03:00
( FIR_OP_CM0 < < FIR_OP0_SHIFT ) |
2008-02-07 00:36:21 +03:00
( FIR_OP_CA < < FIR_OP1_SHIFT ) |
( FIR_OP_PA < < FIR_OP2_SHIFT ) |
( FIR_OP_RBW < < FIR_OP3_SHIFT ) ) ;
if ( oob )
out_be32 ( & lbc - > fcr , NAND_CMD_READOOB < < FCR_CMD0_SHIFT ) ;
else
out_be32 ( & lbc - > fcr , NAND_CMD_READ0 < < FCR_CMD0_SHIFT ) ;
}
}
/* cmdfunc send commands to the FCM */
static void fsl_elbc_cmdfunc ( struct mtd_info * mtd , unsigned int command ,
int column , int page_addr )
{
2015-12-01 14:03:04 +03:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2015-12-10 11:00:41 +03:00
struct fsl_elbc_mtd * priv = nand_get_controller_data ( chip ) ;
2010-10-18 11:22:31 +04:00
struct fsl_lbc_ctrl * ctrl = priv - > ctrl ;
struct fsl_elbc_fcm_ctrl * elbc_fcm_ctrl = ctrl - > nand ;
2008-03-11 20:23:28 +03:00
struct fsl_lbc_regs __iomem * lbc = ctrl - > regs ;
2008-02-07 00:36:21 +03:00
2010-10-18 11:22:31 +04:00
elbc_fcm_ctrl - > use_mdr = 0 ;
2008-02-07 00:36:21 +03:00
/* clear the read buffer */
2010-10-18 11:22:31 +04:00
elbc_fcm_ctrl - > read_bytes = 0 ;
2008-02-07 00:36:21 +03:00
if ( command ! = NAND_CMD_PAGEPROG )
2010-10-18 11:22:31 +04:00
elbc_fcm_ctrl - > index = 0 ;
2008-02-07 00:36:21 +03:00
switch ( command ) {
/* READ0 and READ1 read the entire buffer to use hardware ECC. */
case NAND_CMD_READ1 :
column + = 256 ;
/* fall-through */
case NAND_CMD_READ0 :
2010-10-18 11:22:31 +04:00
dev_dbg ( priv - > dev ,
2008-02-07 00:36:21 +03:00
" fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr: "
" 0x%x, column: 0x%x. \n " , page_addr , column ) ;
out_be32 ( & lbc - > fbcr , 0 ) ; /* read entire page to enable ECC */
set_addr ( mtd , 0 , page_addr , 0 ) ;
2010-10-18 11:22:31 +04:00
elbc_fcm_ctrl - > read_bytes = mtd - > writesize + mtd - > oobsize ;
elbc_fcm_ctrl - > index + = column ;
2008-02-07 00:36:21 +03:00
fsl_elbc_do_read ( chip , 0 ) ;
fsl_elbc_run_command ( mtd ) ;
return ;
/* READOOB reads only the OOB because no ECC is performed. */
case NAND_CMD_READOOB :
2010-10-18 11:22:31 +04:00
dev_vdbg ( priv - > dev ,
2008-02-07 00:36:21 +03:00
" fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr: "
" 0x%x, column: 0x%x. \n " , page_addr , column ) ;
out_be32 ( & lbc - > fbcr , mtd - > oobsize - column ) ;
set_addr ( mtd , column , page_addr , 1 ) ;
2010-10-18 11:22:31 +04:00
elbc_fcm_ctrl - > read_bytes = mtd - > writesize + mtd - > oobsize ;
2008-02-07 00:36:21 +03:00
fsl_elbc_do_read ( chip , 1 ) ;
fsl_elbc_run_command ( mtd ) ;
return ;
case NAND_CMD_READID :
2011-12-12 13:40:53 +04:00
case NAND_CMD_PARAM :
dev_vdbg ( priv - > dev , " fsl_elbc_cmdfunc: NAND_CMD %x \n " , command ) ;
2008-02-07 00:36:21 +03:00
2009-11-13 23:13:01 +03:00
out_be32 ( & lbc - > fir , ( FIR_OP_CM0 < < FIR_OP0_SHIFT ) |
2008-02-07 00:36:21 +03:00
( FIR_OP_UA < < FIR_OP1_SHIFT ) |
( FIR_OP_RBW < < FIR_OP2_SHIFT ) ) ;
2011-12-12 13:40:53 +04:00
out_be32 ( & lbc - > fcr , command < < FCR_CMD0_SHIFT ) ;
/*
* although currently it ' s 8 bytes for READID , we always read
* the maximum 256 bytes ( for PARAM )
*/
out_be32 ( & lbc - > fbcr , 256 ) ;
elbc_fcm_ctrl - > read_bytes = 256 ;
2010-10-18 11:22:31 +04:00
elbc_fcm_ctrl - > use_mdr = 1 ;
2011-12-12 13:40:53 +04:00
elbc_fcm_ctrl - > mdr = column ;
2008-02-07 00:36:21 +03:00
set_addr ( mtd , 0 , 0 , 0 ) ;
fsl_elbc_run_command ( mtd ) ;
return ;
/* ERASE1 stores the block and page address */
case NAND_CMD_ERASE1 :
2010-10-18 11:22:31 +04:00
dev_vdbg ( priv - > dev ,
2008-02-07 00:36:21 +03:00
" fsl_elbc_cmdfunc: NAND_CMD_ERASE1, "
" page_addr: 0x%x. \n " , page_addr ) ;
set_addr ( mtd , 0 , page_addr , 0 ) ;
return ;
/* ERASE2 uses the block and page address from ERASE1 */
case NAND_CMD_ERASE2 :
2010-10-18 11:22:31 +04:00
dev_vdbg ( priv - > dev , " fsl_elbc_cmdfunc: NAND_CMD_ERASE2. \n " ) ;
2008-02-07 00:36:21 +03:00
out_be32 ( & lbc - > fir ,
2009-11-13 23:13:01 +03:00
( FIR_OP_CM0 < < FIR_OP0_SHIFT ) |
2008-02-07 00:36:21 +03:00
( FIR_OP_PA < < FIR_OP1_SHIFT ) |
2009-11-13 23:13:01 +03:00
( FIR_OP_CM2 < < FIR_OP2_SHIFT ) |
( FIR_OP_CW1 < < FIR_OP3_SHIFT ) |
( FIR_OP_RS < < FIR_OP4_SHIFT ) ) ;
2008-02-07 00:36:21 +03:00
out_be32 ( & lbc - > fcr ,
( NAND_CMD_ERASE1 < < FCR_CMD0_SHIFT ) |
2009-11-13 23:13:01 +03:00
( NAND_CMD_STATUS < < FCR_CMD1_SHIFT ) |
( NAND_CMD_ERASE2 < < FCR_CMD2_SHIFT ) ) ;
2008-02-07 00:36:21 +03:00
out_be32 ( & lbc - > fbcr , 0 ) ;
2010-10-18 11:22:31 +04:00
elbc_fcm_ctrl - > read_bytes = 0 ;
elbc_fcm_ctrl - > use_mdr = 1 ;
2008-02-07 00:36:21 +03:00
fsl_elbc_run_command ( mtd ) ;
return ;
/* SEQIN sets up the addr buffer and all registers except the length */
case NAND_CMD_SEQIN : {
__be32 fcr ;
2010-10-18 11:22:31 +04:00
dev_vdbg ( priv - > dev ,
" fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, "
2008-02-07 00:36:21 +03:00
" page_addr: 0x%x, column: 0x%x. \n " ,
page_addr , column ) ;
2010-11-23 20:38:36 +03:00
elbc_fcm_ctrl - > column = column ;
2010-10-18 11:22:31 +04:00
elbc_fcm_ctrl - > use_mdr = 1 ;
2008-02-07 00:36:21 +03:00
2011-12-04 08:31:36 +04:00
if ( column > = mtd - > writesize ) {
/* OOB area */
column - = mtd - > writesize ;
elbc_fcm_ctrl - > oob = 1 ;
} else {
WARN_ON ( column ! = 0 ) ;
elbc_fcm_ctrl - > oob = 0 ;
}
2009-11-13 23:13:01 +03:00
fcr = ( NAND_CMD_STATUS < < FCR_CMD1_SHIFT ) |
( NAND_CMD_SEQIN < < FCR_CMD2_SHIFT ) |
( NAND_CMD_PAGEPROG < < FCR_CMD3_SHIFT ) ;
2008-04-05 02:06:05 +04:00
2009-11-13 23:13:01 +03:00
if ( priv - > page_size ) {
2008-02-07 00:36:21 +03:00
out_be32 ( & lbc - > fir ,
2009-11-13 23:13:01 +03:00
( FIR_OP_CM2 < < FIR_OP0_SHIFT ) |
2008-02-07 00:36:21 +03:00
( FIR_OP_CA < < FIR_OP1_SHIFT ) |
( FIR_OP_PA < < FIR_OP2_SHIFT ) |
( FIR_OP_WB < < FIR_OP3_SHIFT ) |
2009-11-13 23:13:01 +03:00
( FIR_OP_CM3 < < FIR_OP4_SHIFT ) |
( FIR_OP_CW1 < < FIR_OP5_SHIFT ) |
( FIR_OP_RS < < FIR_OP6_SHIFT ) ) ;
2008-02-07 00:36:21 +03:00
} else {
out_be32 ( & lbc - > fir ,
2009-11-13 23:13:01 +03:00
( FIR_OP_CM0 < < FIR_OP0_SHIFT ) |
2008-02-07 00:36:21 +03:00
( FIR_OP_CM2 < < FIR_OP1_SHIFT ) |
( FIR_OP_CA < < FIR_OP2_SHIFT ) |
( FIR_OP_PA < < FIR_OP3_SHIFT ) |
( FIR_OP_WB < < FIR_OP4_SHIFT ) |
2009-11-13 23:13:01 +03:00
( FIR_OP_CM3 < < FIR_OP5_SHIFT ) |
( FIR_OP_CW1 < < FIR_OP6_SHIFT ) |
( FIR_OP_RS < < FIR_OP7_SHIFT ) ) ;
2008-02-07 00:36:21 +03:00
2011-12-04 08:31:36 +04:00
if ( elbc_fcm_ctrl - > oob )
2008-02-07 00:36:21 +03:00
/* OOB area --> READOOB */
fcr | = NAND_CMD_READOOB < < FCR_CMD0_SHIFT ;
2011-12-04 08:31:36 +04:00
else
2008-02-07 00:36:21 +03:00
/* First 256 bytes --> READ0 */
fcr | = NAND_CMD_READ0 < < FCR_CMD0_SHIFT ;
}
out_be32 ( & lbc - > fcr , fcr ) ;
2010-10-18 11:22:31 +04:00
set_addr ( mtd , column , page_addr , elbc_fcm_ctrl - > oob ) ;
2008-02-07 00:36:21 +03:00
return ;
}
/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
case NAND_CMD_PAGEPROG : {
2010-10-18 11:22:31 +04:00
dev_vdbg ( priv - > dev ,
2008-02-07 00:36:21 +03:00
" fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "
2010-10-18 11:22:31 +04:00
" writing %d bytes. \n " , elbc_fcm_ctrl - > index ) ;
2008-02-07 00:36:21 +03:00
/* if the write did not start at 0 or is not a full page
* then set the exact length , otherwise use a full page
* write so the HW generates the ECC .
*/
2010-10-18 11:22:31 +04:00
if ( elbc_fcm_ctrl - > oob | | elbc_fcm_ctrl - > column ! = 0 | |
2011-07-06 03:14:48 +04:00
elbc_fcm_ctrl - > index ! = mtd - > writesize + mtd - > oobsize )
2011-12-04 08:31:37 +04:00
out_be32 ( & lbc - > fbcr ,
elbc_fcm_ctrl - > index - elbc_fcm_ctrl - > column ) ;
2011-07-06 03:14:48 +04:00
else
2008-02-07 00:36:21 +03:00
out_be32 ( & lbc - > fbcr , 0 ) ;
fsl_elbc_run_command ( mtd ) ;
return ;
}
/* CMD_STATUS must read the status byte while CEB is active */
/* Note - it does not wait for the ready line */
case NAND_CMD_STATUS :
out_be32 ( & lbc - > fir ,
( FIR_OP_CM0 < < FIR_OP0_SHIFT ) |
( FIR_OP_RBW < < FIR_OP1_SHIFT ) ) ;
out_be32 ( & lbc - > fcr , NAND_CMD_STATUS < < FCR_CMD0_SHIFT ) ;
out_be32 ( & lbc - > fbcr , 1 ) ;
set_addr ( mtd , 0 , 0 , 0 ) ;
2010-10-18 11:22:31 +04:00
elbc_fcm_ctrl - > read_bytes = 1 ;
2008-02-07 00:36:21 +03:00
fsl_elbc_run_command ( mtd ) ;
/* The chip always seems to report that it is
* write - protected , even when it is not .
*/
2010-10-18 11:22:31 +04:00
setbits8 ( elbc_fcm_ctrl - > addr , NAND_STATUS_WP ) ;
2008-02-07 00:36:21 +03:00
return ;
/* RESET without waiting for the ready line */
case NAND_CMD_RESET :
2010-10-18 11:22:31 +04:00
dev_dbg ( priv - > dev , " fsl_elbc_cmdfunc: NAND_CMD_RESET. \n " ) ;
2008-02-07 00:36:21 +03:00
out_be32 ( & lbc - > fir , FIR_OP_CM0 < < FIR_OP0_SHIFT ) ;
out_be32 ( & lbc - > fcr , NAND_CMD_RESET < < FCR_CMD0_SHIFT ) ;
fsl_elbc_run_command ( mtd ) ;
return ;
default :
2010-10-18 11:22:31 +04:00
dev_err ( priv - > dev ,
2008-02-07 00:36:21 +03:00
" fsl_elbc_cmdfunc: error, unsupported command 0x%x. \n " ,
command ) ;
}
}
static void fsl_elbc_select_chip ( struct mtd_info * mtd , int chip )
{
/* The hardware does not seem to support multiple
* chips per bank .
*/
}
/*
* Write buf to the FCM Controller Data Buffer
*/
static void fsl_elbc_write_buf ( struct mtd_info * mtd , const u8 * buf , int len )
{
2015-12-01 14:03:04 +03:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2015-12-10 11:00:41 +03:00
struct fsl_elbc_mtd * priv = nand_get_controller_data ( chip ) ;
2010-10-18 11:22:31 +04:00
struct fsl_elbc_fcm_ctrl * elbc_fcm_ctrl = priv - > ctrl - > nand ;
2008-02-07 00:36:21 +03:00
unsigned int bufsize = mtd - > writesize + mtd - > oobsize ;
2008-03-28 22:10:54 +03:00
if ( len < = 0 ) {
2010-10-18 11:22:31 +04:00
dev_err ( priv - > dev , " write_buf of %d bytes " , len ) ;
elbc_fcm_ctrl - > status = 0 ;
2008-02-07 00:36:21 +03:00
return ;
}
2010-10-18 11:22:31 +04:00
if ( ( unsigned int ) len > bufsize - elbc_fcm_ctrl - > index ) {
dev_err ( priv - > dev ,
2008-02-07 00:36:21 +03:00
" write_buf beyond end of buffer "
" (%d requested, %u available) \n " ,
2010-10-18 11:22:31 +04:00
len , bufsize - elbc_fcm_ctrl - > index ) ;
len = bufsize - elbc_fcm_ctrl - > index ;
2008-02-07 00:36:21 +03:00
}
2010-10-18 11:22:31 +04:00
memcpy_toio ( & elbc_fcm_ctrl - > addr [ elbc_fcm_ctrl - > index ] , buf , len ) ;
2008-03-28 22:10:54 +03:00
/*
* This is workaround for the weird elbc hangs during nand write ,
* Scott Wood says : " ...perhaps difference in how long it takes a
* write to make it through the localbus compared to a write to IMMR
* is causing problems , and sync isn ' t helping for some reason . "
* Reading back the last byte helps though .
*/
2010-10-18 11:22:31 +04:00
in_8 ( & elbc_fcm_ctrl - > addr [ elbc_fcm_ctrl - > index ] + len - 1 ) ;
2008-03-28 22:10:54 +03:00
2010-10-18 11:22:31 +04:00
elbc_fcm_ctrl - > index + = len ;
2008-02-07 00:36:21 +03:00
}
/*
* read a byte from either the FCM hardware buffer if it has any data left
* otherwise issue a command to read a single byte .
*/
static u8 fsl_elbc_read_byte ( struct mtd_info * mtd )
{
2015-12-01 14:03:04 +03:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2015-12-10 11:00:41 +03:00
struct fsl_elbc_mtd * priv = nand_get_controller_data ( chip ) ;
2010-10-18 11:22:31 +04:00
struct fsl_elbc_fcm_ctrl * elbc_fcm_ctrl = priv - > ctrl - > nand ;
2008-02-07 00:36:21 +03:00
/* If there are still bytes in the FCM, then use the next byte. */
2010-10-18 11:22:31 +04:00
if ( elbc_fcm_ctrl - > index < elbc_fcm_ctrl - > read_bytes )
return in_8 ( & elbc_fcm_ctrl - > addr [ elbc_fcm_ctrl - > index + + ] ) ;
2008-02-07 00:36:21 +03:00
2010-10-18 11:22:31 +04:00
dev_err ( priv - > dev , " read_byte beyond end of buffer \n " ) ;
2008-02-07 00:36:21 +03:00
return ERR_BYTE ;
}
/*
* Read from the FCM Controller Data Buffer
*/
static void fsl_elbc_read_buf ( struct mtd_info * mtd , u8 * buf , int len )
{
2015-12-01 14:03:04 +03:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2015-12-10 11:00:41 +03:00
struct fsl_elbc_mtd * priv = nand_get_controller_data ( chip ) ;
2010-10-18 11:22:31 +04:00
struct fsl_elbc_fcm_ctrl * elbc_fcm_ctrl = priv - > ctrl - > nand ;
2008-02-07 00:36:21 +03:00
int avail ;
if ( len < 0 )
return ;
2010-10-18 11:22:31 +04:00
avail = min ( ( unsigned int ) len ,
elbc_fcm_ctrl - > read_bytes - elbc_fcm_ctrl - > index ) ;
memcpy_fromio ( buf , & elbc_fcm_ctrl - > addr [ elbc_fcm_ctrl - > index ] , avail ) ;
elbc_fcm_ctrl - > index + = avail ;
2008-02-07 00:36:21 +03:00
if ( len > avail )
2010-10-18 11:22:31 +04:00
dev_err ( priv - > dev ,
2008-02-07 00:36:21 +03:00
" read_buf beyond end of buffer "
" (%d requested, %d available) \n " ,
len , avail ) ;
}
/* This function is called after Program and Erase Operations to
* check for success or failure .
*/
static int fsl_elbc_wait ( struct mtd_info * mtd , struct nand_chip * chip )
{
2015-12-10 11:00:41 +03:00
struct fsl_elbc_mtd * priv = nand_get_controller_data ( chip ) ;
2010-10-18 11:22:31 +04:00
struct fsl_elbc_fcm_ctrl * elbc_fcm_ctrl = priv - > ctrl - > nand ;
2008-02-07 00:36:21 +03:00
2010-10-18 11:22:31 +04:00
if ( elbc_fcm_ctrl - > status ! = LTESR_CC )
2008-02-07 00:36:21 +03:00
return NAND_STATUS_FAIL ;
/* The chip always seems to report that it is
* write - protected , even when it is not .
*/
2010-10-18 11:22:31 +04:00
return ( elbc_fcm_ctrl - > mdr & 0xff ) | NAND_STATUS_WP ;
2008-02-07 00:36:21 +03:00
}
static int fsl_elbc_chip_init_tail ( struct mtd_info * mtd )
{
2015-12-01 14:03:04 +03:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2015-12-10 11:00:41 +03:00
struct fsl_elbc_mtd * priv = nand_get_controller_data ( chip ) ;
2010-10-18 11:22:31 +04:00
struct fsl_lbc_ctrl * ctrl = priv - > ctrl ;
2008-03-11 20:23:28 +03:00
struct fsl_lbc_regs __iomem * lbc = ctrl - > regs ;
2008-02-07 00:36:21 +03:00
unsigned int al ;
/* calculate FMR Address Length field */
al = 0 ;
if ( chip - > pagemask & 0xffff0000 )
al + + ;
if ( chip - > pagemask & 0xff000000 )
al + + ;
2011-12-12 13:40:52 +04:00
priv - > fmr | = al < < FMR_AL_SHIFT ;
2008-02-07 00:36:21 +03:00
2010-10-18 11:22:31 +04:00
dev_dbg ( priv - > dev , " fsl_elbc_init: nand->numchips = %d \n " ,
2008-02-07 00:36:21 +03:00
chip - > numchips ) ;
2010-10-18 11:22:31 +04:00
dev_dbg ( priv - > dev , " fsl_elbc_init: nand->chipsize = %lld \n " ,
2008-02-07 00:36:21 +03:00
chip - > chipsize ) ;
2010-10-18 11:22:31 +04:00
dev_dbg ( priv - > dev , " fsl_elbc_init: nand->pagemask = %8x \n " ,
2008-02-07 00:36:21 +03:00
chip - > pagemask ) ;
2010-10-18 11:22:31 +04:00
dev_dbg ( priv - > dev , " fsl_elbc_init: nand->chip_delay = %d \n " ,
2008-02-07 00:36:21 +03:00
chip - > chip_delay ) ;
2010-10-18 11:22:31 +04:00
dev_dbg ( priv - > dev , " fsl_elbc_init: nand->badblockpos = %d \n " ,
2008-02-07 00:36:21 +03:00
chip - > badblockpos ) ;
2010-10-18 11:22:31 +04:00
dev_dbg ( priv - > dev , " fsl_elbc_init: nand->chip_shift = %d \n " ,
2008-02-07 00:36:21 +03:00
chip - > chip_shift ) ;
2010-10-18 11:22:31 +04:00
dev_dbg ( priv - > dev , " fsl_elbc_init: nand->page_shift = %d \n " ,
2008-02-07 00:36:21 +03:00
chip - > page_shift ) ;
2010-10-18 11:22:31 +04:00
dev_dbg ( priv - > dev , " fsl_elbc_init: nand->phys_erase_shift = %d \n " ,
2008-02-07 00:36:21 +03:00
chip - > phys_erase_shift ) ;
2010-10-18 11:22:31 +04:00
dev_dbg ( priv - > dev , " fsl_elbc_init: nand->ecc.mode = %d \n " ,
2008-02-07 00:36:21 +03:00
chip - > ecc . mode ) ;
2010-10-18 11:22:31 +04:00
dev_dbg ( priv - > dev , " fsl_elbc_init: nand->ecc.steps = %d \n " ,
2008-02-07 00:36:21 +03:00
chip - > ecc . steps ) ;
2010-10-18 11:22:31 +04:00
dev_dbg ( priv - > dev , " fsl_elbc_init: nand->ecc.bytes = %d \n " ,
2008-02-07 00:36:21 +03:00
chip - > ecc . bytes ) ;
2010-10-18 11:22:31 +04:00
dev_dbg ( priv - > dev , " fsl_elbc_init: nand->ecc.total = %d \n " ,
2008-02-07 00:36:21 +03:00
chip - > ecc . total ) ;
2016-02-03 22:01:04 +03:00
dev_dbg ( priv - > dev , " fsl_elbc_init: mtd->ooblayout = %p \n " ,
mtd - > ooblayout ) ;
2010-10-18 11:22:31 +04:00
dev_dbg ( priv - > dev , " fsl_elbc_init: mtd->flags = %08x \n " , mtd - > flags ) ;
dev_dbg ( priv - > dev , " fsl_elbc_init: mtd->size = %lld \n " , mtd - > size ) ;
dev_dbg ( priv - > dev , " fsl_elbc_init: mtd->erasesize = %d \n " ,
2008-02-07 00:36:21 +03:00
mtd - > erasesize ) ;
2010-10-18 11:22:31 +04:00
dev_dbg ( priv - > dev , " fsl_elbc_init: mtd->writesize = %d \n " ,
2008-02-07 00:36:21 +03:00
mtd - > writesize ) ;
2010-10-18 11:22:31 +04:00
dev_dbg ( priv - > dev , " fsl_elbc_init: mtd->oobsize = %d \n " ,
2008-02-07 00:36:21 +03:00
mtd - > oobsize ) ;
/* adjust Option Register and ECC to match Flash page size */
if ( mtd - > writesize = = 512 ) {
priv - > page_size = 0 ;
2008-03-19 20:40:15 +03:00
clrbits32 ( & lbc - > bank [ priv - > bank ] . or , OR_FCM_PGS ) ;
2008-02-07 00:36:21 +03:00
} else if ( mtd - > writesize = = 2048 ) {
priv - > page_size = 1 ;
setbits32 ( & lbc - > bank [ priv - > bank ] . or , OR_FCM_PGS ) ;
} else {
2010-10-18 11:22:31 +04:00
dev_err ( priv - > dev ,
2008-02-07 00:36:21 +03:00
" fsl_elbc_init: page size %d is not supported \n " ,
mtd - > writesize ) ;
return - 1 ;
}
return 0 ;
}
2012-05-02 21:14:55 +04:00
static int fsl_elbc_read_page ( struct mtd_info * mtd , struct nand_chip * chip ,
uint8_t * buf , int oob_required , int page )
2008-02-07 00:36:21 +03:00
{
2015-12-10 11:00:41 +03:00
struct fsl_elbc_mtd * priv = nand_get_controller_data ( chip ) ;
2012-04-25 23:06:09 +04:00
struct fsl_lbc_ctrl * ctrl = priv - > ctrl ;
struct fsl_elbc_fcm_ctrl * elbc_fcm_ctrl = ctrl - > nand ;
2008-02-07 00:36:21 +03:00
fsl_elbc_read_buf ( mtd , buf , mtd - > writesize ) ;
2012-05-02 21:15:00 +04:00
if ( oob_required )
fsl_elbc_read_buf ( mtd , chip - > oob_poi , mtd - > oobsize ) ;
2008-02-07 00:36:21 +03:00
if ( fsl_elbc_wait ( mtd , chip ) & NAND_STATUS_FAIL )
mtd - > ecc_stats . failed + + ;
2012-04-25 23:06:09 +04:00
return elbc_fcm_ctrl - > max_bitflips ;
2008-02-07 00:36:21 +03:00
}
/* ECC will be calculated automatically, and errors will be detected in
* waitfunc .
*/
2012-06-25 14:07:45 +04:00
static int fsl_elbc_write_page ( struct mtd_info * mtd , struct nand_chip * chip ,
2015-10-13 12:22:18 +03:00
const uint8_t * buf , int oob_required , int page )
2008-02-07 00:36:21 +03:00
{
fsl_elbc_write_buf ( mtd , buf , mtd - > writesize ) ;
fsl_elbc_write_buf ( mtd , chip - > oob_poi , mtd - > oobsize ) ;
2012-06-25 14:07:45 +04:00
return 0 ;
2008-02-07 00:36:21 +03:00
}
2014-05-06 08:11:32 +04:00
/* ECC will be calculated automatically, and errors will be detected in
* waitfunc .
*/
static int fsl_elbc_write_subpage ( struct mtd_info * mtd , struct nand_chip * chip ,
uint32_t offset , uint32_t data_len ,
2015-10-13 12:22:18 +03:00
const uint8_t * buf , int oob_required , int page )
2014-05-06 08:11:32 +04:00
{
fsl_elbc_write_buf ( mtd , buf , mtd - > writesize ) ;
fsl_elbc_write_buf ( mtd , chip - > oob_poi , mtd - > oobsize ) ;
return 0 ;
}
2008-02-07 00:36:21 +03:00
static int fsl_elbc_chip_init ( struct fsl_elbc_mtd * priv )
{
2010-10-18 11:22:31 +04:00
struct fsl_lbc_ctrl * ctrl = priv - > ctrl ;
2008-03-11 20:23:28 +03:00
struct fsl_lbc_regs __iomem * lbc = ctrl - > regs ;
2010-10-18 11:22:31 +04:00
struct fsl_elbc_fcm_ctrl * elbc_fcm_ctrl = ctrl - > nand ;
2008-02-07 00:36:21 +03:00
struct nand_chip * chip = & priv - > chip ;
2015-12-10 11:00:02 +03:00
struct mtd_info * mtd = nand_to_mtd ( chip ) ;
2008-02-07 00:36:21 +03:00
dev_dbg ( priv - > dev , " eLBC Set Information for bank %d \n " , priv - > bank ) ;
/* Fill in fsl_elbc_mtd structure */
2015-12-10 11:00:02 +03:00
mtd - > dev . parent = priv - > dev ;
2015-10-31 06:33:25 +03:00
nand_set_flash_node ( chip , priv - > dev - > of_node ) ;
2008-12-09 09:32:31 +03:00
2011-12-12 13:40:52 +04:00
/* set timeout to maximum */
priv - > fmr = 15 < < FMR_CWTO_SHIFT ;
if ( in_be32 ( & lbc - > bank [ priv - > bank ] . or ) & OR_FCM_PGS )
priv - > fmr | = FMR_ECCM ;
2008-02-07 00:36:21 +03:00
/* fill in nand_chip structure */
/* set up function call table */
chip - > read_byte = fsl_elbc_read_byte ;
chip - > write_buf = fsl_elbc_write_buf ;
chip - > read_buf = fsl_elbc_read_buf ;
chip - > select_chip = fsl_elbc_select_chip ;
chip - > cmdfunc = fsl_elbc_cmdfunc ;
chip - > waitfunc = fsl_elbc_wait ;
2008-06-27 23:04:13 +04:00
chip - > bbt_td = & bbt_main_descr ;
chip - > bbt_md = & bbt_mirror_descr ;
2008-02-07 00:36:21 +03:00
/* set up nand options */
2011-06-01 03:31:23 +04:00
chip - > bbt_options = NAND_BBT_USE_FLASH ;
2008-02-07 00:36:21 +03:00
2010-10-18 11:22:31 +04:00
chip - > controller = & elbc_fcm_ctrl - > controller ;
2015-12-10 11:00:41 +03:00
nand_set_controller_data ( chip , priv ) ;
2008-02-07 00:36:21 +03:00
chip - > ecc . read_page = fsl_elbc_read_page ;
chip - > ecc . write_page = fsl_elbc_write_page ;
2014-05-06 08:11:32 +04:00
chip - > ecc . write_subpage = fsl_elbc_write_subpage ;
2008-02-07 00:36:21 +03:00
/* If CS Base Register selects full hardware ECC then use it */
if ( ( in_be32 ( & lbc - > bank [ priv - > bank ] . br ) & BR_DECC ) = =
BR_DECC_CHK_GEN ) {
chip - > ecc . mode = NAND_ECC_HW ;
2016-02-03 22:01:04 +03:00
mtd_set_ooblayout ( mtd , & fsl_elbc_ooblayout_ops ) ;
2008-02-07 00:36:21 +03:00
chip - > ecc . size = 512 ;
chip - > ecc . bytes = 3 ;
2012-03-12 01:21:11 +04:00
chip - > ecc . strength = 1 ;
2008-02-07 00:36:21 +03:00
} else {
/* otherwise fall back to default software ECC */
chip - > ecc . mode = NAND_ECC_SOFT ;
2016-04-13 15:07:02 +03:00
chip - > ecc . algo = NAND_ECC_HAMMING ;
2008-02-07 00:36:21 +03:00
}
return 0 ;
}
static int fsl_elbc_chip_remove ( struct fsl_elbc_mtd * priv )
{
2010-10-18 11:22:31 +04:00
struct fsl_elbc_fcm_ctrl * elbc_fcm_ctrl = priv - > ctrl - > nand ;
2015-12-10 11:00:02 +03:00
struct mtd_info * mtd = nand_to_mtd ( & priv - > chip ) ;
2008-02-07 00:36:21 +03:00
2015-12-10 11:00:02 +03:00
nand_release ( mtd ) ;
kfree ( mtd - > name ) ;
[MTD] [NAND] fsl_elbc_nand: fix mtd name
Currently fsl_elbc_nand doesn't initialize mtd->name, and this causes
nand_get_flash_type() to assign name that is equal to chip type, like
this:
root@b1:~# cat /proc/mtd
dev: size erasesize name
mtd0: 00800000 00010000 "fe000000.flash"
mtd1: 02000000 00004000 "NAND 32MiB 3,3V 8-bit"
mtd0 is physmap_of flash (normal name), and mtd1 is fsl_elbc_nand.
Despite inconsistency, with mtd name like this specifying paritions
from the kernel command line becomes a torture (though, I didn't tried
and not sure if mtdparts= can handle spaces at all). Plus, this causes
real bugs when multiple fsl_elbc_nand chips registered.
With this patch applied fsl_elbc_nand chip will have proper name:
root@b1:~# cat /proc/mtd
dev: size erasesize name
mtd0: 00800000 00010000 "fe000000.flash"
mtd1: 02000000 00004000 "e0600000.flash"
p.s. We can't use priv->dev->bus_id as in physmap_of, because
fsl_elbc_nand pretends to be a localbus controller, so its bus_id is
"address.localbus", which is incorrect and thus will also not work
for multiple chips.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
2008-03-18 19:34:03 +03:00
2008-02-07 00:36:21 +03:00
if ( priv - > vbase )
iounmap ( priv - > vbase ) ;
2010-10-18 11:22:31 +04:00
elbc_fcm_ctrl - > chips [ priv - > bank ] = NULL ;
2008-02-07 00:36:21 +03:00
kfree ( priv ) ;
return 0 ;
}
2010-10-18 11:22:31 +04:00
static DEFINE_MUTEX ( fsl_elbc_nand_mutex ) ;
2012-11-19 22:23:07 +04:00
static int fsl_elbc_nand_probe ( struct platform_device * pdev )
2008-02-07 00:36:21 +03:00
{
2010-10-18 11:22:31 +04:00
struct fsl_lbc_regs __iomem * lbc ;
2008-02-07 00:36:21 +03:00
struct fsl_elbc_mtd * priv ;
struct resource res ;
2010-10-18 11:22:31 +04:00
struct fsl_elbc_fcm_ctrl * elbc_fcm_ctrl ;
2008-02-07 00:36:21 +03:00
static const char * part_probe_types [ ]
2011-05-30 01:02:22 +04:00
= { " cmdlinepart " , " RedBoot " , " ofpart " , NULL } ;
2008-02-07 00:36:21 +03:00
int ret ;
int bank ;
2010-10-18 11:22:31 +04:00
struct device * dev ;
struct device_node * node = pdev - > dev . of_node ;
2015-12-10 11:00:02 +03:00
struct mtd_info * mtd ;
2010-10-18 11:22:31 +04:00
if ( ! fsl_lbc_ctrl_dev | | ! fsl_lbc_ctrl_dev - > regs )
return - ENODEV ;
lbc = fsl_lbc_ctrl_dev - > regs ;
dev = fsl_lbc_ctrl_dev - > dev ;
2008-02-07 00:36:21 +03:00
/* get, allocate and map the memory resource */
ret = of_address_to_resource ( node , 0 , & res ) ;
if ( ret ) {
2010-10-18 11:22:31 +04:00
dev_err ( dev , " failed to get resource \n " ) ;
2008-02-07 00:36:21 +03:00
return ret ;
}
/* find which chip select it is connected to */
for ( bank = 0 ; bank < MAX_BANKS ; bank + + )
if ( ( in_be32 ( & lbc - > bank [ bank ] . br ) & BR_V ) & &
( in_be32 ( & lbc - > bank [ bank ] . br ) & BR_MSEL ) = = BR_MS_FCM & &
( in_be32 ( & lbc - > bank [ bank ] . br ) &
in_be32 ( & lbc - > bank [ bank ] . or ) & BR_BA )
2010-10-18 11:22:32 +04:00
= = fsl_lbc_addr ( res . start ) )
2008-02-07 00:36:21 +03:00
break ;
if ( bank > = MAX_BANKS ) {
2010-10-18 11:22:31 +04:00
dev_err ( dev , " address did not match any chip selects \n " ) ;
2008-02-07 00:36:21 +03:00
return - ENODEV ;
}
priv = kzalloc ( sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
2010-10-18 11:22:31 +04:00
mutex_lock ( & fsl_elbc_nand_mutex ) ;
if ( ! fsl_lbc_ctrl_dev - > nand ) {
elbc_fcm_ctrl = kzalloc ( sizeof ( * elbc_fcm_ctrl ) , GFP_KERNEL ) ;
if ( ! elbc_fcm_ctrl ) {
mutex_unlock ( & fsl_elbc_nand_mutex ) ;
ret = - ENOMEM ;
goto err ;
}
elbc_fcm_ctrl - > counter + + ;
2016-07-27 12:23:52 +03:00
nand_hw_control_init ( & elbc_fcm_ctrl - > controller ) ;
2010-10-18 11:22:31 +04:00
fsl_lbc_ctrl_dev - > nand = elbc_fcm_ctrl ;
} else {
elbc_fcm_ctrl = fsl_lbc_ctrl_dev - > nand ;
}
mutex_unlock ( & fsl_elbc_nand_mutex ) ;
elbc_fcm_ctrl - > chips [ bank ] = priv ;
2008-02-07 00:36:21 +03:00
priv - > bank = bank ;
2010-10-18 11:22:31 +04:00
priv - > ctrl = fsl_lbc_ctrl_dev ;
2012-06-07 03:36:39 +04:00
priv - > dev = & pdev - > dev ;
dev_set_drvdata ( priv - > dev , priv ) ;
2008-02-07 00:36:21 +03:00
2009-12-15 00:19:44 +03:00
priv - > vbase = ioremap ( res . start , resource_size ( & res ) ) ;
2008-02-07 00:36:21 +03:00
if ( ! priv - > vbase ) {
2010-10-18 11:22:31 +04:00
dev_err ( dev , " failed to map chip region \n " ) ;
2008-02-07 00:36:21 +03:00
ret = - ENOMEM ;
goto err ;
}
2015-12-10 11:00:02 +03:00
mtd = nand_to_mtd ( & priv - > chip ) ;
mtd - > name = kasprintf ( GFP_KERNEL , " %llx.flash " , ( u64 ) res . start ) ;
if ( ! nand_to_mtd ( & priv - > chip ) - > name ) {
[MTD] [NAND] fsl_elbc_nand: fix mtd name
Currently fsl_elbc_nand doesn't initialize mtd->name, and this causes
nand_get_flash_type() to assign name that is equal to chip type, like
this:
root@b1:~# cat /proc/mtd
dev: size erasesize name
mtd0: 00800000 00010000 "fe000000.flash"
mtd1: 02000000 00004000 "NAND 32MiB 3,3V 8-bit"
mtd0 is physmap_of flash (normal name), and mtd1 is fsl_elbc_nand.
Despite inconsistency, with mtd name like this specifying paritions
from the kernel command line becomes a torture (though, I didn't tried
and not sure if mtdparts= can handle spaces at all). Plus, this causes
real bugs when multiple fsl_elbc_nand chips registered.
With this patch applied fsl_elbc_nand chip will have proper name:
root@b1:~# cat /proc/mtd
dev: size erasesize name
mtd0: 00800000 00010000 "fe000000.flash"
mtd1: 02000000 00004000 "e0600000.flash"
p.s. We can't use priv->dev->bus_id as in physmap_of, because
fsl_elbc_nand pretends to be a localbus controller, so its bus_id is
"address.localbus", which is incorrect and thus will also not work
for multiple chips.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
2008-03-18 19:34:03 +03:00
ret = - ENOMEM ;
goto err ;
}
2008-02-07 00:36:21 +03:00
ret = fsl_elbc_chip_init ( priv ) ;
if ( ret )
goto err ;
2015-12-10 11:00:02 +03:00
ret = nand_scan_ident ( mtd , 1 , NULL ) ;
2008-02-07 00:36:21 +03:00
if ( ret )
goto err ;
2015-12-10 11:00:02 +03:00
ret = fsl_elbc_chip_init_tail ( mtd ) ;
2008-02-07 00:36:21 +03:00
if ( ret )
goto err ;
2015-12-10 11:00:02 +03:00
ret = nand_scan_tail ( mtd ) ;
2008-02-07 00:36:21 +03:00
if ( ret )
goto err ;
/* First look for RedBoot table or partitions on the command
* line , these take precedence over device tree information */
2015-12-10 11:00:02 +03:00
mtd_device_parse_register ( mtd , part_probe_types , NULL ,
2011-06-02 18:00:36 +04:00
NULL , 0 ) ;
2008-02-07 00:36:21 +03:00
2009-01-21 16:16:28 +03:00
printk ( KERN_INFO " eLBC NAND device at 0x%llx, bank %d \n " ,
( unsigned long long ) res . start , priv - > bank ) ;
2008-02-07 00:36:21 +03:00
return 0 ;
err :
fsl_elbc_chip_remove ( priv ) ;
return ret ;
}
2010-10-18 11:22:31 +04:00
static int fsl_elbc_nand_remove ( struct platform_device * pdev )
2008-02-07 00:36:21 +03:00
{
2010-10-18 11:22:31 +04:00
struct fsl_elbc_fcm_ctrl * elbc_fcm_ctrl = fsl_lbc_ctrl_dev - > nand ;
2012-06-07 03:36:39 +04:00
struct fsl_elbc_mtd * priv = dev_get_drvdata ( & pdev - > dev ) ;
fsl_elbc_chip_remove ( priv ) ;
2010-10-18 11:22:31 +04:00
mutex_lock ( & fsl_elbc_nand_mutex ) ;
elbc_fcm_ctrl - > counter - - ;
if ( ! elbc_fcm_ctrl - > counter ) {
fsl_lbc_ctrl_dev - > nand = NULL ;
kfree ( elbc_fcm_ctrl ) ;
2008-02-07 00:36:21 +03:00
}
2010-10-18 11:22:31 +04:00
mutex_unlock ( & fsl_elbc_nand_mutex ) ;
2008-02-07 00:36:21 +03:00
return 0 ;
}
2010-10-18 11:22:31 +04:00
static const struct of_device_id fsl_elbc_nand_match [ ] = {
{ . compatible = " fsl,elbc-fcm-nand " , } ,
2008-02-07 00:36:21 +03:00
{ }
} ;
2015-09-18 01:11:59 +03:00
MODULE_DEVICE_TABLE ( of , fsl_elbc_nand_match ) ;
2008-02-07 00:36:21 +03:00
2010-10-18 11:22:31 +04:00
static struct platform_driver fsl_elbc_nand_driver = {
2008-02-07 00:36:21 +03:00
. driver = {
2010-10-18 11:22:31 +04:00
. name = " fsl,elbc-fcm-nand " ,
. of_match_table = fsl_elbc_nand_match ,
2008-02-07 00:36:21 +03:00
} ,
2010-10-18 11:22:31 +04:00
. probe = fsl_elbc_nand_probe ,
. remove = fsl_elbc_nand_remove ,
2008-02-07 00:36:21 +03:00
} ;
2011-11-27 16:45:03 +04:00
module_platform_driver ( fsl_elbc_nand_driver ) ;
2008-02-07 00:36:21 +03:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Freescale " ) ;
MODULE_DESCRIPTION ( " Freescale Enhanced Local Bus Controller MTD NAND driver " ) ;