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

📄 fmd.cpp

📁 SMDK2450的BSP 有很多新的特性,记得升级PB啊.
💻 CPP
📖 第 1 页 / 共 4 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
#include <fmd.h>
#include <s3c2450_nand.h>
#include <args.h>
#include <ethdbg.h>
#include "Cfnand.h"


#define NAND_BASE 0xB1500000	// changed for 2450

static volatile S3C2450_NAND_REG *s2450NAND = (S3C2450_NAND_REG *)NAND_BASE;

extern "C" void RdPage512(unsigned char *bufPt);
extern "C" void RdPage2048(unsigned char *bufPt);
extern "C" void RdPage512Unalign(unsigned char *bufPt);
extern "C" void WrPage512(unsigned char *bufPt); 
extern "C" void WrPage512Unalign(unsigned char *bufPt); 
extern "C" void WrPageInfo(PBYTE pBuff);
extern "C" void RdPageInfo(PBYTE pBuff);
extern "C" void RdPageSpare(PBYTE pBuff);

NANDDeviceInfo GetNandInfo(void) { return stDeviceInfo; }

/*
	@func   DWORD | ReadFlashID | Reads the flash manufacturer and device codes.
	@rdesc  Manufacturer and device codes.
	@comm	
	@xref   
*/


static DWORD ReadFlashID(void)
{
	BYTE Mfg, Dev;
	volatile DWORD i;

	NF_nFCE_L();						// Deselect the flash chip.
	NF_CMD(CMD_READID);					// Send flash ID read command.

	NF_ADDR(0);						// Send Address 0.
	for (i=0;i<10;i++);

	Mfg	= NF_RDDATA_BYTE();				// Read 1 byte from NFDATA == Maker code
	Dev	= NF_RDDATA_BYTE();				// Read 1 byte from NFDATA == Device code
	
	NF_nFCE_H();						// Deselect the flash chip.
	
	return ((DWORD)(Mfg<<8)+Dev);
}

/*
	@func   PVOID | FMD_Init | Initializes the Smart Media NAND flash controller.
	@rdesc  Pointer to S3C2450 NAND controller registers.
	@comm	
	@xref   
*/
PVOID FMD_Init(LPCTSTR lpActiveReg, PPCI_REG_INFO pRegIn, PPCI_REG_INFO pRegOut)
{

	// Caller should have specified NAND controller address.
	//

	BOOL bLastMode = SetKMode(TRUE);	// always true... dummy function.	
	volatile DWORD nNandID;
	UINT8 nMID, nDID;
	UINT32 nCnt;
	BOOL bNandExt = FALSE;

	RETAILMSG(1,(TEXT("#### FMD_DRIVER:::FMD_INIT \r\n")));

	if (pRegIn && pRegIn->MemBase.Num && pRegIn->MemBase.Reg[0])
		s2450NAND = (S3C2450_NAND_REG *)(pRegIn->MemBase.Reg[0]);
	else
		s2450NAND = (S3C2450_NAND_REG *)NAND_BASE;

	// Set up initial flash controller configuration.
	//
	s2450NAND->NFCONF = 	(TACLS  <<  12) |	/* duration = HCLK * TACLS */
				(TWRPH0 <<  8) |	/* duration = HCLK * (TWRPH0 + 1) */
				(TWRPH1 <<  4);		/* duration = HCLK * (TWRPH1 + 1) */ 
	s2450NAND->NFCONT = (0<<17)|(0<<16)|(0<<10)|(0<<9)|(0<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<4)|(0x3<<1)|(1<<0);
	s2450NAND->NFSTAT = (1<<4);

	// Get manufacturer and device codes.
	nNandID = ReadFlashID();
	RETAILMSG(1, (TEXT(" (NAND ID:0x%x) --> "), nNandID));

	nMID = (UINT8)(nNandID >> 8);	// Maker ID
	nDID = (UINT8)(nNandID & 0xff);	// Device ID

	// 秦寸 maker俊 秦寸 device啊 乐绰瘤 犬牢
	for (nCnt = 0; astNandSpec[nCnt].nMID != 0; nCnt++)
	{
        	if (nDID == astNandSpec[nCnt].nDID)
        	{
        		bNandExt = TRUE;
            		break;
        	}
    	}

	// match啊 救登搁 error
	if (!bNandExt)
	{
		RETAILMSG(1, (TEXT("Error!!!\n")));
		SetKMode (bLastMode);
		return(NULL);
	}
	else
	{
		RETAILMSG(1, (TEXT("OK.\n")));
	}

	// device狼 阿 沥焊甫 掘绢咳.
	NUM_OF_BLOCKS = astNandSpec[nCnt].nNumOfBlks;
	PAGES_PER_BLOCK = astNandSpec[nCnt].nPgsPerBlk;
	SECTORS_PER_PAGE = astNandSpec[nCnt].nSctsPerPg;

	RETAILMSG(1, (TEXT(" NUM_OF_BLOCKS    = %d \r\n"), NUM_OF_BLOCKS));
	RETAILMSG(1, (TEXT(" PAGES_PER_BLOCK  = %d \r\n"), PAGES_PER_BLOCK));
	RETAILMSG(1, (TEXT(" SECTORS_PER_PAGE = %d \r\n"), SECTORS_PER_PAGE));

	SetKMode (bLastMode);	// always true... dummy function.

	return((PVOID)s2450NAND);	// NAND Base 林家 府畔 (NFCONF, NFCONT ... )
}


