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

📄 lpc32xx_fmd.cpp

📁 NXP LPC3000系列 wince BSP包
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//*********************************************************************
//* Software that is described herein is for illustrative purposes only  
//* which provides customers with programming information regarding the  
//* products. This software is supplied "AS IS" without any warranties.  
//* NXP Semiconductors assumes no responsibility or liability for the 
//* use of the software, conveys no license or title under any patent, 
//* copyright, or mask work right to the product. NXP Semiconductors 
//* reserves the right to make changes in the software without 
//* notification. NXP Semiconductors also make no representation or 
//* warranty that such application will be suitable for the specified 
//* use without further testing or modification. 
//*
//* Copyright NXP Semiconductors
//*********************************************************************
//
// lpc32xx_fmd.c
//
// NAND FLASH functions
//

#include <fmd.h>
#include <ceddk.h>
#include <ddkreg.h>
#include <Nkintr.h>
#include <Winbase.h>
#include "lbecc.h"
#include "lpc32xx_fmd.h"
#include "lpc32xx_clkpwr.h"
#include "lpc32xx_slcnand.h"
#include "lpc32xx_gpio.h"
#include "bsp.h"

// NAND info structure
typedef struct
{
	SLCNAND_REGS_T *pSLCRegs;      // Pointer to SLC registers
	CLKPWR_REGS_T *pCLKPWRRegs;    // Pointer to CLKPWR registers
	GPIO_REGS_T *pGPIORegs;        // Pointer to GPIO registers
	DWORD dwSysIntr;               // SLC NAND sysIntr value
	HANDLE dwEvent;                // SLC NAND event
#ifdef FMDACCESSLOCKS
	HANDLE Lockmutex;              // Access mutex
#endif
	// Queried device geometry
	DWORD dwNumBlocks;
	DWORD dwBytesPerBlock;
	WORD dwSectorsPerBlock;
	WORD dwDataBytesPerSector;
	DWORD addressCycles;           // NAND access address cycles
} NANDDRVDAT_T;
static NANDDRVDAT_T nandDrvDat;

//------------------------------------------------------------------------------
//
// nandMutexLock
//
// Get mutex lock
//
static void nandMutexLock(void)
{
#ifdef FMDACCESSLOCKS
    WaitForSingleObject(nandDrvDat.Lockmutex, INFINITE);
#endif
}

//------------------------------------------------------------------------------
//
// nandMutexUnlock
//
// Return mutex lock
//
static void nandMutexUnlock(void)
{
#ifdef FMDACCESSLOCKS
    ReleaseMutex(nandDrvDat.Lockmutex);
#endif
}

//------------------------------------------------------------------------------
//
// nandWpEnable
//
// Enable or disable NAND write protect
//
void nandWpEnable(BOOL enable) 
{
	if (enable == TRUE)
	{
		nandDrvDat.pGPIORegs->pio_outp_set = OUTP_STATE_GPO(19);
	}
	else
	{
		nandDrvDat.pGPIORegs->pio_outp_clr = OUTP_STATE_GPO(19);
	}
}

//------------------------------------------------------------------------------
//
// nandCSLock
//
// Lock or unlock NAND chip select signal
//
static void nandCSLock(BOOL lock)
{
	if (lock != FALSE)
	{
		nandDrvDat.pSLCRegs->slc_cfg |= SLCCFG_CE_LOW;
	}
	else
	{
		nandDrvDat.pSLCRegs->slc_cfg &= ~SLCCFG_CE_LOW;
	}
}

//------------------------------------------------------------------------------
//
// nandCheckReady
//
// Check NAND ready
//
BOOL nandCheckReady(void)
{
	BOOL rdy = FALSE;

	if ((nandDrvDat.pSLCRegs->slc_stat & SLCSTAT_NAND_READY) != 0)
	{
		rdy = TRUE;
	}

	return rdy;
}

//------------------------------------------------------------------------------
//
// nandWriteAddress
//
// Write FLASH address
//
void nandWriteAddress (unsigned char *addr,
					   int bytes)
{
    int idx = 0;
    
    for (idx = 0; idx < bytes; idx++)
	{
		nandDrvDat.pSLCRegs->slc_addr = (UNS_32) addr[idx];
    }
}

//------------------------------------------------------------------------------
//
// nandWriteCommand
//
// Write FLASH command
//
void nandWriteCommand (unsigned char cmd)
{
    nandDrvDat.pSLCRegs->slc_cmd = (UNS_32) cmd;
}

//------------------------------------------------------------------------------
//
// nandWriteData
//
// Write to FLASH data
//
void nandWriteData (void *data,
					int bytes)
{
    int idx;
    unsigned char *datab = (unsigned char *) data;

	for (idx = 0; idx < bytes; idx++)
	{
        nandDrvDat.pSLCRegs->slc_data = (UINT32) datab[idx];
    }
}

//------------------------------------------------------------------------------
//
// nandReadData
//
// Read from FLASH data
//
void nandReadData (void *addr,
				   int bytes)
{
    int idx;
    unsigned char *datab = (unsigned char *) addr;

	for (idx = 0; idx < bytes; idx++)
	{
        datab[idx] = (UNS_8) nandDrvDat.pSLCRegs->slc_data;
    }
}

//------------------------------------------------------------------------------
//
// nandWaitReady
//
// Wait for data ready from device
//
BOOL nandWaitReady(DWORD dataTimeout)
{
	if (dataTimeout > 0)
	{
		// Clear and enable NAND interrupts
		nandDrvDat.pSLCRegs->slc_icr = (SLCSTAT_INT_TC |
			SLCSTAT_INT_RDY_EN);
		InterruptDone(nandDrvDat.dwSysIntr);

		// Wait for interrupt
		WaitForSingleObject(nandDrvDat.dwEvent, dataTimeout);
	}

	// Return RDY status
	return nandCheckReady();
}

//------------------------------------------------------------------------------
//
// nandGetGeom
//
// Get device geometry
//
BOOL nandGetGeom (void)
{
	unsigned char temp[2];
	int to = 50;
	BOOL goodid = FALSE;

    // Send read ID command and wait for response
    nandCSLock(TRUE);
    nandWriteCommand(LPCNAND_CMD_READ_ID);
    temp[0] = 0;
    nandWriteAddress(temp, 1);
    while ((nandCheckReady() == FALSE) && (to > 0))
	{
		Sleep(1);
		to--;
	}

	// RDY failed?
	if (nandWaitReady(0) == FALSE)
	{
		RETAILMSG(1, (TEXT("FMD: Failed RDY response on NAND\r\n")));
		nandCSLock(FALSE);
		return FALSE;
	}

    // Read response
    nandReadData(temp, 2);


	// Verify manufacturer
	if (temp[0] == LPCNAND_VENDOR_STMICRO)
	{
		nandDrvDat.dwSectorsPerBlock = 32;
		nandDrvDat.dwDataBytesPerSector = 512;

		// Determine geometry based on device ID
		goodid = TRUE;
		switch (temp[1])
		{
		case 0x73:
			// 128MBit device
			nandDrvDat.dwNumBlocks = 1024;
			nandDrvDat.addressCycles = 3;
			break;

		case 0x35:
		case 0x75:
			// 256MBit device
			nandDrvDat.dwNumBlocks = 2048;
			nandDrvDat.addressCycles = 3;
			break;

		case 0x36:
		case 0x76:
			// 512MBit device
			nandDrvDat.dwNumBlocks = 4096;
			nandDrvDat.addressCycles = 4;
			break;

		case 0x39:
		case 0x79:
			// 1024MBit device
			nandDrvDat.dwNumBlocks = 8192;
			nandDrvDat.addressCycles = 4;
			break;

		default:
			goodid = FALSE;
			break;
		}

#if BYPASSBLOCKS>0
		nandDrvDat.dwNumBlocks = nandDrvDat.dwNumBlocks - BYPASSBLOCKS;
#endif

		nandDrvDat.dwBytesPerBlock = (nandDrvDat.dwSectorsPerBlock *
			nandDrvDat.dwDataBytesPerSector);
	}

    nandCSLock(FALSE);

	return goodid;
}

