Re: [U-Boot] [PATCH v6 2/8] lpc32xx: mtd: nand: add MLC NAND controller

2015-03-24 Thread Albert ARIBAUD
Hi Scott,

Le Mon, 23 Mar 2015 20:20:50 -0500, Scott Wood
 a écrit :

> On Mon, 2015-03-23 at 09:45 +0100, Albert ARIBAUD wrote:
> > Bonjour Scott,
> > 
> > Le Fri, 20 Mar 2015 17:41:11 -0500, Scott Wood
> >  a écrit :
> > 
> > > On Fri, 2015-03-20 at 10:35 +0100, Albert ARIBAUD wrote:
> > > > BTW, is there a standard way to ask a NAND chip which page(s) in a bad
> > > > block should be checked?
> > > 
> > > Yes and no:
> > > http://lists.infradead.org/pipermail/linux-mtd/2011-November/038419.html
> > 
> > ... right.
> > 
> > How about this: the driver expects a driver-specific configuration
> > option which tells it which page(s) in a block, and which byte in a
> > page's OOB area, should be scanned for bad block markers, and "my"
> > board provides a value for said option.
> 
> It looks like the common NAND code will set
> NAND_BBT_SCANLASTPAGE/NAND_BBT_SCAN2NDPAGE automatically if it sees
> certain manufacturer IDs, so I don't think drivers should be setting
> them at all (and currently, none do).

Ok.

> That still leaves the question of what to do in SPL.  For simplicity you
> could check every page as you do the normal read.

Ok. Patch series v7 to follow... as soon as I have completed it.

> > This leads me to a half-OT question: so those SPL, while too tiny to
> > handle non-raw images, still do include the whole common/spl/spl.c
> 
> No, there's no room for that.

Ok.

> > > If you want to do this, just put a comment in explaining why you're
> > > skipping in that situation.
> > 
> > Ok -- I will go with the 'option' method then, and add a (lengthy, I'm
> > afraid) comment in common/spl/spl.c explaining that skipping the raw
> > image handling is required when chainloading from NAND and the NAND
> > driver considers totally unreadable sectors bad, in order not to
> > confuse a missing image header with a raw image.
> 
> Skipping raw wouldn't be needed for all NAND drivers, only those that
> aren't guaranteed to halt on a legitimate unrecoverable ECC error.

Understood.

> -Scott

Cordialement,
Albert ARIBAUD
3ADEV
___
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot


Re: [U-Boot] [PATCH v6 2/8] lpc32xx: mtd: nand: add MLC NAND controller

2015-03-23 Thread Scott Wood
On Mon, 2015-03-23 at 09:45 +0100, Albert ARIBAUD wrote:
> Bonjour Scott,
> 
> Le Fri, 20 Mar 2015 17:41:11 -0500, Scott Wood
>  a écrit :
> 
> > On Fri, 2015-03-20 at 10:35 +0100, Albert ARIBAUD wrote:
> > > BTW, is there a standard way to ask a NAND chip which page(s) in a bad
> > > block should be checked?
> > 
> > Yes and no:
> > http://lists.infradead.org/pipermail/linux-mtd/2011-November/038419.html
> 
> ... right.
> 
> How about this: the driver expects a driver-specific configuration
> option which tells it which page(s) in a block, and which byte in a
> page's OOB area, should be scanned for bad block markers, and "my"
> board provides a value for said option.

It looks like the common NAND code will set
NAND_BBT_SCANLASTPAGE/NAND_BBT_SCAN2NDPAGE automatically if it sees
certain manufacturer IDs, so I don't think drivers should be setting
them at all (and currently, none do).

That still leaves the question of what to do in SPL.  For simplicity you
could check every page as you do the normal read.

> This leads me to a half-OT question: so those SPL, while too tiny to
> handle non-raw images, still do include the whole common/spl/spl.c

No, there's no room for that.

> > If you want to do this, just put a comment in explaining why you're
> > skipping in that situation.
> 
> Ok -- I will go with the 'option' method then, and add a (lengthy, I'm
> afraid) comment in common/spl/spl.c explaining that skipping the raw
> image handling is required when chainloading from NAND and the NAND
> driver considers totally unreadable sectors bad, in order not to
> confuse a missing image header with a raw image.

