blob: 471a86ff372613c2f3a977aeea490536ac73311e [file] [log] [blame]
/*
* (C) Copyright 2016 ZXIC Inc.
*/
#include <common.h>
#include <asm/io.h>
#include <bbt.h>
#include "config.h"
#include "flash.h"
static uint8_t block_bad_table[BBT_SIZE]={0};
static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
static struct nand_bbt_descr bbt_main_descr = {
.offs = 4,
.len = 4,
.veroffs = 20,
.maxblocks = 16,
.pattern = bbt_pattern,
};
static struct nand_bbt_descr bbt_mirror_descr = {
.offs = 4,
.len = 4,
.veroffs = 20,
.maxblocks = 16,
.pattern = mirror_pattern,
};
static int nand_check_pattern(uint8_t *buf,struct nand_bbt_descr *td)
{
int i;
uint8_t *p = buf;
p += td->offs;
/* Compare the pattern */
for (i = 0; i < td->len; i++)
{
if (p[i] != td->pattern[i])
return -1;
}
return 0;
}
void nand_creat_ram_bbt( void )
{
uint32_t i = 0;
uint32_t off = 0;
uint32_t oob_size = flash.oob_size;
uint32_t block_size = flash.block_size;
uint8_t oob[256]; /* ÕâÀﶨÒå×î´óµÄOOB SIZE */
//#ifdef CONFIG_ZX297520V3E_MDL_AB
#if defined(CONFIG_ZX297520V3E_MDL_AB) || defined(CONFIG_ZX297520V3E_VEHICLE_DC) || defined(CONFIG_ZX297520V3E_VEHICLE_DC_REF)
uint32_t block_nums = 72;
#else
uint32_t block_nums = 17;
#endif
for( i=0; i<block_nums; i++ )
{
flash.read_oob(&oob[0], off, oob_size);
if(oob[0] != 0xff) /* bad block */
block_bad_table[i] = BAD_BLOCK;
else
block_bad_table[i] = 0x0;
off += block_size;
}
}
int nand_search_bbt(struct nand_bbt_descr *td)
{
int startblock, block;
int blocktopage = flash.block_size_shift - flash.page_size_shift;
uint8_t oob_buffer[256]={0xFF};
uint32_t offs = 0;
/* Search direction down -> top */
startblock = flash.block_num -1;
td->page= -1;
/* Scan the maximum number of blocks */
for (block = 0; block < td->maxblocks; block++)
{
int actblock = startblock -block;
offs = actblock << flash.block_size_shift;
/* Read first page */
flash.read_oob(oob_buffer, offs, flash.oob_size);
if (!nand_check_pattern(oob_buffer,td))
{
td->page = actblock << blocktopage;
td->version= oob_buffer[td->veroffs];
break;
}
}
return 0;
}
static int nand_read_bbt(struct nand_bbt_descr *td,int num)
{
int bits=2;
int res, i, j, act = 0;
int totlen;
int from;
uint8_t msk = (uint8_t) ((1 << bits) - 1);
totlen = (num * bits) >> 3;
from =(td->page)<<(flash.page_size_shift);
char* buf;
res = flash.read_page_raw(CFG_TEMP_ADDR, from);
if (res < 0)
{
return -1;
}
buf =(char*) CFG_TEMP_ADDR;
/* Analyse data */
for (i = 0; i < totlen; i++)
{
uint8_t dat = buf[i];
for (j = 0; j < 8; j += bits, act += 2)
{
uint8_t tmp = (dat >> j) & msk;
if (tmp == msk)
{
block_bad_table[(act >> 1)]= 0X0;
continue;
}
else
{
block_bad_table[(act >> 1)]= BAD_BLOCK;
}
}
}
return 0;
}
static void nand_init_bbt_descr(struct nand_bbt_descr *td,
struct nand_bbt_descr *md)
{
switch(flash.manuf_id)
{
case NAND_MFR_PARAGON:
if(flash.device_id != NAND_DEVID_FDANWEI_1G)
{
td->offs = BBT_INFO_OOB_OFFSET_PARAGON;
md->offs = BBT_INFO_OOB_OFFSET_PARAGON;
td->veroffs = BBT_INFO_OOB_VER_OFFSET_PARAGON;
md->veroffs = BBT_INFO_OOB_VER_OFFSET_PARAGON;
}
break;
case NAND_MFR_HEYANGTEK:
td->offs = BBT_INFO_OOB_OFFSET_HEYANGTEK;
md->offs = BBT_INFO_OOB_OFFSET_HEYANGTEK;
td->veroffs = BBT_INFO_OOB_VER_OFFSET_HEYANGTEK;
md->veroffs =BBT_INFO_OOB_VER_OFFSET_HEYANGTEK;
break;
default:
break;
}
}
int nand_creat_bbt( void )
{
struct nand_bbt_descr *td = &bbt_main_descr;
struct nand_bbt_descr *md = &bbt_mirror_descr;
nand_init_bbt_descr(td, md);
// 2.0 search main bbt
nand_search_bbt(td);
// 2.1 search mirror bbt
nand_search_bbt(md);
if(td->page==-1&&md->page ==-1)
{
/* if failed found bbt, we create a ram bbt */
nand_creat_ram_bbt();
return 0;
}
// 3.0 read and analyze bbt
if(td->page==-1)
{
nand_read_bbt(md,BBT_SIZE);
}
else
{
if(md->page == -1)
{
nand_read_bbt(td,BBT_SIZE);
}
else
{
if(td->version >= md->version)
{
nand_read_bbt(td,BBT_SIZE);
}
else
{
nand_read_bbt(md,BBT_SIZE);
}
}
}
printf("bbt ok.\n");
return 0;
}
/*******************************************************************************
* Function:
* Description:
* Parameters:
* Input:
*
* Output:
*
* Returns:
*
*
* Others:
********************************************************************************/
uint32_t nand_block_isbad(uint32_t offset)
{
uint32_t block_offset = offset >> (flash.block_size_shift);
return block_bad_table[block_offset];
}