📄 cmd_nand.c
字号:
// ----------------------------------------------------------------------------
// ATMEL Microcontroller Software Support - ROUSSET -
// ----------------------------------------------------------------------------
// DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
// DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ----------------------------------------------------------------------------
/************************************************************************/
/* smc_prim.c */
/* routines to talk to the serial flash. */
/* */
/* Note that these routines all must be re-entrant. Since they talk */
/* to hardware, this also means that they must disable tasking */
/* in most cases. */
/* */
/* Note on ECC in Sunburst. */
/* In order to be compatible with parts written by old software */
/* the presence of ECC data must be checked for. The ECC */
/* data is the first 4 bytes after the block. If the next 2 bytes */
/* (bytes 4 and 5 in the ECC area) are not the same value, it is */
/* assumed that the block has ECC data. */
/* */
//*----------------------------------------------------------------------------
//*----------------------------------------------------------------------------
// $Revision: 1.12 $
// $Date: 2006/06/19 16:29:49 $
// $Author: nico $
/************************************************************************/
#include "cmd_nand.h"
#include "main.h"
extern char message[];
/*
* Chip ID list
*
* Name. ID code, pagesize, chipsize in MegaByte, eraseblock size,
* options
*
* Pagesize; 0, 256, 512
* 0 get this information from the extended chip ID
+ 256 256 Byte page size
* 512 512 Byte page size
*/
struct nand_flash_dev nand_flash_ids[] = {
{0x6e, 256, 1, 0x1000, 0}, // "NAND 1MiB 5V 8-bit"
{0x64, 256, 2, 0x1000, 0}, // "NAND 2MiB 5V 8-bit"
{0x6b, 512, 4, 0x2000, 0}, // "NAND 4MiB 5V 8-bit"
{0xe8, 256, 1, 0x1000, 0}, // "NAND 1MiB 3,3V 8-bit"
{0xec, 256, 1, 0x1000, 0}, // "NAND 1MiB 3,3V 8-bit"
{0xea, 256, 2, 0x1000, 0}, // "NAND 2MiB 3,3V 8-bit"
{0xd5, 512, 4, 0x2000, 0}, // "NAND 4MiB 3,3V 8-bit"
{0xe3, 512, 4, 0x2000, 0}, // "NAND 4MiB 3,3V 8-bit"
{0xe5, 512, 4, 0x2000, 0}, // "NAND 4MiB 3,3V 8-bit"
{0xd6, 512, 8, 0x2000, 0}, // "NAND 8MiB 3,3V 8-bit"
{0x39, 512, 8, 0x2000, 0}, // "NAND 8MiB 1,8V 8-bit"
{0xe6, 512, 8, 0x2000, 0}, // "NAND 8MiB 3,3V 8-bit"
{0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16}, // "NAND 8MiB 1,8V 16-bit"
{0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16}, // "NAND 8MiB 3,3V 16-bit"
{0x33, 512, 16, 0x4000, 0}, // "NAND 16MiB 1,8V 8-bit"
{0x73, 512, 16, 0x4000, 0}, // "NAND 16MiB 3,3V 8-bit"
{0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16}, // "NAND 16MiB 1,8V 16-bit"
{0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16}, // "NAND 16MiB 3,3V 16-bit"
{0x35, 512, 32, 0x4000, 0}, // "NAND 32MiB 1,8V 8-bit"
{0x75, 512, 32, 0x4000, 0}, // "NAND 32MiB 3,3V 8-bit"
{0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16}, // "NAND 32MiB 1,8V 16-bit"
{0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16}, // "NAND 32MiB 3,3V 16-bit"
{0x36, 512, 64, 0x4000, 0}, // "NAND 64MiB 1,8V 8-bit"
{0x76, 512, 64, 0x4000, 0}, // "NAND 64MiB 3,3V 8-bit"
{0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16}, // "NAND 64MiB 1,8V 16-bit"
{0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16}, // "NAND 64MiB 3,3V 16-bit"
{0x78, 512, 128, 0x4000, 0}, // "NAND 128MiB 1,8V 8-bit"
{0x79, 512, 128, 0x4000, 0}, // "NAND 128MiB 3,3V 8-bit"
{0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16}, // "NAND 128MiB 1,8V 16-bit"
{0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16}, // "NAND 128MiB 3,3V 16-bit"
/* These are the new chips with large page size. The pagesize, erasesize
and buswidth are determined from the extended id bytes
*/
/* 1 Gigabit */
{0xA1, 0, 128, 0, 0}, // "NAND 128MiB 1,8V 8-bit"
{0xF1, 0, 128, 0, 0}, // "NAND 128MiB 3,3V 8-bit"
{0xB1, 0, 128, 0, 0}, // "NAND 128MiB 1,8V 16-bit"
{0xC1, 0, 128, 0, 0}, // "NAND 128MiB 3,3V 16-bit"
/* 2 Gigabit */
{0xAA, 0, 256, 0, 0}, // "NAND 256MiB 1,8V 8-bit"
{0xDA, 0, 256, 0, 0}, // "NAND 256MiB 3,3V 8-bit"
{0xBA, 0, 256, 0, 0}, // "NAND 256MiB 1,8V 16-bit"
{0xCA, 0, 256, 0, 0}, // "NAND 256MiB 3,3V 16-bit"
/* 4 Gigabit */
{0xAC, 0, 512, 0, 0}, // "NAND 512MiB 1,8V 8-bit"
{0xDC, 0, 512, 0, 0}, // "NAND 512MiB 3,3V 8-bit"
{0xBC, 0, 512, 0, 0}, // "NAND 512MiB 1,8V 16-bit"
{0xCC, 0, 512, 0, 0}, // "NAND 512MiB 3,3V 16-bit"
/* 8 Gigabit */
{0xA3, 0, 1024, 0, 0}, // "NAND 1GiB 1,8V 8-bit"
{0xD3, 0, 1024, 0, 0}, // "NAND 1GiB 3,3V 8-bit"
{0xB3, 0, 1024, 0, 0}, // "NAND 1GiB 1,8V 16-bit"
{0xC3, 0, 1024, 0, 0}, // "NAND 1GiB 3,3V 16-bit"
/* 16 Gigabit */
{0xA5, 0, 2048, 0, 0}, // "NAND 2GiB 1,8V 8-bit"
{0xD5, 0, 2048, 0, 0}, // "NAND 2GiB 3,3V 8-bit"
{0xB5, 0, 2048, 0, 0}, // "NAND 2GiB 1,8V 16-bit"
{0xC5, 0, 2048, 0, 0}, // "NAND 2GiB 3,3V 16-bit"
{0, 0, 0, 0, 0}
};
/*
* Manufacturer ID list
*/
int nand_manufacturers[] = {
NAND_MFR_TOSHIBA,
NAND_MFR_SAMSUNG,
NAND_MFR_FUJITSU,
NAND_MFR_NATIONAL,
NAND_MFR_STMICRO,
NAND_MFR_MICRON,
0x0
};
struct nand_info nand_chip;
/************************************************************************/
/* nand_write_data for large blocks */
/* This routine reads a buffer of data to the serial flash */
/* device. */
/* */
/* ARGUMENTS: */
/* file_pos Position (in bytes) in flash to read from */
/* buffer Buffer to place data into */
/* bytes_to_write Number of bytes to write */
/************************************************************************/
void nand_write_page(unsigned long file_pos_ll, unsigned char *buffer,
unsigned int bytes_to_write,int type)
{
unsigned long int end_pos, file_pos;
unsigned long int column, page_addr;
int bytes_in_page;
if (bytes_to_write > 0)
{
file_pos = (unsigned long int)file_pos_ll;
NAND_ENABLE_CE;
NAND_WAIT_READY;
WRITE_NAND_COMMAND(NAND_CMD_SEQIN, AT91_SMARTMEDIA_BASE);
if(type == NAND_OOB) column = nand_chip.nand_bytes_per_page;
else column = 0/*file_pos % nand_chip.nand_bytes_per_page*//* can write only on page boundary*/;
page_addr = file_pos / nand_chip.nand_bytes_per_page;
if (nand_chip.nand_buswidth_16 == TRUE)
column >>= 1;
// Send Column Address
WRITE_NAND_ADDRESS(column & 0x0FF, AT91_SMARTMEDIA_BASE);
WRITE_NAND_ADDRESS(column >> 8, AT91_SMARTMEDIA_BASE);
// Send Row Address
WRITE_NAND_ADDRESS(page_addr & 0x0FF, AT91_SMARTMEDIA_BASE);
WRITE_NAND_ADDRESS((page_addr >> 8) & 0x0FF, AT91_SMARTMEDIA_BASE);
// Large Blocks 2Gb devices uses 5 address cycles
if (nand_chip.extended_address_s == TRUE)
WRITE_NAND_ADDRESS((page_addr >> 16) & 0x0FF, AT91_SMARTMEDIA_BASE);
end_pos = file_pos + bytes_to_write;
bytes_in_page = (int)(nand_chip.nand_bytes_per_page - (file_pos & nand_chip.page_mask));
while (file_pos < end_pos)
{
if (nand_chip.nand_buswidth_16 == TRUE)
{
unsigned short wData = (*buffer++) | (*buffer++ << 8);
WRITE_NAND16(wData , AT91_SMARTMEDIA_BASE);
file_pos += 2;
bytes_in_page -= 2;
} else {
WRITE_NAND16(*buffer++ , AT91_SMARTMEDIA_BASE);
file_pos++;
bytes_in_page--;
}
}
WRITE_NAND_COMMAND(NAND_CMD_PAGEPROG, AT91_SMARTMEDIA_BASE);
NAND_WAIT_READY;
NAND_DISABLE_CE;
}
}
/************************************************************************/
/* nand_read_data for large blocks */
/* This routine reads a buffer of data from the serial flash */
/* device. */
/* */
/* ARGUMENTS: */
/* file_pos Position (in bytes) in flash to read from */
/* buffer Buffer to place data into */
/* bytes_to_read Number of bytes to read */
/************************************************************************/
void nand_read_page(unsigned long file_pos_ll, unsigned char *buffer,
unsigned int bytes_to_read,int type)
{
unsigned long int end_pos, file_pos;
unsigned long int column, page_addr;
int bytes_in_page;
if (bytes_to_read > 0)
{
file_pos = (unsigned long int)file_pos_ll;
NAND_ENABLE_CE;
NAND_WAIT_READY;
WRITE_NAND_COMMAND(NAND_CMD_READ0, AT91_SMARTMEDIA_BASE);
if(type == NAND_OOB) column = nand_chip.nand_bytes_per_page;
else column = 0/*file_pos % nand_chip.nand_bytes_per_page*//* can write only on page boundary*/;
page_addr = file_pos / nand_chip.nand_bytes_per_page;
if (nand_chip.nand_buswidth_16 == TRUE)
column >>= 1;
// Send Column Address
WRITE_NAND_ADDRESS(column & 0x0FF, AT91_SMARTMEDIA_BASE);
WRITE_NAND_ADDRESS(column >> 8, AT91_SMARTMEDIA_BASE);
// Send Row Address
WRITE_NAND_ADDRESS(page_addr & 0x0FF, AT91_SMARTMEDIA_BASE);
WRITE_NAND_ADDRESS((page_addr >> 8) & 0x0FF, AT91_SMARTMEDIA_BASE);
// Large Blocks 2Gb devices uses 5 address cycles
if (nand_chip.extended_address_s == TRUE)
WRITE_NAND_ADDRESS((page_addr >> 16) & 0x0FF, AT91_SMARTMEDIA_BASE);
WRITE_NAND_COMMAND(NAND_CMD_READ_CONFIRM, AT91_SMARTMEDIA_BASE);
end_pos = file_pos + bytes_to_read;
bytes_in_page = (int)(nand_chip.nand_bytes_per_page - (file_pos & nand_chip.page_mask));
while (file_pos < end_pos)
{
NAND_WAIT_READY;
if (nand_chip.nand_buswidth_16 == TRUE)
{
unsigned short wData = READ_NAND16(AT91_SMARTMEDIA_BASE);
*buffer++ = (unsigned char)(wData & 0x00FF);
*buffer++ = (unsigned char)((wData >> 8) & 0x00FF);
file_pos += 2;
bytes_in_page -= 2;
} else {
*buffer++ = READ_NAND(AT91_SMARTMEDIA_BASE);
file_pos++;
bytes_in_page--;
}
}
NAND_DISABLE_CE;
}
}
//*----------------------------------------------------------------------------
//* \fn AT91F_NandFlash_Erase_Page
//* \brief
//*----------------------------------------------------------------------------
void AT91F_NandFlash_Erase_Block(unsigned int Block_Number){
unsigned long volatile Block_Add;
Block_Add = Block_Number * nand_chip.nand_bytes_per_page * 64;
NAND_ENABLE_CE;
WRITE_NAND_COMMAND(NAND_CMD_ERASE1, AT91_SMARTMEDIA_BASE);
WRITE_NAND_ADDRESS( Block_Add, AT91_SMARTMEDIA_BASE);
WRITE_NAND_ADDRESS( (Block_Add >> 8), AT91_SMARTMEDIA_BASE);
WRITE_NAND_ADDRESS( (Block_Add >> 16), AT91_SMARTMEDIA_BASE);
WRITE_NAND_COMMAND(NAND_CMD_ERASE2, AT91_SMARTMEDIA_BASE);
WRITE_NAND_COMMAND(NAND_CMD_STATUS, AT91_SMARTMEDIA_BASE);
NAND_WAIT_READY;
NAND_DISABLE_CE;
}
/************************************************************************/
/* This routine returns the type of SMC chip installed. */
/************************************************************************/
smc_chip_t nand_chip_type(void)
{
int i = 0;
smc_chip_t chip_type;
unsigned char maker_id, device_id;
NAND_ENABLE_CE;
WRITE_NAND_COMMAND(NAND_CMD_READID, AT91_SMARTMEDIA_BASE);
WRITE_NAND_ADDRESS(0, AT91_SMARTMEDIA_BASE);
NAND_WAIT_READY;
maker_id = READ_NAND(AT91_SMARTMEDIA_BASE);
NAND_WAIT_READY;
device_id = READ_NAND(AT91_SMARTMEDIA_BASE);
chip_type = SMC_UNKNOWN;
while (nand_manufacturers[i] != 0)
{
if (maker_id == nand_manufacturers[i])
break;
i++;
}
if (nand_manufacturers[i] == 0)
return chip_type;
/* Print and store flash device information */
for (i = 0; nand_flash_ids[i].id != 0; i++)
{
if (device_id != nand_flash_ids[i].id)
continue;
sprintf(message, "NandFlash chip found:\n\r Manufacturer ID: 0x%2.2X Chip ID: 0x%2.2X\n\r",
maker_id, device_id);
AT91F_DBGU_Printk(message);
nand_chip.chipsize = nand_flash_ids[i].chipsize << 20;
// New devices have all the information in additional id bytes
if (!nand_flash_ids[i].pagesize)
{
int extid;
nand_chip.nand_large_blocks = TRUE;
if (nand_chip.chipsize > (128 << 20))
nand_chip.extended_address_s = TRUE;
// The 3rd id byte contains non relevant data ATM
extid = READ_NAND(AT91_SMARTMEDIA_BASE);
// The 4th id byte is the important one
extid = READ_NAND(AT91_SMARTMEDIA_BASE);
// Calc pagesize
nand_chip.nand_bytes_per_page = 1024 << (extid & 0x3);
extid >>= 4;
// Calc blocksize. Blocksize is multiples of 64KiB
nand_chip.blocksize = (64 * 1024) << (extid & 0x03);
extid >>= 2;
// Get buswidth information
if (extid & 0x01)
nand_chip.nand_buswidth_16 = TRUE;
}
else
{
/* Old devices have this data hardcoded in the
* device id table */
if (nand_chip.chipsize > (32 << 20))
nand_chip.extended_address_s = TRUE;
nand_chip.nand_bytes_per_page = nand_flash_ids[i].pagesize;
nand_chip.blocksize = nand_flash_ids[i].erasesize;
if (nand_flash_ids[i].buswidth & NAND_BUSWIDTH_16)
nand_chip.nand_buswidth_16 = TRUE;
}
nand_chip.page_mask = nand_chip.nand_bytes_per_page - 1;
break;
}
NAND_DISABLE_CE;
chip_type = SMC_KNOWN;
return chip_type;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -