📄 flashwriternand.c
字号:
///////////////////////////////////////////////////////////////////////////////
//
// Copyright 1999, 2000, 2001, 2002, 2003, 2004 by Texas Instruments Incorporated. All rights
// reserved. Property of Texas Instruments Incorporated. Restricted rights to use,
// duplicate or disclose this code are granted through contract.
//
///////////////////////////////////////////////////////////////////////////////
//
// This file contains the stand-alone code for copying an Image from Memory to
// Flash.
//
// Last Revision date: 2-3-04
// Release 1.8
//
//Headers
//
#include "types.h"
#include "Flash_params.h"
#include "OMAP.h"
//
//Globals
//
//Parameters downloaded in .vars section
//(this sits at fixed memory locations!)
#pragma DATA_SECTION ( image, ".image" )
ULONG image;
#pragma DATA_SECTION ( global_vars, ".vars" )
Download_Parms global_vars;
Download_Parms *gp_vars = &global_vars;
//
//Build Parameters
#define USES_CCS
// HW Register pointers
volatile USHORT *pNFReg;
volatile USHORT *pNFCMD;
volatile USHORT *pNFADDR;
volatile USHORT *pNFDATA;
volatile USHORT *pNFSTAT;
USHORT gStatus_Mask;
PageInfo block_reserved = {
(~(BLOCK_RESERVED | BLOCK_READONLY)),
(~(BADBLOCKMARK))
};
void printinfo(ULONG size, ULONG srcAddr, ULONG destAddr)
{
printf("FlashWriter Version 1.8\n");
printf("Starting Download to NAND Flash\n");
printf("Image is %d bytes long\n", size);
printf("Reading Image from: %08X\n", srcAddr);
printf("Writing Image to: %08X\n", destAddr);
}
void printNANDflashtype(enum NANDFlashType flash_id)
{
switch (flash_id)
{
case NANDFLASH_SAMSUNG_32x8_Q:
printf("Samsung Nand Flash K9F5608Q0B 32MB \n");
break;
case NANDFLASH_SAMSUNG_32x8_U:
printf("Samsung Nand Flash K9F5608Q0U 32MB \n");
break;
case NANDFLASH_SAMSUNG_16x16_Q:
printf("Samsung Nand Flash K9F5616Q0B 32MB \n");
break;
case NANDFLASH_SAMSUNG_16x16_U:
printf("Samsung Nand Flash K9F5616Q0U 32MB \n");
break;
case NANDFLASH_NOT_FOUND:
default:
printf("Flash not Found or unsupported!\n");
break;
}
}
//
// This function compares two ECC's and indicates if there is an error.
// If the error can be corrected it will be corrected to the buffer
//
BYTE flash_CompareEcc( BYTE* ecc_data1, BYTE* ecc_data2, BYTE* page_data)
{
WORD i;
BYTE tmp0_bit[8],tmp1_bit[8],tmp2_bit[8];
BYTE comp0_bit[8],comp1_bit[8],comp2_bit[8];
BYTE tmp[3];
BYTE ecc_bit[24];
BYTE ecc_sum=0;
BYTE ecc_value,find_bit=0;
WORD find_byte=0;
for( i=0; i<=2; i++ )
{
*(ecc_data1+i)=~(*(ecc_data1+i));
*(ecc_data2+i)=~(*(ecc_data2+i));
}
for(i=0;i<8;i++)
{
tmp0_bit[i]= *ecc_data1%2;
*ecc_data1=*ecc_data1/2;
tmp1_bit[i]= *(ecc_data1+1)%2;
*(ecc_data1+1)=*(ecc_data1+1)/2;
tmp2_bit[i]= *(ecc_data1+2)%2;
*(ecc_data1+2)=*(ecc_data1+2)/2;
}
for(i=0;i<8;i++)
{
comp0_bit[i]= *ecc_data2%2;
*ecc_data2=*ecc_data2/2;
comp1_bit[i]= *(ecc_data2+1)%2;
*(ecc_data2+1)=*(ecc_data2+1)/2;
comp2_bit[i]= *(ecc_data2+2)%2;
*(ecc_data2+2)=*(ecc_data2+2)/2;
}
for( i=0; i<6; i++ )
{
ecc_bit[i] = tmp2_bit[i+2]^comp2_bit[i+2];
}
for( i=0; i<8; i++)
{
ecc_bit[i+6] = tmp0_bit[i]^comp0_bit[i];
ecc_bit[i+14] = tmp1_bit[i]^comp1_bit[i];
}
ecc_bit[22] = tmp2_bit[0] ^ comp2_bit[0];
ecc_bit[23] = tmp2_bit[1] ^ comp2_bit[1];
for( i=0; i<24; i++ )
{
ecc_sum += ecc_bit[i];
}
switch(ecc_sum)
{
case 0: // Not reached because this function is not called if ECC values are equal
return NO_ERROR;
case 1:
return ECC_ERROR;
case 12:
find_byte = (ecc_bit[23]<<8)+(ecc_bit[21]<<7)+(ecc_bit[19]<<6)
+(ecc_bit[17]<<5)+(ecc_bit[15]<<4)+(ecc_bit[13]<<3)
+(ecc_bit[11]<<2)+(ecc_bit[9]<<1)+ecc_bit[7];
find_bit = (ecc_bit[5]<<2) +(ecc_bit[3]<<1)+ecc_bit[1];
ecc_value = (page_data[find_byte]>>find_bit)%2;
if(ecc_value==0)
{
ecc_value=1;
} else
{
ecc_value=0;
}
*tmp=page_data[find_byte];
for(i=0;i<8;i++)
{
tmp0_bit[i]= *tmp%2;
*tmp=*tmp/2;
}
tmp0_bit[find_bit]=ecc_value;
*tmp=(tmp0_bit[7]<<7)+(tmp0_bit[6]<<6)+(tmp0_bit[5]<<5)
+(tmp0_bit[4]<<4)+(tmp0_bit[3]<<3)+(tmp0_bit[2]<<2)
+(tmp0_bit[1]<<1)+tmp0_bit[0];
page_data[find_byte] = *tmp;
return CORRECTED_ERROR;
default:
return UNCORRECTED_ERROR;
}
}
void InitEcc()
{
//Setup NFC to generate ECC codes for page size
pNFC_ECC_SELECT = 0x00; //Generate 3 ECC bytes in NND_ECC1,2,3
pNFC_CTRL = 0x00000001; //Setting for Little Endian, ECC boundary = 512, ECC = enabled
pNFC_PSC_CLK = 0x0; //Set Clock divider = 1 (fastest clock, won't work for real HW connect on NFC)
pNFC_RESET == 0x1; //Resets the ECC generation
}
void EccGenNFC(BYTE write_data[512], LPBYTE ecc_gen)
{
ULONG ecc;
int i;
ULONG *data;
//Send the data 4 bytes at a time to the NAND Flash Controller
data = (ULONG *) write_data;
for(i=0;i<PAGE_SIZE/4;i++)
{
pNFC_ACCESS = *data;
data++;
}
//read the ECC values
ecc = pNFC_ECC_1;
//OK now we need to bit twiddle the results to match the expected ECC correction
ecc_gen[0] = ecc & 0xFF;
ecc_gen[1] = (ecc & 0xFF0000) >> 16;
ecc_gen[2] = ((ecc & 0x0F000000) >> 20) | ((ecc & 0xF00)>>4);
//To use for correction...
pNFC_RESET = 0x1; //Reset the ECC calculator for the next page
}
void reorderECC(LPBYTE ecc_in, LPBYTE ecc_out)
{
ULONG ecc;
ecc = ( ecc_in[0] )
| ( ecc_in[1]<<16 )
| ( (ecc_in[2]&0xF0)<<20 )
| ( (ecc_in[2]&0x0F)<<8 );
//OK now we need to bit twiddle the results to match the expected ECC correction
ecc_out[0] = ~((ecc & BIT22 >> (21-7)) //P64o
| (ecc & BIT6 <<1) // (5-6)) //P64e
| (ecc & BIT21 >> (20-5)) //P32o
| (ecc & BIT5 >> (4-4)) //P32e
| (ecc & BIT20 >> (19-3)) //P16o
| (ecc & BIT4 >> (3-2)) //P16e
| (ecc & BIT19 >> (18-1)) //P8o
| (ecc & BIT3 >> (2-0))); //P8e
ecc_out[1] = ~((ecc & BIT26 >> (25-7)) //P1024o
| (ecc & BIT10 >> (9-6)) //P1024e
| (ecc & BIT25 >> (24-5)) //P512o
| (ecc & BIT9 >> (8-4)) //P512e
| (ecc & BIT24 >> (23-3)) //P256o
| (ecc & BIT8 >> (7-2)) //P256e
| (ecc & BIT23 >> (22-1)) //P128o
| (ecc & BIT7 >> (6-0))); //P128e
ecc_out[2] = ~((ecc & BIT18 >> (17-7)) //P4o
| (ecc & BIT2 << 5) //>> (2-6)) //P4e
| (ecc & BIT17 >> (16-5)) //P2o
| (ecc & BIT1 << 4) //>> (1-4)) //P2e
| (ecc & BIT16 >> (15-3)) //P1o
| (ecc & BIT0 << 3) //>> (0-2)) //P1e
| (ecc & BIT27 >> (26-1)) //P2048o
| (ecc & BIT11 >> (10-0))); //P2048e
}
////////////////////////////////////////////////////////////////////////////////
//NAND CODE
////////////////////////////////////////////////////////////////////////////////
#define NF_CMD(cmd) WRITE_REGISTER_USHORT(pNFCMD, (USHORT) (cmd))
#define NF_ADDR(addr) WRITE_REGISTER_USHORT(pNFADDR, (USHORT) (addr & 0xff))
#define NF_DATA_R() READ_REGISTER_USHORT(pNFDATA)
#define NF_DATA_W(val) WRITE_REGISTER_USHORT(pNFDATA, (USHORT) (val))
#define NF_STAT() READ_REGISTER_ULONG(pNFSTAT)
void NF_WAITRB()
{
while(!((NF_STAT() & gStatus_Mask) == gStatus_Mask));
}
void reset_NAND()
{
NF_CMD(CMD_RESET);
NF_WAITRB();
}
////////////////////////////////////////////////////////////////////////////////
// NAND_WriteProtection()
// Enables/disables any flash write protection.
////////////////////////////////////////////////////////////////////////////////
void NAND_WriteProtection( BOOL wp )
{
ULONG temp;
if (wp) // Enable.
{
// Enable write protection in TC.
temp = READ_REGISTER_ULONG(MIF_CONFIG_REG);
temp &= ~BIT0;
WRITE_REGISTER_ULONG( MIF_CONFIG_REG, temp);
}
else // Disable.
{
// Disable write protection in TC.
temp = READ_REGISTER_ULONG(MIF_CONFIG_REG);
temp |= BIT0;
WRITE_REGISTER_ULONG(MIF_CONFIG_REG, temp);
}
}
///////////////////////////////////////////////////////////////////////////////
// Identify_Nand_Flash
// Description:
// Reads the Flash Manufacturer ID and device codes to differentiate
// the nand flash device.
// Return:
// NANDFLASH_NOT_FOUND
// NANDFLASH_SAMSUNG_32x8_Q
// NANDFLASH_SAMSUNG_32x8_U
// NANDFLASH_SAMSUNG_16x16_Q
// NANDFLASH_SAMSUNG_16x16_U
///////////////////////////////////////////////////////////////////////////////
enum NANDFlashType IdentifyNandFlash(void)
{
USHORT wManufacturer;
USHORT wDevice;
// Get the Manufacturer & Device ID
// Send Read ID Command
NF_CMD(CMD_READID);
NF_WAITRB();
// Send Address 00h
NF_ADDR(0x00);
NF_WAITRB();
// Read the manufacturer ID
wManufacturer = NF_DATA_R();
// Read the device code
wDevice = NF_DATA_R();
//return
if ( wManufacturer != SAMSUNG_MANUFACT_ID )
{
return NANDFLASH_NOT_FOUND;
}
switch ( wDevice )
{
case SAMSUNG_K9F5608Q0B:
return NANDFLASH_SAMSUNG_32x8_Q;
case SAMSUNG_K9F5608U0B:
return NANDFLASH_SAMSUNG_32x8_U;
case SAMSUNG_K9F5616Q0B:
return NANDFLASH_SAMSUNG_16x16_Q;
case SAMSUNG_K9F5616U0B:
return NANDFLASH_SAMSUNG_16x16_U;
default:
return NANDFLASH_NOT_FOUND;
}
}
///////////////////////////////////////////////////////////////////////////
//
// NAND_FinishCommand
//
// Write data into the Page. The current implementation only handles
// one Page at a time.
//
///////////////////////////////////////////////////////////////////////////
BOOL NAND_FinishCommand(BYTE bCmd)
{
BOOL bRet;
// Complete operation
NF_CMD(bCmd);
// Wait for ready bit
NF_WAITRB();
// Check the status
NF_CMD(CMD_STATUS);
bRet = !(NF_DATA_R() & STATUS_ERROR);
// Disable the chip
return bRet;
}
///////////////////////////////////////////////////////////////////////////
//
// NAND_SendFullCommand
//
// Send Command with Full Address
//
///////////////////////////////////////////////////////////////////////////
void NAND_SendFullCommand(BYTE bCmd, ULONG PageAddr, ULONG dwOffset)
{
// Write the command
NF_CMD(bCmd);
// Write the address
NF_ADDR(dwOffset);
NF_ADDR(PageAddr);
NF_ADDR((PageAddr >> 8));
if (NEED_EXT_ADDR)
{
NF_ADDR((PageAddr >> 16));
}
// Wait for the Ready bit
NF_WAITRB();
}
////////////////////////////////////////////////////////////////////////////
//
// NAND_EraseBlock
//
// Erase the given block
//
////////////////////////////////////////////////////////////////////////////
BOOL NAND_EraseBlock(ULONG blockID)
{
ULONG dwPageID = blockID << 5;
// Issue command
NF_CMD(CMD_ERASE);
// Set up address
NF_ADDR((dwPageID) & 0xff);
NF_ADDR((dwPageID >> 8) & 0xff);
if (NEED_EXT_ADDR)
{
NF_ADDR((dwPageID >> 16) & 0xff);
}
// Complete erase operation
if( !NAND_FinishCommand(CMD_ERASE2))
{ //Failed Erase Operation
return FALSE;
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////////
//
// NAND_SimpleRead
//
// Read data out of the Page. The current implementation only handles
// one Page at a time.
//
//////////////////////////////////////////////////////////////////////////
void NAND_SimpleRead(LPBYTE pPageBuff, ULONG dwNumBytes)
{
ULONG i;
ULONG dwNumWords;
USHORT usData;
dwNumWords = (dwNumBytes + 1)/sizeof(USHORT);
if (pPageBuff)
{ // Handle unaligned buffer
if (((ULONG)pPageBuff) & 0x1)
{
for(i=0; i<dwNumWords; i++)
{
usData = NF_DATA_R();
pPageBuff[i*2] = (usData & 0xff);
pPageBuff[i*2+1] = (usData >> 8) & 0xff;
}
} else
{
for(i=0; i<dwNumWords; i++)
{
((USHORT *)pPageBuff)[i] = NF_DATA_R();
}
}
} else
{
// Advance the read pointer
for(i=0; i<dwNumWords; i++)
{
usData = NF_DATA_R();
}
}
}
///////////////////////////////////////////////////////////////////////////
//
// NAND_SimpleWrite
//
// Write data into the Page. The current implementation only handles
// one Page at a time.
//
///////////////////////////////////////////////////////////////////////////
void NAND_SimpleWrite(LPBYTE pPageBuff, ULONG dwNumBytes)
{
ULONG i;
ULONG dwNumWrites;
//NOTE: This hardware is odd: only a byte can be written at a time and it must reside in the
//upper byte of a USHORT.
dwNumWrites = (dwNumBytes + 1)/sizeof(USHORT);
if (pPageBuff)
{
// Special case to handle un-aligned buffer pointer.
for(i=0; i<dwNumWrites; i++)
{
NF_DATA_W( ((USHORT *)pPageBuff)[i] );
}
} else
{
// Make sure we advance the Flash's write pointer (even though we aren't writing real data)
for(i=0; i<dwNumWrites; i++)
{
NF_DATA_W(0xffff);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -