mtd: pxa3xx_nand: unify prepare command
authorLei Wen <leiwen@marvell.com>
Mon, 28 Feb 2011 02:32:13 +0000 (10:32 +0800)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Fri, 11 Mar 2011 14:22:50 +0000 (14:22 +0000)
Make the interface simpler which could make both debug
and enhancement easier.

Signed-off-by: Lei Wen <leiwen@marvell.com>
Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
drivers/mtd/nand/pxa3xx_nand.c

index be0aa44..de0a2a2 100644 (file)
@@ -28,6 +28,7 @@
 
 #define        CHIP_DELAY_TIMEOUT      (2 * HZ/10)
 #define NAND_STOP_DELAY                (2 * HZ/50)
+#define PAGE_CHUNK_SIZE                (2048)
 
 /* registers and bit definitions */
 #define NDCR           (0x00) /* Control register */
@@ -77,6 +78,7 @@
 #define NDSR_RDDREQ            (0x1 << 1)
 #define NDSR_WRCMDREQ          (0x1)
 
+#define NDCB0_ST_ROW_EN         (0x1 << 26)
 #define NDCB0_AUTO_RS          (0x1 << 25)
 #define NDCB0_CSEL             (0x1 << 24)
 #define NDCB0_CMD_TYPE_MASK    (0x7 << 21)
@@ -319,66 +321,6 @@ static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info)
        nand_writel(info, NDSR, NDSR_MASK);
 }
 
-static void prepare_read_prog_cmd(struct pxa3xx_nand_info *info,
-               uint16_t cmd, int column, int page_addr)
-{
-       const struct pxa3xx_nand_cmdset *cmdset = info->cmdset;
-       pxa3xx_set_datasize(info);
-
-       /* generate values for NDCBx registers */
-       info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
-       info->ndcb1 = 0;
-       info->ndcb2 = 0;
-       info->ndcb0 |= NDCB0_ADDR_CYC(info->row_addr_cycles + info->col_addr_cycles);
-
-       if (info->col_addr_cycles == 2) {
-               /* large block, 2 cycles for column address
-                * row address starts from 3rd cycle
-                */
-               info->ndcb1 |= page_addr << 16;
-               if (info->row_addr_cycles == 3)
-                       info->ndcb2 = (page_addr >> 16) & 0xff;
-       } else
-               /* small block, 1 cycles for column address
-                * row address starts from 2nd cycle
-                */
-               info->ndcb1 = page_addr << 8;
-
-       if (cmd == cmdset->program)
-               info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS;
-}
-
-static void prepare_erase_cmd(struct pxa3xx_nand_info *info,
-                       uint16_t cmd, int page_addr)
-{
-       info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
-       info->ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS | NDCB0_ADDR_CYC(3);
-       info->ndcb1 = page_addr;
-       info->ndcb2 = 0;
-}
-
-static void prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd)
-{
-       const struct pxa3xx_nand_cmdset *cmdset = info->cmdset;
-
-       info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
-       info->ndcb1 = 0;
-       info->ndcb2 = 0;
-
-       info->oob_size = 0;
-       if (cmd == cmdset->read_id) {
-               info->ndcb0 |= NDCB0_CMD_TYPE(3) | NDCB0_ADDR_CYC(1);
-               info->data_size = 8;
-       } else if (cmd == cmdset->read_status) {
-               info->ndcb0 |= NDCB0_CMD_TYPE(4);
-               info->data_size = 8;
-       } else if (cmd == cmdset->reset || cmd == cmdset->lock ||
-                  cmd == cmdset->unlock) {
-               info->ndcb0 |= NDCB0_CMD_TYPE(5);
-       } else
-               BUG();
-}
-
 static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
 {
        uint32_t ndcr;
@@ -529,81 +471,167 @@ static inline int is_buf_blank(uint8_t *buf, size_t len)
        return 1;
 }
 
-static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
-                               int column, int page_addr)
+static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
+               uint16_t column, int page_addr)
 {
-       struct pxa3xx_nand_info *info = mtd->priv;
-       const struct pxa3xx_nand_cmdset *cmdset = info->cmdset;
-       int ret, exec_cmd = 0;
+       uint16_t cmd;
+       int addr_cycle, exec_cmd, ndcb0;
+       struct mtd_info *mtd = info->mtd;
+
+       ndcb0 = 0;
+       addr_cycle = 0;
+       exec_cmd = 1;
 
-       info->use_dma = (use_dma) ? 1 : 0;
-       info->use_ecc = 0;
-       info->data_size = 0;
-       info->state = 0;
-       info->retcode = ERR_NONE;
+       /* reset data and oob column point to handle data */
+       info->buf_start = 0;
+       info->buf_count = 0;
+       info->oob_size          = 0;
+       info->use_ecc           = 0;
+       info->retcode           = ERR_NONE;
 
        switch (command) {
+       case NAND_CMD_READ0:
+       case NAND_CMD_PAGEPROG:
+               info->use_ecc = 1;
        case NAND_CMD_READOOB:
-               /* disable HW ECC to get all the OOB data */
-               info->buf_count = mtd->writesize + mtd->oobsize;
-               info->buf_start = mtd->writesize + column;
-               memset(info->data_buff, 0xFF, info->buf_count);
-
-               prepare_read_prog_cmd(info, cmdset->read1, column, page_addr);
-               exec_cmd = 1;
+               pxa3xx_set_datasize(info);
+               break;
+       case NAND_CMD_SEQIN:
+               exec_cmd = 0;
+               break;
+       default:
+               info->ndcb1 = 0;
+               info->ndcb2 = 0;
                break;
+       }
+
+       info->ndcb0 = ndcb0;
+       addr_cycle = NDCB0_ADDR_CYC(info->row_addr_cycles
+                                   + info->col_addr_cycles);
 
+       switch (command) {
+       case NAND_CMD_READOOB:
        case NAND_CMD_READ0:
-               info->use_ecc = 1;
-               info->buf_start = column;
-               info->buf_count = mtd->writesize + mtd->oobsize;
-               memset(info->data_buff, 0xFF, info->buf_count);
+               cmd = info->cmdset->read1;
+               if (command == NAND_CMD_READOOB)
+                       info->buf_start = mtd->writesize + column;
+               else
+                       info->buf_start = column;
+
+               if (unlikely(info->page_size < PAGE_CHUNK_SIZE))
+                       info->ndcb0 |= NDCB0_CMD_TYPE(0)
+                                       | addr_cycle
+                                       | (cmd & NDCB0_CMD1_MASK);
+               else
+                       info->ndcb0 |= NDCB0_CMD_TYPE(0)
+                                       | NDCB0_DBC
+                                       | addr_cycle
+                                       | cmd;
 
-               prepare_read_prog_cmd(info, cmdset->read1, column, page_addr);
-               exec_cmd = 1;
-               break;
        case NAND_CMD_SEQIN:
-               info->buf_start = column;
+               /* small page addr setting */
+               if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) {
+                       info->ndcb1 = ((page_addr & 0xFFFFFF) << 8)
+                                       | (column & 0xFF);
+
+                       info->ndcb2 = 0;
+               } else {
+                       info->ndcb1 = ((page_addr & 0xFFFF) << 16)
+                                       | (column & 0xFFFF);
+
+                       if (page_addr & 0xFF0000)
+                               info->ndcb2 = (page_addr & 0xFF0000) >> 16;
+                       else
+                               info->ndcb2 = 0;
+               }
+
                info->buf_count = mtd->writesize + mtd->oobsize;
-               memset(info->data_buff, 0xff, info->buf_count);
+               memset(info->data_buff, 0xFF, info->buf_count);
 
-               /* save column/page_addr for next CMD_PAGEPROG */
-               info->seqin_column = column;
-               info->seqin_page_addr = page_addr;
                break;
+
        case NAND_CMD_PAGEPROG:
-               info->use_ecc = (info->seqin_column >= mtd->writesize) ? 0 : 1;
+               if (is_buf_blank(info->data_buff,
+                                       (mtd->writesize + mtd->oobsize))) {
+                       exec_cmd = 0;
+                       break;
+               }
 
-               prepare_read_prog_cmd(info, cmdset->program,
-                               info->seqin_column, info->seqin_page_addr);
-               exec_cmd = 1;
-               break;
-       case NAND_CMD_ERASE1:
-               prepare_erase_cmd(info, cmdset->erase, page_addr);
-               exec_cmd = 1;
-               break;
-       case NAND_CMD_ERASE2:
+               cmd = info->cmdset->program;
+               info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
+                               | NDCB0_AUTO_RS
+                               | NDCB0_ST_ROW_EN
+                               | NDCB0_DBC
+                               | cmd
+                               | addr_cycle;
                break;
+
        case NAND_CMD_READID:
+               cmd = info->cmdset->read_id;
+               info->buf_count = info->read_id_bytes;
+               info->ndcb0 |= NDCB0_CMD_TYPE(3)
+                               | NDCB0_ADDR_CYC(1)
+                               | cmd;
+
+               info->data_size = 8;
+               break;
        case NAND_CMD_STATUS:
-               info->use_dma = 0;      /* force PIO read */
-               info->buf_start = 0;
-               info->buf_count = (command == NAND_CMD_READID) ?
-                               info->read_id_bytes : 1;
-
-               prepare_other_cmd(info, (command == NAND_CMD_READID) ?
-                               cmdset->read_id : cmdset->read_status);
-               exec_cmd = 1;
+               cmd = info->cmdset->read_status;
+               info->buf_count = 1;
+               info->ndcb0 |= NDCB0_CMD_TYPE(4)
+                               | NDCB0_ADDR_CYC(1)
+                               | cmd;
+
+               info->data_size = 8;
+               break;
+
+       case NAND_CMD_ERASE1:
+               cmd = info->cmdset->erase;
+               info->ndcb0 |= NDCB0_CMD_TYPE(2)
+                               | NDCB0_AUTO_RS
+                               | NDCB0_ADDR_CYC(3)
+                               | NDCB0_DBC
+                               | cmd;
+               info->ndcb1 = page_addr;
+               info->ndcb2 = 0;
+
                break;
        case NAND_CMD_RESET:
-               prepare_other_cmd(info, cmdset->reset);
-               exec_cmd = 1;
+               cmd = info->cmdset->reset;
+               info->ndcb0 |= NDCB0_CMD_TYPE(5)
+                               | cmd;
+
+               break;
+
+       case NAND_CMD_ERASE2:
+               exec_cmd = 0;
                break;
+
        default:
-               printk(KERN_ERR "non-supported command.\n");
+               exec_cmd = 0;
+               printk(KERN_ERR "pxa3xx-nand: non-supported"
+                       " command %x\n", command);
                break;
        }
 
+       return exec_cmd;
+}
+
+static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
+                               int column, int page_addr)
+{
+       struct pxa3xx_nand_info *info = mtd->priv;
+       int ret, exec_cmd;
+
+       /*
+        * if this is a x16 device ,then convert the input
+        * "byte" address into a "word" address appropriate
+        * for indexing a word-oriented device
+        */
+       if (info->reg_ndcr & NDCR_DWIDTH_M)
+               column /= 2;
+
+       exec_cmd = prepare_command_pool(info, command, column, page_addr);
        if (exec_cmd) {
                init_completion(&info->cmd_complete);
                pxa3xx_nand_start(info);
@@ -919,6 +947,7 @@ static void pxa3xx_nand_init_mtd(struct mtd_info *mtd,
        struct nand_chip *this = &info->nand_chip;
 
        this->options = (info->reg_ndcr & NDCR_DWIDTH_C) ? NAND_BUSWIDTH_16: 0;
+       this->options |= NAND_NO_AUTOINCR;
 
        this->waitfunc          = pxa3xx_nand_waitfunc;
        this->select_chip       = pxa3xx_nand_select_chip;