📄 flash_nand.c
字号:
static const unsigned char _nand_ecc_precalc_table[] = { 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00};static void _nand_trans_result(unsigned char reg2, unsigned char reg3, unsigned char *ecc0, unsigned char *ecc1){ unsigned char a, b, i, tmp1, tmp2; /* Initialize variables */ a = b = 0x80; tmp1 = tmp2 = 0; /* Calculate first ECC byte */ for (i = 0; i < 4; i++) { if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ tmp1 |= b; b >>= 1; if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */ tmp1 |= b; b >>= 1; a >>= 1; } /* Calculate second ECC byte */ b = 0x80; for (i = 0; i < 4; i++) { if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */ tmp2 |= b; b >>= 1; if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */ tmp2 |= b; b >>= 1; a >>= 1; } /* Store two of the ECC bytes */ *ecc0 = tmp1; *ecc1 = tmp2;}//// Calculate 3 byte ECC on 256 bytes of data//static void_nand_page_ECC(unsigned char *data, unsigned char *ecc0, unsigned char *ecc1, unsigned char *ecc2){ unsigned char idx, reg1, reg2, reg3; int j; /* Initialize variables */ reg1 = reg2 = reg3 = 0; *ecc0 = *ecc1 = *ecc2 = 0; /* Build up column parity */ for(j = 0; j < 256; j++) { /* Get CP0 - CP5 from table */ idx = _nand_ecc_precalc_table[*data++]; reg1 ^= (idx & 0x3f); /* All bit XOR = 1 ? */ if (idx & 0x40) { reg3 ^= (unsigned char) j; reg2 ^= ~((unsigned char) j); } } /* Create non-inverted ECC code from line parity */ _nand_trans_result(reg2, reg3, ecc0, ecc1); /* Calculate final ECC code */ *ecc0 = ~*ecc0; *ecc1 = ~*ecc1; *ecc2 = ((~reg1) << 2) | 0x03;}//// Correct a buffer via ECC (1 bit, 256 byte block)// Return: 0 => No error// 1 => Corrected// 2 => Not corrected, ECC updated// -1 => Not correctable//int _nand_correct_data(unsigned char *dat, unsigned char *read_ecc, unsigned char *calc_ecc){ unsigned char a, b, c, d1, d2, d3, add, bit, i; /* Do error detection */ d1 = calc_ecc[0] ^ read_ecc[0]; d2 = calc_ecc[1] ^ read_ecc[1]; d3 = calc_ecc[2] ^ read_ecc[2]; if ((d1 | d2 | d3) == 0) { /* No errors */ return 0; } else { a = (d1 ^ (d1 >> 1)) & 0x55; b = (d2 ^ (d2 >> 1)) & 0x55; c = (d3 ^ (d3 >> 1)) & 0x54; /* Found and will correct single bit error in the data */ if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { c = 0x80; add = 0; a = 0x80; for (i=0; i<4; i++) { if (d1 & c) add |= a; c >>= 2; a >>= 1; } c = 0x80; for (i=0; i<4; i++) { if (d2 & c) add |= a; c >>= 2; a >>= 1; } bit = 0; b = 0x04; c = 0x80; for (i=0; i<3; i++) { if (d3 & c) bit |= b; c >>= 2; b >>= 1; } b = 0x01; a = dat[add]; a ^= (b << bit); dat[add] = a; return 1; } else { i = 0; while (d1) { if (d1 & 0x01) ++i; d1 >>= 1; } while (d2) { if (d2 & 0x01) ++i; d2 >>= 1; } while (d3) { if (d3 & 0x01) ++i; d3 >>= 1; } if (i == 1) { /* ECC Code Error Correction */ read_ecc[0] = calc_ecc[0]; read_ecc[1] = calc_ecc[1]; read_ecc[2] = calc_ecc[2]; return 2; } else { /* Uncorrectable Error */ return -1; } } } /* Should never happen */ return -1;}//----------------------------------------------------------------------------// Program Bufferstatic intflash_program_buf(void* addr, void* data, int len){ int res=FLASH_ERR_OK; unsigned char *paddr=addr; unsigned char *pdata=data; while(len>0) { if(StatusCheck(chip0_en, def_width)!=FAIL) { if( pagewrite(paddr,pdata,flash_dev_info->page_size) != PASS) return FLASH_ERR_PROGRAM; flash_delay(); len -= flash_dev_info->page_size; paddr += flash_dev_info->page_size ; pdata += flash_dev_info->page_size ; } } return res;}//----------------------------------------------------------------------------// Read data into bufferintflash_read_buf(void* addr, void* buff, int len){ int i,res=FLASH_ERR_OK; UINT8 read_buff[2048+64],*pbuff=(UINT8*)buff; while(len>0){ if(StatusCheck(chip0_en, def_width)!=FAIL) { if(pageread((UINT64)addr,((len>=info_flash[4])?pbuff:read_buff))!=PASS){ res = FLASH_ERR_HWR; break; } //memcpy(pbuff,read_buff,(len>flash_dev_info->page_size)?flash_dev_info->page_size:len); if(len < info_flash[4]) memcpy(pbuff,read_buff,(len>flash_dev_info->page_size)?flash_dev_info->page_size:len); flash_delay(); len -= flash_dev_info->page_size; addr += flash_dev_info->page_size; pbuff += flash_dev_info->page_size; } } return res;}int pageread(UINT64 page_add, UINT8* page_data){ UINT32 i,j,data,nwidth;//,po; UINT8 *adr=page_add,ecc,ecc_byte,ecc_bit; UINT8 dev_oob[64],oob[64]; nwidth = NFLASH_WiDTH8; page_add -= 0x30000000; page_add /= info_flash[5]; ADD5=ADD4=ADD3=ADD2=0; //ndirect = 0; // nmode = 1 ; ndirect = 0x4000; nmode = 1 ; if(info_flash[5] < 528) {/* ADD5=(UINT32)((page_add<<8)>>32); ADD4=(UINT32)((page_add<<16)>>32); ADD3=(UINT32)((page_add<<24)>>32); ADD2=(UINT32)((page_add<<32)>>32);*/ ADD5 = (page_add & 0xff000000)>>24; ADD4 = (page_add & 0x00ff0000)>>16; ADD3 = (page_add & 0x0000ff00)>>8; ADD2 = (page_add & 0x000000ff); } else { ADD5=(UINT32)((page_add<<16)>>32); ADD4=(UINT32)((page_add<<24)>>32); ADD3=(UINT32)((page_add<<32)>>32); } if(nmode == 2) ////DMA mode { FLASH_CTRL_WRITE_REG(NFLASH_FIFO_CONTROL, 0x8000); //clear fifo FLASH_WRITE_DMA_REG(DMA_MAIN_CFG, 0x1); //enable DMA FLASH_WRITE_DMA_REG(DMA_CH0_SRC_ADDR, 0x65888800); //src_address FLASH_WRITE_DMA_REG(DMA_CH0_DST_ADDR, (UINT32)page_data); //dest_address FLASH_WRITE_DMA_REG(DMA_CH0_LLP, 0x0); //LLP FLASH_WRITE_DMA_REG(DMA_CH0_SIZE, (info_flash[4]/4)); //size FLASH_WRITE_DMA_REG(DMA_CH0_CFG, 0x2); //CFG FLASH_WRITE_DMA_REG(DMA_CH0_CSR, 0x112c3); //CSR } //reset(chip0_en); //FLASH_CTRL_WRITE_REG(NFLASH_ECC_CONTROL, 0x00000000); //set 31b = 0 FLASH_CTRL_WRITE_REG(NFLASH_ECC_CONTROL, 0x80000001); //set 31b = 0 if(ndirect==0x0) { if(info_flash[1]<64) { FLASH_CTRL_WRITE_REG(NFLASH_COUNT, 0x0f01ff20); //set only command & address and two data opcode = 0x00000000; } if(info_flash[1]>=64&&info_flash[1]<256) { FLASH_CTRL_WRITE_REG(NFLASH_COUNT, 0x3f07ff31); //set only command & address and two data opcode = 0x000003000; } if(info_flash[1]>256) { FLASH_CTRL_WRITE_REG(NFLASH_COUNT, 0x3f07ff41); //set only command & address and two data opcode = 0x00003000; } opcode |= (ADD5<<24); FLASH_CTRL_WRITE_REG(NFLASH_COMMAND_ADDRESS, opcode); //write address 0x00 opcode = 0x00000000|(ADD4<<24)|(ADD3<<16)|(ADD2<<8); FLASH_CTRL_WRITE_REG(NFLASH_ADDRESS, opcode); //write address 0x00 if(nmode == 1) //indirect mode { for(i=0;i<info_flash[4];i++) { //hal_delay_us(1); opcode = 0x80002000|chip0_en|nwidth|ndirect; //set start bit & 8bits read command FLASH_CTRL_WRITE_REG(NFLASH_ACCESS, opcode); while(opcode&0x80000000) //polling flash access 31b { opcode=FLASH_CTRL_READ_REG(NFLASH_ACCESS); flash_delay(); } data = FLASH_CTRL_READ_REG(NFLASH_DATA); /////////// if((i&0x03)==0x01) data>>=8; else if((i&0x03)==0x02) data>>=16; else if((i&0x03)==0x03) data>>=24; page_data[i] = (UINT8)data; //flash_delay(); data =0; } } else if(nmode == 2) ////DMA mode { opcode = 0x00888800; FLASH_CTRL_WRITE_REG(NFLASH_FIFO_ADDRESS, opcode); FLASH_CTRL_WRITE_REG(NFLASH_FIFO_CONTROL, 0x80002000); opcode=FLASH_READ_DMA_REG(DMA_TC); while(!(opcode&0x01)) //polling flash access 31b { opcode=FLASH_READ_DMA_REG(DMA_TC); flash_delay(); } opcode=FLASH_CTRL_READ_REG(NFLASH_FIFO_CONTROL); while(opcode&0x80000000) //polling flash access 31b { opcode=FLASH_CTRL_READ_REG(NFLASH_FIFO_CONTROL); flash_delay(); } //Disable channel 0 DMA FLASH_WRITE_DMA_REG(DMA_CH0_CSR, 0x0); //DMA TC int status Rg //write clear int FLASH_WRITE_DMA_REG(DMA_INT_TC_CLR, 0x1); //Flash status Reg //write clear fifo_int FLASH_CTRL_WRITE_REG(FLASH_STATUS, 0x20000); } } else //direct mode { FLASH_CTRL_WRITE_REG(NFLASH_ACCESS, NFLASH_DIRECT); //memcpy(page_data, adr, info_flash[5]); //memcpy(dev_oob, (adr+info_flash[5]), info_flash[6]); //for(i=0;i<info_flash[5];i++) for(i=0;i<info_flash[4];i++) { //hal_delay_us(7); page_data[i] = *adr++; } /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -