Introduction to MTD/CFI driver under Linux system

  
                  

Some Intel's FLASH chips (such as the StrataFlash series) support multiple partitions, that is, each partition can operate simultaneously. It should be said that this is a good feature, but it will also bring some problems.

Remember that when I ported Linux-2.4.21 and hang the JFFS2 file system, I often reported some errors such as "Magic bitmask not found". I followed up and found that FLASH read out some 0x80 and the like. The data, view the data found that the FLASH has the characteristics of the partition, and the Linux FLASH driver only uses a state variable to indicate the state of the entire FLASH, which will cause the actual state of a certain partition and the system record does not match, resulting in reading FLASH This point is actually not in the read state.

The solution at the time was that, every time you read, regardless of the state of the record, you should enter the read state first, of course, this will bring about a decline in performance. How many clock cycles are lost? .

In the era of Linux-2.6.x (specifically 2.6.13), except Lock/Unlock (Linux does not unlock first when erasing/writing, the solution is to initialize all Unlock first) In addition to the old problem, even the error of multiple partitions did not appear. I was surprised to decide to study the MTD/FLASH driver of Linux.

Before driving, first clear several programming points:

1: Read and write, read and write according to bus width, note that the FLASH chip width is not (for example, back to back).

2: Addressing, the address to be accessed by the program and the value obtained by the FLASH chip address pin are different, for example, 16-bit FLASH chip. For CPU, 0x00 and 0x01 indicate 2 different bytes. But the FLASH pin gets 0, which means that it points to the first WORD of FLASH. It can be considered that the bit0 of the address bus is left floating, or that the conversion bus is considered, and bit1 is actually output on bit0. This explains point 1.

3: The chip manual mentions that the offset is based on WORD, and the bit width of WORD depends on the bit width of the chip, so in the next command, the actual offset = manual offset * buswidth /8 .

4: The length of the variable mentioned in the chip manual (typically CFI information), for example, 2 means that the variable is a 16-bit number, but when reading, you need to read 2 WORDs, then put each WORD The lower 8 bits are combined into one 16-bit number. Reading WORD and patching together is really troublesome, especially when reading large structures, but the cfi_read_pri function of cfi_util.c is simple.

5: Back to back, that is to say, two 16-bit chips are connected to the 32-bit bus. What brings is the problem of addressing. Obviously, first read and write by 32 bits; secondly, the address of the next command, the actual offset = manual offset *interleave*device_type/8, device_type=buswidth/interleave, and buswidth The time is 32 (bus width). In addition, when back to back, the status code of the command and return is "double", for example, two 16-bit back-to-back, the read command is 0x00ff00ff.

If you don't want to write code that is as flexible as Linux (considering various connections/bit width/CFI acquisition information, etc.), then things are much simpler, just consider the point 1 and the size of the erase block. Of course, if it is back-to-back connection, the actual size of the erase block should be multiplied by an interleave.

Entering the Linux code

The relationship between CHIP/MAP/MTD is still confused, so the following is just a brief description of the context and various programming points.

1: Construct the map_info structure, specify the base address/bit width/size and other information as well as the "cfi_probe" limit, then call do_map_probe().

2: do_map_probe() finds the chip driver "cfi_probe.c" according to the name "cfi_probe" and calls cfi_probe() directly.

3: cfi_probe() directly calls mtd_do_chip_probe(), passing in the cfi_probe_chip() function pointer.

4: mtd_do_chip_probe() is divided into 2 steps. First, genprobe_ident_chips() is called to detect the chip information, and then check_cmd_set() is called to acquire and initialize the chip command set (multi-partition initialization is in it).

5: genprobe_ident_chips() function If you do not consider multi-chip concatenation, then just look at the previous genprobe_new_chip() call, after completion cfi.chipshift=cfi.cfiq->DevSize, 2^chipshift =FLASH size.

6:genprobe_new_chip() enumerates various chip bit widths and back-to-back numbers. In combination with the configuration settings, call cfi_probe_chip() in step 3, pay attention to cfi->device_type=bankwidth/nr_chips, bankwidth is Bus width, device_type is the chip width. Here we only need to pay attention to the finite complex situation, the so-called finite complexity refers to the complex connection determined at compile time. Thus, cfi_probe_chip() succeeds only for the first call. If the 32-bit wide FLASH is inserted on the 16-bit bus, the second call is successful.

7:cfi_probe_chip(), due to the reason of step 6, the function returns directly in cfi_chip_setup(), and the following code is not considered.

8: cfi_chip_setup() reads CFI information, you can pay attention to how Linux achieves point 4.

9: Go back to the check_cmd_set() stage of step 4, enter the cfi_cmdset_0001() function, first call read_pri_intelext() to read the extension information of Intel, and then call cfi_intelext_setup() to initialize its structure.

10: read_pri_intelext () function, you can pay attention to how to read the variable length structure, which is the use of "need_more". Here are the meanings of the following variables. For example, for the StrataFlash 128Mb Bottom type of FLASH chip, the block structure is 4*32KB+127*128KB=16MB, a total of 16 partitions, 1MB per partition. Nb_parts=2.

◆Part 1

NumIdentPartitions=1 //There are 1 duplicate partitions

NumBlockTypes=2 //There are 2 different Block types in the sub-area

Type 1

NumIdentBlocks=3 //There are 4 Block(3+1)

BlockSize=0x80 //32KB(0x80*256)

2 type

NumIdentBlocks=6 //There are 7 Block(6+1)

BlockSize=0x200 //128KB(0x200*256)

◆Part 2< Br>

NumIdentPartitions=15//There are 15 duplicate partitions

NumBlockTypes=1 //There is 1 type of Block in the partition

Type 1

NumIdentBlocks =7 //There are 8 Block(7+1)

BlockSize=0x200 //128KB(0x200*256)

11: The cfi_intelext_setup() function first creates the mtd_erase_region_info information according to the CFI, then Call cfi_intelext_partition_fixup() to support partitioning.

12: cfi_intelext_partition_fixup() is used to create a virtual chip. Each partition corresponds to one chip, but it is not completely established according to the CFI extension information. Instead, each partition is assumed to be the same size. Cfi-> chipshift is adjusted to partshift, and each virtual chip->start is adjusted to the base address of each partition. In the future, the entry function cfi_varsize_frob() for accessing FLASH will get chipnum(chipnum=ofs>>cfi->chipshift) according to ofs, which is why the partition is assumed to be consistent.

Copyright © Windows knowledge All Rights Reserved