/* 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); }
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_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 */