diff options
-rw-r--r-- | board/atmel/at91cap9adk/nand.c | 37 | ||||
-rw-r--r-- | board/atmel/at91sam9260ek/nand.c | 37 | ||||
-rw-r--r-- | board/atmel/at91sam9261ek/nand.c | 37 | ||||
-rw-r--r-- | board/atmel/at91sam9263ek/nand.c | 37 | ||||
-rw-r--r-- | board/atmel/at91sam9rlek/nand.c | 37 | ||||
-rw-r--r-- | board/freescale/m5373evb/nand.c | 64 | ||||
-rw-r--r-- | board/quad100hd/nand.c | 36 | ||||
-rw-r--r-- | board/socrates/nand.c | 84 | ||||
-rw-r--r-- | common/env_onenand.c | 10 | ||||
-rw-r--r-- | cpu/arm920t/s3c24x0/nand.c | 64 | ||||
-rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 131 | ||||
-rw-r--r-- | drivers/mtd/onenand/onenand_bbt.c | 4 | ||||
-rw-r--r-- | include/linux/mtd/mtd.h | 16 | ||||
-rw-r--r-- | include/linux/mtd/nand.h | 16 | ||||
-rw-r--r-- | include/linux/mtd/nand_legacy.h | 12 | ||||
-rw-r--r-- | include/linux/mtd/onenand.h | 19 |
16 files changed, 307 insertions, 334 deletions
diff --git a/board/atmel/at91cap9adk/nand.c b/board/atmel/at91cap9adk/nand.c index 0432ef1..1dec558 100644 --- a/board/atmel/at91cap9adk/nand.c +++ b/board/atmel/at91cap9adk/nand.c @@ -37,36 +37,35 @@ #define MASK_ALE (1 << 21) /* our ALE is AD21 */ #define MASK_CLE (1 << 22) /* our CLE is AD22 */ -static void at91cap9adk_nand_hwcontrol(struct mtd_info *mtd, int cmd) +static void at91cap9adk_nand_hwcontrol(struct mtd_info *mtd, + int cmd, unsigned int ctrl) { struct nand_chip *this = mtd->priv; - ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; - IO_ADDR_W &= ~(MASK_ALE|MASK_CLE); - switch (cmd) { - case NAND_CTL_SETCLE: - IO_ADDR_W |= MASK_CLE; - break; - case NAND_CTL_SETALE: - IO_ADDR_W |= MASK_ALE; - break; - case NAND_CTL_CLRNCE: - at91_set_gpio_value(AT91_PIN_PD15, 1); - break; - case NAND_CTL_SETNCE: - at91_set_gpio_value(AT91_PIN_PD15, 0); - break; + if (ctrl & NAND_CTRL_CHANGE) { + ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; + IO_ADDR_W &= ~(MASK_ALE | MASK_CLE); + + if (ctrl & NAND_CLE) + IO_ADDR_W |= MASK_CLE; + if (ctrl & NAND_ALE) + IO_ADDR_W |= MASK_ALE; + + at91_set_gpio_value(AT91_PIN_PD15, !(ctrl & NAND_NCE)); + this->IO_ADDR_W = (void *) IO_ADDR_W; } - this->IO_ADDR_W = (void *) IO_ADDR_W; + + if (cmd != NAND_CMD_NONE) + writeb(cmd, this->IO_ADDR_W); } int board_nand_init(struct nand_chip *nand) { - nand->eccmode = NAND_ECC_SOFT; + nand->ecc.mode = NAND_ECC_SOFT; #ifdef CFG_NAND_DBW_16 nand->options = NAND_BUSWIDTH_16; #endif - nand->hwcontrol = at91cap9adk_nand_hwcontrol; + nand->cmd_ctrl = at91cap9adk_nand_hwcontrol; nand->chip_delay = 20; return 0; diff --git a/board/atmel/at91sam9260ek/nand.c b/board/atmel/at91sam9260ek/nand.c index 9738f0f..665e35c 100644 --- a/board/atmel/at91sam9260ek/nand.c +++ b/board/atmel/at91sam9260ek/nand.c @@ -37,27 +37,26 @@ #define MASK_ALE (1 << 21) /* our ALE is AD21 */ #define MASK_CLE (1 << 22) /* our CLE is AD22 */ -static void at91sam9260ek_nand_hwcontrol(struct mtd_info *mtd, int cmd) +static void at91sam9260ek_nand_hwcontrol(struct mtd_info *mtd, + int cmd, unsigned int ctrl) { struct nand_chip *this = mtd->priv; - ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; - IO_ADDR_W &= ~(MASK_ALE|MASK_CLE); - switch (cmd) { - case NAND_CTL_SETCLE: - IO_ADDR_W |= MASK_CLE; - break; - case NAND_CTL_SETALE: - IO_ADDR_W |= MASK_ALE; - break; - case NAND_CTL_CLRNCE: - at91_set_gpio_value(AT91_PIN_PC14, 1); - break; - case NAND_CTL_SETNCE: - at91_set_gpio_value(AT91_PIN_PC14, 0); - break; + if (ctrl & NAND_CTRL_CHANGE) { + ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; + IO_ADDR_W &= ~(MASK_ALE | MASK_CLE); + + if (ctrl & NAND_CLE) + IO_ADDR_W |= MASK_CLE; + if (ctrl & NAND_ALE) + IO_ADDR_W |= MASK_ALE; + + at91_set_gpio_value(AT91_PIN_PC14, !(ctrl & NAND_NCE)); + this->IO_ADDR_W = (void *) IO_ADDR_W; } - this->IO_ADDR_W = (void *) IO_ADDR_W; + + if (cmd != NAND_CMD_NONE) + writeb(cmd, this->IO_ADDR_W); } static int at91sam9260ek_nand_ready(struct mtd_info *mtd) @@ -67,11 +66,11 @@ static int at91sam9260ek_nand_ready(struct mtd_info *mtd) int board_nand_init(struct nand_chip *nand) { - nand->eccmode = NAND_ECC_SOFT; + nand->ecc.mode = NAND_ECC_SOFT; #ifdef CFG_NAND_DBW_16 nand->options = NAND_BUSWIDTH_16; #endif - nand->hwcontrol = at91sam9260ek_nand_hwcontrol; + nand->cmd_ctrl = at91sam9260ek_nand_hwcontrol; nand->dev_ready = at91sam9260ek_nand_ready; nand->chip_delay = 20; diff --git a/board/atmel/at91sam9261ek/nand.c b/board/atmel/at91sam9261ek/nand.c index 35b26db..fccb9d7 100644 --- a/board/atmel/at91sam9261ek/nand.c +++ b/board/atmel/at91sam9261ek/nand.c @@ -37,27 +37,26 @@ #define MASK_ALE (1 << 22) /* our ALE is AD22 */ #define MASK_CLE (1 << 21) /* our CLE is AD21 */ -static void at91sam9261ek_nand_hwcontrol(struct mtd_info *mtd, int cmd) +static void at91sam9261ek_nand_hwcontrol(struct mtd_info *mtd, + int cmd, unsigned int ctrl) { struct nand_chip *this = mtd->priv; - ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; - IO_ADDR_W &= ~(MASK_ALE|MASK_CLE); - switch (cmd) { - case NAND_CTL_SETCLE: - IO_ADDR_W |= MASK_CLE; - break; - case NAND_CTL_SETALE: - IO_ADDR_W |= MASK_ALE; - break; - case NAND_CTL_CLRNCE: - at91_set_gpio_value(AT91_PIN_PC14, 1); - break; - case NAND_CTL_SETNCE: - at91_set_gpio_value(AT91_PIN_PC14, 0); - break; + if (ctrl & NAND_CTRL_CHANGE) { + ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; + IO_ADDR_W &= ~(MASK_ALE | MASK_CLE); + + if (ctrl & NAND_CLE) + IO_ADDR_W |= MASK_CLE; + if (ctrl & NAND_ALE) + IO_ADDR_W |= MASK_ALE; + + at91_set_gpio_value(AT91_PIN_PC14, !(ctrl & NAND_NCE)); + this->IO_ADDR_W = (void *) IO_ADDR_W; } - this->IO_ADDR_W = (void *) IO_ADDR_W; + + if (cmd != NAND_CMD_NONE) + writeb(cmd, this->IO_ADDR_W); } static int at91sam9261ek_nand_ready(struct mtd_info *mtd) @@ -67,11 +66,11 @@ static int at91sam9261ek_nand_ready(struct mtd_info *mtd) int board_nand_init(struct nand_chip *nand) { - nand->eccmode = NAND_ECC_SOFT; + nand->ecc.mode = NAND_ECC_SOFT; #ifdef CFG_NAND_DBW_16 nand->options = NAND_BUSWIDTH_16; #endif - nand->hwcontrol = at91sam9261ek_nand_hwcontrol; + nand->cmd_ctrl = at91sam9261ek_nand_hwcontrol; nand->dev_ready = at91sam9261ek_nand_ready; nand->chip_delay = 20; diff --git a/board/atmel/at91sam9263ek/nand.c b/board/atmel/at91sam9263ek/nand.c index 5079972..250ec7f 100644 --- a/board/atmel/at91sam9263ek/nand.c +++ b/board/atmel/at91sam9263ek/nand.c @@ -37,27 +37,26 @@ #define MASK_ALE (1 << 21) /* our ALE is AD21 */ #define MASK_CLE (1 << 22) /* our CLE is AD22 */ -static void at91sam9263ek_nand_hwcontrol(struct mtd_info *mtd, int cmd) +static void at91sam9263ek_nand_hwcontrol(struct mtd_info *mtd, + int cmd, unsigned int ctrl) { struct nand_chip *this = mtd->priv; - ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; - IO_ADDR_W &= ~(MASK_ALE|MASK_CLE); - switch (cmd) { - case NAND_CTL_SETCLE: - IO_ADDR_W |= MASK_CLE; - break; - case NAND_CTL_SETALE: - IO_ADDR_W |= MASK_ALE; - break; - case NAND_CTL_CLRNCE: - at91_set_gpio_value(AT91_PIN_PD15, 1); - break; - case NAND_CTL_SETNCE: - at91_set_gpio_value(AT91_PIN_PD15, 0); - break; + if (ctrl & NAND_CTRL_CHANGE) { + ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; + IO_ADDR_W &= ~(MASK_ALE | MASK_CLE); + + if (ctrl & NAND_CLE) + IO_ADDR_W |= MASK_CLE; + if (ctrl & NAND_ALE) + IO_ADDR_W |= MASK_ALE; + + at91_set_gpio_value(AT91_PIN_PD15, !(ctrl & NAND_NCE)); + this->IO_ADDR_W = (void *) IO_ADDR_W; } - this->IO_ADDR_W = (void *) IO_ADDR_W; + + if (cmd != NAND_CMD_NONE) + writeb(cmd, this->IO_ADDR_W); } static int at91sam9263ek_nand_ready(struct mtd_info *mtd) @@ -67,11 +66,11 @@ static int at91sam9263ek_nand_ready(struct mtd_info *mtd) int board_nand_init(struct nand_chip *nand) { - nand->eccmode = NAND_ECC_SOFT; + nand->ecc.mode = NAND_ECC_SOFT; #ifdef CFG_NAND_DBW_16 nand->options = NAND_BUSWIDTH_16; #endif - nand->hwcontrol = at91sam9263ek_nand_hwcontrol; + nand->cmd_ctrl = at91sam9263ek_nand_hwcontrol; nand->dev_ready = at91sam9263ek_nand_ready; nand->chip_delay = 20; diff --git a/board/atmel/at91sam9rlek/nand.c b/board/atmel/at91sam9rlek/nand.c index 5af1a31..eb342b8 100644 --- a/board/atmel/at91sam9rlek/nand.c +++ b/board/atmel/at91sam9rlek/nand.c @@ -37,27 +37,26 @@ #define MASK_ALE (1 << 21) /* our ALE is AD21 */ #define MASK_CLE (1 << 22) /* our CLE is AD22 */ -static void at91sam9rlek_nand_hwcontrol(struct mtd_info *mtd, int cmd) +static void at91sam9rlek_nand_hwcontrol(struct mtd_info *mtd, + int cmd, unsigned int ctrl) { struct nand_chip *this = mtd->priv; - ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; - IO_ADDR_W &= ~(MASK_ALE|MASK_CLE); - switch (cmd) { - case NAND_CTL_SETCLE: - IO_ADDR_W |= MASK_CLE; - break; - case NAND_CTL_SETALE: - IO_ADDR_W |= MASK_ALE; - break; - case NAND_CTL_CLRNCE: - at91_set_gpio_value(AT91_PIN_PB6, 1); - break; - case NAND_CTL_SETNCE: - at91_set_gpio_value(AT91_PIN_PB6, 0); - break; + if (ctrl & NAND_CTRL_CHANGE) { + ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; + IO_ADDR_W &= ~(MASK_ALE | MASK_CLE); + + if (ctrl & NAND_CLE) + IO_ADDR_W |= MASK_CLE; + if (ctrl & NAND_ALE) + IO_ADDR_W |= MASK_ALE; + + at91_set_gpio_value(AT91_PIN_PB6, !(ctrl & NAND_NCE)); + this->IO_ADDR_W = (void *) IO_ADDR_W; } - this->IO_ADDR_W = (void *) IO_ADDR_W; + + if (cmd != NAND_CMD_NONE) + writeb(cmd, this->IO_ADDR_W); } static int at91sam9rlek_nand_ready(struct mtd_info *mtd) @@ -67,11 +66,11 @@ static int at91sam9rlek_nand_ready(struct mtd_info *mtd) int board_nand_init(struct nand_chip *nand) { - nand->eccmode = NAND_ECC_SOFT; + nand->ecc.mode = NAND_ECC_SOFT; #ifdef CFG_NAND_DBW_16 nand->options = NAND_BUSWIDTH_16; #endif - nand->hwcontrol = at91sam9rlek_nand_hwcontrol; + nand->cmd_ctrl = at91sam9rlek_nand_hwcontrol; nand->dev_ready = at91sam9rlek_nand_ready; nand->chip_delay = 20; diff --git a/board/freescale/m5373evb/nand.c b/board/freescale/m5373evb/nand.c index 344a614..404a9c3 100644 --- a/board/freescale/m5373evb/nand.c +++ b/board/freescale/m5373evb/nand.c @@ -36,64 +36,39 @@ DECLARE_GLOBAL_DATA_PTR; #include <linux/mtd/mtd.h> #define SET_CLE 0x10 -#define CLR_CLE ~SET_CLE #define SET_ALE 0x08 -#define CLR_ALE ~SET_ALE -static void nand_hwcontrol(struct mtd_info *mtdinfo, int cmd) +static void nand_hwcontrol(struct mtd_info *mtdinfo, int cmd, unsigned int ctrl) { struct nand_chip *this = mtdinfo->priv; volatile fbcs_t *fbcs = (fbcs_t *) MMAP_FBCS; u32 nand_baseaddr = (u32) this->IO_ADDR_W; - switch (cmd) { - case NAND_CTL_SETNCE: - case NAND_CTL_CLRNCE: - break; - case NAND_CTL_SETCLE: - nand_baseaddr |= SET_CLE; - break; - case NAND_CTL_CLRCLE: - nand_baseaddr &= CLR_CLE; - break; - case NAND_CTL_SETALE: - nand_baseaddr |= SET_ALE; - break; - case NAND_CTL_CLRALE: - nand_baseaddr |= CLR_ALE; - break; - case NAND_CTL_SETWP: - fbcs->csmr2 |= FBCS_CSMR_WP; - break; - case NAND_CTL_CLRWP: - fbcs->csmr2 &= ~FBCS_CSMR_WP; - break; - } - this->IO_ADDR_W = (void __iomem *)(nand_baseaddr); -} + if (ctrl & NAND_CTRL_CHANGE) { + ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; + IO_ADDR_W &= ~(SET_ALE | SE_CLE); -static void nand_write_byte(struct mtd_info *mtdinfo, u_char byte) -{ - struct nand_chip *this = mtdinfo->priv; - *((volatile u8 *)(this->IO_ADDR_W)) = byte; -} + if (ctrl & NAND_CLE) + IO_ADDR_W |= SET_CLE; + if (ctrl & NAND_ALE) + IO_ADDR_W |= SET_ALE; -static u8 nand_read_byte(struct mtd_info *mtdinfo) -{ - struct nand_chip *this = mtdinfo->priv; - return (u8) (*((volatile u8 *)this->IO_ADDR_R)); -} + at91_set_gpio_value(AT91_PIN_PD15, !(ctrl & NAND_NCE)); + this->IO_ADDR_W = (void *)IO_ADDR_W; -static int nand_dev_ready(struct mtd_info *mtdinfo) -{ - return 1; + } + + if (cmd != NAND_CMD_NONE) + writeb(cmd, this->IO_ADDR_W); } int board_nand_init(struct nand_chip *nand) { volatile gpio_t *gpio = (gpio_t *) MMAP_GPIO; + volatile fbcs_t *fbcs = (fbcs_t *) MMAP_FBCS; *((volatile u16 *)CFG_LATCH_ADDR) |= 0x0004; + fbcs->csmr2 &= ~FBCS_CSMR_WP; /* set up pin configuration */ gpio->par_timer &= ~GPIO_PAR_TIN3_TIN3; @@ -103,11 +78,8 @@ int board_nand_init(struct nand_chip *nand) gpio->podr_timer = 0; nand->chip_delay = 50; - nand->eccmode = NAND_ECC_SOFT; - nand->hwcontrol = nand_hwcontrol; - nand->read_byte = nand_read_byte; - nand->write_byte = nand_write_byte; - nand->dev_ready = nand_dev_ready; + nand->ecc.mode = NAND_ECC_SOFT; + nand->cmd_ctrl = nand_hwcontrol; return 0; } diff --git a/board/quad100hd/nand.c b/board/quad100hd/nand.c index a36b89d..766ee95 100644 --- a/board/quad100hd/nand.c +++ b/board/quad100hd/nand.c @@ -25,35 +25,25 @@ #include <config.h> #if defined(CONFIG_CMD_NAND) #include <asm/gpio.h> +#include <asm/io.h> #include <nand.h> /* * hardware specific access to control-lines */ -static void quad100hd_hwcontrol(struct mtd_info *mtd, int cmd) +static void quad100hd_hwcontrol(struct mtd_info *mtd, + int cmd, unsigned int ctrl) { - switch(cmd) { - case NAND_CTL_SETCLE: - gpio_write_bit(CFG_NAND_CLE, 1); - break; - case NAND_CTL_CLRCLE: - gpio_write_bit(CFG_NAND_CLE, 0); - break; + struct nand_chip *this = mtd->priv; - case NAND_CTL_SETALE: - gpio_write_bit(CFG_NAND_ALE, 1); - break; - case NAND_CTL_CLRALE: - gpio_write_bit(CFG_NAND_ALE, 0); - break; - - case NAND_CTL_SETNCE: - gpio_write_bit(CFG_NAND_CE, 0); - break; - case NAND_CTL_CLRNCE: - gpio_write_bit(CFG_NAND_CE, 1); - break; + if (ctrl & NAND_CTRL_CHANGE) { + gpio_write_bit(CFG_NAND_CLE, !!(ctrl & NAND_CLE)); + gpio_write_bit(CFG_NAND_ALE, !!(ctrl & NAND_ALE)); + gpio_write_bit(CFG_NAND_CE, !(ctrl & NAND_NCE)); } + + if (cmd != NAND_CMD_NONE) + writeb(cmd, this->IO_ADDR_W); } static int quad100hd_nand_ready(struct mtd_info *mtd) @@ -67,9 +57,9 @@ static int quad100hd_nand_ready(struct mtd_info *mtd) int board_nand_init(struct nand_chip *nand) { /* Set address of hardware control function */ - nand->hwcontrol = quad100hd_hwcontrol; + nand->cmd_ctrl = quad100hd_hwcontrol; nand->dev_ready = quad100hd_nand_ready; - nand->eccmode = NAND_ECC_SOFT; + nand->ecc.mode = NAND_ECC_SOFT; /* 15 us command delay time */ nand->chip_delay = 20; diff --git a/board/socrates/nand.c b/board/socrates/nand.c index fc82ecb..6ec53f8 100644 --- a/board/socrates/nand.c +++ b/board/socrates/nand.c @@ -31,22 +31,20 @@ static int state; static void nand_write_byte(struct mtd_info *mtd, u_char byte); static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len); -static void nand_write_word(struct mtd_info *mtd, u16 word); static u_char nand_read_byte(struct mtd_info *mtd); static u16 nand_read_word(struct mtd_info *mtd); static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len); static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len); static int nand_device_ready(struct mtd_info *mtdinfo); -static void nand_hwcontrol(struct mtd_info *mtdinfo, int cmd); #define FPGA_NAND_CMD_MASK (0x7 << 28) -#define FPGA_NAND_CMD_COMMAND (0x0 << 28) +#define FPGA_NAND_CMD_COMMAND (0x0 << 28) #define FPGA_NAND_CMD_ADDR (0x1 << 28) #define FPGA_NAND_CMD_READ (0x2 << 28) #define FPGA_NAND_CMD_WRITE (0x3 << 28) #define FPGA_NAND_BUSY (0x1 << 15) #define FPGA_NAND_ENABLE (0x1 << 31) -#define FPGA_NAND_DATA_SHIFT 16 +#define FPGA_NAND_DATA_SHIFT 16 /** * nand_write_byte - write one byte to the chip @@ -59,16 +57,6 @@ static void nand_write_byte(struct mtd_info *mtd, u_char byte) } /** - * nand_write_word - write one word to the chip - * @mtd: MTD device structure - * @word: data word to write - */ -static void nand_write_word(struct mtd_info *mtd, u16 word) -{ - nand_write_buf(mtd, (const uchar *)&word, sizeof(word)); -} - -/** * nand_write_buf - write buffer to chip * @mtd: MTD device structure * @buf: data buffer @@ -78,18 +66,10 @@ static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) { int i; struct nand_chip *this = mtd->priv; - long val; - - if ((state & FPGA_NAND_CMD_MASK) == FPGA_NAND_CMD_MASK) { - /* Write data */ - val = (state & FPGA_NAND_ENABLE) | FPGA_NAND_CMD_WRITE; - } else { - /* Write address or command */ - val = state; - } for (i = 0; i < len; i++) { - out_be32(this->IO_ADDR_W, val | (buf[i] << FPGA_NAND_DATA_SHIFT)); + out_be32(this->IO_ADDR_W, + state | (buf[i] << FPGA_NAND_DATA_SHIFT)); } } @@ -148,7 +128,7 @@ static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) for (i = 0; i < len; i++) { if (buf[i] != nand_read_byte(mtd)); - return -EFAULT; + return -EFAULT; } return 0; } @@ -171,42 +151,42 @@ static int nand_device_ready(struct mtd_info *mtdinfo) * @mtd: MTD device structure * @cmd: Command */ -static void nand_hwcontrol(struct mtd_info *mtdinfo, int cmd) +static void nand_hwcontrol(struct mtd_info *mtdinfo, int cmd, unsigned int ctrl) { + if (ctrl & NAND_CTRL_CHANGE) { + state &= ~(FPGA_NAND_CMD_MASK | FPGA_NAND_ENABLE); + + switch (ctrl & (NAND_ALE | NAND_CLE)) { + case 0: + state |= FPGA_NAND_CMD_WRITE; + break; + + case NAND_ALE: + state |= FPGA_NAND_CMD_ADDR; + break; - switch(cmd) { - case NAND_CTL_CLRALE: - state |= FPGA_NAND_CMD_MASK; /* use all 1s to mark */ - break; - case NAND_CTL_CLRCLE: - state |= FPGA_NAND_CMD_MASK; /* use all 1s to mark */ - break; - case NAND_CTL_SETCLE: - state = (state & ~FPGA_NAND_CMD_MASK) | FPGA_NAND_CMD_COMMAND; - break; - case NAND_CTL_SETALE: - state = (state & ~FPGA_NAND_CMD_MASK) | FPGA_NAND_CMD_ADDR; - break; - case NAND_CTL_SETNCE: - state |= FPGA_NAND_ENABLE; - break; - case NAND_CTL_CLRNCE: - state &= ~FPGA_NAND_ENABLE; - break; - default: - printf("%s: unknown cmd %#x\n", __FUNCTION__, cmd); - break; + case NAND_CLE: + state |= FPGA_NAND_CMD_COMMAND; + break; + + default: + printf("%s: unknown ctrl %#x\n", __FUNCTION__, ctrl); + } + + if (ctrl & NAND_NCE) + state |= FPGA_NAND_ENABLE; } + + if (cmd != NAND_CMD_NONE) + nand_write_byte(mtdinfo, cmd); } int board_nand_init(struct nand_chip *nand) { - nand->hwcontrol = nand_hwcontrol; - nand->eccmode = NAND_ECC_SOFT; + nand->cmd_ctrl = nand_hwcontrol; + nand->ecc.mode = NAND_ECC_SOFT; nand->dev_ready = nand_device_ready; - nand->write_byte = nand_write_byte; nand->read_byte = nand_read_byte; - nand->write_word = nand_write_word; nand->read_word = nand_read_word; nand->write_buf = nand_write_buf; nand->read_buf = nand_read_buf; diff --git a/common/env_onenand.c b/common/env_onenand.c index dbd0883..d5c907c 100644 --- a/common/env_onenand.c +++ b/common/env_onenand.c @@ -40,7 +40,7 @@ extern struct onenand_chip onenand_chip; /* References to names in env_common.c */ extern uchar default_environment[]; -#define ONENAND_ENV_SIZE(mtd) (mtd.oobblock - ENV_HEADER_SIZE) +#define ONENAND_ENV_SIZE(mtd) (mtd.writesize - ENV_HEADER_SIZE) char *env_name_spec = "OneNAND"; @@ -68,12 +68,12 @@ void env_relocate_spec(void) env_addr = CFG_ENV_ADDR; /* Check OneNAND exist */ - if (onenand_mtd.oobblock) + if (onenand_mtd.writesize) /* Ignore read fail */ - onenand_read(&onenand_mtd, env_addr, onenand_mtd.oobblock, + onenand_read(&onenand_mtd, env_addr, onenand_mtd.writesize, &retlen, (u_char *) env_ptr); else - onenand_mtd.oobblock = MAX_ONENAND_PAGESIZE; + onenand_mtd.writesize = MAX_ONENAND_PAGESIZE; if (crc32(0, env_ptr->data, ONENAND_ENV_SIZE(onenand_mtd)) != env_ptr->crc) @@ -109,7 +109,7 @@ int saveenv(void) env_ptr->crc = crc32(0, env_ptr->data, ONENAND_ENV_SIZE(onenand_mtd)); - if (onenand_write(&onenand_mtd, env_addr, onenand_mtd.oobblock, &retlen, + if (onenand_write(&onenand_mtd, env_addr, onenand_mtd.writesize, &retlen, (u_char *) env_ptr)) { printf("OneNAND: write failed at 0x%08x\n", instr.addr); return 2; diff --git a/cpu/arm920t/s3c24x0/nand.c b/cpu/arm920t/s3c24x0/nand.c index 14882cb..60174fb 100644 --- a/cpu/arm920t/s3c24x0/nand.c +++ b/cpu/arm920t/s3c24x0/nand.c @@ -31,6 +31,7 @@ #include <nand.h> #include <s3c2410.h> +#include <asm/io.h> #define __REGb(x) (*(volatile unsigned char *)(x)) #define __REGi(x) (*(volatile unsigned int *)(x)) @@ -54,34 +55,33 @@ #define S3C2410_NFCONF_TWRPH0(x) ((x)<<4) #define S3C2410_NFCONF_TWRPH1(x) ((x)<<0) -static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd) +#define S3C2410_ADDR_NALE 4 +#define S3C2410_ADDR_NCLE 8 + +static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) { struct nand_chip *chip = mtd->priv; - DEBUGN("hwcontrol(): 0x%02x: ", cmd); - - switch (cmd) { - case NAND_CTL_SETNCE: - NFCONF &= ~S3C2410_NFCONF_nFCE; - DEBUGN("NFCONF=0x%08x\n", NFCONF); - break; - case NAND_CTL_CLRNCE: - NFCONF |= S3C2410_NFCONF_nFCE; - DEBUGN("NFCONF=0x%08x\n", NFCONF); - break; - case NAND_CTL_SETALE: - chip->IO_ADDR_W = NF_BASE + 0x8; - DEBUGN("SETALE\n"); - break; - case NAND_CTL_SETCLE: - chip->IO_ADDR_W = NF_BASE + 0x4; - DEBUGN("SETCLE\n"); - break; - default: - chip->IO_ADDR_W = NF_BASE + 0xc; - break; + DEBUGN("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl); + + if (ctrl & NAND_CTRL_CHANGE) { + ulong IO_ADDR_W = NF_BASE; + + if (!(ctrl & NAND_CLE)) + IO_ADDR_W |= S3C2410_ADDR_NCLE; + if (!(ctrl & NAND_ALE)) + IO_ADDR_W |= S3C2410_ADDR_NALE; + + chip->IO_ADDR_W = (void *)IO_ADDR_W; + + if (ctrl & NAND_NCE) + NFCONF &= ~S3C2410_NFCONF_nFCE; + else + NFCONF |= S3C2410_NFCONF_nFCE; } - return; + + if (cmd != NAND_CMD_NONE) + writeb(cmd, chip->IO_ADDR_W); } static int s3c2410_dev_ready(struct mtd_info *mtd) @@ -93,7 +93,7 @@ static int s3c2410_dev_ready(struct mtd_info *mtd) #ifdef CONFIG_S3C2410_NAND_HWECC void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode) { - DEBUGN("s3c2410_nand_enable_hwecc(%p, %d)\n", mtd ,mode); + DEBUGN("s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode); NFCONF |= S3C2410_NFCONF_INITECC; } @@ -143,23 +143,23 @@ int board_nand_init(struct nand_chip *nand) NFCONF = cfg; /* initialize nand_chip data structure */ - nand->IO_ADDR_R = nand->IO_ADDR_W = 0x4e00000c; + nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e00000c; /* read_buf and write_buf are default */ /* read_byte and write_byte are default */ /* hwcontrol always must be implemented */ - nand->hwcontrol = s3c2410_hwcontrol; + nand->cmd_ctrl = s3c2410_hwcontrol; nand->dev_ready = s3c2410_dev_ready; #ifdef CONFIG_S3C2410_NAND_HWECC - nand->enable_hwecc = s3c2410_nand_enable_hwecc; - nand->calculate_ecc = s3c2410_nand_calculate_ecc; - nand->correct_data = s3c2410_nand_correct_data; - nand->eccmode = NAND_ECC_HW3_512; + nand->ecc.hwctl = s3c2410_nand_enable_hwecc; + nand->ecc.calculate = s3c2410_nand_calculate_ecc; + nand->ecc.correct = s3c2410_nand_correct_data; + nand->ecc.mode = NAND_ECC_HW3_512; #else - nand->eccmode = NAND_ECC_SOFT; + nand->ecc.mode = NAND_ECC_SOFT; #endif #ifdef CONFIG_S3C2410_NAND_BBT diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 7c9438b..8f12fa2 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -328,7 +328,7 @@ static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area) if (ONENAND_CURRENT_BUFFERRAM(this)) { if (area == ONENAND_DATARAM) - return mtd->oobblock; + return mtd->writesize; if (area == ONENAND_SPARERAM) return mtd->oobsize; } @@ -479,6 +479,30 @@ static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr, } /** + * onenand_invalidate_bufferram - [GENERIC] Invalidate BufferRAM information + * @param mtd MTD data structure + * @param addr start address to invalidate + * @param len length to invalidate + * + * Invalidate BufferRAM information + */ +static void onenand_invalidate_bufferram(struct mtd_info *mtd, loff_t addr, + unsigned int len) +{ + struct onenand_chip *this = mtd->priv; + int i; + loff_t end_addr = addr + len; + + /* Invalidate BufferRAM */ + for (i = 0; i < MAX_BUFFERRAM; i++) { + loff_t buf_addr = this->bufferram[i].block << this->erase_shift; + + if (buf_addr >= addr && buf_addr < end_addr) + this->bufferram[i].valid = 0; + } +} + +/** * onenand_get_device - [GENERIC] Get chip for selected access * @param mtd MTD device structure * @param new_state the state which is requested @@ -538,15 +562,15 @@ static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, onenand_get_device(mtd, FL_READING); while (read < len) { - thislen = min_t(int, mtd->oobblock, len - read); + thislen = min_t(int, mtd->writesize, len - read); - column = from & (mtd->oobblock - 1); - if (column + thislen > mtd->oobblock) - thislen = mtd->oobblock - column; + column = from & (mtd->writesize - 1); + if (column + thislen > mtd->writesize) + thislen = mtd->writesize - column; if (!onenand_check_bufferram(mtd, from)) { this->command(mtd, ONENAND_CMD_READ, from, - mtd->oobblock); + mtd->writesize); ret = this->wait(mtd, FL_READING); /* First copy data and check return value for ECC handling */ onenand_update_bufferram(mtd, from, 1); @@ -661,7 +685,7 @@ int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, /* Read more? */ if (read < len) { /* Page size */ - from += mtd->oobblock; + from += mtd->writesize; column = 0; } } @@ -688,7 +712,7 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char * buf, void __iomem *dataram0, *dataram1; int ret = 0; - this->command(mtd, ONENAND_CMD_READ, addr, mtd->oobblock); + this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize); ret = this->wait(mtd, FL_READING); if (ret) @@ -698,9 +722,9 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char * buf, /* Check, if the two dataram areas are same */ dataram0 = this->base + ONENAND_DATARAM; - dataram1 = dataram0 + mtd->oobblock; + dataram1 = dataram0 + mtd->writesize; - if (memcmp(dataram0, dataram1, mtd->oobblock)) + if (memcmp(dataram0, dataram1, mtd->writesize)) return -EBADMSG; return 0; @@ -709,7 +733,7 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char * buf, #define onenand_verify_page(...) (0) #endif -#define NOTALIGNED(x) ((x & (mtd->oobblock - 1)) != 0) +#define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0) /** * onenand_write_ecc - [MTD Interface] OneNAND write with ECC @@ -757,15 +781,15 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, /* Loop until all data write */ while (written < len) { - int thislen = min_t(int, mtd->oobblock, len - written); + int thislen = min_t(int, mtd->writesize, len - written); - this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock); + this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->writesize); this->write_bufferram(mtd, ONENAND_DATARAM, buf, 0, thislen); this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); - this->command(mtd, ONENAND_CMD_PROG, to, mtd->oobblock); + this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); onenand_update_bufferram(mtd, to, 1); @@ -890,6 +914,25 @@ int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, } /** + * onenand_block_isbad_nolock - [GENERIC] Check if a block is marked bad + * @param mtd MTD device structure + * @param ofs offset from device start + * @param allowbbt 1, if its allowed to access the bbt area + * + * Check, if the block is bad, Either by reading the bad block table or + * calling of the scan function. + */ +static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt) +{ + struct onenand_chip *this = mtd->priv; + struct bbm_info *bbm = this->bbm; + + /* Return info from the table */ + return bbm->isbad_bbt(mtd, ofs, allowbbt); +} + + +/** * onenand_erase - [MTD Interface] erase block(s) * @param mtd MTD device structure * @param instr erase instruction @@ -947,6 +990,8 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) this->command(mtd, ONENAND_CMD_ERASE, addr, block_size); + onenand_invalidate_bufferram(mtd, addr, block_size); + ret = this->wait(mtd, FL_ERASING); /* Check, if it is write protected */ if (ret) { @@ -1002,30 +1047,45 @@ void onenand_sync(struct mtd_info *mtd) * onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad * @param mtd MTD device structure * @param ofs offset relative to mtd start + * + * Check whether the block is bad */ int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs) { - /* - * TODO - * 1. Bad block table (BBT) - * -> using NAND BBT to support JFFS2 - * 2. Bad block management (BBM) - * -> bad block replace scheme - * - * Currently we do nothing - */ - return 0; + int ret; + + /* Check for invalid offset */ + if (ofs > mtd->size) + return -EINVAL; + + onenand_get_device(mtd, FL_READING); + ret = onenand_block_isbad_nolock(mtd,ofs, 0); + onenand_release_device(mtd); + return ret; } /** * onenand_block_markbad - [MTD Interface] Mark the block at the given offset as bad * @param mtd MTD device structure * @param ofs offset relative to mtd start + * + * Mark the block as bad */ int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs) { - /* see above */ - return 0; + struct onenand_chip *this = mtd->priv; + int ret; + + ret = onenand_block_isbad(mtd, ofs); + if (ret) { + /* If it was bad already, return success and do nothing */ + if (ret > 0) + return 0; + return ret; + } + + ret = this->block_markbad(mtd, ofs); + return ret; } /** @@ -1181,10 +1241,8 @@ static int onenand_probe(struct mtd_info *mtd) /* Reset OneNAND to read default register values */ this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM); - { - int i; - for (i = 0; i < 10000; i++) ; - } + /* Wait reset */ + this->wait(mtd, FL_RESETING); /* Read manufacturer and device IDs from Register */ maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID); @@ -1209,16 +1267,16 @@ static int onenand_probe(struct mtd_info *mtd) /* OneNAND page size & block size */ /* The data buffer size is equal to page size */ - mtd->oobblock = + mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE); - mtd->oobsize = mtd->oobblock >> 5; + mtd->oobsize = mtd->writesize >> 5; /* Pagers per block is always 64 in OneNAND */ - mtd->erasesize = mtd->oobblock << 6; + mtd->erasesize = mtd->writesize << 6; this->erase_shift = ffs(mtd->erasesize) - 1; - this->page_shift = ffs(mtd->oobblock) - 1; + this->page_shift = ffs(mtd->writesize) - 1; this->ppb_shift = (this->erase_shift - this->page_shift); - this->page_mask = (mtd->erasesize / mtd->oobblock) - 1; + this->page_mask = (mtd->erasesize / mtd->writesize) - 1; /* REVIST: Multichip handling */ @@ -1237,11 +1295,10 @@ static int onenand_probe(struct mtd_info *mtd) this->options |= ONENAND_CONT_LOCK; } + mtd->flags = MTD_CAP_NANDFLASH; mtd->erase = onenand_erase; mtd->read = onenand_read; mtd->write = onenand_write; - mtd->read_ecc = onenand_read_ecc; - mtd->write_ecc = onenand_write_ecc; mtd->read_oob = onenand_read_oob; mtd->write_oob = onenand_write_oob; mtd->sync = onenand_sync; diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index 0abaa1a..d13d277 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c @@ -94,7 +94,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t * buf, /* No need to read pages fully, * just read required OOB bytes */ ret = onenand_read_oob(mtd, - from + j * mtd->oobblock + + from + j * mtd->writesize + bd->offs, readlen, &retlen, &buf[0]); @@ -104,7 +104,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t * buf, } if (check_short_pattern - (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { + (&buf[j * scanlen], scanlen, mtd->writesize, bd)) { bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", i >> 1, diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 8e0dc00..14815c2 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -22,6 +22,22 @@ #define MTD_ERASE_DONE 0x08 #define MTD_ERASE_FAILED 0x10 +/* + * Enumeration for NAND/OneNAND flash chip state + */ +enum { + FL_READY, + FL_READING, + FL_WRITING, + FL_ERASING, + FL_SYNCING, + FL_CACHEDPRG, + FL_RESETING, + FL_UNLOCKING, + FL_LOCKING, + FL_PM_SUSPENDED, +}; + /* If the erase fails, fail_addr might indicate exactly which block failed. If fail_addr = 0xffffffff, the failure was not at the device level or was not specific to any particular block. */ diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 2993a89..7ac72de 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -213,20 +213,6 @@ typedef enum { #define NAND_CI_CHIPNR_MSK 0x03 #define NAND_CI_CELLTYPE_MSK 0x0C -/* - * nand_state_t - chip states - * Enumeration for NAND flash chip state - */ -typedef enum { - FL_READY, - FL_READING, - FL_WRITING, - FL_ERASING, - FL_SYNCING, - FL_CACHEDPRG, - FL_PM_SUSPENDED, -} nand_state_t; - /* Keep gcc happy */ struct nand_chip; @@ -416,7 +402,7 @@ struct nand_chip { uint8_t cellinfo; int badblockpos; - nand_state_t state; + int state; uint8_t *oob_poi; struct nand_hw_control *controller; diff --git a/include/linux/mtd/nand_legacy.h b/include/linux/mtd/nand_legacy.h index 4494bc5..99eafbb 100644 --- a/include/linux/mtd/nand_legacy.h +++ b/include/linux/mtd/nand_legacy.h @@ -55,18 +55,6 @@ #define NAND_CMD_RESET 0xff /* - * Enumeration for NAND flash chip state - */ -typedef enum { - FL_READY, - FL_READING, - FL_WRITING, - FL_ERASING, - FL_SYNCING -} nand_state_t; - - -/* * NAND Private Flash Chip Data * * Structure overview: diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h index 4b0c2df..8a0fd0d 100644 --- a/include/linux/mtd/onenand.h +++ b/include/linux/mtd/onenand.h @@ -17,6 +17,7 @@ /* Note: The header order is impoertant */ #include <onenand_uboot.h> +#include <linux/mtd/compat.h> #include <linux/mtd/bbm.h> #define MAX_BUFFERRAM 2 @@ -28,20 +29,6 @@ extern int onenand_scan (struct mtd_info *mtd, int max_chips); extern void onenand_release (struct mtd_info *mtd); /** - * onenand_state_t - chip states - * Enumeration for OneNAND flash chip state - */ -typedef enum { - FL_READY, - FL_READING, - FL_WRITING, - FL_ERASING, - FL_SYNCING, - FL_UNLOCKING, - FL_LOCKING, -} onenand_state_t; - -/** * struct onenand_bufferram - OneNAND BufferRAM Data * @param block block address in BufferRAM * @param page page address in BufferRAM @@ -103,10 +90,12 @@ struct onenand_chip { unsigned short (*read_word) (void __iomem * addr); void (*write_word) (unsigned short value, void __iomem * addr); void (*mmcontrol) (struct mtd_info * mtd, int sync_read); + int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); + int (*scan_bbt)(struct mtd_info *mtd); spinlock_t chip_lock; wait_queue_head_t wq; - onenand_state_t state; + int state; struct nand_oobinfo *autooob; |