From: Enrico Scholz <enrico.scholz@sigma-chemnitz.de>
Subject: Using nand_chip for hardware NAND controllers (here: PXA3xx DFC)?
Date: Thu, 05 Jul 2007 17:58:32 +0200 [thread overview]
Message-ID: <ly644yg7vb.fsf@ensc-pc.intern.sigma-chemnitz.de> (raw)
[-- Attachment #1: Type: text/plain, Size: 6360 bytes --]
Hello,
while working on a driver for the PXA3xx NAND controller (short:
DFC), I stumbled about some problems. Current state of work is
available at
https://www.cvg.de/people/ensc/pxa3xx_dfc/
but this is not meant for submission (it does not build as pxa3xx
arch is not supported by kernel, and beside the write_oob problem,
parts like pure-IO and perhaps polling (for bootloaders) are not
implemented yet).
Some details about the DFC:
* hardware ECC; read operations correct single bit errors and
report double bit errors.
Due to this, visible OOB area is reduced by 8 (6 ECC + 2 padding
bytes) resp. 24 bytes.
--> in practice, the used ECC algorithm is somehow broken by
resulting into an ECC sum of 0x00 for erased pages. This causes
double-byte errors on reading erased pages :(
I workaround this by comparing read data against 0xff when a
double byte error occurs and ignoring this error then. Not very
efficiently, but it works....
--> I had some problems to find the correct ECC_XXX type.
Finally I decided to use ECC_NONE, ignore the warnings at
bootup and fix some settings between nand_scan_ident() +
_tail().
--> Raw (reading without ECC checks and perhaps the ECC bytes
too) and normal read operations can not be distinguished;
nand_do_read_ops() executes:
| chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
| if (...)
| chip->ecc.read_page_raw(...);
| else
| chip->ecc.read_page(...);
Unfortunately, the bits which decide whether to use raw- or normal
mode (NDCR_ECC_EN) are set already by the cmdfunc(). Hence, I can
not read plain ECC bytes with the current software interface. This
is a minor problem only; for debugging I use a module parameter to
configure ECC mode.
In future, it would be nice when cmdfunc() already knows what
the READ0 is supposed to do (see comments below regarding
verify_buf() too).
--> nand_base.c contains a lot of non-trivial code (all the ECC
functions) which is not used. As pxa3xx is somehow a processor
for embedded platforms, I would like avoid any bloat in the
kernel.
* data operation have to happen page-wise; it is not possible to
read only a single byte or to write only OOB information
--> this is a huge and still unsolved problem. E.g. using the
'flash_erase' and 'nand_write' tools in a way like
| flash_erase /dev/mtd2
| nandwrite -n -o /dev/mtd2 /tmp/page
results into a sequence of:
1. erase page (from 'flash_erase')
2. ioctl(..., MEMWRITEOOB, ...)
3. pwrite(..., data, ...);
On the NAND layer, step 2 (MEMWRITEOOB) will write OOB data and
probably a non-FF ECC which is calculated over:
- the empty data (all 0xFF) and
- the new OOB.
Step 3 (data-write) calculates an ECC over:
- the new data and
- the previously written OOB
Both ECCs probably differ and will cause read errors.
How can I implement write_oob() that it works with current upper
layers (e.g. JFFS2, YAFFS)? Is it always used as 'write-oob();
write-data();'?
--> partial reads are not supported; reading e.g. only 20
bytes will set the pxa internal ringbuffer into a state that
subsequent reads return old data but not the new page.
A non-DMA based read_buf() implementation will have to read
into a temporary buffer and copy the content then. This
makes the implementation ineffienctly.
It would be nice when a finished-with-current-page callback
would be added, that is called after all requested data of a
page have been read. In this callback, the pxa internal buffer
can be flushed.
* data and command operations are DMA capable; multiple pages can
be read/written in a single operation
--> I first tried to implement a zero-copy strategy using
NAND_OWN_BUFFERS option and publishing internal DMA
buffers. This would reduce read_buf() to wait for a
command-done event.
Unfortunately, this did not worked well, because:
1. verify_buf() can not implemented
2. upper layers use own buffers which would nullify the zero-copy
effect
Hence, read_buf() is now a wait-for-done and a memcpy()
operation.
--> multi-page operations are not supported by the current
nand_base driver. Dunno, about the possible performance gain.
* there is support for two 8 bit chips connected in parallel. This
implicates a pagesize of 1024 bytes and bad-block positions of
10 and 11
--> I solved this, by not calling nand_scan() but by executing
nand_scan_ident() and nand_scan_tail() separately and fixing
some values between these calls.
| nand_scan_ident(&mtd);
| dfc_fill_mtd_info();
| nand_scan_tail(&mtd);
Such a double-buswidth setup can/should be solved in nand_base.
* the internal boot ROM expects a certain format for the relocation
information of bad blocks (e.g. last 28 pages of the first block
contain [bad-block, new-block] pairs by reserving the last 127
blocks for relocation)
--> I had no time yet to implement this. Does there exist
already a relocation scheme which works similarly?
* erase & program can execute a READSTATUS command automatically
and report the result through some status register
--> nand_base executes this command explicitly; removing these
calls might improve performance.
* only READ0, PROGRAM, ERASE, RESET, STATUS and READ_ID operations
are supported, but not READ1 or READOOB or the advanced stuff
like copy-back.
--> Some ops (READOOB) are emulated, others (READ1) are assumed
never to be called. Can become a maintenance problem but is not
important atm.
* Multi-command operations are handled by the controller (it
knows when to sent CMD1, addresses, data and CMD2).
--> Implementation of the cmdfunc looks a little bit hacky. Some
commands are executed immediately (READ*), others are delayed
(SEQIN) and others are noops (ERASE2).
This is the main reason why I am in doubt that nand_base is
the right choice for hardware NAND controllers. My current
driver is somehow a NAND emulator which makes some effort to
downgrade the existing high-level functionality into this of a
bit-banging interface.
Unfortunately, higher MTD layers require features like
non-aligned/non-padded access and shuffling of OOB data.
Because this is solved in nand_base, I made my driver based
upon 'nand_chip'.
Enrico
[-- Attachment #2: Type: application/pgp-signature, Size: 480 bytes --]
reply other threads:[~2007-07-05 17:35 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ly644yg7vb.fsf@ensc-pc.intern.sigma-chemnitz.de \
--to=enrico.scholz@sigma-chemnitz.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox