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

📄 fmd.c

📁 Windows CE 6.0 BSP for the Beagle Board.
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
//------------------------------------------------------------------------------
//
//  File: fmd.c
//
//
#include <windows.h>
#include <fmd.h>
#include <oal.h>
#include <omap2420.h>
#include <bsp_nand_cfg.h>
#include <bsp_base_regs.h>

BOOL ECC_ComputeECC(UCHAR *pData, DWORD size, UCHAR *pECC, DWORD eccSize);
BOOL ECC_IsDataValid(UCHAR *pData, DWORD size, UCHAR *pECC, DWORD eccSize);
BOOL ECC_CorrectData(UCHAR *pData, DWORD size, UCHAR *pECC, DWORD eccSize);


//  TI's ECC spare area layout

#define ECC_SIZE        3

//------------------------------------------------------------------------------
//  Spare area on NAND used for OMAP2420

#pragma pack( push, 1 )
typedef struct {
    WORD  badBlock1;            // Indicates if block is BAD
    BYTE  ecc[ECC_SIZE];        // ECC values
    BYTE  badBlock;             // Indicates if block is BAD
    BYTE  unused;               // Unused byte
    BYTE  oemReserved;          // For use by OEM
    WORD  reserved2;            // Reserved - used by FAL
    WORD  badBlock2;            // Indicates if block is BAD
    DWORD reserved1;            // Reserved - used by FAL
} NAND_SPARE_AREA;
#pragma pack( pop )

//------------------------------------------------------------------------------
//  Geometry info structure

typedef struct {
    UINT8  manufacturerId;
    UINT8  deviceId;
    UINT32 blocks;
    UINT32 sectorsPerBlock;
    UINT32 sectorSize;
    BOOL   extendedAddress;
} NAND_INFO;

//------------------------------------------------------------------------------
//  Hardware NAND registers structure

typedef volatile struct {
    UINT32 CMD;
    UINT32 ADDRESS;
    UINT32 DATA;
} NAND_REGS;

//------------------------------------------------------------------------------
//  Local Variable

static struct {
    CRITICAL_SECTION cs;
    OMAP2420_GPMC_REGS *pGPMCRegs;  
    NAND_REGS *pNANDRegs;
    const NAND_INFO *pNANDInfo;
    UCHAR *pBuffer;
} g_fmd;

//------------------------------------------------------------------------------
//  NAND geometry info

static const NAND_INFO g_nandInfo[] = { BSP_NAND_INFO };

//------------------------------------------------------------------------------
//  Local Functions

_inline static BOOL NAND_WaitForReady();
static BOOL NAND_SendFullCommand(UINT8 cmd, SECTOR_ADDR sector, UINT32 offset);
static BOOL NAND_FinishCommand(UINT8 cmd);
static VOID NAND_Read(UINT8 *pBuffer, UINT32 bytes);
static VOID NAND_Write(UINT8 *pBuffer, UINT32 bytes);

//------------------------------------------------------------------------------
//
//  Function:  FMD_Init
//
//  This function is called to initialize flash subsystem.
//
PVOID FMD_Init(LPCTSTR pActive, PPCI_REG_INFO pRegIn, PPCI_REG_INFO pRegOut)
{
    VOID *pHandle = NULL;
    PHYSICAL_ADDRESS pa;
    UINT8 manufacturer, device;
    UINT32 ix;

    memset(&g_fmd, 0, sizeof(g_fmd));

    InitializeCriticalSection(&g_fmd.cs);
    
    pa.QuadPart = OMAP2420_GPMC_REGS_PA;      
    g_fmd.pGPMCRegs = MmMapIoSpace(pa, sizeof(OMAP2420_GPMC_REGS), FALSE);
    if (g_fmd.pGPMCRegs == NULL) {
        goto cleanUp;
    }
    pa.QuadPart = BSP_NAND_REGS_PA;
    g_fmd.pNANDRegs = MmMapIoSpace(pa, sizeof(NAND_REGS), FALSE);
    if (g_fmd.pNANDRegs == NULL) {
        goto cleanUp;
    }

    // Wait for NAND
    if (!NAND_WaitForReady()) goto cleanUp;

    // Send Read ID Command
    OUTREG16(&g_fmd.pNANDRegs->CMD, BSP_NAND_CMD_READID);

    // Wait for NAND
    if (!NAND_WaitForReady()) goto cleanUp;

    // Send Address 00h
    OUTREG16(&g_fmd.pNANDRegs->ADDRESS, 0);
    if (!NAND_WaitForReady()) goto cleanUp;

    // Read the manufacturer ID & device code
    manufacturer = (UINT8)INREG16(&g_fmd.pNANDRegs->DATA);
    device = (UINT8)INREG16(&g_fmd.pNANDRegs->DATA);

    // Find if we support chip
    g_fmd.pNANDInfo = NULL;
    for (ix = 0; ix < sizeof(g_nandInfo)/sizeof(g_nandInfo[0]); ix++) {
        if (
            manufacturer == g_nandInfo[ix].manufacturerId &&
            device == g_nandInfo[ix].deviceId
        ) {
          g_fmd.pNANDInfo = &g_nandInfo[ix];
          break;
        }
    }            

    // If we don't support NAND, fail...
    if (g_fmd.pNANDInfo == NULL) goto cleanUp;

    // Allocate buffer
    g_fmd.pBuffer = LocalAlloc(LPTR, g_fmd.pNANDInfo->sectorSize);
    if (g_fmd.pBuffer == NULL) goto cleanUp;
    
    // We are done
    pHandle = &g_fmd;

cleanUp:    
    return pHandle;
}

//------------------------------------------------------------------------------
//
//  Function:  FMD_Deinit
//
BOOL FMD_Deinit(VOID *pContext)
{
    BOOL rc = FALSE;
    if (pContext != &g_fmd) goto cleanUp;

    if (g_fmd.pBuffer != NULL) LocalFree(g_fmd.pBuffer);
    
    if (g_fmd.pGPMCRegs != NULL) MmUnmapIoSpace(
        (VOID*)g_fmd.pGPMCRegs, sizeof(OMAP2420_GPMC_REGS)
    );

    if (g_fmd.pNANDRegs != NULL) MmUnmapIoSpace(
        (VOID*)g_fmd.pNANDRegs, sizeof(NAND_REGS)
    );

    DeleteCriticalSection(&g_fmd.cs);

    rc = TRUE;
    
cleanUp:    
    return rc;
}

//------------------------------------------------------------------------------
//
//  Function:  FMD_GetInfo
//
//  This function is call to get flash information
//
BOOL FMD_GetInfo(FlashInfo *pFlashInfo)
{
    BOOL rc = FALSE;

    // If we don't support NAND, fail...
    if (g_fmd.pNANDInfo == NULL) goto cleanUp;

    // Memory type is NAND
    pFlashInfo->flashType = NAND;
    pFlashInfo->dwNumBlocks = g_fmd.pNANDInfo->blocks;
    pFlashInfo->wSectorsPerBlock = g_fmd.pNANDInfo->sectorsPerBlock;
    pFlashInfo->wDataBytesPerSector = g_fmd.pNANDInfo->sectorSize;
    pFlashInfo->dwBytesPerBlock = 
        g_fmd.pNANDInfo->sectorSize * g_fmd.pNANDInfo->sectorsPerBlock;

    // Done
    rc = TRUE;

cleanUp:
    return rc;
}

//------------------------------------------------------------------------------
//
//  Function:  FMD_ReadSector
//
//  Read the content of the sector.
//
BOOL FMD_ReadSector(
    SECTOR_ADDR sector, UCHAR *pBuffer, SectorInfo *pSectorInfo, DWORD sectors
) {
    BOOL rc = FALSE;
    NAND_SPARE_AREA sa;
    UINT32 i;


    // There isn't clear semantic how to read more than one sector
    if (sectors > 1 || g_fmd.pNANDInfo == NULL) goto cleanUp;

    EnterCriticalSection(&g_fmd.cs);
    
    // Read sector from A
    if (pBuffer != NULL) {
        NAND_SendFullCommand(BSP_NAND_CMD_READ, sector, 0);
        NAND_Read(pBuffer, g_fmd.pNANDInfo->sectorSize);
    }

    // Write the command
    NAND_SendFullCommand(BSP_NAND_CMD_READ2, sector, 0);
    // Read NAND spare area data
    NAND_Read((UINT8*)&sa, sizeof(sa));

    LeaveCriticalSection(&g_fmd.cs);
    
    // Copy sector info
    if (pSectorInfo != NULL) {
        pSectorInfo->bBadBlock = sa.badBlock;
        pSectorInfo->bOEMReserved = sa.oemReserved;
        pSectorInfo->dwReserved1 = sa.reserved1;
        pSectorInfo->wReserved2 = sa.reserved2;
    }

    // Verify ECC
    if (pBuffer != NULL) {
        // Check if we get same ECC from data
        if (!ECC_IsDataValid(
            pBuffer, g_fmd.pNANDInfo->sectorSize, sa.ecc, ECC_SIZE
        )) {
            //  Now try to correct them
            if (!ECC_CorrectData(
                pBuffer, g_fmd.pNANDInfo->sectorSize, sa.ecc, ECC_SIZE
            )) {
                // Check if spare and data are all 0xFF - erased sector
                for (i = 0; i < sizeof(sa); i++) {
                    if (((UINT8*)&sa)[i] != 0xFF) goto cleanUp;
                }                    
                for (i = 0; i < g_fmd.pNANDInfo->sectorSize; i++) {
                    if (pBuffer[i] != 0xFF) goto cleanUp;
                }                    
            }                
        }
    }

    // Done
    rc = TRUE;

cleanUp:
    return rc;
}

//------------------------------------------------------------------------------
//
//  Function:  FMD_WriteSector
//
BOOL FMD_WriteSector(
    SECTOR_ADDR sector, UCHAR *pBuffer, SectorInfo *pSectorInfo, DWORD sectors
) {
    BOOL rc = FALSE;
    NAND_SPARE_AREA sa;

    // There isn't clear semantic how to read more than one sector
    if (sectors > 1 || g_fmd.pNANDInfo == NULL) goto cleanUp;

    EnterCriticalSection(&g_fmd.cs);

    // Remove flash write protection
    SETREG32(&g_fmd.pGPMCRegs->ulGPMC_CONFIG,BIT4);


    // When there is buffer write data
    if (pBuffer != NULL) {

        // Select A area
        OUTREG16(&g_fmd.pNANDRegs->CMD, BSP_NAND_CMD_READ);
        // Issue command
        NAND_SendFullCommand(BSP_NAND_CMD_WRITE, sector, 0);
        // Write the data
        NAND_Write(pBuffer, g_fmd.pNANDInfo->sectorSize);
        // Calculate the ECC
        ECC_ComputeECC(
            pBuffer, g_fmd.pNANDInfo->sectorSize, sa.ecc, ECC_SIZE
        );
        // Finish up the write operation
        if (!NAND_FinishCommand(BSP_NAND_CMD_WRITE2)) goto cleanUp;

    } else {

⌨️ 快捷键说明

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