/*
	@func   BOOL | FMD_ReadSector | Reads the specified sector(s) from NAND flash.
	@rdesc  TRUE = Success, FALSE = Failure.
	@comm	LB牢瘤 SB牢瘤俊 蝶扼 阿阿狼 窃荐甫 龋免 (wrapper function)
	@xref   
*/
BOOL FMD_ReadSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)
{
	BOOL bRet;

//	RETAILMSG(1, (TEXT("FMD::FMD_ReadSector 0x%x \r\n"), startSectorAddr));

	if ( IS_LB )
		bRet = FMD_LB_ReadSector(startSectorAddr, pSectorBuff, pSectorInfoBuff, dwNumSectors, USE_NFCE);
	else
		bRet = FMD_SB_ReadSector(startSectorAddr, pSectorBuff, pSectorInfoBuff, dwNumSectors, USE_NFCE);

	return bRet;
}


/*
	@func   BOOL | FMD_WriteSector | Writes the specified sector(s) to NAND flash.
	@rdesc  TRUE = Success, FALSE = Failure.
	@comm	LB牢瘤 SB牢瘤俊 蝶扼 阿阿狼 窃荐甫 龋免 (wrapper function)
	@xref   
*/
BOOL FMD_WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff,
                        DWORD dwNumSectors)
{
    BOOL    bRet = TRUE;

	//RETAILMSG(1, (TEXT("FMD::FMD_WriteSector 0x%x \r\n"), startSectorAddr));

	if ( IS_LB )
		bRet = FMD_LB_WriteSector(startSectorAddr, pSectorBuff, pSectorInfoBuff, dwNumSectors, USE_NFCE);
	else
		bRet = FMD_SB_WriteSector(startSectorAddr, pSectorBuff, pSectorInfoBuff, dwNumSectors, USE_NFCE);

    return bRet;
}

/*
	@func   BOOL | FMD_EraseBlock | Erases the specified flash block.
	@rdesc  TRUE = Success, FALSE = Failure.
	@comm	LB牢瘤 SB牢瘤俊 蝶扼 阿阿狼 窃荐甫 龋免 (wrapper function)
	@xref   
*/
BOOL FMD_EraseBlock(BLOCK_ID blockID)
{
	BOOL    bRet = TRUE;

	//RETAILMSG(1, (TEXT("FMD::FMD_EraseBlock 0x%x \r\n"),blockID));

	if ( IS_LB )
		bRet = FMD_LB_EraseBlock(blockID, USE_NFCE);
	else
		bRet = FMD_SB_EraseBlock(blockID, USE_NFCE);

    return bRet;
}


//  FMD_PowerUp
//
//  Performs any necessary powerup procedures...
//
VOID FMD_PowerUp(VOID)
{
	// Set up initial flash controller configuration.
	//
	s2450NAND->NFCONF =  	(TACLS  <<  12) |	/* duration = HCLK * TACLS */
				(TWRPH0 <<  8) |	/* duration = HCLK * (TWRPH0 + 1) */
				(TWRPH1 <<  4);		/* duration = HCLK * (TWRPH1 + 1) */ 
	s2450NAND->NFCONT = (0<<17)|(0<<16)|(0<<10)|(0<<9)|(0<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<4)|(0x3<<1)|(1<<0);
	s2450NAND->NFSTAT = (1<<4);
}


//  FMD_PowerDown
//
//  Performs any necessary powerdown procedures...
//
VOID FMD_PowerDown(VOID)
{
}


//  We don't have to build the following interface functions for the
//  bootloader.
//

