📄 nandflsh.c
字号:
//****************************************************************************
//
// NANDFLSH.C - Routines to access the NAND FLASH and SmartMedia
//
// Copyright (c) 1999 - 2001 Cirrus Logic, Inc.
//
//****************************************************************************
#include "ep7312.h"
#include "lib7312.h"
//****************************************************************************
//
// The following table contains the mapping from the NAND device ID to the
// physical layout of the NAND memory array.
//
//****************************************************************************
#define NOP __asm { nop }
#define NUMIDS 7
static const struct
{
unsigned char ucID;
unsigned char ucPageSize;
unsigned char ucPagesPerBlock;
unsigned char ucBlocks;
} sNANDMap[NUMIDS] =
{
{ 0xEA, 0, 16, 1 }, // 256bytes * 16pages * 512blocks = 2Meg
{ 0xE3, 1, 16, 1 }, // 512bytes * 16pages * 512blocks = 4Meg
{ 0xE5, 1, 16, 1 }, // 512bytes * 16pages * 512blocks = 4Meg
{ 0xE6, 1, 16, 2 }, // 512bytes * 16pages * 1024blocks = 8Meg
{ 0x73, 1, 32, 2 }, // 512bytes * 32pages * 1024blocks = 16Meg
{ 0x75, 1, 32, 4 }, // 512bytes * 32pages * 2048blocks = 32Meg
{ 0x76, 1, 32, 8 }, // 512bytes * 32pages * 4096blocks = 64Meg
};
//****************************************************************************
//
// The layout of the on-board NAND FLASH.
//
//****************************************************************************
static unsigned long ulNANDReadID = 0;
static unsigned long ulNANDPageSize;
static unsigned long ulNANDPagesPerBlock;
static unsigned long ulNANDNumBlocks;
//****************************************************************************
//
// The layout of the SmartMedia card.
//
//****************************************************************************
static unsigned long ulSMPageSize;
static unsigned long ulSMPagesPerBlock;
static unsigned long ulSMNumBlocks;
//****************************************************************************
//
// NANDGetSize determines the size and layout of the on-board NAND FLASH based
// on the device ID read from the NAND FLASH.
//
//****************************************************************************
long
NANDGetSize(unsigned long *pulDeviceSize, unsigned long *pulPageSize,
unsigned long *pulPagesPerBlock, unsigned long *pulNumBlocks)
{
unsigned long * volatile pulPtr = (unsigned long *)HwNANDAddress;
unsigned char * volatile pucPortB = (unsigned char *)(HwBaseAddress +
HwPortB);
unsigned char * volatile pucPortBdir = (unsigned char *)(HwBaseAddress +
HwDdrB);
unsigned long * volatile pulMemPtr = (unsigned long *)(HwBaseAddress +
HwMemConfig1);
unsigned char volatile ucTemp;
long lIdx;
//
// Set up chip select 1 for bus width of 32 bits
//
*pulMemPtr |= 0x1900;
//
// Set the port B data direction register.
//
*pucPortBdir = 0xFA;
//
// Set the initial value of port B, with both the NAND and Smart
// Media chip selects set to 0.
//
*pucPortB = 0x00;
//
// Select the NAND FLASH.
//
*pucPortB |= HwPortBNANDCS;
//
// Assert CLE.
//
*pucPortB |= HwPortBCLE;
//
// Write the read id command.
//
*pulPtr = 0x00000090;
//
// Deassert CLE.
//
*pucPortB &= ~HwPortBCLE;
//
// Assert ALE.
//
*pucPortB |= HwPortBALE;
//
// Write the address.
//
*pulPtr = 0x00000000;
//
// Deassert ALE.
//
*pucPortB &= ~HwPortBALE;
//
// Read the maker ID.
//
ucTemp = *pulPtr;
//
// Read the device ID.
//
ucTemp = *pulPtr;
//
// Deassert the NAND FLASH.
//
*pucPortB &= ~HwPortBNANDCS;
//
// Find this device ID in our table.
//
for(lIdx = 0; lIdx < NUMIDS; lIdx++)
{
if((ucTemp & 255) == sNANDMap[lIdx].ucID)
{
break;
}
}
//
// Return an error if we could not find this device ID.
//
if(lIdx == NUMIDS)
{
return(0);
}
//
// Fill in the NAND FLASH globals based on the physical layout of the NAND
// devices on the board.
//
ulNANDPageSize = sNANDMap[lIdx].ucPageSize ? 512 : 256;
ulNANDPagesPerBlock = sNANDMap[lIdx].ucPagesPerBlock;
ulNANDNumBlocks = (unsigned long)sNANDMap[lIdx].ucBlocks << 9;
ulNANDReadID = 1;
//
// If requested, return the size of the NAND memory.
//
if(pulDeviceSize)
{
*pulDeviceSize = ulNANDPageSize * ulNANDPagesPerBlock *
ulNANDNumBlocks * 4;
*pulPageSize = ulNANDPageSize;
*pulPagesPerBlock = ulNANDPagesPerBlock;
*pulNumBlocks = ulNANDNumBlocks;
}
//
// Success.
//
return(1);
}
//****************************************************************************
//
// NANDReadPage reads data from the specified page of the on-board NAND FLASH.
//
//****************************************************************************
void
NANDReadPage(unsigned long ulPage, int bReadSpare, unsigned char *pucBuffer)
{
unsigned long * volatile pulPtr = (unsigned long *)HwNANDAddress;
unsigned char * volatile pucPortB = (unsigned char *)(HwBaseAddress +
HwPortB);
long lIdx;
//
// Make sure that we know the layout of the on-board NAND FLASH.
//
if(!ulNANDReadID)
{
NANDGetSize(0, 0, 0, 0);
}
//
// Select the NAND FLASH.
//
*pucPortB |= HwPortBNANDCS;
//
// Assert CLE.
//
*pucPortB |= HwPortBCLE;
//
// Write the read1 command.
//
*pulPtr = 0x00;
//
// Deassert CLE.
//
*pucPortB &= ~HwPortBCLE;
//
// Assert ALE.
//
*pucPortB |= HwPortBALE;
//
// Write the address.
//
*pulPtr = 0x00;
lIdx = ulPage & 0xFF;
*pulPtr = lIdx;
lIdx = (ulPage >> 8) & 0xFF;
*pulPtr = lIdx;
//
// Deassert ALE.
//
*pucPortB &= ~HwPortBALE;
//
// Wait for at least 7uS for the row to copy from the cell array.
//
for(lIdx = 0; lIdx < 256; lIdx++)
{
}
//
// Read the data from this page.
//
for(lIdx = 0; lIdx < ulNANDPageSize; lIdx++)
{
pucBuffer[lIdx] = *pulPtr;
}
//
// Read the spare area if requested.
//
if(bReadSpare)
{
for(lIdx = 0; lIdx < (ulNANDPageSize / 32); lIdx++)
{
pucBuffer[ulNANDPageSize + lIdx] = *pulPtr;
}
}
//
// De-select the NAND FLASH.
//
*pucPortB &= ~HwPortBNANDCS;
}
//****************************************************************************
//
// NANDEraseBlock erases the specified block of the on-board NAND FLASH.
//
//****************************************************************************
void
NANDEraseBlock(unsigned long ulBlock)
{
unsigned long * volatile pulPtr = (unsigned long *)HwNANDAddress;
unsigned char * volatile pucPortB = (unsigned char *)(HwBaseAddress +
HwPortB);
long lIdx;
//
// Make sure that we know the layout of the on-board NAND FLASH.
//
if(!ulNANDReadID)
{
NANDGetSize(0, 0, 0, 0);
}
//
// Convert the block number into the page number of the first page of the
// block. This is dependent on the number of pages per block.
//
switch(ulNANDPagesPerBlock)
{
case 16:
{
ulBlock <<= 4;
break;
}
case 32:
{
ulBlock <<= 5;
break;
}
}
//
// Select the NAND FLASH.
//
*pucPortB |= HwPortBNANDCS;
//
// Assert CLE.
//
*pucPortB |= HwPortBCLE;
//
// Write the auto block erase setup command.
//
*pulPtr = 0x60;
//
// Deassert CLE.
//
*pucPortB &= ~HwPortBCLE;
//
// Assert ALE.
//
*pucPortB |= HwPortBALE;
//
// Write the address.
//
lIdx = ulBlock & 0xFF;
*pulPtr = lIdx;
lIdx = (ulBlock >> 8) & 0xFF;
*pulPtr = lIdx;
//
// Deassert ALE.
//
*pucPortB &= ~HwPortBALE;
//
// Assert CLE.
//
*pucPortB |= HwPortBCLE;
//
// Write the erase command.
//
*pulPtr = 0xd0;
//
// Write the read status command.
//
*pulPtr = 0x70;
//
// Deassert CLE.
//
*pucPortB &= ~HwPortBCLE;
//
// Wait until the erase has completed.
//
while((*pulPtr & 0x40) != 0x40)
{
for(lIdx = 0; lIdx < 1024; lIdx++)
{
}
}
//
// Deselect the NAND FLASH.
//
*pucPortB &= ~HwPortBNANDCS;
}
//****************************************************************************
//
// NANDWritePage writes data to the specified page of the on-board NAND FLASH.
//
//****************************************************************************
void
NANDWritePage(unsigned long ulPage, int bWriteSpare, unsigned char *pucBuffer)
{
unsigned long * volatile pulPtr = (unsigned long *)HwNANDAddress;
unsigned char * volatile pucPortB = (unsigned char *)(HwBaseAddress +
HwPortB);
long lIdx;
//
// Make sure that we know the layout of the on-board NAND FLASH.
//
if(!ulNANDReadID)
{
NANDGetSize(0, 0, 0, 0);
}
//
// Select the NAND FLASH.
//
*pucPortB |= HwPortBNANDCS;
//
// Assert CLE.
//
*pucPortB |= HwPortBCLE;
//
// Write the sequential data input command.
//
*pulPtr = 0x80;
//
// Deassert CLE.
//
*pucPortB &= ~HwPortBCLE;
//
// Assert ALE.
//
*pucPortB |= HwPortBALE;
//
// Write the address.
//
*pulPtr = 0x00;
lIdx = ulPage & 0xFF;
*pulPtr = lIdx;
lIdx = (ulPage >> 8) & 0xFF;
*pulPtr = lIdx;
//
// Deassert ALE.
//
*pucPortB &= ~HwPortBALE;
//
// Write the data to this page.
//
for(lIdx = 0; lIdx < ulNANDPageSize; lIdx++)
{
*pulPtr = pucBuffer[lIdx];
}
//
// Write data for the spare area if requested.
//
if(bWriteSpare)
{
for(lIdx = 0; lIdx < (ulNANDPageSize / 32); lIdx++)
{
*pulPtr = pucBuffer[ulNANDPageSize + lIdx];
}
}
//
// Assert CLE.
//
*pucPortB |= HwPortBCLE;
//
// Write the program command.
//
*pulPtr = 0x10;
//
// Write the read status command.
//
*pulPtr = 0x70;
//
// Deassert CLE.
//
*pucPortB &= ~HwPortBCLE;
//
// Wait until the program has completed.
//
while((*pulPtr & 0x40) != 0x40)
{
for(lIdx = 0; lIdx < 1024; lIdx++)
{
}
}
//
// Deselect the NAND FLASH.
//
*pucPortB &= ~HwPortBNANDCS;
}
//****************************************************************************
//
// SMGetSize determines the size and layout of the SmartMedia card based on
// the device ID read from the SmartMedia card. If an invalid ID is read, or
// the Smart Media card is not inserted, an error will be returned.
//
//****************************************************************************
long
SMGetSize(unsigned long *pulDeviceSize, unsigned long *pulPageSize,
unsigned long *pulPagesPerBlock, unsigned long *pulNumBlocks)
{
unsigned long * volatile pulPtr = (unsigned long *)HwNANDAddress;
unsigned char * volatile pucPortB = (unsigned char *)(HwBaseAddress +
HwPortB);
unsigned char * volatile pucPortBdir = (unsigned char *)(HwBaseAddress +
HwDdrB);
unsigned char volatile ucTemp;
long lIdx;
//
// Set the port B data direction register.
//
*pucPortBdir = 0xFA;
//
// Set the initial value of port B, with both the NAND and Smart
// Media chip selects set to 0.
//
*pucPortB = 0x00;
//
// Select the SmartMedia card.
//
*pucPortB |= HwPortBSMCS;
//
// Assert CLE.
//
*pucPortB |= HwPortBCLE;
//
// Write the read id command.
//
*pulPtr = 0x90;
//
// Deassert CLE.
//
*pucPortB &= ~HwPortBCLE;
//
// Assert ALE.
//
*pucPortB |= HwPortBALE;
//
// Write the address.
//
*pulPtr = 0x00;
//
// Deassert ALE.
//
*pucPortB &= ~HwPortBALE;
//
// Read the maker ID.
//
ucTemp = *pulPtr;
//
// Read the device ID.
//
ucTemp = *pulPtr;
//
// Deassert the SmartMedia card.
//
*pucPortB &= ~HwPortBSMCS;
//
// Find this device ID in our table.
//
for(lIdx = 0; lIdx < NUMIDS; lIdx++)
{
if(ucTemp == sNANDMap[lIdx].ucID)
{
break;
}
}
//
// Return an error if we could not find this device ID.
//
if(lIdx == NUMIDS)
{
return(0);
}
//
// Fill in the SmartMedia globals based on the physical layout of the
// SmartMedia card.
//
ulSMPageSize = sNANDMap[lIdx].ucPageSize ? 512 : 256;
ulSMPagesPerBlock = sNANDMap[lIdx].ucPagesPerBlock;
ulSMNumBlocks = (unsigned long)sNANDMap[lIdx].ucBlocks << 9;
//
// If requested, return the size of the SmartMedia card.
//
if(pulDeviceSize)
{
*pulDeviceSize = ulSMPageSize * ulSMPagesPerBlock * ulSMNumBlocks;
*pulPageSize = ulSMPageSize;
*pulPagesPerBlock = ulSMPagesPerBlock;
*pulNumBlocks = ulSMNumBlocks;
}
//
// Success.
//
return(1);
}
//****************************************************************************
//
// SMReadPage reads data from the specified page of the SmartMedia card.
//
//****************************************************************************
#if 0
long
SMReadPage(unsigned long ulPage, int bReadSpare, unsigned char *pucBuffer)
{
unsigned long * volatile pulPtr = (unsigned long *)HwNANDAddress;
unsigned char * volatile pucPortB = (unsigned char *)(HwBaseAddress +
HwPortB);
long lIdx;
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -