[Linux driver]-----NAND FLASH

1. NAND principle and hardware operation

C: fopen, fread, fwrite
APP: open, read, write "1.txt"
---------------------------------- ----------- File reading and writing
File system: vfat, ext2, ext3, yaffs (convert file reading and writing into sector reading and writing)
----------- -------ll_rw_block-------------- Sector read and write
block device driver
Hardware: hard disk, FLASH

1.1NAND FLASH hardware

Insert image description hereQuestion 1: On the schematic diagram, there are only data lines (LDATA0~7) between NAND FLASH and S3C2440, and no address pins are seen. How to transmit the address (how to tell the address signal to NAND)?
Answer 1: Both data and addresses are transmitted on DATA0~DATA7. Use a signal ALE to distinguish between "address" and "signal". When ALE is high level, the address is transmitted. When ALE is low level, data is transmitted.
Question 2: To operate NAND FLASH, you need to issue a command first. How to incoming commands with only 8 data lines of DATA0~7?
Answer 2: Data, addresses and commands are transmitted on DATA0~DATA7.
When ALE is high level, the address is transmitted,
when CLE is high level, the command is transmitted, and
when both ALE and CLE are low level, data is transmitted.
Question 3: The data line is connected to NAND FLASH, NOR FLASH, SDRAM, DM9000, etc. So how to avoid interference? Answer 3
: These devices must be "selected" before accessing, and the unselected chips will not work. , which is equivalent to not receiving it. To "select" it means that they all have "chip select". Signal
Question 4: Assuming that NAND FLASH is programmed, after sending the command, address and data to it, NAND FLASH will definitely not be able to complete the programming instantly. How to judge when programming is complete?
Answer 4: Judge by the status pin RnB: it is high level to indicate ready, and it is low level to indicate busy.
Question 5.: How to operate NAND FLASH?
Answer 5.: According to the NAND FLASH chip manual, the general process is:
issue a command,
issue an address
, issue data or read data

1.2NAND structure

Insert image description hereThe structure of NAND FLASH is a page-by-page (sector by sector) structure. One page is 2KB. In addition to these 2KB, there is 64B of space. This 64B area is called "OOB" (out of bank). something other than). This OOB area does not participate in "unified addressing", that is to say, if the address of a certain page A is "2-2047", then the address 2048 is not in the OOB area, but on page B (2048-4095).
OOB was introduced because NAND has a shortcoming: bit inversion. For example, when reading a page of data, it is very likely that a certain bit in it has been bit reversed. The original value is 0, but it is read as "1". "Bit reversal" may also occur when writing, so the "ECC" check is introduced
to solve the bit reversal:
when writing:
1. Write one page of data.
2. Use this page of data to generate ECC code (check code).
3. Write ECC into OOB.
When reading:
1. Read the entire page of data.
2. Read the ECC code in OOB. 3. Calculate the check code through the read page of data.
4. Compare the ECC code read from OOB and the ECC code calculated by reading one page of data. If they are the same or different, bit inversion has occurred. The ECC code is specifically set up to know which bit has been inverted.

The ECC check code can be generated by hardware or software.

2. NAND driver writing

2.1init function framework

static int __init s3c_nand_init(void)
{
    
    
    printk("s3c_nand_init NAND Driver, (c) 2020 Simtec Electronics\n");
    /* 1. 分配一个nand_chip结构体 */
    s3c_nand = kzalloc(sizeof(struct nand_chip),GFP_KERNEL);

    /* 2. 设置nand_chip */
    /* 设置nand_chip是给nand_scan函数使用的, 如果不知道怎么设置, 先看nand_scan怎么使用 
     * 它应该提供:选中,发命令,发地址,发数据,读数据,判断状态的功能
     */
    s3c_nand->select_chip = s3c2440_select_chip;
    s3c_nand->cmd_ctrl = s3c2440_nand_cmd_ctrl;
    s3c_nand->IO_ADDR_R   = "NFDATA的虚拟地址";
    s3c_nand->IO_ADDR_W   = "NFDATA的虚拟地址";
    s3c_nand->dev_ready = s3c2440_dev_ready;
    /* 3. 硬件相关的设置 */

    /* 4. 使用: nand_scan */
    s3c_mtd = kzalloc(sizeof(struct mtd_info),GFP_KERNEL);
    mtd->priv = nand_chip;
    mtd->owner = THIS_MODULE;

    nand_scan(s3c_mtd,1);   /* 识别NAND FLASH, 构造mtd_info */
    /* 5. add_mtd_partitions */
    return 0;
}

2.1.1Set the nand_chip structure

Analyze how to use nand_chip by analyzing the use of nand_chip in "nand_scan". The following is the nand_scan function:

nand_scan   // drivers/mtd/nand/nand_base.c,构造mtd_info
nand_scan_ident
  busw = chip->options & NAND_BUSWIDTH_16;  //总线宽度即FLASH为8位还是16位
  nand_set_defaults //成员函数为空时默认函数,nandflash协议层
        if (!chip->select_chip) 
        chip->select_chip = nand_select_chip; // 默认值不适用 
        if (chip->cmdfunc == NULL)
        chip->cmdfunc = nand_command; 
        chip->cmd_ctrl(mtd, command, ctrl); 
        if (!chip->read_byte) 
        chip->read_byte = nand_read_byte; 
        readb(chip->IO_ADDR_R); 
        if (chip->waitfunc == NULL) 
        chip->waitfunc = nand_wait; 
        chip->dev_ready
    nand_get_flash_type //硬件相关层
        chip->select_chip(mtd, 0);
        chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
        *maf_id = chip->read_byte(mtd); //读厂家ID 
         dev_id = chip->read_byte(mtd); //读设备ID 
nand_scan_tail
    //ECC
    mtd->erase = nand_erase;
    mtd->read = nand_read;
    mtd->write = nand_write; 

Chip select chip
chip->select_chip(mtd, 0) The platform default function is as follows and does not perform other operations, so some customization is required to chip select the current chip.

static void nand_select_chip(struct mtd_info *mtd, int chipnr)
{
    
    
    struct nand_chip *chip = mtd->priv;

    switch (chipnr) {
    
    
    case -1:
        chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
        break;
    case 0: //为0时为第一个芯片,里面什么也没做 
        break;

    default:
        BUG();
    }
}

Looking at the 2440 NAND controller, we can see that the chip select is set to 0 in the "Reg_nCE" bit1 field of the "NFCONT" register, as follows

static void s3c2440_select_chip(struct mtd_info *mtd, int chipnr)
{
    
    
    if(chipnr == -1)
    {
    
    
        s3c_nand_regs->nfcont |= (1<<1); 
        /* 取消选中: NFCONT[1]设为1 */
    }else{
    
    
        s3c_nand_regs->nfcont &= ~(1<<1);  
        /* 选中: NFCONT[1]设为0 */
    }
}

Send command/address/data.
First, when NAND FLASH gets the address, first look at which page and then which address in the page.
Default function: chip->cmdfunc = nand_command;

void nand_command(struct mtd_info *mtd, unsigned int command, int column, int page_addr) 
//“column”:页内地址(页内哪一个地址) 
//“page_addr”:页地址
chip->cmd_ctrl(mtd, readcmd, ctrl);//参 2 为命令值或地址值,参 3 控制了是发命令还是发地址。

Check the 2440 NAND controller to implement the 2440 interface

static void s3c2440_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
{
    
    
    if (ctrl & NAND_CLE)
    {
    
    
        /* 发命令: NFCMMD=dat */
        s3c_nand_regs->nfcmd = dat;
    }else{
    
    
        /* 发地址: NFADDR=dat */
        s3c_nand_regs->nfaddr = dat;
    }
}

Read data: Manufacturer ID, device ID
Default function: chip->read_byte = busw ? nand_read_byte16: nand_read_byte
From the schematic, 8-bit nand flash is used, so the following function is used

static uint8_t nand_read_byte(struct mtd_info *mtd)
{
    
    
    struct nand_chip *chip = mtd->priv;
    return readb(chip->IO_ADDR_R);
}

The default function needs to provide: nand_chip->IO_ADDR_R
s3c_nand->IO_ADDR_R = &s3c_nand_regs->nfdata; //The address of the NFDATA register needs to be provided to read and
write data
. The default function: chip->write_buf = busw? nand_write_buf16: nand_write_buf;

static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
    
    
    int i;
    struct nand_chip *chip = mtd->priv;

    for (i = 0; i < len; i++)
        writeb(buf[i], chip->IO_ADDR_W);
}

Determine the status
Default function: chip->waitfunc = nand_wait
uses the 'NFSTAT' register in the 2440 nand controller

static int s3c2440_dev_ready(struct mtd_info *mtd) 
{
    
     
return (s3c_nand_regs->nfstat & (1<<0)); 
} 

2.1.2 Set hardware status

Insert image description hereFrom the 2440 nand controller timing diagram above, we can see that
after sending "CLE/ALE", it will take "TACLS" time to start sending an "nWE" write signal. After the "nWE" write signal becomes high level, "TWRPH1" time will pass before "CLE/ALE" becomes low level.
Let’s look at the timing diagram of the NAND chip:

Insert image description here
Refer to the data sheet to calculate the time difference

#define TACLS 0 //因为TACLS=0 
#define TWRPH0 1 //因为TWRPH0 >= 1 
#define TWRPH1 0 //因为TWRPH1 >= 0 
s3c_nand_regs->nfconf = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4); 

To save power. When the kernel starts, some unused modules will be turned off. To use a certain module, you must enable the CLKCON related bit field and turn on CLKCON

clk = clk_get(NULL, "nand"); 
clk_enable(clk); /* CLKCON'bit[4] 设置为1*/ 

Add a partition
If you just divide NAND into a partition, just use "add_mtd_device (mtd_info structure)". To construct partitions, use "add_mtd_partitions()

/*
参 1,mtd_info 结构体。 
参 2,mtd_partition 结构指针。相当于一个结构数组。最终是数组,组元是结构体。 
参 3,就是参 2 这个 mtd_partition 结构数组的组元有多少项。 
*/
int add_mtd_partitions
(struct mtd_info *master,const struct mtd_partition *parts,int  nbparts)
{
    
    
static struct mtd_partition s3c_nand_parts[] = {
    
    
    [0] = {
    
    
        .name   = "bootloader",
        .size   = 0x00040000,
        .offset = 0,
    },
    [1] = {
    
    
        .name   = "params",
        .offset = MTDPART_OFS_APPEND,
        .size   = 0x00020000,
    },
    [2] = {
    
    
        .name   = "kernel",
        .offset = MTDPART_OFS_APPEND,
        .size   = 0x00200000,
    },
    [3] = {
    
    
        .name   = "root",
        .offset = MTDPART_OFS_APPEND,
        .size   = MTDPART_SIZ_FULL,
    }
};

2.2exit function

static void s3c_nand_exit(void)
{
    
    
    del_mtd_partitions(s3c_mtd);//清除分区结构数组
    kfree(s3c_mtd);
    iounmap(s3c_nand_regs);
    kfree(s3c_nand);
}

Guess you like

Origin blog.csdn.net/weixin_45281868/article/details/127914687