www.pudn.com > nand_flash_arithmetic.rar > NandFlash.c
/*************************************************************************/ /* */ /* FILE NAME VERSION */ /* */ /* source\flash.c 1.0 */ /* */ /* DESCRIPTION */ /* */ /* */ /* */ /* DATA STRUCTURES */ /* */ /* FUNCTIONS : Flash Fujitsu program code */ /* */ /* DEPENDENCIES */ /* */ /* */ /* */ /* Copyrigth (C) 2001 AIJISYSTEM CO.,LTD */ /*************************************************************************/ #include#include #include "common.h" #define SAMSUNG //#define TOSHIBA #define PAGE_CNT 32 #define PAGE_SIZE 512 #define BLOCK_COUNT 4096 #define BLOCK_SIZE 0x4000 #define BASE_ADDR (ulong)0x64000000 volatile ulong *data_reg = (ulong *)0x64000000; volatile ulong *spare_data_reg = (ulong *)0x64000320; volatile ulong *cle_reg = (ulong *)0x64000300; volatile ulong *ale_reg = (ulong *)0x64000304; volatile ulong *status_reg = (ulong *)0x64000308; volatile ulong *ecc_read_reg = (ulong *)0x6400030c; volatile ushort *flash_cfg_reg = (ushort *)0x6400031c; volatile ulong *clear_status_reg = (ulong *)0x80000c84; // WatchDog resetÀ» ¹æÁöÇϱâ À§ÇÑ register //volatile ushort *AutoKick_reg = (ushort *)0x3000600; //MSM3000, 3100, 5000, 5105 //volatile ushort *AutoKick_reg = (ushort *)0x3000700; //MSM5100 watch dog address //volatile ushort *AutoKick_reg = (ushort *)0x30006d0; //MSM6050 //volatile ushort *AutoKick_reg = (ushort *)0x3001080; //MSM5500 volatile ushort *AutoKick_reg = (ushort *)0x80000700; //MSM6100 // Host program°ú data & command¸¦ ÁÖ°í¹Þ±â À§ÇÑ structure extern FLASH_INFO Flash_Info; uchar TempBuf[BLOCK_SIZE]; uchar FillBuf[PAGE_SIZE]; ulong Current_Block_No = 2; ulong Current_Page_No = 0; ulong BIB_Block_No = 1; ulong LastAddr = 0; ulong crc = 0; ulong image_size = 0; /* The CRC table size is based on how many bits at a time we are going ** to process through the table. Given that we are processing the data ** 8 bits at a time, this gives us 2^8 (256) entries. */ #define CRC_TAB_SIZE 256 /* 2^CRC_TAB_BITS */ /* CRC table for 30 bit CRC, with generator polynomial 0x6030b9c7, ** calculated 8 bits at a time, MSB first. */ const ulong crc30_table[ CRC_TAB_SIZE ] = { 0x00000000, 0x2030b9c7, 0x2051ca49, 0x0061738e, 0x20932d55, 0x00a39492, 0x00c2e71c, 0x20f25edb, 0x2116e36d, 0x01265aaa, 0x01472924, 0x217790e3, 0x0185ce38, 0x21b577ff, 0x21d40471, 0x01e4bdb6, 0x221d7f1d, 0x022dc6da, 0x024cb554, 0x227c0c93, 0x028e5248, 0x22beeb8f, 0x22df9801, 0x02ef21c6, 0x030b9c70, 0x233b25b7, 0x235a5639, 0x036aeffe, 0x2398b125, 0x03a808e2, 0x03c97b6c, 0x23f9c2ab, 0x240a47fd, 0x043afe3a, 0x045b8db4, 0x246b3473, 0x04996aa8, 0x24a9d36f, 0x24c8a0e1, 0x04f81926, 0x051ca490, 0x252c1d57, 0x254d6ed9, 0x057dd71e, 0x258f89c5, 0x05bf3002, 0x05de438c, 0x25eefa4b, 0x061738e0, 0x26278127, 0x2646f2a9, 0x06764b6e, 0x268415b5, 0x06b4ac72, 0x06d5dffc, 0x26e5663b, 0x2701db8d, 0x0731624a, 0x075011c4, 0x2760a803, 0x0792f6d8, 0x27a24f1f, 0x27c33c91, 0x07f38556, 0x2824363d, 0x08148ffa, 0x0875fc74, 0x284545b3, 0x08b71b68, 0x2887a2af, 0x28e6d121, 0x08d668e6, 0x0932d550, 0x29026c97, 0x29631f19, 0x0953a6de, 0x29a1f805, 0x099141c2, 0x09f0324c, 0x29c08b8b, 0x0a394920, 0x2a09f0e7, 0x2a688369, 0x0a583aae, 0x2aaa6475, 0x0a9addb2, 0x0afbae3c, 0x2acb17fb, 0x2b2faa4d, 0x0b1f138a, 0x0b7e6004, 0x2b4ed9c3, 0x0bbc8718, 0x2b8c3edf, 0x2bed4d51, 0x0bddf496, 0x0c2e71c0, 0x2c1ec807, 0x2c7fbb89, 0x0c4f024e, 0x2cbd5c95, 0x0c8de552, 0x0cec96dc, 0x2cdc2f1b, 0x2d3892ad, 0x0d082b6a, 0x0d6958e4, 0x2d59e123, 0x0dabbff8, 0x2d9b063f, 0x2dfa75b1, 0x0dcacc76, 0x2e330edd, 0x0e03b71a, 0x0e62c494, 0x2e527d53, 0x0ea02388, 0x2e909a4f, 0x2ef1e9c1, 0x0ec15006, 0x0f25edb0, 0x2f155477, 0x2f7427f9, 0x0f449e3e, 0x2fb6c0e5, 0x0f867922, 0x0fe70aac, 0x2fd7b36b, 0x3078d5bd, 0x10486c7a, 0x10291ff4, 0x3019a633, 0x10ebf8e8, 0x30db412f, 0x30ba32a1, 0x108a8b66, 0x116e36d0, 0x315e8f17, 0x313ffc99, 0x110f455e, 0x31fd1b85, 0x11cda242, 0x11acd1cc, 0x319c680b, 0x1265aaa0, 0x32551367, 0x323460e9, 0x1204d92e, 0x32f687f5, 0x12c63e32, 0x12a74dbc, 0x3297f47b, 0x337349cd, 0x1343f00a, 0x13228384, 0x33123a43, 0x13e06498, 0x33d0dd5f, 0x33b1aed1, 0x13811716, 0x14729240, 0x34422b87, 0x34235809, 0x1413e1ce, 0x34e1bf15, 0x14d106d2, 0x14b0755c, 0x3480cc9b, 0x3564712d, 0x1554c8ea, 0x1535bb64, 0x350502a3, 0x15f75c78, 0x35c7e5bf, 0x35a69631, 0x15962ff6, 0x366fed5d, 0x165f549a, 0x163e2714, 0x360e9ed3, 0x16fcc008, 0x36cc79cf, 0x36ad0a41, 0x169db386, 0x17790e30, 0x3749b7f7, 0x3728c479, 0x17187dbe, 0x37ea2365, 0x17da9aa2, 0x17bbe92c, 0x378b50eb, 0x185ce380, 0x386c5a47, 0x380d29c9, 0x183d900e, 0x38cfced5, 0x18ff7712, 0x189e049c, 0x38aebd5b, 0x394a00ed, 0x197ab92a, 0x191bcaa4, 0x392b7363, 0x19d92db8, 0x39e9947f, 0x3988e7f1, 0x19b85e36, 0x3a419c9d, 0x1a71255a, 0x1a1056d4, 0x3a20ef13, 0x1ad2b1c8, 0x3ae2080f, 0x3a837b81, 0x1ab3c246, 0x1b577ff0, 0x3b67c637, 0x3b06b5b9, 0x1b360c7e, 0x3bc452a5, 0x1bf4eb62, 0x1b9598ec, 0x3ba5212b, 0x3c56a47d, 0x1c661dba, 0x1c076e34, 0x3c37d7f3, 0x1cc58928, 0x3cf530ef, 0x3c944361, 0x1ca4faa6, 0x1d404710, 0x3d70fed7, 0x3d118d59, 0x1d21349e, 0x3dd36a45, 0x1de3d382, 0x1d82a00c, 0x3db219cb, 0x1e4bdb60, 0x3e7b62a7, 0x3e1a1129, 0x1e2aa8ee, 0x3ed8f635, 0x1ee84ff2, 0x1e893c7c, 0x3eb985bb, 0x3f5d380d, 0x1f6d81ca, 0x1f0cf244, 0x3f3c4b83, 0x1fce1558, 0x3ffeac9f, 0x3f9fdf11, 0x1faf66d6 }; void Main(void) { switch(Flash_Info.Command) { case FPROGRAM: Program(); break; case FERASEALL: Flash_Info.Result = 1; //EraseAll(); break; case FERASESEC: Flash_Info.Result = 1; //EraseSector(); break; case FREADID: ReadChipID(); break; case FREADMEM: ReadMem(); break; case FWRITE_BIB: WriteBIB(); break; case FINIT: InitFlash(); break; default : Flash_Info.Result = 0; } } // Flash program function void Program(void) { ulong len, flen, i, fillsize, wSize; volatile ulong status; uchar *srcP, *bsrcP; Flash_Info.Result = 0; Flash_Info.TargetAddr &= 0x3FFFFFF; wSize = 0; if(Flash_Info.TargetAddr != LastAddr) { fillsize = Flash_Info.TargetAddr - LastAddr; for(i = 0; i < PAGE_SIZE; i++) FillBuf[i] = 0xff; while(fillsize && (Current_Block_No < BLOCK_COUNT)) { if(!(Current_Page_No%PAGE_CNT)) { if(!PrepareBlock()) return; } if(Current_Block_No >= BLOCK_COUNT) return; status = WriteChar(FillBuf, Current_Page_No); if(!status) // error return; ReadChar(TempBuf, Current_Page_No*PAGE_SIZE, PAGE_SIZE); if(!Verification((ulong *)TempBuf, PAGE_SIZE, (ulong *)FillBuf)) return; Current_Page_No++; crc = crc_30_step (crc, FillBuf, (ushort)PAGE_SIZE*8); image_size +=PAGE_SIZE; fillsize -= PAGE_SIZE; AutoKick(); } } AutoKick(); srcP = (uchar *)Flash_Info.Buf; len = Flash_Info.Length; while(len && (Current_Block_No < BLOCK_COUNT)) { if(!(Current_Page_No%PAGE_CNT)) { if(!PrepareBlock()) return; } if(Current_Block_No >= BLOCK_COUNT) return; if(len > PAGE_SIZE) flen = PAGE_SIZE; else { flen = len; bsrcP = srcP+len; for(i=len; i magic1 = MAGIC1; bib->magic2 = MAGIC2; bib->version = BIB_VERSION; bib->crc = crc; bib->startaddr = 0x0; bib->length = image_size; bib_size = sizeof(struct boot_info_block); for(i=bib_size; i > 1; no_of_shifts++; } /* Set the block address in Nand_Flash_Addr */ nand_cntlr_block_addr = block << (9 + no_of_shifts); *ale_reg = nand_cntlr_block_addr; /* Issue the block erase command */ *cle_reg = ERASE_CMD; /* Wait for erase command to be executed */ while(*status_reg & ERASE_CMD) ; /* Check status after erase */ status = *status_reg; if( (status & FS_NAND_OP_ERR_MASK != 0) || (status & FS_NAND_OP_RESULT_MASK != 0) ) { return 0; } return 1; } // Read Manufacturer & Device ID void ReadChipID(void) { ulong manId,devId; *cle_reg = RESET_CMD; *cle_reg = ID_CMD; /* Wait for completion. */ while(*status_reg & ID_CMD) { *AutoKick_reg = 1; *AutoKick_reg = 0; } manId = *status_reg; devId = (manId >> 15) & 0xff; manId = (manId >> 23) & 0xff; Flash_Info.Result = (devId << 8) + manId; } ulong PrepareBlock(void) { while(!Bad_Block_Check(++Current_Block_No)) ; if(Current_Block_No >= BLOCK_COUNT) return 0; if(!OneBlockErase(Current_Block_No)) return 0; Current_Page_No = Current_Block_No*PAGE_CNT; return 1; } int BlankCheck(ulong *targetP,ulong targetSize) { ulong i; for(i=0; i PAGE_SIZE) flen = PAGE_SIZE; else flen = len; *ale_reg = targetAddr & 0x01FFFE00; *cle_reg = READ_DATA; while(*status_reg & READ_DATA) { *AutoKick_reg = 1; *AutoKick_reg = 0; } status = *status_reg; if( (status & FS_NAND_OP_ERR_MASK != 0) || (status & FS_NAND_ECC_SELF_ERR_MASK != 0) || (status & FS_NAND_READ_ECC_ERR_MASK != 0) ) return 0; // for(j=0; j = 8; len -= 8, buf_ptr++) { crc_30 = crc30_table[ ((crc_30 >> (30 - 8)) ^ *buf_ptr) & 0xff ] ^ (crc_30 << 8); } /* Finish calculating the CRC over the trailing data bits ** ** XOR the MS bit of data with the MS bit of the CRC. ** Shift the CRC and data left 1 bit. ** If the XOR result is 1, XOR the generating polynomial in with the CRC. */ if (len != 0) { data = ((ulong) (*buf_ptr)) << (30-8); /* Align data MSB with CRC MSB */ while (len-- != 0) { if ( ((crc_30 ^ data) & (1L << 29)) != 0 ) { /* Is MSB of XOR a 1 */ crc_30 <<= 1; /* Left shift CRC */ crc_30 ^= CRC_30_POLYNOMIAL; /* XOR polynomial into CRC */ } else { crc_30 <<= 1; /* Left shift CRC */ } data <<= 1; /* Left shift data */ } } crc_30 = ~crc_30; /* 1's complement the CRC */ return( crc_30 & 0x3FFFFFFF ); /* mask the result to 30 bits */ } /* end of crc_30_calc */ #ifdef SAMSUNG // Samsung nand flash int Bad_Block_Check(ulong block) { ulong page_address, status, spare_byte; ulong page_no =0; int block_size_shift; ushort no_of_shifts = 1; ushort no_pages_to_check; block_size_shift = PAGE_CNT; while( block_size_shift != 2 ) { block_size_shift = block_size_shift >> 1; no_of_shifts++; } /* Set the first page number */ page_no = block << no_of_shifts; /* Check the first two pages of the samsung block */ for( no_pages_to_check=0; no_pages_to_check < 2 ; no_pages_to_check++ ) { /* Read the 6th spare byte */ page_address = (page_no << 9) + 5; *ale_reg = page_address; *cle_reg = READ_FLAG; while(*status_reg & READ_FLAG) ; status = *status_reg; if(status & FS_NAND_OP_ERR_MASK) return 0; spare_byte = *spare_data_reg; *AutoKick_reg = 1; *AutoKick_reg = 0; if( (spare_byte & 0xFF ) != 0xFF ) { return 0; } /* Check the second page in the block */ page_no++; } /* After the spare byte is read the nand device needs to be reset before any other operation is performed */ /* Software reset the controller. */ *cle_reg = RESET_CTRL; /* Reset NAND flash memory */ *cle_reg = RESET_CMD; /* Configure NAND flash */ *flash_cfg_reg = FS_NAND_CNFG_VAL; /* Wait for completion. */ while(*status_reg & PROGRAM_CMD) ; /* Do a id check. */ *cle_reg = ID_CMD; /* Wait for completion. */ while(*status_reg & ID_CMD) ; return 1; } /* End of samsung_nand_bad_block_check */ #endif #ifdef TOSHIBA int Bad_Block_Check(ulong block) { int i; ulong page_address, status, page_no, first_page_no; ulong sram_buffer=0x0; int block_size_shift; ushort no_of_shifts = 1; int block_size=PAGE_CNT; int page_size=PAGE_SIZE; ulong ecc; block_size_shift=PAGE_CNT; while ( block_size_shift != 2 ) { block_size_shift = block_size_shift >> 1; no_of_shifts++; } /*Reset sram memory */ for (i = 0; i < page_size/4; i++) *(data_reg + i) = 0; /* Set the first page number */ first_page_no = block << no_of_shifts; for ( page_no = first_page_no ; page_no < first_page_no+block_size ; page_no++ ) { page_address = page_no << 9; *ale_reg = page_address; *cle_reg = READ_DATA; status = *status_reg; while ( status & READ_DATA != 0) { status = *status_reg; } status = *status_reg; if ( (status & FS_NAND_OP_ERR_MASK != 0) || (status & FS_NAND_ECC_SELF_ERR_MASK != 0) || (status & FS_NAND_READ_ECC_ERR_MASK != 0) ) { return 0; } /* TESTING ecc malfunction !!*/ ecc = *ecc_read_reg; if ( ((ecc & FS_NAND_READ_ECC_ERR_MASK) != 0) || ((ecc & FS_NAND_ECC_UC_ERR_MASK) != 0 )) { /*printf("fs_nand_common_fnc: fs_nand_read_page - error bad ecc 0: 0x%08x", ecc);*/ status = *status_reg; if ( (status & FS_NAND_OP_ERR_MASK != 0) || (status & FS_NAND_ECC_SELF_ERR_MASK != 0) || (status & FS_NAND_READ_ECC_ERR_MASK != 0) ) { /* printf("ecc was bad and status was also bad\n");*/ } } /* Reading the sram buffer in chunks of 4 bytes */ for (i = 0; i < page_size/4; i++) { sram_buffer = *(data_reg + i); if ( (sram_buffer & 0xFFFFFFFF ) != 0xFFFFFFFF ) return 0; sram_buffer=0x0; } } return 1; } /* End of toshiba_nand_bad_block_check */ #endif