forked from luck/tmp_suning_uos_patched
mtd: nand: pxa3xx: Add documentation about the controller
Given there's no public specification to this date, and in order to capture some important details and singularities about the controller let's document them once and for good. Cc: linux-doc@vger.kernel.org Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
This commit is contained in:
parent
ad58b2d65f
commit
de484a381c
113
Documentation/mtd/nand/pxa3xx-nand.txt
Normal file
113
Documentation/mtd/nand/pxa3xx-nand.txt
Normal file
|
@ -0,0 +1,113 @@
|
|||
|
||||
About this document
|
||||
===================
|
||||
|
||||
Some notes about Marvell's NAND controller available in PXA and Armada 370/XP
|
||||
SoC (aka NFCv1 and NFCv2), with an emphasis on the latter.
|
||||
|
||||
NFCv2 controller background
|
||||
===========================
|
||||
|
||||
The controller has a 2176 bytes FIFO buffer. Therefore, in order to support
|
||||
larger pages, I/O operations on 4 KiB and 8 KiB pages is done with a set of
|
||||
chunked transfers.
|
||||
|
||||
For instance, if we choose a 2048 data chunk and set "BCH" ECC (see below)
|
||||
we'll have this layout in the pages:
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
| 2048B data | 32B spare | 30B ECC || 2048B data | 32B spare | 30B ECC | ... |
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
The driver reads the data and spare portions independently and builds an internal
|
||||
buffer with this layout (in the 4 KiB page case):
|
||||
|
||||
------------------------------------------
|
||||
| 4096B data | 64B spare |
|
||||
------------------------------------------
|
||||
|
||||
Also, for the READOOB command the driver disables the ECC and reads a 'spare + ECC'
|
||||
OOB, one per chunk read.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
| 4096B data | 32B spare | 30B ECC | 32B spare | 30B ECC |
|
||||
-------------------------------------------------------------------
|
||||
|
||||
So, in order to achieve reading (for instance), we issue several READ0 commands
|
||||
(with some additional controller-specific magic) and read two chunks of 2080B
|
||||
(2048 data + 32 spare) each.
|
||||
The driver accommodates this data to expose the NAND core a contiguous buffer
|
||||
(4096 data + spare) or (4096 + spare + ECC + spare + ECC).
|
||||
|
||||
ECC
|
||||
===
|
||||
|
||||
The controller has built-in hardware ECC capabilities. In addition it is
|
||||
configurable between two modes: 1) Hamming, 2) BCH.
|
||||
|
||||
Note that the actual BCH mode: BCH-4 or BCH-8 will depend on the way
|
||||
the controller is configured to transfer the data.
|
||||
|
||||
In the BCH mode the ECC code will be calculated for each transfered chunk
|
||||
and expected to be located (when reading/programming) right after the spare
|
||||
bytes as the figure above shows.
|
||||
|
||||
So, repeating the above scheme, a 2048B data chunk will be followed by 32B
|
||||
spare, and then the ECC controller will read/write the ECC code (30B in
|
||||
this case):
|
||||
|
||||
------------------------------------
|
||||
| 2048B data | 32B spare | 30B ECC |
|
||||
------------------------------------
|
||||
|
||||
If the ECC mode is 'BCH' then the ECC is *always* 30 bytes long.
|
||||
If the ECC mode is 'Hamming' the ECC is 6 bytes long, for each 512B block.
|
||||
So in Hamming mode, a 2048B page will have a 24B ECC.
|
||||
|
||||
Despite all of the above, the controller requires the driver to only read or
|
||||
write in multiples of 8-bytes, because the data buffer is 64-bits.
|
||||
|
||||
OOB
|
||||
===
|
||||
|
||||
Because of the above scheme, and because the "spare" OOB is really located in
|
||||
the middle of a page, spare OOB cannot be read or write independently of the
|
||||
data area. In other words, in order to read the OOB (aka READOOB), the entire
|
||||
page (aka READ0) has to be read.
|
||||
|
||||
In the same sense, in order to write to the spare OOB the driver has to write
|
||||
an *entire* page.
|
||||
|
||||
Factory bad blocks handling
|
||||
===========================
|
||||
|
||||
Given the ECC BCH requires to layout the device's pages in a split
|
||||
data/OOB/data/OOB way, the controller has a view of the flash page that's
|
||||
different from the specified (aka the manufacturer's) view. In other words,
|
||||
|
||||
Factory view:
|
||||
|
||||
-----------------------------------------------
|
||||
| Data |x OOB |
|
||||
-----------------------------------------------
|
||||
|
||||
Driver's view:
|
||||
|
||||
-----------------------------------------------
|
||||
| Data | OOB | Data x | OOB |
|
||||
-----------------------------------------------
|
||||
|
||||
It can be seen from the above, that the factory bad block marker must be
|
||||
searched within the 'data' region, and not in the usual OOB region.
|
||||
|
||||
In addition, this means under regular usage the driver will write such
|
||||
position (since it belongs to the data region) and every used block is
|
||||
likely to be marked as bad.
|
||||
|
||||
For this reason, marking the block as bad in the OOB is explicitly
|
||||
disabled by using the NAND_BBT_NO_OOB_BBM option in the driver. The rationale
|
||||
for this is that there's no point in marking a block as bad, because good
|
||||
blocks are also 'marked as bad' (in the OOB BBM sense) under normal usage.
|
||||
|
||||
Instead, the driver relies on the bad block table alone, and should only perform
|
||||
the bad block scan on the very first time (when the device hasn't been used).
|
|
@ -7,6 +7,8 @@
|
|||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* See Documentation/mtd/nand/pxa3xx-nand.txt for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
|
Loading…
Reference in New Issue
Block a user