Friendly mini-2440 embedded Linux applications read and write NAND Flash

Source: Internet
Author: User
Read and Write operations by applications on NAND Flash

Next, continue to analyze the NAND Flash Driver:The function for detecting devices in NAND Flash is s3c24xx_nand_probe..

The s3c24xx_nand_probe function first creates a Data Structure struct mtd_info * MTD representing the original MTD device and initializes it. The source code is as follows:

/* S3c24xx_nand_probe
* Called by device layer when it finds a device matching one our driver can handled. This code checks to see if
* It can allocate all necessary resources then callthe NAND layer to look for devices
*/
Static intS3c24xx_nand_probe(Struct platform_device * pdev)
{
Struct s3c2410_platform_nand * plat = to_nand_plat (pdev );
Enum initi_cpu_type cpu_type;
Struct s3c2410_nand_info * Info;
Struct s3c2410_nand_mtd * nmtd;
Struct s3c2410_nand_set * sets;
Struct resource * res;
Int err = 0;
Int size;
Int nr_sets;
Int setno;

Cpu_type = platform_get_device_id (pdev)-> driver_data; // obtain the device ID

Pr_debug ("s3c2410_nand_probe (% P) \ n", pdev );

Info = kmalloc (sizeof (* info), gfp_kernel); // create a struct s3c2410_nand_info * info struct variable representing the NAND Flash Controller
If (Info = NULL ){
Dev_err (& pdev-> Dev, "no memory for flash info \ n ");
Err =-enomem;
Goto exit_error;
}

Memset (Info, 0, sizeof (* info ));
Platform_set_drvdata (pdev, Info );

Spin_lock_init (& info-> controller. Lock );
// Use the spin lock to initialize the waiting queue
Init_waitqueue_head (& info-> controller. WQ );

/* Get the clock source and enable it */

// Initialize the struct s3c2410_nand_info * info struct variable

Info-> CLK = clk_get (& pdev-> Dev, "NAND ");
If (is_err (Info-> CLK )){
Dev_err (& pdev-> Dev, "failed to get clock \ n ");
Err =-enoent;
Goto exit_error;
}

Clk_enable (Info-> CLK );

/* Allocate and map the resource */

/* Currently we assume we have the one resource */
Res = pdev-> resource;
Size = res-> end-res-> Start + 1;

Info-> area = request_mem_region (res-> Start, size, pdev-> name );

If (Info-> area = NULL ){
Dev_err (& pdev-> Dev, "cannot reserve register region \ n ");
Err =-enoent;
Goto exit_error;
}

Info-> device = & pdev-> dev;
Info-> platform = plat;
Info-> regs = ioremap (res-> Start, size );
Info-> cpu_type = cpu_type;

If (Info-> regs = NULL ){
Dev_err (& pdev-> Dev, "cannot reserve register region \ n ");
Err =-EIO;
Goto exit_error;
}

Dev_dbg (& pdev-> Dev, "mapped registers at % P \ n", info-> regs );

/* Initialise the hardware */

Err = s3c2410_nand_inithw (Info );
If (Err! = 0)
Goto exit_error;

Sets = (plat! = NULL )? Plat-> sets: NULL;
Nr_sets = (plat! = NULL )? Plat-> nr_sets: 1;

Info-> mtd_count = nr_sets;

/* Allocate our information */

Size = nr_sets * sizeof (* Info-> MTDs); // create the MTD struct variable struct s3c2410_nand_mtd * MTDS for the driver layer of the NAND Flash Hardware Device
Info-> MTDS = kmalloc (size, gfp_kernel );
If (Info-> MTDS = NULL ){
Dev_err (& pdev-> Dev, "failed to allocate MTD storage \ n ");
Err =-enomem;
Goto exit_error;
}

Memset (Info-> MTDS, 0, size );

/* Initialise all possible chips */

Nmtd = Info-> MTDS;

For (setno = 0; setno <nr_sets; setno ++, nmtd ++ ){
Pr_debug ("initialising set % d (% P, info % P) \ n", setno, nmtd, Info );

S3c2410_nand_init_chip(Info, nmtd, sets); // initializes the interface operation function of the underlying NAND Chip structure of struct nand_chip.

Nmtd-> scan_res =Nand_scan_ident(& Nmtd-> MTD, // read the NAND flash device ID and compare it with the NAND Flash ID table in the drive
(Sets )? Sets-> nr_chips: 1 );

If (nmtd-> scan_res = 0 ){
S3c2410_nand_update_chip (Info, nmtd );
Nand_scan_tail (& nmtd-> MTD );
S3c2410_nand_add_partition(Info, nmtd, sets );
// Add the created and initialized MTD original device to the MTD original device list
}

If (sets! = NULL)
Sets ++;
}

Err = s3c2410_nand_cpufreq_register (Info );
If (ERR <0 ){
Dev_err (& pdev-> Dev, "failed to init cpufreq support \ n ");
Goto exit_error;
}

If (allow_clk_stop (Info )){
Dev_info (& pdev-> Dev, "clock idle support enabled \ n ");
Clk_disable (Info-> CLK );
}

Pr_debug ("initialised OK \ n ");
Return 0;

Exit_error:
 S3c24xx_nand_remove(Pdev );

If (ERR = 0)
Err =-einval;
Return err;
}

