I am reading the code for writing yaffs2 in uboot. I have some questions.
Enter the command, run do_nand, and then run nand_write_opts
Int nand_write_opts (nand_info_t * meminfo, const nand_write_options_t * opts) { .............................. ............................ Memcpy (data_buf, buffer, readlen ); Buffer + = readlen;If (OPTs-> writeoob ){ /* Read OOB data from input memory block, exit * On failure */ Memcpy (oob_buf, buffer, meminfo-> oobsize );
Buffer + = meminfo-> oobsize; /* Write OOB data first, as ECC will be placed * In There */ Result = meminfo-> write_oob (meminfo, Mtdoffset, Meminfo-> oobsize, & Written, (Unsigned char *) & Oob_buf ); ...................... ..................... } Result = meminfo-> write (meminfo, Mtdoffset, Meminfo-> oobblock, & Written, (Unsigned char *) & data_buf ); |
In this Code, OPTs-> writeoob = 1, first executes meminfo-> write_oob, writes the OOB area of flash, and then runs to meminfo-> write, meminfo-> write = nand_write
Static int nand_write (struct mtd_info * MTD, loff_t to, size_t Len, size_t * retlen, const u_char * BUF) { Return (nand_write_ecc (MTD, to, Len, retlen, Buf, null, null )); }Static int nand_write_ecc (struct mtd_info * MTD, loff_t to, size_t Len, Size_t * retlen, const u_char * Buf, u_char * eccbuf, struct nand_oobinfo * oobsel) {.............................. Oobbuf = nand_prepare_oobbuf (MTD, eccbuf, oobsel, autoplace, numpages ); While (written <Len ){ This-> data_poi = (u_char *) & Buf [written]; Ret = nand_write_page (MTD, this, page, & oobbuf [OOB], oobsel, (-- numpages> 0 )); .................. } ...................... } |
In nand_write_page, the OOB area is rewritten again, And oobbuf of the above function is used. However, the pointer returned by nand_prepare_oobbuf is oob_buf In the NAND Chip structure. Therefore, the oob_buf in the Flash OOB area is written to the NAND chip struct. Throughout the process, we did not find the steps to read oob_buf from the OOB area of the file.
[Answer]
After reading the code for a long enough time, I still don't understand the problem.
Finally, I asked my colleagues and understood what was going on.
[Simple explanation]
To answer this question in the simplest language, you can:
When OOB is written for the second time, the first half of oob_buf is 0xff, and the second half is ECC data,
Due to the features of NAND Flash, the original data remains unchanged after 0xff is written,
Therefore, the second half of OOB on NAND Flash is the first time you write it. It must be 0xff. The second write ECC data can also be written.
That is, during the second write, the first half of OOB is 0xff, And the write to NAND has no effect on the original OOB data;
The second half of OOB is ECC data, which can be written normally.
In this way, the data is implicitly written to the NAND Flash as expected.
[Explanation]
The specific explanation is as follows:
Before explaining the following content, let's briefly talk about some assumptions here,
1. Assume that it is a 2 k pagesize NAND Flash, and the corresponding OOB is 64 bytes.
2. The storage location of ECC in OOB. According to nand_oob_64, ECC is placed in 32-63.
3. The yaffs2 data is stored in 2-31 parts, while byte0 and byte1 are used to be compatible with the bad block mark, with 0xff.
In this section, the uboot program to write yaffs2 can implement our desired functions, and finally write the correct value, mainly because of the features of nand flash:
1. before writing data, be sure to erase (to 0xff), that is, the data can only be changed from 1 to 0. Therefore, if you want to write data (not all are 0xff), ensure that before writing, all are 0xff.
2. The data in NAND Flash remains unchanged when data is written into NAND Flash and 0xff is written again.
1. when writing OOB data for the first time, the first half is the data of yaffs2, and the second half is the data of 0xff. After writing, the OOB corresponding to NAND Flash is yaffs2 + 0xff, similar data:
OOB:
FF 00 10 00 00 01 00
00 00 00 00 00 FF
00 00 30 23 84 BF 05 00
00 00 05 00 00 00 FF
FF
FF
FF
FF
In the latter part, you must ensure that the data is 0xff before writing, so that data can be written later when writing ECC data.
2.
The OOB data at the time of the second write, that is, oob_buf, which is a parameter passed in from nand_write_page
The pointer returned in the previous nand_prepare_oobbuf. You can see the code, that is, this-> oob_buf,
This this-> oob_buf, that is, MTD-> priv-> oob_buf, is at the end of nand_scan, and all values are 0xff:
/* Preset the internal OOB buffer */
Memset (this-> oob_buf, 0xff, MTD-> oobsize <(this-> phys_erase_shift-this-> page_shift ));
When the above page data is written, after the ECC data is filled in the corresponding position, it is similar to the following:
OOB:
FF
FF
FF
FF
F0 EC 72 7b 9e 2f 0f 00
07 D1 75 E5 47 72 0f 00
FD 7d 33 5B 1D 2C 0e 00
95 26 41 7C 61 AA 08 00
Writing such data to the OOB location corresponding to NAND Flash is consistent with the above mentioned:
The first half is 0xff. After writing, it does not affect the original data, that is, it does not affect the first half of the OOB written for the first time, that is, the data of yaffs2 and the second half, this is exactly the ECC we want to write. As we have already ensured that it is 0xff, data can be written normally here.
[Summary]
The above implementation is estimated to be so complex and obscure to implement simple things to be compatible with the writing of other different types of data.
For writing yaffs2, a very simple method should actually be, and what I saw earlier seems to be in uboot in 1.1.6, about the code for writing yaffs:
If (OPTs-> writeyaffs) { /* Read page data from input memory buffer */ Memcpy (data_buf, buffer, readlen ); Buffer + = readlen; /* Read OOB data from input memory block, exit * On failure */ Memcpy (oob_buf, buffer, meminfo-> oobsize ); Buffer + = meminfo-> oobsize;Result = meminfo-> write_ecc (meminfo, Mtdoffset, Meminfo-> oobblock, & Written, (Unsigned char *) & data_buf, (Unsigned char *) & oob_buf, Null ); If (result! = 0 ){ Printf ("Writing NAND page at offset 0x % lx failed/N ", Mtdoffset ); Goto restoreoob; } Imglen-= meminfo-> oobsize; Imglen-= readlen; } Else {....} |
The OOB data and page data are directly prepared at one time, and then write_ecc is called,
You can write the number of pages and OOB data at a time. You don't need to use the method above, which is hard to understand...