//------------------------------------------------------------------------------
//
// nandGetPageIndex
//
// Get an address from a sector number
//
void nandGetPageIndex(ULONG SectorAddr,
					  ULONG offset,
					  unsigned char *addrbytes) {
    ULONG block, page, nandaddr;

	// Limit offset
    if (offset >= 256)
	{
        offset = 0;
    }

    // Determine block and page offsets from passed sector address
    block = SectorAddr / nandDrvDat.dwSectorsPerBlock;
    page = SectorAddr - (block * nandDrvDat.dwSectorsPerBlock);

	// Block  Page  Index
	// 31..13 12..8 7..0
	nandaddr = offset + ((page & 0x1F) << 8);
	nandaddr = nandaddr | ((block & 0xFFF) << 13);

    // Save block and page address
	addrbytes[0] = (UNS_8) ((nandaddr >> 0) & 0xFF);
	addrbytes[1] = (UNS_8) ((nandaddr >> 8) & 0xFF);
	addrbytes[2] = (UNS_8) ((nandaddr >> 16) & 0xFF);
	if (nandDrvDat.addressCycles == 4) 
	{
		addrbytes[3] = (UNS_8) ((nandaddr >> 24) & 0xFF);
	}
}

//------------------------------------------------------------------------------
//
// FMD_Init
//
// Initialize FLASH interface and data
//
extern "C"
PVOID FMD_Init(LPCTSTR lpActiveReg,
			   PPCI_REG_INFO pRegIn,
               PPCI_REG_INFO pRegOut)
{
    PHYSICAL_ADDRESS pa;
	DWORD irq;
	UINT32 clk, bytesret;
	PVOID ret = NULL;
    BOOL validconfig = FALSE;
    
    /* Unused parameters */
    (void) pRegIn;
    (void) lpActiveReg;

	// Defaults
	nandDrvDat.pCLKPWRRegs = NULL;
	nandDrvDat.pSLCRegs = NULL;
	nandDrvDat.pGPIORegs = NULL;
	nandDrvDat.dwSysIntr = SYSINTR_UNDEFINED;
	nandDrvDat.dwEvent = NULL;
#ifdef FMDACCESSLOCKS
	nandDrvDat.Lockmutex = NULL;
#endif
	// MAP CLKPWR and SLC registers
	pa.QuadPart = CLK_PM_BASE;
	nandDrvDat.pCLKPWRRegs = (CLKPWR_REGS_T *) MmMapIoSpace(pa,
		sizeof (CLKPWR_REGS_T), FALSE);
	pa.QuadPart = SLC_BASE;
	nandDrvDat.pSLCRegs = (SLCNAND_REGS_T *) MmMapIoSpace(pa,
		sizeof (SLCNAND_REGS_T), FALSE);
	pa.QuadPart = GPIO_BASE;
	nandDrvDat.pGPIORegs = (GPIO_REGS_T *) MmMapIoSpace(pa,
		sizeof (GPIO_REGS_T), FALSE);
	if ((nandDrvDat.pCLKPWRRegs == NULL) || (nandDrvDat.pSLCRegs == NULL) ||
		(nandDrvDat.pGPIORegs == NULL))
	{
        RETAILMSG(1, 
			(TEXT("FMD: Failed to map registers\r\n")));
		goto cleanup;
	}

	// Setup SLC mode and enable SLC clock
	nandDrvDat.pCLKPWRRegs->clkpwr_nand_clk_ctrl = (CLKPWR_NANDCLK_SEL_SLC |
		CLKPWR_NANDCLK_SLCCLK_EN);

	// Reset SLC controller and setup for 8-bit mode, disable and clear interrupts
	nandDrvDat.pSLCRegs->slc_ctrl = SLCCTRL_SW_RESET;
	Sleep(1);
	nandDrvDat.pSLCRegs->slc_cfg = 0;
	nandDrvDat.pSLCRegs->slc_ien = SLCSTAT_INT_RDY_EN;
	nandDrvDat.pSLCRegs->slc_icr = (SLCSTAT_INT_TC |
		SLCSTAT_INT_RDY_EN);

	// Get current system clock speed for the SLC block
	if (KernelIoControl(IOCTL_LPC32XX_GETHCLK, NULL, 0, &clk,
		sizeof (clk), (LPDWORD) &bytesret) == FALSE)
	{
		// Cannot get clock, use default
        RETAILMSG(1, 
            (TEXT("FMD: Error getting SLC base clock rate.\r\n")));
		clk = 104000000;
	}

	// Setup SLC timing based on current clock
    nandDrvDat.pSLCRegs->slc_tac = (
		SLCTAC_WDR(1 + PHY_NAND_WDR) |
		SLCTAC_WWIDTH(1 + (clk / PHY_NAND_WWIDTH)) |
		SLCTAC_WHOLD(1 + (clk / PHY_NAND_WHOLD)) |
		SLCTAC_WSETUP(1 + (clk / PHY_NAND_WSETUP)) |
		SLCTAC_RDR(1 + PHY_NAND_RDR) |
		SLCTAC_RWIDTH(1 + (clk / PHY_NAND_RWIDTH)) |
		SLCTAC_RHOLD((1 + clk / PHY_NAND_RHOLD)) |
		SLCTAC_RSETUP(1 + (clk / PHY_NAND_RSETUP)));

	// Get device geometry
	if (nandGetGeom() == FALSE)
	{
		// Unsupported type
        RETAILMSG(1, (TEXT("FMD: Unsupported device type.\r\n")));
		goto cleanup;
	}

	// Map sysIntr value to the NAND interrupt
	irq = OAL_INTR_IRQ_NAND;
    if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &irq,
		sizeof(irq), &nandDrvDat.dwSysIntr, sizeof(nandDrvDat.dwSysIntr), NULL))
    {
		RETAILMSG(1,
			(TEXT("FMD: Error obtaining SYSINTR value!\r\n")));
        nandDrvDat.dwSysIntr = SYSINTR_UNDEFINED;
        goto cleanup;
    }

	// Create NAND interrupt event
	nandDrvDat.dwEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
	if (nandDrvDat.dwEvent == NULL)
	{
		RETAILMSG(1, 
			(TEXT("FMD: Failed to create NAND handler event.\r\n")));
		nandDrvDat.dwEvent = NULL;
        goto cleanup;
	}

	// Bind interrupt to events
	if (InterruptInitialize(nandDrvDat.dwSysIntr, nandDrvDat.dwEvent, NULL,
		0) == FALSE)
	{
		// Cannot initialize interrupt
		RETAILMSG(1, 
			(TEXT("FMD: Cannot initialize NAND interrupt\r\n")));
        goto cleanup;
	}

#ifdef FMDACCESSLOCKS
	// Create lock
	nandDrvDat.Lockmutex = CreateMutex(NULL, FALSE, NULL);
    if (nandDrvDat.Lockmutex == NULL) {
		RETAILMSG(1, 
			(TEXT("FMD: Cannot create mutex lock\r\n")));
        goto cleanup;
    }
#endif

	// Initialize ECC
    eccInitTables();

	// Reset device
	nandWriteCommand(LPCNAND_CMD_RESET);
	nandWaitReady(10);

    ret = &nandDrvDat;

⌨️ 快捷键说明

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