2. Read and Write Applications to NAND Flash Devices

1. s3c2440_nand_hwcontrol FunctionDirectly operate the command registers and address registers of the S3C2440 NAND flash controller.

Static void s3c2440_nand_hwcontrol (struct mtd_info * MTD, int cmd,
Unsigned int CTRL) // cmd indicates the command or address to be written to the NAND Flash Controller.

// CTRL indicates whether to write commands or addresses
{
Struct s3c2410_nand_info * info = s3c2410_nand_mtd_toinfo (MTD );

If (cmd = nand_assist_none)
Return;

If (CTRL & nand_cle)
// Command
Writeb (CMD, info-> regs + s3c2440_nfcmd );
Else
Writeb (CMD, info-> regs + s3c2440_nfaddr );
}

2. The specific commands of the nand_command function should refer to the chip manual, including the operation sequence.

/**
* Nand_command-[Default] send command to NAND Device
* @ MTD: MTD device structure
* @ Command: the command to be sent
* @ Column: the column address for this command,-1 if none
* @ Page_addr: The page address for this command,-1 if none
*
* Send command to NAND device. This function is used for small page
* Devices (256/512 bytes per page)
*/
Static void nand_command (struct mtd_info * MTD, unsigned int command,
Int column, int page_addr)
{
Register struct nand_chip * chip = MTD-> priv;
Int CTRL = nand_ctrl_cle | nand_ctrl_change;

/*
* Write out the command to the device.
*/
If (command = nand_cmd_seqin ){
Int readcmd;

If (column> = MTD-> writesize ){
/* OOB area */
Column-= MTD-> writesize;
Readcmd = nand_cmd_readoob;
} Else if (column <256 ){
/* First 256 bytes --> read0 */
Readcmd = nand_assist_read0;
} Else {
Column-= 256;
Readcmd = nand_assist_read1;
}
Chip-> cmd_ctrl (MTD, readcmd, CTRL );
CTRL & = ~ Nand_ctrl_change;
}
Chip-> cmd_ctrl (MTD, command, CTRL );

/*
* Address cycle, when necessary
*/
CTRL = nand_ctrl_ale | nand_ctrl_change;
/* Serially input address */
If (column! =-1 ){
/* Adjust columns for 16 bit buswidth */
If (chip-> options & nand_buswidth_16)
Column >>> = 1;
Chip-> cmd_ctrl (MTD, column, CTRL );
CTRL & = ~ Nand_ctrl_change;
}
If (page_addr! =-1 ){
Chip-> cmd_ctrl (MTD, page_addr, CTRL );
CTRL & = ~ Nand_ctrl_change;
Chip-> cmd_ctrl (MTD, page_addr> 8, CTRL );
/* One More address cycle for devices> 32mib */
If (chip-> chipsize> (32 <20 ))
Chip-> cmd_ctrl (MTD, page_addr> 16, CTRL );
}
Chip-> 1__ctrl (MTD, nand_1__none, nand_nce | nand_ctrl_change );

/*
* Program and erase have their own busy handlers
* Status and sequential in needs no delay
*/
Switch (command ){

Case nand_cmd_pageprog:
Case nand_assist_erase1:
Case nand_assist_erase2:
Case nand_pai_seqin:
Case nand_assist_status:
Return;

Case nand_assist_reset:
If (chip-> dev_ready)
Break;
Udelay (chip-> chip_delay );
Chip-> cmd_ctrl (MTD, nand_cmd_status,
Nand_ctrl_cle | nand_ctrl_change );
Chip-> cmd_ctrl (MTD,
Nand_assist_none, nand_nce | nand_ctrl_change );
While (! (Chip-> read_byte (MTD) & nand_status_ready ));
Return;

/* This applies to read commands */
Default:
/*
* If we don't have access to the busy pin, we apply the given
* Command Delay
*/
If (! Chip-> dev_ready ){
Udelay (chip-> chip_delay );
Return;
}
}
/* Apply this short delay always to ensure that we do wait twb in
* Any case on any machine .*/
Ndelay (100 );

Nand_wait_ready (MTD );
}

3. nand_command_lp Function

The size of the page is 2 Kbytes,Replace the nand_command function with the nand_command_lp Function.

Static void nand_command_lp (struct mtd_info * MTD, unsigned int command,
Int column, int page_addr)
{
Register struct nand_chip * chip = MTD-> priv;

/* Emulate nand_assist_readoob */
If (command = nand_cmd_readoob ){
Column + = MTD-> writesize;
Command = nand_assist_read0;
}

/* Command latch cycle */
Chip-> cmd_ctrl (MTD, command & 0xff,
Nand_nce | nand_cle | nand_ctrl_change );

If (column! =-1 | page_addr! =-1 ){
Int CTRL = nand_ctrl_change | nand_nce | nand_ale;

/* Serially input address */
If (column! =-1 ){
/* Adjust columns for 16 bit buswidth */
If (chip-> options & nand_buswidth_16)
Column >>> = 1;
Chip-> cmd_ctrl (MTD, column, CTRL );
CTRL & = ~ Nand_ctrl_change;
Chip-> 1__ctrl (MTD, column> 8, CTRL );
}
If (page_addr! =-1 ){
Chip-> cmd_ctrl (MTD, page_addr, CTRL );
Chip-> maid (MTD, page_addr> 8,
Nand_nce | nand_ale );
/* One More address cycle for devices> 128mib */
If (chip-> chipsize> (128 <20 ))
Chip-> cmd_ctrl (MTD, page_addr> 16,
Nand_nce | nand_ale );
}
}
Chip-> 1__ctrl (MTD, nand_1__none, nand_nce | nand_ctrl_change );

/*
* Program and erase have their own busy handlers
* Status, sequential in, and deplete1 need no delay
*/
Switch (command ){

Case nand_cmd_cachedprog:
Case nand_cmd_pageprog:
Case nand_assist_erase1:
Case nand_assist_erase2:
Case nand_pai_seqin:
Case nand_assist_rndin:
Case nand_assist_status:
Case nand_assist_deplete1:
Return;

/*
* Read error status commands require only a short delay
*/
Case nand_assist_status_error:
Case nand_1__status_error0:
Case nand_assist_status_error1:
Case nand_assist_status_error2:
Case nand_assist_status_error3:
Udelay (chip-> chip_delay );
Return;

Case nand_assist_reset:
If (chip-> dev_ready)
Break;
Udelay (chip-> chip_delay );
Chip-> cmd_ctrl (MTD, nand_cmd_status,
Nand_nce | nand_cle | nand_ctrl_change );
Chip-> 1__ctrl (MTD, nand_1__none,
Nand_nce | nand_ctrl_change );
While (! (Chip-> read_byte (MTD) & nand_status_ready ));
Return;

Case nand_assist_rndout:
/* No ready/busy check necessary */
Chip-> cmd_ctrl (MTD, nand_cmd_rndoutstart,
Nand_nce | nand_cle | nand_ctrl_change );
Chip-> 1__ctrl (MTD, nand_1__none,
Nand_nce | nand_ctrl_change );
Return;

Case nand_assist_read0:
Chip-> 1__ctrl (MTD, nand_1__readstart,
Nand_nce | nand_cle | nand_ctrl_change );
Chip-> 1__ctrl (MTD, nand_1__none,
Nand_nce | nand_ctrl_change );

/* This applies to read commands */
Default:
/*
* If we don't have access to the busy pin, we apply the given
* Command Delay
*/
If (! Chip-> dev_ready ){
Udelay (chip-> chip_delay );
Return;
}
}

/* Apply this short delay always to ensure that we do wait twb in
* Any case on any machine .*/
Ndelay (100 );

Nand_wait_ready (MTD );
}

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.