diff mbox

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

Message ID 1426669491-13878-3-git-send-email-albert.aribaud@3adev.fr
State Superseded
Delegated to: Albert ARIBAUD
Headers show

Commit Message

Albert ARIBAUD (3ADEV) March 18, 2015, 9:04 a.m. UTC
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) <albert.aribaud@3adev.fr>
---

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

Comments

Scott Wood March 19, 2015, 9:39 p.m. UTC | #1
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
Albert ARIBAUD (3ADEV) March 20, 2015, 9:35 a.m. UTC | #2
Hi Scott,

Le Thu, 19 Mar 2015 16:39:42 -0500, Scott Wood
<scottwood@freescale.com> 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
Scott Wood March 20, 2015, 10:41 p.m. UTC | #3
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
> <scottwood@freescale.com> 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, or the sector was actually
>   bad, and the image will run as expected.

...but this seems reasonable as well (it wouldn't work for eLBC/IFC
since they need to support tiny SPLs that can only handle raw images).
If you want to do this, just put a comment in explaining why you're
skipping in that situation.

-Scott
Albert ARIBAUD (3ADEV) March 23, 2015, 8:45 a.m. UTC | #4
Bonjour Scott,

Le Fri, 20 Mar 2015 17:41:11 -0500, Scott Wood
<scottwood@freescale.com> 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
> > <scottwood@freescale.com> 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 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, or the sector was actually
> >   bad, and the image will run as expected.
> 
> ...but this seems reasonable as well (it wouldn't work for eLBC/IFC
> since they need to support tiny SPLs that can only handle raw images).

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
and thus contain code which will never apply to them? Then maybe we
should have /two/ options, one enabling raw images, and one enabling
'non-raw' images (and at least one enabled for any SPL), so that each
SPL could choose what code it wants in. Again, I am not offering to do
that in this patch series.

> 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.

> -Scott

Thanks for the feedback!

Cordialement,
Albert ARIBAUD
3ADEV
Scott Wood March 24, 2015, 1:20 a.m. UTC | #5
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
> <scottwood@freescale.com> 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
Albert ARIBAUD (3ADEV) March 24, 2015, 2:12 p.m. UTC | #6
Hi Scott,

Le Mon, 23 Mar 2015 20:20:50 -0500, Scott Wood
<scottwood@freescale.com> 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
> > <scottwood@freescale.com> 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
diff mbox

Patch

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 0000000..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 <http://3adev.com>
+ * Written by Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * 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 <common.h>
+#include <nand.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <nand.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/sys_proto.h>
+
+/*
+ * 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 0x0000A25E  /* Magic unlock value */
+
+/* ICR defines */
+#define ICR_LARGE_BLOCKS 0x00000004	/* configure for 2KB blocks */
+#define ICR_ADDR4        0x00000002	/* configure for 4-word addrs */
+
+/* CEH defines */
+#define CEH_NORMAL_CE  0x00000001	/* do not force CE ON */
+
+/* ISR register defines */
+#define ISR_NAND_READY        0x00000001
+#define ISR_CONTROLLER_READY  0x00000002
+#define ISR_ECC_READY         0x00000004
+#define ISR_DECODER_ERRORS(s) ((((s) >> 4) & 3)+1)
+#define ISR_DECODER_FAILURE   0x00000040
+#define ISR_DECODER_ERROR     0x00000008
+
+/* time-out for NAND chip / controller loops, in us */
+#define LPC32X_NAND_TIMEOUT 5000
+
+/*
+ * There is a single instance of the NAND MLC controller
+ */
+
+static struct lpc32xx_nand_mlc_registers __iomem *lpc32xx_nand_mlc_registers
+	= (struct lpc32xx_nand_mlc_registers __iomem *)MLC_NAND_BASE;
+
+#define clkdiv(v, w, o) (((1+(clk/v)) & w) << o)
+
+/**
+ * OOB data in each small page are 6 'free' then 10 ECC bytes.
+ * To make things easier, when reading large pages, the four pages'
+ * 'free' OOB bytes are grouped in the first 24 bytes of the OOB buffer,
+ * while the the four ECC bytes are groupe in its last 40 bytes.
+ *
+ * The struct below represents how free vs ecc oob bytes are stored
+ * in the buffer.
+ *
+ * Note: the OOB bytes contain the bad block marker at offsets 0 and 1.
+ */
+
+struct lpc32xx_oob {
+	struct {
+		uint8_t free_oob_bytes[6];
+	} free[4];
+	struct {
+		uint8_t ecc_oob_bytes[10];
+	} ecc[4];
+};
+
+/*
+ * Initialize the controller
+ */
+
+static void lpc32xx_nand_init(void)
+{
+	unsigned int clk;
+
+	/* Configure controller for no software write protection, x8 bus
+	   width, large block device, and 4 address words */
+
+	/* unlock controller registers with magic key */
+	writel(LOCK_PR_UNLOCK_KEY,
+	       &lpc32xx_nand_mlc_registers->lock_pr);
+
+	/* enable large blocks and large NANDs */
+	writel(ICR_LARGE_BLOCKS | ICR_ADDR4,
+	       &lpc32xx_nand_mlc_registers->icr);
+
+	/* Make sure MLC interrupts are disabled */
+	writel(0, &lpc32xx_nand_mlc_registers->irq_mr);
+
+	/* Normal chip enable operation */
+	writel(CEH_NORMAL_CE,
+	       &lpc32xx_nand_mlc_registers->ceh);
+
+	/* Setup NAND timing */
+	clk = get_hclk_clk_rate();
+
+	writel(
+		clkdiv(CONFIG_LPC32XX_NAND_MLC_TCEA_DELAY, 0x03, 24) |
+		clkdiv(CONFIG_LPC32XX_NAND_MLC_BUSY_DELAY, 0x1F, 19) |
+		clkdiv(CONFIG_LPC32XX_NAND_MLC_NAND_TA,    0x07, 16) |
+		clkdiv(CONFIG_LPC32XX_NAND_MLC_RD_HIGH,    0x0F, 12) |
+		clkdiv(CONFIG_LPC32XX_NAND_MLC_RD_LOW,     0x0F, 8) |
+		clkdiv(CONFIG_LPC32XX_NAND_MLC_WR_HIGH,    0x0F, 4) |
+		clkdiv(CONFIG_LPC32XX_NAND_MLC_WR_LOW,     0x0F, 0),
+		&lpc32xx_nand_mlc_registers->time_reg);
+}
+
+#if !defined(CONFIG_SPL_BUILD)
+
+/**
+ * lpc32xx_cmd_ctrl - write command to either cmd or data register
+ */
+
+static void lpc32xx_cmd_ctrl(struct mtd_info *mtd, int cmd,
+				   unsigned int ctrl)
+{
+	if (cmd == NAND_CMD_NONE)
+		return;
+
+	if (ctrl & NAND_CLE)
+		writeb(cmd & 0Xff, &lpc32xx_nand_mlc_registers->cmd);
+	else if (ctrl & NAND_ALE)
+		writeb(cmd & 0Xff, &lpc32xx_nand_mlc_registers->addr);
+}
+
+/**
+ * lpc32xx_read_byte - read a byte from the NAND
+ * @mtd:	MTD device structure
+ */
+
+static uint8_t lpc32xx_read_byte(struct mtd_info *mtd)
+{
+	return readb(&lpc32xx_nand_mlc_registers->data);
+}
+
+/**
+ * lpc32xx_dev_ready - test if NAND device (actually controller) is ready
+ * @mtd:	MTD device structure
+ * @mode:	mode to set the ECC HW to.
+ */
+
+static int lpc32xx_dev_ready(struct mtd_info *mtd)
+{
+	/* means *controller* ready for us */
+	int status = readl(&lpc32xx_nand_mlc_registers->isr);
+	return status & ISR_CONTROLLER_READY;
+}
+
+/**
+ * ECC layout -- this is needed whatever ECC mode we are using.
+ * In a 2KB (4*512B) page, R/S codes occupy 40 (4*10) bytes.
+ * To make U-Boot's life easier, we pack 'useable' OOB at the
+ * front and R/S ECC at the back.
+ */
+
+static struct nand_ecclayout lpc32xx_largepage_ecclayout = {
+	.eccbytes = 40,
+	.eccpos = {24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+		   34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+		   44, 45, 46, 47, 48, 48, 50, 51, 52, 53,
+		   54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+		   },
+	.oobfree = {
+		/* bytes 0 and 1 are used for the bad block marker */
+		{
+			.offset = 2,
+			.length = 22
+		},
+	}
+};
+
+/**
+ * lpc32xx_read_page_hwecc - read in- and out-of-band data with ECC
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
+ *
+ * Use large block Auto Decode Read Mode(1) as described in User Manual
+ * section 8.6.2.1.
+ *
+ * The initial Read Mode and Read Start commands are sent by the caller.
+ *
+ * ECC will be false if out-of-band data has been updated since in-band
+ * data was initially written.
+ */
+
+static int lpc32xx_read_page_hwecc(struct mtd_info *mtd,
+	struct nand_chip *chip, uint8_t *buf, int oob_required,
+	int page)
+{
+	unsigned int i, status, timeout, err, max_bitflips = 0;
+	struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
+
+	/* go through all four small pages */
+	for (i = 0; i < 4; i++) {
+		/* start auto decode (reads 528 NAND bytes) */
+		writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg);
+		/* wait for controller to return to ready state */
+		for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
+			status = readl(&lpc32xx_nand_mlc_registers->isr);
+			if (status & ISR_CONTROLLER_READY)
+				break;
+			udelay(1);
+		}
+		/* if decoder failed, return failure */
+		if (status & ISR_DECODER_FAILURE)
+			return -1;
+		/* keep count of maximum bitflips performed */
+		if (status & ISR_DECODER_ERROR) {
+			err = ISR_DECODER_ERRORS(status);
+			if (err > max_bitflips)
+				max_bitflips = err;
+		}
+		/* copy first 512 bytes into buffer */
+		memcpy(buf+512*i, lpc32xx_nand_mlc_registers->buff, 512);
+		/* copy next 6 bytes at front of OOB buffer */
+		memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6);
+		/* copy last 10 bytes (R/S ECC) at back of OOB buffer */
+		memcpy(&oob->ecc[i], lpc32xx_nand_mlc_registers->buff, 10);
+	}
+	return max_bitflips;
+}
+
+/**
+ * lpc32xx_read_page_raw - read raw (in-band, out-of-band and ECC) data
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
+ *
+ * Read NAND directly; can read pages with invalid ECC.
+ */
+
+static int lpc32xx_read_page_raw(struct mtd_info *mtd,
+	struct nand_chip *chip, uint8_t *buf, int oob_required,
+	int page)
+{
+	unsigned int i, status, timeout;
+	struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
+
+	/* when we get here we've already had the Read Mode(1) */
+
+	/* go through all four small pages */
+	for (i = 0; i < 4; i++) {
+		/* wait for NAND to return to ready state */
+		for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
+			status = readl(&lpc32xx_nand_mlc_registers->isr);
+			if (status & ISR_NAND_READY)
+				break;
+			udelay(1);
+		}
+		/* if NAND stalled, return failure */
+		if (!(status & ISR_NAND_READY))
+			return -1;
+		/* copy first 512 bytes into buffer */
+		memcpy(buf+512*i, lpc32xx_nand_mlc_registers->data, 512);
+		/* copy next 6 bytes at front of OOB buffer */
+		memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->data, 6);
+		/* copy last 10 bytes (R/S ECC) at back of OOB buffer */
+		memcpy(&oob->ecc[i], lpc32xx_nand_mlc_registers->data, 10);
+	}
+	return 0;
+}
+
+/**
+ * lpc32xx_read_oob - read out-of-band data
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to read
+ *
+ * Read out-of-band data. User Manual section 8.6.4 suggests using Read
+ * Mode(3) which the controller will turn into a Read Mode(1) internally
+ * but nand_base.c will turn Mode(3) into Mode(0), so let's use Mode(0)
+ * directly.
+ *
+ * ECC covers in- and out-of-band data and was written when out-of-band
+ * data was blank. Therefore, if the out-of-band being read here is not
+ * blank, then the ECC will be false and the read will return bitflips,
+ * even in case of ECC failure where we will return 5 bitflips. The
+ * caller should be prepared to handle this.
+ */
+
+static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+	int page)
+{
+	unsigned int i, status, timeout, err, max_bitflips = 0;
+	struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
+
+	/* No command was sent before calling read_oob() so send one */
+
+	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+	/* go through all four small pages */
+	for (i = 0; i < 4; i++) {
+		/* start auto decode (reads 528 NAND bytes) */
+		writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg);
+		/* wait for controller to return to ready state */
+		for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
+			status = readl(&lpc32xx_nand_mlc_registers->isr);
+			if (status & ISR_CONTROLLER_READY)
+				break;
+			udelay(1);
+		}
+		/* if decoder failure, count 'one too many' bitflips */
+		if (status & ISR_DECODER_FAILURE)
+			max_bitflips = 5;
+		/* keep count of maximum bitflips performed */
+		if (status & ISR_DECODER_ERROR) {
+			err = ISR_DECODER_ERRORS(status);
+			if (err > max_bitflips)
+				max_bitflips = err;
+		}
+		/* set read pointer to OOB area */
+		writel(0, &lpc32xx_nand_mlc_registers->robp);
+		/* copy next 6 bytes at front of OOB buffer */
+		memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6);
+		/* copy next 10 bytes (R/S ECC) at back of OOB buffer */
+		memcpy(&oob->ecc[i], lpc32xx_nand_mlc_registers->buff, 10);
+	}
+	return max_bitflips;
+}
+
+/**
+ * lpc32xx_write_page_hwecc - write in- and out-of-band data with ECC
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ * @oob_required: must write chip->oob_poi to OOB
+ *
+ * Use large block Auto Encode as per User Manual section 8.6.4.
+ *
+ * The initial Write Serial Input and final Auto Program commands are
+ * sent by the caller.
+ */
+
+static int lpc32xx_write_page_hwecc(struct mtd_info *mtd,
+	struct nand_chip *chip, const uint8_t *buf, int oob_required)
+{
+	unsigned int i, status, timeout;
+	struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
+
+	/* when we get here we've already had the SEQIN */
+	for (i = 0; i < 4; i++) {
+		/* start encode (expects 518 writes to buff) */
+		writel(0, &lpc32xx_nand_mlc_registers->ecc_enc_reg);
+		/* copy first 512 bytes from buffer */
+		memcpy(&lpc32xx_nand_mlc_registers->buff, buf+512*i, 512);
+		/* copy next 6 bytes from OOB buffer -- excluding ECC */
+		memcpy(&lpc32xx_nand_mlc_registers->buff, &oob->free[i], 6);
+		/* wait for ECC to return to ready state */
+		for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
+			status = readl(&lpc32xx_nand_mlc_registers->isr);
+			if (status & ISR_ECC_READY)
+				break;
+			udelay(1);
+		}
+		/* if ECC stalled, return failure */
+		if (!(status & ISR_ECC_READY))
+			return -1;
+		/* Trigger auto encode (writes 528 bytes to NAND) */
+		writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_enc_reg);
+		/* wait for controller to return to ready state */
+		for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
+			status = readl(&lpc32xx_nand_mlc_registers->isr);
+			if (status & ISR_CONTROLLER_READY)
+				break;
+			udelay(1);
+		}
+		/* if controller stalled, return error */
+		if (!(status & ISR_CONTROLLER_READY))
+			return -1;
+	}
+	return 0;
+}
+
+/**
+ * lpc32xx_write_page_raw - write raw (in-band, out-of-band and ECC) data
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @oob_required: caller requires OOB data read to chip->oob_poi
+ * @page: page number to read
+ *
+ * Use large block write but without encode.
+ *
+ * The initial Write Serial Input and final Auto Program commands are
+ * sent by the caller.
+ *
+ * This function will write the full out-of-band data, including the
+ * ECC area. Therefore, it can write pages with valid *or* invalid ECC.
+ */
+
+static int lpc32xx_write_page_raw(struct mtd_info *mtd,
+	struct nand_chip *chip, const uint8_t *buf, int oob_required)
+{
+	unsigned int i;
+	struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
+
+	/* when we get here we've already had the Read Mode(1) */
+	for (i = 0; i < 4; i++) {
+		/* copy first 512 bytes from buffer */
+		memcpy(lpc32xx_nand_mlc_registers->buff, buf+512*i, 512);
+		/* copy next 6 bytes into OOB buffer -- excluding ECC */
+		memcpy(lpc32xx_nand_mlc_registers->buff, &oob->free[i], 6);
+		/* copy next 10 bytes into OOB buffer -- that is 'ECC' */
+		memcpy(lpc32xx_nand_mlc_registers->buff, &oob->ecc[i], 10);
+	}
+	return 0;
+}
+
+/**
+ * lpc32xx_write_oob - write out-of-band data
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to read
+ *
+ * Since ECC covers in- and out-of-band data, writing out-of-band data
+ * with ECC will render the page ECC wrong -- or, if the page was blank,
+ * then it will produce a good ECC but a later in-band data write will
+ * render it wrong.
+ *
+ * Therefore, do not compute or write any ECC, and always return success.
+ *
+ * This implies that we do four writes, since non-ECC out-of-band data
+ * are not contiguous in a large page.
+ */
+
+static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+	int page)
+{
+	/* update oob on all 4 subpages in sequence */
+	unsigned int i, status, timeout;
+	struct lpc32xx_oob *oob = (struct lpc32xx_oob *)chip->oob_poi;
+
+	for (i = 0; i < 4; i++) {
+		/* start data input */
+		chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x200+0x210*i, page);
+		/* copy 6 non-ECC out-of-band bytes directly into NAND */
+		memcpy(lpc32xx_nand_mlc_registers->data, &oob->free[i], 6);
+		/* program page */
+		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+		/* wait for NAND to return to ready state */
+		for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
+			status = readl(&lpc32xx_nand_mlc_registers->isr);
+			if (status & ISR_NAND_READY)
+				break;
+			udelay(1);
+		}
+		/* if NAND stalled, return error */
+		if (!(status & ISR_NAND_READY))
+			return -1;
+	}
+	return 0;
+}
+
+/**
+ * lpc32xx_waitfunc - wait until a command is done
+ * @mtd: MTD device structure
+ * @chip: NAND chip structure
+ *
+ * Wait for controller and FLASH to both be ready.
+ */
+
+static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
+{
+	int status;
+	unsigned int timeout;
+	/* wait until both controller and NAND are ready */
+	for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
+		status = readl(&lpc32xx_nand_mlc_registers->isr);
+		if ((status & (ISR_CONTROLLER_READY || ISR_NAND_READY))
+		    == (ISR_CONTROLLER_READY || ISR_NAND_READY))
+			break;
+		udelay(1);
+	}
+	/* if controller or NAND stalled, return error */
+	if ((status & (ISR_CONTROLLER_READY || ISR_NAND_READY))
+	    != (ISR_CONTROLLER_READY || ISR_NAND_READY))
+		return -1;
+	/* write NAND status command */
+	writel(NAND_CMD_STATUS, &lpc32xx_nand_mlc_registers->cmd);
+	/* read back status and return it */
+	return readb(&lpc32xx_nand_mlc_registers->data);
+}
+
+/*
+ * We are self-initializing, so we need our own chip struct
+ */
+
+static struct nand_chip lpc32xx_chip;
+
+/*
+ * Initialize the controller
+ */
+
+void board_nand_init(void)
+{
+	/* we have only one device anyway */
+	struct mtd_info *mtd = &nand_info[0];
+	/* chip is struct nand_chip, and is now provided by the driver. */
+	mtd->priv = &lpc32xx_chip;
+	/* to store return status in case we need to print it */
+	int ret;
+
+	/* Set all BOARDSPECIFIC (actually core-specific) fields  */
+
+	lpc32xx_chip.IO_ADDR_R = &lpc32xx_nand_mlc_registers->buff;
+	lpc32xx_chip.IO_ADDR_W = &lpc32xx_nand_mlc_registers->buff;
+	lpc32xx_chip.cmd_ctrl = lpc32xx_cmd_ctrl;
+	/* do not set init_size: nand_base.c will read sizes from chip */
+	lpc32xx_chip.dev_ready = lpc32xx_dev_ready;
+	/* do not set setup_read_retry: this is NAND-chip-specific */
+	/* do not set chip_delay: we have dev_ready defined. */
+	lpc32xx_chip.options |= NAND_NO_SUBPAGE_WRITE;
+
+	/* Set needed ECC fields */
+
+	lpc32xx_chip.ecc.mode = NAND_ECC_HW;
+	lpc32xx_chip.ecc.layout = &lpc32xx_largepage_ecclayout;
+	lpc32xx_chip.ecc.size = 512;
+	lpc32xx_chip.ecc.bytes = 10;
+	lpc32xx_chip.ecc.strength = 4;
+	lpc32xx_chip.ecc.read_page = lpc32xx_read_page_hwecc;
+	lpc32xx_chip.ecc.read_page_raw = lpc32xx_read_page_raw;
+	lpc32xx_chip.ecc.write_page = lpc32xx_write_page_hwecc;
+	lpc32xx_chip.ecc.write_page_raw = lpc32xx_write_page_raw;
+	lpc32xx_chip.ecc.read_oob = lpc32xx_read_oob;
+	lpc32xx_chip.ecc.write_oob = lpc32xx_write_oob;
+	lpc32xx_chip.waitfunc = lpc32xx_waitfunc;
+
+	lpc32xx_chip.read_byte = lpc32xx_read_byte; /* FIXME: NEEDED? */
+
+	/* BBT options: read from last two pages */
+	lpc32xx_chip.bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_LASTBLOCK
+		| NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE
+		| NAND_BBT_WRITE;
+
+	/* Initialize NAND interface */
+	lpc32xx_nand_init();
+
+	/* identify chip */
+	ret = nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_CHIPS, NULL);
+	if (ret) {
+		error("nand_scan_ident returned %i", ret);
+		return;
+	}
+
+	/* finish scanning the chip */
+	ret = nand_scan_tail(mtd);
+	if (ret) {
+		error("nand_scan_tail returned %i", ret);
+		return;
+	}
+
+	/* chip is good, register it */
+	ret = nand_register(0);
+	if (ret)
+		error("nand_register returned %i", ret);
+}
+
+#else /* defined(CONFIG_SPL_BUILD) */
+
+void nand_init(void)
+{
+	/* enable NAND controller */
+	lpc32xx_mlc_nand_init();
+	/* initialize NAND controller */
+	lpc32xx_nand_init();
+}
+
+void nand_deselect(void)
+{
+	/* nothing to do, but SPL requires this function */
+}
+
+static int read_single_page(uint8_t *dest, int page,
+	struct lpc32xx_oob *oob)
+{
+	int status, i, timeout, err, max_bitflips = 0;
+
+	/* enter read mode */
+	writel(NAND_CMD_READ0, &lpc32xx_nand_mlc_registers->cmd);
+	/* send column (lsb then MSB) and page (lsb to MSB) */
+	writel(0, &lpc32xx_nand_mlc_registers->addr);
+	writel(0, &lpc32xx_nand_mlc_registers->addr);
+	writel(page & 0xff, &lpc32xx_nand_mlc_registers->addr);
+	writel((page>>8) & 0xff, &lpc32xx_nand_mlc_registers->addr);
+	writel((page>>16) & 0xff, &lpc32xx_nand_mlc_registers->addr);
+	/* start reading */
+	writel(NAND_CMD_READSTART, &lpc32xx_nand_mlc_registers->cmd);
+
+	/* large page auto decode read */
+	for (i = 0; i < 4; i++) {
+		/* start auto decode (reads 528 NAND bytes) */
+		writel(0, &lpc32xx_nand_mlc_registers->ecc_auto_dec_reg);
+		/* wait for controller to return to ready state */
+		for (timeout = LPC32X_NAND_TIMEOUT; timeout; timeout--) {
+			status = readl(&lpc32xx_nand_mlc_registers->isr);
+			if (status & ISR_CONTROLLER_READY)
+				break;
+			udelay(1);
+		}
+		/* if controller stalled, return error */
+		if (!(status & ISR_CONTROLLER_READY))
+			return -1;
+		/* if decoder failure, return error */
+		if (status & ISR_DECODER_FAILURE)
+			return -1;
+		/* keep count of maximum bitflips performed */
+		if (status & ISR_DECODER_ERROR) {
+			err = ISR_DECODER_ERRORS(status);
+			if (err > max_bitflips)
+				max_bitflips = err;
+		}
+		/* copy first 512 bytes into buffer */
+		memcpy(dest+i*512, lpc32xx_nand_mlc_registers->buff, 512);
+		/* copy next 6 bytes bytes into OOB buffer */
+		memcpy(&oob->free[i], lpc32xx_nand_mlc_registers->buff, 6);
+	}
+	return max_bitflips;
+}
+
+#define BYTES_PER_PAGE 2048
+#define PAGES_PER_BLOCK 64
+#define PAGES_PER_CHIP_MAX 524288
+
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
+{
+	int block_good;
+	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;
+		/* if first page in a block, update 'block good' status */
+		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;
+			/* Bad block marker makes block bad */
+			if (block_good) {
+				if (oob.free[0].free_oob_bytes[0] != 0xff)
+					block_good = 0;
+				if (oob.free[0].free_oob_bytes[1] != 0xff)
+					block_good = 0;
+			}
+		}
+		/* if block is good, keep page */
+		if (block_good) {
+			dst += BYTES_PER_PAGE;
+			left--;
+		}
+	}
+
+	/* if we could not read all the data we needed, report failure */
+	if (left > 0)
+		return -1;
+
+	/* report success */
+	return 0;
+}
+
+#endif /* CONFIG_SPL_BUILD */