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

📄 fmd.cpp

📁 三星2440原版bsp
💻 CPP
📖 第 1 页 / 共 5 页
字号:
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 2002  Microsoft Corporation

Module Name:	FMD.CPP

Abstract:		FLASH Media Driver Interface Samsung K9F2808UOB NAND Flash Chip
                on AT-Rise development board.

Notes:			Currently, *only* the CE 3.0 (and earlier) power management logic
				is implemented (i.e. the PowerUp() and PowerDown() APIs).

Environment:	As noted, this media driver works on behalf of the FAL to directly
				access the underlying FLASH hardware.  Consquently, this module
				needs to be linked with FAL.LIB to produce the device driver
				named FLASHDRV.DLL.

-----------------------------------------------------------------------------*/
#include <fmd.h>
#include <s3c2440x.h>
#include "cfnand.h"
#include "args.h"
#include "image_cfg.h"

#define NAND_BASE 0xB0E00000
#define IOP_BASE  0xB1600000

#define BADBLOCKMARK                0x00

#define MAX_REGIONS 16
static FlashRegion g_pRegionTable[MAX_REGIONS];

static DWORD g_dwNumRegions;
static FlashInfo g_flashInfo;

// TODO: Make sector size generic
static BYTE g_pFLSBuffer[SECTOR_SIZE];
#define DEFAULT_COMPACTION_BLOCKS 4

//  Registers
volatile PUSHORT pNFReg;
volatile PUSHORT pNFCONF;
volatile PUSHORT pNFCONT;
volatile PUSHORT pNFCMD;
volatile PUSHORT pNFADDR;
volatile PULONG  pNFDATA;
volatile PUSHORT pNFSTAT;
volatile PULONG  pNFMECCD0;
volatile PULONG  pNFMECCD1;
volatile PULONG  pNFESTAT0;
volatile PULONG  pNFESTAT1;
volatile PULONG  pNFMECC0;
volatile PULONG  pNFMECC1;
volatile PULONG  pNFECC;
volatile PULONG  pNFSBLK;
volatile PULONG  pNFEBLK;

#define NFDATA 0x4E000010

S3C2440X_IOPORT_REG *v_pIOPregs;

static BOOL DefineLayout();
//void NANDTest();

//  External function
extern "C" {
BOOL ECC_CorrectData(LPBYTE pData, LPBYTE pExistingECC, LPBYTE pNewECC);
}

#define LOW	0
#define HIGH 1

void SetChipSelect(int mode, int status)
{
		if ( status == LOW )
			NF_CE_L();
		else // if ( status == HIGH )
			NF_CE_H();
}

//  Reset the chip
//
void NF_Reset()
{
    BOOL bLastMode = SetKMode(TRUE);

// Do not anything...

//	if ()
//	{
//		LB_NF_Reset(USE_NFCE);
//		SB_NF_Reset(USE_GPIO);
//	}
//	else
//	{
//		LB_NF_Reset(USE_GPIO);
//		SB_NF_Reset(USE_NFCE);
//	}

    SetKMode(bLastMode);
}

/*
 *  NAND_ReadSectorInfo
 *
 *  Read SectorInfo out of the spare area. The current implementation only handles
 *  one sector at a time.
 */
void NAND_ReadSectorInfo(SECTOR_ADDR sectorAddr, PSectorInfo pInfo)
{
	RETAILMSG(1, (TEXT("FMD::NAND_ReadSectorInfo ++ \r\n")));
	if ( sectorAddr < (unsigned)wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK )
	{
		if ( astNandSpec[dwPrimaryNandDevice].nSctsPerPg == 4 )
			NAND_LB_ReadSectorInfo(sectorAddr, pInfo, USE_NFCE);
		else
			NAND_SB_ReadSectorInfo(sectorAddr, pInfo, USE_NFCE);
	}
	else
	{
		if ( astNandSpec[dwSecondaryNandDevice].nSctsPerPg == 4 )
			NAND_LB_ReadSectorInfo(sectorAddr-wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK, pInfo, USE_GPIO);
		else
			NAND_SB_ReadSectorInfo(sectorAddr-wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK, pInfo, USE_GPIO);
	}
	RETAILMSG(1, (TEXT("FMD::NAND_ReadSectorInfo -- \r\n")));
}

/*
 *  NAND_WriteSectorInfo
 *
 *  Write SectorInfo out to the spare area. The current implementation only handles
 *  one sector at a time.
 */
BOOL NAND_WriteSectorInfo(SECTOR_ADDR sectorAddr, PSectorInfo pInfo)
{
    BOOL    bRet = TRUE;

	if ( sectorAddr < (unsigned)wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK )
	{
		if ( astNandSpec[dwPrimaryNandDevice].nSctsPerPg == 4 )
			bRet = NAND_LB_WriteSectorInfo(sectorAddr, pInfo, USE_NFCE);
		else
			bRet = NAND_SB_WriteSectorInfo(sectorAddr, pInfo, USE_NFCE);
	}
	else
	{
		if ( astNandSpec[dwSecondaryNandDevice].nSctsPerPg == 4 )
			bRet = NAND_LB_WriteSectorInfo(sectorAddr-wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK, pInfo, USE_GPIO);
		else
			bRet = NAND_SB_WriteSectorInfo(sectorAddr-wPRIMARY_NAND_BLOCKS*PAGES_PER_BLOCK, pInfo, USE_GPIO);
	}
    return bRet;
}

/*-----------------------------------------------------------------------------
 *  FMD Interface functions
 *
 *----------------------------------------------------------------------------*/
//  FMD_Init
//
//  Initialize the flash chip
//
//  Note: Presently, the Flash size characteristics are hardcoded in CFNAND.H
//		  and are NOT stored in the registry.  Refer to the StratFlash FMD in
//		  %WINCEROOT%\PUBLIC\COMMON\OAK\DRIVERS\BLOCK\... for an example of how
//		  to use the registry for storing this information.
//
PVOID FMD_Init(LPCTSTR lpActiveReg, PPCI_REG_INFO pRegIn, PPCI_REG_INFO pRegOut)
{
    BSP_ARGS *pBSPArgs = ((BSP_ARGS *) IMAGE_SHARE_ARGS_UA_START);

	RETAILMSG(1, (TEXT("FMD::FMD_Init\r\n")));
    //  0. Create the Mutex for shared access between the kernel and MSFLASH

//	RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_Init: pNFReg = %x \r\n"), pNFReg));
    pNFReg = (PUSHORT) (NAND_BASE);
//#if defined SMALLBLOCK_FIRST || defined LARGEBLOCK_FIRST
    v_pIOPregs = (S3C2440X_IOPORT_REG*)(IOP_BASE);
//#endif

    pNFCONF		= pNFReg;
    pNFCONT		= (PUSHORT) ((PBYTE) pNFReg + 0x04);
    pNFCMD		= (PUSHORT) ((PBYTE) pNFReg + 0x08);
    pNFADDR		= (PUSHORT) ((PBYTE) pNFReg + 0x0C);
    pNFDATA		= (PULONG)  ((PBYTE) pNFReg + 0x10);
	pNFMECCD0	= (PULONG)  ((PBYTE) pNFReg + 0x14);
	pNFMECCD1	= (PULONG)  ((PBYTE) pNFReg + 0x18);
    pNFSTAT		= (PUSHORT) ((PBYTE) pNFReg + 0x20);
	pNFESTAT0	= (PULONG)  ((PBYTE) pNFReg + 0x24);
	pNFESTAT1	= (PULONG)  ((PBYTE) pNFReg + 0x28);
	pNFMECC0	= (PULONG)  ((PBYTE) pNFReg + 0x2C);
	pNFMECC1	= (PULONG)  ((PBYTE) pNFReg + 0x30);
    pNFECC		= (PULONG)  ((PBYTE) pNFReg + 0x2C);
	pNFSBLK		= (PULONG)  ((PBYTE) pNFReg + 0x38);
	pNFEBLK		= (PULONG)  ((PBYTE) pNFReg + 0x3C);

    //  Now we need enable the NAND Flash controller
    BOOL bLastMode = SetKMode(TRUE);
    WRITE_REGISTER_USHORT(pNFCONF, (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0));
	WRITE_REGISTER_USHORT(pNFCONT, (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0));
    WRITE_REGISTER_USHORT(pNFSTAT, 0);

	DefineLayout();

    WRITE_REGISTER_ULONG(pNFEBLK, 0xFFFFE0);	// Maximum Number
#ifdef ULDR
    WRITE_REGISTER_ULONG(pNFSBLK, 0x0);			// Minimum Number
#else
	RETAILMSG(1, (TEXT("FMD::FMD_Init - pBSPArgs->nfsblk = 0x%x \r\n"), pBSPArgs->nfsblk));
	RETAILMSG(1, (TEXT("FMD::FMD_Init - READ_REGISTER_BYTE(pNFSBLK) = 0x%x \r\n"), READ_REGISTER_ULONG(pNFSBLK)));

	if ( (READ_REGISTER_ULONG(pNFSBLK) >> 5) == 0 )		// soft reset or IPL
	{
		if ( pBSPArgs->nfsblk == 0 )	// IPL
		{
			RETAILMSG(1, (TEXT("FMD::FMD_Init IPL ..... \r\n")));
		}
		else
		{
			RETAILMSG(1, (TEXT("FMD::FMD_Init Softreset ..... \r\n")));

			if ( astNandSpec[dwPrimaryNandDevice].nSctsPerPg == 4 )		// Large Block
			{
			    WRITE_REGISTER_ULONG(pNFSBLK, pBSPArgs->nfsblk << 6);				// Minimum Number
			}
			else
			{
			    WRITE_REGISTER_ULONG(pNFSBLK, pBSPArgs->nfsblk << 5);				// Minimum Number
			}
			WRITE_REGISTER_USHORT(pNFCONT, READ_REGISTER_USHORT(pNFCONT) | (1<<13));
		}
	}
	else
	{
		RETAILMSG(1, (TEXT("FMD::FMD_Init First Booting IN OS .... \r\n")));

		if ( astNandSpec[dwPrimaryNandDevice].nSctsPerPg == 4 )		// Large Block
		{
			WRITE_REGISTER_ULONG(pNFSBLK, pBSPArgs->nfsblk << 6);				// Minimum Number
		}
		else
		{
			WRITE_REGISTER_ULONG(pNFSBLK, pBSPArgs->nfsblk << 5);				// Minimum Number
		}
//		WRITE_REGISTER_ULONG(pNFSBLK, pBSPArgs->nfsblk << 5);				// Minimum Number
		WRITE_REGISTER_USHORT(pNFCONT, READ_REGISTER_USHORT(pNFCONT) | (1<<13));
	}
#endif

//#if defined SMALLBLOCK_FIRST || defined LARGEBLOCK_FIRST
	//v_pIOPregs->GPACON &= ~(1<<16);
	//v_pIOPregs->GPADAT |= (1<<16);
//#endif

    SetKMode(bLastMode);

	RETAILMSG(1, (TEXT("FMD::FMD_Init Done\r\n")));
	
//	NANDTest();

    return (PVOID)pNFCONF;
}

