diff options
Diffstat (limited to 'packages/u-boot/u-boot-1.3.1/mpc8313e-rdb-nand.patch')
-rw-r--r-- | packages/u-boot/u-boot-1.3.1/mpc8313e-rdb-nand.patch | 895 |
1 files changed, 895 insertions, 0 deletions
diff --git a/packages/u-boot/u-boot-1.3.1/mpc8313e-rdb-nand.patch b/packages/u-boot/u-boot-1.3.1/mpc8313e-rdb-nand.patch new file mode 100644 index 0000000000..e653b75fb9 --- /dev/null +++ b/packages/u-boot/u-boot-1.3.1/mpc8313e-rdb-nand.patch @@ -0,0 +1,895 @@ +diff -urN u-boot-1.3.1.orig/board/freescale/mpc8313erdb/Makefile u-boot-1.3.1/board/freescale/mpc8313erdb/Makefile +--- u-boot-1.3.1.orig/board/freescale/mpc8313erdb/Makefile 2007-12-06 10:21:19.000000000 +0100 ++++ u-boot-1.3.1/board/freescale/mpc8313erdb/Makefile 2008-01-31 17:35:43.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)) +diff -urN u-boot-1.3.1.orig/board/freescale/mpc8313erdb/nand.c u-boot-1.3.1/board/freescale/mpc8313erdb/nand.c +--- u-boot-1.3.1.orig/board/freescale/mpc8313erdb/nand.c 1970-01-01 01:00:00.000000000 +0100 ++++ u-boot-1.3.1/board/freescale/mpc8313erdb/nand.c 2008-01-31 17:35:26.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 +diff -urN u-boot-1.3.1.orig/include/configs/MPC8313ERDB.h u-boot-1.3.1/include/configs/MPC8313ERDB.h +--- u-boot-1.3.1.orig/include/configs/MPC8313ERDB.h 2007-12-06 10:21:19.000000000 +0100 ++++ u-boot-1.3.1/include/configs/MPC8313ERDB.h 2008-01-31 17:36:18.000000000 +0100 +@@ -360,6 +360,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 |