/* * nand.c - NAND flash functions * * Copyright (C) 2008 Hugo Villeneuve * * Based on TI DaVinci Flash and Boot Utilities, original copyright follows: * Copyright 2008 Texas Instruments, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "common.h" #include "davinci.h" #include "util.h" #include "uart.h" #include "gpio.h" #include "nand.h" /* BUS width defines */ #define BUS_8BIT 0x01 #define BUS_16BIT 0x02 #define BUS_32BIT 0x04 /* NAND flash addresses */ #define NAND_DATA_OFFSET 0x00 #define NAND_ALE_OFFSET 0x08 #define NAND_CLE_OFFSET 0x10 #define NAND_TIMEOUT 50000 /*us*/ /* NAND flash commands */ #define NAND_LO_PAGE 0x00 #define NAND_HI_PAGE 0x01 #define NAND_LOCK 0x2A #define NAND_UNLOCK_START 0x23 #define NAND_UNLOCK_END 0x24 #define NAND_READ_30H 0x30 #define NAND_EXTRA_PAGE 0x50 #define NAND_RDID 0x90 #define NAND_RDIDADD 0x00 #define NAND_RESET 0xFF #define NAND_PGRM_START 0x80 #define NAND_PGRM_END 0x10 #define NAND_RDY 0x40 #define NAND_PGM_FAIL 0x01 #define NAND_BERASEC1 0x60 #define NAND_BERASEC2 0xD0 #define NAND_STATUS 0x70 /* Status output */ #define NAND_NANDFSR_READY 0x01 #define NAND_STATUS_WRITEREADY 0xC0 #define NAND_STATUS_ERROR 0x01 #define NAND_STATUS_BUSY 0x40 #define UNKNOWN_NAND 0xFF /* Unknown device id */ /* Gives the page size in bytes without the spare bytes */ #define NANDFLASH_PAGESIZE(x) ((x >> 8) << 8) union flash_data { uint8_t c; uint16_t w; uint32_t l; }; union flash_ptr { volatile uint8_t *cp; volatile uint16_t *wp; volatile uint32_t *lp; }; struct nand_dev_infos_t { uint8_t id; /* Device ID */ uint16_t num_blocks; /* Number of blocks */ uint8_t pages_per_block; /* Number of pages per block */ uint16_t bytes_per_page; /* Number of bytes per page (with spare) */ }; struct nand_info_t { uint32_t base_addr; /* Base address of NAND CS memory space. */ int bus_width; /* Bus width: 0 = 8 bits, 1 = 16 bits */ int id; /* Index into nand_dev_infos_t array. */ int num_blocks; /* Number of blocks */ int pages_per_block; /* Number of pages per block */ int bytes_per_page; /* Number of bytes per page (with spare) */ int num_cab; /* Number of Column address cycles */ int num_rab; /* Number of Row address cycles */ uint32_t ecc_mask; /* Mask for ECC register */ int large_page; /* True if page size >= 2048 bytes */ int ecc_index; /* ECC position is different for small and * large page devices. */ int chunk_size; /* Always read/write in 512 bytes chunk max. * This will be set based on page size. */ int spare_bytes; /* Number of spare area bytes per page. */ int blk_addr_shift; /* Number of bits by which to shift block address */ int page_addr_shift; /* Number of bits by which to shift page address */ int cs_offset; /* * Chip-select offset: * 0 = CS2 space * 1 = CS3 space * 2 = CS4 space * 3 = CS5 space */ }; /* Buffer for storing data read from NAND flash */ static uint8_t read_buf[MAX_PAGE_SIZE] __attribute__((section(".ddrram"))); /* Symbol from linker script */ extern uint32_t __NANDFlash; /* structure for holding details about the NAND device itself */ static volatile struct nand_info_t nand_info; /* Table of ROM supported NAND devices */ static const struct nand_dev_infos_t nand_dev_infos[] = { /* id, num_blocks, pages_per_block, bytes_per_page */ {0x6E, 256, 16, 256+8}, /* 1 MB */ {0x68, 256, 16, 256+8}, /* 1 MB */ {0xEC, 256, 16, 256+8}, /* 1 MB */ {0xE8, 256, 16, 256+8}, /* 1 MB */ {0xEA, 512, 16, 256+8}, /* 2 MB */ {0xE3, 512, 16, 512+16}, /* 4 MB */ {0xE5, 512, 16, 512+16}, /* 4 MB */ {0xE6, 1024, 16, 512+16}, /* 8 MB */ {0x39, 1024, 16, 512+16}, /* 8 MB */ {0x6B, 1024, 16, 512+16}, /* 8 MB */ {0x73, 1024, 32, 512+16}, /* 16 MB */ {0x33, 1024, 32, 512+16}, /* 16 MB */ {0x75, 2048, 32, 512+16}, /* 32 MB */ {0x35, 2048, 32, 512+16}, /* 32 MB */ {0x43, 1024, 32, 512+16}, /* 16 MB 0x1243 */ {0x45, 2048, 32, 512+16}, /* 32 MB 0x1245 */ {0x53, 1024, 32, 512+16}, /* 16 MB 0x1253 */ {0x55, 2048, 32, 512+16}, /* 32 MB 0x1255 */ {0x36, 4096, 32, 512+16}, /* 64 MB */ {0x46, 4096, 32, 512+16}, /* 64 MB 0x1346 */ {0x56, 4096, 32, 512+16}, /* 64 MB 0x1356 */ {0x76, 4096, 32, 512+16}, /* 64 MB */ {0x74, 8192, 32, 512+16}, /* 128 MB 0x1374 */ {0x79, 8192, 32, 512+16}, /* 128 MB */ {0x71, 16384, 32, 512+16}, /* 256 MB */ {0xF1, 1024, 64, 2048+64}, /* 128 MB - Big Block */ {0xA1, 1024, 64, 2048+64}, /* 128 MB - Big Block */ {0xAA, 2048, 64, 2048+64}, /* 256 MB - Big Block */ {0xDA, 2048, 64, 2048+64}, /* 256 MB - Big Block */ {0xDC, 4096, 64, 2048+64}, /* 512 MB - Big Block */ {0xAC, 4096, 64, 2048+64}, /* 512 MB - Big Block */ {0xB1, 1024, 64, 2048+64}, /* 128 MB - Big Block */ {0xC1, 1024, 64, 2048+64}, /* 128 MB - Big Block */ {0xD3, 4096, 64, 2048+64}, /* 512 MB - Big Block */ {0x00, 0, 0, 0} /* Indicate end of table */ }; static volatile uint8_t * flash_make_addr(uint32_t baseAddr, uint32_t offset) { return (volatile uint8_t *) (baseAddr + offset); } static void flash_write_data(uint32_t offset, uint32_t data) { volatile union flash_ptr addr; union flash_data dataword; dataword.l = data; addr.cp = flash_make_addr(nand_info.base_addr, offset); switch (nand_info.bus_width) { case BUS_8BIT: *addr.cp = dataword.c; break; case BUS_16BIT: *addr.wp = dataword.w; break; } } static void flash_write_cmd(uint32_t cmd) { flash_write_data(NAND_CLE_OFFSET, cmd); } static void flash_write_addr(uint32_t addr) { flash_write_data(NAND_ALE_OFFSET, addr); } static void flash_write_bytes(const uint8_t *src, uint32_t numBytes) { volatile union flash_ptr destAddr, srcAddr; uint32_t i; srcAddr.cp = (volatile uint8_t *) src; destAddr.cp = flash_make_addr(nand_info.base_addr, NAND_DATA_OFFSET); switch (nand_info.bus_width) { case BUS_8BIT: for (i = 0; i < numBytes; i++) *destAddr.cp = *srcAddr.cp++; break; case BUS_16BIT: for (i = 0; i < (numBytes >> 1); i++) *destAddr.wp = *srcAddr.wp++; break; } } static void flash_write_addr_bytes(uint32_t numAddrBytes, uint32_t addr) { uint32_t i; for (i = 0; i < numAddrBytes; i++) flash_write_addr((addr >> (8*i)) & 0xff); } static void flash_write_row_addr_bytes(uint32_t block, uint32_t page) { uint32_t row_addr; row_addr = (block << (nand_info.blk_addr_shift - nand_info.page_addr_shift)) | page; flash_write_addr_bytes(nand_info.num_rab, row_addr); } static void flash_write_addr_cycles(uint32_t block, uint32_t page) { flash_write_addr_bytes(nand_info.num_cab, 0x00000000); flash_write_row_addr_bytes(block, page); } static uint32_t flash_read_data(void) { volatile union flash_ptr addr; union flash_data cmdword; cmdword.l = 0x0; addr.cp = flash_make_addr(nand_info.base_addr, NAND_DATA_OFFSET); switch (nand_info.bus_width) { case BUS_8BIT: cmdword.c = *addr.cp; break; case BUS_16BIT: cmdword.w = *addr.wp; break; } return cmdword.l; } static void flash_read_bytes(uint8_t *dest, uint32_t numBytes) { volatile union flash_ptr destAddr, srcAddr; uint32_t i; destAddr.cp = (volatile uint8_t *) dest; srcAddr.cp = flash_make_addr(nand_info.base_addr, NAND_DATA_OFFSET); switch (nand_info.bus_width) { case BUS_8BIT: for (i = 0; i < numBytes; i++) *destAddr.cp++ = *srcAddr.cp; break; case BUS_16BIT: for (i = 0; i < (numBytes >> 1); i++) *destAddr.wp++ = *srcAddr.wp; break; } } /* Poll bit of NANDFSR to indicate ready */ static int nand_wait_for_ready(uint32_t timeout_us) { uint32_t ready; uint32_t timerStatus; waitloop(200); timer0_start(SYSTEM_CLK_MHZ * timeout_us); do { ready = AEMIF->NANDFSR & NAND_NANDFSR_READY; timerStatus = timer0_status(); } while (!ready && timerStatus); if (timerStatus == 0) { log_info("NAND busy timeout"); return E_FAIL; } return E_PASS; } /* Wait for the status to be ready in NAND register * There were some problems reported in DM320 with Ready/Busy pin * not working with all NANDs. So this check has also been added. */ static int nand_wait_for_status(uint32_t timeout) { volatile uint32_t cnt; uint32_t status; cnt = timeout; do { flash_write_cmd(NAND_STATUS); status = flash_read_data() & (NAND_STATUS_ERROR | NAND_STATUS_BUSY); cnt--; } while ((cnt > 0) && !status); if (cnt == 0) { log_info("NAND status timeout"); return E_FAIL; } return E_PASS; } /* Read the current ECC calculation and restart process */ static uint32_t nand_read_ecc(void) { uint32_t retval; /* Read and mask appropriate (based on CSn space flash is in) * ECC register */ retval = ((uint32_t *)(&(AEMIF->NANDF1ECC)))[nand_info.cs_offset] & nand_info.ecc_mask; waitloop(5); #ifdef NAND_DEBUG uart_send_str("Value read from ECC register: "); uart_send_hexnum(retval, 8); uart_send_lf(); #endif /* Write appropriate bit to start ECC calculations */ AEMIF->NANDFCR |= (1<<(8 + (nand_info.cs_offset))); return retval; } /* Get details of the NAND flash used from the id and the table of NAND * devices. */ static int nand_get_details(uint8_t *out_manID, uint8_t *out_deviceID) { uint32_t manID, deviceID, i, j; /* Issue device read ID command. */ flash_write_cmd(NAND_RDID); flash_write_addr(NAND_RDIDADD); /* Read ID bytes */ manID = flash_read_data() & 0xFF; deviceID = flash_read_data() & 0xFF; j = flash_read_data() & 0xFF; j = flash_read_data() & 0xFF; *out_manID = manID; *out_deviceID = deviceID; uart_send_str(" ID:"); uart_send_hexnum(deviceID, 2); if (nand_info.bus_width == BUS_16BIT) uart_send_str(", 16"); else uart_send_str(", 8"); log_info("-bit bus"); i = 0; while (nand_dev_infos[i].id != 0x00) { if (deviceID == nand_dev_infos[i].id) { nand_info.id = (uint8_t) nand_dev_infos[i].id; nand_info.pages_per_block = nand_dev_infos[i].pages_per_block; nand_info.num_blocks = nand_dev_infos[i].num_blocks; nand_info.bytes_per_page = NANDFLASH_PAGESIZE( nand_dev_infos[i].bytes_per_page); nand_info.spare_bytes = nand_dev_infos[i].bytes_per_page - nand_info.bytes_per_page; /* Configure small or large page device. */ if (nand_info.bytes_per_page >= 2048) { /* Set the large page flag */ nand_info.large_page = true; nand_info.ecc_index = 2; nand_info.chunk_size = 512; /* Limit to 512 bytes */ } else { /* Clear the large page flag */ nand_info.large_page = false; nand_info.ecc_index = 0; nand_info.chunk_size = nand_info.bytes_per_page; } /* Setup address shift values */ j = 0; while ((nand_info.pages_per_block >> j) > 1) j++; nand_info.blk_addr_shift = j; nand_info.page_addr_shift = (nand_info.large_page) ? 16 : 8; nand_info.blk_addr_shift += nand_info.page_addr_shift; /* Set number of column address bytes needed */ nand_info.num_cab = nand_info.page_addr_shift >> 3; j = 0; while ((nand_info.num_blocks >> j) > 1) j++; /* Set number of row address bytes needed */ if ((nand_info.blk_addr_shift + j) <= 24) nand_info.num_rab = 3 - nand_info.num_cab; else if ((nand_info.blk_addr_shift + j) <= 32) nand_info.num_rab = 4 - nand_info.num_cab; else nand_info.num_rab = 5 - nand_info.num_cab; /* Set the ECC bit mask */ if (nand_info.bytes_per_page < 512) nand_info.ecc_mask = 0x07FF07FF; else nand_info.ecc_mask = 0x0FFF0FFF; /* Report informations */ uart_send_str(" Blocks: "); uart_send_hexnum(nand_info.num_blocks, 5); uart_send_str(", Pages/block: "); uart_send_hexnum(nand_info.pages_per_block, 3); uart_send_str(", Bytes per page: "); uart_send_hexnum(nand_info.bytes_per_page, 4); uart_send_lf(); /* Report additional debug informations */ #ifdef NAND_DEBUG uart_send_str(" Page shift: "); uart_send_hexnum(nand_info.page_addr_shift, 2); uart_send_lf(); uart_send_str(" Block shift: "); uart_send_hexnum(nand_info.blk_addr_shift, 2); uart_send_lf(); uart_send_str(" Column address bytes: "); uart_send_hexnum(nand_info.num_cab, 2); uart_send_lf(); uart_send_str(" Row address bytes: "); uart_send_hexnum(nand_info.num_rab, 2); uart_send_lf(); uart_send_str(" ECC mask: "); uart_send_hexnum(nand_info.ecc_mask, 8); uart_send_lf(); #endif return E_PASS; } i++; } /* No match was found for the device ID */ return E_FAIL; } static int nand_set_a1cr(uint8_t manID, uint8_t deviceID) { if (deviceID != 0xA1) { log_info( "Unsupported NAND device" ); return E_FAIL; } switch (manID) { /* ST/Numonyx */ case 0x20: AEMIF->A1CR = 0x1844431C; break; /* Micron */ case 0x2C: AEMIF->A1CR = 0x102442EC; break; /* Spansion */ case 0x01: AEMIF->A1CR = 0x1844437C; break; /* Toshiba */ case 0x98: AEMIF->A1CR = 0x102442DC; break; default: log_info( "Unsupported NAND device" ); return E_FAIL; } return E_PASS; } static void nand_write_spare(uint32_t eccvalue) { uint32_t spare_data[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; /* Place the ECC values where the RBL expects them */ spare_data[nand_info.ecc_index] = eccvalue; /* Write spare bytes infos */ if (nand_info.bytes_per_page == 256) flash_write_bytes((uint8_t *) spare_data, 8); else flash_write_bytes((uint8_t *) spare_data, 16); } /* * RBL-expected layout for large page NAND (ex: 2048 bytes/page): * * DM35x DM644x * ----------------------------- * 512 DATA 2048 DATA * 16 SPARE 64 SPARE * 512 DATA * 16 SPARE * 512 DATA * 16 SPARE * 512 DATA * 16 SPARE * * So for big block NAND devices (bytes per page > 512) on the DM35x, we must * write 512 bytes and write the ECC immediately after that data, and repeat * until all the page is written. */ /* Generic routine to write a page of data to NAND */ static int nand_write_page(uint32_t block, uint32_t page, const uint8_t *src) { uint32_t hw_ecc[4]; /* Maximum of 2048 bytes/page (4 * 512 = 2048) */ uint8_t numWrites, i; numWrites = (nand_info.bytes_per_page >> 9); /* Divide by 512 */ if (numWrites == 0) numWrites++; /* Write program command */ flash_write_cmd(NAND_PGRM_START); /* Write address bytes */ flash_write_addr_cycles(block, page); /* Starting the ECC in the NANDFCR register for CS2 (bit no.8) */ nand_read_ecc(); /* Write data */ for (i = 0; i < numWrites; i++) { /* Write data to page */ flash_write_bytes(src, nand_info.chunk_size); /* Read the ECC value */ hw_ecc[i] = nand_read_ecc(); /* Format ECC */ endian_data(&(hw_ecc[i])); #if defined(DM35x) /* Write spare area */ nand_write_spare(hw_ecc[i]); #endif /* Increment the pointer */ src += nand_info.chunk_size; } #if defined(DM644x) for (i = 0; i < numWrites; i++) { nand_write_spare(hw_ecc[i]); } #endif /* Write program end command */ flash_write_cmd(NAND_PGRM_END); /* Wait for the device to be ready */ if (nand_wait_for_ready(NAND_TIMEOUT) != E_PASS) return E_FAIL; /* Return status check result */ return nand_wait_for_status(NAND_TIMEOUT); } static uint32_t nand_read_spare(void) { uint32_t spare_ecc[4], spare_ecc_temp; /* Read the stored ECC value(s) */ if (nand_info.bytes_per_page == 256) flash_read_bytes((uint8_t *) spare_ecc, 8); else flash_read_bytes((uint8_t *) spare_ecc, 16); spare_ecc_temp = spare_ecc[nand_info.ecc_index]; /* Format ECC */ endian_data(&spare_ecc_temp); return spare_ecc_temp; } /* * GPLv2 code taken from the kernel to correct the bit error. * The content of the ECC register is in the sprue20c.pdf. For * the odd/even there are four bits spare each. The kernel is * shifting this around and it is the easiest just to do the * same. */ static uint32_t squeeze_ecc_bits(uint32_t tmp) { /* Squeeze 4 bytes ECC into 3 bytes by removing RESERVED bits * and shifting. RESERVED bits are 31 to 28 and 15 to 12. */ tmp = (tmp & 0x00000fff) | ((tmp & 0x0fff0000) >> 4); /* Invert so that erased block ECC is correct */ return ~tmp; } static int nand_check_fix( const uint32_t _calc_ecc, const uint32_t _ecc_nand, uint8_t *dat, int size) { uint32_t ecc_nand, ecc_calc; ecc_calc = squeeze_ecc_bits(_calc_ecc); ecc_nand = squeeze_ecc_bits(_ecc_nand); uint32_t diff = ecc_calc ^ ecc_nand; if (diff) { if ((((diff >> 12) ^ diff) & 0xfff) == 0xfff) { /* Correctable error */ if ((diff >> (12 + 3)) < size) { uint8_t find_bit = 1 << ((diff >> 12) & 7); uint32_t find_byte = diff >> (12 + 3); dat[find_byte] ^= find_bit; log_info("Correcting single bit error."); uart_send_str("BYTE="); uart_send_hexnum(find_byte, 8); uart_send_str(" BIT="); uart_send_hexnum(find_bit, 8); uart_send_lf(); return 1; } else { log_info("Too many bit errors:"); uart_send_hexnum(diff >> (12+3), 8); uart_send_lf(); return -1; } } else if (!(diff & (diff - 1))) { /* Single bit ECC error in the ECC itself, nothing to fix */ log_info("Bit error in the spare data. Ignoring"); return 1; } else { /* Uncorrectable error */ log_info("Uncorrectable error"); return -1; } } return 0; } /* Read a page from NAND */ int nand_read_page(uint32_t block, uint32_t page, uint8_t *orig_dest) { uint32_t hw_ecc[4]; uint32_t spare_ecc[4]; uint8_t numReads, i; uint8_t *dest = orig_dest; numReads = (nand_info.bytes_per_page >> 9); /* Divide by 512 */ if (numReads == 0) numReads++; /* Write read command */ flash_write_cmd(NAND_LO_PAGE); /* Write address bytes */ flash_write_addr_cycles(block, page); /* Additional confirm command for big_block devices */ if (nand_info.large_page) flash_write_cmd(NAND_READ_30H); /* Wait for data to be available */ if (nand_wait_for_ready(NAND_TIMEOUT) != E_PASS) return E_FAIL; /* Starting the ECC in the NANDFCR register for CS2(bit no.8) */ nand_read_ecc(); /* Read the page data */ for (i = 0; i < numReads; i++) { /* Read data bytes */ flash_read_bytes(dest, nand_info.chunk_size); /* Read hardware computed ECC */ hw_ecc[i] = nand_read_ecc(); #if defined(DM35x) /* Read spare area ECC */ spare_ecc[i] = nand_read_spare(); #endif /* Increment the pointer */ dest += nand_info.chunk_size; } #if defined(DM644x) for (i = 0; i < numReads; i++) { spare_ecc[i] = nand_read_spare(); } #endif #ifndef NAND_BYPASS_READ_PAGE_ECC_CHECK for (i = 0; i < numReads; i++) { /* Verify ECC values */ if (nand_check_fix(hw_ecc[i], spare_ecc[i], &orig_dest[i * nand_info.chunk_size], nand_info.chunk_size) < 0) { log_info("NAND ECC failure:"); uart_send_str("HW = "); uart_send_hexnum(hw_ecc[i], 8); uart_send_lf(); uart_send_str("SPARE ="); uart_send_hexnum(spare_ecc[i], 8); uart_send_lf(); return E_FAIL; } } #endif /* NAND_BYPASS_READ_PAGE_ECC_CHECK */ /* Return status check result */ return nand_wait_for_status(NAND_TIMEOUT); } /* Verify data written by reading and comparing byte for byte */ static int nand_verify_page(int block, int page, const uint8_t *src) { int i; if (nand_read_page(block, page, read_buf) != E_PASS) return E_FAIL; for (i = 0; i < nand_info.bytes_per_page; i++) { /* Check for data read errors */ if (src[i] != read_buf[i]) { int k = i; uart_send_str("NAND verify page failed at block "); uart_send_hexnum(block, 4); uart_send_str(", page "); uart_send_hexnum(page, 4); uart_send_str(", offset "); uart_send_hexnum(i, 4); uart_send_lf(); for (k = i - 8; k < (i + 20); k += 4) { uart_send_str("offset "); uart_send_hexnum(k, 4); uart_send_str(", ram="); uart_send_hexnum(*((uint32_t *) &src[k]), 8); uart_send_str(", nand="); uart_send_hexnum(*((uint32_t *) &read_buf[k]), 8); uart_send_lf(); } return E_FAIL; } } return E_PASS; } /* NAND Flash unprotect command */ static uint32_t nand_unprotect_blocks(uint32_t startBlkNum, uint32_t blkCnt) { uint32_t endBlkNum; endBlkNum = startBlkNum + blkCnt - 1; uart_send_str("Unprotecting blocks "); uart_send_hexnum(startBlkNum, 4); uart_send_str(" to "); uart_send_hexnum(endBlkNum, 4); uart_send_lf(); /* Do bounds checking */ if (endBlkNum >= nand_info.num_blocks) { log_fail("Invalid last block"); return E_FAIL; } flash_write_cmd(NAND_UNLOCK_START); flash_write_row_addr_bytes(startBlkNum, 0); flash_write_cmd(NAND_UNLOCK_END); flash_write_row_addr_bytes(endBlkNum, 0); return E_PASS; } /* NAND Flash protect command */ static void nand_protect_blocks(void) { log_info("Protecting the entire NAND flash"); flash_write_cmd(NAND_LOCK); } /* NAND Flash erase block function */ static uint32_t nand_erase_blocks(uint32_t startBlkNum, uint32_t blkCnt) { uint32_t i; /* Do bounds checking */ if ((startBlkNum + blkCnt - 1) >= nand_info.num_blocks) return E_FAIL; /* Output info about what we are doing */ uart_send_str("Erasing blocks "); uart_send_hexnum(startBlkNum, 4); uart_send_str(" to "); uart_send_hexnum(startBlkNum + blkCnt - 1, 4); uart_send_lf(); for (i = 0; i < blkCnt; i++) { /* Start erase command */ flash_write_cmd(NAND_BERASEC1); /* Write the row addr bytes only */ flash_write_row_addr_bytes(startBlkNum + i, 0); /* Confirm erase command */ flash_write_cmd(NAND_BERASEC2); /* Wait for the device to be ready */ if (nand_wait_for_ready(NAND_TIMEOUT) != E_PASS) return E_FAIL; /* Verify the op succeeded by reading status from flash */ if (nand_wait_for_status(NAND_TIMEOUT) != E_PASS) return E_FAIL; } return E_PASS; } /* Initialize NAND interface and find the details of the NAND used */ int nand_init(void) { uint32_t width; uint32_t *CSRegs; uint8_t manID, deviceID; log_info("Initializing NAND flash:"); #ifdef NAND_BYPASS_READ_PAGE_ECC_CHECK log_info(" Bypassing ECC checks"); #endif /* NAND_BYPASS_READ_PAGE_ECC_CHECK */ /* Set NAND flash base address */ nand_info.base_addr = (uint32_t) &__NANDFlash; /* Get the cs_offset (can be 0 through 3 - corresponds with CS2 through * CS5) */ nand_info.cs_offset = (nand_info.base_addr >> 25) - 1; /* Setting the nand_width = 0(8 bit NAND) or 1(16 bit NAND). AEMIF CS2 * bus Width is given by the BOOTCFG(bit no.5). */ width = (((SYSTEM->BOOTCFG) & 0x20) >> 5); nand_info.bus_width = (width)?BUS_16BIT:BUS_8BIT; /* Setup AEMIF registers for NAND */ CSRegs = (uint32_t *) &(AEMIF->A1CR); /* Set correct AxCR reg */ CSRegs[nand_info.cs_offset] = 0x3FFFFFFC | width; /* NAND enable for CSx. */ AEMIF->NANDFCR |= (0x1 << (nand_info.cs_offset)); nand_read_ecc(); /* Send reset command to NAND */ flash_write_cmd(NAND_RESET); if (nand_wait_for_ready(NAND_TIMEOUT) != E_PASS) return E_FAIL; if (nand_get_details(&manID, &deviceID) != E_PASS) return E_FAIL; return nand_set_a1cr(manID, deviceID); } static int nand_write_verify_page(int block, int page, const uint8_t *src) { int status; status = nand_write_page(block, page, src); if (status != E_PASS) return E_FAIL; waitloop(200); /* Verify the page just written */ return nand_verify_page(block, page, src); } int nand_write_prog(struct nand_image_descriptor_t *im_desc, const uint8_t *src, size_t size) { int num_blocks; int max_block_num; int page_num; uint32_t count_mask; im_desc->page_num = 1; /* Always start data in page 1 */ /* Do some rounding based on data buffer size */ im_desc->size_in_pages = 0; while ((im_desc->size_in_pages * nand_info.bytes_per_page) < size) im_desc->size_in_pages++; /* Get total number of blocks needed */ num_blocks = 0; while ((num_blocks * nand_info.pages_per_block) < (im_desc->size_in_pages + 1)) num_blocks++; uart_send_str("Needed blocks: "); uart_send_hexnum(num_blocks, 4); uart_send_lf(); uart_send_str("Needed pages: "); uart_send_hexnum(im_desc->size_in_pages, 4); uart_send_lf(); /* Check whether writing UBL or APP (based on destination block) */ if (im_desc->block_num <= END_UBL_BLOCK_NUM) max_block_num = END_UBL_BLOCK_NUM; else max_block_num = im_desc->block_num + MAX_BLOCK_PER_UBOOT - 1; NAND_WRITE_RETRY: if (im_desc->block_num > max_block_num) { log_fail("Block > last block"); return E_FAIL; } uart_send_str("Trying block "); uart_send_hexnum(im_desc->block_num, 4); uart_send_lf(); /* Unprotect all needed blocks of the Flash */ if (nand_unprotect_blocks(im_desc->block_num, num_blocks) != E_PASS) { im_desc->block_num++; log_info("Unprotect failed"); goto NAND_WRITE_RETRY; } /* Erase the block where the header goes and the data starts */ if (nand_erase_blocks(im_desc->block_num, num_blocks) != E_PASS) { im_desc->block_num++; log_info("Erase failed"); goto NAND_WRITE_RETRY; } #ifdef NAND_DEBUG_WRITE_RAMP { int k; /* Usefull for debugging NAND ECC and spare bytes errors. */ for (k = 0; k < 512; k++) ptr[k] = 0xCAFE0000 | k; } #endif page_num = 0; /* Start in page 0. */ if (im_desc->magic != UBL_CMD_FLASH_DATA) { /* Write the header to page 0. */ log_info("Writing header"); if (nand_write_verify_page(im_desc->block_num, page_num, (uint8_t *) im_desc) != E_PASS) return E_FAIL; /* Set starting page number for next data portion. */ page_num = 1; } /* The following assumes power of 2 page_cnt - *should* always be * valid. */ count_mask = nand_info.pages_per_block - 1; log_info("Writing data"); do { /* Write data on a per page basis */ if (nand_write_verify_page(im_desc->block_num, page_num & count_mask, src) != E_PASS) return E_FAIL; page_num++; src += nand_info.bytes_per_page; if (!(page_num & count_mask)) im_desc->block_num++; } while (page_num <= im_desc->size_in_pages); nand_protect_blocks(); return E_PASS; } int nand_erase_all(void) { /* Unprotect the NAND Flash */ nand_unprotect_blocks(0, nand_info.num_blocks - 1); /* Erase all the pages */ if (nand_erase_blocks(0, nand_info.num_blocks - 1) != E_PASS) return E_FAIL; /* Protect the device */ nand_protect_blocks(); return E_PASS; } int nand_get_pages_per_block(void) { return nand_info.pages_per_block; } int nand_get_bytes_per_page(void) { return nand_info.bytes_per_page; } int nand_get_bytes_per_block(void) { return nand_info.pages_per_block * nand_info.bytes_per_page; } int nand_remove_nwp(int need_gpio) { #ifdef NAND_nWP_GPIO if (need_gpio) { gpio_direction_out(NAND_nWP_GPIO, 1); waitloop(50); } #endif return 0; }