All of lore.kernel.org
 help / color / mirror / Atom feed
From: Daniel Mack <zonque@gmail.com>
To: Lei Wen <leiwen@marvell.com>
Cc: Eric Miao <eric.y.miao@gmail.com>,
	David Woodhouse <David.Woodhouse@intel.com>,
	Artem Bityutskiy <dedekind1@gmail.com>,
	Haojian Zhuang <haojian.zhuang@gmail.com>,
	linux-mtd@lists.infradead.org,
	Igor Grinberg <grinberg@compulab.co.il>,
	linux-arm-kernel <linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH] MTD: pxa3xx_nand: enable multiple chip select support
Date: Sat, 25 Jun 2011 14:32:17 +0200	[thread overview]
Message-ID: <BANLkTimY2+qV_A7gSWOjAk0f54zKRC2wCg@mail.gmail.com> (raw)
In-Reply-To: <1309000666-5242-1-git-send-email-leiwen@marvell.com>

On Sat, Jun 25, 2011 at 1:17 PM, Lei Wen <leiwen@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@marvell.com>

I tested this on a PXA303 platform with one chipselect only, at at
least I can say that this patch doesn't seem to cause any regression
here. But I couldn't test the new feature it adds.

So, FWIW:

Tested-by: Daniel Mack <zonque@gmail.com>


Thanks!
Daniel


