Index: u-boot-1.3.2/board/freescale/mpc8313erdb/Makefile
===================================================================
--- u-boot-1.3.2.orig/board/freescale/mpc8313erdb/Makefile	2008-11-24 16:39:09.000000000 +0100
+++ u-boot-1.3.2/board/freescale/mpc8313erdb/Makefile	2008-11-24 16:39:15.000000000 +0100
@@ -25,7 +25,7 @@
 
 LIB	= $(obj)lib$(BOARD).a
 
-COBJS	:= $(BOARD).o sdram.o
+COBJS	:= $(BOARD).o sdram.o nand.o
 
 SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
 OBJS	:= $(addprefix $(obj),$(COBJS))
Index: u-boot-1.3.2/board/freescale/mpc8313erdb/nand.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ u-boot-1.3.2/board/freescale/mpc8313erdb/nand.c	2008-11-24 16:39:15.000000000 +0100
@@ -0,0 +1,868 @@
+/*
+ * Copyright (C) Freescale Semiconductor, Inc. 2006. 
+ * 
+ * Initialized by Nick.Spence@freescale.com
+ *                Wilson.Lo@freescale.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_CMD_NAND)
+#if defined(CFG_NAND_LEGACY)
+ #error "U-Boot legacy NAND commands not supported."
+#else
+
+#include <malloc.h>
+#include <asm/errno.h>
+#include <nand.h>
+
+#undef CFG_FCM_DEBUG
+#define CFG_FCM_DEBUG_LVL 1
+#ifdef CFG_FCM_DEBUG
+#define FCM_DEBUG(n, args...)				\
+	do {						\
+		if (n <= (CFG_FCM_DEBUG_LVL + 0))	\
+			printf(args);			\
+	} while(0)
+#else /* CONFIG_FCM_DEBUG */
+#define FCM_DEBUG(n, args...) do { } while(0)
+#endif
+
+#define MIN(x, y)		((x < y) ? x : y)
+
+#define ERR_BYTE 0xFF	/* Value returned for read bytes when read failed */
+
+#define FCM_TIMEOUT_USECS 100000 /* Maximum number of uSecs to wait for FCM */
+
+/* Private structure holding NAND Flash device specific information */
+struct fcm_nand {
+	int		bank;       /* Chip select bank number             */
+	unsigned int	base;       /* Chip select base address            */
+	int		pgs;        /* NAND page size                      */
+	int		oobbuf;     /* Pointer to OOB block                */
+	unsigned int	page;       /* Last page written to / read from    */
+	unsigned int	fmr;        /* FCM Flash Mode Register value       */
+	unsigned int	mdr;        /* UPM/FCM Data Register value         */
+	unsigned int	use_mdr;    /* Non zero if the MDR is to be set    */
+	u_char	       *addr;       /* Address of assigned FCM buffer      */
+	unsigned int	read_bytes; /* Number of bytes read during command */
+	unsigned int	index;      /* Pointer to next byte to 'read'      */
+	unsigned int	req_bytes;  /* Number of bytes read if command ok  */
+	unsigned int	req_index;  /* New read index if command ok        */
+	unsigned int	status;     /* status read from LTESR after last op*/
+};
+
+
+/* These map to the positions used by the FCM hardware ECC generator */
+
+/* Small Page FLASH with FMR[ECCM] = 0 */
+static struct nand_oobinfo fcm_oob_sp_eccm0 = { /* TODO */
+	.useecc = MTD_NANDECC_AUTOPL_USR, /* MTD_NANDECC_PLACEONLY, */
+	.eccbytes = 3,
+	.eccpos = {6, 7, 8},
+	.oobfree = { {0, 5}, {9, 7} }
+};
+
+/* Small Page FLASH with FMR[ECCM] = 1 */
+static struct nand_oobinfo fcm_oob_sp_eccm1 = { /* TODO */
+	.useecc = MTD_NANDECC_AUTOPL_USR, /* MTD_NANDECC_PLACEONLY, */
+	.eccbytes = 3,
+	.eccpos = {8, 9, 10},
+	.oobfree = { {0, 5}, {6, 2}, {11, 5} }
+};
+
+/* Large Page FLASH with FMR[ECCM] = 0 */
+static struct nand_oobinfo fcm_oob_lp_eccm0 = {
+	.useecc = MTD_NANDECC_AUTOPL_USR, /* MTD_NANDECC_PLACEONLY, */
+	.eccbytes = 12,
+	.eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56},
+	.oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} }
+};
+
+/* Large Page FLASH with FMR[ECCM] = 1 */
+static struct nand_oobinfo fcm_oob_lp_eccm1 = {
+	.useecc = MTD_NANDECC_AUTOPL_USR, /* MTD_NANDECC_PLACEONLY, */
+	.eccbytes = 12,
+	.eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58},
+	.oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} }
+};
+
+/*
+ * execute FCM command and wait for it to complete
+ */
+static int fcm_run_command(struct mtd_info *mtd)
+{
+	volatile immap_t *im = (immap_t *) CFG_IMMR;
+	volatile lbus83xx_t *lbc= &im->lbus;
+	register struct nand_chip *this = mtd->priv;
+	struct fcm_nand *fcm = this->priv;
+	long long end_tick;
+
+	/* Setup the FMR[OP] to execute without write protection */
+	lbc->fmr = fcm->fmr | 3;
+	if (fcm->use_mdr)
+		lbc->mdr = fcm->mdr;
+
+	FCM_DEBUG(5,"fcm_run_command: fmr= %08X fir= %08X fcr= %08X\n",
+		lbc->fmr, lbc->fir, lbc->fcr);
+	FCM_DEBUG(5,"fcm_run_command: fbar=%08X fpar=%08X fbcr=%08X bank=%d\n",
+		lbc->fbar, lbc->fpar, lbc->fbcr, fcm->bank);
+
+	/* clear event registers */
+	lbc->lteatr = 0;
+	lbc->ltesr |= (LTESR_FCT | LTESR_PAR | LTESR_CC);
+
+	/* execute special operation */
+	lbc->lsor = fcm->bank;
+
+	/* wait for FCM complete flag or timeout */
+	fcm->status = 0;
+	end_tick = usec2ticks(FCM_TIMEOUT_USECS) + get_ticks();
+
+	while (end_tick > get_ticks()) {
+		if (lbc->ltesr & LTESR_CC) {
+			fcm->status = lbc->ltesr &
+					(LTESR_FCT | LTESR_PAR | LTESR_CC);
+			break;
+		}
+	}
+
+	/* store mdr value in case it was needed */
+	if (fcm->use_mdr)
+		fcm->mdr = lbc->mdr;
+
+	fcm->use_mdr = 0;
+
+	FCM_DEBUG(5,"fcm_run_command: stat=%08X mdr= %08X fmr= %08X\n",
+		fcm->status, fcm->mdr, lbc->fmr);
+
+	/* if the operation completed ok then set the read buffer pointers */
+	if (fcm->status == LTESR_CC) {
+		fcm->read_bytes = fcm->req_bytes;
+		fcm->index      = fcm->req_index;
+		return 0;
+	}
+
+	return -1;
+}
+
+/*
+ * Set up the FCM hardware block and page address fields, and the fcm
+ * structure addr field to point to the correct FCM buffer in memory
+ */
+static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
+{
+	volatile immap_t *im = (immap_t *) CFG_IMMR;
+	volatile lbus83xx_t *lbc= &im->lbus;
+	register struct nand_chip *this = mtd->priv;
+	struct fcm_nand *fcm = this->priv;
+	int buf_num;
+
+	fcm->page = page_addr;
+
+	lbc->fbar = page_addr >> (this->phys_erase_shift - this->page_shift);
+	if (fcm->pgs) {
+		lbc->fpar = ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) |
+			    ( oob ? FPAR_LP_MS : 0) |
+			      column;
+		buf_num = (page_addr & 1) << 2;
+	} else {
+		lbc->fpar = ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) |
+			    ( oob ? FPAR_SP_MS : 0) |
+			      column;
+		buf_num = page_addr & 7;
+	}
+	fcm->addr = (unsigned char*)(fcm->base + (buf_num * 1024));
+
+	/* for OOB data point to the second half of the buffer */
+	if (oob) {
+		fcm->addr += (fcm->pgs ? 2048 : 512);
+	}
+}
+
+/* not required for FCM */
+static void fcm_hwcontrol(struct mtd_info *mtdinfo, int cmd)
+{
+	return;
+}
+
+
+/*
+ * FCM does not support 16 bit data busses
+ */
+static u16 fcm_read_word(struct mtd_info *mtd)
+{
+	printf("fcm_read_word: UNIMPLEMENTED.\n");
+	return 0;
+}
+static void fcm_write_word(struct mtd_info *mtd, u16 word)
+{
+	printf("fcm_write_word: UNIMPLEMENTED.\n");
+}
+
+/*
+ * Write buf to the FCM Controller Data Buffer
+ */
+static void fcm_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	register struct nand_chip *this = mtd->priv;
+	struct fcm_nand *fcm = this->priv;
+
+	FCM_DEBUG(3,"fcm_write_buf: writing %d bytes starting with 0x%x"
+		    " at %d.\n", len, *((unsigned long*) buf), fcm->index);
+
+	/* If armed catch the address of the OOB buffer so that it can be */
+	/* updated with the real signature after the program comletes */
+	if (!fcm->oobbuf)
+		fcm->oobbuf = (int) buf;
+
+	/* copy the data into the FCM hardware buffer and update the index */
+	memcpy(&(fcm->addr[fcm->index]), buf, len);
+	fcm->index += len;
+	return;
+}
+
+
+/*
+ * FCM does not support individual writes. Instead these are either commands
+ * or data being written, both of which are handled through the cmdfunc
+ * handler.
+ */
+static void fcm_write_byte(struct mtd_info *mtd, u_char byte)
+{
+	printf("fcm_write_byte: UNIMPLEMENTED.\n");
+}
+
+/*
+ * read a byte from either the FCM hardware buffer if it has any data left
+ * otherwise issue a command to read a single byte.
+ */
+static u_char fcm_read_byte(struct mtd_info *mtd)
+{
+	volatile immap_t *im = (immap_t *) CFG_IMMR;
+	volatile lbus83xx_t *lbc= &im->lbus;
+	register struct nand_chip *this = mtd->priv;
+	struct fcm_nand *fcm = this->priv;
+	unsigned char byte;
+
+	/* If there are still bytes in the FCM then use the next byte */
+	if(fcm->index < fcm->read_bytes) {
+		byte = fcm->addr[(fcm->index)++];
+		FCM_DEBUG(4,"fcm_read_byte: byte %u (%02X): %d of %d.\n",
+			  byte, byte, fcm->index-1, fcm->read_bytes);
+	} else {
+		/* otherwise issue a command to read 1 byte */
+		lbc->fir = (FIR_OP_RSW << FIR_OP0_SHIFT);
+		fcm->use_mdr = 1;
+		fcm->read_bytes = 0;
+		fcm->index = 0;
+		fcm->req_bytes = 0;
+		fcm->req_index = 0;
+		byte = fcm_run_command(mtd) ? ERR_BYTE : fcm->mdr & 0xff;
+		FCM_DEBUG(4,"fcm_read_byte: byte %u (%02X) from bus.\n",
+			  byte, byte);
+	}
+
+	return byte;
+}
+
+
+/*
+ * Read from the FCM Controller Data Buffer
+ */
+static void fcm_read_buf(struct mtd_info *mtd, u_char* buf, int len)
+{
+	volatile immap_t *im = (immap_t *) CFG_IMMR;
+	volatile lbus83xx_t *lbc= &im->lbus;
+	register struct nand_chip *this = mtd->priv;
+	struct fcm_nand *fcm = this->priv;
+	int i;
+	int rest;
+
+	FCM_DEBUG(3,"fcm_read_buf: reading %d bytes.\n", len);
+
+	/* If last read failed then return error bytes */
+	if (fcm->status != LTESR_CC) {
+		/* just keep copying bytes so that the oob works */
+		memcpy(buf, &(fcm->addr[(fcm->index)]), len);
+		fcm->index += len;
+	}
+	else
+	{
+		/* see how much is still in the FCM buffer */
+		i = min(len, (fcm->read_bytes - fcm->index));
+		rest = i - len;
+		len = i;
+
+		memcpy(buf, &(fcm->addr[(fcm->index)]), len);
+		fcm->index += len;
+
+		/* If more data is needed then issue another block read */
+		if (rest) {
+			FCM_DEBUG(3,"fcm_read_buf: getting %d more bytes.\n",
+				    rest);
+			buf += len;
+			lbc->fir = (FIR_OP_RBW << FIR_OP0_SHIFT);
+			set_addr(mtd, 0, 0, 0);
+			lbc->fbcr = rest;
+			fcm->req_bytes = lbc->fbcr;
+			fcm->req_index = 0;
+			fcm->use_mdr = 0;
+			if (!fcm_run_command(mtd))
+				fcm_read_buf(mtd, buf, rest);
+			else
+				memcpy(buf, fcm->addr, rest);
+		}
+	}
+	return;
+}
+
+
+/*
+ * Verify buffer against the FCM Controller Data Buffer
+ */
+static int fcm_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	volatile immap_t *im = (immap_t *) CFG_IMMR;
+	volatile lbus83xx_t *lbc= &im->lbus;
+	register struct nand_chip *this = mtd->priv;
+	struct fcm_nand *fcm = this->priv;
+	int i;
+	int rest;
+
+	FCM_DEBUG(3,"fcm_verify_buf: checking %d bytes starting with 0x%02x.\n",
+		len, *((unsigned long*) buf));
+	/* If last read failed then return error bytes */
+	if (fcm->status != LTESR_CC) {
+		return EFAULT;
+	}
+
+	/* see how much is still in the FCM buffer */
+	i = min(len, (fcm->read_bytes - fcm->index));
+	rest = i - len;
+	len = i;
+
+	if (memcmp(buf,	&(fcm->addr[(fcm->index)]), len)) {
+		return EFAULT;
+	}
+
+	fcm->index += len;
+	if (rest) {
+		FCM_DEBUG(3,"fcm_verify_buf: getting %d more bytes.\n", rest);
+		buf += len;
+		lbc->fir = (FIR_OP_RBW << FIR_OP0_SHIFT);
+		set_addr(mtd, 0, 0, 0);
+		lbc->fbcr = rest;
+		fcm->req_bytes = lbc->fbcr;
+		fcm->req_index = 0;
+		fcm->use_mdr = 0;
+		if (fcm_run_command(mtd))
+			return EFAULT;
+		return fcm_verify_buf(mtd, buf, rest);
+
+	}
+	return 0;
+}
+
+/* this function is called after Program and Erase Operations to
+ * check for success or failure */
+static int fcm_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
+{
+	volatile immap_t *im = (immap_t *) CFG_IMMR;
+	volatile lbus83xx_t *lbc= &im->lbus;
+	struct fcm_nand *fcm = this->priv;
+
+	if (fcm->status != LTESR_CC) {
+		return(0x1); /* Status Read error */
+	}
+
+	/* Use READ_STATUS command, but wait for the device to be ready */
+	fcm->use_mdr = 0;
+	fcm->req_index = 0;
+	fcm->read_bytes = 0;
+	fcm->index = 0;
+	fcm->oobbuf = -1;
+	lbc->fir = (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+		   (FIR_OP_RBW << FIR_OP1_SHIFT);
+	lbc->fcr = (NAND_CMD_STATUS << FCR_CMD0_SHIFT);
+	set_addr(mtd, 0, 0, 0);
+	lbc->fbcr = 1;
+	fcm->req_bytes = lbc->fbcr;
+	fcm_run_command(mtd);
+	if (fcm->status != LTESR_CC) {
+		return(0x1); /* Status Read error */
+	}
+	return this->read_byte(mtd);
+}
+
+
+/* cmdfunc send commands to the FCM */
+static void fcm_cmdfunc(struct mtd_info *mtd, unsigned command,
+			int column, int page_addr)
+{
+	volatile immap_t *im = (immap_t *) CFG_IMMR;
+	volatile lbus83xx_t *lbc= &im->lbus;
+	register struct nand_chip *this = mtd->priv;
+	struct fcm_nand *fcm = this->priv;
+
+	fcm->use_mdr = 0;
+	fcm->req_index = 0;
+
+	/* clear the read buffer */
+	fcm->read_bytes = 0;
+	if (command != NAND_CMD_PAGEPROG) {
+		fcm->index = 0;
+		fcm->oobbuf = -1;
+	}
+
+	switch (command) {
+	/* READ0 and READ1 read the entire buffer to use hardware ECC */
+	case NAND_CMD_READ1:
+		FCM_DEBUG(2,"fcm_cmdfunc: NAND_CMD_READ1, page_addr:"
+			    " 0x%x, column: 0x%x.\n", page_addr, column);
+		fcm->req_index = column + 256;
+		goto read0;
+	case NAND_CMD_READ0:
+		FCM_DEBUG(2,"fcm_cmdfunc: NAND_CMD_READ0, page_addr:"
+			    " 0x%x, column: 0x%x.\n", page_addr, column);
+		fcm->req_index = column;
+read0:
+		if (fcm->pgs) {
+			lbc->fir = (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+				   (FIR_OP_CA  << FIR_OP1_SHIFT) |
+				   (FIR_OP_PA  << FIR_OP2_SHIFT) |
+				   (FIR_OP_CW1 << FIR_OP3_SHIFT) |
+				   (FIR_OP_RBW << FIR_OP4_SHIFT);
+		} else {
+			lbc->fir = (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+				   (FIR_OP_CA  << FIR_OP1_SHIFT) |
+				   (FIR_OP_PA  << FIR_OP2_SHIFT) |
+				   (FIR_OP_RBW << FIR_OP3_SHIFT);
+		}
+		lbc->fcr = (NAND_CMD_READ0     << FCR_CMD0_SHIFT) |
+			   (NAND_CMD_READSTART << FCR_CMD1_SHIFT);
+		lbc->fbcr = 0; /* read entire page to enable ECC */
+		set_addr(mtd, 0, page_addr, 0);
+		fcm->req_bytes = mtd->oobblock + mtd->oobsize;
+		goto write_cmd2;
+	/* READOOB read only the OOB becasue no ECC is performed */
+	case NAND_CMD_READOOB:
+		FCM_DEBUG(2,"fcm_cmdfunc: NAND_CMD_READOOB, page_addr:"
+			    " 0x%x, column: 0x%x.\n", page_addr, column);
+		if (fcm->pgs) {
+			lbc->fir = (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+				   (FIR_OP_CA  << FIR_OP1_SHIFT) |
+				   (FIR_OP_PA  << FIR_OP2_SHIFT) |
+				   (FIR_OP_CW1 << FIR_OP3_SHIFT) |
+				   (FIR_OP_RBW << FIR_OP4_SHIFT);
+			lbc->fcr = (NAND_CMD_READ0     << FCR_CMD0_SHIFT) |
+				   (NAND_CMD_READSTART << FCR_CMD1_SHIFT);
+		} else {
+			lbc->fir = (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+				   (FIR_OP_CA  << FIR_OP1_SHIFT) |
+				   (FIR_OP_PA  << FIR_OP2_SHIFT) |
+				   (FIR_OP_RBW << FIR_OP3_SHIFT);
+			lbc->fcr = (NAND_CMD_READOOB << FCR_CMD0_SHIFT);
+		}
+		lbc->fbcr = mtd->oobsize - column;
+		set_addr(mtd, column, page_addr, 1);
+		goto write_cmd1;
+	/* READID must read all 5 possible bytes while CEB is active */
+	case NAND_CMD_READID:
+		FCM_DEBUG(2,"fcm_cmdfunc: NAND_CMD_READID.\n");
+		lbc->fir = (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+			   (FIR_OP_UA  << FIR_OP1_SHIFT) |
+			   (FIR_OP_RBW << FIR_OP2_SHIFT);
+		lbc->fcr = (NAND_CMD_READID << FCR_CMD0_SHIFT);
+		lbc->fbcr = 5; /* 5 bytes for manuf, device and exts */
+		fcm->use_mdr = 1;
+		fcm->mdr = 0;
+		goto write_cmd0;
+	/* ERASE1 stores the block and page address */
+	case NAND_CMD_ERASE1:
+		FCM_DEBUG(2,"fcm_cmdfunc: NAND_CMD_ERASE1, page_addr:"
+			    " 0x%x.\n", page_addr);
+		set_addr(mtd, 0, page_addr, 0);
+		goto end;
+	/* ERASE2 uses the block and page address from ERASE1 */
+	case NAND_CMD_ERASE2:
+		FCM_DEBUG(2,"fcm_cmdfunc: NAND_CMD_ERASE2.\n");
+		lbc->fir = (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+			   (FIR_OP_PA  << FIR_OP1_SHIFT) |
+			   (FIR_OP_CM1 << FIR_OP2_SHIFT);
+		lbc->fcr = (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) |
+			   (NAND_CMD_ERASE2 << FCR_CMD1_SHIFT);
+		lbc->fbcr = 0;
+		goto write_cmd1;
+	/* SEQIN sets up the addr buffer and all registers except the length */
+	case NAND_CMD_SEQIN:
+		FCM_DEBUG(2,"fcm_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, page_addr:"
+			    " 0x%x, column: 0x%x.\n", page_addr, column);
+		if (column == 0) {
+			lbc->fbcr = 0; /* write entire page to enable ECC */
+		} else {
+			lbc->fbcr = 1; /* mark as partial page so no HW ECC */
+		}
+		if (fcm->pgs) {
+			/* always use READ0 for large page devices */
+			lbc->fir = (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+				   (FIR_OP_CA  << FIR_OP1_SHIFT) |
+				   (FIR_OP_PA  << FIR_OP2_SHIFT) |
+				   (FIR_OP_WB  << FIR_OP3_SHIFT) |
+				   (FIR_OP_CW1 << FIR_OP4_SHIFT);
+			lbc->fcr = (NAND_CMD_SEQIN << FCR_CMD0_SHIFT) |
+				   (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT);
+			set_addr(mtd, column, page_addr, 0);
+		} else {
+			lbc->fir = (FIR_OP_CW0 << FIR_OP0_SHIFT) |
+				   (FIR_OP_CM2 << FIR_OP1_SHIFT) |
+				   (FIR_OP_CA  << FIR_OP2_SHIFT) |
+				   (FIR_OP_PA  << FIR_OP3_SHIFT) |
+				   (FIR_OP_WB  << FIR_OP4_SHIFT) |
+				   (FIR_OP_CW1 << FIR_OP5_SHIFT);
+			if (column >= mtd->oobblock) {
+				/* OOB area --> READOOB */
+				column -= mtd->oobblock;
+				lbc->fcr = (NAND_CMD_READOOB << FCR_CMD0_SHIFT)
+					 | (NAND_CMD_PAGEPROG<< FCR_CMD1_SHIFT)
+					 | (NAND_CMD_SEQIN << FCR_CMD2_SHIFT);
+				set_addr(mtd, column, page_addr, 1);
+			} else if (column < 256) {
+				/* First 256 bytes --> READ0 */
+				lbc->fcr = (NAND_CMD_READ0 << FCR_CMD0_SHIFT)
+					 | (NAND_CMD_PAGEPROG<< FCR_CMD1_SHIFT)
+					 | (NAND_CMD_SEQIN << FCR_CMD2_SHIFT);
+				set_addr(mtd, column, page_addr, 0);
+			} else {
+				/* Second 256 bytes --> READ1 */
+				column -= 256;
+				lbc->fcr = (NAND_CMD_READ1 << FCR_CMD0_SHIFT)
+					 | (NAND_CMD_PAGEPROG<< FCR_CMD1_SHIFT)
+					 | (NAND_CMD_SEQIN << FCR_CMD2_SHIFT);
+				set_addr(mtd, column, page_addr, 0);
+			}
+		}
+		goto end;
+	/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
+	case NAND_CMD_PAGEPROG:
+		FCM_DEBUG(2,"fcm_cmdfunc: NAND_CMD_PAGEPROG"
+			    " writing %d bytes.\n",fcm->index);
+		/* if the write did not start at 0 or is not a full page */
+		/* then set the exact length, otherwise use a full page  */
+		/* write so the HW generates the ECC. */
+		if (lbc->fbcr ||
+		   (fcm->index != (mtd->oobblock + mtd->oobsize)))
+			lbc->fbcr = fcm->index;
+		fcm->req_bytes = 0;
+		goto write_cmd2;
+	/* CMD_STATUS must read the status byte while CEB is active */
+	/* Note - it does not wait for the ready line */
+	case NAND_CMD_STATUS:
+		FCM_DEBUG(2,"fcm_cmdfunc: NAND_CMD_STATUS.\n");
+		lbc->fir = (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+			   (FIR_OP_RBW << FIR_OP1_SHIFT);
+		lbc->fcr = (NAND_CMD_STATUS << FCR_CMD0_SHIFT);
+		lbc->fbcr = 1;
+		goto write_cmd0;
+	/* RESET without waiting for the ready line */
+	case NAND_CMD_RESET:
+		FCM_DEBUG(2,"fcm_cmdfunc: NAND_CMD_RESET.\n");
+		lbc->fir = (FIR_OP_CM0 << FIR_OP0_SHIFT);
+		lbc->fcr = (NAND_CMD_RESET << FCR_CMD0_SHIFT);
+		lbc->fbcr = 0;
+		goto write_cmd0;
+	default:
+		printk("fcm_cmdfunc: error, unsupported command.\n");
+		goto end;
+	}
+
+	/* Short cuts fall through to save code */
+ write_cmd0:
+	set_addr(mtd, 0, 0, 0);
+ write_cmd1:
+	fcm->req_bytes = lbc->fbcr;
+ write_cmd2:
+	fcm_run_command(mtd);
+
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+	/* if we wrote a page then read back the oob to get the ECC */
+	if ((command == NAND_CMD_PAGEPROG) &&
+	    (this->eccmode > NAND_ECC_SOFT) &&
+	    (lbc->fbcr == 0) &&
+	    (fcm->oobbuf != 0) &&
+	    (fcm->oobbuf != -1)) {
+		int i;
+		uint *oob_config;
+		unsigned char *oob_buf;
+
+		i = fcm->page;
+		oob_buf = (unsigned char*) fcm->oobbuf;
+		oob_config = this->autooob->eccpos;
+
+		/* wait for the write to complete and check it passed */
+		if (!(this->waitfunc(mtd, this, FL_WRITING) & 0x01)) {
+			/* read back the OOB */
+			fcm_cmdfunc(mtd, NAND_CMD_READOOB, 0, i);
+			/* if it succeeded then copy the ECC bytes */
+			if (fcm->status == LTESR_CC) {
+				for (i = 0; i < this->eccbytes; i++) {
+					oob_buf[oob_config[i]] =
+						fcm->addr[oob_config[i]];
+				}
+			}
+		}
+	}
+#endif
+
+ end:
+	return;
+}
+
+/*
+ * fcm_enable_hwecc - start ECC generation
+ */
+static void fcm_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+	return;
+}
+
+/*
+ * fcm_calculate_ecc - Calculate the ECC bytes
+ * This is done by hardware during the write process, so we use this
+ * to arm the oob buf capture on the next write_buf() call. The ECC bytes
+ * only need to be captured if CONFIG_MTD_NAND_VERIFY_WRITE is defined which
+ * reads back the pages and checks they match the data and oob buffers.
+ */
+static int fcm_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
+{
+	register struct nand_chip *this = mtd->priv;
+	struct fcm_nand *fcm = this->priv;
+
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+	/* arm capture of oob buf ptr on next write_buf */
+	fcm->oobbuf = 0;
+#endif
+	return 0;
+}
+
+/*
+ * fcm_correct_data - Detect and correct bit error(s)
+ * The detection and correction is done automatically by the hardware,
+ * if the complete page was read. If the status code is okay then there
+ * was no error, otherwise we return an error code indicating an uncorrectable
+ * error.
+ */
+static int fcm_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+{
+	register struct nand_chip *this = mtd->priv;
+	struct fcm_nand *fcm = this->priv;
+
+	/* No errors */
+	if (fcm->status == LTESR_CC)
+		return 0;
+
+	return -1; /* uncorrectable error */
+}
+
+
+
+/*
+ * Dummy scan_bbt to complete setup of the FMR based on NAND size
+ */
+static int fcm_scan_bbt (struct mtd_info *mtd)
+{
+	volatile immap_t *im = (immap_t *) CFG_IMMR;
+	volatile lbus83xx_t *lbc= &im->lbus;
+	register struct nand_chip *this = mtd->priv;
+	struct fcm_nand *fcm = this->priv;
+	unsigned int i;
+	unsigned int al;
+
+	if (!fcm) {
+		printk (KERN_ERR "fcm_scan_bbt():" \
+			" Failed to allocate chip specific data structure\n");
+		return -1;
+	}
+
+	/* calculate FMR Address Length field */
+	al = 0;
+	for (i = this->pagemask >> 16; i ; i >>= 8) {
+		al++;
+	}
+
+	/* add to ECCM mode set in fcm_init */
+	fcm->fmr |= 12 << FMR_CWTO_SHIFT |  /* Timeout > 12 mSecs */
+		    al << FMR_AL_SHIFT;
+
+	FCM_DEBUG(1,"fcm_init: nand->options  =   %08X\n", this->options);
+	FCM_DEBUG(1,"fcm_init: nand->numchips = %10d\n", this->numchips);
+	FCM_DEBUG(1,"fcm_init: nand->chipsize = %10d\n", this->chipsize);
+	FCM_DEBUG(1,"fcm_init: nand->pagemask = %10X\n", this->pagemask);
+	FCM_DEBUG(1,"fcm_init: nand->eccmode  = %10d\n", this->eccmode );
+	FCM_DEBUG(1,"fcm_init: nand->eccsize  = %10d\n", this->eccsize );
+	FCM_DEBUG(1,"fcm_init: nand->eccbytes = %10d\n", this->eccbytes);
+	FCM_DEBUG(1,"fcm_init: nand->eccsteps = %10d\n", this->eccsteps);
+	FCM_DEBUG(1,"fcm_init: nand->chip_delay = %8d\n", this->chip_delay);
+	FCM_DEBUG(1,"fcm_init: nand->badblockpos = %7d\n", this->badblockpos);
+	FCM_DEBUG(1,"fcm_init: nand->chip_shift = %8d\n", this->chip_shift);
+	FCM_DEBUG(1,"fcm_init: nand->page_shift = %8d\n", this->page_shift);
+	FCM_DEBUG(1,"fcm_init: nand->phys_erase_shift = %2d\n",
+						      this->phys_erase_shift);
+	FCM_DEBUG(1,"fcm_init: mtd->flags     =   %08X\n", mtd->flags);
+	FCM_DEBUG(1,"fcm_init: mtd->size      = %10d\n", mtd->size);
+	FCM_DEBUG(1,"fcm_init: mtd->erasesize = %10d\n", mtd->erasesize);
+	FCM_DEBUG(1,"fcm_init: mtd->oobblock  = %10d\n", mtd->oobblock);
+	FCM_DEBUG(1,"fcm_init: mtd->oobsize   = %10d\n", mtd->oobsize);
+	FCM_DEBUG(1,"fcm_init: mtd->oobavail  = %10d\n", mtd->oobavail);
+	FCM_DEBUG(1,"fcm_init: mtd->ecctype   = %10d\n", mtd->ecctype);
+	FCM_DEBUG(1,"fcm_init: mtd->eccsize   = %10d\n", mtd->eccsize);
+
+	/* adjust Option Register and ECC to match Flash page size */
+	if (mtd->oobblock == 512)
+		lbc->bank[fcm->bank].or &= ~(OR_FCM_PGS);
+	else if (mtd->oobblock == 2048) {
+		lbc->bank[fcm->bank].or |= OR_FCM_PGS;
+		/* adjust ecc setup if needed */
+		if ( (lbc->bank[fcm->bank].br & BR_DECC) == BR_DECC_CHK_GEN) {
+			mtd->eccsize = 2048;
+			mtd->oobavail -= 9;
+			this->eccmode = NAND_ECC_HW12_2048;
+			this->eccsize = 2048;
+			this->eccbytes += 9;
+			this->eccsteps = 1;
+			this->autooob = (fcm->fmr & FMR_ECCM) ?
+					&fcm_oob_lp_eccm1 : &fcm_oob_lp_eccm0;
+			memcpy(&mtd->oobinfo, this->autooob,
+					sizeof(mtd->oobinfo));
+		}
+	}
+	else {
+		printf("fcm_init: page size %d is not supported\n",
+			mtd->oobblock);
+		return -1;
+	}
+	fcm->pgs = (lbc->bank[fcm->bank].or>>OR_FCM_PGS_SHIFT) & 1;
+
+	if (al > 2) {
+		printf("fcm_init: %d address bytes is not supported\n", al+2);
+		return -1;
+	}
+
+	/* restore default scan_bbt function and call it */
+	this->scan_bbt = nand_default_bbt;
+	return nand_default_bbt(mtd);
+}
+
+/*
+ * Board-specific NAND initialization. The following members of the
+ * argument are board-specific (per include/linux/mtd/nand_new.h):
+ * - IO_ADDR_R?: address to read the 8 I/O lines of the flash device
+ * - IO_ADDR_W?: address to write the 8 I/O lines of the flash device
+ * - hwcontrol: hardwarespecific function for accesing control-lines
+ * - dev_ready: hardwarespecific function for accesing device ready/busy line
+ * - enable_hwecc: function to enable (reset) hardware ecc generator. Must
+ *   only be provided if a hardware ECC is available
+ * - eccmode: mode of ecc, see defines
+ * - chip_delay: chip dependent delay for transfering data from array to
+ *   read regs (tR)
+ * - options: various chip options. They can partly be set to inform
+ *   nand_scan about special functionality. See the defines for further
+ *   explanation
+ * Members with a "?" were not set in the merged testing-NAND branch,
+ * so they are not set here either.
+ */
+int board_nand_init(struct nand_chip *nand)
+{
+	volatile immap_t *im = (immap_t *) CFG_IMMR;
+	volatile lbus83xx_t *lbc= &im->lbus;
+	struct fcm_nand *fcm;
+	unsigned int bank;
+
+	/* Enable FCM detection of timeouts, ECC errors and completion */
+	lbc->ltedr &= ~(LTESR_FCT | LTESR_PAR | LTESR_CC);
+
+	fcm = kmalloc (sizeof(struct fcm_nand), GFP_KERNEL);
+	if (!fcm) {
+		printk (KERN_ERR "board_nand_init():" \
+			" Cannot allocate read buffer data structure\n");
+		return;
+	}
+
+	/* Find which chip select bank is being used for this device */
+	for (bank=0; bank<8; bank++) {
+		if ( (lbc->bank[bank].br & BR_V) &&
+		   ( (lbc->bank[bank].br & BR_MSEL) == BR_MS_FCM ) &&
+		   ( (lbc->bank[bank].br & BR_BA) ==
+		     (lbc->bank[bank].or & OR_FCM_AM &
+			(unsigned int)(nand->IO_ADDR_R) ) ) ) {
+			fcm->bank = bank;
+// TODO			fcm->fmr = FMR_ECCM; /* rest filled in later */
+			fcm->fmr = 0; /* rest filled in later */
+			fcm->read_bytes = 0;
+			fcm->index = 0;
+			fcm->pgs = (lbc->bank[bank].or>>OR_FCM_PGS_SHIFT) & 1;
+			fcm->base = lbc->bank[bank].br & BR_BA;
+			fcm->addr = (unsigned char*) (fcm->base);
+			nand->priv = fcm;
+			fcm->oobbuf = -1;
+			break;
+		}
+	}
+
+	if (!nand->priv) {
+		printk (KERN_ERR "board_nand_init():" \
+			" Could not find matching Chip Select\n");
+		return -1;
+	}
+
+	/* set up nand options */
+	nand->options = 0;
+	/* set up function call table */
+	nand->hwcontrol = fcm_hwcontrol;
+	nand->waitfunc = fcm_wait;
+	nand->read_byte = fcm_read_byte;
+	nand->write_byte = fcm_write_byte;
+	nand->read_word = fcm_read_word;
+	nand->write_word = fcm_write_word;
+	nand->read_buf = fcm_read_buf;
+	nand->verify_buf = fcm_verify_buf;
+	nand->write_buf = fcm_write_buf;
+	nand->cmdfunc = fcm_cmdfunc;
+	nand->scan_bbt = fcm_scan_bbt;
+
+	/* If CS Base Register selects full hardware ECC then use it */
+	if ( ( (lbc->bank[bank].br & BR_DECC) >> BR_DECC_SHIFT) == 2) {
+		/* put in small page settings and adjust later if needed */
+		nand->eccmode = NAND_ECC_HW3_512;
+		nand->autooob = (fcm->fmr & FMR_ECCM) ?
+				&fcm_oob_sp_eccm1 : &fcm_oob_sp_eccm0;
+		nand->calculate_ecc = fcm_calculate_ecc;
+		nand->correct_data = fcm_correct_data;
+		nand->enable_hwecc = fcm_enable_hwecc;
+	} else {
+		/* otherwise fall back to default software ECC */
+		nand->eccmode = NAND_ECC_SOFT;
+	}
+	return 0;
+}
+
+#endif
+#endif
Index: u-boot-1.3.2/include/configs/MPC8313ERDB.h
===================================================================
--- u-boot-1.3.2.orig/include/configs/MPC8313ERDB.h	2008-11-24 16:39:14.000000000 +0100
+++ u-boot-1.3.2/include/configs/MPC8313ERDB.h	2008-11-24 16:39:15.000000000 +0100
@@ -357,6 +357,7 @@
 #define CONFIG_CMD_MII
 #define CONFIG_CMD_DATE
 #define CONFIG_CMD_PCI
+#define CONFIG_CMD_NAND
 
 #if defined(CFG_RAMBOOT)
     #undef CONFIG_CMD_ENV