@ -31,6 +31,10 @@
# ifdef CONFIG_ATMEL_NAND_HW_PMECC
# ifdef CONFIG_SPL_BUILD
# undef CONFIG_SYS_NAND_ONFI_DETECTION
# endif
struct atmel_nand_host {
struct pmecc_regs __iomem * pmecc ;
struct pmecc_errloc_regs __iomem * pmerrloc ;
@ -1169,6 +1173,209 @@ static int at91_nand_ready(struct mtd_info *mtd)
}
# endif
# ifdef CONFIG_SPL_BUILD
/* The following code is for SPL */
static nand_info_t mtd ;
static struct nand_chip nand_chip ;
static int nand_command ( int block , int page , uint32_t offs , u8 cmd )
{
struct nand_chip * this = mtd . priv ;
int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT ;
void ( * hwctrl ) ( struct mtd_info * mtd , int cmd ,
unsigned int ctrl ) = this - > cmd_ctrl ;
while ( this - > dev_ready ( & mtd ) )
;
if ( cmd = = NAND_CMD_READOOB ) {
offs + = CONFIG_SYS_NAND_PAGE_SIZE ;
cmd = NAND_CMD_READ0 ;
}
hwctrl ( & mtd , cmd , NAND_CTRL_CLE | NAND_CTRL_CHANGE ) ;
if ( this - > options & NAND_BUSWIDTH_16 )
offs > > = 1 ;
hwctrl ( & mtd , offs & 0xff , NAND_CTRL_ALE | NAND_CTRL_CHANGE ) ;
hwctrl ( & mtd , ( offs > > 8 ) & 0xff , NAND_CTRL_ALE ) ;
hwctrl ( & mtd , ( page_addr & 0xff ) , NAND_CTRL_ALE ) ;
hwctrl ( & mtd , ( ( page_addr > > 8 ) & 0xff ) , NAND_CTRL_ALE ) ;
# ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE
hwctrl ( & mtd , ( page_addr > > 16 ) & 0x0f , NAND_CTRL_ALE ) ;
# endif
hwctrl ( & mtd , NAND_CMD_NONE , NAND_NCE | NAND_CTRL_CHANGE ) ;
hwctrl ( & mtd , NAND_CMD_READSTART , NAND_CTRL_CLE | NAND_CTRL_CHANGE ) ;
hwctrl ( & mtd , NAND_CMD_NONE , NAND_NCE | NAND_CTRL_CHANGE ) ;
while ( this - > dev_ready ( & mtd ) )
;
return 0 ;
}
static int nand_is_bad_block ( int block )
{
struct nand_chip * this = mtd . priv ;
nand_command ( block , 0 , CONFIG_SYS_NAND_BAD_BLOCK_POS , NAND_CMD_READOOB ) ;
if ( this - > options & NAND_BUSWIDTH_16 ) {
if ( readw ( this - > IO_ADDR_R ) ! = 0xffff )
return 1 ;
} else {
if ( readb ( this - > IO_ADDR_R ) ! = 0xff )
return 1 ;
}
return 0 ;
}
# ifdef CONFIG_SPL_NAND_ECC
static int nand_ecc_pos [ ] = CONFIG_SYS_NAND_ECCPOS ;
# define ECCSTEPS (CONFIG_SYS_NAND_PAGE_SIZE / \
CONFIG_SYS_NAND_ECCSIZE )
# define ECCTOTAL (ECCSTEPS * CONFIG_SYS_NAND_ECCBYTES)
static int nand_read_page ( int block , int page , void * dst )
{
struct nand_chip * this = mtd . priv ;
u_char ecc_calc [ ECCTOTAL ] ;
u_char ecc_code [ ECCTOTAL ] ;
u_char oob_data [ CONFIG_SYS_NAND_OOBSIZE ] ;
int eccsize = CONFIG_SYS_NAND_ECCSIZE ;
int eccbytes = CONFIG_SYS_NAND_ECCBYTES ;
int eccsteps = ECCSTEPS ;
int i ;
uint8_t * p = dst ;
nand_command ( block , page , 0 , NAND_CMD_READ0 ) ;
for ( i = 0 ; eccsteps ; eccsteps - - , i + = eccbytes , p + = eccsize ) {
if ( this - > ecc . mode ! = NAND_ECC_SOFT )
this - > ecc . hwctl ( & mtd , NAND_ECC_READ ) ;
this - > read_buf ( & mtd , p , eccsize ) ;
this - > ecc . calculate ( & mtd , p , & ecc_calc [ i ] ) ;
}
this - > read_buf ( & mtd , oob_data , CONFIG_SYS_NAND_OOBSIZE ) ;
for ( i = 0 ; i < ECCTOTAL ; i + + )
ecc_code [ i ] = oob_data [ nand_ecc_pos [ i ] ] ;
eccsteps = ECCSTEPS ;
p = dst ;
for ( i = 0 ; eccsteps ; eccsteps - - , i + = eccbytes , p + = eccsize )
this - > ecc . correct ( & mtd , p , & ecc_code [ i ] , & ecc_calc [ i ] ) ;
return 0 ;
}
# else
static int nand_read_page ( int block , int page , void * dst )
{
struct nand_chip * this = mtd . priv ;
nand_command ( block , page , 0 , NAND_CMD_READ0 ) ;
atmel_nand_pmecc_read_page ( & mtd , this , dst , 0 , page ) ;
return 0 ;
}
# endif /* CONFIG_SPL_NAND_ECC */
int nand_spl_load_image ( uint32_t offs , unsigned int size , void * dst )
{
unsigned int block , lastblock ;
unsigned int page ;
block = offs / CONFIG_SYS_NAND_BLOCK_SIZE ;
lastblock = ( offs + size - 1 ) / CONFIG_SYS_NAND_BLOCK_SIZE ;
page = ( offs % CONFIG_SYS_NAND_BLOCK_SIZE ) / CONFIG_SYS_NAND_PAGE_SIZE ;
while ( block < = lastblock ) {
if ( ! nand_is_bad_block ( block ) ) {
while ( page < CONFIG_SYS_NAND_PAGE_COUNT ) {
nand_read_page ( block , page , dst ) ;
dst + = CONFIG_SYS_NAND_PAGE_SIZE ;
page + + ;
}
page = 0 ;
} else {
lastblock + + ;
}
block + + ;
}
return 0 ;
}
int at91_nand_wait_ready ( struct mtd_info * mtd )
{
struct nand_chip * this = mtd - > priv ;
udelay ( this - > chip_delay ) ;
return 0 ;
}
int board_nand_init ( struct nand_chip * nand )
{
int ret = 0 ;
nand - > ecc . mode = NAND_ECC_SOFT ;
# ifdef CONFIG_SYS_NAND_DBW_16
nand - > options = NAND_BUSWIDTH_16 ;
nand - > read_buf = nand_read_buf16 ;
# else
nand - > read_buf = nand_read_buf ;
# endif
nand - > cmd_ctrl = at91_nand_hwcontrol ;
# ifdef CONFIG_SYS_NAND_READY_PIN
nand - > dev_ready = at91_nand_ready ;
# else
nand - > dev_ready = at91_nand_wait_ready ;
# endif
nand - > chip_delay = 20 ;
# ifdef CONFIG_ATMEL_NAND_HWECC
# ifdef CONFIG_ATMEL_NAND_HW_PMECC
ret = atmel_pmecc_nand_init_params ( nand , & mtd ) ;
# endif
# endif
return ret ;
}
void nand_init ( void )
{
mtd . writesize = CONFIG_SYS_NAND_PAGE_SIZE ;
mtd . oobsize = CONFIG_SYS_NAND_OOBSIZE ;
mtd . priv = & nand_chip ;
nand_chip . IO_ADDR_R = ( void __iomem * ) CONFIG_SYS_NAND_BASE ;
nand_chip . IO_ADDR_W = ( void __iomem * ) CONFIG_SYS_NAND_BASE ;
board_nand_init ( & nand_chip ) ;
# ifdef CONFIG_SPL_NAND_ECC
if ( nand_chip . ecc . mode = = NAND_ECC_SOFT ) {
nand_chip . ecc . calculate = nand_calculate_ecc ;
nand_chip . ecc . correct = nand_correct_data ;
}
# endif
if ( nand_chip . select_chip )
nand_chip . select_chip ( & mtd , 0 ) ;
}
void nand_deselect ( void )
{
if ( nand_chip . select_chip )
nand_chip . select_chip ( & mtd , - 1 ) ;
}
# else
# ifndef CONFIG_SYS_NAND_BASE_LIST
# define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE }
# endif
@ -1227,3 +1434,4 @@ void board_nand_init(void)
dev_err ( host - > dev , " atmel_nand: Fail to initialize #%d chip " ,
i ) ;
}
# endif /* CONFIG_SPL_BUILD */