?? onenand.c
字號:
/*======================================================================
Project Name : S3C2443
Copyright 2006 by Samsung Electronics, Inc.
All rights reserved.
Project Description :
This software is only for verifying functions of the S3C2443.
Anybody can use this code without our permission.
File Name : OneNAND.c
Description : S3C2443 OneNAND access module
Author : Junon Jeon
Dept : AP
Created Date : 2006.06.02
Version : 0.0
History
R0.0 (2006.06.02): Junon draft
- This code is derived from S5I3000 OneNAND driver.
=======================================================================*/
#include <stdio.h>
#include <string.h>
#include "2443addr.h"
#include "Option.h"
#include "OneNand.h"
#include "System.h"
#include "Console.h"
#include "PLL.h"
// Setting address of OneNAND device
//****** Setting base address by using CSn ******
#define OND_BANK 0 // 0:nCS0 ~ 5:nCS5
#define __OND_BASEADDR (OND_BANK * 0x08000000)
#define __OND_BootRAM_BASE (__OND_BASEADDR + 0x0)
#define __OND_DataRAM0_BASE (__OND_BASEADDR + 0x0400)
#define __OND_DataRAM1_BASE (__OND_BASEADDR + 0x0c00)
#define __OND_BootRAM_Spare (__OND_BASEADDR + 0x10000)
#define __OND_DataRAM0_Spare (__OND_BASEADDR + 0x10020)
#define __OND_DataRAM1_Spare (__OND_BASEADDR + 0x10060)
// Register address of OneNAND device
#define rOND_MANU (*(volatile U16 *)(__OND_BASEADDR + 0x1e000))
#define rOND_DEV (*(volatile U16 *)(__OND_BASEADDR + 0x1e002))
#define rOND_VER (*(volatile U16 *)(__OND_BASEADDR + 0x1e004))
#define rOND_DBUFSIZE (*(volatile U16 *)(__OND_BASEADDR + 0x1e006))
#define rOND_BBUFSIZE (*(volatile U16 *)(__OND_BASEADDR + 0x1e008))
#define rOND_BUFAMOUNT (*(volatile U16 *)(__OND_BASEADDR + 0x1e00a))
#define rOND_TECH (*(volatile U16 *)(__OND_BASEADDR + 0x1e00c))
#define rOND_START_ADDR1 (*(volatile U16 *)(__OND_BASEADDR + 0x1e200))
#define rOND_START_ADDR2 (*(volatile U16 *)(__OND_BASEADDR + 0x1e202))
#define rOND_START_ADDR3 (*(volatile U16 *)(__OND_BASEADDR + 0x1e204))
#define rOND_START_ADDR4 (*(volatile U16 *)(__OND_BASEADDR + 0x1e206))
#define rOND_START_ADDR5 (*(volatile U16 *)(__OND_BASEADDR + 0x1e208))
#define rOND_START_ADDR6 (*(volatile U16 *)(__OND_BASEADDR + 0x1e20a))
#define rOND_START_ADDR7 (*(volatile U16 *)(__OND_BASEADDR + 0x1e20c))
#define rOND_START_ADDR8 (*(volatile U16 *)(__OND_BASEADDR + 0x1e20e))
#define rOND_START_BUFFER (*(volatile U16 *)(__OND_BASEADDR + 0x1e400))
#define rOND_COMMAND (*(volatile U16 *)(__OND_BASEADDR + 0x1e440))
#define rOND_SYS_CONFIG1 (*(volatile U16 *)(__OND_BASEADDR + 0x1e442))
#define rOND_SYS_CONFIG2 (*(volatile U16 *)(__OND_BASEADDR + 0x1e444))
#define rOND_CON_STATUS (*(volatile U16 *)(__OND_BASEADDR + 0x1e480))
#define rOND_INT_STATUS (*(volatile U16 *)(__OND_BASEADDR + 0x1e482))
#define rOND_START_BADDR (*(volatile U16 *)(__OND_BASEADDR + 0x1e498))
#define rOND_WPROT_STATUS (*(volatile U16 *)(__OND_BASEADDR + 0x1e49c))
#define rOND_ECC_STATUS (*(volatile U16 *)(__OND_BASEADDR + 0x1fe00))
#define rOND_ECC_RES_M0 (*(volatile U16 *)(__OND_BASEADDR + 0x1fe02))
#define rOND_ECC_RES_S0 (*(volatile U16 *)(__OND_BASEADDR + 0x1fe04))
#define rOND_ECC_RES_M1 (*(volatile U16 *)(__OND_BASEADDR + 0x1fe06))
#define rOND_ECC_RES_S1 (*(volatile U16 *)(__OND_BASEADDR + 0x1fe08))
#define rOND_ECC_RES_M2 (*(volatile U16 *)(__OND_BASEADDR + 0x1fe0a))
#define rOND_ECC_RES_S2 (*(volatile U16 *)(__OND_BASEADDR + 0x1fe0c))
#define rOND_ECC_RES_M3 (*(volatile U16 *)(__OND_BASEADDR + 0x1fe0e))
#define rOND_ECC_RES_S3 (*(volatile U16 *)(__OND_BASEADDR + 0x1fe10))
// Values of Command Register - CMD
#define OND_LD_MS_TO_BUF 0x0000
#define OND_LD_SS_TO_BUF 0x0013
#define OND_PG_MS_FR_BUF 0x0080
#define OND_PG_SS_FR_BUF 0x001a
#define OND_CP_BACK_PRG 0x001b
#define OND_UNLOCK 0x0023
#define OND_LOCK 0x002a
#define OND_LOCK_TIGHT 0x002c
#define OND_ERASE_VERIFY 0x0071
#define OND_BLK_ERASE 0x0094
#define OND_MULTY_ERASE 0x0095
#define OND_ERASE_SUS 0x00b0
#define OND_ERASE_RESUME 0x0030
#define OND_RST_CORE 0x00f0
#define OND_RST_OND 0x00f3
#define OND_OTP_ACS 0x0065
#define DBS(b) ((b<<5)&0x8000) // BufferRAM of DDP (Device BufferRAM Select)
#define DFS(b) ((b<<5)&0x8000) // flash core of DDP (Device Flash Core Select)
#define FBA(b) (b&0x03ff) // NAND Flash Block Address
#define FPA(p) ((p<<2)&0xfc) // NAND Flash Page Address
#define FSA(s) (s&0x3) // NAND Flash Sector Address
#define BSA(r) ((r<<8)&0x0f00) // BufferRAM Sector Address
#define BSC(n) (n&0x3) // BufferRAM Sector Count
#define SBA(b) (b&0x03ff) // Start Block Address
// Others
#define DATABUFFERSIZE ((rOND_DBUFSIZE<<1)/(rOND_BUFAMOUNT>>8))
#define USE_DMA 0
// OneNAND interface library
void OND_HotReset( void);
U32 OND_erase_block( U16);
U32 OND_erase_multi_block_verify( U16, U16, U16);
U32 OND_page_program( U16, U16);
U32 OND_page_load( U16, U16);
void OND_lock_block( U16);
void OND_lock_tight_block( U16);
void OND_unlock_block( U16);
void OND_read( U32 *, U32, U16);
void OND_write( U32 *, U32, U16);
void OneNAND_TimingCheck(void);
void OneNAND_Burst_Read(void);
// Temporary library
void set_dma_control(U8 burst, U8 tw);
void dma_memcpy(U32 s_addr, U32 d_addr, U32 N_LLI, U32 trans_size);
void SMC_Config4OneNAND(U32 nBank);
void * function_OND[][2]=
{
(void *)OneNAND_ReadID, "OneNAND Read ID ",
(void *)OneNAND_Program, "OneNAND program ",
(void *)OneNAND_Read_Page, "Read page ",
(void *)OneNAND_Write_Page, "Write page ",
(void *)OneNAND_Erase_All, "Erase all blocks ",
(void *)OneNAND_Erase_Block, "Erase block ",
(void *)OneNAND_Unlock_Block, "Unlock block ",
(void *)OneNAND_Lock_Block, "Lock block ",
(void *)OneNAND_Performance_Test, "Performance Test ",
(void *)OneNAND_TimingCheck, "Timing Check ",
(void *)OneNAND_Burst_Read, "Read burst(page) ",
0,0
};
void Test_OneNAND( void)
{
int i;
OND_HotReset();
SMC_Config4OneNAND(OND_BANK);
while(1)
{
i=0;
while(1)
{
printf("%2d:%s",i,function_OND[i][1]);
i++;
if((int)(function_OND[i][0])==0)
{
printf("\n");
break;
}
if((i%4)==0)
printf("\n");
}
printf("\nPress Enter key to exit : ");
i = GetIntNum();
if( i == (-1) ) break;
if( (i>=0) && (i<sizeof(function_OND)/8-1) )
( (void (*)(void)) (function_OND[i][0]) )();
}
}
//========================= [Drivers] ============================
void OND_HotReset( void)
{
rOND_INT_STATUS = 0x0;
rOND_COMMAND = OND_RST_OND;
while ((rOND_INT_STATUS & 0x8010) != 0x8010);
}
U32 OND_erase_block( U16 block)
{
rOND_START_ADDR1 = DFS(block) | FBA(block);
rOND_INT_STATUS = 0;
rOND_COMMAND = OND_BLK_ERASE;
while (!(rOND_INT_STATUS & (1<<15)));
if (rOND_CON_STATUS & (1<<10)) {
printf("Fail to erase the block %d\n", block);
return 0x3;
}
return 0x0;
}
U32 OND_erase_multi_block_verify( U16 start_block, U16 end_block, U16 do_verify)
{
U16 block;
if (end_block < start_block) return 0x1;
for (block = start_block; block <= end_block; block++)
{
OND_unlock_block( block);
rOND_START_ADDR1 = FBA(block);
rOND_INT_STATUS = 0;
rOND_COMMAND = OND_MULTY_ERASE;
while (!(rOND_INT_STATUS & (1<<15)));
}
rOND_START_ADDR1 = FBA(end_block);
rOND_INT_STATUS = 0;
rOND_COMMAND = OND_BLK_ERASE;
while (!(rOND_INT_STATUS & (1<<15)));
if (do_verify)
{
for (block = start_block; block <= end_block; block++)
{
rOND_START_ADDR1 = FBA(block);
rOND_INT_STATUS = 0;
rOND_COMMAND = OND_ERASE_VERIFY;
while (!(rOND_INT_STATUS & (1<<15)));
if (rOND_CON_STATUS & (1<<10))
printf(" Fail to erase-verify the block %d\n", block);
}
}
return 0x0;
}
U32 OND_page_program( U16 block, U16 page)
{
rOND_START_ADDR2 = DBS(block);
rOND_START_ADDR1 = DFS(block) | FBA(block);
rOND_START_ADDR8 = FPA(page) | FSA(0);
rOND_START_BUFFER = BSA(0x8) | BSC(0);
rOND_INT_STATUS = 0;
rOND_COMMAND = OND_PG_MS_FR_BUF;
while (!(rOND_INT_STATUS & (1<<15)));
if (rOND_CON_STATUS & (1<<10)) {
printf("Fail to program the page (B: %d, P: %d)\n", block, page);
return 0x1;
}
return 0x0;
}
U32 OND_page_load( U16 block, U16 page)
{
rOND_START_ADDR1 = DFS(block) | FBA(block);
rOND_START_ADDR8 = FPA(page) | FSA(0);
rOND_START_BUFFER = BSA(0x8) | BSC(0);
rOND_START_ADDR2 = DBS(block);
rOND_INT_STATUS = 0;
rOND_COMMAND = OND_LD_MS_TO_BUF;
while (!(rOND_INT_STATUS & (1<<15)));
if (rOND_CON_STATUS & (1<<10)) {
printf("Fail to load the page (B: %d, P: %d)\n", block, page);
return 0x1;
}
return 0x0;
}
void OND_write_protection_block( U16 cmd, U16 block)
{
rOND_START_ADDR1 = DFS(block) | FBA(block);
rOND_START_BADDR = SBA(block);
rOND_INT_STATUS = 0;
rOND_COMMAND = cmd;
while (!(rOND_INT_STATUS & (1<<15)));
}
void OND_lock_block( U16 block)
{
OND_write_protection_block( OND_LOCK, block);
}
void OND_lock_tight_block( U16 block)
{
OND_write_protection_block( OND_LOCK_TIGHT, block);
}
void OND_unlock_block( U16 block)
{
OND_write_protection_block( OND_UNLOCK, block);
}
// Read-While-Load Operation
void OND_read( U32 *Address, U32 Size, U16 block)
{
U32 size;
U16 page;
U16 b_temp;
U32 data_load;
U32 data_read;
// U32 st_cnt = 1;
b_temp = 0xffff;
page = 0;
data_load = 0;
data_read = 0;
if (!Size) {
printf("The size is zero!! Retry this operation!! \n");
return;
}
while(Size > (data_read*DATABUFFERSIZE)) {
if (b_temp!=0xffff) { // check int pending
while (!(rOND_INT_STATUS & (1<<15)));
if (rOND_CON_STATUS & (1<<10)) {
printf("ECC Fail.\n");
} else
data_load++;
}
if (Size > (data_load*DATABUFFERSIZE)) { // data load
rOND_START_ADDR1 = DFS(block) | FBA(block);
rOND_START_ADDR8 = FPA(page) | FSA(0);
if (data_load&1)
rOND_START_BUFFER = BSA(0xc) | BSC(0); // DataRAM1
else
rOND_START_BUFFER = BSA(0x8) | BSC(0); // DataRAM0
rOND_START_ADDR2 = DBS(block);
rOND_INT_STATUS = 0;
rOND_COMMAND = OND_LD_MS_TO_BUF;
}
if (data_load > data_read) { // data read. 105 us @50MHz 8,16,cont.-words
rOND_START_ADDR2 = DBS(b_temp);
if ((Size-(data_read*DATABUFFERSIZE)) >= DATABUFFERSIZE) // edit by junon
size = DATABUFFERSIZE;
else
size = Size-(data_read*DATABUFFERSIZE);
// for memory copy time check
//if (data_load == 3)
// StartStopwatch();
// printf("Address = 0x%x\n", (U32)Address);
#if USE_DMA
if (data_read&0x1) // 87 us @50MHz 8,16,cont.-words
dma_memcpy( __OND_DataRAM1_BASE, (U32)Address, 0, size );
else
dma_memcpy( __OND_DataRAM0_BASE, (U32)Address, 0, size );
#else
if (data_read&0x1) // 87 us @50MHz 8,16,cont.-words
memcpy( Address, (U32 *)__OND_DataRAM1_BASE, size );
else
memcpy( Address, (U32 *)__OND_DataRAM0_BASE, size );
#endif
// for memory copy time check
//if (data_load == 3)
//{
// st_cnt = EndStopwatch();
// printf("\n load cycle time : %d us", st_cnt);
//}
Address+=(DATABUFFERSIZE>>2);
data_read++;
}
b_temp = block;
page = (page+1)&0x3f;
if (page==0) block++;
}
}
// Write-While-Program Operation, unit : page
void OND_write( U32 *Address, U32 Size, U16 block)
{
U16 page;
U32 data_program;
U32 data_write;
page = 0;
data_program = 0;
data_write = 0;
if (!Size) {
printf("The size is zero!! Retry this operation!! \n");
return;
}
while( Size >= (data_program*DATABUFFERSIZE)) { // edit by junon
if (data_write > 0) {
if (page==0) {
OND_unlock_block(block);
OND_erase_block(block);
}
rOND_START_ADDR1 = DFS(block) | FBA(block);
rOND_START_ADDR8 = FPA(page) | FSA(0);
if (data_program&1)
rOND_START_BUFFER = BSA(0xc) | BSC(0);
else
rOND_START_BUFFER = BSA(0x8) | BSC(0);
rOND_INT_STATUS = 0;
rOND_COMMAND = OND_PG_MS_FR_BUF;
page = (page+1) & 0x3f;
if (page==0) block++;
}
// write data to DataRAM0 or 1
if (Size >= (data_write*DATABUFFERSIZE)) { // edit by junon
if (data_write <= (data_program+1)) {
rOND_START_ADDR2 = DBS(block);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -