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