/* Sends a reset command to the NAND flash. This function should * always be called after NFC initialization before any other * command is sent to the NAND flash. * * Parameters: * none */ void nfc_reset_cmd(void) { /* Clear all status and error bits in the NFC_ISR register */ NFC_ISR |= ( NFC_ISR_WERRCLR_MASK | NFC_ISR_DONECLR_MASK | NFC_ISR_IDLECLR_MASK ); /* Write the NFC_CMD2 register with the command byte and code for a reset */ NFC_CMD2 = NFC_CMD2_BYTE1(RESET_CMD_BYTE) | NFC_CMD2_CODE(NFC_RESET_CMD_CODE); /* Set Start Bit to send reset to the NAND flash */ NFC_CMD2 |= NFC_CMD2_BUSY_START_MASK; /* Wait for start/busy bit to clear indicating command is done */ while (NFC_CMD2 & NFC_CMD2_BUSY_START_MASK); }
/* Reads a single page worth of data from the NAND flash at the * specified address into the NFC's buffers. This function will only * read one NAND page at a time. If multiple pages need to be * read, then the function should be called once per page to * read. Data will be loaded into the NFC's buffers after the function * completes. * * Parameters: * flash_bufno first NFC internal buffer to load data to (auto increment will be used ) * row_addr NAND flash row addr for the block to program (up to 24 bits) * col_addr NAND flash col addr for the page to program (up to 16 bits) * * NOTE: the column address should be aligned to the NAND page size */ void nfc_page_read(uint8 flash_bufno, uint32 row_addr, uint16 col_addr) { /* Clear all status and error bits in the NFC_ISR register */ NFC_ISR |= ( NFC_ISR_WERRCLR_MASK | NFC_ISR_DONECLR_MASK | NFC_ISR_IDLECLR_MASK ); /* Make sure ECC is enabled before reading */ NFC_CFG |= NFC_CFG_ECCMODE(0x7); /* Set the chip select to use */ if(NFC_CE == NFC_CE0) { NFC_RAR = (NFC_RAR_CS0_MASK | NFC_RAR_RB0_MASK); } else /* (NFC_CE == NFC_CE1) */ { NFC_RAR = (NFC_RAR_CS1_MASK | NFC_RAR_RB1_MASK); } /* Set the row address */ NFC_RAR |= row_addr; /* Set the column address */ NFC_CAR = col_addr; /* Write the NFC_CMD2 register with the command byte and code for an erase */ NFC_CMD2 = (NFC_CMD2_BYTE1(PAGE_READ_CMD_BYTE1) | NFC_CMD2_CODE(NFC_READ_PAGE_CMD_CODE) | NFC_CMD2_BUFNO(flash_bufno) ); /* Write the NFC_CMD1 register with the command byte2 and byte3 for an erase */ NFC_CMD1 = NFC_CMD1_BYTE2(PAGE_READ_CMD_BYTE2) | NFC_CMD1_BYTE3(READ_STATUS_CMD_BYTE); /* Set Start Bit to send command to the NAND flash */ NFC_CMD2 |= NFC_CMD2_BUSY_START_MASK; /* Wait for start/busy bit to clear indicating command is done */ while (NFC_CMD2 & NFC_CMD2_BUSY_START_MASK); }
/* Erases the NFC block containing the specified address. This function * will only erase one block at a time. If multiple blocks need to be * erased, then the function should be called once per block to erase. * * Parameters: * row_addr NAND flash row addr for the block to erase (up to 24 bits) */ void nfc_block_erase(uint32 row_addr) { /* Clear all status and error bits in the NFC_ISR register */ NFC_ISR |= ( NFC_ISR_WERRCLR_MASK | NFC_ISR_DONECLR_MASK | NFC_ISR_IDLECLR_MASK ); /* Disable ECC during block erase */ NFC_CFG &= ~NFC_CFG_ECCMODE(0x7); /* Make sure the column address is cleared - not needed for block erase */ NFC_CAR = 0x0; /* Set the chip select to use */ if(NFC_CE == NFC_CE0) { NFC_RAR = (NFC_RAR_CS0_MASK | NFC_RAR_RB0_MASK); } else /* (NFC_CE == NFC_CE1) */ { NFC_RAR = (NFC_RAR_CS1_MASK | NFC_RAR_RB1_MASK); } /* Set the row address */ NFC_RAR |= row_addr; /* Write the NFC_CMD2 register with the command byte and code for an erase */ NFC_CMD2 = (NFC_CMD2_BYTE1(BLOCK_ERASE_CMD_BYTE1) | NFC_CMD2_CODE(NFC_BLOCK_ERASE_CMD_CODE) ); /* Write the NFC_CMD1 register with the command byte2 and byte3 for an erase */ NFC_CMD1 = NFC_CMD1_BYTE2(BLOCK_ERASE_CMD_BYTE2) | NFC_CMD1_BYTE3(READ_STATUS_CMD_BYTE); /* Set Start Bit to send command to the NAND flash */ NFC_CMD2 |= NFC_CMD2_BUSY_START_MASK; /* Wait for start/busy bit to clear indicating command is done */ while (NFC_CMD2 & NFC_CMD2_BUSY_START_MASK); }
/* Reads the NAND flash ID for the specified buffer. * * Parameters: * fls_bufno NAND flash internal buffer number * fls_id0 first 32 bits of the flash ID (return value) * fls_id1 second 32 bits of the flash ID (return value) */ void nfc_read_flash_id(uint8 flash_bufno, uint32* flash_id0, uint32* flash_id1) { /* Clear all status and error bits in the NFC_ISR register */ NFC_ISR |= ( NFC_ISR_WERRCLR_MASK | NFC_ISR_DONECLR_MASK | NFC_ISR_IDLECLR_MASK ); /* Write the NFC_CMD2 register with the command byte and code for a reset */ NFC_CMD2 = NFC_CMD2_BYTE1(READ_ID_CMD_BYTE) | NFC_CMD2_CODE(NFC_READ_ID_CMD_CODE) | NFC_CMD2_BUFNO(flash_bufno); /* Set Start Bit to send command to the NAND flash */ NFC_CMD2 |= NFC_CMD2_BUSY_START_MASK; /* Wait for start/busy bit to clear indicating command is done */ while (NFC_CMD2 & NFC_CMD2_BUSY_START_MASK); /* Load the flash ID values into fls_id0 and fls_id1 */ *((vuint32 *)(flash_id0)) = NFC_SR1; *((vuint32 *)(flash_id1)) = NFC_SR2; }
uint_32 nfc_write_phy_page_raw ( /* [IN] the NAND flash information */ IO_NANDFLASH_WL_STRUCT_PTR nandflash_ptr, /* [IN] where to copy data from */ uchar_ptr from_ptr, /* [IN] the first page to write */ uint_32 phy_page_number, /* [IN] the amount of pages to write */ uint_32 page_count ) { /* Body */ uint_32 result = NANDFLASHERR_TIMEOUT; uint_32 count1, count2; uint_32 row, col, num_ecc_bytes; boolean swap = FALSE; uint_32 cfg_bck; NFC_MemMapPtr nfc_ptr; if (nandflash_ptr->CORE_NANDFLASH.WRITE_PROTECT) { (*nandflash_ptr->CORE_NANDFLASH.WRITE_PROTECT)(&nandflash_ptr->CORE_NANDFLASH, FALSE); }/* Endif */ /* Get the pointer to nfc registers structure */ nfc_ptr = (NFC_MemMapPtr)_bsp_get_nfc_address(); /* Set the ECCMODE to 0 - ECC bypass */ cfg_bck = nfc_ptr->CFG; nfc_ptr->CFG &= ~(NFC_CFG_ECCMODE(7)); /* Reset the swap register */ nfc_ptr->SWAP = NFC_SWAP_ADDR1(0x7FF) | NFC_SWAP_ADDR2(0x7FF); for (count1 = phy_page_number; count1 < (phy_page_number + page_count); count1++) { num_ecc_bytes = NANDFLASH_ECC_SIZE_TO_NUM_BYTES_CONV(nandflash_ptr->CORE_NANDFLASH.ECC_SIZE); row = count1; col =0; if(nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->WIDTH == 16) col = col/2; /* Copy one virtual page into the SRAM buffer #0 */ for ( count2 = 0; count2 < (nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->PHY_PAGE_SIZE + nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->SPARE_AREA_SIZE); count2++ ) { // nfc_ptr->SRAM_B0[count2] = *(from_ptr + count2); NFC_SRAM_B0_REG(nfc_ptr, count2) = *(from_ptr + count2); } nfc_ptr->CMD1 = NFC_CMD1_BYTE2(NANDFLASH_CMD_PAGE_PROGRAM_CYCLE2) | NFC_CMD1_BYTE3(NANDFLASH_CMD_READ_STATUS); nfc_ptr->CMD2 = NFC_CMD2_BYTE1(NANDFLASH_CMD_PAGE_PROGRAM_CYCLE1) | NFC_CMD2_CODE(0x7FD8) | NFC_CMD2_BUFNO(0); nfc_ptr->CAR = col & 0xFFFF; nfc_ptr->RAR = NFC_RAR_CS0_MASK | NFC_RAR_RB0_MASK | (row & 0xFFFFFF); nfc_ptr->SECSZ = nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->PHY_PAGE_SIZE + nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->SPARE_AREA_SIZE ; nfc_ptr->ISR |= (NFC_ISR_DONECLR_MASK | NFC_ISR_DONEEN_MASK | NFC_ISR_IDLECLR_MASK | NFC_ISR_IDLEEN_MASK); /* Start command execution */ nfc_ptr->CMD2 |= NFC_CMD2_BUSY_START_MASK; for (count2 = 0; count2 <= MAX_WAIT_COMMAND; count2++) { if (nfc_ptr->ISR & NFC_ISR_IDLE_MASK) { if (nfc_ptr->SR2 & NANDFLASH_STATUS_ERR) { result = NANDFLASHERR_WRITE_FAILED; goto exit; } else { result = NANDFLASHERR_NO_ERROR; } break; } } from_ptr += nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->PHY_PAGE_SIZE; } exit: if (nandflash_ptr->CORE_NANDFLASH.WRITE_PROTECT) { (*nandflash_ptr->CORE_NANDFLASH.WRITE_PROTECT)(&nandflash_ptr->CORE_NANDFLASH, TRUE); }/* Endif */ nfc_ptr->CFG = cfg_bck; return(result); } /* Endbody */
uint_32 nfc_read_phy_page_raw ( /* [IN] the NAND flash information */ IO_NANDFLASH_WL_STRUCT_PTR nandflash_ptr, /* [OUT} where to copy data to */ uchar_ptr to_ptr, /* [IN] the page to read */ uint_32 phy_page_number, /* [IN] the amount of pages to read */ uint_32 page_count ) { /* Body */ uint_32 result = NANDFLASHERR_TIMEOUT; uint_32 count1, count2, count3; uint_32 output_offset = 0; uint_32 row, col; uint_32 num_ecc_bytes; uint_32 count, cfg_bck; NFC_MemMapPtr nfc_ptr; /* Get the pointer to nfc registers structure */ nfc_ptr = (NFC_MemMapPtr)_bsp_get_nfc_address(); /* Set the ECCMODE to 0 - ECC bypass */ cfg_bck = nfc_ptr->CFG; nfc_ptr->CFG &= ~(NFC_CFG_ECCMODE(7)); /* Do not write ECC Status to SRAM */ nfc_ptr->CFG &= ~(NFC_CFG_ECCSRAM_MASK); /* Reset the swap register */ nfc_ptr->SWAP = NFC_SWAP_ADDR1(0x7FF) | NFC_SWAP_ADDR2(0x7FF); for (count1 = phy_page_number; count1 < (phy_page_number + page_count); count1++) { num_ecc_bytes = NANDFLASH_ECC_SIZE_TO_NUM_BYTES_CONV(nandflash_ptr->CORE_NANDFLASH.ECC_SIZE); row = count1; /* Read from begin of physical page */ col = 0; /* Is the bad block byte(s) about to be re-written? */ nfc_ptr->CMD1 = NFC_CMD1_BYTE2(NANDFLASH_CMD_PAGE_READ_CYCLE2); nfc_ptr->CMD2 = NFC_CMD2_BYTE1(NANDFLASH_CMD_PAGE_READ_CYCLE1) | NFC_CMD2_CODE(0x7EE0) | NFC_CMD2_BUFNO(1); nfc_ptr->CAR = col & 0xFFFF; nfc_ptr->RAR = NFC_RAR_CS0_MASK | NFC_RAR_RB0_MASK | (row & 0xFFFFFF); nfc_ptr->SECSZ = nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->PHY_PAGE_SIZE + nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->SPARE_AREA_SIZE ; nfc_ptr->ISR |= (NFC_ISR_DONECLR_MASK | NFC_ISR_DONEEN_MASK | NFC_ISR_IDLECLR_MASK | NFC_ISR_IDLEEN_MASK); /* Start command execution */ nfc_ptr->CMD2 |= NFC_CMD2_BUSY_START_MASK; for (count2 = 0; count2 <= MAX_WAIT_COMMAND; count2++) { if (nfc_ptr->ISR & NFC_ISR_IDLE_MASK) { for(count3 = 0; count3 < (nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->PHY_PAGE_SIZE + nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->SPARE_AREA_SIZE); count3++) { *(to_ptr + output_offset) = NFC_SRAM_B1_REG(nfc_ptr, count3); output_offset++; } result = NANDFLASHERR_NO_ERROR; break; /* break for (count2 = 0;... */ } /* if nfc_ptr->ISR & NFC_ISR_IDLE */ } } /* for (count1 = phy_page_number */ nfc_ptr->CFG = cfg_bck; return(result); } /* Endbody */
uint_32 nfc_write_page_with_metadata ( /* [IN] the NAND flash information */ IO_NANDFLASH_WL_STRUCT_PTR nandflash_ptr, /* [IN] where to copy data from */ uchar_ptr data_from_ptr, /* [IN] where to copy metadata from */ uchar_ptr metadata_from_ptr, /* [IN] the first page to write */ uint_32 page_number, /* [IN] the amount of pages to write */ uint_32 page_count ) { /* Body */ uint_32 result = NANDFLASHERR_TIMEOUT; uint_32 count1, count2; uint_32 row, col, num_ecc_bytes, num_metadata_bytes; boolean swap = FALSE; uint_32 output_offset = 0; uint_32 output_metadata_offset = 0; uint_32 real_virt_page_offset; NFC_MemMapPtr nfc_ptr; if (nandflash_ptr->CORE_NANDFLASH.WRITE_PROTECT) { (*nandflash_ptr->CORE_NANDFLASH.WRITE_PROTECT)(&nandflash_ptr->CORE_NANDFLASH, FALSE); } /* Endif */ num_ecc_bytes = NANDFLASH_ECC_SIZE_TO_NUM_BYTES_CONV(nandflash_ptr->CORE_NANDFLASH.ECC_SIZE); num_metadata_bytes = nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->SPARE_AREA_SIZE/nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO - num_ecc_bytes; /* Get the pointer to nfc registers structure */ nfc_ptr = (NFC_MemMapPtr)_bsp_get_nfc_address(); for (count1 = page_number; count1 < (page_number + page_count); count1++) { /* Calculate physical page address */ row = count1/nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO; real_virt_page_offset = nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO - 1 - (count1 - (row * nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO)); /* Calculate byte offset in this physical page */ /* For preserve bad marking block address, we writes all pages in reserved order. * Virtual page 0 <-> write physically in Virtual page 3 * Virtual page 1 <-> write physically in Virtual page 2 */ col = real_virt_page_offset *(nandflash_ptr->CORE_NANDFLASH.VIRTUAL_PAGE_SIZE + num_metadata_bytes + num_ecc_bytes); /* If the last virtual page of the first or the second physical page is about to be written the swapping needs to be switched on due to the bad block marking */ count2 = count1 % ((nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->BLOCK_SIZE / nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->PHY_PAGE_SIZE) * nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO); swap = ((count2 == (0)) || (count2 == (nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO))); if(swap) { nfc_ptr->SWAP = NFC_SWAP_ADDR1(nfc_swap_addr1_with_metadata) | NFC_SWAP_ADDR2(nfc_swap_addr2); } else { nfc_ptr->SWAP = NFC_SWAP_ADDR1(0x7FF) | NFC_SWAP_ADDR2(0x7FF); } if(nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->WIDTH == 16) col = col/2; /* Copy one virtual page data into the SRAM buffer #0 */ for ( count2 = 0; count2 < (nandflash_ptr->CORE_NANDFLASH.VIRTUAL_PAGE_SIZE); count2++ ) { NFC_SRAM_B0_REG(nfc_ptr, count2) = *(data_from_ptr + output_offset); output_offset++; } NFC_LOG("nfc_write_page_with_metadata: copy %d from page DATA to SRAM \n", count2); /* Copy one virtual page metadata into the SRAM buffer #0 */ for ( count2 = nandflash_ptr->CORE_NANDFLASH.VIRTUAL_PAGE_SIZE; count2 < (nandflash_ptr->CORE_NANDFLASH.VIRTUAL_PAGE_SIZE + num_metadata_bytes); count2++) { NFC_SRAM_B0_REG(nfc_ptr, count2) = *(metadata_from_ptr + output_metadata_offset); output_metadata_offset++; } NFC_LOG("nfc_write_page_with_metadata: copy %d from page METADATA to SRAM \n", count2 - nandflash_ptr->CORE_NANDFLASH.VIRTUAL_PAGE_SIZE); nfc_ptr->CMD1 = NFC_CMD1_BYTE2(NANDFLASH_CMD_PAGE_PROGRAM_CYCLE2) | NFC_CMD1_BYTE3(NANDFLASH_CMD_READ_STATUS); nfc_ptr->CMD2 = NFC_CMD2_BYTE1(NANDFLASH_CMD_PAGE_PROGRAM_CYCLE1) | NFC_CMD2_CODE(0x7FD8) | NFC_CMD2_BUFNO(0); nfc_ptr->CAR = col & 0xFFFF; nfc_ptr->RAR = NFC_RAR_CS0_MASK | NFC_RAR_RB0_MASK | (row & 0xFFFFFF); nfc_ptr->SECSZ = (nandflash_ptr->CORE_NANDFLASH.VIRTUAL_PAGE_SIZE)+ num_metadata_bytes + num_ecc_bytes; /* For 16-bit data width flash devices, only odd SIZE is supported */ if((nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->WIDTH == 16) && !(nfc_ptr->SECSZ % 2)) nfc_ptr->SECSZ += 1; NFC_LOG("nfc_write_page_with_metadata: issue a WRITE cmd w/ SECTZ=%d at COL*2=%d page %d\n", nfc_ptr->SECSZ, col*2, count1); nfc_ptr->ISR |= (NFC_ISR_DONECLR_MASK | NFC_ISR_DONEEN_MASK | NFC_ISR_IDLECLR_MASK | NFC_ISR_IDLEEN_MASK); /* Start command execution */ nfc_ptr->CMD2 |= NFC_CMD2_BUSY_START_MASK; for (count2 = 0; count2 <= MAX_WAIT_COMMAND; count2++) { if (nfc_ptr->ISR & NFC_ISR_IDLE_MASK) { if (nfc_ptr->SR2 & NANDFLASH_STATUS_ERR) { result = NANDFLASHERR_WRITE_FAILED; goto exit; } else { result = NANDFLASHERR_NO_ERROR; } break; } } } exit: if (nandflash_ptr->CORE_NANDFLASH.WRITE_PROTECT) { (*nandflash_ptr->CORE_NANDFLASH.WRITE_PROTECT)(&nandflash_ptr->CORE_NANDFLASH, TRUE); }/* Endif */ nfc_dump_buff(data_from_ptr, output_offset, "Write Page Buffer"); nfc_dump_buff(metadata_from_ptr, output_metadata_offset, "Write Page Metadata Buffer"); return(result); } /* Endbody */
uint_32 nfc_read_page_metadata ( /* [IN] the NAND flash information */ IO_NANDFLASH_WL_STRUCT_PTR nandflash_ptr, /* [OUT} where to copy data to */ uchar_ptr to_ptr, /* [IN] the page to read */ uint_32 page_number, /* [IN] the amount of pages to read */ uint_32 page_count ) { /* Body */ uint_32 result = NANDFLASHERR_TIMEOUT; uint_32 count1, count2, count3; uint_32 output_offset = 0; boolean swap = FALSE; uint_32 row, col, num_ecc_bytes, real_virt_page_offset ; uint_32 num_metadata_bytes; uint_32 cfg_bck; NFC_MemMapPtr nfc_ptr; num_ecc_bytes = NANDFLASH_ECC_SIZE_TO_NUM_BYTES_CONV(nandflash_ptr->CORE_NANDFLASH.ECC_SIZE); num_metadata_bytes = nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->SPARE_AREA_SIZE/nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO - num_ecc_bytes; /* Get the pointer to nfc registers structure */ nfc_ptr = (NFC_MemMapPtr)_bsp_get_nfc_address(); /* Set the ECCMODE to 0 - ECC bypass */ cfg_bck = nfc_ptr->CFG; nfc_ptr->CFG &= ~(NFC_CFG_ECCMODE(7)); /* Do not write ECC Status to SRAM */ nfc_ptr->CFG &= ~(NFC_CFG_ECCSRAM_MASK); /* Reset the swap register */ nfc_ptr->SWAP = NFC_SWAP_ADDR1(0x7FF) | NFC_SWAP_ADDR2(0x7FF); for (count1 = page_number; count1 < (page_number + page_count); count1++) { row = count1/nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO; real_virt_page_offset = nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO - 1 - (count1 - (row * nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO)); /* Calculate byte offset in this physical page */ /* For preserve bad marking block address, we writes all pages in reserved order. * Virtual page 0 <-> write physically in Virtual page 3 * Virtual page 1 <-> write physically in Virtual page 2 */ col = real_virt_page_offset *(nandflash_ptr->CORE_NANDFLASH.VIRTUAL_PAGE_SIZE + num_metadata_bytes + num_ecc_bytes);row = count1/nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO; real_virt_page_offset = nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO - 1 - (count1 - (row * nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO)); /* Calculate byte offset in this physical page */ /* For preserve bad marking block address, we writes all pages in reserved order. * Virtual page 0 <-> write physically in Virtual page 3 * Virtual page 1 <-> write physically in Virtual page 2 */ col = real_virt_page_offset *(nandflash_ptr->CORE_NANDFLASH.VIRTUAL_PAGE_SIZE + num_metadata_bytes + num_ecc_bytes); col += nandflash_ptr->CORE_NANDFLASH.VIRTUAL_PAGE_SIZE; /* Is the bad block byte(s) about to be re-written? */ count2 = count1 % ((nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->BLOCK_SIZE / nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->PHY_PAGE_SIZE) * nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO); swap = ((count2 == (0)) || (count2 == (nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO))); /* If the last virtual page of the first or the second physical page is about to be read the virtual page needs to be enlarged by 8 bytes and swapping switched on due to the bad block marking */ if(swap) { /* Here we are read MD from page MD swapped * * -> we need to calculate to real MD of this * * swapped page */ col -= ( nfc_swap_addr2 - nfc_swap_addr1_with_metadata ) * 8; } if(nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->WIDTH == 16) col = col/2; nfc_ptr->CMD1 = NFC_CMD1_BYTE2(NANDFLASH_CMD_PAGE_READ_CYCLE2); nfc_ptr->CMD2 = NFC_CMD2_BYTE1(NANDFLASH_CMD_PAGE_READ_CYCLE1) | NFC_CMD2_CODE(0x7EE0) | NFC_CMD2_BUFNO(1); nfc_ptr->CAR = col & 0xFFFF; nfc_ptr->RAR = NFC_RAR_CS0_MASK | NFC_RAR_RB0_MASK | (row & 0xFFFFFF); /* Calculate metadata size for each page (exclude ECC size), * since SPARE_ARE_SIZE is total spare size for each Physical page */ nfc_ptr->SECSZ = num_metadata_bytes +num_ecc_bytes; /* For 16-bit data width flash devices, only odd SIZE is supported */ if((nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->WIDTH == 16) && !(nfc_ptr->SECSZ % 2)) nfc_ptr->SECSZ += 1; nfc_ptr->ISR |= (NFC_ISR_DONECLR_MASK | NFC_ISR_DONEEN_MASK | NFC_ISR_IDLECLR_MASK | NFC_ISR_IDLEEN_MASK); NFC_LOG("nfc_read_page_metadata: issue a READ cmd w/ col =%d page %d\n", col, count1); /* Start command execution */ nfc_ptr->CMD2 |= NFC_CMD2_BUSY_START_MASK; for (count2 = 0; count2 <= MAX_WAIT_COMMAND; count2++) { if (nfc_ptr->ISR & NFC_ISR_IDLE_MASK) { for(count3 = 0; count3 < (num_metadata_bytes); count3++) { *(to_ptr + output_offset) = NFC_SRAM_B1_REG(nfc_ptr, count3); output_offset++; } result = NANDFLASHERR_NO_ERROR; break; } } } nfc_ptr->CFG = cfg_bck; return(result); } /* Endbody */
uint_32 nfc_read_page_with_metadata ( /* [IN] the NAND flash information */ IO_NANDFLASH_WL_STRUCT_PTR nandflash_ptr, /* [OUT] where to copy data to */ uchar_ptr to_data_ptr, /* [OUT] where to copy metadata to */ uchar_ptr to_metadata_ptr, /* [IN] the page to read */ uint_32 page_number, /* [IN] the amount of pages to read */ uint_32 page_count ) { /* Body */ uint_32 result = NANDFLASHERR_TIMEOUT; uint_32 count1, count2, count3, real_virt_page_offset; uint_32 data_output_offset = 0, metadata_output_offset = 0; boolean ecc_corrected = FALSE, swap = FALSE; uint_32 row, col, num_ecc_bytes, num_metadata_bytes; uint_32 cfg_bck; NFC_MemMapPtr nfc_ptr; uint_8 ecc_num_bit_correct; num_ecc_bytes = NANDFLASH_ECC_SIZE_TO_NUM_BYTES_CONV(nandflash_ptr->CORE_NANDFLASH.ECC_SIZE); num_metadata_bytes = nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->SPARE_AREA_SIZE/nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO - num_ecc_bytes; /* Get the pointer to nfc registers structure */ nfc_ptr = (NFC_MemMapPtr)_bsp_get_nfc_address(); /* back up current nfc_ptr then change the ECC status position in output read buffer */ cfg_bck = nfc_ptr->CFG; nfc_ptr->CFG = (nfc_ptr->CFG & (~NFC_CFG_ECCAD(0xFFFF))) | NFC_CFG_ECCAD(( (nandflash_ptr->CORE_NANDFLASH.VIRTUAL_PAGE_SIZE +num_metadata_bytes) / 8) + 1); for (count1 = page_number; count1 < (page_number + page_count); count1++) { /* Calculate physical page address */ row = count1/nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO; real_virt_page_offset = nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO - 1 - (count1 - (row * nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO)); /* Calculate byte offset in this physical page */ /* For preserve bad marking block address, we writes all pages in reserved order. * Virtual page 0 <-> write physically in Virtual page 3 * Virtual page 1 <-> write physically in Virtual page 2 */ col = real_virt_page_offset *(nandflash_ptr->CORE_NANDFLASH.VIRTUAL_PAGE_SIZE + num_metadata_bytes + num_ecc_bytes); /* If the last virtual page of the first or the second physical page is about to be written the swapping needs to be switched on due to the bad block marking */ count2 = count1 % ((nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->BLOCK_SIZE / nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->PHY_PAGE_SIZE) * nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO); swap = ((count2 == (0)) || (count2 == (nandflash_ptr->CORE_NANDFLASH.PHY_PAGE_SIZE_TO_VIRTUAL_PAGE_SIZE_RATIO))); if(nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->WIDTH == 16) col = col/2; nfc_ptr->CMD1 = NFC_CMD1_BYTE2(NANDFLASH_CMD_PAGE_READ_CYCLE2); nfc_ptr->CMD2 = NFC_CMD2_BYTE1(NANDFLASH_CMD_PAGE_READ_CYCLE1) | NFC_CMD2_CODE(0x7EE0) | NFC_CMD2_BUFNO(1); nfc_ptr->CAR = col & 0xFFFF; nfc_ptr->RAR = NFC_RAR_CS0_MASK | NFC_RAR_RB0_MASK | (row & 0xFFFFFF); nfc_ptr->SECSZ = (nandflash_ptr->CORE_NANDFLASH.VIRTUAL_PAGE_SIZE)+ num_metadata_bytes +num_ecc_bytes ; /* For 16-bit data width flash devices, only odd SIZE is supported */ if((nandflash_ptr->CORE_NANDFLASH.NANDFLASH_INFO_PTR->WIDTH == 16) && !(nfc_ptr->SECSZ % 2)) nfc_ptr->SECSZ += 1; /* If the last virtual page of the first or the second physical page is about to be read the virtual page needs to be enlarged by 8 bytes and swapping switched on due to the bad block marking */ if(swap) { nfc_ptr->SWAP = NFC_SWAP_ADDR1(nfc_swap_addr1_with_metadata) | NFC_SWAP_ADDR2(nfc_swap_addr2); } else { nfc_ptr->SWAP = NFC_SWAP_ADDR1(0x7FF) | NFC_SWAP_ADDR2(0x7FF); } NFC_LOG("nfc_read_page_with_metadata: issue a READ cmd w/ SECTZ=%d at COL*2=%d, page=%d\n", nfc_ptr->SECSZ, col*2, count1); nfc_ptr->ISR |= (NFC_ISR_DONECLR_MASK | NFC_ISR_DONEEN_MASK | NFC_ISR_IDLECLR_MASK | NFC_ISR_IDLEEN_MASK); /* Start command execution */ nfc_ptr->CMD2 |= NFC_CMD2_BUSY_START_MASK; for (count2 = 0; count2 <= MAX_WAIT_COMMAND; count2++) { if (nfc_ptr->ISR & NFC_ISR_IDLE_MASK) { if ( nandflash_ptr->CORE_NANDFLASH.ECC_SIZE == 0) { if (nfc_ptr->SR2 & NANDFLASH_STATUS_ERR) { result = NANDFLASHERR_ECC_FAILED; break; /* break to out of for MAX_WAIT_COMMAND*/ } } else /* if nandflash_ptr->ECC_SIZE == 0)*/ { if((*(uint_32*)&NFC_SRAM_B1_REG(nfc_ptr, nandflash_ptr->CORE_NANDFLASH.VIRTUAL_PAGE_SIZE + num_metadata_bytes + (num_ecc_bytes + 4))) & NFC_ECC_STATUS_CORFAIL) { /* ECC Fix FAILED */ result = NANDFLASHERR_ECC_FAILED; break; } else { if((*(uint_32*)&NFC_SRAM_B1_REG(nfc_ptr, nandflash_ptr->CORE_NANDFLASH.VIRTUAL_PAGE_SIZE + num_metadata_bytes + (num_ecc_bytes + 4))) & NFC_ECC_STATUS_CORFAIL) { ecc_corrected = TRUE; ecc_num_bit_correct = (*(uint_32*)&NFC_SRAM_B1_REG(nfc_ptr, nandflash_ptr->CORE_NANDFLASH.VIRTUAL_PAGE_SIZE + num_metadata_bytes + (num_ecc_bytes + 4))) & NFC_ECC_STATUS_ERROR_COUNT; result = NANDFLASHERR_ECC_CORRECTED; } else /* ECC is success, we donot need to correct any bits */ { result = NANDFLASHERR_NO_ERROR; } } } /* if nfc_ptr->ISR & NFC_ISR_IDLE*/ /* In case we catch ECC_CORRECTED or NO_ERROR, we still copy data from SRAM -> requested buffer */ /* Copy Page DATA from SRAM buffer to to_data_ptr */ for(count3 = 0; count3 < (nandflash_ptr->CORE_NANDFLASH.VIRTUAL_PAGE_SIZE); count3++) { *(to_data_ptr + data_output_offset) = NFC_SRAM_B1_REG(nfc_ptr, count3); data_output_offset++; } NFC_LOG("nfc_read_page_with_metadata: copy %d from page DATA to SRAM \n", count3); /* Copy Page METADATA from SRAM buffer to to_data_ptr */ for(count3 = nandflash_ptr->CORE_NANDFLASH.VIRTUAL_PAGE_SIZE; count3 < (nandflash_ptr->CORE_NANDFLASH.VIRTUAL_PAGE_SIZE + num_metadata_bytes); count3++) { *(to_metadata_ptr + metadata_output_offset) = NFC_SRAM_B1_REG(nfc_ptr, count3); metadata_output_offset++; } NFC_LOG("nfc_read_page_with_metadata: copy %d from page METADATA to SRAM \n", count3-nandflash_ptr->CORE_NANDFLASH.VIRTUAL_PAGE_SIZE); break; } /* if nfc_ptr->ISR & IDLE */ } /* for MAX_WAIT_COMMAND */ /* Everytime we catch error even ECC_CORRECTED, just quit */ if (NANDFLASHERR_NO_ERROR != result ) { break; /* break out of for count1=page_number */ } } if (ecc_corrected) { if (ecc_num_bit_correct >= _ecc_mode_threshold[curr_ecc_mode]) result = NANDFLASHERR_ECC_CORRECTED_EXCEED_THRESHOLD; else result = NANDFLASHERR_ECC_CORRECTED; } nfc_dump_buff(to_data_ptr, data_output_offset, "Read Page Buffer"); nfc_dump_buff(to_metadata_ptr, metadata_output_offset, "Read Page Metadata Buffer"); /* Restore nfc config */ nfc_ptr->CFG = cfg_bck ; return(result); } /* Endbody */