📄 mxc_nb_nfc.c
字号:
/* * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *//*! * @file mxc_nb_nfc.c * * @brief NANDBoot NFC code. * * This code implements the SPL part of the NANDboot. This reads the pages from * NAND Flash to RAM and detects the bad block before copying the pages. * * @ingroup NANDboot */#include "mxc_nb_uart.h"#include "mxc_nb_nfc.h"#define MXC_CMD_WAIT_US 25#define MXC_ADDR_WAIT_US 25#define MXC_BUFADDR_WAIT_US 40#define TEST_BAD 1//#define NB_DEBUGint badblock_list[16];#ifdef NB_DEBUG#define NB_DEBUG_BUF_ADDR 0x81000000#define NB_DEBUG_BUF_LEN 0x100static char *dbg_ptr = (char *)NB_DEBUG_BUF_ADDR;static char idx=0;/* * This function writes a one byte message number and 7 char message into the * debug buffer. This is used for debugging when there is no serial output yet * and possibly the debugger is not able to single stpe through the code! */void nb_dbg1(char *msg){ int i; /* dbg_ptr boundary check */ if ((dbg_ptr + 8) > (char *)(NB_DEBUG_BUF_ADDR + NB_DEBUG_BUF_LEN)) { dbg_ptr = (char *)NB_DEBUG_BUF_ADDR; } *dbg_ptr = idx++; /* Put the message number */ /* put the message, until null */ for (i = 0; i < 7; i++) { *(dbg_ptr + i) = *(msg + i); } /* Point to the next message to be written*/ dbg_ptr += 8;}void nb_dbg(char *msg){ int i; /* dbg_ptr boundary check */ if ((dbg_ptr + 8) > (char *)(NB_DEBUG_BUF_ADDR + NB_DEBUG_BUF_LEN)) { dbg_ptr = (char *)NB_DEBUG_BUF_ADDR; } *dbg_ptr++ = idx++; /* Put the message number */}#else /* !NB_DEBUG */#define nb_dbg(_msg)#endif /*! * This is helper sleep function which loops for approximately given number * usecs. * * @param count number of usec to wait loop */void udelay(int count){/* Assuming 366 MHz, 366 instructions will take 1 usec, we will execute 2 * inst in the loop (1 compare, 1 increment). */#define LOOPS_PER_USEC (366 / 2) volatile int i; int j; count *= LOOPS_PER_USEC; /* 'count' number of usec */ j = count; for (i = 0; i < j; i++) ;}/*! * This function polls the NANDFC to wait for an operation to complete * function. It sets the flags for the commands that requires different read * and write operations. * * @param maxRetries number of retry attempts (separated by 1 us) */int wait_op_done(U32 maxRetries){ while (maxRetries-- > 0) { if (NFC_CONFIG2 & 0x8000) break; udelay(1); } if (maxRetries <= 0) { nb_dbg("1-fail"); return -1; } return 0;}/*! * The NFC has to be preset before performing any operation */ void mxc_nfb_preset(void){ /* Unlock the internal RAM Buffer */ NFC_CONFIG = 0x2; /* Blocks to be unlocked */ NFC_UNLOCKSTART_BLKADDR = 0x0; /* Last Unlock Block */ NFC_UNLOCKEND_BLKADDR = 0x800; /* Unlock Block Command */ NFC_WRPROT = 0x4; /* Mask Interrupt */ NFC_CONFIG1 = 0x10;}/*! * For every read/write operation on NAND Flash, command has to be send . * This function sends command to the NAND Flash. It writes the command to the * NFC's Command Register. Configures the NFC's Configuration Register to * perform the Command Input Operation. * * @param cmd area from where to read the page * * @return This function returns 0 if command operation is not complete * else returns 1. */ int mxc_nfb_command(U8 cmd){ NFC_FLASH_CMD = cmd; /* Configure NAND Flash Config2 Register * Set INT to 0, FCMD to 1, rest to 0 */ NFC_CONFIG2 = 0x1; /* Confirm Cmd Complete */ return (wait_op_done(MXC_CMD_WAIT_US) == 0)? 1 : 0;}/*! * Reading or writing to any location in NAND Flash requires to pass an * address of that location in NFC. This function writes the NAND Flash Address * to the NFC's Address Register. Sets the Configuration Register for the * Address Input Operation * * @param addr addr from where to read the page * * @return This function returns 0 if address operation is not complete * else returns 1. */int mxc_nfb_address(U16 addr){ NFC_FLASH_ADDR = addr; /* Configure NAND Flash Config2 Register * Set INT to 0, FADD to 1, rest to 0 */ NFC_CONFIG2 = 0x2; /* Confirm Cmd Complete */ return (wait_op_done(MXC_ADDR_WAIT_US) == 0)? 1 : 0;}/*! * This function configures the NFC to copy the NAND Flash data in the main * area number passed as parameter during read operation or write the data * from main area to the NAND Flash. * * @param addr value for the internal main area buffer. * * @return This function returns 0 if the operation is not complete * else returns 1. */int mxc_nfb_bufferaddr(U16 addr){ NFC_BUFFER_ADDR = addr; /* * Configure NAND Flash Config2 Register * Set INT to 0, FDO to 1, rest to 0 */ NFC_CONFIG2 = 0x8; /* Confirm Cmd Complete */ return (wait_op_done(MXC_BUFADDR_WAIT_US) == 0)? 1 : 0;}/*! * This function reads pages to NAND flash RAM buffer. It configures the NFC * with address of the internal RamBuffer where the data has to be copied and * then configures the NFC Configuration Register to perform the read * operation. * Address of NAND flash is send as 3 bytes. LSB 6bits of 1st byte is the offset of the * page. MSB 2bits of 1th byte , 2nd bytes and LSB 2 bit of 3rd byte forms the 12 bits of block address. * This function also checks for the bad block. The block is said to be bad if * the value at OxBth location in the spare area for page 0 or 1 of the block * is not 0xFF (for 16 bit NAND flash only). * If the destination pointer is null this function will just check whether * the block is good or bad without copying data to RAM. * * @param page 6 bit page address in the block * @param block 12 bit block address * * @return This function returns 0 if the page read is in bad block * It returns 1 is page is in good block * It returns -1 if any of the command or address has failed */int mxc_nfb_readpage(U16 page, U16 block){ U32 i, addr, bi; volatile U16 *spbuff8; volatile U16 *spbuff16; addr = ((U32)block << 6) | page; /* Check for Badblock */ if (badblock_list[block] == 1) { mxcnb_outstring(" Bad Block : "); mxcnb_puthex(block); return 0; } NFC_BUFFER_ADDR = 0; if (!mxc_nfb_command(0x0)) { return -1; } /* * The NAND Flash Addr is a 5 Cycle process. Write to NAND Flash Addr * Register - Start Addr in Page */ if (!mxc_nfb_address(0)) { return -1; } if (!mxc_nfb_address(0)) { return -1; } /* Write to NAND Flash Addr Register - 6 bit Page Addr and * 2 bit LSB Block Addr */ if (!mxc_nfb_address(addr & 0x00ff)) { return -1; } /* Write to NAND Flash Addr Register */ if (!mxc_nfb_address((addr & 0xff00)>> 8)) { return -1; } /* * The current nandflash need one more address cycle */ if (!mxc_nfb_address((addr & 0x30000)>> 16)) { return -1; } if (!mxc_nfb_command(0x30)) { return -1; } NFC_CONFIG2 = 0x8; wait_op_done(MXC_BUFADDR_WAIT_US); /* Receive Data in RAM Buffer Addr Register - Set to 4th Internal * Buffer, where data will be loaded */ if (!mxc_nfb_bufferaddr(0x1)) { return -1; } if (!mxc_nfb_bufferaddr(0x2)) { return -1; } if (!mxc_nfb_bufferaddr(0x3)) { return -1; } return 1;}/*! * This function copies Linux kernel Image starting from 1st block of the * NAND Flash to RAM. The Linux kernl image written to NAND Flash has 4 bytes * size and 4 bytes of crc value written at starting of the image. This 8 bytes * are initially skipped and then remaining data are copied to RAM. Using the * size and crc value validity of the Linux kernel image is checked. * * @param pmem memory address in RAM where Linux has to be copied * @param start_block starting block from where to copy kernel from * * @return This function returns 0 if copying of kernel is not succeeded * else it will return 1. * */ int mxc_nfb_copykernel(U16* pmem, U32 start_block){ U16 page, block, bd_blk, nf_addr, addr, bi; U8 * ch; volatile U16 * membuff; U32 size, crc, i, tmp, ret; mxc_nfb_preset(); /* Read first page of linux kernel image in order to get size and crc*/ bd_blk = 0; do { page = 0; block = start_block + bd_blk; ret = mxc_nfb_readpage(page, block); if (ret == -1) { mxcnb_outstring("\n-->Failed to read page... "); return 0; } if (ret == 0) { bd_blk++; } } while (ret != 1); membuff = MAIN_AREA0; tmp = *(membuff++); size = *(membuff++); size = (size << 16) | tmp; tmp = *(membuff++); crc = *(membuff++); crc = (crc << 16) | tmp; mxcnb_outstring("\n-->Size: "); mxcnb_puthex(size); mxcnb_outstring("\n-->Crc: "); mxcnb_puthex(crc); ch = (U8*)pmem; /* for checking crc */ mxcnb_outstring("\nCopying pages...."); /* Copy first 2040 bytes of Linux kernel image */ memcpy(pmem, membuff, 2040); pmem += 1020; membuff += 1020; /* Get total number of pages of image */ nf_addr = (size / 2048) + 1; addr = (start_block << 6) + 1; /* Read the remaining pages */ for (; addr < (nf_addr + (start_block << 6)); addr++) { page = addr & 0x3F; ret = 0; while (ret != 1) { block = (addr >> 6) + bd_blk; ret = mxc_nfb_readpage(page, block); if (ret == -1) { mxcnb_outstring("\n-->Failed to read page... "); return 0; } if (ret == 0) { /* bad block when reading */ bd_blk++; } } /* Copy bytes from RAM buffer main area 0 to RAM */ membuff = MAIN_AREA0; memcpy(pmem, membuff, 2048); pmem += 1024; membuff += 1024; } /* Check addition crc for image validity */ tmp = 0; for (i = 0; i < size; i++) { tmp += *(ch++); } mxcnb_outstring("\n-->Calculated CRC: "); mxcnb_puthex(tmp); mxcnb_outstring("\n"); if (tmp != crc) { return 0; } mxcnb_outstring("\n-->Found valid CRC\n"); return 1;}/*! * This function scan for badblock and maintains the Badblock table * Badblock table is maintained only for Kernel partition (i.e)4Mb. */void mxcnb_scan_badblocks(void){ int ret,i; U16 bi; volatile U16 *spbuff; /* Byte at 0x800 location in spare area 0 of RAM BUFFER * has Bad block Information for 8 bit NAND flash */ spbuff = BI_BASE_8; for (i = 1; i < 16; i++) { /* Check page 0 for Badblock */ ret = mxc_nfb_readpage(0, i); bi = *(spbuff); bi = (bi & 0xFF00)>>8; if (bi != 0xFF) { badblock_list[i] = 1; } /* Check page 1 for Badblock */ if (!badblock_list[i]) { ret = mxc_nfb_readpage(1,i); bi = *(spbuff); bi = (bi & 0xFF00)>>8; if (bi != 0xFF) { badblock_list[i] = 1; } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -