|  | /* | 
|  | * (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]; | 
|  | } | 
|  |  | 
|  |  | 
|  |  |