//  FMD_Deinit
//
//  De-initialize the flash chip
//
BOOL    FMD_Deinit(PVOID hFMD)
{
    return TRUE;
}


/*****************************************************************************/
/*                                                                           */
/* NAME                                                                      */
/*      _ReadXID                                                             */
/* DESCRIPTION                                                               */
/*      This function reads ManufavturerID and DeviceID.                     */
/* PARAMETERS                                                                */
/*      pMID                                                                 */
/*          NAND Flash Manufacturer ID                                       */
/*          NOW, only detect SAMSUNG (0xEC)                                  */
/*      pDID                                                                 */
/*          NAND Flash device ID                                             */
/* RETURN VALUES                                                             */
/*      FAIL                                                     */
/*          In case of ID Finding Failure                                    */
/*      TRUE                                                          */
/*          Operation success                                                */
/* NOTES                                                                     */
/*                                                                           */
/*****************************************************************************/
INT32
_ReadXID(UINT8* pMID, UINT8* pDID, int mode)
{
    UINT32  nCnt, nRet;
    UINT8   n4thcycle, nBuff;
	int i;
    
//	RETAILMSG(1, (TEXT("[S2440:  IN] ++_ReadXID()\r\n")));
    n4thcycle = nBuff = 0;
    BOOL bLastMode = SetKMode(TRUE);

	SetChipSelect(mode, LOW);
	NF_CLEAR_RB();
    NF_CMD  (CMD_READ_ID);
    NF_ADDR (0x00);
	for ( i = 0; i < 100; i++ );

    /* tREA is necessary to Get a MID. */
    for (nCnt = 0; nCnt < 5; nCnt++)
    {
        *pMID = (BYTE) NF_DATA_R();
        if (0xEC == *pMID)
            break;
    }

    *pDID = (BYTE) NF_DATA_R();
    
    nBuff     = (BYTE) NF_DATA_R();
    n4thcycle = (BYTE) NF_DATA_R();
	SetChipSelect(mode, HIGH);

    SetKMode(bLastMode);

    if (*pMID != (UINT8)0xEC)
    {
        RETAILMSG(1, (TEXT("[S2440 : ERR] ID Finding Failure\r\n")));
        nRet = FALSE;
    }
    else
    {
        RETAILMSG(1, (TEXT("MID = 0x%x, DID = 0x%x 4th Cycle : 0x%x\n"),*pMID, *pDID, n4thcycle));
        nRet = TRUE;
    }
    
//	RETAILMSG(1, (TEXT("[S2440 : OUT] --_ReadXID()\r\n")));
    return (nRet);
}

//  FMD_GetInfo
//
//  Return the Flash information
//
BOOL    FMD_GetInfo(PFlashInfo pFlashInfo)
{
    UINT32  nCnt;
    UINT8 nMID, nDID;

    if (!pFlashInfo)
        return(FALSE);

    pFlashInfo->flashType = NAND;

    if (_ReadXID(&nMID, &nDID, USE_NFCE) != TRUE)
    {
        RETAILMSG(1, (TEXT("[FMD_GetInfo : ERR] _ReadXID() Error\r\n")));
        return (FALSE);
    }

    for (nCnt = 0; astNandSpec[nCnt].nMID != 0; nCnt++)
    {
        if (nDID == astNandSpec[nCnt].nDID)
        {
            break;
        }
    }

	dwPrimaryNandDevice = nCnt;
	wPRIMARY_REAL_NAND_BLOCKS = astNandSpec[dwPrimaryNandDevice].nNumOfBlks;
	wSECONDARY_NAND_BLOCKS = 0;
	wSECONDARY_REAL_NAND_BLOCKS = 0;

//	RETAILMSG(1, (TEXT("dwPrimaryNandDevice : %d(0x%x) \r\n"), dwPrimaryNandDevice, dwPrimaryNandDevice));
//	RETAILMSG(1, (TEXT("astNandSpec[dwPrimaryNandDevice].nSctsPerPg: %d(0x%x) \r\n"), astNandSpec[dwPrimaryNandDevice].nSctsPerPg, astNandSpec[dwPrimaryNandDevice].nSctsPerPg));
//	RETAILMSG(1, (TEXT("wPRIMARY_REAL_NAND_BLOCKS : %d(0x%x) \r\n"), wPRIMARY_REAL_NAND_BLOCKS, wPRIMARY_REAL_NAND_BLOCKS));

	if ( astNandSpec[dwPrimaryNandDevice].nSctsPerPg == 4 )	// Primary NAND is Large Block...
	{
		wPRIMARY_NAND_BLOCKS = wPRIMARY_REAL_NAND_BLOCKS;
	}
	else
	{
		wPRIMARY_NAND_BLOCKS = wPRIMARY_REAL_NAND_BLOCKS / 8;
	}
	wNUM_BLOCKS = wPRIMARY_NAND_BLOCKS + wSECONDARY_NAND_BLOCKS;

    //  OK, instead of reading it from the chip, we use the hardcoded
    //  numbers here.

	pFlashInfo->dwNumBlocks			= wNUM_BLOCKS;
	pFlashInfo->wSectorsPerBlock	= PAGES_PER_BLOCK;
	pFlashInfo->wDataBytesPerSector = SECTOR_SIZE;
	pFlashInfo->dwBytesPerBlock     = (pFlashInfo->wSectorsPerBlock * pFlashInfo->wDataBytesPerSector);

	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));

    return TRUE;
}

BOOL  FMD_GetInfoEx(PFlashInfoEx pFlashInfo, PDWORD pdwNumRegions)
{
    // Temp
    RETAILMSG(1, (L"FMD_GetInfoEx enter.\r\n"));

    if (!pdwNumRegions) 
    {
        return FALSE;
    }
    
    if (!pFlashInfo)
    {
        // Return required buffer size to caller
        *pdwNumRegions = g_dwNumRegions;
        return TRUE;
    }
    
    if (*pdwNumRegions < g_dwNumRegions)
    {
        *pdwNumRegions = g_dwNumRegions;
        DEBUGMSG (1, (TEXT("FMD_GetInfoEx: Insufficient buffer for number of regions")));
        return FALSE;
    }

    memcpy (pFlashInfo->region, g_pRegionTable, g_dwNumRegions * sizeof(FlashRegion));

    // Temp
    for (DWORD iRegion = 0; iRegion < g_dwNumRegions; iRegion++) {
        RETAILMSG(1, (L"Type=%d, StartP=0x%x, NumP=0x%x, NumL=0x%x, Sec/Blk=0x%x, B/Blk=0x%x, Compact=%d.\r\n", 
            g_pRegionTable[iRegion].regionType,
            g_pRegionTable[iRegion].dwStartPhysBlock,
            g_pRegionTable[iRegion].dwNumPhysBlocks,
            g_pRegionTable[iRegion].dwNumLogicalBlocks,
            g_pRegionTable[iRegion].dwSectorsPerBlock,
            g_pRegionTable[iRegion].dwBytesPerBlock,
            g_pRegionTable[iRegion].dwCompactBlocks));

    }

    *pdwNumRegions = g_dwNumRegions;

    pFlashInfo->cbSize					= sizeof(FlashInfoEx);
    pFlashInfo->flashType				= NAND;
    pFlashInfo->dwNumBlocks				= wNUM_BLOCKS;
    pFlashInfo->dwDataBytesPerSector	= SECTOR_SIZE;
    pFlashInfo->dwNumRegions			= g_dwNumRegions;
    
    return(TRUE);
}

static BOOL DefineLayout()
{
    PFlashRegion pRegion = NULL;
    DWORD dwBlock = 0;

    if (!FMD_GetInfo (&g_flashInfo)) {
        return FALSE;
    }
    
    // Find the MBR to determine if there is a flash layout sector
    g_dwNumRegions = 0;


    // Find the first usuable block

⌨️ 快捷键说明

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