//  FMD_OEMIoControl
//
//  Used for any OEM defined IOCTL operations
//
BOOL  FMD_OEMIoControl(DWORD dwIoControlCode, PBYTE pInBuf, DWORD nInBufSize,
                       PBYTE pOutBuf, DWORD nOutBufSize, PDWORD pBytesReturned)
{
	//RETAILMSG(1,(TEXT("#### FMD_DRIVER:::FMD_OEMIoControl \r\n")));

    switch(dwIoControlCode)
    {
	    case IOCTL_FMD_GET_INTERFACE:
	    {
	    	RETAILMSG(1, (TEXT("FMD_OEMIoControl: IOCTL_FMD_GET_INTERFACE \r\n")));
	            
	        if (!pOutBuf || nOutBufSize < sizeof(FMDInterface))
	        {
	            RETAILMSG(1, (TEXT("FMD_OEMIoControl: IOCTL_FMD_GET_INTERFACE bad parameter(s).\r\n")));
	            return(FALSE);
	        }    
	
	        PFMDInterface pInterface = (PFMDInterface)pOutBuf;
	        pInterface->cbSize = sizeof(FMDInterface);
	        pInterface->pInit = FMD_Init;
	        pInterface->pDeInit = FMD_Deinit;
	        pInterface->pGetInfo = FMD_GetInfo;        
	        pInterface->pGetBlockStatus = FMD_GetBlockStatus;     
	        pInterface->pSetBlockStatus = FMD_SetBlockStatus;
	        pInterface->pReadSector = FMD_ReadSector;
	        pInterface->pWriteSector = FMD_WriteSector;
	        pInterface->pEraseBlock = FMD_EraseBlock;
	        pInterface->pPowerUp = FMD_PowerUp;
	        pInterface->pPowerDown = FMD_PowerDown;
	        pInterface->pGetPhysSectorAddr = NULL;            
	
	        break;
	    }
	    default:
	        RETAILMSG(1, (TEXT("FMD_OEMIoControl: unrecognized IOCTL (0x%x).\r\n"), dwIoControlCode));
	        return(FALSE);
								
    }

    return TRUE; 
}

BOOL FMD_Deinit(PVOID hFMD)
{
	return(TRUE);
}


/*
	@func   BOOL | FMD_GetInfo | Provides information on the NAND flash.
	@rdesc  TRUE = Success, FALSE = Failure.
	@comm	
	@xref   
*/
BOOL FMD_GetInfo(PFlashInfo pFlashInfo)
{
	UINT32  nCnt;
	UINT32 nNandID;
	UINT8 nMID, nDID;

	if (!pFlashInfo)
		return(FALSE);

	BOOL bLastMode = SetKMode(TRUE);	// always true... dummy function.

	pFlashInfo->flashType = NAND;
    
    
	/************酒阀 何盒 鞘夸绝澜 **************/
	nNandID = ReadFlashID();

	nMID = nNandID >> 8;
	nDID = nNandID & 0xff;
	
    for (nCnt = 0; astNandSpec[nCnt].nMID != 0; nCnt++)
    {
        if (nDID == astNandSpec[nCnt].nDID)
        {
            break;
        }
    }
	/********* 拉何盒 鞘夸绝澜 ***************/
	
    //  OK, instead of reading it from the chip, we use the hardcoded
    //  numbers here.

	pFlashInfo->dwNumBlocks         = NUM_OF_BLOCKS;
	pFlashInfo->wSectorsPerBlock    = PAGES_PER_BLOCK;
	pFlashInfo->wDataBytesPerSector = NAND_SECTOR_SIZE;
	pFlashInfo->dwBytesPerBlock     = (PAGES_PER_BLOCK * NAND_SECTOR_SIZE);

	RETAILMSG(1, (TEXT("NUMBLOCKS : %d(0x%x), SECTORSPERBLOCK = %d(0x%x), BYTESPERSECTOR = %d(0x%x) \r\n"), pFlashInfo->dwNumBlocks, pFlashInfo->dwNumBlocks, pFlashInfo->wSectorsPerBlock, pFlashInfo->wSectorsPerBlock, pFlashInfo->wDataBytesPerSector, pFlashInfo->wDataBytesPerSector));

	SetKMode(bLastMode);
    return TRUE;
}


