⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cmd_nand.c

📁 AT91SAM 系列微控制器的NAND Flash支持代码 描述怎样将NAND Flash和AT91SAM 系列微控制器连接起来。
💻 C
字号:
 //  ----------------------------------------------------------------------------
 //          ATMEL Microcontroller Software Support  -  ROUSSET  -
 //  ----------------------------------------------------------------------------
 //  DISCLAIMER:  THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
 //  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 //  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 //  DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
 //  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 //  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 //  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 //  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 //  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 //  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 //  ----------------------------------------------------------------------------
/************************************************************************/
/*  smc_prim.c                                                          */
/*      routines to talk to the serial flash.                           */
/*                                                                      */
/* Note that these routines all must be re-entrant.  Since they talk    */
/*      to hardware, this also means that they must disable tasking     */
/*      in most cases.                                                  */
/*                                                                      */
/* Note on ECC in Sunburst.                                             */
/*      In order to be compatible with parts written by old software    */
/*      the presence of ECC data must be checked for.  The ECC          */
/*      data is the first 4 bytes after the block.  If the next 2 bytes */
/*      (bytes 4 and 5 in the ECC area) are not the same value, it is   */
/*      assumed that the block has ECC data.                            */
/*                                                                      */
//*----------------------------------------------------------------------------
//*----------------------------------------------------------------------------
//       $Revision: 1.12 $
//       $Date: 2006/06/19 16:29:49 $
//       $Author: nico $
/************************************************************************/

#include "cmd_nand.h"
#include "main.h"

extern char message[];
/*
*	Chip ID list
*
*	Name. ID code, pagesize, chipsize in MegaByte, eraseblock size,
*	options
*
* 	Pagesize; 0, 256, 512
*	0 	get this information from the extended chip ID
+	256	256 Byte page size
*	512	512 Byte page size
*/
struct nand_flash_dev nand_flash_ids[] = {
	{0x6e, 256, 1, 0x1000, 0},	// "NAND 1MiB 5V 8-bit"
	{0x64, 256, 2, 0x1000, 0},	// "NAND 2MiB 5V 8-bit"
	{0x6b, 512, 4, 0x2000, 0},	// "NAND 4MiB 5V 8-bit"
	{0xe8, 256, 1, 0x1000, 0},	// "NAND 1MiB 3,3V 8-bit"
	{0xec, 256, 1, 0x1000, 0},	// "NAND 1MiB 3,3V 8-bit"
	{0xea, 256, 2, 0x1000, 0},	// "NAND 2MiB 3,3V 8-bit"
	{0xd5, 512, 4, 0x2000, 0},	// "NAND 4MiB 3,3V 8-bit"
	{0xe3, 512, 4, 0x2000, 0},	// "NAND 4MiB 3,3V 8-bit"
	{0xe5, 512, 4, 0x2000, 0},	// "NAND 4MiB 3,3V 8-bit"
	{0xd6, 512, 8, 0x2000, 0},	// "NAND 8MiB 3,3V 8-bit"

	{0x39, 512, 8, 0x2000, 0},	// "NAND 8MiB 1,8V 8-bit"
	{0xe6, 512, 8, 0x2000, 0},	// "NAND 8MiB 3,3V 8-bit"
	{0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},	// "NAND 8MiB 1,8V 16-bit"
	{0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},	// "NAND 8MiB 3,3V 16-bit"

	{0x33, 512, 16, 0x4000, 0},	// "NAND 16MiB 1,8V 8-bit"
	{0x73, 512, 16, 0x4000, 0},	// "NAND 16MiB 3,3V 8-bit"
	{0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},	// "NAND 16MiB 1,8V 16-bit"
	{0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},	// "NAND 16MiB 3,3V 16-bit"

	{0x35, 512, 32, 0x4000, 0},	// "NAND 32MiB 1,8V 8-bit"
	{0x75, 512, 32, 0x4000, 0},	// "NAND 32MiB 3,3V 8-bit"
	{0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},	// "NAND 32MiB 1,8V 16-bit"
	{0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},	// "NAND 32MiB 3,3V 16-bit"

	{0x36, 512, 64, 0x4000, 0},	// "NAND 64MiB 1,8V 8-bit"
	{0x76, 512, 64, 0x4000, 0},	// "NAND 64MiB 3,3V 8-bit"
	{0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},	// "NAND 64MiB 1,8V 16-bit"
	{0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},	// "NAND 64MiB 3,3V 16-bit"

	{0x78, 512, 128, 0x4000, 0},	// "NAND 128MiB 1,8V 8-bit"
	{0x79, 512, 128, 0x4000, 0},	// "NAND 128MiB 3,3V 8-bit"
	{0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},	// "NAND 128MiB 1,8V 16-bit"
	{0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},	// "NAND 128MiB 3,3V 16-bit"

	/* These are the new chips with large page size. The pagesize, erasesize
	   and buswidth are determined from the extended id bytes
	*/
	/* 1 Gigabit */
	{0xA1, 0, 128, 0, 0},	// "NAND 128MiB 1,8V 8-bit"
	{0xF1, 0, 128, 0, 0},	// "NAND 128MiB 3,3V 8-bit"
	{0xB1, 0, 128, 0, 0},	// "NAND 128MiB 1,8V 16-bit"
	{0xC1, 0, 128, 0, 0},	// "NAND 128MiB 3,3V 16-bit"

	/* 2 Gigabit */
	{0xAA, 0, 256, 0, 0},	// "NAND 256MiB 1,8V 8-bit"
	{0xDA, 0, 256, 0, 0},	// "NAND 256MiB 3,3V 8-bit"
	{0xBA, 0, 256, 0, 0},	// "NAND 256MiB 1,8V 16-bit"
	{0xCA, 0, 256, 0, 0},	// "NAND 256MiB 3,3V 16-bit"

	/* 4 Gigabit */
	{0xAC, 0, 512, 0, 0},	// "NAND 512MiB 1,8V 8-bit"
	{0xDC, 0, 512, 0, 0},	// "NAND 512MiB 3,3V 8-bit"
	{0xBC, 0, 512, 0, 0},	// "NAND 512MiB 1,8V 16-bit"
	{0xCC, 0, 512, 0, 0},	// "NAND 512MiB 3,3V 16-bit"

	/* 8 Gigabit */
	{0xA3, 0, 1024, 0, 0},	// "NAND 1GiB 1,8V 8-bit"
	{0xD3, 0, 1024, 0, 0},	// "NAND 1GiB 3,3V 8-bit"
	{0xB3, 0, 1024, 0, 0},	// "NAND 1GiB 1,8V 16-bit"
	{0xC3, 0, 1024, 0, 0},	// "NAND 1GiB 3,3V 16-bit"

	/* 16 Gigabit */
	{0xA5, 0, 2048, 0, 0},	// "NAND 2GiB 1,8V 8-bit"
	{0xD5, 0, 2048, 0, 0},	// "NAND 2GiB 3,3V 8-bit"
	{0xB5, 0, 2048, 0, 0},	// "NAND 2GiB 1,8V 16-bit"
	{0xC5, 0, 2048, 0, 0},	// "NAND 2GiB 3,3V 16-bit"

	{0, 0, 0, 0, 0}
};

/*
*	Manufacturer ID list
*/
int nand_manufacturers[] = {
	NAND_MFR_TOSHIBA,
	NAND_MFR_SAMSUNG,
	NAND_MFR_FUJITSU,
	NAND_MFR_NATIONAL,
	NAND_MFR_STMICRO,
	NAND_MFR_MICRON,
	0x0
};

struct nand_info nand_chip;


/************************************************************************/
/* nand_write_data for large blocks                                           */
/*      This routine reads a buffer of data to the serial flash       */
/*      device.                                                         */
/*                                                                      */
/* ARGUMENTS:                                                           */
/*      file_pos        Position (in bytes) in flash to read from       */
/*      buffer          Buffer to place data into                       */
/*      bytes_to_write   Number of bytes to write                         */
/************************************************************************/
void nand_write_page(unsigned long file_pos_ll, unsigned char *buffer,
                   unsigned int bytes_to_write,int type)
{

	unsigned long int end_pos, file_pos;
	unsigned long int column, page_addr;
	int               bytes_in_page;

	if (bytes_to_write > 0)
   	{
   		file_pos = (unsigned long int)file_pos_ll;

		NAND_ENABLE_CE;
		NAND_WAIT_READY;

    	WRITE_NAND_COMMAND(NAND_CMD_SEQIN, AT91_SMARTMEDIA_BASE);

		if(type == NAND_OOB)	column = nand_chip.nand_bytes_per_page;
		else column = 0/*file_pos % nand_chip.nand_bytes_per_page*//* can write only on page boundary*/;
		page_addr = file_pos / nand_chip.nand_bytes_per_page;

		if (nand_chip.nand_buswidth_16 == TRUE)
			column >>= 1;

		// Send Column Address
	    WRITE_NAND_ADDRESS(column & 0x0FF, AT91_SMARTMEDIA_BASE);
	    WRITE_NAND_ADDRESS(column >> 8, AT91_SMARTMEDIA_BASE);

		// Send Row Address
	    WRITE_NAND_ADDRESS(page_addr & 0x0FF, AT91_SMARTMEDIA_BASE);
	    WRITE_NAND_ADDRESS((page_addr >> 8) & 0x0FF, AT91_SMARTMEDIA_BASE);
		// Large Blocks 2Gb devices uses 5 address cycles
		if (nand_chip.extended_address_s == TRUE)
			WRITE_NAND_ADDRESS((page_addr >> 16) & 0x0FF, AT91_SMARTMEDIA_BASE);

      	end_pos = file_pos + bytes_to_write;
      	bytes_in_page = (int)(nand_chip.nand_bytes_per_page - (file_pos & nand_chip.page_mask));

      	while (file_pos < end_pos)
      	{
   			if (nand_chip.nand_buswidth_16 == TRUE)
   			{
				unsigned short wData = (*buffer++) | (*buffer++ << 8);
   				WRITE_NAND16(wData , AT91_SMARTMEDIA_BASE);

	         	file_pos += 2;
	         	bytes_in_page -= 2;
   			} else {
   				WRITE_NAND16(*buffer++ , AT91_SMARTMEDIA_BASE);

	         	file_pos++;
	         	bytes_in_page--;
	        }

      	}

    	WRITE_NAND_COMMAND(NAND_CMD_PAGEPROG, AT91_SMARTMEDIA_BASE);

		NAND_WAIT_READY;

		NAND_DISABLE_CE;
   }
}

/************************************************************************/
/* nand_read_data for large blocks                                           */
/*      This routine reads a buffer of data from the serial flash       */
/*      device.                                                         */
/*                                                                      */
/* ARGUMENTS:                                                           */
/*      file_pos        Position (in bytes) in flash to read from       */
/*      buffer          Buffer to place data into                       */
/*      bytes_to_read   Number of bytes to read                         */
/************************************************************************/
void nand_read_page(unsigned long file_pos_ll, unsigned char *buffer,
                   unsigned int bytes_to_read,int type)
{

	unsigned long int end_pos, file_pos;
	unsigned long int column, page_addr;
	int               bytes_in_page;

	if (bytes_to_read > 0)
   	{
   		file_pos = (unsigned long int)file_pos_ll;

		NAND_ENABLE_CE;
		NAND_WAIT_READY;

    	WRITE_NAND_COMMAND(NAND_CMD_READ0, AT91_SMARTMEDIA_BASE);

		if(type == NAND_OOB)	column = nand_chip.nand_bytes_per_page;
		else column = 0/*file_pos % nand_chip.nand_bytes_per_page*//* can write only on page boundary*/;
		page_addr = file_pos / nand_chip.nand_bytes_per_page;

		if (nand_chip.nand_buswidth_16 == TRUE)
			column >>= 1;

		// Send Column Address
	    WRITE_NAND_ADDRESS(column & 0x0FF, AT91_SMARTMEDIA_BASE);
	    WRITE_NAND_ADDRESS(column >> 8, AT91_SMARTMEDIA_BASE);

		// Send Row Address
	    WRITE_NAND_ADDRESS(page_addr & 0x0FF, AT91_SMARTMEDIA_BASE);
	    WRITE_NAND_ADDRESS((page_addr >> 8) & 0x0FF, AT91_SMARTMEDIA_BASE);
		// Large Blocks 2Gb devices uses 5 address cycles
		if (nand_chip.extended_address_s == TRUE)
			WRITE_NAND_ADDRESS((page_addr >> 16) & 0x0FF, AT91_SMARTMEDIA_BASE);

    	WRITE_NAND_COMMAND(NAND_CMD_READ_CONFIRM, AT91_SMARTMEDIA_BASE);

      	end_pos = file_pos + bytes_to_read;
      	bytes_in_page = (int)(nand_chip.nand_bytes_per_page - (file_pos & nand_chip.page_mask));

      	while (file_pos < end_pos)
      	{
   			NAND_WAIT_READY;

   			if (nand_chip.nand_buswidth_16 == TRUE)
   			{
				unsigned short wData = READ_NAND16(AT91_SMARTMEDIA_BASE);
   				*buffer++ = (unsigned char)(wData & 0x00FF);
   				*buffer++ = (unsigned char)((wData >> 8) & 0x00FF);

	         	file_pos += 2;
	         	bytes_in_page -= 2;
   			} else {
	   			*buffer++ = READ_NAND(AT91_SMARTMEDIA_BASE);

	         	file_pos++;
	         	bytes_in_page--;
	        }

      	}

		NAND_DISABLE_CE;
   }
}


//*----------------------------------------------------------------------------
//* \fn    AT91F_NandFlash_Erase_Page
//* \brief  
//*----------------------------------------------------------------------------

void AT91F_NandFlash_Erase_Block(unsigned int Block_Number){
	unsigned long volatile Block_Add;

	Block_Add = Block_Number *  nand_chip.nand_bytes_per_page * 64;
	NAND_ENABLE_CE;
	WRITE_NAND_COMMAND(NAND_CMD_ERASE1, AT91_SMARTMEDIA_BASE);
	WRITE_NAND_ADDRESS( Block_Add, AT91_SMARTMEDIA_BASE);
	WRITE_NAND_ADDRESS( (Block_Add >> 8), AT91_SMARTMEDIA_BASE);
	WRITE_NAND_ADDRESS( (Block_Add >> 16), AT91_SMARTMEDIA_BASE);
	WRITE_NAND_COMMAND(NAND_CMD_ERASE2, AT91_SMARTMEDIA_BASE);
	WRITE_NAND_COMMAND(NAND_CMD_STATUS, AT91_SMARTMEDIA_BASE);
	NAND_WAIT_READY;
	NAND_DISABLE_CE;

}

/************************************************************************/
/* This routine returns the type of SMC chip installed.                 */
/************************************************************************/
smc_chip_t nand_chip_type(void)
{
	int i = 0;
	smc_chip_t    chip_type;
   	unsigned char maker_id, device_id;

	NAND_ENABLE_CE;
	WRITE_NAND_COMMAND(NAND_CMD_READID, AT91_SMARTMEDIA_BASE);
	WRITE_NAND_ADDRESS(0, AT91_SMARTMEDIA_BASE);
	NAND_WAIT_READY;
	maker_id = READ_NAND(AT91_SMARTMEDIA_BASE);
	NAND_WAIT_READY;
	device_id = READ_NAND(AT91_SMARTMEDIA_BASE);

   	chip_type = SMC_UNKNOWN;

	while (nand_manufacturers[i] != 0)
	{
		if (maker_id == nand_manufacturers[i])
			break;

		i++;
	}

	if (nand_manufacturers[i] == 0)
		return chip_type;

	/* Print and store flash device information */
	for (i = 0; nand_flash_ids[i].id != 0; i++)
	{
		if (device_id != nand_flash_ids[i].id)
			continue;

		sprintf(message, "NandFlash chip found:\n\r Manufacturer ID: 0x%2.2X Chip ID: 0x%2.2X\n\r",
				maker_id, device_id);					
				AT91F_DBGU_Printk(message);
		nand_chip.chipsize = nand_flash_ids[i].chipsize << 20;

		// New devices have all the information in additional id bytes
		if (!nand_flash_ids[i].pagesize)
		{
			int extid;

			nand_chip.nand_large_blocks = TRUE;

			if (nand_chip.chipsize > (128 << 20))
				nand_chip.extended_address_s = TRUE;

			// The 3rd id byte contains non relevant data ATM
			extid = READ_NAND(AT91_SMARTMEDIA_BASE);
			// The 4th id byte is the important one
			extid = READ_NAND(AT91_SMARTMEDIA_BASE);
			// Calc pagesize
			nand_chip.nand_bytes_per_page = 1024 << (extid & 0x3);
			extid >>= 4;
			// Calc blocksize. Blocksize is multiples of 64KiB
			nand_chip.blocksize = (64 * 1024)  << (extid & 0x03);
			extid >>= 2;
			// Get buswidth information
			if (extid & 0x01)
				nand_chip.nand_buswidth_16 = TRUE;
		}
		else
		{
			/* Old devices have this data hardcoded in the
			 * device id table */
			if (nand_chip.chipsize > (32 << 20))
				nand_chip.extended_address_s = TRUE;

			nand_chip.nand_bytes_per_page = nand_flash_ids[i].pagesize;
			nand_chip.blocksize = nand_flash_ids[i].erasesize;
			if (nand_flash_ids[i].buswidth & NAND_BUSWIDTH_16)
				nand_chip.nand_buswidth_16 = TRUE;
		}

		nand_chip.page_mask = nand_chip.nand_bytes_per_page - 1;
		break;
	}

	NAND_DISABLE_CE;

   	chip_type = SMC_KNOWN;

	return chip_type;
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -