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