1. Nand_Init()
int NandInit(void)
{
// -------------------------------
// Configure GPIO9 in Alt Funct. A
// -------------------------------
*((uint32_t *) (GPIO0_REG_START_ADDR + 0x20)) |= 0x00000200;
nand.addr.pBase = (volatile uint16_t *) NAND_FLASH_CS0_START_ADDR;
nand.addr.pCommand = (volatile uint8_t *) NAND_FLASH_CS0_START_ADDR + 0x00810000;
nand.addr.pCommonArea = (volatile uint8_t *) NAND_FLASH_CS0_START_ADDR + 0x01020000;
// Map The Space for FSMC Registers
nand.regs = (FSMCRegs *) 0x10100000;
// --------------------------------------------------
// Disable all the other CS that we do not use (NOR),
// keeping high bit 7 for disabling WP.
// This is a temporary solution to avoid conflicts
// --------------------------------------------------
// Bank NOR 0, 1, 2, 3 (to be removed when NOR comes)
// --------------------------------------------------
nand.regs->FSMC_BCR1 &= 0x00000080;
nand.regs->FSMC_BCR2 &= 0x00000080;
nand.regs->FSMC_BCR3 &= 0x00000080;
// -----------------------------------------------
// Set NAND Control Values depending on the CS
// -----------------------------------------------
// CONTROL REGISTER
// -----------------------------------------------
// address_low : 0
// page_length : 512 (for ECC calculation)
// ecc_logic : 0 (enabled when required)
// bus_width : 16
// mem_type : 1 (NAND)
// wait_feature : 1 (linked to GPIO9 Alt. Func. "A")
// pc_reset : 0
// -----------------------------------------------
nand.regs->FSMC_PCR0 = FMSC_PCR_BUS_WIDTH_16 | FMSC_PCR_MEM_TYPE_NAND
| FMSC_PCR_BANK_ENABLE | FMSC_PCR_WAIT_ENABLE;
// ----------------------------------------------
// Set NAND Timings Registers depending on the CS.
// -----------------------------------------------
// COMMON AREA
// -----------------------------------------------
// data_bus_hiz_phase : 0x0D
// addr_hold_phase : 0x0D
// wait_phase : 0x0D
// addr_setup_phase : 0x0D
// -----------------------------------------------
nand.regs->FSMC_PMEM0 = FMSC_PMEM_MEM0HIZ | FMSC_PMEM_MEM0HOLD
| FMSC_PMEM_MEM0WAIT | FMSC_PMEM_MEM0SET;
// -----------------------------------------
// Reset the device and wait till it's ready
// -----------------------------------------
*(nand.addr.pCommand) = 0xff;
// ---------------------------------------------
// Write the specific command for reading the ID
// ---------------------------------------------
*(nand.addr.pCommand) = 0x90;
*(nand.addr.pCommonArea) = 0x00;
// --------------------------------------------
// Assign the Device ID and the Manifacturer ID
// --------------------------------------------
nand.id.uiManID = (*(nand.addr.pBase) & 0xff);
nand.id.uiDeviceID = (*(nand.addr.pBase) & 0xff);
if (nand.id.uiManID != MAKER_ID || nand.id.uiDeviceID != DEVICE_ID)
return -1;
// -------------------------------------------------------------------
// Let's assume that the ECC is implementation is supported by default
// -------------------------------------------------------------------
// We support BCH8 (8 correctable bits every 512 bytes of data)
// -------------------------------------------------------------------
return 0;
}
2. FSMCRegs ---FSMC 是Nandflash controller 模块, FSMCRegs表示了该模块的寄存器情况
typedef volatile struct
{
uint32_t FSMC_BCR0; // 0x00
uint32_t FSMC_BTR0; // 0x04
uint32_t FSMC_BCR1; // 0x08
uint32_t FSMC_BTR1; // 0x0C
uint32_t FSMC_BCR2; // 0x10
uint32_t FSMC_BTR2; // 0x14
uint32_t FSMC_BCR3; // 0x18
uint32_t FSMC_BTR3; // 0x1C
uint32_t UNUSED0[8]; // [0x18 - 0x40]
uint32_t FSMC_PCR0; // 0x40
uint32_t FSMC_PISR0; // 0x44
uint32_t FSMC_PMEM0; // 0x48
uint32_t FSMC_PATT0; // 0x4C
uint32_t FSMC_PIO0; // 0x50
uint32_t FSMC_ECCR0; // 0x54
uint32_t FSMC_ECC2R0; // 0x58
uint32_t FSMC_ECC3R0; // 0x5C
} FSMCRegs;
3. Nand flash 模块的虚拟内存映射地址定义:
/* CF/CF+/NAND Flash chip-select 0 (SMPS0n LOW) */
#define NAND_FLASH_CS0_START_ADDR 0x40000000
#define NAND_FLASH_CS0_LENGTH 0x10000000
#define NAND_FLASH_CS0_END_ADDR (NAND_FLASH_CS0_START_ADDR+NAND_FLASH_CS0_LENGTH-1)
/* CF/CF+/NAND Flash chip-select 1 (SMPS1n LOW) */
#define NAND_FLASH_CS1_START_ADDR 0x50000000
#define NAND_FLASH_CS1_LENGTH 0x10000000
#define NAND_FLASH_CS1_END_ADDR (NAND_FLASH_CS1_START_ADDR+NAND_FLASH_CS1_LENGTH-1)
4. 一些nandflash相关的常量定义:
#define PAGE_SIZE DATA_BYTES_PER_SECTOR
#define NAND_SECTOR_SIZE PAGE_SIZE
#define NAND_SECTORS_PER_BLOCK SECTORS_PER_BLOCK;
#define ECC_WORD_LIMIT 256 // 512 Byte data is the max length for ECC.
#define ECC_BYTES_PER_SUB_BLOCK 16 // Effective number of ECC Byte per block.
#define ECC_WORD_PER_SUB_BLOCK 8 // Number of ECC Word per block with padding.
#define SIZE_BYTE_SUB_BLOCK 512 // Size in Byte per ECC data block.
#define PAGE(x) ((x + PAGE_SIZE - 1) / PAGE_SIZE)
/* --------FSMC--PCR------ */
#define FMSC_PCR_BUS_WIDTH_8 (0x0)
#define FMSC_PCR_BUS_WIDTH_16 (0x10)
#define FMSC_PCR_MEM_TYPE_NAND (0x8)
#define FMSC_PCR_BANK_ENABLE (0x4)
#define FMSC_PCR_WAIT_ENABLE (0x2)
#define FMSC_PCR_PC_RESET (0x0)
/* --------FSMC--PMEM 0------ */
#define FMSC_PMEM_MEM0HIZ (0x00<<24)
#define FMSC_PMEM_MEM0HOLD (NAND_TIMING_1<<16)
#define FMSC_PMEM_MEM0WAIT (NAND_TIMING_2<<8)
#define FMSC_PMEM_MEM0SET (0x00)
#define ERROR_NAND_BAD_BLOCK -6
5. 这是初始化时候会校验的nandflash两个出厂值
typedef struct
{
uint8_t uiManID;
uint8_t uiDeviceID;
} NAND_Id;
6. Nandflash, 使用时的地址情况定义
typedef struct
{
volatile uint8_t *pCommand; // Pointer to command area
volatile uint8_t *pCommonArea;// Pointer to common area
volatile uint8_t *pAttributeArea;// Pointer to attribute area
volatile uint16_t *pBase;// Pointer to I/O area
} NAND_Address;
7. nand_system_context_t --- nand 模块上下文定义,几乎包括了nandflash所有的信息
typedef struct
{
FSMCRegs *regs; // Virtual Address of the mapped register space (FSMC)
NAND_Id id; // Identity Card for the current device
NAND_Address addr; // Logical Addresses associated to the current NAND device
} nand_system_context_t;
8. ReadNandPages() --- 读取nandflash中指定的从起始页到结束页的内容到buffer中
uint32_t ReadNandPages(uint32_t page, uint8_t *buf, int pageCount, int endPage)
{
int err;
seekBlock(page);
while (pageCount && page <= endPage) {
cacheNext();
while (getBlockStatus()) {
// --------------------------------------------------
// Every time we meet a bad block, jump to next one
// --------------------------------------------------
page++;
if (page > endPage) {
puts("ERROR: Too many BAD BLOCKS for this image copy\r\n");
cacheEnd();
return 0;
}
cacheNext();
}
err = readPage((uint16_t *)buf);
if (err)
return 0;
buf += PAGE_SIZE;
pageCount--;
page++;
}
cacheEnd();
if (pageCount) {
puts("ERROR: Partition too small for this image copy\r\n");
return 0;
}
return page;
}
9. 一些nandflash 读写的辅助操作
static void cacheEnd(void)
{
*(nand.addr.pCommand) = 0x3f;
}
static void cacheNext(void)
{
*(nand.addr.pCommand) = 0x31;
}
//确定block地址
static void seekBlock(uint32_t BlockAddress)
{
*(nand.addr.pCommand) = 0x00;
SET_BLOCK_ADDRESSING(nand.addr.pCommonArea, 0, BlockAddress);
*(nand.addr.pCommand) = 0x30;
}
10。 getBlockStatus() --- 获取block的状态,看是不是坏块。
static int getBlockStatus(void)
{
uint32_t Data;
// Position to OOB area
*(nand.addr.pCommand) = 0x05;
SET_BLOCK_OFFSET(nand.addr.pCommonArea, DATA_BYTES_PER_SECTOR);
*(nand.addr.pCommand) = 0xE0;
// Read the first word
Data = (*nand.addr.pBase);
// -----------------------------------------------------------------------------
// Verify if the block is bad (return 1 in this case)
// -----------------------------------------------------------------------------
// The first byte of the first page spare area tells us if a block is bad (0x00)
// -----------------------------------------------------------------------------
return ((0xFF & Data) != 0xFF) ? ERROR_NAND_BAD_BLOCK : 0;
}
11 readPage() --- 读nandflash, 读写都是以page为单位,擦除是以block为单位。
static int readPage(uint16_t *buf)
{
#ifdef CONFIG_ECC
uint32_t data_pos = 0;
uint32_t ecc_pos = PAGE_SIZE + ECC_OOB_START;
int ErrorCounter;
int block, i, t;
for (block = 0; block < ECC_BLOCKS_PER_PAGE; block++, buf += ECC_WORD_LIMIT) {
// Position to read block
*(nand.addr.pCommand) = 0x05;
SET_BLOCK_OFFSET(nand.addr.pCommonArea, data_pos);
*(nand.addr.pCommand) = 0xE0;
data_pos += SIZE_BYTE_SUB_BLOCK;
// reset ECC calculation
nand.regs->FSMC_PCR0 &= ~0x00000040;
nand.regs->FSMC_PCR0 |= 0x00000040;
// ----------------------------------
// Read 512 Bytes of data (128 WORDS)
// ----------------------------------
dma_copy16 (buf, (void *)nand.addr.pBase, ECC_WORD_LIMIT, DMA_CR_DSTI);
// Position to ECC in the OOB area
*(nand.addr.pCommand) = 0x05;
SET_BLOCK_OFFSET(nand.addr.pCommonArea, ecc_pos);
*(nand.addr.pCommand) = 0xE0;
ecc_pos += ECC_BYTES_PER_SUB_BLOCK;
// -------------------------------------------------
// Read 16 Bytes of data (4 WORDS). 14 bytes are ecc
// -------------------------------------------------
for (i = 0; i < ECC_WORD_PER_SUB_BLOCK; i++)
t = *(nand.addr.pBase);
ErrorCounter = correctData((uint8_t *)buf);
// -----------------------------
// 0 or positive means we are OK
// -----------------------------
if (ErrorCounter < 0) {
// ---------------------
// Impossible to correct
// ---------------------
puts("RNP: IMPOSSIBLE TO CORRECT SECTOR SUB_BLOCK\r\n");
return -1;
}
}
#else
// Position to read block
*(nand.addr.pCommand) = 0x05;
SET_BLOCK_OFFSET(nand.addr.pCommonArea, 0);
*(nand.addr.pCommand) = 0xE0;
dma_copy16 (buf, (void *)nand.addr.pBase, ECC_WORD_LIMIT * ECC_BLOCKS_PER_PAGE, DMA_CR_DSTI);
#endif
return 0;
}
12. correctData() --- 这个不知道干啥用的
#ifdef CONFIG_ECC
static int correctData(uint8_t *buf)
{
const uint8_t flip[8] = {3, 2, 1, 0, 7, 6, 5, 4};
const struct {
uint32_t start;
int shift;
} pos13[8] = {
{0, 0}, {1, 5}, {3, 2}, {4, 7},
{6, 4}, {8, 1}, {9, 6}, {11, 3}
};
uint32_t val;
int i;
int error_count;
uint16_t pos;
uint16_t change;
uint16_t invert;
uint8_t ecc_code[14];
// -----------------------------------------------------
// Wait for the ECC to be ready
// -----------------------------------------------------
while (!(nand.regs->FSMC_PISR0 & 0x8000));
val = nand.regs->FSMC_ECCR0;
ecc_code[0] = (val >> 0) & 0xFF;
ecc_code[1] = (val >> 8) & 0xFF;
ecc_code[2] = (val >> 16) & 0xFF;
ecc_code[3] = (val >> 24) & 0xFF;
val = nand.regs->FSMC_ECC2R0;
ecc_code[4] = (val >> 0) & 0xFF;
ecc_code[5] = (val >> 8) & 0xFF;
ecc_code[6] = (val >> 16) & 0xFF;
ecc_code[7] = (val >> 24) & 0xFF;
val = nand.regs->FSMC_ECC3R0;
ecc_code[8] = (val >> 0) & 0xFF;
ecc_code[9] = (val >> 8) & 0xFF;
ecc_code[10] = (val >> 16) & 0xFF;
ecc_code[11] = (val >> 24) & 0xFF;
val = nand.regs->FSMC_PISR0;
if (!(val & 0x4000)) {
ecc_code[12] = (val >> 8) & 0xFF;
ecc_code[13] = (val >> 16) & 0xFF;
} else {
ecc_code[12] = (val >> 16) & 0xFF;
ecc_code[13] = 0xFF;
}
// --------------------------
// Clear CodeReady status bit
// --------------------------
nand.regs->FSMC_PISR0 &= ~0x00008000;
error_count = (ecc_code[3] & ERROR_COUNT_MASK) >> ERROR_COUNT_POS;
/* If there are too many ECC errors, then we can't correct this block */
if (error_count > ERROR_COUNT_MAX)
return -1;
for (i = 0; i < error_count; i++) {
pos = (ecc_code[pos13[i].start] >> pos13[i].shift);
pos |= (ecc_code[pos13[i].start+1] << (8 - pos13[i].shift));
pos |= (ecc_code[pos13[i].start+2] << (16 - pos13[i].shift));
pos &= 0x1fff;
if (pos <= 4095) {
change = pos / 8;
invert = pos % 8;
if (buf[change] & 1<<flip[invert])
/* inversion 1->0 */
buf[change] = (buf[change] & ~(1<<flip[invert]));
else
/* inversion 0->1 */
buf[change] = (buf[change] | 1<<flip[invert]);
}
}
return error_count;
}
#endif