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

📄 nand.c

📁 davinci的NANDFLASH烧写程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/* --------------------------------------------------------------------------
    FILE        : nand.c 				                             	 	        
    PURPOSE     : NAND driver file
    PROJECT     : DaVinci CCS NAND Flashing Utility
    AUTHOR      : Daniel Allred
    DATE	    : 04-Jun-2007  
 
    HISTORY
 	     v1.00 - DJA - 04-Jun-2007
 	        Completion (with support for DM6441 and DM6441_LV)
 ----------------------------------------------------------------------------- */

#include "nandwriter.h"
#include "dm644x.h"
#include "stdio.h"
#include "nand.h"

// Table of ROM supported NAND devices
const NAND_DEVICE_INFO gNandDevInfo[] = 
{ // devID, numBlocks,  pagesPerBlock,  bytesPerPage
    {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 0x22B1 */
    {0xC1,  1024,       64,             2048+64},   /* 128 MB - Big Block 0x22C1 */
    {0x00,	0,          0,              0}	        /* Dummy null entry to indicate end of table*/
};

// ***************************************
// Generic Low-level NAND access functions
// ***************************************
VUint8 *flash_make_addr (Uint32 baseAddr, Uint32 offset)
{
	return ((VUint8 *) ( baseAddr + offset ));
}

void flash_write_data(PNAND_INFO pNandInfo, Uint32 offset, Uint32 data)
{
	volatile FLASHPtr addr;
	FLASHData dataword;
	dataword.l = data;

	addr.cp = flash_make_addr (pNandInfo->flashBase, offset);
	switch (pNandInfo->busWidth)
	{
	    case BUS_8BIT:
            *addr.cp = dataword.c;
            break;
        case BUS_16BIT:
            *addr.wp = dataword.w;
            break;
	}
}

void flash_write_cmd (PNAND_INFO pNandInfo, Uint32 cmd)
{
	flash_write_data(pNandInfo, NAND_CLE_OFFSET, cmd);
}

void flash_write_addr (PNAND_INFO pNandInfo, Uint32 addr)
{
	flash_write_data(pNandInfo, NAND_ALE_OFFSET, addr);
}

void flash_write_bytes(PNAND_INFO pNandInfo, void* pSrc, Uint32 numBytes)
{
    volatile FLASHPtr destAddr, srcAddr;
	Uint32 i;
	
	srcAddr.cp = (VUint8*) pSrc;
	destAddr.cp = flash_make_addr (pNandInfo->flashBase, NAND_DATA_OFFSET );
	switch (pNandInfo->busWidth)
	{
    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;
    }

}

void flash_write_addr_cycles(PNAND_INFO pNandInfo, Uint32 block, Uint32 page)
{
    flash_write_addr_bytes(pNandInfo, pNandInfo->numColAddrBytes, 0x00000000);
    flash_write_row_addr_bytes(pNandInfo, block, page);
}

void flash_write_addr_bytes(PNAND_INFO pNandInfo, Uint32 numAddrBytes, Uint32 addr)
{    
    Uint32 i;
    for (i=0; i<numAddrBytes; i++)
    {
        flash_write_addr(pNandInfo, ( (addr >> (8*i) ) & 0xff) );
	}
}

void flash_write_row_addr_bytes(PNAND_INFO pNandInfo, Uint32 block, Uint32 page)
{
    Uint32 row_addr;
	row_addr = (block << (pNandInfo->blkShift - pNandInfo->pageShift)) | page;
	flash_write_addr_bytes(pNandInfo, pNandInfo->numRowAddrBytes, row_addr);
}

Uint32 flash_read_data (PNAND_INFO pNandInfo)
{
	volatile FLASHPtr addr;
	FLASHData cmdword;
	cmdword.l = 0x0;

	addr.cp = flash_make_addr (pNandInfo->flashBase, NAND_DATA_OFFSET );
	switch (pNandInfo->busWidth)
	{
	    case BUS_8BIT:
            cmdword.c = *addr.cp;
            break;
        case BUS_16BIT:
            cmdword.w = *addr.wp;
            break;
	}
	return cmdword.l;
}

void flash_read_bytes(PNAND_INFO pNandInfo, void* pDest, Uint32 numBytes)
{
    volatile FLASHPtr destAddr, srcAddr;
	Uint32 i;
	
	destAddr.cp = (VUint8*) pDest;
	srcAddr.cp = flash_make_addr (pNandInfo->flashBase, NAND_DATA_OFFSET );
	switch (pNandInfo->busWidth)
	{
    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;
    }
}

void flash_swap_data(PNAND_INFO pNandInfo, Uint32* data)
{
    Uint32 i,temp = *data;
    volatile FLASHPtr  dataAddr, tempAddr;
    
    dataAddr.cp = flash_make_addr((Uint32) data, 3);
    tempAddr.cp = flash_make_addr((Uint32) &temp,0);
        
    switch (pNandInfo->busWidth)
	{
    case BUS_8BIT:
        for(i=0; i<4; i++)
	        *dataAddr.cp-- = *tempAddr.cp++;
        break;
    case BUS_16BIT:
        for(i=0; i<2; i++)
	        *dataAddr.wp-- = *tempAddr.wp++;
        break;
    }
}

// **********************
// Status Check functions
// **********************

// Poll bit of NANDFSR to indicate ready
Uint32 NAND_WaitForRdy(Uint32 timeout) {
	VUint32 cnt;
	cnt = timeout;

	waitloop(200);

	while( !(AEMIF->NANDFSR & NAND_NANDFSR_READY) && ((cnt--) > 0) )

    if(cnt <= 0)
	{
		printf("NAND_WaitForRdy() Timeout!\r\n");
		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.
Uint32 NAND_WaitForStatus(PNAND_INFO pNandInfo, Uint32 timeout) {
	VUint32 cnt;
	Uint32 status;
	cnt = timeout;

    do
    {
	    flash_write_cmd(pNandInfo, NAND_STATUS);
	    status = flash_read_data(pNandInfo) & (NAND_STATUS_ERROR | NAND_STATUS_BUSY);
        cnt--;
  	}
  	while((cnt>0) && !status);

	if(cnt == 0)
	{
		printf("NANDWaitForStatus() Timeout!\r\n");
		return E_FAIL;
	}

	return E_PASS;
}


// ****************************************************
// Read the current ECC calculation and restart process
// ****************************************************
Uint32 NAND_ECCReadAndRestart (PNAND_INFO pNandInfo)
{
    VUint32 retval,temp;

    // Flush data writes (by reading CS3 data region)
	temp = *((VUint32*)(((VUint8*)pNandInfo->flashBase) + 0x02000000));

    // Read and mask appropriate (based on CSn space flash is in) ECC regsiter
    retval = ((VUint32*)(&(AEMIF->NANDF1ECC)))[pNandInfo->CSOffset] & pNandInfo->ECCMask;
    
    // Write appropriate bit to start ECC calcualtions 
    AEMIF->NANDFCR |= (1<<(8 + (pNandInfo->CSOffset)));

    // Flush NANDFCR write (by reading another CFG register)
	temp = AEMIF->ERCSR;
    
    return retval;
}

Uint32 NAND_ECCCorrection(PNAND_INFO pNandInfo, Uint32 ECCold, Uint32 ECCnew, Uint8 *data)
{
	Uint16 ECCxorVal, byteAddr, bitAddr;

	if (!pNandInfo->ECCEnable)
		return E_FAIL;

	ECCxorVal = (Uint16) ((ECCold & 0xFFFF0000) >> 16) ^  // write ECCo
	                     ((ECCold & 0x0000FFFF) >> 0 ) ^  // write ECCe
				         ((ECCnew & 0xFFFF0000) >> 16) ^  // read ECCo 
				         ((ECCnew & 0x0000FFFF) >> 0 );   // read ECCe

	if ( ECCxorVal == (0x0000FFFF & pNandInfo->ECCMask) )
	{
		// Single Bit error - can be corrected
        ECCxorVal = (Uint16) ((ECCold & 0xFFFF0000) >> 16) ^ ((ECCnew & 0xFFFF0000) >> 16);
        byteAddr = (ECCxorVal >> 3);
        bitAddr = (ECCxorVal & 0x7);
        printf("Single bit flip at byte %d, bit %d.", byteAddr, bitAddr);
        data[byteAddr] ^= (0x1 << bitAddr);
        return E_PASS;
	}
	else
	{
        // Multiple Bit error - nothing we can do
        return E_FAIL;
	}
}


// *******************
// NAND Init Functions
// *******************

// Initialze NAND interface and find the details of the NAND used
PNAND_INFO NAND_Open(Uint32 baseCSAddr)
{
    Uint32 width, *CSRegs;
    PNAND_INFO pNandInfo;

    // Alloc the main NAND structue
    pNandInfo = (PNAND_INFO) ubl_alloc_mem(sizeof(NAND_INFO));
	
    pNandInfo->writeBuff = (Uint8 *) ubl_alloc_mem(MAX_PAGE_SIZE);
    pNandInfo->readBuff =  (Uint8 *) ubl_alloc_mem(MAX_PAGE_SIZE);

    // Set NAND flash base address
    pNandInfo->flashBase = baseCSAddr;
    
    //Get the CSOffset (can be 0 through 3 - corresponds with CS2 through CS5)
    pNandInfo->CSOffset = ( (pNandInfo->flashBase & (0x0FFFFFFF)) >> 25) - 1;
    
    // Setting the nand_width = 0(8 bit NAND) or 1(16 bit NAND).
    width = ( ( (SYSTEM->BOOTCFG) & 0x00000020) >> 5);
    pNandInfo->busWidth = (width)?BUS_16BIT:BUS_8BIT;

    // Setup AEMIF registers for NAND
    CSRegs = (Uint32*) &(AEMIF->AB1CR);
    CSRegs[pNandInfo->CSOffset] = 0x3FFFFFFC | width;        // Set correct ABxCR reg
    AEMIF->NANDFCR |= (0x1 << (pNandInfo->CSOffset));        // NAND enable for CSx
    NAND_ECCReadAndRestart(pNandInfo);
                         
	// Send reset command to NAND
	flash_write_cmd( pNandInfo, NAND_RESET );

	if ( NAND_WaitForRdy(NAND_TIMEOUT) != E_PASS )
        return NULL;
		
	if ( NAND_GetDetails(pNandInfo) != E_PASS)
        return NULL;

    return pNandInfo;
}

// Get details of the NAND flash used from the id and the table of NAND devices
Uint32 NAND_GetDetails(PNAND_INFO pNandInfo)
{
	Uint32 manfID,deviceID,i,j;
	
	// Issue device read ID command
    flash_write_cmd( pNandInfo, NAND_RDID);
    flash_write_addr( pNandInfo, NAND_RDIDADD);
    
	// Read ID bytes
	manfID   = flash_read_data( pNandInfo ) & 0xFF;
	deviceID = flash_read_data( pNandInfo ) & 0xFF;
	j        = flash_read_data( pNandInfo ) & 0xFF;
	j        = flash_read_data( pNandInfo ) & 0xFF;

	i=0;
	while (gNandDevInfo[i].devID != 0x00)
	{
		if(deviceID == gNandDevInfo[i].devID)
		{
		    pNandInfo->manfID            = (Uint8) manfID;
			printf( "\tManufacturer ID  = 0x%8.8X\r\n", pNandInfo->manfID);
		
			pNandInfo->devID             = (Uint8) gNandDevInfo[i].devID;
			printf( "\tDevice ID        = 0x%8.8X\r\n", pNandInfo->devID);
			
			pNandInfo->pagesPerBlock     = gNandDevInfo[i].pagesPerBlock;
			printf( "\tPages Per Block  = %d\r\n", pNandInfo->pagesPerBlock);
	
			pNandInfo->numBlocks         = gNandDevInfo[i].numBlocks;
			printf( "\tNumber of Blocks = %d\r\n", pNandInfo->numBlocks);
			
			pNandInfo->bytesPerPage      = NANDFLASH_PAGESIZE(gNandDevInfo[i].bytesPerPage);
			printf( "\tBytes Per Page   = %d\r\n", pNandInfo->bytesPerPage);
            printf( "\tTotal size       = %dM\r\n", (pNandInfo->pagesPerBlock * pNandInfo->bytesPerPage * pNandInfo->numBlocks) >> 20);
			break;
		}
		i++;
	}
    if (gNandDevInfo[i].devID == 0x00) return E_FAIL;
			
	// Assign the big_block flag
	pNandInfo->bigBlock = (pNandInfo->bytesPerPage>MAX_BYTES_PER_OP)?TRUE:FALSE;
	
	// Assign the bytes per operation value
	pNandInfo->bytesPerOp = (pNandInfo->bytesPerPage>MAX_BYTES_PER_OP)?MAX_BYTES_PER_OP:pNandInfo->bytesPerPage;
	
	// Assign the number of operations per page value
	pNandInfo->numOpsPerPage = (pNandInfo->bytesPerOp < MAX_BYTES_PER_OP)?1:(pNandInfo->bytesPerPage >> MAX_BYTES_PER_OP_SHIFT);
	
	// Assign the number of spare bytes per operation
	pNandInfo->spareBytesPerOp = pNandInfo->bytesPerOp >> SPAREBYTES_PER_OP_SHIFT;
	
	// Setup address shift values	
	j = 0;
	while( (pNandInfo->pagesPerBlock >> j) > 1)
	{
		j++;
	}
	pNandInfo->blkShift = j;        

⌨️ 快捷键说明

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