> ---
>  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 |   19 +-
>  drivers/mtd/nand/pxa3xx_nand.c               |  512 +++++++++++++++-----------
>  9 files changed, 346 insertions(+), 224 deletions(-)
>
> diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c
> index 06b5fa8..c4996f3 100644
> --- a/arch/arm/mach-mmp/aspenite.c
> +++ b/arch/arm/mach-mmp/aspenite.c
> @@ -167,8 +167,9 @@ static struct mtd_partition aspenite_nand_partitions[] = {
>
>  static struct pxa3xx_nand_platform_data aspenite_nand_info = {
>        .enable_arbiter = 1,
> -       .parts          = aspenite_nand_partitions,
> -       .nr_parts       = ARRAY_SIZE(aspenite_nand_partitions),
> +       .num_cs = 1,
> +       .parts[0]       = aspenite_nand_partitions,
> +       .nr_parts[0]    = ARRAY_SIZE(aspenite_nand_partitions),
>  };
>
>  static struct i2c_board_info aspenite_i2c_info[] __initdata = {
> diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
> index b2248e7..969d252 100644
> --- a/arch/arm/mach-pxa/cm-x300.c
> +++ b/arch/arm/mach-pxa/cm-x300.c
> @@ -423,8 +423,9 @@ static struct mtd_partition cm_x300_nand_partitions[] = {
>  static struct pxa3xx_nand_platform_data cm_x300_nand_info = {
>        .enable_arbiter = 1,
>        .keep_config    = 1,
> -       .parts          = cm_x300_nand_partitions,
> -       .nr_parts       = ARRAY_SIZE(cm_x300_nand_partitions),
> +       .num_cs         = 1,
> +       .parts[0]       = cm_x300_nand_partitions,
> +       .nr_parts[0]    = ARRAY_SIZE(cm_x300_nand_partitions),
>  };
>
>  static void __init cm_x300_init_nand(void)
> diff --git a/arch/arm/mach-pxa/colibri-pxa3xx.c b/arch/arm/mach-pxa/colibri-pxa3xx.c
> index 3f9be41..2b8ca0d 100644
> --- a/arch/arm/mach-pxa/colibri-pxa3xx.c
> +++ b/arch/arm/mach-pxa/colibri-pxa3xx.c
> @@ -139,8 +139,9 @@ static struct mtd_partition colibri_nand_partitions[] = {
>  static struct pxa3xx_nand_platform_data colibri_nand_info = {
>        .enable_arbiter = 1,
>        .keep_config    = 1,
> -       .parts          = colibri_nand_partitions,
> -       .nr_parts       = ARRAY_SIZE(colibri_nand_partitions),
> +       .num_cs         = 1,
> +       .parts[0]       = colibri_nand_partitions,
> +       .nr_parts[0]    = ARRAY_SIZE(colibri_nand_partitions),
>  };
>
>  void __init colibri_pxa3xx_init_nand(void)
> diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c
> index e5e326d..f6d1f9d 100644
> --- a/arch/arm/mach-pxa/littleton.c
> +++ b/arch/arm/mach-pxa/littleton.c
> @@ -325,8 +325,9 @@ static struct mtd_partition littleton_nand_partitions[] = {
>
>  static struct pxa3xx_nand_platform_data littleton_nand_info = {
>        .enable_arbiter = 1,
> -       .parts          = littleton_nand_partitions,
> -       .nr_parts       = ARRAY_SIZE(littleton_nand_partitions),
> +       .num_cs         = 1,
> +       .parts[0]       = littleton_nand_partitions,
> +       .nr_parts[0]    = ARRAY_SIZE(littleton_nand_partitions),
>  };
>
>  static void __init littleton_init_nand(void)
> diff --git a/arch/arm/mach-pxa/mxm8x10.c b/arch/arm/mach-pxa/mxm8x10.c
> index b5a8fd3..90928d6 100644
> --- a/arch/arm/mach-pxa/mxm8x10.c
> +++ b/arch/arm/mach-pxa/mxm8x10.c
> @@ -389,10 +389,11 @@ static struct mtd_partition mxm_8x10_nand_partitions[] = {
>  };
>
>  static struct pxa3xx_nand_platform_data mxm_8x10_nand_info = {
> -       .enable_arbiter = 1,
> -       .keep_config = 1,
> -       .parts = mxm_8x10_nand_partitions,
> -       .nr_parts = ARRAY_SIZE(mxm_8x10_nand_partitions)
> +       .enable_arbiter = 1,
> +       .keep_config    = 1,
> +       .num_cs         = 1,
> +       .parts[0]       = mxm_8x10_nand_partitions,
> +       .nr_parts[0]    = ARRAY_SIZE(mxm_8x10_nand_partitions)
>  };
>
>  static void __init mxm_8x10_nand_init(void)
> diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c
> index d130f77..c7ec847 100644
> --- a/arch/arm/mach-pxa/raumfeld.c
> +++ b/arch/arm/mach-pxa/raumfeld.c
> @@ -349,8 +349,9 @@ static struct mtd_partition raumfeld_nand_partitions[] = {
>  static struct pxa3xx_nand_platform_data raumfeld_nand_info = {
>        .enable_arbiter = 1,
>        .keep_config    = 1,
> -       .parts          = raumfeld_nand_partitions,
> -       .nr_parts       = ARRAY_SIZE(raumfeld_nand_partitions),
> +       .num_cs         = 1,
> +       .parts[0]       = raumfeld_nand_partitions,
> +       .nr_parts[0]    = ARRAY_SIZE(raumfeld_nand_partitions),
>  };
>
>  /**
> diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
> index 5821185..64fdac9 100644
> --- a/arch/arm/mach-pxa/zylonite.c
> +++ b/arch/arm/mach-pxa/zylonite.c
> @@ -366,8 +366,9 @@ static struct mtd_partition zylonite_nand_partitions[] = {
>
>  static struct pxa3xx_nand_platform_data zylonite_nand_info = {
>        .enable_arbiter = 1,
> -       .parts          = zylonite_nand_partitions,
> -       .nr_parts       = ARRAY_SIZE(zylonite_nand_partitions),
> +       .num_cs         = 1,
> +       .parts[0]       = zylonite_nand_partitions,
> +       .nr_parts[0]    = ARRAY_SIZE(zylonite_nand_partitions),
>  };
>
>  static void __init zylonite_init_nand(void)
> diff --git a/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h
> index 442301f..4e17309 100644
> --- a/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h
> +++ b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h
> @@ -41,6 +41,19 @@ struct pxa3xx_nand_flash {
>        struct pxa3xx_nand_timing *timing;      /* NAND Flash timing */
>  };
>
> +/*
> + * Current pxa3xx_nand controller has two chip select which
> + * both be workable.
> + *
> + * 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.
> + */
> +
> +/* The max num of chip select current support */
> +#define NUM_CHIP_SELECT                (2)
>  struct pxa3xx_nand_platform_data {
>
>        /* the data flash bus is shared between the Static Memory
> @@ -52,8 +65,10 @@ struct pxa3xx_nand_platform_data {
>        /* allow platform code to keep OBM/bootloader defined NFC config */
>        int     keep_config;
>
> -       const struct mtd_partition              *parts;
> -       unsigned int                            nr_parts;
> +       /* indicate how many chip selects will be used */
> +       int     num_cs;
> +       const struct mtd_partition              *parts[NUM_CHIP_SELECT];
> +       unsigned int                            nr_parts[NUM_CHIP_SELECT];
>
>        const struct pxa3xx_nand_flash *        flash;
>        size_t                                  num_flash;
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index b7db1b2..0825b7d 100644
> --- a/drivers/mtd/nand/pxa3xx_nand.c
> +++ b/drivers/mtd/nand/pxa3xx_nand.c
> @@ -110,6 +110,7 @@ enum {
>
>  enum {
>        STATE_IDLE = 0,
> +       STATE_PREPARED,
>        STATE_CMD_HANDLE,
>        STATE_DMA_READING,
>        STATE_DMA_WRITING,
> @@ -120,21 +121,40 @@ enum {
>        STATE_READY,
>  };
>
> -struct pxa3xx_nand_info {
> -       struct nand_chip        nand_chip;
> +struct pxa3xx_nand_host {
> +       struct nand_chip        chip;
> +       struct pxa3xx_nand_cmdset *cmdset;
> +       struct mtd_info         *mtd;
> +       void                    *info_data;
>
> +       /* page size of attached chip */
> +       unsigned int            page_size;
> +       int                     cs;
> +       int                     use_ecc;
> +
> +       /* calculated from pxa3xx_nand_flash data */
> +       unsigned int            col_addr_cycles;
> +       unsigned int            row_addr_cycles;
> +       size_t                  read_id_bytes;
> +
> +       /* cached register value */
> +       uint32_t                reg_ndcr;
> +       uint32_t                ndtr0cs0;
> +       uint32_t                ndtr1cs0;
> +};
> +
> +struct pxa3xx_nand_info {
>        struct nand_hw_control  controller;
>        struct platform_device   *pdev;
> -       struct pxa3xx_nand_cmdset *cmdset;
>
>        struct clk              *clk;
>        void __iomem            *mmio_base;
>        unsigned long           mmio_phys;
> +       struct completion       cmd_complete;
>
>        unsigned int            buf_start;
>        unsigned int            buf_count;
>
> -       struct mtd_info         *mtd;
>        /* DMA information */
>        int                     drcmr_dat;
>        int                     drcmr_cmd;
> @@ -142,44 +162,27 @@ struct pxa3xx_nand_info {
>        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_desc_addr;
>
> -       uint32_t                reg_ndcr;
> -
> -       /* saved column/page_addr during CMD_SEQIN */
> -       int                     seqin_column;
> -       int                     seqin_page_addr;
> -
> +       struct pxa3xx_nand_host *host[NUM_CHIP_SELECT];
>        /* relate to the command */
>        unsigned int            state;
>
> +       int                     cs;
>        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 */
> +       unsigned int            oob_size;
>        int                     retcode;
> -       struct completion       cmd_complete;
>
>        /* generated NDCBx register values */
>        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)
> @@ -241,9 +244,10 @@ const char *mtd_names[] = {"pxa3xx_nand-0", NULL};
>  /* convert nano-seconds to nand flash controller clock cycles */
>  #define ns2cycle(ns, clk)      (int)((ns) * (clk / 1000000) / 1000)
>
> -static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info,
> +static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
>                                   const struct pxa3xx_nand_timing *t)
>  {
> +       struct pxa3xx_nand_info *info = host->info_data;
>        unsigned long nand_clk = clk_get_rate(info->clk);
>        uint32_t ndtr0, ndtr1;
>
> @@ -258,23 +262,24 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info,
>                NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
>                NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
>
> -       info->ndtr0cs0 = ndtr0;
> -       info->ndtr1cs0 = ndtr1;
> +       host->ndtr0cs0 = ndtr0;
> +       host->ndtr1cs0 = ndtr1;
>        nand_writel(info, NDTR0CS0, ndtr0);
>        nand_writel(info, NDTR1CS0, ndtr1);
>  }
>
>  static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
>  {
> -       int oob_enable = info->reg_ndcr & NDCR_SPARE_EN;
> +       struct pxa3xx_nand_host *host = info->host[info->cs];
> +       int oob_enable = host->reg_ndcr & NDCR_SPARE_EN;
>
> -       info->data_size = info->page_size;
> +       info->data_size = host->page_size;
>        if (!oob_enable) {
>                info->oob_size = 0;
>                return;
>        }
>
> -       switch (info->page_size) {
> +       switch (host->page_size) {
>        case 2048:
>                info->oob_size = (info->use_ecc) ? 40 : 64;
>                break;
> @@ -292,9 +297,10 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
>  */
>  static void pxa3xx_nand_start(struct pxa3xx_nand_info *info)
>  {
> +       struct pxa3xx_nand_host *host = info->host[info->cs];
>        uint32_t ndcr;
>
> -       ndcr = info->reg_ndcr;
> +       ndcr = host->reg_ndcr;
>        ndcr |= info->use_ecc ? NDCR_ECC_EN : 0;
>        ndcr |= info->use_dma ? NDCR_DMA_EN : 0;
>        ndcr |= NDCR_ND_RUN;
> @@ -359,8 +365,8 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)
>                                        DIV_ROUND_UP(info->oob_size, 4));
>                break;
>        default:
> -               printk(KERN_ERR "%s: invalid state %d\n", __func__,
> -                               info->state);
> +               dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
> +                       info->state);
>                BUG();
>        }
>  }
> @@ -385,7 +391,7 @@ static void start_data_dma(struct pxa3xx_nand_info *info)
>                desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC;
>                break;
>        default:
> -               printk(KERN_ERR "%s: invalid state %d\n", __func__,
> +               dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
>                                info->state);
>                BUG();
>        }
> @@ -416,9 +422,17 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
>  {
>        struct pxa3xx_nand_info *info = devid;
>        unsigned int status, is_completed = 0;
> +       unsigned int ready, cmd_done;
> +
> +       if (info->cs == 0) {
> +               ready           = NDSR_FLASH_RDY;
> +               cmd_done        = NDSR_CS0_CMDD;
> +       } else {
> +               ready           = NDSR_RDY;
> +               cmd_done        = NDSR_CS1_CMDD;
> +       }
>
>        status = nand_readl(info, NDSR);
> -
>        if (status & NDSR_DBERR)
>                info->retcode = ERR_DBERR;
>        if (status & NDSR_SBERR)
> @@ -437,11 +451,11 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
>                        handle_data_pio(info);
>                }
>        }
> -       if (status & NDSR_CS0_CMDD) {
> +       if (status & cmd_done) {
>                info->state = STATE_CMD_DONE;
>                is_completed = 1;
>        }
> -       if (status & NDSR_FLASH_RDY) {
> +       if (status & ready) {
>                info->is_ready = 1;
>                info->state = STATE_READY;
>        }
> @@ -463,12 +477,6 @@ 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--)
> @@ -481,10 +489,10 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
>                uint16_t column, int page_addr)
>  {
>        uint16_t cmd;
> -       int addr_cycle, exec_cmd, ndcb0;
> -       struct mtd_info *mtd = info->mtd;
> +       int addr_cycle, exec_cmd;
> +       struct pxa3xx_nand_host *host = info->host[info->cs];
> +       struct mtd_info *mtd = host->mtd;
>
> -       ndcb0 = 0;
>        addr_cycle = 0;
>        exec_cmd = 1;
>
> @@ -495,6 +503,10 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
>        info->use_ecc           = 0;
>        info->is_ready          = 0;
>        info->retcode           = ERR_NONE;
> +       if (info->cs != 0)
> +               info->ndcb0 = NDCB0_CSEL;
> +       else
> +               info->ndcb0 = 0;
>
>        switch (command) {
>        case NAND_CMD_READ0:
> @@ -512,20 +524,19 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
>                break;
>        }
>
> -       info->ndcb0 = ndcb0;
> -       addr_cycle = NDCB0_ADDR_CYC(info->row_addr_cycles
> -                                   + info->col_addr_cycles);
> +       addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles
> +                                   + host->col_addr_cycles);
>
>        switch (command) {
>        case NAND_CMD_READOOB:
>        case NAND_CMD_READ0:
> -               cmd = info->cmdset->read1;
> +               cmd = host->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))
> +               if (unlikely(host->page_size < PAGE_CHUNK_SIZE))
>                        info->ndcb0 |= NDCB0_CMD_TYPE(0)
>                                        | addr_cycle
>                                        | (cmd & NDCB0_CMD1_MASK);
> @@ -537,7 +548,7 @@ 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)) {
> +               if (unlikely(host->page_size < PAGE_CHUNK_SIZE)) {
>                        info->ndcb1 = ((page_addr & 0xFFFFFF) << 8)
>                                        | (column & 0xFF);
>
> @@ -564,7 +575,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
>                        break;
>                }
>
> -               cmd = info->cmdset->program;
> +               cmd = host->cmdset->program;
>                info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
>                                | NDCB0_AUTO_RS
>                                | NDCB0_ST_ROW_EN
> @@ -574,8 +585,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
>                break;
>
>        case NAND_CMD_READID:
> -               cmd = info->cmdset->read_id;
> -               info->buf_count = info->read_id_bytes;
> +               cmd = host->cmdset->read_id;
> +               info->buf_count = host->read_id_bytes;
>                info->ndcb0 |= NDCB0_CMD_TYPE(3)
>                                | NDCB0_ADDR_CYC(1)
>                                | cmd;
> @@ -583,7 +594,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
>                info->data_size = 8;
>                break;
>        case NAND_CMD_STATUS:
> -               cmd = info->cmdset->read_status;
> +               cmd = host->cmdset->read_status;
>                info->buf_count = 1;
>                info->ndcb0 |= NDCB0_CMD_TYPE(4)
>                                | NDCB0_ADDR_CYC(1)
> @@ -593,7 +604,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
>                break;
>
>        case NAND_CMD_ERASE1:
> -               cmd = info->cmdset->erase;
> +               cmd = host->cmdset->erase;
>                info->ndcb0 |= NDCB0_CMD_TYPE(2)
>                                | NDCB0_AUTO_RS
>                                | NDCB0_ADDR_CYC(3)
> @@ -604,7 +615,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
>
>                break;
>        case NAND_CMD_RESET:
> -               cmd = info->cmdset->reset;
> +               cmd = host->cmdset->reset;
>                info->ndcb0 |= NDCB0_CMD_TYPE(5)
>                                | cmd;
>
> @@ -616,7 +627,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
>
>        default:
>                exec_cmd = 0;
> -               printk(KERN_ERR "pxa3xx-nand: non-supported"
> +               dev_err(&info->pdev->dev, "pxa3xx-nand: non-supported"
>                        " command %x\n", command);
>                break;
>        }
> @@ -627,7 +638,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
>  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_host *host = mtd->priv;
> +       struct pxa3xx_nand_info *info = host->info_data;
>        int ret, exec_cmd;
>
>        /*
> @@ -635,9 +647,21 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
>         * "byte" address into a "word" address appropriate
>         * for indexing a word-oriented device
>         */
> -       if (info->reg_ndcr & NDCR_DWIDTH_M)
> +       if (host->reg_ndcr & NDCR_DWIDTH_M)
>                column /= 2;
>
> +       /*
> +        * 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 (info->cs != host->cs) {
> +               info->cs = host->cs;
> +               nand_writel(info, NDTR0CS0, host->ndtr0cs0);
> +               nand_writel(info, NDTR1CS0, host->ndtr1cs0);
> +       }
> +
> +       info->state = STATE_PREPARED;
>        exec_cmd = prepare_command_pool(info, command, column, page_addr);
>        if (exec_cmd) {
>                init_completion(&info->cmd_complete);
> @@ -646,12 +670,12 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
>                ret = wait_for_completion_timeout(&info->cmd_complete,
>                                CHIP_DELAY_TIMEOUT);
>                if (!ret) {
> -                       printk(KERN_ERR "Wait time out!!!\n");
> +                       dev_err(&info->pdev->dev, "Wait time out!!!\n");
>                        /* Stop State Machine for next command cycle */
>                        pxa3xx_nand_stop(info);
>                }
> -               info->state = STATE_IDLE;
>        }
> +       info->state = STATE_IDLE;
>  }
>
>  static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
> @@ -664,7 +688,8 @@ static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
>  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_host *host = mtd->priv;
> +       struct pxa3xx_nand_info *info = host->info_data;
>
>        chip->read_buf(mtd, buf, mtd->writesize);
>        chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
> @@ -695,7 +720,8 @@ 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_host *host = mtd->priv;
> +       struct pxa3xx_nand_info *info = host->info_data;
>        char retval = 0xFF;
>
>        if (info->buf_start < info->buf_count)
> @@ -707,7 +733,8 @@ 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_host *host = mtd->priv;
> +       struct pxa3xx_nand_info *info = host->info_data;
>        u16 retval = 0xFFFF;
>
>        if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) {
> @@ -719,7 +746,8 @@ 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;
> +       struct pxa3xx_nand_host *host = mtd->priv;
> +       struct pxa3xx_nand_info *info = host->info_data;
>        int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
>
>        memcpy(buf, info->data_buff + info->buf_start, real_len);
> @@ -729,7 +757,8 @@ static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
>  static void pxa3xx_nand_write_buf(struct mtd_info *mtd,
>                const uint8_t *buf, int len)
>  {
> -       struct pxa3xx_nand_info *info = mtd->priv;
> +       struct pxa3xx_nand_host *host = mtd->priv;
> +       struct pxa3xx_nand_info *info = host->info_data;
>        int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
>
>        memcpy(info->data_buff + info->buf_start, buf, real_len);
> @@ -749,7 +778,8 @@ 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_host *host = mtd->priv;
> +       struct pxa3xx_nand_info *info = host->info_data;
>
>        /* pxa3xx_nand_send_command has waited for command complete */
>        if (this->state == FL_WRITING || this->state == FL_ERASING) {
> @@ -772,54 +802,69 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
>  {
>        struct platform_device *pdev = info->pdev;
>        struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;
> +       struct pxa3xx_nand_host *host = info->host[info->cs];
>        uint32_t ndcr = 0x0; /* enable all interrupts */
>
> -       if (f->page_size != 2048 && f->page_size != 512)
> +       if (f->page_size != 2048 && f->page_size != 512) {
> +               dev_err(&pdev->dev, "Current only support 2048 and 512 size\n");
>                return -EINVAL;
> +       }
>
> -       if (f->flash_width != 16 && f->flash_width != 8)
> +       if (f->flash_width != 16 && f->flash_width != 8) {
> +               dev_err(&pdev->dev, "Only support 8bit and 16 bit!\n");
>                return -EINVAL;
> +       }
>
>        /* calculate flash information */
> -       info->cmdset = &default_cmdset;
> -       info->page_size = f->page_size;
> -       info->read_id_bytes = (f->page_size == 2048) ? 4 : 2;
> +       host->cmdset = &default_cmdset;
> +       host->page_size = f->page_size;
> +       host->read_id_bytes = (f->page_size == 2048) ? 4 : 2;
>
>        /* calculate addressing information */
> -       info->col_addr_cycles = (f->page_size == 2048) ? 2 : 1;
> +       host->col_addr_cycles = (f->page_size == 2048) ? 2 : 1;
>
>        if (f->num_blocks * f->page_per_block > 65536)
> -               info->row_addr_cycles = 3;
> +               host->row_addr_cycles = 3;
>        else
> -               info->row_addr_cycles = 2;
> +               host->row_addr_cycles = 2;
>
>        ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
> -       ndcr |= (info->col_addr_cycles == 2) ? NDCR_RA_START : 0;
> +       ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0;
>        ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0;
>        ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0;
>        ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0;
>        ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0;
>
> -       ndcr |= NDCR_RD_ID_CNT(info->read_id_bytes);
> +       ndcr |= NDCR_RD_ID_CNT(host->read_id_bytes);
>        ndcr |= NDCR_SPARE_EN; /* enable spare by default */
>
> -       info->reg_ndcr = ndcr;
> +       host->reg_ndcr = ndcr;
>
> -       pxa3xx_nand_set_timing(info, f->timing);
> +       pxa3xx_nand_set_timing(host, f->timing);
>        return 0;
>  }
>
>  static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
>  {
> +       /*
> +        * We set 0 by hard coding here, for we don't support keep_config
> +        * when there is more than one chip attached to the controller
> +        */
> +       struct pxa3xx_nand_host *host = info->host[0];
>        uint32_t ndcr = nand_readl(info, NDCR);
> -       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);
> +       if (ndcr & NDCR_PAGE_SZ) {
> +               host->page_size = 2048;
> +               host->read_id_bytes = 4;
> +       } else {
> +               host->page_size = 512;
> +               host->read_id_bytes = 2;
> +       }
> +       host->reg_ndcr = ndcr & ~NDCR_INT_MASK;
> +       host->cmdset = &default_cmdset;
> +
> +       host->ndtr0cs0 = nand_readl(info, NDTR0CS0);
> +       host->ndtr1cs0 = nand_readl(info, NDTR1CS0);
>
>        return 0;
>  }
> @@ -829,59 +874,41 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
>  * data buffer and the DMA descriptor
>  */
>  #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_host *host;
> +       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->host[cs])
> +               return;
>
> -       return 0;
> +       host = info->host[cs];
> +       mtd = host->mtd;
> +       kfree(mtd);
> +       info->host[cs] = NULL;
>  }
>
>  static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info)
>  {
> -       struct mtd_info *mtd = info->mtd;
> -       struct nand_chip *chip = mtd->priv;
> +       struct mtd_info *mtd = info->host[info->cs]->mtd;
> +       int ret;
>
>        /* use the common timing to make a try */
> -       pxa3xx_nand_config_flash(info, &builtin_flash_types[0]);
> -       chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0);
> +       ret = pxa3xx_nand_config_flash(info, &builtin_flash_types[0]);
> +       if (ret)
> +               return ret;
> +
> +       pxa3xx_nand_cmdfunc(mtd, NAND_CMD_RESET, 0, 0);
>        if (info->is_ready)
> -               return 1;
> -       else
>                return 0;
> +
> +       return -ENODEV;
>  }
>
>  static int pxa3xx_nand_scan(struct mtd_info *mtd)
>  {
> -       struct pxa3xx_nand_info *info = mtd->priv;
> +       struct pxa3xx_nand_host *host = mtd->priv;
> +       struct pxa3xx_nand_info *info = host->info_data;
>        struct platform_device *pdev = info->pdev;
>        struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;
>        struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL;
> @@ -891,26 +918,26 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
>        uint64_t chipsize;
>        int i, ret, num;
>
> +       info->cs = host->cs;
>        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");
> +       if (ret) {
> +               free_cs_resource(info, info->cs);
> +               dev_info(&info->pdev->dev, "There is no nand chip on cs 0!\n");
>
> -               return -EINVAL;
> +               return ret;
>        }
>
>        chip->cmdfunc(mtd, NAND_CMD_READID, 0, 0);
>        id = *((uint16_t *)(info->data_buff));
>        if (id != 0)
> -               printk(KERN_INFO "Detect a flash id %x\n", id);
> +               dev_info(&info->pdev->dev, "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, info->cs);
> +               dev_warn(&info->pdev->dev, "Read out ID 0, "
> +                        "potential timing set wrong!!\n");
>
>                return -EINVAL;
>        }
> @@ -928,14 +955,17 @@ 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;
> -               printk(KERN_ERR "ERROR!! flash not defined!!!\n");
> +               free_cs_resource(info, info->cs);
> +               dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n");
>
>                return -EINVAL;
>        }
>
> -       pxa3xx_nand_config_flash(info, f);
> +       ret = pxa3xx_nand_config_flash(info, f);
> +       if (ret) {
> +               dev_err(&info->pdev->dev, "ERROR! Configure failed\n");
> +               return ret;
> +       }
>        pxa3xx_flash_ids[0].name = f->name;
>        pxa3xx_flash_ids[0].id = (f->chip_id >> 8) & 0xffff;
>        pxa3xx_flash_ids[0].pagesize = f->page_size;
> @@ -950,66 +980,51 @@ KEEP_CONFIG:
>        if (nand_scan_ident(mtd, 1, def))
>                return -ENODEV;
>        /* calculate addressing information */
> -       info->col_addr_cycles = (mtd->writesize >= 2048) ? 2 : 1;
> +       if (mtd->writesize >= 2048)
> +               host->col_addr_cycles = 2;
> +       else
> +               host->col_addr_cycles = 1;
>        info->oob_buff = info->data_buff + mtd->writesize;
>        if ((mtd->size >> chip->page_shift) > 65536)
> -               info->row_addr_cycles = 3;
> +               host->row_addr_cycles = 3;
>        else
> -               info->row_addr_cycles = 2;
> -       mtd->name = mtd_names[0];
> +               host->row_addr_cycles = 2;
> +       mtd->name = mtd_names[info->cs];
>        chip->ecc.mode = NAND_ECC_HW;
> -       chip->ecc.size = info->page_size;
> +       chip->ecc.size = host->page_size;
>
> -       chip->options = (info->reg_ndcr & NDCR_DWIDTH_M) ? NAND_BUSWIDTH_16 : 0;
> +       chip->options = 0;
> +       if (host->reg_ndcr & NDCR_DWIDTH_M)
> +               chip->options = NAND_BUSWIDTH_16;
>        chip->options |= NAND_NO_AUTOINCR;
>        chip->options |= NAND_NO_READRDY;
>
>        return nand_scan_tail(mtd);
>  }
>
> -static
> -struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev)
> +static int alloc_nand_resource(struct platform_device *pdev)
>  {
> +       struct pxa3xx_nand_platform_data *pdata;
>        struct pxa3xx_nand_info *info;
> +       struct pxa3xx_nand_host *host;
>        struct nand_chip *chip;
>        struct mtd_info *mtd;
>        struct resource *r;
> -       int ret, irq;
> +       int ret, irq, cs;
> +       int data_desc_offset = MAX_BUFF_SIZE - sizeof(struct pxa_dma_desc);
>
> -       mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct pxa3xx_nand_info),
> -                       GFP_KERNEL);
> -       if (!mtd) {
> +       pdata = pdev->dev.platform_data;
> +       info = kzalloc(sizeof(struct pxa3xx_nand_info), GFP_KERNEL);
> +       if (!info) {
>                dev_err(&pdev->dev, "failed to allocate memory\n");
> -               return NULL;
> +               return -ENOMEM;
>        }
> -
> -       info = (struct pxa3xx_nand_info *)(&mtd[1]);
> -       chip = (struct nand_chip *)(&mtd[1]);
>        info->pdev = pdev;
> -       info->mtd = mtd;
> -       mtd->priv = info;
> -       mtd->owner = THIS_MODULE;
> -
> -       chip->ecc.read_page     = pxa3xx_nand_read_page_hwecc;
> -       chip->ecc.write_page    = pxa3xx_nand_write_page_hwecc;
> -       chip->controller        = &info->controller;
> -       chip->waitfunc          = pxa3xx_nand_waitfunc;
> -       chip->select_chip       = pxa3xx_nand_select_chip;
> -       chip->dev_ready         = pxa3xx_nand_dev_ready;
> -       chip->cmdfunc           = pxa3xx_nand_cmdfunc;
> -       chip->read_word         = pxa3xx_nand_read_word;
> -       chip->read_byte         = pxa3xx_nand_read_byte;
> -       chip->read_buf          = pxa3xx_nand_read_buf;
> -       chip->write_buf         = pxa3xx_nand_write_buf;
> -       chip->verify_buf        = pxa3xx_nand_verify_buf;
> -
> -       spin_lock_init(&chip->controller->lock);
> -       init_waitqueue_head(&chip->controller->wq);
>        info->clk = clk_get(&pdev->dev, NULL);
>        if (IS_ERR(info->clk)) {
>                dev_err(&pdev->dev, "failed to get nand clock\n");
>                ret = PTR_ERR(info->clk);
> -               goto fail_free_mtd;
> +               goto fail_alloc;
>        }
>        clk_enable(info->clk);
>
> @@ -1058,10 +1073,6 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev)
>        }
>        info->mmio_phys = r->start;
>
> -       ret = pxa3xx_nand_init_buff(info);
> -       if (ret)
> -               goto fail_free_io;
> -
>        /* initialize all interrupts to be disabled */
>        disable_int(info, NDSR_MASK);
>
> @@ -1069,21 +1080,80 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev)
>                          pdev->name, info);
>        if (ret < 0) {
>                dev_err(&pdev->dev, "failed to request IRQ\n");
> -               goto fail_free_buf;
> +               ret = ENXIO;
> +               goto fail_free_io;
>        }
>
>        platform_set_drvdata(pdev, info);
>
> -       return info;
> +       for (cs = 0; cs < pdata->num_cs; cs++) {
> +               mtd = kzalloc(sizeof(struct mtd_info)
> +                               + sizeof(struct pxa3xx_nand_host),
> +                               GFP_KERNEL);
> +               if (!mtd) {
> +                       dev_err(&pdev->dev, "failed to allocate memory\n");
> +                       ret = -ENOMEM;
> +                       goto fail_free_irq;
> +               }
> +
> +               host = (struct pxa3xx_nand_host *)(&mtd[1]);
> +               host->info_data = info;
> +               host->cs = cs;
> +               host->mtd = mtd;
> +               mtd->priv = host;
> +               mtd->owner = THIS_MODULE;
> +               info->host[cs] = host;
> +
> +               chip = (struct nand_chip *)(&mtd[1]);
> +               chip->ecc.read_page     = pxa3xx_nand_read_page_hwecc;
> +               chip->ecc.write_page    = pxa3xx_nand_write_page_hwecc;
> +               chip->waitfunc          = pxa3xx_nand_waitfunc;
> +               chip->select_chip       = pxa3xx_nand_select_chip;
> +               chip->cmdfunc           = pxa3xx_nand_cmdfunc;
> +               chip->read_word         = pxa3xx_nand_read_word;
> +               chip->read_byte         = pxa3xx_nand_read_byte;
> +               chip->read_buf          = pxa3xx_nand_read_buf;
> +               chip->write_buf         = pxa3xx_nand_write_buf;
> +               chip->verify_buf        = pxa3xx_nand_verify_buf;
> +       }
> +
> +       if (use_dma == 0) {
> +               info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL);
> +               if (info->data_buff == NULL) {
> +                       ret = -ENOMEM;
> +                       goto fail_free_buf;
> +               }
> +               goto success_exit;
> +       }
> +
> +       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");
> +               ret = -ENOMEM;
> +               goto fail_free_buf;
> +       }
> +
> +       info->data_desc = (void *)info->data_buff + data_desc_offset;
> +       info->data_desc_addr = info->data_buff_phys + data_desc_offset;
> +       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");
> +               ret = -ENXIO;
> +               goto fail_free_dma_buf;
> +       }
> +success_exit:
> +       return 0;
>
> +fail_free_dma_buf:
> +       dma_free_writecombine(&pdev->dev, MAX_BUFF_SIZE,
> +                       info->data_buff, info->data_buff_phys);
>  fail_free_buf:
> +       for (cs = 0; cs < pdata->num_cs; cs++)
> +               free_cs_resource(info, cs);
> +fail_free_irq:
>        free_irq(irq, info);
> -       if (use_dma) {
> -               pxa_free_dma(info->data_dma_ch);
> -               dma_free_coherent(&pdev->dev, info->data_buff_size,
> -                       info->data_buff, info->data_buff_phys);
> -       } else
> -               kfree(info->data_buff);
>  fail_free_io:
>        iounmap(info->mmio_base);
>  fail_free_res:
> @@ -1091,18 +1161,20 @@ fail_free_res:
>  fail_put_clk:
>        clk_disable(info->clk);
>        clk_put(info->clk);
> -fail_free_mtd:
> -       kfree(mtd);
> -       return NULL;
> +fail_alloc:
> +       kfree(info);
> +       return ret;
>  }
>
>  static int pxa3xx_nand_remove(struct platform_device *pdev)
>  {
>        struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
> -       struct mtd_info *mtd = info->mtd;
> +       struct pxa3xx_nand_platform_data *pdata;
> +       struct pxa3xx_nand_host *host;
>        struct resource *r;
> -       int irq;
> +       int irq, cs;
>
> +       pdata = pdev->dev.platform_data;
>        platform_set_drvdata(pdev, NULL);
>
>        irq = platform_get_irq(pdev, 0);
> @@ -1110,7 +1182,7 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
>                free_irq(irq, info);
>        if (use_dma) {
>                pxa_free_dma(info->data_dma_ch);
> -               dma_free_writecombine(&pdev->dev, info->data_buff_size,
> +               dma_free_writecombine(&pdev->dev, MAX_BUFF_SIZE,
>                                info->data_buff, info->data_buff_phys);
>        } else
>                kfree(info->data_buff);
> @@ -1122,9 +1194,12 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
>        clk_disable(info->clk);
>        clk_put(info->clk);
>
> -       if (mtd) {
> -               nand_release(mtd);
> -               kfree(mtd);
> +       for (cs = 0; cs < pdata->num_cs; cs++) {
> +               host = info->host[cs];
> +               if (!host)
> +                       continue;
> +               nand_release(host->mtd);
> +               free_cs_resource(info, cs);
>        }
>        return 0;
>  }
> @@ -1133,6 +1208,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
>  {
>        struct pxa3xx_nand_platform_data *pdata;
>        struct pxa3xx_nand_info *info;
> +       int cs, ret, probe_success = 0;
>
>        pdata = pdev->dev.platform_data;
>        if (!pdata) {
> @@ -1140,18 +1216,38 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
>                return -ENODEV;
>        }
>
> -       info = alloc_nand_resource(pdev);
> -       if (info == NULL)
> -               return -ENOMEM;
> +       if (pdata->keep_config && pdata->num_cs > 1) {
> +               dev_warn(&pdev->dev, "keep_config is prohibited with multiple"
> +                        " chip selects feature!\n");
> +               pdata->keep_config = 0;
> +       }
> +
> +       ret = alloc_nand_resource(pdev);
> +       if (ret) {
> +               dev_err(&pdev->dev, "alloc nand resource failed\n");
> +               return ret;
> +       }
> +
> +       info = platform_get_drvdata(pdev);
> +       for (cs = 0; cs < pdata->num_cs; cs++) {
> +               ret = pxa3xx_nand_scan(info->host[cs]->mtd);
> +               if (ret) {
> +                       dev_err(&pdev->dev, "failed to scan nand\n");
> +                       continue;
> +               }
> +
> +               ret = mtd_device_parse_register(info->host[cs]->mtd, NULL, 0,
> +                       pdata->parts[cs], pdata->nr_parts[cs]);
> +               if (!ret)
> +                       probe_success = 1;
> +       }
>
> -       if (pxa3xx_nand_scan(info->mtd)) {
> -               dev_err(&pdev->dev, "failed to scan nand\n");
> +       if (!probe_success) {
>                pxa3xx_nand_remove(pdev);
>                return -ENODEV;
>        }
>
> -       return mtd_device_parse_register(info->mtd, NULL, 0,
> -                       pdata->parts, pdata->nr_parts);
> +       return 0;
>  }
>
>  #ifdef CONFIG_PM
> @@ -1171,8 +1267,12 @@ static int pxa3xx_nand_resume(struct platform_device *pdev)
>  {
>        struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
>
> -       nand_writel(info, NDTR0CS0, info->ndtr0cs0);
> -       nand_writel(info, NDTR1CS0, info->ndtr1cs0);
> +       /*
> +        * Directly set the chip select to a invalid value,
> +        * then the driver would reset the timing according
> +        * to current chip select at the beginning of cmdfunc
> +        */
> +       info->cs = 0xff;
>        clk_enable(info->clk);
>
>        return 0;
> --
> 1.7.0.4
>
>

WARNING: multiple messages have this Message-ID (diff)
From: zonque@gmail.com (Daniel Mack)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH] MTD: pxa3xx_nand: enable multiple chip select support
Date: Sat, 25 Jun 2011 14:32:17 +0200	[thread overview]
Message-ID: <BANLkTimY2+qV_A7gSWOjAk0f54zKRC2wCg@mail.gmail.com> (raw)
In-Reply-To: <1309000666-5242-1-git-send-email-leiwen@marvell.com>

On Sat, Jun 25, 2011 at 1:17 PM, Lei Wen <leiwen@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@marvell.com>

I tested this on a PXA303 platform with one chipselect only, at at
least I can say that this patch doesn't seem to cause any regression
here. But I couldn't test the new feature it adds.

So, FWIW:

Tested-by: Daniel Mack <zonque@gmail.com>


Thanks!
Daniel


> ---
> ?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 | ? 19 +-
> ?drivers/mtd/nand/pxa3xx_nand.c ? ? ? ? ? ? ? | ?512 +++++++++++++++-----------
> ?9 files changed, 346 insertions(+), 224 deletions(-)
>
> diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c
> index 06b5fa8..c4996f3 100644
> --- a/arch/arm/mach-mmp/aspenite.c
> +++ b/arch/arm/mach-mmp/aspenite.c
> @@ -167,8 +167,9 @@ static struct mtd_partition aspenite_nand_partitions[] = {
>
> ?static struct pxa3xx_nand_platform_data aspenite_nand_info = {
> ? ? ? ?.enable_arbiter = 1,
> - ? ? ? .parts ? ? ? ? ?= aspenite_nand_partitions,
> - ? ? ? .nr_parts ? ? ? = ARRAY_SIZE(aspenite_nand_partitions),
> + ? ? ? .num_cs = 1,
> + ? ? ? .parts[0] ? ? ? = aspenite_nand_partitions,
> + ? ? ? .nr_parts[0] ? ?= ARRAY_SIZE(aspenite_nand_partitions),
> ?};
>
> ?static struct i2c_board_info aspenite_i2c_info[] __initdata = {
> diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
> index b2248e7..969d252 100644
> --- a/arch/arm/mach-pxa/cm-x300.c
> +++ b/arch/arm/mach-pxa/cm-x300.c
> @@ -423,8 +423,9 @@ static struct mtd_partition cm_x300_nand_partitions[] = {
> ?static struct pxa3xx_nand_platform_data cm_x300_nand_info = {
> ? ? ? ?.enable_arbiter = 1,
> ? ? ? ?.keep_config ? ?= 1,
> - ? ? ? .parts ? ? ? ? ?= cm_x300_nand_partitions,
> - ? ? ? .nr_parts ? ? ? = ARRAY_SIZE(cm_x300_nand_partitions),
> + ? ? ? .num_cs ? ? ? ? = 1,
> + ? ? ? .parts[0] ? ? ? = cm_x300_nand_partitions,
> + ? ? ? .nr_parts[0] ? ?= ARRAY_SIZE(cm_x300_nand_partitions),
> ?};
>
> ?static void __init cm_x300_init_nand(void)
> diff --git a/arch/arm/mach-pxa/colibri-pxa3xx.c b/arch/arm/mach-pxa/colibri-pxa3xx.c
> index 3f9be41..2b8ca0d 100644
> --- a/arch/arm/mach-pxa/colibri-pxa3xx.c
> +++ b/arch/arm/mach-pxa/colibri-pxa3xx.c
> @@ -139,8 +139,9 @@ static struct mtd_partition colibri_nand_partitions[] = {
> ?static struct pxa3xx_nand_platform_data colibri_nand_info = {
> ? ? ? ?.enable_arbiter = 1,
> ? ? ? ?.keep_config ? ?= 1,
> - ? ? ? .parts ? ? ? ? ?= colibri_nand_partitions,
> - ? ? ? .nr_parts ? ? ? = ARRAY_SIZE(colibri_nand_partitions),
> + ? ? ? .num_cs ? ? ? ? = 1,
> + ? ? ? .parts[0] ? ? ? = colibri_nand_partitions,
> + ? ? ? .nr_parts[0] ? ?= ARRAY_SIZE(colibri_nand_partitions),
> ?};
>
> ?void __init colibri_pxa3xx_init_nand(void)
> diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c
> index e5e326d..f6d1f9d 100644
> --- a/arch/arm/mach-pxa/littleton.c
> +++ b/arch/arm/mach-pxa/littleton.c
> @@ -325,8 +325,9 @@ static struct mtd_partition littleton_nand_partitions[] = {
>
> ?static struct pxa3xx_nand_platform_data littleton_nand_info = {
> ? ? ? ?.enable_arbiter = 1,
> - ? ? ? .parts ? ? ? ? ?= littleton_nand_partitions,
> - ? ? ? .nr_parts ? ? ? = ARRAY_SIZE(littleton_nand_partitions),
> + ? ? ? .num_cs ? ? ? ? = 1,
> + ? ? ? .parts[0] ? ? ? = littleton_nand_partitions,
> + ? ? ? .nr_parts[0] ? ?= ARRAY_SIZE(littleton_nand_partitions),
> ?};
>
> ?static void __init littleton_init_nand(void)
> diff --git a/arch/arm/mach-pxa/mxm8x10.c b/arch/arm/mach-pxa/mxm8x10.c
> index b5a8fd3..90928d6 100644
> --- a/arch/arm/mach-pxa/mxm8x10.c
> +++ b/arch/arm/mach-pxa/mxm8x10.c
> @@ -389,10 +389,11 @@ static struct mtd_partition mxm_8x10_nand_partitions[] = {
> ?};
>
> ?static struct pxa3xx_nand_platform_data mxm_8x10_nand_info = {
> - ? ? ? .enable_arbiter = 1,
> - ? ? ? .keep_config = 1,
> - ? ? ? .parts = mxm_8x10_nand_partitions,
> - ? ? ? .nr_parts = ARRAY_SIZE(mxm_8x10_nand_partitions)
> + ? ? ? .enable_arbiter = 1,
> + ? ? ? .keep_config ? ?= 1,
> + ? ? ? .num_cs ? ? ? ? = 1,
> + ? ? ? .parts[0] ? ? ? = mxm_8x10_nand_partitions,
> + ? ? ? .nr_parts[0] ? ?= ARRAY_SIZE(mxm_8x10_nand_partitions)
> ?};
>
> ?static void __init mxm_8x10_nand_init(void)
> diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c
> index d130f77..c7ec847 100644
> --- a/arch/arm/mach-pxa/raumfeld.c
> +++ b/arch/arm/mach-pxa/raumfeld.c
> @@ -349,8 +349,9 @@ static struct mtd_partition raumfeld_nand_partitions[] = {
> ?static struct pxa3xx_nand_platform_data raumfeld_nand_info = {
> ? ? ? ?.enable_arbiter = 1,
> ? ? ? ?.keep_config ? ?= 1,
> - ? ? ? .parts ? ? ? ? ?= raumfeld_nand_partitions,
> - ? ? ? .nr_parts ? ? ? = ARRAY_SIZE(raumfeld_nand_partitions),
> + ? ? ? .num_cs ? ? ? ? = 1,
> + ? ? ? .parts[0] ? ? ? = raumfeld_nand_partitions,
> + ? ? ? .nr_parts[0] ? ?= ARRAY_SIZE(raumfeld_nand_partitions),
> ?};
>
> ?/**
> diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
> index 5821185..64fdac9 100644
> --- a/arch/arm/mach-pxa/zylonite.c
> +++ b/arch/arm/mach-pxa/zylonite.c
> @@ -366,8 +366,9 @@ static struct mtd_partition zylonite_nand_partitions[] = {
>
> ?static struct pxa3xx_nand_platform_data zylonite_nand_info = {
> ? ? ? ?.enable_arbiter = 1,
> - ? ? ? .parts ? ? ? ? ?= zylonite_nand_partitions,
> - ? ? ? .nr_parts ? ? ? = ARRAY_SIZE(zylonite_nand_partitions),
> + ? ? ? .num_cs ? ? ? ? = 1,
> + ? ? ? .parts[0] ? ? ? = zylonite_nand_partitions,
> + ? ? ? .nr_parts[0] ? ?= ARRAY_SIZE(zylonite_nand_partitions),
> ?};
>
> ?static void __init zylonite_init_nand(void)
> diff --git a/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h
> index 442301f..4e17309 100644
> --- a/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h
> +++ b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h
> @@ -41,6 +41,19 @@ struct pxa3xx_nand_flash {
> ? ? ? ?struct pxa3xx_nand_timing *timing; ? ? ?/* NAND Flash timing */
> ?};
>
> +/*
> + * Current pxa3xx_nand controller has two chip select which
> + * both be workable.
> + *
> + * 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.
> + */
> +
> +/* The max num of chip select current support */
> +#define NUM_CHIP_SELECT ? ? ? ? ? ? ? ?(2)
> ?struct pxa3xx_nand_platform_data {
>
> ? ? ? ?/* the data flash bus is shared between the Static Memory
> @@ -52,8 +65,10 @@ struct pxa3xx_nand_platform_data {
> ? ? ? ?/* allow platform code to keep OBM/bootloader defined NFC config */
> ? ? ? ?int ? ? keep_config;
>
> - ? ? ? const struct mtd_partition ? ? ? ? ? ? ?*parts;
> - ? ? ? unsigned int ? ? ? ? ? ? ? ? ? ? ? ? ? ?nr_parts;
> + ? ? ? /* indicate how many chip selects will be used */
> + ? ? ? int ? ? num_cs;
> + ? ? ? const struct mtd_partition ? ? ? ? ? ? ?*parts[NUM_CHIP_SELECT];
> + ? ? ? unsigned int ? ? ? ? ? ? ? ? ? ? ? ? ? ?nr_parts[NUM_CHIP_SELECT];
>
> ? ? ? ?const struct pxa3xx_nand_flash * ? ? ? ?flash;
> ? ? ? ?size_t ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?num_flash;
> diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
> index b7db1b2..0825b7d 100644
> --- a/drivers/mtd/nand/pxa3xx_nand.c
> +++ b/drivers/mtd/nand/pxa3xx_nand.c
> @@ -110,6 +110,7 @@ enum {
>
> ?enum {
> ? ? ? ?STATE_IDLE = 0,
> + ? ? ? STATE_PREPARED,
> ? ? ? ?STATE_CMD_HANDLE,
> ? ? ? ?STATE_DMA_READING,
> ? ? ? ?STATE_DMA_WRITING,
> @@ -120,21 +121,40 @@ enum {
> ? ? ? ?STATE_READY,
> ?};
>
> -struct pxa3xx_nand_info {
> - ? ? ? struct nand_chip ? ? ? ?nand_chip;
> +struct pxa3xx_nand_host {
> + ? ? ? struct nand_chip ? ? ? ?chip;
> + ? ? ? struct pxa3xx_nand_cmdset *cmdset;
> + ? ? ? struct mtd_info ? ? ? ? *mtd;
> + ? ? ? void ? ? ? ? ? ? ? ? ? ?*info_data;
>
> + ? ? ? /* page size of attached chip */
> + ? ? ? unsigned int ? ? ? ? ? ?page_size;
> + ? ? ? int ? ? ? ? ? ? ? ? ? ? cs;
> + ? ? ? int ? ? ? ? ? ? ? ? ? ? use_ecc;
> +
> + ? ? ? /* calculated from pxa3xx_nand_flash data */
> + ? ? ? unsigned int ? ? ? ? ? ?col_addr_cycles;
> + ? ? ? unsigned int ? ? ? ? ? ?row_addr_cycles;
> + ? ? ? size_t ? ? ? ? ? ? ? ? ?read_id_bytes;
> +
> + ? ? ? /* cached register value */
> + ? ? ? uint32_t ? ? ? ? ? ? ? ?reg_ndcr;
> + ? ? ? uint32_t ? ? ? ? ? ? ? ?ndtr0cs0;
> + ? ? ? uint32_t ? ? ? ? ? ? ? ?ndtr1cs0;
> +};
> +
> +struct pxa3xx_nand_info {
> ? ? ? ?struct nand_hw_control ?controller;
> ? ? ? ?struct platform_device ? *pdev;
> - ? ? ? struct pxa3xx_nand_cmdset *cmdset;
>
> ? ? ? ?struct clk ? ? ? ? ? ? ?*clk;
> ? ? ? ?void __iomem ? ? ? ? ? ?*mmio_base;
> ? ? ? ?unsigned long ? ? ? ? ? mmio_phys;
> + ? ? ? struct completion ? ? ? cmd_complete;
>
> ? ? ? ?unsigned int ? ? ? ? ? ?buf_start;
> ? ? ? ?unsigned int ? ? ? ? ? ?buf_count;
>
> - ? ? ? struct mtd_info ? ? ? ? *mtd;
> ? ? ? ?/* DMA information */
> ? ? ? ?int ? ? ? ? ? ? ? ? ? ? drcmr_dat;
> ? ? ? ?int ? ? ? ? ? ? ? ? ? ? drcmr_cmd;
> @@ -142,44 +162,27 @@ struct pxa3xx_nand_info {
> ? ? ? ?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_desc_addr;
>
> - ? ? ? uint32_t ? ? ? ? ? ? ? ?reg_ndcr;
> -
> - ? ? ? /* saved column/page_addr during CMD_SEQIN */
> - ? ? ? int ? ? ? ? ? ? ? ? ? ? seqin_column;
> - ? ? ? int ? ? ? ? ? ? ? ? ? ? seqin_page_addr;
> -
> + ? ? ? struct pxa3xx_nand_host *host[NUM_CHIP_SELECT];
> ? ? ? ?/* relate to the command */
> ? ? ? ?unsigned int ? ? ? ? ? ?state;
>
> + ? ? ? int ? ? ? ? ? ? ? ? ? ? cs;
> ? ? ? ?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 */
> + ? ? ? unsigned int ? ? ? ? ? ?oob_size;
> ? ? ? ?int ? ? ? ? ? ? ? ? ? ? retcode;
> - ? ? ? struct completion ? ? ? cmd_complete;
>
> ? ? ? ?/* generated NDCBx register values */
> ? ? ? ?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)
> @@ -241,9 +244,10 @@ const char *mtd_names[] = {"pxa3xx_nand-0", NULL};
> ?/* convert nano-seconds to nand flash controller clock cycles */
> ?#define ns2cycle(ns, clk) ? ? ?(int)((ns) * (clk / 1000000) / 1000)
>
> -static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info,
> +static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const struct pxa3xx_nand_timing *t)
> ?{
> + ? ? ? struct pxa3xx_nand_info *info = host->info_data;
> ? ? ? ?unsigned long nand_clk = clk_get_rate(info->clk);
> ? ? ? ?uint32_t ndtr0, ndtr1;
>
> @@ -258,23 +262,24 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info,
> ? ? ? ? ? ? ? ?NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
> ? ? ? ? ? ? ? ?NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
>
> - ? ? ? info->ndtr0cs0 = ndtr0;
> - ? ? ? info->ndtr1cs0 = ndtr1;
> + ? ? ? host->ndtr0cs0 = ndtr0;
> + ? ? ? host->ndtr1cs0 = ndtr1;
> ? ? ? ?nand_writel(info, NDTR0CS0, ndtr0);
> ? ? ? ?nand_writel(info, NDTR1CS0, ndtr1);
> ?}
>
> ?static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
> ?{
> - ? ? ? int oob_enable = info->reg_ndcr & NDCR_SPARE_EN;
> + ? ? ? struct pxa3xx_nand_host *host = info->host[info->cs];
> + ? ? ? int oob_enable = host->reg_ndcr & NDCR_SPARE_EN;
>
> - ? ? ? info->data_size = info->page_size;
> + ? ? ? info->data_size = host->page_size;
> ? ? ? ?if (!oob_enable) {
> ? ? ? ? ? ? ? ?info->oob_size = 0;
> ? ? ? ? ? ? ? ?return;
> ? ? ? ?}
>
> - ? ? ? switch (info->page_size) {
> + ? ? ? switch (host->page_size) {
> ? ? ? ?case 2048:
> ? ? ? ? ? ? ? ?info->oob_size = (info->use_ecc) ? 40 : 64;
> ? ? ? ? ? ? ? ?break;
> @@ -292,9 +297,10 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
> ?*/
> ?static void pxa3xx_nand_start(struct pxa3xx_nand_info *info)
> ?{
> + ? ? ? struct pxa3xx_nand_host *host = info->host[info->cs];
> ? ? ? ?uint32_t ndcr;
>
> - ? ? ? ndcr = info->reg_ndcr;
> + ? ? ? ndcr = host->reg_ndcr;
> ? ? ? ?ndcr |= info->use_ecc ? NDCR_ECC_EN : 0;
> ? ? ? ?ndcr |= info->use_dma ? NDCR_DMA_EN : 0;
> ? ? ? ?ndcr |= NDCR_ND_RUN;
> @@ -359,8 +365,8 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?DIV_ROUND_UP(info->oob_size, 4));
> ? ? ? ? ? ? ? ?break;
> ? ? ? ?default:
> - ? ? ? ? ? ? ? printk(KERN_ERR "%s: invalid state %d\n", __func__,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? info->state);
> + ? ? ? ? ? ? ? dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
> + ? ? ? ? ? ? ? ? ? ? ? info->state);
> ? ? ? ? ? ? ? ?BUG();
> ? ? ? ?}
> ?}
> @@ -385,7 +391,7 @@ static void start_data_dma(struct pxa3xx_nand_info *info)
> ? ? ? ? ? ? ? ?desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC;
> ? ? ? ? ? ? ? ?break;
> ? ? ? ?default:
> - ? ? ? ? ? ? ? printk(KERN_ERR "%s: invalid state %d\n", __func__,
> + ? ? ? ? ? ? ? dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?info->state);
> ? ? ? ? ? ? ? ?BUG();
> ? ? ? ?}
> @@ -416,9 +422,17 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
> ?{
> ? ? ? ?struct pxa3xx_nand_info *info = devid;
> ? ? ? ?unsigned int status, is_completed = 0;
> + ? ? ? unsigned int ready, cmd_done;
> +
> + ? ? ? if (info->cs == 0) {
> + ? ? ? ? ? ? ? ready ? ? ? ? ? = NDSR_FLASH_RDY;
> + ? ? ? ? ? ? ? cmd_done ? ? ? ?= NDSR_CS0_CMDD;
> + ? ? ? } else {
> + ? ? ? ? ? ? ? ready ? ? ? ? ? = NDSR_RDY;
> + ? ? ? ? ? ? ? cmd_done ? ? ? ?= NDSR_CS1_CMDD;
> + ? ? ? }
>
> ? ? ? ?status = nand_readl(info, NDSR);
> -
> ? ? ? ?if (status & NDSR_DBERR)
> ? ? ? ? ? ? ? ?info->retcode = ERR_DBERR;
> ? ? ? ?if (status & NDSR_SBERR)
> @@ -437,11 +451,11 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
> ? ? ? ? ? ? ? ? ? ? ? ?handle_data_pio(info);
> ? ? ? ? ? ? ? ?}
> ? ? ? ?}
> - ? ? ? if (status & NDSR_CS0_CMDD) {
> + ? ? ? if (status & cmd_done) {
> ? ? ? ? ? ? ? ?info->state = STATE_CMD_DONE;
> ? ? ? ? ? ? ? ?is_completed = 1;
> ? ? ? ?}
> - ? ? ? if (status & NDSR_FLASH_RDY) {
> + ? ? ? if (status & ready) {
> ? ? ? ? ? ? ? ?info->is_ready = 1;
> ? ? ? ? ? ? ? ?info->state = STATE_READY;
> ? ? ? ?}
> @@ -463,12 +477,6 @@ 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--)
> @@ -481,10 +489,10 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
> ? ? ? ? ? ? ? ?uint16_t column, int page_addr)
> ?{
> ? ? ? ?uint16_t cmd;
> - ? ? ? int addr_cycle, exec_cmd, ndcb0;
> - ? ? ? struct mtd_info *mtd = info->mtd;
> + ? ? ? int addr_cycle, exec_cmd;
> + ? ? ? struct pxa3xx_nand_host *host = info->host[info->cs];
> + ? ? ? struct mtd_info *mtd = host->mtd;
>
> - ? ? ? ndcb0 = 0;
> ? ? ? ?addr_cycle = 0;
> ? ? ? ?exec_cmd = 1;
>
> @@ -495,6 +503,10 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
> ? ? ? ?info->use_ecc ? ? ? ? ? = 0;
> ? ? ? ?info->is_ready ? ? ? ? ?= 0;
> ? ? ? ?info->retcode ? ? ? ? ? = ERR_NONE;
> + ? ? ? if (info->cs != 0)
> + ? ? ? ? ? ? ? info->ndcb0 = NDCB0_CSEL;
> + ? ? ? else
> + ? ? ? ? ? ? ? info->ndcb0 = 0;
>
> ? ? ? ?switch (command) {
> ? ? ? ?case NAND_CMD_READ0:
> @@ -512,20 +524,19 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
> ? ? ? ? ? ? ? ?break;
> ? ? ? ?}
>
> - ? ? ? info->ndcb0 = ndcb0;
> - ? ? ? addr_cycle = NDCB0_ADDR_CYC(info->row_addr_cycles
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? + info->col_addr_cycles);
> + ? ? ? addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? + host->col_addr_cycles);
>
> ? ? ? ?switch (command) {
> ? ? ? ?case NAND_CMD_READOOB:
> ? ? ? ?case NAND_CMD_READ0:
> - ? ? ? ? ? ? ? cmd = info->cmdset->read1;
> + ? ? ? ? ? ? ? cmd = host->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))
> + ? ? ? ? ? ? ? if (unlikely(host->page_size < PAGE_CHUNK_SIZE))
> ? ? ? ? ? ? ? ? ? ? ? ?info->ndcb0 |= NDCB0_CMD_TYPE(0)
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| addr_cycle
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| (cmd & NDCB0_CMD1_MASK);
> @@ -537,7 +548,7 @@ 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)) {
> + ? ? ? ? ? ? ? if (unlikely(host->page_size < PAGE_CHUNK_SIZE)) {
> ? ? ? ? ? ? ? ? ? ? ? ?info->ndcb1 = ((page_addr & 0xFFFFFF) << 8)
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| (column & 0xFF);
>
> @@ -564,7 +575,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
> ? ? ? ? ? ? ? ? ? ? ? ?break;
> ? ? ? ? ? ? ? ?}
>
> - ? ? ? ? ? ? ? cmd = info->cmdset->program;
> + ? ? ? ? ? ? ? cmd = host->cmdset->program;
> ? ? ? ? ? ? ? ?info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_AUTO_RS
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_ST_ROW_EN
> @@ -574,8 +585,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
> ? ? ? ? ? ? ? ?break;
>
> ? ? ? ?case NAND_CMD_READID:
> - ? ? ? ? ? ? ? cmd = info->cmdset->read_id;
> - ? ? ? ? ? ? ? info->buf_count = info->read_id_bytes;
> + ? ? ? ? ? ? ? cmd = host->cmdset->read_id;
> + ? ? ? ? ? ? ? info->buf_count = host->read_id_bytes;
> ? ? ? ? ? ? ? ?info->ndcb0 |= NDCB0_CMD_TYPE(3)
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_ADDR_CYC(1)
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| cmd;
> @@ -583,7 +594,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
> ? ? ? ? ? ? ? ?info->data_size = 8;
> ? ? ? ? ? ? ? ?break;
> ? ? ? ?case NAND_CMD_STATUS:
> - ? ? ? ? ? ? ? cmd = info->cmdset->read_status;
> + ? ? ? ? ? ? ? cmd = host->cmdset->read_status;
> ? ? ? ? ? ? ? ?info->buf_count = 1;
> ? ? ? ? ? ? ? ?info->ndcb0 |= NDCB0_CMD_TYPE(4)
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_ADDR_CYC(1)
> @@ -593,7 +604,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
> ? ? ? ? ? ? ? ?break;
>
> ? ? ? ?case NAND_CMD_ERASE1:
> - ? ? ? ? ? ? ? cmd = info->cmdset->erase;
> + ? ? ? ? ? ? ? cmd = host->cmdset->erase;
> ? ? ? ? ? ? ? ?info->ndcb0 |= NDCB0_CMD_TYPE(2)
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_AUTO_RS
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| NDCB0_ADDR_CYC(3)
> @@ -604,7 +615,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
>
> ? ? ? ? ? ? ? ?break;
> ? ? ? ?case NAND_CMD_RESET:
> - ? ? ? ? ? ? ? cmd = info->cmdset->reset;
> + ? ? ? ? ? ? ? cmd = host->cmdset->reset;
> ? ? ? ? ? ? ? ?info->ndcb0 |= NDCB0_CMD_TYPE(5)
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| cmd;
>
> @@ -616,7 +627,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
>
> ? ? ? ?default:
> ? ? ? ? ? ? ? ?exec_cmd = 0;
> - ? ? ? ? ? ? ? printk(KERN_ERR "pxa3xx-nand: non-supported"
> + ? ? ? ? ? ? ? dev_err(&info->pdev->dev, "pxa3xx-nand: non-supported"
> ? ? ? ? ? ? ? ? ? ? ? ?" command %x\n", command);
> ? ? ? ? ? ? ? ?break;
> ? ? ? ?}
> @@ -627,7 +638,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
> ?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_host *host = mtd->priv;
> + ? ? ? struct pxa3xx_nand_info *info = host->info_data;
> ? ? ? ?int ret, exec_cmd;
>
> ? ? ? ?/*
> @@ -635,9 +647,21 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
> ? ? ? ? * "byte" address into a "word" address appropriate
> ? ? ? ? * for indexing a word-oriented device
> ? ? ? ? */
> - ? ? ? if (info->reg_ndcr & NDCR_DWIDTH_M)
> + ? ? ? if (host->reg_ndcr & NDCR_DWIDTH_M)
> ? ? ? ? ? ? ? ?column /= 2;
>
> + ? ? ? /*
> + ? ? ? ?* 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 (info->cs != host->cs) {
> + ? ? ? ? ? ? ? info->cs = host->cs;
> + ? ? ? ? ? ? ? nand_writel(info, NDTR0CS0, host->ndtr0cs0);
> + ? ? ? ? ? ? ? nand_writel(info, NDTR1CS0, host->ndtr1cs0);
> + ? ? ? }
> +
> + ? ? ? info->state = STATE_PREPARED;
> ? ? ? ?exec_cmd = prepare_command_pool(info, command, column, page_addr);
> ? ? ? ?if (exec_cmd) {
> ? ? ? ? ? ? ? ?init_completion(&info->cmd_complete);
> @@ -646,12 +670,12 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
> ? ? ? ? ? ? ? ?ret = wait_for_completion_timeout(&info->cmd_complete,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?CHIP_DELAY_TIMEOUT);
> ? ? ? ? ? ? ? ?if (!ret) {
> - ? ? ? ? ? ? ? ? ? ? ? printk(KERN_ERR "Wait time out!!!\n");
> + ? ? ? ? ? ? ? ? ? ? ? dev_err(&info->pdev->dev, "Wait time out!!!\n");
> ? ? ? ? ? ? ? ? ? ? ? ?/* Stop State Machine for next command cycle */
> ? ? ? ? ? ? ? ? ? ? ? ?pxa3xx_nand_stop(info);
> ? ? ? ? ? ? ? ?}
> - ? ? ? ? ? ? ? info->state = STATE_IDLE;
> ? ? ? ?}
> + ? ? ? info->state = STATE_IDLE;
> ?}
>
> ?static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
> @@ -664,7 +688,8 @@ static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
> ?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_host *host = mtd->priv;
> + ? ? ? struct pxa3xx_nand_info *info = host->info_data;
>
> ? ? ? ?chip->read_buf(mtd, buf, mtd->writesize);
> ? ? ? ?chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
> @@ -695,7 +720,8 @@ 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_host *host = mtd->priv;
> + ? ? ? struct pxa3xx_nand_info *info = host->info_data;
> ? ? ? ?char retval = 0xFF;
>
> ? ? ? ?if (info->buf_start < info->buf_count)
> @@ -707,7 +733,8 @@ 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_host *host = mtd->priv;
> + ? ? ? struct pxa3xx_nand_info *info = host->info_data;
> ? ? ? ?u16 retval = 0xFFFF;
>
> ? ? ? ?if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) {
> @@ -719,7 +746,8 @@ 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;
> + ? ? ? struct pxa3xx_nand_host *host = mtd->priv;
> + ? ? ? struct pxa3xx_nand_info *info = host->info_data;
> ? ? ? ?int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
>
> ? ? ? ?memcpy(buf, info->data_buff + info->buf_start, real_len);
> @@ -729,7 +757,8 @@ static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
> ?static void pxa3xx_nand_write_buf(struct mtd_info *mtd,
> ? ? ? ? ? ? ? ?const uint8_t *buf, int len)
> ?{
> - ? ? ? struct pxa3xx_nand_info *info = mtd->priv;
> + ? ? ? struct pxa3xx_nand_host *host = mtd->priv;
> + ? ? ? struct pxa3xx_nand_info *info = host->info_data;
> ? ? ? ?int real_len = min_t(size_t, len, info->buf_count - info->buf_start);
>
> ? ? ? ?memcpy(info->data_buff + info->buf_start, buf, real_len);
> @@ -749,7 +778,8 @@ 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_host *host = mtd->priv;
> + ? ? ? struct pxa3xx_nand_info *info = host->info_data;
>
> ? ? ? ?/* pxa3xx_nand_send_command has waited for command complete */
> ? ? ? ?if (this->state == FL_WRITING || this->state == FL_ERASING) {
> @@ -772,54 +802,69 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
> ?{
> ? ? ? ?struct platform_device *pdev = info->pdev;
> ? ? ? ?struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;
> + ? ? ? struct pxa3xx_nand_host *host = info->host[info->cs];
> ? ? ? ?uint32_t ndcr = 0x0; /* enable all interrupts */
>
> - ? ? ? if (f->page_size != 2048 && f->page_size != 512)
> + ? ? ? if (f->page_size != 2048 && f->page_size != 512) {
> + ? ? ? ? ? ? ? dev_err(&pdev->dev, "Current only support 2048 and 512 size\n");
> ? ? ? ? ? ? ? ?return -EINVAL;
> + ? ? ? }
>
> - ? ? ? if (f->flash_width != 16 && f->flash_width != 8)
> + ? ? ? if (f->flash_width != 16 && f->flash_width != 8) {
> + ? ? ? ? ? ? ? dev_err(&pdev->dev, "Only support 8bit and 16 bit!\n");
> ? ? ? ? ? ? ? ?return -EINVAL;
> + ? ? ? }
>
> ? ? ? ?/* calculate flash information */
> - ? ? ? info->cmdset = &default_cmdset;
> - ? ? ? info->page_size = f->page_size;
> - ? ? ? info->read_id_bytes = (f->page_size == 2048) ? 4 : 2;
> + ? ? ? host->cmdset = &default_cmdset;
> + ? ? ? host->page_size = f->page_size;
> + ? ? ? host->read_id_bytes = (f->page_size == 2048) ? 4 : 2;
>
> ? ? ? ?/* calculate addressing information */
> - ? ? ? info->col_addr_cycles = (f->page_size == 2048) ? 2 : 1;
> + ? ? ? host->col_addr_cycles = (f->page_size == 2048) ? 2 : 1;
>
> ? ? ? ?if (f->num_blocks * f->page_per_block > 65536)
> - ? ? ? ? ? ? ? info->row_addr_cycles = 3;
> + ? ? ? ? ? ? ? host->row_addr_cycles = 3;
> ? ? ? ?else
> - ? ? ? ? ? ? ? info->row_addr_cycles = 2;
> + ? ? ? ? ? ? ? host->row_addr_cycles = 2;
>
> ? ? ? ?ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
> - ? ? ? ndcr |= (info->col_addr_cycles == 2) ? NDCR_RA_START : 0;
> + ? ? ? ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0;
> ? ? ? ?ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0;
> ? ? ? ?ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0;
> ? ? ? ?ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0;
> ? ? ? ?ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0;
>
> - ? ? ? ndcr |= NDCR_RD_ID_CNT(info->read_id_bytes);
> + ? ? ? ndcr |= NDCR_RD_ID_CNT(host->read_id_bytes);
> ? ? ? ?ndcr |= NDCR_SPARE_EN; /* enable spare by default */
>
> - ? ? ? info->reg_ndcr = ndcr;
> + ? ? ? host->reg_ndcr = ndcr;
>
> - ? ? ? pxa3xx_nand_set_timing(info, f->timing);
> + ? ? ? pxa3xx_nand_set_timing(host, f->timing);
> ? ? ? ?return 0;
> ?}
>
> ?static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
> ?{
> + ? ? ? /*
> + ? ? ? ?* We set 0 by hard coding here, for we don't support keep_config
> + ? ? ? ?* when there is more than one chip attached to the controller
> + ? ? ? ?*/
> + ? ? ? struct pxa3xx_nand_host *host = info->host[0];
> ? ? ? ?uint32_t ndcr = nand_readl(info, NDCR);
> - ? ? ? 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);
> + ? ? ? if (ndcr & NDCR_PAGE_SZ) {
> + ? ? ? ? ? ? ? host->page_size = 2048;
> + ? ? ? ? ? ? ? host->read_id_bytes = 4;
> + ? ? ? } else {
> + ? ? ? ? ? ? ? host->page_size = 512;
> + ? ? ? ? ? ? ? host->read_id_bytes = 2;
> + ? ? ? }
> + ? ? ? host->reg_ndcr = ndcr & ~NDCR_INT_MASK;
> + ? ? ? host->cmdset = &default_cmdset;
> +
> + ? ? ? host->ndtr0cs0 = nand_readl(info, NDTR0CS0);
> + ? ? ? host->ndtr1cs0 = nand_readl(info, NDTR1CS0);
>
> ? ? ? ?return 0;
> ?}
> @@ -829,59 +874,41 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
> ?* data buffer and the DMA descriptor
> ?*/
> ?#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_host *host;
> + ? ? ? 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->host[cs])
> + ? ? ? ? ? ? ? return;
>
> - ? ? ? return 0;
> + ? ? ? host = info->host[cs];
> + ? ? ? mtd = host->mtd;
> + ? ? ? kfree(mtd);
> + ? ? ? info->host[cs] = NULL;
> ?}
>
> ?static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info)
> ?{
> - ? ? ? struct mtd_info *mtd = info->mtd;
> - ? ? ? struct nand_chip *chip = mtd->priv;
> + ? ? ? struct mtd_info *mtd = info->host[info->cs]->mtd;
> + ? ? ? int ret;
>
> ? ? ? ?/* use the common timing to make a try */
> - ? ? ? pxa3xx_nand_config_flash(info, &builtin_flash_types[0]);
> - ? ? ? chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0);
> + ? ? ? ret = pxa3xx_nand_config_flash(info, &builtin_flash_types[0]);
> + ? ? ? if (ret)
> + ? ? ? ? ? ? ? return ret;
> +
> + ? ? ? pxa3xx_nand_cmdfunc(mtd, NAND_CMD_RESET, 0, 0);
> ? ? ? ?if (info->is_ready)
> - ? ? ? ? ? ? ? return 1;
> - ? ? ? else
> ? ? ? ? ? ? ? ?return 0;
> +
> + ? ? ? return -ENODEV;
> ?}
>
> ?static int pxa3xx_nand_scan(struct mtd_info *mtd)
> ?{
> - ? ? ? struct pxa3xx_nand_info *info = mtd->priv;
> + ? ? ? struct pxa3xx_nand_host *host = mtd->priv;
> + ? ? ? struct pxa3xx_nand_info *info = host->info_data;
> ? ? ? ?struct platform_device *pdev = info->pdev;
> ? ? ? ?struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;
> ? ? ? ?struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL;
> @@ -891,26 +918,26 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
> ? ? ? ?uint64_t chipsize;
> ? ? ? ?int i, ret, num;
>
> + ? ? ? info->cs = host->cs;
> ? ? ? ?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");
> + ? ? ? if (ret) {
> + ? ? ? ? ? ? ? free_cs_resource(info, info->cs);
> + ? ? ? ? ? ? ? dev_info(&info->pdev->dev, "There is no nand chip on cs 0!\n");
>
> - ? ? ? ? ? ? ? return -EINVAL;
> + ? ? ? ? ? ? ? return ret;
> ? ? ? ?}
>
> ? ? ? ?chip->cmdfunc(mtd, NAND_CMD_READID, 0, 0);
> ? ? ? ?id = *((uint16_t *)(info->data_buff));
> ? ? ? ?if (id != 0)
> - ? ? ? ? ? ? ? printk(KERN_INFO "Detect a flash id %x\n", id);
> + ? ? ? ? ? ? ? dev_info(&info->pdev->dev, "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, info->cs);
> + ? ? ? ? ? ? ? dev_warn(&info->pdev->dev, "Read out ID 0, "
> + ? ? ? ? ? ? ? ? ? ? ? ?"potential timing set wrong!!\n");
>
> ? ? ? ? ? ? ? ?return -EINVAL;
> ? ? ? ?}
> @@ -928,14 +955,17 @@ 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;
> - ? ? ? ? ? ? ? printk(KERN_ERR "ERROR!! flash not defined!!!\n");
> + ? ? ? ? ? ? ? free_cs_resource(info, info->cs);
> + ? ? ? ? ? ? ? dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n");
>
> ? ? ? ? ? ? ? ?return -EINVAL;
> ? ? ? ?}
>
> - ? ? ? pxa3xx_nand_config_flash(info, f);
> + ? ? ? ret = pxa3xx_nand_config_flash(info, f);
> + ? ? ? if (ret) {
> + ? ? ? ? ? ? ? dev_err(&info->pdev->dev, "ERROR! Configure failed\n");
> + ? ? ? ? ? ? ? return ret;
> + ? ? ? }
> ? ? ? ?pxa3xx_flash_ids[0].name = f->name;
> ? ? ? ?pxa3xx_flash_ids[0].id = (f->chip_id >> 8) & 0xffff;
> ? ? ? ?pxa3xx_flash_ids[0].pagesize = f->page_size;
> @@ -950,66 +980,51 @@ KEEP_CONFIG:
> ? ? ? ?if (nand_scan_ident(mtd, 1, def))
> ? ? ? ? ? ? ? ?return -ENODEV;
> ? ? ? ?/* calculate addressing information */
> - ? ? ? info->col_addr_cycles = (mtd->writesize >= 2048) ? 2 : 1;
> + ? ? ? if (mtd->writesize >= 2048)
> + ? ? ? ? ? ? ? host->col_addr_cycles = 2;
> + ? ? ? else
> + ? ? ? ? ? ? ? host->col_addr_cycles = 1;
> ? ? ? ?info->oob_buff = info->data_buff + mtd->writesize;
> ? ? ? ?if ((mtd->size >> chip->page_shift) > 65536)
> - ? ? ? ? ? ? ? info->row_addr_cycles = 3;
> + ? ? ? ? ? ? ? host->row_addr_cycles = 3;
> ? ? ? ?else
> - ? ? ? ? ? ? ? info->row_addr_cycles = 2;
> - ? ? ? mtd->name = mtd_names[0];
> + ? ? ? ? ? ? ? host->row_addr_cycles = 2;
> + ? ? ? mtd->name = mtd_names[info->cs];
> ? ? ? ?chip->ecc.mode = NAND_ECC_HW;
> - ? ? ? chip->ecc.size = info->page_size;
> + ? ? ? chip->ecc.size = host->page_size;
>
> - ? ? ? chip->options = (info->reg_ndcr & NDCR_DWIDTH_M) ? NAND_BUSWIDTH_16 : 0;
> + ? ? ? chip->options = 0;
> + ? ? ? if (host->reg_ndcr & NDCR_DWIDTH_M)
> + ? ? ? ? ? ? ? chip->options = NAND_BUSWIDTH_16;
> ? ? ? ?chip->options |= NAND_NO_AUTOINCR;
> ? ? ? ?chip->options |= NAND_NO_READRDY;
>
> ? ? ? ?return nand_scan_tail(mtd);
> ?}
>
> -static
> -struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev)
> +static int alloc_nand_resource(struct platform_device *pdev)
> ?{
> + ? ? ? struct pxa3xx_nand_platform_data *pdata;
> ? ? ? ?struct pxa3xx_nand_info *info;
> + ? ? ? struct pxa3xx_nand_host *host;
> ? ? ? ?struct nand_chip *chip;
> ? ? ? ?struct mtd_info *mtd;
> ? ? ? ?struct resource *r;
> - ? ? ? int ret, irq;
> + ? ? ? int ret, irq, cs;
> + ? ? ? int data_desc_offset = MAX_BUFF_SIZE - sizeof(struct pxa_dma_desc);
>
> - ? ? ? mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct pxa3xx_nand_info),
> - ? ? ? ? ? ? ? ? ? ? ? GFP_KERNEL);
> - ? ? ? if (!mtd) {
> + ? ? ? pdata = pdev->dev.platform_data;
> + ? ? ? info = kzalloc(sizeof(struct pxa3xx_nand_info), GFP_KERNEL);
> + ? ? ? if (!info) {
> ? ? ? ? ? ? ? ?dev_err(&pdev->dev, "failed to allocate memory\n");
> - ? ? ? ? ? ? ? return NULL;
> + ? ? ? ? ? ? ? return -ENOMEM;
> ? ? ? ?}
> -
> - ? ? ? info = (struct pxa3xx_nand_info *)(&mtd[1]);
> - ? ? ? chip = (struct nand_chip *)(&mtd[1]);
> ? ? ? ?info->pdev = pdev;
> - ? ? ? info->mtd = mtd;
> - ? ? ? mtd->priv = info;
> - ? ? ? mtd->owner = THIS_MODULE;
> -
> - ? ? ? chip->ecc.read_page ? ? = pxa3xx_nand_read_page_hwecc;
> - ? ? ? chip->ecc.write_page ? ?= pxa3xx_nand_write_page_hwecc;
> - ? ? ? chip->controller ? ? ? ?= &info->controller;
> - ? ? ? chip->waitfunc ? ? ? ? ?= pxa3xx_nand_waitfunc;
> - ? ? ? chip->select_chip ? ? ? = pxa3xx_nand_select_chip;
> - ? ? ? chip->dev_ready ? ? ? ? = pxa3xx_nand_dev_ready;
> - ? ? ? chip->cmdfunc ? ? ? ? ? = pxa3xx_nand_cmdfunc;
> - ? ? ? chip->read_word ? ? ? ? = pxa3xx_nand_read_word;
> - ? ? ? chip->read_byte ? ? ? ? = pxa3xx_nand_read_byte;
> - ? ? ? chip->read_buf ? ? ? ? ?= pxa3xx_nand_read_buf;
> - ? ? ? chip->write_buf ? ? ? ? = pxa3xx_nand_write_buf;
> - ? ? ? chip->verify_buf ? ? ? ?= pxa3xx_nand_verify_buf;
> -
> - ? ? ? spin_lock_init(&chip->controller->lock);
> - ? ? ? init_waitqueue_head(&chip->controller->wq);
> ? ? ? ?info->clk = clk_get(&pdev->dev, NULL);
> ? ? ? ?if (IS_ERR(info->clk)) {
> ? ? ? ? ? ? ? ?dev_err(&pdev->dev, "failed to get nand clock\n");
> ? ? ? ? ? ? ? ?ret = PTR_ERR(info->clk);
> - ? ? ? ? ? ? ? goto fail_free_mtd;
> + ? ? ? ? ? ? ? goto fail_alloc;
> ? ? ? ?}
> ? ? ? ?clk_enable(info->clk);
>
> @@ -1058,10 +1073,6 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev)
> ? ? ? ?}
> ? ? ? ?info->mmio_phys = r->start;
>
> - ? ? ? ret = pxa3xx_nand_init_buff(info);
> - ? ? ? if (ret)
> - ? ? ? ? ? ? ? goto fail_free_io;
> -
> ? ? ? ?/* initialize all interrupts to be disabled */
> ? ? ? ?disable_int(info, NDSR_MASK);
>
> @@ -1069,21 +1080,80 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev)
> ? ? ? ? ? ? ? ? ? ? ? ? ?pdev->name, info);
> ? ? ? ?if (ret < 0) {
> ? ? ? ? ? ? ? ?dev_err(&pdev->dev, "failed to request IRQ\n");
> - ? ? ? ? ? ? ? goto fail_free_buf;
> + ? ? ? ? ? ? ? ret = ENXIO;
> + ? ? ? ? ? ? ? goto fail_free_io;
> ? ? ? ?}
>
> ? ? ? ?platform_set_drvdata(pdev, info);
>
> - ? ? ? return info;
> + ? ? ? for (cs = 0; cs < pdata->num_cs; cs++) {
> + ? ? ? ? ? ? ? mtd = kzalloc(sizeof(struct mtd_info)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? + sizeof(struct pxa3xx_nand_host),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? GFP_KERNEL);
> + ? ? ? ? ? ? ? if (!mtd) {
> + ? ? ? ? ? ? ? ? ? ? ? dev_err(&pdev->dev, "failed to allocate memory\n");
> + ? ? ? ? ? ? ? ? ? ? ? ret = -ENOMEM;
> + ? ? ? ? ? ? ? ? ? ? ? goto fail_free_irq;
> + ? ? ? ? ? ? ? }
> +
> + ? ? ? ? ? ? ? host = (struct pxa3xx_nand_host *)(&mtd[1]);
> + ? ? ? ? ? ? ? host->info_data = info;
> + ? ? ? ? ? ? ? host->cs = cs;
> + ? ? ? ? ? ? ? host->mtd = mtd;
> + ? ? ? ? ? ? ? mtd->priv = host;
> + ? ? ? ? ? ? ? mtd->owner = THIS_MODULE;
> + ? ? ? ? ? ? ? info->host[cs] = host;
> +
> + ? ? ? ? ? ? ? chip = (struct nand_chip *)(&mtd[1]);
> + ? ? ? ? ? ? ? chip->ecc.read_page ? ? = pxa3xx_nand_read_page_hwecc;
> + ? ? ? ? ? ? ? chip->ecc.write_page ? ?= pxa3xx_nand_write_page_hwecc;
> + ? ? ? ? ? ? ? chip->waitfunc ? ? ? ? ?= pxa3xx_nand_waitfunc;
> + ? ? ? ? ? ? ? chip->select_chip ? ? ? = pxa3xx_nand_select_chip;
> + ? ? ? ? ? ? ? chip->cmdfunc ? ? ? ? ? = pxa3xx_nand_cmdfunc;
> + ? ? ? ? ? ? ? chip->read_word ? ? ? ? = pxa3xx_nand_read_word;
> + ? ? ? ? ? ? ? chip->read_byte ? ? ? ? = pxa3xx_nand_read_byte;
> + ? ? ? ? ? ? ? chip->read_buf ? ? ? ? ?= pxa3xx_nand_read_buf;
> + ? ? ? ? ? ? ? chip->write_buf ? ? ? ? = pxa3xx_nand_write_buf;
> + ? ? ? ? ? ? ? chip->verify_buf ? ? ? ?= pxa3xx_nand_verify_buf;
> + ? ? ? }
> +
> + ? ? ? if (use_dma == 0) {
> + ? ? ? ? ? ? ? info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL);
> + ? ? ? ? ? ? ? if (info->data_buff == NULL) {
> + ? ? ? ? ? ? ? ? ? ? ? ret = -ENOMEM;
> + ? ? ? ? ? ? ? ? ? ? ? goto fail_free_buf;
> + ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? goto success_exit;
> + ? ? ? }
> +
> + ? ? ? 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");
> + ? ? ? ? ? ? ? ret = -ENOMEM;
> + ? ? ? ? ? ? ? goto fail_free_buf;
> + ? ? ? }
> +
> + ? ? ? info->data_desc = (void *)info->data_buff + data_desc_offset;
> + ? ? ? info->data_desc_addr = info->data_buff_phys + data_desc_offset;
> + ? ? ? 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");
> + ? ? ? ? ? ? ? ret = -ENXIO;
> + ? ? ? ? ? ? ? goto fail_free_dma_buf;
> + ? ? ? }
> +success_exit:
> + ? ? ? return 0;
>
> +fail_free_dma_buf:
> + ? ? ? dma_free_writecombine(&pdev->dev, MAX_BUFF_SIZE,
> + ? ? ? ? ? ? ? ? ? ? ? info->data_buff, info->data_buff_phys);
> ?fail_free_buf:
> + ? ? ? for (cs = 0; cs < pdata->num_cs; cs++)
> + ? ? ? ? ? ? ? free_cs_resource(info, cs);
> +fail_free_irq:
> ? ? ? ?free_irq(irq, info);
> - ? ? ? if (use_dma) {
> - ? ? ? ? ? ? ? pxa_free_dma(info->data_dma_ch);
> - ? ? ? ? ? ? ? dma_free_coherent(&pdev->dev, info->data_buff_size,
> - ? ? ? ? ? ? ? ? ? ? ? info->data_buff, info->data_buff_phys);
> - ? ? ? } else
> - ? ? ? ? ? ? ? kfree(info->data_buff);
> ?fail_free_io:
> ? ? ? ?iounmap(info->mmio_base);
> ?fail_free_res:
> @@ -1091,18 +1161,20 @@ fail_free_res:
> ?fail_put_clk:
> ? ? ? ?clk_disable(info->clk);
> ? ? ? ?clk_put(info->clk);
> -fail_free_mtd:
> - ? ? ? kfree(mtd);
> - ? ? ? return NULL;
> +fail_alloc:
> + ? ? ? kfree(info);
> + ? ? ? return ret;
> ?}
>
> ?static int pxa3xx_nand_remove(struct platform_device *pdev)
> ?{
> ? ? ? ?struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
> - ? ? ? struct mtd_info *mtd = info->mtd;
> + ? ? ? struct pxa3xx_nand_platform_data *pdata;
> + ? ? ? struct pxa3xx_nand_host *host;
> ? ? ? ?struct resource *r;
> - ? ? ? int irq;
> + ? ? ? int irq, cs;
>
> + ? ? ? pdata = pdev->dev.platform_data;
> ? ? ? ?platform_set_drvdata(pdev, NULL);
>
> ? ? ? ?irq = platform_get_irq(pdev, 0);
> @@ -1110,7 +1182,7 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
> ? ? ? ? ? ? ? ?free_irq(irq, info);
> ? ? ? ?if (use_dma) {
> ? ? ? ? ? ? ? ?pxa_free_dma(info->data_dma_ch);
> - ? ? ? ? ? ? ? dma_free_writecombine(&pdev->dev, info->data_buff_size,
> + ? ? ? ? ? ? ? dma_free_writecombine(&pdev->dev, MAX_BUFF_SIZE,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?info->data_buff, info->data_buff_phys);
> ? ? ? ?} else
> ? ? ? ? ? ? ? ?kfree(info->data_buff);
> @@ -1122,9 +1194,12 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
> ? ? ? ?clk_disable(info->clk);
> ? ? ? ?clk_put(info->clk);
>
> - ? ? ? if (mtd) {
> - ? ? ? ? ? ? ? nand_release(mtd);
> - ? ? ? ? ? ? ? kfree(mtd);
> + ? ? ? for (cs = 0; cs < pdata->num_cs; cs++) {
> + ? ? ? ? ? ? ? host = info->host[cs];
> + ? ? ? ? ? ? ? if (!host)
> + ? ? ? ? ? ? ? ? ? ? ? continue;
> + ? ? ? ? ? ? ? nand_release(host->mtd);
> + ? ? ? ? ? ? ? free_cs_resource(info, cs);
> ? ? ? ?}
> ? ? ? ?return 0;
> ?}
> @@ -1133,6 +1208,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
> ?{
> ? ? ? ?struct pxa3xx_nand_platform_data *pdata;
> ? ? ? ?struct pxa3xx_nand_info *info;
> + ? ? ? int cs, ret, probe_success = 0;
>
> ? ? ? ?pdata = pdev->dev.platform_data;
> ? ? ? ?if (!pdata) {
> @@ -1140,18 +1216,38 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
> ? ? ? ? ? ? ? ?return -ENODEV;
> ? ? ? ?}
>
> - ? ? ? info = alloc_nand_resource(pdev);
> - ? ? ? if (info == NULL)
> - ? ? ? ? ? ? ? return -ENOMEM;
> + ? ? ? if (pdata->keep_config && pdata->num_cs > 1) {
> + ? ? ? ? ? ? ? dev_warn(&pdev->dev, "keep_config is prohibited with multiple"
> + ? ? ? ? ? ? ? ? ? ? ? ?" chip selects feature!\n");
> + ? ? ? ? ? ? ? pdata->keep_config = 0;
> + ? ? ? }
> +
> + ? ? ? ret = alloc_nand_resource(pdev);
> + ? ? ? if (ret) {
> + ? ? ? ? ? ? ? dev_err(&pdev->dev, "alloc nand resource failed\n");
> + ? ? ? ? ? ? ? return ret;
> + ? ? ? }
> +
> + ? ? ? info = platform_get_drvdata(pdev);
> + ? ? ? for (cs = 0; cs < pdata->num_cs; cs++) {
> + ? ? ? ? ? ? ? ret = pxa3xx_nand_scan(info->host[cs]->mtd);
> + ? ? ? ? ? ? ? if (ret) {
> + ? ? ? ? ? ? ? ? ? ? ? dev_err(&pdev->dev, "failed to scan nand\n");
> + ? ? ? ? ? ? ? ? ? ? ? continue;
> + ? ? ? ? ? ? ? }
> +
> + ? ? ? ? ? ? ? ret = mtd_device_parse_register(info->host[cs]->mtd, NULL, 0,
> + ? ? ? ? ? ? ? ? ? ? ? pdata->parts[cs], pdata->nr_parts[cs]);
> + ? ? ? ? ? ? ? if (!ret)
> + ? ? ? ? ? ? ? ? ? ? ? probe_success = 1;
> + ? ? ? }
>
> - ? ? ? if (pxa3xx_nand_scan(info->mtd)) {
> - ? ? ? ? ? ? ? dev_err(&pdev->dev, "failed to scan nand\n");
> + ? ? ? if (!probe_success) {
> ? ? ? ? ? ? ? ?pxa3xx_nand_remove(pdev);
> ? ? ? ? ? ? ? ?return -ENODEV;
> ? ? ? ?}
>
> - ? ? ? return mtd_device_parse_register(info->mtd, NULL, 0,
> - ? ? ? ? ? ? ? ? ? ? ? pdata->parts, pdata->nr_parts);
> + ? ? ? return 0;
> ?}
>
> ?#ifdef CONFIG_PM
> @@ -1171,8 +1267,12 @@ static int pxa3xx_nand_resume(struct platform_device *pdev)
> ?{
> ? ? ? ?struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
>
> - ? ? ? nand_writel(info, NDTR0CS0, info->ndtr0cs0);
> - ? ? ? nand_writel(info, NDTR1CS0, info->ndtr1cs0);
> + ? ? ? /*
> + ? ? ? ?* Directly set the chip select to a invalid value,
> + ? ? ? ?* then the driver would reset the timing according
> + ? ? ? ?* to current chip select at the beginning of cmdfunc
> + ? ? ? ?*/
> + ? ? ? info->cs = 0xff;
> ? ? ? ?clk_enable(info->clk);
>
> ? ? ? ?return 0;
> --
> 1.7.0.4
>
>

  reply	other threads:[~2011-06-25 12:32 UTC|newest]

Thread overview: 162+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-06-22  3:17 [PATCH] MTD: pxa3xx_nand: enable multiple chip select support Lei Wen
2011-07-08 16:00 ` Lei Wen
2011-06-22 11:39 ` Daniel Mack
2011-06-22 11:39   ` Daniel Mack
2011-06-22 12:21   ` Lei Wen
2011-07-08 17:38     ` Lei Wen
2011-06-22 13:06     ` Daniel Mack
2011-06-22 13:06       ` Daniel Mack
2011-06-23  6:22       ` Lei Wen
2011-06-23  6:22         ` Lei Wen
2011-06-22 13:45 ` Igor Grinberg
2011-07-08 16:09   ` Igor Grinberg
2011-06-23  6:35   ` Lei Wen
2011-07-08 15:26     ` Lei Wen
2011-06-23 10:44     ` Igor Grinberg
2011-06-23 10:44       ` Igor Grinberg
2011-06-25 11:17       ` Lei Wen
2011-06-25 11:17         ` Lei Wen
2011-06-25 12:32         ` Daniel Mack [this message]
2011-06-25 12:32           ` Daniel Mack
2011-06-25 12:51           ` Lei Wen
2011-06-25 12:51             ` Lei Wen
2011-06-27 13:22         ` Igor Grinberg
2011-06-27 13:22           ` Igor Grinberg
2011-06-28  7:32         ` Artem Bityutskiy
2011-06-28  7:32           ` Artem Bityutskiy
2011-06-28 15:12           ` Lei Wen
2011-06-28 15:12             ` Lei Wen
2011-06-29  3:51           ` [PATCH V3 0/9] pxa3xx_nand: add two " Lei Wen
2011-06-29  3:51             ` Lei Wen
2011-06-29  9:00             ` Igor Grinberg
2011-06-29  9:00               ` Igor Grinberg
2011-06-29 10:20               ` Artem Bityutskiy
2011-06-29 10:20                 ` Artem Bityutskiy
2011-07-04  9:27                 ` Lei Wen
2011-07-04  9:27                   ` Lei Wen
2011-07-04  9:25             ` [PATCH V4 0/4] " Lei Wen
2011-07-04  9:25               ` Lei Wen
2011-07-08  3:34               ` [PATCH V5 0/3] " Lei Wen
2011-07-08  3:34                 ` Lei Wen
2011-07-12 10:28                 ` [PATCH V6 0/4] " Lei Wen
2011-07-12 10:28                   ` Lei Wen
2011-07-12 14:35                   ` [PATCH V7 " Lei Wen
2011-07-12 14:35                     ` Lei Wen
2011-07-15  3:44                     ` [PATCH V8 " Lei Wen
2011-07-15  3:44                       ` Lei Wen
2011-07-20  4:51                       ` Artem Bityutskiy
2011-07-20  4:51                         ` Artem Bityutskiy
2011-07-15  3:44                     ` [PATCH V8 1/4] MTD: pxa3xx_nand: enhance suspend and resume routine Lei Wen
2011-07-15  3:44                       ` Lei Wen
2011-07-15  3:44                     ` [PATCH V8 2/4] MTD: pxa3xx_nand: convert all printk into dev_* Lei Wen
2011-07-15  3:44                       ` Lei Wen
2011-07-15  3:44                     ` [PATCH V8 3/4] MTD: pxa3xx_nand: sperate each chip individual info Lei Wen
2011-07-15  3:44                       ` Lei Wen
2011-07-15  3:44                     ` [PATCH V8 4/4] MTD: pxa3xx_nand: enable multiple chip select support Lei Wen
2011-07-15  3:44                       ` Lei Wen
2011-07-12 14:35                   ` [PATCH V7 1/4] MTD: pxa3xx_nand: enhance suspend and resume routine Lei Wen
2011-07-12 14:35                     ` Lei Wen
2011-07-13 10:53                     ` Sergei Shtylyov
2011-07-13 10:53                       ` Sergei Shtylyov
2011-07-12 14:35                   ` [PATCH V7 2/4] MTD: pxa3xx_nand: convert all printk into dev_* Lei Wen
2011-07-12 14:35                     ` Lei Wen
2011-07-13 10:57                     ` Sergei Shtylyov
2011-07-13 10:57                       ` Sergei Shtylyov
2011-07-13 12:41                       ` Lei Wen
2011-07-13 12:41                         ` Lei Wen
2011-07-13 14:35                         ` Sergei Shtylyov
2011-07-13 14:35                           ` Sergei Shtylyov
2011-07-12 14:35                   ` [PATCH V7 3/4] MTD: pxa3xx_nand: sperate each chip individual info Lei Wen
2011-07-12 14:35                     ` Lei Wen
2011-07-12 14:35                   ` [PATCH V7 4/4] MTD: pxa3xx_nand: enable multiple chip select support Lei Wen
2011-07-12 14:35                     ` Lei Wen
2011-07-12 10:28                 ` [PATCH V6 1/4] MTD: pxa3xx_nand: convert all printk into dev_* Lei Wen
2011-07-12 10:28                   ` Lei Wen
2011-07-12 10:28                 ` [PATCH V6 2/4] MTD: pxa3xx_nand: sperate each chip individual info Lei Wen
2011-07-12 10:28                   ` Lei Wen
2011-07-12 10:28                 ` [PATCH V6 3/4] MTD: pxa3xx_nand: enable multiple chip select support Lei Wen
2011-07-12 10:28                   ` Lei Wen
2011-07-12 10:28                 ` [PATCH V6 4/4] MTD: pxa3xx_nand: enhance suspend and resume routine Lei Wen
2011-07-12 10:28                   ` Lei Wen
2011-07-12 11:39                   ` Daniel Mack
2011-07-12 11:39                     ` Daniel Mack
2011-07-12 12:02                     ` Daniel Mack
2011-07-12 12:02                       ` Daniel Mack
2011-07-12 15:56                       ` Igor Grinberg
2011-07-12 15:56                         ` Igor Grinberg
2011-07-12 17:35                         ` Daniel Mack
2011-07-12 17:35                           ` Daniel Mack
2011-07-08  3:34               ` [PATCH 1/3] MTD: pxa3xx_nand: convert all printk into dev_* Lei Wen
2011-07-08  3:34                 ` Lei Wen
2011-07-08  3:34               ` [PATCH 2/3] MTD: pxa3xx_nand: sperate each chip individual info Lei Wen
2011-07-08  3:34                 ` Lei Wen
2011-07-08  3:34               ` [PATCH 3/3] MTD: pxa3xx_nand: enable multiple chip select support Lei Wen
2011-07-08  3:34                 ` Lei Wen
2011-07-04  9:25             ` [PATCH 1/4] MTD: pxa3xx_nand: convert all printk into dev_* Lei Wen
2011-07-04  9:25               ` Lei Wen
2011-07-04  9:25             ` [PATCH 2/4] MTD: pxa3xx_nand: sperate each chip individual info Lei Wen
2011-07-04  9:25               ` Lei Wen
2011-07-06  7:29               ` Igor Grinberg
2011-07-06  7:29                 ` Igor Grinberg
2011-07-04  9:25             ` [PATCH 3/4] MTD: pxa3xx_nand: enable multiple chip select support Lei Wen
2011-07-04  9:25               ` Lei Wen
2011-07-06  6:53               ` Artem Bityutskiy
2011-07-06  6:53                 ` Artem Bityutskiy
2011-07-06  6:54                 ` Lei Wen
2011-07-06  6:54                   ` Lei Wen
2011-07-06  7:07                   ` Artem Bityutskiy
2011-07-06  7:07                     ` Artem Bityutskiy
2011-07-06  7:41               ` Igor Grinberg
2011-07-06  7:41                 ` Igor Grinberg
2011-07-07  6:26                 ` Lei Wen
2011-07-07  6:26                   ` Lei Wen
2011-07-07  8:59                   ` Igor Grinberg
2011-07-07  8:59                     ` Igor Grinberg
2011-07-07  9:06                     ` Lei Wen
2011-07-07  9:06                       ` Lei Wen
2011-07-07 11:23                       ` Igor Grinberg
2011-07-07 11:23                         ` Igor Grinberg
2011-07-11 14:49                 ` Daniel Mack
2011-07-11 14:49                   ` Daniel Mack
2011-07-11 18:19                   ` Igor Grinberg
2011-07-11 18:19                     ` Igor Grinberg
2011-07-11 18:53                     ` Daniel Mack
2011-07-11 18:53                       ` Daniel Mack
2011-07-11 19:25                       ` Igor Grinberg
2011-07-11 19:25                         ` Igor Grinberg
2011-07-12  9:40                         ` Lei Wen
2011-07-12  9:40                           ` Lei Wen
2011-07-12  9:57                           ` Daniel Mack
2011-07-12  9:57                             ` Daniel Mack
2011-07-12 10:29                             ` Lei Wen
2011-07-12 10:29                               ` Lei Wen
2011-07-12 12:05                               ` Daniel Mack
2011-07-12 12:05                                 ` Daniel Mack
2011-07-12 12:48                         ` Daniel Mack
2011-07-12 12:48                           ` Daniel Mack
2011-07-12 15:49                           ` Igor Grinberg
2011-07-12 15:49                             ` Igor Grinberg
2011-07-04  9:25             ` [PATCH 4/4] ARM: mmp/pxa: fix nand platform data Lei Wen
2011-07-04  9:25               ` Lei Wen
2011-06-29  3:51           ` [PATCH 1/9] MTD: pxa3xx_nand: convert all printk into dev_* Lei Wen
2011-06-29  3:51             ` Lei Wen
2011-06-29  3:51           ` [PATCH 2/9] MTD: pxa3xx_nand: enable multiple chip select support Lei Wen
2011-06-29  3:51             ` Lei Wen
2011-06-29  7:11             ` Artem Bityutskiy
2011-06-29  7:11               ` Artem Bityutskiy
2011-06-29  7:16               ` Lei Wen
2011-06-29  7:16                 ` Lei Wen
2011-06-29  3:51           ` [PATCH 3/9] ARM: aspenite: fix nand platform data Lei Wen
2011-06-29  3:51             ` Lei Wen
2011-06-29  3:51           ` [PATCH 4/9] ARM: cm-x300: " Lei Wen
2011-06-29  3:51             ` Lei Wen
2011-06-29  3:51           ` [PATCH 5/9] ARM: colibri-pxa3xx: " Lei Wen
2011-06-29  3:51             ` Lei Wen
2011-06-29  3:51           ` [PATCH 6/9] ARM: littleton: " Lei Wen
2011-06-29  3:51             ` Lei Wen
2011-06-29  3:51           ` [PATCH 7/9] ARM: mxm8x10: " Lei Wen
2011-06-29  3:51             ` Lei Wen
2011-06-29  3:51           ` [PATCH 8/9] ARM: raumfeld: " Lei Wen
2011-06-29  3:51             ` Lei Wen
2011-06-29  3:51           ` [PATCH 9/9] ARM: zylonite: " Lei Wen
2011-06-29  3:51             ` Lei Wen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=BANLkTimY2+qV_A7gSWOjAk0f54zKRC2wCg@mail.gmail.com \
    --to=zonque@gmail.com \
    --cc=David.Woodhouse@intel.com \
    --cc=dedekind1@gmail.com \
    --cc=eric.y.miao@gmail.com \
    --cc=grinberg@compulab.co.il \
    --cc=haojian.zhuang@gmail.com \
    --cc=leiwen@marvell.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-mtd@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.