]> git.ipfire.org Git - people/ms/u-boot.git/commitdiff
Merge branch 'master' of git://git.denx.de/u-boot-nand-flash
authorWolfgang Denk <wd@denx.de>
Thu, 14 Aug 2008 09:26:22 +0000 (11:26 +0200)
committerWolfgang Denk <wd@denx.de>
Thu, 14 Aug 2008 09:26:22 +0000 (11:26 +0200)
1  2 
cpu/arm920t/s3c24x0/nand.c
drivers/mtd/onenand/onenand_base.c
drivers/mtd/onenand/onenand_bbt.c
include/linux/mtd/nand_legacy.h

index 14882cb24382390220adf9d39b33e29f48e938ba,9d63243223a4b39c77de8845d5c508842753def2..60174fb4d2b8716f2ca45f2c3064000fb1f9ad6a
  #endif
  
  #if defined(CONFIG_CMD_NAND)
 -#if !defined(CFG_NAND_LEGACY)
 +#if !defined(CONFIG_NAND_LEGACY)
  
  #include <nand.h>
  #include <s3c2410.h>
+ #include <asm/io.h>
  
  #define __REGb(x)     (*(volatile unsigned char *)(x))
  #define __REGi(x)     (*(volatile unsigned int *)(x))
  #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 +93,7 @@@
  #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", mtdmode);
        NFCONF |= S3C2410_NFCONF_INITECC;
  }
  
@@@ -143,23 -143,23 +143,23 @@@ int board_nand_init(struct nand_chip *n
        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
index 7c9438be316b71b876a5763fe6eeca681559f7ad,eaa48f94873887fdb472ef7d118b21d1d810d7fd..8f12fa26e062cf670b36163ba3c6ffb1a16a90e9
@@@ -10,6 -10,9 +10,6 @@@
   */
  
  #include <common.h>
 -
 -#ifdef CONFIG_CMD_ONENAND
 -
  #include <linux/mtd/compat.h>
  #include <linux/mtd/mtd.h>
  #include <linux/mtd/onenand.h>
@@@ -328,7 -331,7 +328,7 @@@ static inline int onenand_bufferram_off
  
        if (ONENAND_CURRENT_BUFFERRAM(this)) {
                if (area == ONENAND_DATARAM)
-                       return mtd->oobblock;
+                       return mtd->writesize;
                if (area == ONENAND_SPARERAM)
                        return mtd->oobsize;
        }
@@@ -478,6 -481,30 +478,30 @@@ static int onenand_update_bufferram(str
        return 0;
  }
  
+ /**
+  * 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
@@@ -538,15 -565,15 +562,15 @@@ static int onenand_read_ecc(struct mtd_
        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 -688,7 +685,7 @@@ int onenand_read_oob(struct mtd_info *m
                /* Read more? */
                if (read < len) {
                        /* Page size */
-                       from += mtd->oobblock;
+                       from += mtd->writesize;
                        column = 0;
                }
        }
@@@ -688,7 -715,7 +712,7 @@@ static int onenand_verify_page(struct m
        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)
  
        /* 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;
  #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 -784,15 +781,15 @@@ static int onenand_write_ecc(struct mtd
  
        /* 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);
  
@@@ -889,6 -916,25 +913,25 @@@ int onenand_write_oob(struct mtd_info *
        return 0;
  }
  
+ /**
+  * 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
@@@ -947,6 -993,8 +990,8 @@@ int onenand_erase(struct mtd_info *mtd
  
                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 -1050,45 +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 -1244,8 +1241,8 @@@ static int onenand_probe(struct mtd_inf
        /* 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);
  
        /* 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 */
  
                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;
@@@ -1301,3 -1361,5 +1358,3 @@@ int onenand_scan(struct mtd_info *mtd, 
  void onenand_release(struct mtd_info *mtd)
  {
  }
 -
 -#endif /* CONFIG_CMD_ONENAND */
index 0abaa1ab38ca8a093d0bad3caeae1e8b6f4a7a0e,318d877bfbbd99bfe4080f341c4c38f68b8d1582..d13d2777e200e5c2b58dd77ec4b3882dc5260eb5
@@@ -15,6 -15,9 +15,6 @@@
   */
  
  #include <common.h>
 -
 -#ifdef CONFIG_CMD_ONENAND
 -
  #include <linux/mtd/compat.h>
  #include <linux/mtd/mtd.h>
  #include <linux/mtd/onenand.h>
@@@ -94,7 -97,7 +94,7 @@@ static int create_bbt(struct mtd_info *
                        /* 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]);
  
                        }
  
                        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,
@@@ -258,3 -261,5 +258,3 @@@ int onenand_default_bbt(struct mtd_inf
  
        return onenand_scan_bbt(mtd, bbm->badblock_pattern);
  }
 -
 -#endif /* CFG_CMD_ONENAND */
index 4494bc569d955e5d8238dc41caa289587cee4888,bb66e4547017265be04e2b6a90127bf579c5643b..99eafbbcdccde31e808984ac746adc33bda5edb9
@@@ -36,7 -36,7 +36,7 @@@
  #ifndef __LINUX_MTD_NAND_LEGACY_H
  #define __LINUX_MTD_NAND_LEGACY_H
  
 -#ifndef CFG_NAND_LEGACY
 +#ifndef CONFIG_NAND_LEGACY
  #error This module is for the legacy NAND support
  #endif
  
  #define NAND_CMD_ERASE2               0xd0
  #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
   *