Skipping raw wouldn't be needed for all NAND drivers, only those that
aren't guaranteed to halt on a legitimate unrecoverable ECC error.

-Scott


___
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot


Re: [U-Boot] [PATCH v6 2/8] lpc32xx: mtd: nand: add MLC NAND controller

2015-03-23 Thread Albert ARIBAUD
Bonjour Scott,

Le Fri, 20 Mar 2015 17:41:11 -0500, Scott Wood
 a écrit :

> On Fri, 2015-03-20 at 10:35 +0100, Albert ARIBAUD wrote:
> > Hi Scott,
> > 
> > Le Thu, 19 Mar 2015 16:39:42 -0500, Scott Wood
> >  a écrit :
> > 
> > > On Wed, 2015-03-18 at 10:04 +0100, Albert ARIBAUD (3ADEV) wrote:
> > > > +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
> > > > +{
> > > > +   int block_good;
> > > 
> > > bool?
> > > 
> > > > +   struct lpc32xx_oob oob;
> > > > +   unsigned int page, left;
> > > > +
> > > > +   /* if starting mid-block consider block good */
> > > > +   block_good = 1;
> > > > +
> > > > +   for (page = offs / BYTES_PER_PAGE,
> > > > +left = DIV_ROUND_UP(size, BYTES_PER_PAGE);
> > > > +left && (page < PAGES_PER_CHIP_MAX); page++) {
> > > > +   /* read inband and oob page data anyway */
> > > > +   int res = read_single_page(dst, page, &oob);
> > > > +   /* return error if a good block's page was not readable 
> > > > */
> > > > +   if ((res < 0) && block_good)
> > > > +   return -1;
> > > 
> > > Why even try to read it if it's been marked bad?
> > 
> > Actually, at this point, we may not know yet if the block is good or
> > bad, since we might be reading a page of it for the first time. Will
> > fix, see below.
> > 
> > > > +   /* if first page in a block, update 'block good' status 
> > > > */
> > > 
> > > The non-SPL driver appears to be checking the last two pages in the
> > > block, not the first page.
> > 
> > Thanks for pointing out this discrepancy.
> > 
> > I took the first page option here after checking the NAND's datasheet,
> > which says that for factory bad block marking at least, while all pages
> > in a bad block /should/ bear the bad block marker, only the first one is
> > /guaranteed/ to have it. The driver might have inherited the 'last page'
> > option from the previous NAND chip used, or from a mistake of my own.
> 
> Are there any plans for this controller to be used with different chips?

Not that I know; but in the same vein, the current LPC32XX maintainer
did not consider there were any plans for a few devices in it, and then
came my patch series :) so I cannot rule out that someday a new LPC32XX
board pops up in U-Boot with another NAND device.

> > BTW, is there a standard way to ask a NAND chip which page(s) in a bad
> > block should be checked?
> 
> Yes and no:
> http://lists.infradead.org/pipermail/linux-mtd/2011-November/038419.html

... right.

How about this: the driver expects a driver-specific configuration
option which tells it which page(s) in a block, and which byte in a
page's OOB area, should be scanned for bad block markers, and "my"
board provides a value for said option.

This way, when the driver is used with a new NAND chip in another
board, it can be configured for this board's specific case.  

> > > > +   if ((page % PAGES_PER_BLOCK) == 0) {
> > > > +   /* assume block is good */
> > > > +   block_good = 1;
> > > > +   /* if page could not be read, assume block is 
> > > > bad */
> > > > +   if (res < 0)
> > > > +   block_good = 0;
> > > 
> > > No.  A block is to be skipped if and only if it has a bad block marker.
> > > ECC errors should not be silently ignored just because they happen on
> > > the first page of a block.  If the writer of this data didn't skip the
> > > block, then skipping it when reading will result in unusable data
> > > regardless of the underlying ECC problem.
> > 
> > You're correct of course.
> > 
> > However, I do want the SPL chainloading to be as resilient as
> > possible, and we have established that it will have to read some part
> > of a bad block -- possibly resulting in a read failure -- before
> > knowing that the block is bad, which means it may have to finally
> > ignore the read failure.
> 
> FWIW, the eLBC/IFC SPL functions have the same problem regarding halting
> on an ECC error before checking the bad block status.  Instead it should
> return an error code, and let the caller halt after it's sure it's not
> marked bad.

Maybe we could generalize an SPL chainloading common/spl/spl.c routine
and have boards /SoCs only provide the hardware-specific page/OOB read
function(s) ? Honestly, that would be way beyond my scope for this
patch series.
 
> > I guess I could wait to declare the block good or bad until I could
> > read at least one if its pages (actually, one of its pages' OOB data)
> > properly, only bail out if the OOB says the block is supposed to be
> > good.
> >
> > Now, if none of the block's pages could be read, this still prevents us
> > from knowing whether these read failures are catastrophic.
> >
> > If the block was actually bad and skipped, then the resulting image
> > might be intact, will pass the checksum test, and will run; if 

Re: [U-Boot] [PATCH v6 2/8] lpc32xx: mtd: nand: add MLC NAND controller

2015-03-20 Thread Scott Wood
On Fri, 2015-03-20 at 10:35 +0100, Albert ARIBAUD wrote:
> Hi Scott,
> 
> Le Thu, 19 Mar 2015 16:39:42 -0500, Scott Wood
>  a écrit :
> 
> > On Wed, 2015-03-18 at 10:04 +0100, Albert ARIBAUD (3ADEV) wrote:
> > > +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
> > > +{
> > > + int block_good;
> > 
> > bool?
> > 
> > > + struct lpc32xx_oob oob;
> > > + unsigned int page, left;
> > > +
> > > + /* if starting mid-block consider block good */
> > > + block_good = 1;
> > > +
> > > + for (page = offs / BYTES_PER_PAGE,
> > > +  left = DIV_ROUND_UP(size, BYTES_PER_PAGE);
> > > +  left && (page < PAGES_PER_CHIP_MAX); page++) {
> > > + /* read inband and oob page data anyway */
> > > + int res = read_single_page(dst, page, &oob);
> > > + /* return error if a good block's page was not readable */
> > > + if ((res < 0) && block_good)
> > > + return -1;
> > 
> > Why even try to read it if it's been marked bad?
> 
> Actually, at this point, we may not know yet if the block is good or
> bad, since we might be reading a page of it for the first time. Will
> fix, see below.
> 
> > > + /* if first page in a block, update 'block good' status */
> > 
> > The non-SPL driver appears to be checking the last two pages in the
> > block, not the first page.
> 
> Thanks for pointing out this discrepancy.
> 
> I took the first page option here after checking the NAND's datasheet,
> which says that for factory bad block marking at least, while all pages
> in a bad block /should/ bear the bad block marker, only the first one is
> /guaranteed/ to have it. The driver might have inherited the 'last page'
> option from the previous NAND chip used, or from a mistake of my own.

Are there any plans for this controller to be used with different chips?

> BTW, is there a standard way to ask a NAND chip which page(s) in a bad
> block should be checked?

Yes and no:
http://lists.infradead.org/pipermail/linux-mtd/2011-November/038419.html

> > > + if ((page % PAGES_PER_BLOCK) == 0) {
> > > + /* assume block is good */
> > > + block_good = 1;
> > > + /* if page could not be read, assume block is bad */
> > > + if (res < 0)
> > > + block_good = 0;
> > 
> > No.  A block is to be skipped if and only if it has a bad block marker.
> > ECC errors should not be silently ignored just because they happen on
> > the first page of a block.  If the writer of this data didn't skip the
> > block, then skipping it when reading will result in unusable data
> > regardless of the underlying ECC problem.
> 
> You're correct of course.
> 
> However, I do want the SPL chainloading to be as resilient as
> possible, and we have established that it will have to read some part
> of a bad block -- possibly resulting in a read failure -- before
> knowing that the block is bad, which means it may have to finally
> ignore the read failure.

FWIW, the eLBC/IFC SPL functions have the same problem regarding halting
on an ECC error before checking the bad block status.  Instead it should
return an error code, and let the caller halt after it's sure it's not
marked bad.

> I guess I could wait to declare the block good or bad until I could
> read at least one if its pages (actually, one of its pages' OOB data)
> properly, only bail out if the OOB says the block is supposed to be
> good.
>
> Now, if none of the block's pages could be read, this still prevents us
> from knowing whether these read failures are catastrophic.
>
> If the block was actually bad and skipped, then the resulting image
> might be intact, will pass the checksum test, and will run; if the
> block was actually good, SPL will detect it and not boot the corrupt
> image -- except if the completely unreadable good block was the first
> one, which holds the signature and checksum, in which case SPL will
> fall back to considering a raw, unsigned, unverifiable image, and will
> jump into corrupt code.
> 
> This may happen; but I think the probability of having a completely
> unreadable sector is very low, and the probability of this sector being
> the first one of the image is very low too [1].
> 
> Which leads me to two possible courses of action:
> 
> - consider the risk even though the probabilities are very low, thus
>   consider any totally unreadable sector as good, and bail out in this
>   case, or

I was thinking instead to distinguish between a hard failure where you
got no data from the NAND (e.g. a timeout), versus an ECC failure.  In
the later case you can still look in the OOB for a bad block marker.

> - add an option to SPL that prevents common/spl/spl.c from falling back
>   to running the image as raw if no signature is found, and consider
>   any totally unreadable sector as bad and therefore ignore the read
>   errors. Either the sector was actually good, and SPL will catch the
>   image as corrupt or missing a signature

Re: [U-Boot] [PATCH v6 2/8] lpc32xx: mtd: nand: add MLC NAND controller

2015-03-20 Thread Albert ARIBAUD
Hi Scott,

Le Thu, 19 Mar 2015 16:39:42 -0500, Scott Wood
 a écrit :

> On Wed, 2015-03-18 at 10:04 +0100, Albert ARIBAUD (3ADEV) wrote:
> > +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
> > +{
> > +   int block_good;
> 
> bool?
> 
> > +   struct lpc32xx_oob oob;
> > +   unsigned int page, left;
> > +
> > +   /* if starting mid-block consider block good */
> > +   block_good = 1;
> > +
> > +   for (page = offs / BYTES_PER_PAGE,
> > +left = DIV_ROUND_UP(size, BYTES_PER_PAGE);
> > +left && (page < PAGES_PER_CHIP_MAX); page++) {
> > +   /* read inband and oob page data anyway */
> > +   int res = read_single_page(dst, page, &oob);
> > +   /* return error if a good block's page was not readable */
> > +   if ((res < 0) && block_good)
> > +   return -1;
> 
> Why even try to read it if it's been marked bad?

Actually, at this point, we may not know yet if the block is good or
bad, since we might be reading a page of it for the first time. Will
fix, see below.

> > +   /* if first page in a block, update 'block good' status */
> 
> The non-SPL driver appears to be checking the last two pages in the
> block, not the first page.

Thanks for pointing out this discrepancy.

I took the first page option here after checking the NAND's datasheet,
which says that for factory bad block marking at least, while all pages
in a bad block /should/ bear the bad block marker, only the first one is
/guaranteed/ to have it. The driver might have inherited the 'last page'
option from the previous NAND chip used, or from a mistake of my own.

BTW, is there a standard way to ask a NAND chip which page(s) in a bad
block should be checked?

> > +   if ((page % PAGES_PER_BLOCK) == 0) {
> > +   /* assume block is good */
> > +   block_good = 1;
> > +   /* if page could not be read, assume block is bad */
> > +   if (res < 0)
> > +   block_good = 0;
> 
> No.  A block is to be skipped if and only if it has a bad block marker.
> ECC errors should not be silently ignored just because they happen on
> the first page of a block.  If the writer of this data didn't skip the
> block, then skipping it when reading will result in unusable data
> regardless of the underlying ECC problem.

You're correct of course.

However, I do want the SPL chainloading to be as resilient as
possible, and we have established that it will have to read some part
of a bad block -- possibly resulting in a read failure -- before
knowing that the block is bad, which means it may have to finally
ignore the read failure.

I guess I could wait to declare the block good or bad until I could
read at least one if its pages (actually, one of its pages' OOB data)
properly, only bail out if the OOB says the block is supposed to be
good.

Now, if none of the block's pages could be read, this still prevents us
from knowing whether these read failures are catastrophic. If the block
was actually bad and skipped, then the resulting image might be intact,
will pass the checksum test, and will run; if the block was actually
good, SPL will detect it and not boot the corrupt image -- except if
the completely unreadable good block was the first one, which holds the
signature and checksum, in which case SPL will fall back to considering
a raw, unsigned, unverifiable image, and will jump into corrupt code.

This may happen; but I think the probability of having a completely
unreadable sector is very low, and the probability of this sector being
the first one of the image is very low too [1].

Which leads me to two possible courses of action:

- consider the risk even though the probabilities are very low, thus
  consider any totally unreadable sector as good, and bail out in this
  case, or

- add an option to SPL that prevents common/spl/spl.c from falling back
  to running the image as raw if no signature is found, and consider
  any totally unreadable sector as bad and therefore ignore the read
  errors. Either the sector was actually good, and SPL will catch the
  image as corrupt or missing a signature, or the sector was actually
  bad, and the image will run as expected.

I personally prefer the second one, as it bring a valuable (I think)
feature to U-Boot, for any board on which one wants to prevent an
unverifiable image from running.

> -Scott

Cordialement,
Albert ARIBAUD
3ADEV
-- 
[1] Both together would require Douglas Adam's infinite improbability
generator while probably attracting its arch-nemesis, Murphy's Law.
I wouldn't like to be trapped between the two. :)
___
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot


Re: [U-Boot] [PATCH v6 2/8] lpc32xx: mtd: nand: add MLC NAND controller

2015-03-19 Thread Scott Wood
On Wed, 2015-03-18 at 10:04 +0100, Albert ARIBAUD (3ADEV) wrote:
> +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
> +{
> + int block_good;

bool?

> + struct lpc32xx_oob oob;
> + unsigned int page, left;
> +
> + /* if starting mid-block consider block good */
> + block_good = 1;
> +
> + for (page = offs / BYTES_PER_PAGE,
> +  left = DIV_ROUND_UP(size, BYTES_PER_PAGE);
> +  left && (page < PAGES_PER_CHIP_MAX); page++) {
> + /* read inband and oob page data anyway */
> + int res = read_single_page(dst, page, &oob);
> + /* return error if a good block's page was not readable */
> + if ((res < 0) && block_good)
> + return -1;

Why even try to read it if it's been marked bad?

> + /* if first page in a block, update 'block good' status */

The non-SPL driver appears to be checking the last two pages in the
block, not the first page.

> + if ((page % PAGES_PER_BLOCK) == 0) {
> + /* assume block is good */
> + block_good = 1;
> + /* if page could not be read, assume block is bad */
> + if (res < 0)
> + block_good = 0;

No.  A block is to be skipped if and only if it has a bad block marker.
ECC errors should not be silently ignored just because they happen on
the first page of a block.  If the writer of this data didn't skip the
block, then skipping it when reading will result in unusable data
regardless of the underlying ECC problem.

-Scott


___
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot


[U-Boot] [PATCH v6 2/8] lpc32xx: mtd: nand: add MLC NAND controller

2015-03-18 Thread Albert ARIBAUD (3ADEV)
The controller's Reed-Solomon ECC hardware is
used except of course for raw reads and writes.
It covers in- and out-of-band data together.

The SPL framework is supported.

Signed-off-by: Albert ARIBAUD (3ADEV) 
---

Changes in v6:
- rewrite timeout loops
- fix bad block skipping in SPL chainload loop

Changes in v5:
- switch to CONFIG_SYS_NAND_SELF_INIT

Changes in v4:
- remove two debugging statements
- add __iomem to regs struct
- remove useless 'else return;'
- take BB marker out of free OOB area
- replace magic numbers in OOB reads/writes
- add timeouts in NAND loops
- use DIV_ROUND_UP where applicable
- fix erroneous comment
- skip bad blocks in SPL chainload loop

Changes in v3: None
Changes in v2: None

 arch/arm/cpu/arm926ejs/lpc32xx/devices.c  |   6 +
 arch/arm/include/asm/arch-lpc32xx/clk.h   |   4 +
 arch/arm/include/asm/arch-lpc32xx/sys_proto.h |   1 +
 drivers/mtd/nand/Makefile |   1 +
 drivers/mtd/nand/lpc32xx_nand_mlc.c   | 718 ++
 5 files changed, 730 insertions(+)
 create mode 100644 drivers/mtd/nand/lpc32xx_nand_mlc.c

diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c 
b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
index 062db8d..be4c93d 100644
--- a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
@@ -44,3 +44,9 @@ void lpc32xx_mac_init(void)
writel(CLK_MAC_REG | CLK_MAC_SLAVE | CLK_MAC_MASTER
| CLK_MAC_MII, &clk->macclk_ctrl);
 }
+
+void lpc32xx_mlc_nand_init(void)
+{
+   /* Enable NAND interface */
+   writel(CLK_NAND_MLC | CLK_NAND_MLC_INT, &clk->flashclk_ctrl);
+}
diff --git a/arch/arm/include/asm/arch-lpc32xx/clk.h 
b/arch/arm/include/asm/arch-lpc32xx/clk.h
index 92f6c15..bc7d33d 100644
--- a/arch/arm/include/asm/arch-lpc32xx/clk.h
+++ b/arch/arm/include/asm/arch-lpc32xx/clk.h
@@ -147,6 +147,10 @@ struct clk_pm_regs {
 /* DMA Clock Control Register bits */
 #define CLK_DMA_ENABLE (1 << 0)
 
+/* NAND Clock Control Register bits */
+#define CLK_NAND_MLC   (1 << 1)
+#define CLK_NAND_MLC_INT   (1 << 5)
+
 unsigned int get_sys_clk_rate(void);
 unsigned int get_hclk_pll_rate(void);
 unsigned int get_hclk_clk_div(void);
diff --git a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h 
b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
index a6b8826..0c4e712 100644
--- a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
+++ b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
@@ -9,5 +9,6 @@
 
 void lpc32xx_uart_init(unsigned int uart_id);
 void lpc32xx_mac_init(void);
+void lpc32xx_mlc_nand_init(void);
 
 #endif /* _LPC32XX_SYS_PROTO_H */
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 1f02bfc..347ea62 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_NAND_JZ4740) += jz4740_nand.o
 obj-$(CONFIG_NAND_KB9202) += kb9202_nand.o
 obj-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
 obj-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o
+obj-$(CONFIG_NAND_LPC32XX_MLC) += lpc32xx_nand_mlc.o
 obj-$(CONFIG_NAND_MPC5121_NFC) += mpc5121_nfc.o
 obj-$(CONFIG_NAND_VF610_NFC) += vf610_nfc.o
 obj-$(CONFIG_NAND_MXC) += mxc_nand.o
diff --git a/drivers/mtd/nand/lpc32xx_nand_mlc.c 
b/drivers/mtd/nand/lpc32xx_nand_mlc.c
new file mode 100644
index 000..67dd67b
--- /dev/null
+++ b/drivers/mtd/nand/lpc32xx_nand_mlc.c
@@ -0,0 +1,718 @@
+/*
+ * LPC32xx MLC NAND flash controller driver
+ *
+ * (C) Copyright 2014 3ADEV 
+ * Written by Albert ARIBAUD 
+ *
+ * SPDX-License-Identifier:GPL-2.0+
+ *
+ * NOTE:
+ *
+ * The MLC NAND flash controller provides hardware Reed-Solomon ECC
+ * covering in- and out-of-band data together. Therefore, in- and out-
+ * of-band data must be written together in order to have a valid ECC.
+ *
+ * Consequently, pages with meaningful in-band data are written with
+ * blank (all-ones) out-of-band data and a valid ECC, and any later
+ * out-of-band data write will void the ECC.
+ *
+ * Therefore, code which reads such late-written out-of-band data
+ * should not rely on the ECC validity.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/*
+ * MLC NAND controller registers.
+ */
+struct lpc32xx_nand_mlc_registers {
+   u8 buff[32768]; /* controller's serial data buffer */
+   u8 data[32768]; /* NAND's raw data buffer */
+   u32 cmd;
+   u32 addr;
+   u32 ecc_enc_reg;
+   u32 ecc_dec_reg;
+   u32 ecc_auto_enc_reg;
+   u32 ecc_auto_dec_reg;
+   u32 rpr;
+   u32 wpr;
+   u32 rubp;
+   u32 robp;
+   u32 sw_wp_add_low;
+   u32 sw_wp_add_hig;
+   u32 icr;
+   u32 time_reg;
+   u32 irq_mr;
+   u32 irq_sr;
+   u32 lock_pr;
+   u32 isr;
+   u32 ceh;
+};
+
+/* LOCK_PR register defines */
+#define LOCK_PR_UNLOCK_KEY 0xA25E  /* Magic unlock value */
+
+/* ICR defines */
+#define ICR_LARGE_BLOCKS 0x0004/* configure for 2KB blocks */