[PATCH] MTD: pxa3xx_nand: enable multiple chip select support

Daniel Mack zonque at gmail.com
Wed Jun 22 07:39:33 EDT 2011


On Wed, Jun 22, 2011 at 5:17 AM, Lei Wen <leiwen at marvell.com> wrote:
> Current pxa3xx_nand controller has two chip select which
> both be workable. This patch enable this feature.
>
> Update platform driver to support this feature.
>
> Another notice should be taken that:
> When you want to use this feature, you should not enable the
> keep configuration feature, for two chip select could be
> attached with different nand chip. The different page size
> and timing requirement make the keep configuration impossible.
>
> Signed-off-by: Lei Wen <leiwen at marvell.com>
> ---
>  arch/arm/mach-mmp/aspenite.c                 |    5 +-
>  arch/arm/mach-pxa/cm-x300.c                  |    5 +-
>  arch/arm/mach-pxa/colibri-pxa3xx.c           |    5 +-
>  arch/arm/mach-pxa/littleton.c                |    5 +-
>  arch/arm/mach-pxa/mxm8x10.c                  |    9 +-
>  arch/arm/mach-pxa/raumfeld.c                 |    5 +-
>  arch/arm/mach-pxa/zylonite.c                 |    5 +-
>  arch/arm/plat-pxa/include/plat/pxa3xx_nand.h |    8 +-
>  drivers/mtd/nand/pxa3xx_nand.c               |  735 +++++++++++++++-----------
>  9 files changed, 444 insertions(+), 338 deletions(-)

This patch doesn't apply for me on top of Linus' master branch. Which
tree are you based on currently?

[...]

> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index 30689cc..259b8d5 100644
> --- a/drivers/mtd/nand/pxa3xx_nand.c
> +++ b/drivers/mtd/nand/pxa3xx_nand.c
> @@ -92,11 +92,13 @@
>  #define NDCB0_ADDR_CYC_SHIFT   (16)
>
>  /* macros for registers read/write */
> -#define nand_writel(info, off, val)    \
> -       __raw_writel((val), (info)->mmio_base + (off))
> +#define nand_writel(nand, off, val)    \
> +       __raw_writel((val), (nand)->mmio_base + (off))
>
> -#define nand_readl(info, off)          \
> -       __raw_readl((info)->mmio_base + (off))
> +#define nand_readl(nand, off)          \
> +       __raw_readl((nand)->mmio_base + (off))
> +#define get_mtd_by_info(info)          \
> +       (struct mtd_info *)((void *)info - sizeof(struct mtd_info))
>
>  /* error code and state */
>  enum {
> @@ -110,6 +112,7 @@ enum {
>
>  enum {
>        STATE_IDLE = 0,
> +       STATE_PREPARED,
>        STATE_CMD_HANDLE,
>        STATE_DMA_READING,
>        STATE_DMA_WRITING,
> @@ -123,63 +126,63 @@ enum {
>  struct pxa3xx_nand_info {
>        struct nand_chip        nand_chip;
>
> -       struct nand_hw_control  controller;
> -       struct platform_device   *pdev;
>        struct pxa3xx_nand_cmdset *cmdset;
> +       /* page size of attached chip */
> +       uint16_t                page_size;
> +       uint8_t                 chip_select;
> +       uint8_t                 use_ecc;
> +
> +       /* calculated from pxa3xx_nand_flash data */
> +       uint8_t                 col_addr_cycles;
> +       uint8_t                 row_addr_cycles;
> +       uint8_t                 read_id_bytes;
> +
> +       /* cached register value */
> +       uint32_t                reg_ndcr;
> +       uint32_t                ndtr0cs0;
> +       uint32_t                ndtr1cs0;
>
> +       void                    *nand_data;
> +};
> +
> +struct pxa3xx_nand {
>        struct clk              *clk;
>        void __iomem            *mmio_base;
>        unsigned long           mmio_phys;
> +       struct nand_hw_control  controller;
> +       struct completion       cmd_complete;
> +       struct platform_device   *pdev;
>
> -       unsigned int            buf_start;
> -       unsigned int            buf_count;
> -
> -       struct mtd_info         *mtd;
>        /* DMA information */
>        int                     drcmr_dat;
>        int                     drcmr_cmd;
> -
> -       unsigned char           *data_buff;
> -       unsigned char           *oob_buff;
> -       dma_addr_t              data_buff_phys;
> -       size_t                  data_buff_size;
>        int                     data_dma_ch;
> -       struct pxa_dma_desc     *data_desc;
> +       dma_addr_t              data_buff_phys;
>        dma_addr_t              data_desc_addr;
> +       struct pxa_dma_desc     *data_desc;
>
> -       uint32_t                reg_ndcr;
> -
> -       /* saved column/page_addr during CMD_SEQIN */
> -       int                     seqin_column;
> -       int                     seqin_page_addr;
> +       struct pxa3xx_nand_info *info[NUM_CHIP_SELECT];
> +       uint32_t                command;
> +       uint16_t                data_size;      /* data size in FIFO */
> +       uint16_t                oob_size;
> +       unsigned char           *data_buff;
> +       unsigned char           *oob_buff;
> +       uint32_t                buf_start;
> +       uint32_t                buf_count;
>
>        /* relate to the command */
>        unsigned int            state;
> -
> +       uint8_t                 chip_select;
>        int                     use_ecc;        /* use HW ECC ? */
>        int                     use_dma;        /* use DMA ? */
>        int                     is_ready;
> -
> -       unsigned int            page_size;      /* page size of attached chip */
> -       unsigned int            data_size;      /* data size in FIFO */
>        int                     retcode;
> -       struct completion       cmd_complete;
>
>        /* generated NDCBx register values */
> +       uint8_t                 total_cmds;
>        uint32_t                ndcb0;
>        uint32_t                ndcb1;
>        uint32_t                ndcb2;
> -
> -       /* timing calcuted from setting */
> -       uint32_t                ndtr0cs0;
> -       uint32_t                ndtr1cs0;
> -
> -       /* calculated from pxa3xx_nand_flash data */
> -       size_t          oob_size;
> -       size_t          read_id_bytes;
> -
> -       unsigned int    col_addr_cycles;
> -       unsigned int    row_addr_cycles;
>  };
>
>  static int use_dma = 1;
> @@ -225,7 +228,7 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = {
>  /* Define a default flash type setting serve as flash detecting only */
>  #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0])
>
> -const char *mtd_names[] = {"pxa3xx_nand-0", NULL};
> +const char *mtd_names[] = {"pxa3xx_nand-0", "pxa3xx_nand-1", NULL};
>
>  #define NDTR0_tCH(c)   (min((c), 7) << 19)
>  #define NDTR0_tCS(c)   (min((c), 7) << 16)
> @@ -244,9 +247,11 @@ const char *mtd_names[] = {"pxa3xx_nand-0", NULL};
>  static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info,
>                                   const struct pxa3xx_nand_timing *t)
>  {
> -       unsigned long nand_clk = clk_get_rate(info->clk);
> +       struct pxa3xx_nand *nand = info->nand_data;
> +       unsigned long nand_clk;
>        uint32_t ndtr0, ndtr1;
>
> +       nand_clk = clk_get_rate(nand->clk);
>        ndtr0 = NDTR0_tCH(ns2cycle(t->tCH, nand_clk)) |
>                NDTR0_tCS(ns2cycle(t->tCS, nand_clk)) |
>                NDTR0_tWH(ns2cycle(t->tWH, nand_clk)) |
> @@ -260,26 +265,27 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info,
>
>        info->ndtr0cs0 = ndtr0;
>        info->ndtr1cs0 = ndtr1;
> -       nand_writel(info, NDTR0CS0, ndtr0);
> -       nand_writel(info, NDTR1CS0, ndtr1);
> +       nand_writel(nand, NDTR0CS0, ndtr0);
> +       nand_writel(nand, NDTR1CS0, ndtr1);
>  }
>
>  static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
>  {
> +       struct pxa3xx_nand *nand = info->nand_data;
>        int oob_enable = info->reg_ndcr & NDCR_SPARE_EN;
>
> -       info->data_size = info->page_size;
> +       nand->data_size = info->page_size;
>        if (!oob_enable) {
> -               info->oob_size = 0;
> +               nand->oob_size = 0;
>                return;
>        }
>
>        switch (info->page_size) {
>        case 2048:
> -               info->oob_size = (info->use_ecc) ? 40 : 64;
> +               nand->oob_size = (info->use_ecc) ? 40 : 64;
>                break;
>        case 512:
> -               info->oob_size = (info->use_ecc) ? 8 : 16;
> +               nand->oob_size = (info->use_ecc) ? 8 : 16;
>                break;
>        }
>  }
> @@ -290,185 +296,189 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
>  * We enable all the interrupt at the same time, and
>  * let pxa3xx_nand_irq to handle all logic.
>  */
> -static void pxa3xx_nand_start(struct pxa3xx_nand_info *info)
> +static void pxa3xx_nand_start(struct pxa3xx_nand *nand)
>  {
> +       struct pxa3xx_nand_info *info;
>        uint32_t ndcr;
>
> +       info = nand->info[nand->chip_select];
>        ndcr = info->reg_ndcr;
> -       ndcr |= info->use_ecc ? NDCR_ECC_EN : 0;
> -       ndcr |= info->use_dma ? NDCR_DMA_EN : 0;
> +       ndcr |= nand->use_ecc ? NDCR_ECC_EN : 0;
> +       ndcr |= nand->use_dma ? NDCR_DMA_EN : 0;
>        ndcr |= NDCR_ND_RUN;
>
>        /* clear status bits and run */
> -       nand_writel(info, NDCR, 0);
> -       nand_writel(info, NDSR, NDSR_MASK);
> -       nand_writel(info, NDCR, ndcr);
> +       nand_writel(nand, NDCR, 0);
> +       nand_writel(nand, NDSR, NDSR_MASK);
> +       nand_writel(nand, NDCR, ndcr);
>  }
>
> -static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info)
> +static void pxa3xx_nand_stop(struct pxa3xx_nand *nand)
>  {
>        uint32_t ndcr;
>        int timeout = NAND_STOP_DELAY;
>
>        /* wait RUN bit in NDCR become 0 */
> -       ndcr = nand_readl(info, NDCR);
> +       ndcr = nand_readl(nand, NDCR);
>        while ((ndcr & NDCR_ND_RUN) && (timeout-- > 0)) {
> -               ndcr = nand_readl(info, NDCR);
> +               ndcr = nand_readl(nand, NDCR);
>                udelay(1);
>        }
>
>        if (timeout <= 0) {
>                ndcr &= ~NDCR_ND_RUN;
> -               nand_writel(info, NDCR, ndcr);
> +               nand_writel(nand, NDCR, ndcr);
>        }
>        /* clear status bits */
> -       nand_writel(info, NDSR, NDSR_MASK);
> +       nand_writel(nand, NDSR, NDSR_MASK);
>  }
>
> -static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
> +static void enable_int(struct pxa3xx_nand *nand, uint32_t int_mask)
>  {
>        uint32_t ndcr;
>
> -       ndcr = nand_readl(info, NDCR);
> -       nand_writel(info, NDCR, ndcr & ~int_mask);
> +       ndcr = nand_readl(nand, NDCR);
> +       nand_writel(nand, NDCR, ndcr & ~int_mask);
>  }
>
> -static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
> +static void disable_int(struct pxa3xx_nand *nand, uint32_t int_mask)
>  {
>        uint32_t ndcr;
>
> -       ndcr = nand_readl(info, NDCR);
> -       nand_writel(info, NDCR, ndcr | int_mask);
> +       ndcr = nand_readl(nand, NDCR);
> +       nand_writel(nand, NDCR, ndcr | int_mask);
>  }
>
> -static void handle_data_pio(struct pxa3xx_nand_info *info)
> +static void handle_data_pio(struct pxa3xx_nand *nand)
>  {
> -       switch (info->state) {
> +       switch (nand->state) {
>        case STATE_PIO_WRITING:
> -               __raw_writesl(info->mmio_base + NDDB, info->data_buff,
> -                               DIV_ROUND_UP(info->data_size, 4));
> -               if (info->oob_size > 0)
> -                       __raw_writesl(info->mmio_base + NDDB, info->oob_buff,
> -                                       DIV_ROUND_UP(info->oob_size, 4));
> +               __raw_writesl(nand->mmio_base + NDDB, nand->data_buff,
> +                               DIV_ROUND_UP(nand->data_size, 4));
> +               if (nand->oob_size > 0)
> +                       __raw_writesl(nand->mmio_base + NDDB, nand->oob_buff,
> +                                       DIV_ROUND_UP(nand->oob_size, 4));
>                break;
>        case STATE_PIO_READING:
> -               __raw_readsl(info->mmio_base + NDDB, info->data_buff,
> -                               DIV_ROUND_UP(info->data_size, 4));
> -               if (info->oob_size > 0)
> -                       __raw_readsl(info->mmio_base + NDDB, info->oob_buff,
> -                                       DIV_ROUND_UP(info->oob_size, 4));
> +               __raw_readsl(nand->mmio_base + NDDB, nand->data_buff,
> +                               DIV_ROUND_UP(nand->data_size, 4));
> +               if (nand->oob_size > 0)
> +                       __raw_readsl(nand->mmio_base + NDDB, nand->oob_buff,
> +                                       DIV_ROUND_UP(nand->oob_size, 4));
>                break;
>        default:
>                printk(KERN_ERR "%s: invalid state %d\n", __func__,
> -                               info->state);
> +                               nand->state);

Can't you use dev_err() here?

>                BUG();

Is crashing the entire kernel really necessary here?

>        }
>  }
>
> -static void start_data_dma(struct pxa3xx_nand_info *info)
> +static void start_data_dma(struct pxa3xx_nand *nand)
>  {
> -       struct pxa_dma_desc *desc = info->data_desc;
> -       int dma_len = ALIGN(info->data_size + info->oob_size, 32);
> +       struct pxa_dma_desc *desc = nand->data_desc;
> +       int dma_len = ALIGN(nand->data_size + nand->oob_size, 32);
>
>        desc->ddadr = DDADR_STOP;
>        desc->dcmd = DCMD_ENDIRQEN | DCMD_WIDTH4 | DCMD_BURST32 | dma_len;
>
> -       switch (info->state) {
> +       switch (nand->state) {
>        case STATE_DMA_WRITING:
> -               desc->dsadr = info->data_buff_phys;
> -               desc->dtadr = info->mmio_phys + NDDB;
> +               desc->dsadr = nand->data_buff_phys;
> +               desc->dtadr = nand->mmio_phys + NDDB;
>                desc->dcmd |= DCMD_INCSRCADDR | DCMD_FLOWTRG;
>                break;
>        case STATE_DMA_READING:
> -               desc->dtadr = info->data_buff_phys;
> -               desc->dsadr = info->mmio_phys + NDDB;
> +               desc->dtadr = nand->data_buff_phys;
> +               desc->dsadr = nand->mmio_phys + NDDB;
>                desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC;
>                break;
>        default:
>                printk(KERN_ERR "%s: invalid state %d\n", __func__,
> -                               info->state);
> +                               nand->state);
>                BUG();
>        }
>
> -       DRCMR(info->drcmr_dat) = DRCMR_MAPVLD | info->data_dma_ch;
> -       DDADR(info->data_dma_ch) = info->data_desc_addr;
> -       DCSR(info->data_dma_ch) |= DCSR_RUN;
> +       DRCMR(nand->drcmr_dat) = DRCMR_MAPVLD | nand->data_dma_ch;
> +       DDADR(nand->data_dma_ch) = nand->data_desc_addr;
> +       DCSR(nand->data_dma_ch) |= DCSR_RUN;
>  }
>
>  static void pxa3xx_nand_data_dma_irq(int channel, void *data)
>  {
> -       struct pxa3xx_nand_info *info = data;
> +       struct pxa3xx_nand *nand = data;
>        uint32_t dcsr;
>
>        dcsr = DCSR(channel);
>        DCSR(channel) = dcsr;
>
>        if (dcsr & DCSR_BUSERR) {
> -               info->retcode = ERR_DMABUSERR;
> +               nand->retcode = ERR_DMABUSERR;
>        }
>
> -       info->state = STATE_DMA_DONE;
> -       enable_int(info, NDCR_INT_MASK);
> -       nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
> +       nand->state = STATE_DMA_DONE;
> +       enable_int(nand, NDCR_INT_MASK);
> +       nand_writel(nand, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
>  }
>
>  static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
>  {
> -       struct pxa3xx_nand_info *info = devid;
> -       unsigned int status, is_completed = 0;
> +       struct pxa3xx_nand *nand = devid;
> +       struct pxa3xx_nand_info *info;
> +       unsigned int status, is_completed = 0, cs;
> +       unsigned int ready, cmd_done, page_done, badblock_detect;
>
> -       status = nand_readl(info, NDSR);
> +       cs              = nand->chip_select;
> +       ready           = (cs) ? NDSR_RDY : NDSR_FLASH_RDY;
> +       cmd_done        = (cs) ? NDSR_CS1_CMDD : NDSR_CS0_CMDD;
> +       page_done       = (cs) ? NDSR_CS1_PAGED : NDSR_CS0_PAGED;
> +       badblock_detect = (cs) ? NDSR_CS1_BBD : NDSR_CS0_BBD;
> +       info            = nand->info[cs];
>
> +       status = nand_readl(nand, NDSR);
>        if (status & NDSR_DBERR)
> -               info->retcode = ERR_DBERR;
> +               nand->retcode = ERR_DBERR;
>        if (status & NDSR_SBERR)
> -               info->retcode = ERR_SBERR;
> +               nand->retcode = ERR_SBERR;
>        if (status & (NDSR_RDDREQ | NDSR_WRDREQ)) {
>                /* whether use dma to transfer data */
> -               if (info->use_dma) {
> -                       disable_int(info, NDCR_INT_MASK);
> -                       info->state = (status & NDSR_RDDREQ) ?
> +               if (nand->use_dma) {
> +                       disable_int(nand, NDCR_INT_MASK);
> +                       nand->state = (status & NDSR_RDDREQ) ?
>                                      STATE_DMA_READING : STATE_DMA_WRITING;
> -                       start_data_dma(info);
> +                       start_data_dma(nand);
>                        goto NORMAL_IRQ_EXIT;
>                } else {
> -                       info->state = (status & NDSR_RDDREQ) ?
> +                       nand->state = (status & NDSR_RDDREQ) ?
>                                      STATE_PIO_READING : STATE_PIO_WRITING;
> -                       handle_data_pio(info);
> +                       handle_data_pio(nand);
>                }
>        }
> -       if (status & NDSR_CS0_CMDD) {
> -               info->state = STATE_CMD_DONE;
> +       if (status & cmd_done) {
> +               nand->state = STATE_CMD_DONE;
>                is_completed = 1;
>        }
> -       if (status & NDSR_FLASH_RDY) {
> -               info->is_ready = 1;
> -               info->state = STATE_READY;
> +       if (status & ready) {
> +               nand->is_ready = 1;
> +               nand->state = STATE_READY;
>        }
>
>        if (status & NDSR_WRCMDREQ) {
> -               nand_writel(info, NDSR, NDSR_WRCMDREQ);
> +               nand_writel(nand, NDSR, NDSR_WRCMDREQ);
>                status &= ~NDSR_WRCMDREQ;
> -               info->state = STATE_CMD_HANDLE;
> -               nand_writel(info, NDCB0, info->ndcb0);
> -               nand_writel(info, NDCB0, info->ndcb1);
> -               nand_writel(info, NDCB0, info->ndcb2);
> +               nand->state = STATE_CMD_HANDLE;
> +               nand_writel(nand, NDCB0, nand->ndcb0);
> +               nand_writel(nand, NDCB0, nand->ndcb1);
> +               nand_writel(nand, NDCB0, nand->ndcb2);
>        }
>
>        /* clear NDSR to let the controller exit the IRQ */
> -       nand_writel(info, NDSR, status);
> +       nand_writel(nand, NDSR, status);
>        if (is_completed)
> -               complete(&info->cmd_complete);
> +               complete(&nand->cmd_complete);
>  NORMAL_IRQ_EXIT:
>        return IRQ_HANDLED;
>  }
>
> -static int pxa3xx_nand_dev_ready(struct mtd_info *mtd)
> -{
> -       struct pxa3xx_nand_info *info = mtd->priv;
> -       return (nand_readl(info, NDSR) & NDSR_RDY) ? 1 : 0;
> -}
> -
>  static inline int is_buf_blank(uint8_t *buf, size_t len)
>  {
>        for (; len > 0; len--)
> @@ -477,42 +487,49 @@ static inline int is_buf_blank(uint8_t *buf, size_t len)
>        return 1;
>  }
>
> -static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
> +static int prepare_command_pool(struct pxa3xx_nand *nand, int command,
>                uint16_t column, int page_addr)
>  {
>        uint16_t cmd;
>        int addr_cycle, exec_cmd, ndcb0;
> -       struct mtd_info *mtd = info->mtd;
> +       struct mtd_info *mtd;
> +       struct pxa3xx_nand_info *info = nand->info[nand->chip_select];
>
> -       ndcb0 = 0;
> +       mtd = get_mtd_by_info(info);
> +       ndcb0 = (nand->chip_select) ? NDCB0_CSEL : 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;
> -       info->is_ready          = 0;
> -       info->retcode           = ERR_NONE;
> +       nand->buf_start         = 0;
> +       nand->buf_count         = 0;
> +       nand->oob_size          = 0;
> +       nand->use_ecc           = 0;
> +       nand->is_ready          = 0;
> +       nand->retcode           = ERR_NONE;
> +       nand->data_size         = 0;
> +       nand->use_dma           = 0;
> +       nand->command           = command;
>
>        switch (command) {
>        case NAND_CMD_READ0:
>        case NAND_CMD_PAGEPROG:
> -               info->use_ecc = 1;
> +               nand->use_ecc = 1;
>        case NAND_CMD_READOOB:
>                pxa3xx_set_datasize(info);
> +               nand->oob_buff = nand->data_buff + nand->data_size;
> +               nand->use_dma = use_dma;
>                break;
>        case NAND_CMD_SEQIN:
>                exec_cmd = 0;
>                break;
>        default:
> -               info->ndcb1 = 0;
> -               info->ndcb2 = 0;
> +               nand->ndcb1 = 0;
> +               nand->ndcb2 = 0;
>                break;
>        }
>
> -       info->ndcb0 = ndcb0;
> +       nand->ndcb0 = ndcb0;
>        addr_cycle = NDCB0_ADDR_CYC(info->row_addr_cycles
>                                    + info->col_addr_cycles);
>
> @@ -521,16 +538,16 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
>        case NAND_CMD_READ0:
>                cmd = info->cmdset->read1;
>                if (command == NAND_CMD_READOOB)
> -                       info->buf_start = mtd->writesize + column;
> +                       nand->buf_start = mtd->writesize + column;
>                else
> -                       info->buf_start = column;
> +                       nand->buf_start = column;
>
>                if (unlikely(info->page_size < PAGE_CHUNK_SIZE))
> -                       info->ndcb0 |= NDCB0_CMD_TYPE(0)
> +                       nand->ndcb0 |= NDCB0_CMD_TYPE(0)
>                                        | addr_cycle
>                                        | (cmd & NDCB0_CMD1_MASK);
>                else
> -                       info->ndcb0 |= NDCB0_CMD_TYPE(0)
> +                       nand->ndcb0 |= NDCB0_CMD_TYPE(0)
>                                        | NDCB0_DBC
>                                        | addr_cycle
>                                        | cmd;
> @@ -538,34 +555,34 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
>        case NAND_CMD_SEQIN:
>                /* small page addr setting */
>                if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) {
> -                       info->ndcb1 = ((page_addr & 0xFFFFFF) << 8)
> +                       nand->ndcb1 = ((page_addr & 0xFFFFFF) << 8)
>                                        | (column & 0xFF);
>
> -                       info->ndcb2 = 0;
> +                       nand->ndcb2 = 0;
>                } else {
> -                       info->ndcb1 = ((page_addr & 0xFFFF) << 16)
> +                       nand->ndcb1 = ((page_addr & 0xFFFF) << 16)
>                                        | (column & 0xFFFF);
>
>                        if (page_addr & 0xFF0000)
> -                               info->ndcb2 = (page_addr & 0xFF0000) >> 16;
> +                               nand->ndcb2 = (page_addr & 0xFF0000) >> 16;
>                        else
> -                               info->ndcb2 = 0;
> +                               nand->ndcb2 = 0;
>                }
>
> -               info->buf_count = mtd->writesize + mtd->oobsize;
> -               memset(info->data_buff, 0xFF, info->buf_count);
> +               nand->buf_count = mtd->writesize + mtd->oobsize;
> +               memset(nand->data_buff, 0xFF, nand->buf_count);
>
>                break;
>
>        case NAND_CMD_PAGEPROG:
> -               if (is_buf_blank(info->data_buff,
> +               if (is_buf_blank(nand->data_buff,
>                                        (mtd->writesize + mtd->oobsize))) {
>                        exec_cmd = 0;
>                        break;
>                }
>
>                cmd = info->cmdset->program;
> -               info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
> +               nand->ndcb0 |= NDCB0_CMD_TYPE(0x1)
>                                | NDCB0_AUTO_RS
>                                | NDCB0_ST_ROW_EN
>                                | NDCB0_DBC
> @@ -575,37 +592,37 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
>
>        case NAND_CMD_READID:
>                cmd = info->cmdset->read_id;
> -               info->buf_count = info->read_id_bytes;
> -               info->ndcb0 |= NDCB0_CMD_TYPE(3)
> +               nand->buf_count = info->read_id_bytes;
> +               nand->ndcb0 |= NDCB0_CMD_TYPE(3)
>                                | NDCB0_ADDR_CYC(1)
>                                | cmd;
>
> -               info->data_size = 8;
> +               nand->data_size = 8;
>                break;
>        case NAND_CMD_STATUS:
>                cmd = info->cmdset->read_status;
> -               info->buf_count = 1;
> -               info->ndcb0 |= NDCB0_CMD_TYPE(4)
> +               nand->buf_count = 1;
> +               nand->ndcb0 |= NDCB0_CMD_TYPE(4)
>                                | NDCB0_ADDR_CYC(1)
>                                | cmd;
>
> -               info->data_size = 8;
> +               nand->data_size = 8;
>                break;
>
>        case NAND_CMD_ERASE1:
>                cmd = info->cmdset->erase;
> -               info->ndcb0 |= NDCB0_CMD_TYPE(2)
> +               nand->ndcb0 |= NDCB0_CMD_TYPE(2)
>                                | NDCB0_AUTO_RS
>                                | NDCB0_ADDR_CYC(3)
>                                | NDCB0_DBC
>                                | cmd;
> -               info->ndcb1 = page_addr;
> -               info->ndcb2 = 0;
> +               nand->ndcb1 = page_addr;
> +               nand->ndcb2 = 0;
>
>                break;
>        case NAND_CMD_RESET:
>                cmd = info->cmdset->reset;
> -               info->ndcb0 |= NDCB0_CMD_TYPE(5)
> +               nand->ndcb0 |= NDCB0_CMD_TYPE(5)
>                                | cmd;
>
>                break;
> @@ -628,6 +645,7 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
>                                int column, int page_addr)
>  {
>        struct pxa3xx_nand_info *info = mtd->priv;
> +       struct pxa3xx_nand *nand = info->nand_data;
>        int ret, exec_cmd;
>
>        /*
> @@ -638,20 +656,32 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
>        if (info->reg_ndcr & NDCR_DWIDTH_M)
>                column /= 2;
>
> -       exec_cmd = prepare_command_pool(info, command, column, page_addr);
> +       /*
> +        * There may be different NAND chip hooked to
> +        * different chip select, so check whether
> +        * chip select has been changed, if yes, reset the timing
> +        */
> +       if (nand->chip_select != info->chip_select) {
> +               nand->chip_select = info->chip_select;
> +               nand_writel(nand, NDTR0CS0, info->ndtr0cs0);
> +               nand_writel(nand, NDTR1CS0, info->ndtr1cs0);
> +       }
> +
> +       nand->state = STATE_PREPARED;
> +       exec_cmd = prepare_command_pool(nand, command, column, page_addr);
>        if (exec_cmd) {
> -               init_completion(&info->cmd_complete);
> -               pxa3xx_nand_start(info);
> +               init_completion(&nand->cmd_complete);
> +               pxa3xx_nand_start(nand);
>
> -               ret = wait_for_completion_timeout(&info->cmd_complete,
> +               ret = wait_for_completion_timeout(&nand->cmd_complete,
>                                CHIP_DELAY_TIMEOUT);
>                if (!ret) {
>                        printk(KERN_ERR "Wait time out!!!\n");
>                        /* Stop State Machine for next command cycle */
> -                       pxa3xx_nand_stop(info);
> +                       pxa3xx_nand_stop(nand);
>                }
> -               info->state = STATE_IDLE;
>        }
> +       nand->state = STATE_IDLE;
>  }
>
>  static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
> @@ -665,11 +695,12 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
>                struct nand_chip *chip, uint8_t *buf, int page)
>  {
>        struct pxa3xx_nand_info *info = mtd->priv;
> +       struct pxa3xx_nand *nand = info->nand_data;
>
>        chip->read_buf(mtd, buf, mtd->writesize);
>        chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
>
> -       if (info->retcode == ERR_SBERR) {
> +       if (nand->retcode == ERR_SBERR) {
>                switch (info->use_ecc) {
>                case 1:
>                        mtd->ecc_stats.corrected++;
> @@ -678,14 +709,14 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
>                default:
>                        break;
>                }
> -       } else if (info->retcode == ERR_DBERR) {
> +       } else if (nand->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(buf, mtd->writesize))
> -                       info->retcode = ERR_NONE;
> +                       nand->retcode = ERR_NONE;
>                else
>                        mtd->ecc_stats.failed++;
>        }
> @@ -696,11 +727,12 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
>  static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
>  {
>        struct pxa3xx_nand_info *info = mtd->priv;
> +       struct pxa3xx_nand *nand = info->nand_data;
>        char retval = 0xFF;
>
> -       if (info->buf_start < info->buf_count)
> +       if (nand->buf_start < nand->buf_count)
>                /* Has just send a new command? */
> -               retval = info->data_buff[info->buf_start++];
> +               retval = nand->data_buff[nand->buf_start++];
>
>        return retval;
>  }
> @@ -708,11 +740,12 @@ static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
>  static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)
>  {
>        struct pxa3xx_nand_info *info = mtd->priv;
> +       struct pxa3xx_nand *nand = info->nand_data;
>        u16 retval = 0xFFFF;
>
> -       if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) {
> -               retval = *((u16 *)(info->data_buff+info->buf_start));
> -               info->buf_start += 2;
> +       if (!(nand->buf_start & 0x01) && nand->buf_start < nand->buf_count) {
> +               retval = *((u16 *)(nand->data_buff+nand->buf_start));
> +               nand->buf_start += 2;
>        }
>        return retval;
>  }
> @@ -720,20 +753,22 @@ static u16 pxa3xx_nand_read_word(struct mtd_info *mtd)
>  static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
>  {
>        struct pxa3xx_nand_info *info = mtd->priv;
> -       int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
> +       struct pxa3xx_nand *nand = info->nand_data;
> +       int real_len = min_t(size_t, len, nand->buf_count - nand->buf_start);
>
> -       memcpy(buf, info->data_buff + info->buf_start, real_len);
> -       info->buf_start += real_len;
> +       memcpy(buf, nand->data_buff + nand->buf_start, real_len);
> +       nand->buf_start += real_len;
>  }
>
>  static void pxa3xx_nand_write_buf(struct mtd_info *mtd,
>                const uint8_t *buf, int len)
>  {
>        struct pxa3xx_nand_info *info = mtd->priv;
> -       int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
> +       struct pxa3xx_nand *nand = info->nand_data;
> +       int real_len = min_t(size_t, len, nand->buf_count - nand->buf_start);
>
> -       memcpy(info->data_buff + info->buf_start, buf, real_len);
> -       info->buf_start += real_len;
> +       memcpy(nand->data_buff + nand->buf_start, buf, real_len);
> +       nand->buf_start += real_len;
>  }
>
>  static int pxa3xx_nand_verify_buf(struct mtd_info *mtd,
> @@ -750,10 +785,11 @@ static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip)
>  static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
>  {
>        struct pxa3xx_nand_info *info = mtd->priv;
> +       struct pxa3xx_nand *nand = info->nand_data;
>
>        /* pxa3xx_nand_send_command has waited for command complete */
>        if (this->state == FL_WRITING || this->state == FL_ERASING) {
> -               if (info->retcode == ERR_NONE)
> +               if (nand->retcode == ERR_NONE)
>                        return 0;
>                else {
>                        /*
> @@ -770,7 +806,8 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
>  static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
>                                    const struct pxa3xx_nand_flash *f)
>  {
> -       struct platform_device *pdev = info->pdev;
> +       struct pxa3xx_nand *nand = info->nand_data;
> +       struct platform_device *pdev = nand->pdev;
>        struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;
>        uint32_t ndcr = 0x0; /* enable all interrupts */
>
> @@ -804,6 +841,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
>        ndcr |= NDCR_SPARE_EN; /* enable spare by default */
>
>        info->reg_ndcr = ndcr;
> +       info->use_ecc = 1;
>
>        pxa3xx_nand_set_timing(info, f->timing);
>        return 0;
> @@ -811,15 +849,22 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
>
>  static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
>  {
> -       uint32_t ndcr = nand_readl(info, NDCR);
> +       struct pxa3xx_nand *nand = info->nand_data;
> +       uint32_t ndcr = nand_readl(nand, NDCR);
> +
> +       if (info->chip_select > 0) {
> +               printk(KERN_ERR "We could not detect configure"
> +                               " if more than one cs is supported!!\n");
> +               BUG();
> +       }
>        info->page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512;
>        /* set info fields needed to read id */
>        info->read_id_bytes = (info->page_size == 2048) ? 4 : 2;
>        info->reg_ndcr = ndcr & ~NDCR_INT_MASK;
>        info->cmdset = &default_cmdset;
>
> -       info->ndtr0cs0 = nand_readl(info, NDTR0CS0);
> -       info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
> +       info->ndtr0cs0 = nand_readl(nand, NDTR0CS0);
> +       info->ndtr1cs0 = nand_readl(nand, NDTR1CS0);
>
>        return 0;
>  }
> @@ -830,50 +875,31 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
>  */
>  #define MAX_BUFF_SIZE  PAGE_SIZE
>
> -static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
> +static void free_cs_resource(struct pxa3xx_nand_info *info, int cs)
>  {
> -       struct platform_device *pdev = info->pdev;
> -       int data_desc_offset = MAX_BUFF_SIZE - sizeof(struct pxa_dma_desc);
> -
> -       if (use_dma == 0) {
> -               info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL);
> -               if (info->data_buff == NULL)
> -                       return -ENOMEM;
> -               return 0;
> -       }
> -
> -       info->data_buff = dma_alloc_coherent(&pdev->dev, MAX_BUFF_SIZE,
> -                               &info->data_buff_phys, GFP_KERNEL);
> -       if (info->data_buff == NULL) {
> -               dev_err(&pdev->dev, "failed to allocate dma buffer\n");
> -               return -ENOMEM;
> -       }
> -
> -       info->data_buff_size = MAX_BUFF_SIZE;
> -       info->data_desc = (void *)info->data_buff + data_desc_offset;
> -       info->data_desc_addr = info->data_buff_phys + data_desc_offset;
> +       struct pxa3xx_nand *nand;
> +       struct mtd_info *mtd;
>
> -       info->data_dma_ch = pxa_request_dma("nand-data", DMA_PRIO_LOW,
> -                               pxa3xx_nand_data_dma_irq, info);
> -       if (info->data_dma_ch < 0) {
> -               dev_err(&pdev->dev, "failed to request data dma\n");
> -               dma_free_coherent(&pdev->dev, info->data_buff_size,
> -                               info->data_buff, info->data_buff_phys);
> -               return info->data_dma_ch;
> -       }
> +       if (!info)
> +               return;
>
> -       return 0;
> +       nand = info->nand_data;
> +       mtd = get_mtd_by_info(info);
> +       kfree(mtd);
> +       nand->info[cs] = NULL;
>  }
>
>  static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info)
>  {
> -       struct mtd_info *mtd = info->mtd;
> +       struct pxa3xx_nand *nand = info->nand_data;
> +       struct mtd_info *mtd = get_mtd_by_info(info);
>        struct nand_chip *chip = mtd->priv;
>
>        /* use the common timing to make a try */
> -       pxa3xx_nand_config_flash(info, &builtin_flash_types[0]);
> +       if (pxa3xx_nand_config_flash(info, &builtin_flash_types[0]))
> +               return 0;
>        chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0);
> -       if (info->is_ready)
> +       if (nand->is_ready)
>                return 1;
>        else
>                return 0;
> @@ -882,7 +908,8 @@ static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info)
>  static int pxa3xx_nand_scan(struct mtd_info *mtd)
>  {
>        struct pxa3xx_nand_info *info = mtd->priv;
> -       struct platform_device *pdev = info->pdev;
> +       struct pxa3xx_nand *nand = info->nand_data;
> +       struct platform_device *pdev = nand->pdev;
>        struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;
>        struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL;
>        const struct pxa3xx_nand_flash *f = NULL;
> @@ -891,27 +918,25 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
>        uint64_t chipsize;
>        int i, ret, num;
>
> +       nand->chip_select = info->chip_select;
>        if (pdata->keep_config && !pxa3xx_nand_detect_config(info))
>                goto KEEP_CONFIG;
>
>        ret = pxa3xx_nand_sensing(info);
>        if (!ret) {
> -               kfree(mtd);
> -               info->mtd = NULL;
> -               printk(KERN_INFO "There is no nand chip on cs 0!\n");
> +               free_cs_resource(info, nand->chip_select);
> +               printk(KERN_INFO "There is no nand chip on cs %d!\n",
> +                               nand->chip_select);

dev_err()?

>
>                return -EINVAL;
>        }
>
>        chip->cmdfunc(mtd, NAND_CMD_READID, 0, 0);
> -       id = *((uint16_t *)(info->data_buff));
> +       id = *((uint16_t *)(nand->data_buff));
>        if (id != 0)
>                printk(KERN_INFO "Detect a flash id %x\n", id);
>        else {
> -               kfree(mtd);
> -               info->mtd = NULL;
> -               printk(KERN_WARNING "Read out ID 0, potential timing set wrong!!\n");
> -
> +               free_cs_resource(info, nand->chip_select);
>                return -EINVAL;
>        }
>
> @@ -928,14 +953,16 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
>        }
>
>        if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1)) {
> -               kfree(mtd);
> -               info->mtd = NULL;
> +               free_cs_resource(info, nand->chip_select);
>                printk(KERN_ERR "ERROR!! flash not defined!!!\n");

Also here.

>
>                return -EINVAL;
>        }
>
> -       pxa3xx_nand_config_flash(info, f);
> +       if (pxa3xx_nand_config_flash(info, f)) {
> +               printk(KERN_ERR "ERROR! Configure failed\n");

And here. Giving no hint about which driver or function causes this
message makes debugging harder than it should be.

[...]

>  #ifdef CONFIG_PM
> @@ -1183,8 +1278,8 @@ static int pxa3xx_nand_resume(struct platform_device *pdev)
>        struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
>        struct mtd_info *mtd = info->mtd;
>
> -       nand_writel(info, NDTR0CS0, info->ndtr0cs0);
> -       nand_writel(info, NDTR1CS0, info->ndtr1cs0);
> +       nand_writel(nand, NDTR0CS0, info->ndtr0cs0);
> +       nand_writel(nand, NDTR1CS0, info->ndtr1cs0);
>        clk_enable(info->clk);

This won't compile.



Daniel



More information about the linux-mtd mailing list