[PATCH 06/25] pxa3xx_nand: unify prepare command

Eric Miao eric.y.miao at gmail.com
Fri Jun 18 02:52:34 EDT 2010


On Fri, Jun 18, 2010 at 1:34 PM, Haojian Zhuang
<haojian.zhuang at gmail.com> wrote:
> From ac05ddc3c13d2b80b243e91cba9922572841f34a Mon Sep 17 00:00:00 2001
> From: Lei Wen <leiwen at marvell.com>
> Date: Mon, 22 Mar 2010 12:04:22 +0800
> Subject: [PATCH 06/25] pxa3xx_nand: unify prepare command
>
> Make the interface simpler which could make both debug
> and enhancement easier.

What is the benefit of combining them into one big several pages lengthy
function? I dislike lengthy function :-/

>
> Signed-off-by: Lei Wen <leiwen at marvell.com>
> Signed-off-by: Haojian Zhuang <haojian.zhuang at marvell.com>
> ---
>  drivers/mtd/nand/pxa3xx_nand.c |  256 +++++++++++++++++++++-------------------
>  1 files changed, 136 insertions(+), 120 deletions(-)
>
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index 753346f..9ab292b 100644
> --- a/drivers/mtd/nand/pxa3xx_nand.c
> +++ b/drivers/mtd/nand/pxa3xx_nand.c
> @@ -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 */
> @@ -78,6 +79,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)
> @@ -340,7 +342,7 @@ static void pxa3xx_nand_start(struct pxa3xx_nand_info *info)
>        uint32_t ndcr;
>
>        ndcr = info->reg_ndcr;
> -       ndcr |= NDCR_ECC_EN;
> +       ndcr |= info->use_ecc ? NDCR_ECC_EN : 0;
>        ndcr |= info->use_dma ? NDCR_DMA_EN : NDCR_STOP_ON_UNCOR;
>        ndcr |= NDCR_ND_RUN;
>
> @@ -369,61 +371,6 @@ static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info)
>        }
>  }
>
> -static void prepare_read_prog_cmd(struct pxa3xx_nand_info *info,
> -               uint16_t cmd, int column, int page_addr)
> -{
> -       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)
> -{
> -       info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
> -       info->ndcb1 = 0;
> -       info->ndcb2 = 0;
> -
> -       if (cmd == cmdset.read_id) {
> -               info->ndcb0 |= NDCB0_CMD_TYPE(3);
> -               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);
> -       }
> -}
> -
>  static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
>  {
>        uint32_t ndcr;
> @@ -561,94 +508,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;
> -       int ret, exec_cmd = 0;
> +       uint16_t cmd;
> +       int addr_cycle, exec_cmd, ndcb0;
> +       struct mtd_info *mtd = info->mtd;
>
> -       info->use_dma = (use_dma) ? 1 : 0;
> -       info->use_ecc = 0;
> -       info->data_size = 0;
> -       info->state = 0;
> +       ndcb0 = 0;
> +       addr_cycle = 0;
> +       exec_cmd = 1;
> +
> +       /* 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;
>
>        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);
> +               pxa3xx_set_datasize(info);
> +               break;
> +       case NAND_CMD_SEQIN:
> +               exec_cmd = 0;
> +               break;
> +       default:
> +               info->ndcb1 = 0;
> +               info->ndcb2 = 0;
> +               break;
> +       }
>
> -               prepare_read_prog_cmd(info, cmdset.read1, column, page_addr);
> +       info->ndcb0 = ndcb0;
> +       addr_cycle = NDCB0_ADDR_CYC(info->row_addr_cycles
> +                       + info->col_addr_cycles);
>
> -               /* We only are OOB, so if the data has error, does not matter */
> -               if (info->retcode == ERR_DBERR)
> -                       info->retcode = ERR_NONE;
> +       switch (command) {
> +       case NAND_CMD_READOOB:
> +       case NAND_CMD_READ0:
>
> -               exec_cmd = 1;
> -               break;
> +               cmd  = cmdset.read1;
> +               if (command == NAND_CMD_READOOB)
> +                       info->buf_start = mtd->writesize + column;
> +               else
> +                       info->buf_start = column;
>
> -       case NAND_CMD_READ0:
> -               info->use_ecc = 1;
> -               info->retcode = ERR_NONE;
> -               info->buf_start = column;
> -               info->buf_count = mtd->writesize + mtd->oobsize;
> -               memset(info->data_buff, 0xFF, info->buf_count);
> +               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);
> -               if (info->retcode == ERR_DBERR) {
> -                       /* for blank page (all 0xff), HW will calculate its ECC as
> -                        * 0, which is different from the ECC information within
> -                        * OOB, ignore such double bit errors
> -                        */
> -                       if (is_buf_blank(info->data_buff, mtd->writesize))
> -                               info->retcode = ERR_NONE;
> +       case NAND_CMD_SEQIN:
> +               /* 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;
>                }
>
> -               exec_cmd = 1;
> -               break;
> -       case NAND_CMD_SEQIN:
> -               info->buf_start = column;
>                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);
> +               cmd = cmdset.program;
>                info->state |= STATE_IS_WRITE;
> -               exec_cmd = 1;
> -               break;
> -       case NAND_CMD_ERASE1:
> -               prepare_erase_cmd(info, cmdset.erase, page_addr);
> -               exec_cmd = 1;
> -       case NAND_CMD_ERASE2:
> +               info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
> +                               | NDCB0_AUTO_RS
> +                               | NDCB0_ST_ROW_EN
> +                               | NDCB0_DBC
> +                               | cmd
> +                               | addr_cycle;
>                break;
> +
>        case NAND_CMD_READID:
> +               cmd = 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 = 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 = 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 = 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);
>                info->state |= STATE_CMD_PREPARED;
> @@ -663,10 +683,6 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info
> *mtd, unsigned command,
>                pxa3xx_nand_stop(info);
>                disable_int(info, NDCR_INT_MASK);
>                info->state &= ~STATE_CMD_PREPARED;
> -               if (info->retcode == ERR_DBERR) {
> -                       printk(KERN_ERR "double bit error @ page %08x\n", page_addr);
> -                       info->retcode = ERR_NONE;
> -               }
>        }
>  }
>
> --
> 1.7.0.4
>


More information about the linux-arm-kernel mailing list