// Bad Block 牢瘤甫 眉农
// LB牢瘤 SB牢瘤甫 备盒秦辑 龋免秦林绰 wrapper 窃荐
static BOOL IsBlockBad(BLOCK_ID blockID)
{
	BOOL bRet = FALSE;

	if ( IS_LB )
		bRet = LB_IsBlockBad(blockID, USE_NFCE);
	else
		bRet = SB_IsBlockBad(blockID, USE_NFCE);

	return bRet;
}


/*
	@func   DWORD | FMD_GetBlockStatus | Returns the status of the specified block.
	@rdesc  Block status (see fmd.h).
	@comm	泅犁 block狼 惑怕甫 眉农秦林绰 wrapper 窃荐
	@xref   
*/
DWORD FMD_GetBlockStatus(BLOCK_ID blockID)
{
    DWORD dwResult = 0;


	if ( IS_LB )
		dwResult = FMD_LB_GetBlockStatus(blockID, USE_NFCE);
	else
		dwResult = FMD_SB_GetBlockStatus(blockID, USE_NFCE);

    return dwResult;
}


/*
	@func   BOOL | MarkBlockBad | Marks the specified block as bad.
	@rdesc  TRUE = Success, FALSE = Failure.
	@comm	
	@xref   
*/
static BOOL MarkBlockBad(BLOCK_ID blockID)
{
    BOOL    bRet = TRUE;

	if ( IS_LB )
		bRet = LB_MarkBlockBad(blockID, USE_NFCE);
	else
		bRet = SB_MarkBlockBad(blockID, USE_NFCE);

    return bRet;
}

/*
	@func   BOOL | FMD_SetBlockStatus | Marks the block with the specified block status.
	@rdesc  TRUE = Success, FALSE = Failure.
	@comm	
	@xref   
*/
BOOL FMD_SetBlockStatus(BLOCK_ID blockID, DWORD dwStatus)
{
    BOOL    bRet = TRUE;

	if ( IS_LB )
		bRet = FMD_LB_SetBlockStatus(blockID, dwStatus, USE_NFCE);
	else
		bRet = FMD_SB_SetBlockStatus(blockID, dwStatus, USE_NFCE);

    return bRet;
}

typedef enum {
    ECC_CORRECT_MAIN = 0,  // correct Main ECC
    ECC_CORRECT_SPARE1 = 1,  // correct Spare for Sector info
    ECC_CORRECT_SPARE2 = 2, // correct Spare for MECC
} ECC_CORRECT_TYPE;

BOOL ECC_CorrectData(SECTOR_ADDR sectoraddr, LPBYTE pData, UINT32 nRetEcc, ECC_CORRECT_TYPE nType)
{
	DWORD  nErrStatus;
	DWORD  nErrDataNo;
	DWORD  nErrBitNo;
	UINT32 nErrDataMask;
	UINT32 nErrBitMask = 0x7;
	BOOL bRet = TRUE;

	//Actually We use only MECC module for generating ECC parity code.
	//So, next if-statement doesn't need... always must set like this...
	if (nType == ECC_CORRECT_MAIN || nType == ECC_CORRECT_SPARE1 || nType == ECC_CORRECT_SPARE2)
	{
		nErrStatus   = 0;
		nErrDataNo   = 7;
		nErrBitNo    = 4;
		nErrDataMask = 0x7ff;
	}
	else
	{
		return FALSE;
	}

	switch((nRetEcc>>nErrStatus) & 0x3)
	{
		case 0:	// No Error
			bRet = TRUE;
			break;
		case 1:	// 1-bit Error(Correctable)
			if(nType == ECC_CORRECT_MAIN) {
				//RETAILMSG(1,(TEXT("#### MECC correctable error(0x%x) ####\r\n"), sectoraddr));
			} else if(nType == ECC_CORRECT_SPARE1) {
				//RETAILMSG(1,(TEXT("#### SECC1 correctable error(0x%x) ####\r\n"), sectoraddr));
			} else if(nType == ECC_CORRECT_SPARE2) {
				//RETAILMSG(1,(TEXT("#### SECC2 correctable error(0x%x) ####\r\n"), sectoraddr));
			}
			(pData)[(nRetEcc>>nErrDataNo)&nErrDataMask] ^= (1<<((nRetEcc>>nErrBitNo)&nErrBitMask));
			bRet = TRUE;		
			break;
		case 2:	// Multiple Error
			if(nType == ECC_CORRECT_MAIN) 
				RETAILMSG(1,(TEXT("#### MECC Uncorrectable error(0x%x) ####\r\n"), sectoraddr));
			else if(nType == ECC_CORRECT_SPARE1)

⌨️ 快捷键说明

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