Merge tag 'powerpc-4.6-4' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[linux-2.6-block.git] / drivers / mtd / nand / pxa3xx_nand.c
index 86fc245dc71a2395227a6b7283fa47ff1cc2fae1..d6508856da9937a433947a57dedce0d8fbd9d0e6 100644 (file)
 #define READ_ID_BYTES          7
 
 /* macros for registers read/write */
-#define nand_writel(info, off, val)    \
-       writel_relaxed((val), (info)->mmio_base + (off))
-
-#define nand_readl(info, off)          \
-       readl_relaxed((info)->mmio_base + (off))
+#define nand_writel(info, off, val)                                    \
+       do {                                                            \
+               dev_vdbg(&info->pdev->dev,                              \
+                        "%s():%d nand_writel(0x%x, 0x%04x)\n",         \
+                        __func__, __LINE__, (val), (off));             \
+               writel_relaxed((val), (info)->mmio_base + (off));       \
+       } while (0)
+
+#define nand_readl(info, off)                                          \
+       ({                                                              \
+               unsigned int _v;                                        \
+               _v = readl_relaxed((info)->mmio_base + (off));          \
+               dev_vdbg(&info->pdev->dev,                              \
+                        "%s():%d nand_readl(0x%04x) = 0x%x\n",         \
+                        __func__, __LINE__, (off), _v);                \
+               _v;                                                     \
+       })
 
 /* error code and state */
 enum {
@@ -199,7 +211,6 @@ struct pxa3xx_nand_info {
        struct dma_chan         *dma_chan;
        dma_cookie_t            dma_cookie;
        int                     drcmr_dat;
-       int                     drcmr_cmd;
 
        unsigned char           *data_buff;
        unsigned char           *oob_buff;
@@ -222,15 +233,44 @@ struct pxa3xx_nand_info {
        int                     use_spare;      /* use spare ? */
        int                     need_wait;
 
-       unsigned int            data_size;      /* data to be read from FIFO */
-       unsigned int            chunk_size;     /* split commands chunk size */
-       unsigned int            oob_size;
+       /* Amount of real data per full chunk */
+       unsigned int            chunk_size;
+
+       /* Amount of spare data per full chunk */
        unsigned int            spare_size;
+
+       /* Number of full chunks (i.e chunk_size + spare_size) */
+       unsigned int            nfullchunks;
+
+       /*
+        * Total number of chunks. If equal to nfullchunks, then there
+        * are only full chunks. Otherwise, there is one last chunk of
+        * size (last_chunk_size + last_spare_size)
+        */
+       unsigned int            ntotalchunks;
+
+       /* Amount of real data in the last chunk */
+       unsigned int            last_chunk_size;
+
+       /* Amount of spare data in the last chunk */
+       unsigned int            last_spare_size;
+
        unsigned int            ecc_size;
        unsigned int            ecc_err_cnt;
        unsigned int            max_bitflips;
        int                     retcode;
 
+       /*
+        * Variables only valid during command
+        * execution. step_chunk_size and step_spare_size is the
+        * amount of real data and spare data in the current
+        * chunk. cur_chunk is the current chunk being
+        * read/programmed.
+        */
+       unsigned int            step_chunk_size;
+       unsigned int            step_spare_size;
+       unsigned int            cur_chunk;
+
        /* cached register value */
        uint32_t                reg_ndcr;
        uint32_t                ndtr0cs0;
@@ -526,25 +566,6 @@ static int pxa3xx_nand_init(struct pxa3xx_nand_host *host)
        return 0;
 }
 
-/*
- * Set the data and OOB size, depending on the selected
- * spare and ECC configuration.
- * Only applicable to READ0, READOOB and PAGEPROG commands.
- */
-static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info,
-                               struct mtd_info *mtd)
-{
-       int oob_enable = info->reg_ndcr & NDCR_SPARE_EN;
-
-       info->data_size = mtd->writesize;
-       if (!oob_enable)
-               return;
-
-       info->oob_size = info->spare_size;
-       if (!info->use_ecc)
-               info->oob_size += info->ecc_size;
-}
-
 /**
  * NOTE: it is a must to set ND_RUN firstly, then write
  * command buffer, otherwise, it does not work.
@@ -660,28 +681,28 @@ static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
 
 static void handle_data_pio(struct pxa3xx_nand_info *info)
 {
-       unsigned int do_bytes = min(info->data_size, info->chunk_size);
-
        switch (info->state) {
        case STATE_PIO_WRITING:
-               writesl(info->mmio_base + NDDB,
-                       info->data_buff + info->data_buff_pos,
-                       DIV_ROUND_UP(do_bytes, 4));
+               if (info->step_chunk_size)
+                       writesl(info->mmio_base + NDDB,
+                               info->data_buff + info->data_buff_pos,
+                               DIV_ROUND_UP(info->step_chunk_size, 4));
 
-               if (info->oob_size > 0)
+               if (info->step_spare_size)
                        writesl(info->mmio_base + NDDB,
                                info->oob_buff + info->oob_buff_pos,
-                               DIV_ROUND_UP(info->oob_size, 4));
+                               DIV_ROUND_UP(info->step_spare_size, 4));
                break;
        case STATE_PIO_READING:
-               drain_fifo(info,
-                          info->data_buff + info->data_buff_pos,
-                          DIV_ROUND_UP(do_bytes, 4));
+               if (info->step_chunk_size)
+                       drain_fifo(info,
+                                  info->data_buff + info->data_buff_pos,
+                                  DIV_ROUND_UP(info->step_chunk_size, 4));
 
-               if (info->oob_size > 0)
+               if (info->step_spare_size)
                        drain_fifo(info,
                                   info->oob_buff + info->oob_buff_pos,
-                                  DIV_ROUND_UP(info->oob_size, 4));
+                                  DIV_ROUND_UP(info->step_spare_size, 4));
                break;
        default:
                dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
@@ -690,9 +711,8 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)
        }
 
        /* Update buffer pointers for multi-page read/write */
-       info->data_buff_pos += do_bytes;
-       info->oob_buff_pos += info->oob_size;
-       info->data_size -= do_bytes;
+       info->data_buff_pos += info->step_chunk_size;
+       info->oob_buff_pos += info->step_spare_size;
 }
 
 static void pxa3xx_nand_data_dma_irq(void *data)
@@ -733,8 +753,9 @@ static void start_data_dma(struct pxa3xx_nand_info *info)
                                info->state);
                BUG();
        }
-       info->sg.length = info->data_size +
-               (info->oob_size ? info->spare_size + info->ecc_size : 0);
+       info->sg.length = info->chunk_size;
+       if (info->use_spare)
+               info->sg.length += info->spare_size + info->ecc_size;
        dma_map_sg(info->dma_chan->device->dev, &info->sg, 1, info->dma_dir);
 
        tx = dmaengine_prep_slave_sg(info->dma_chan, &info->sg, 1, direction,
@@ -895,9 +916,11 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command)
        /* reset data and oob column point to handle data */
        info->buf_start         = 0;
        info->buf_count         = 0;
-       info->oob_size          = 0;
        info->data_buff_pos     = 0;
        info->oob_buff_pos      = 0;
+       info->step_chunk_size   = 0;
+       info->step_spare_size   = 0;
+       info->cur_chunk         = 0;
        info->use_ecc           = 0;
        info->use_spare         = 1;
        info->retcode           = ERR_NONE;
@@ -909,8 +932,6 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command)
        case NAND_CMD_READ0:
        case NAND_CMD_PAGEPROG:
                info->use_ecc = 1;
-       case NAND_CMD_READOOB:
-               pxa3xx_set_datasize(info, mtd);
                break;
        case NAND_CMD_PARAM:
                info->use_spare = 0;
@@ -969,6 +990,14 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
                if (command == NAND_CMD_READOOB)
                        info->buf_start += mtd->writesize;
 
+               if (info->cur_chunk < info->nfullchunks) {
+                       info->step_chunk_size = info->chunk_size;
+                       info->step_spare_size = info->spare_size;
+               } else {
+                       info->step_chunk_size = info->last_chunk_size;
+                       info->step_spare_size = info->last_spare_size;
+               }
+
                /*
                 * Multiple page read needs an 'extended command type' field,
                 * which is either naked-read or last-read according to the
@@ -980,8 +1009,8 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
                        info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8)
                                        | NDCB0_LEN_OVRD
                                        | NDCB0_EXT_CMD_TYPE(ext_cmd_type);
-                       info->ndcb3 = info->chunk_size +
-                                     info->oob_size;
+                       info->ndcb3 = info->step_chunk_size +
+                               info->step_spare_size;
                }
 
                set_command_address(info, mtd->writesize, column, page_addr);
@@ -1001,8 +1030,6 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
                                | NDCB0_EXT_CMD_TYPE(ext_cmd_type)
                                | addr_cycle
                                | command;
-                       /* No data transfer in this case */
-                       info->data_size = 0;
                        exec_cmd = 1;
                }
                break;
@@ -1014,6 +1041,14 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
                        break;
                }
 
+               if (info->cur_chunk < info->nfullchunks) {
+                       info->step_chunk_size = info->chunk_size;
+                       info->step_spare_size = info->spare_size;
+               } else {
+                       info->step_chunk_size = info->last_chunk_size;
+                       info->step_spare_size = info->last_spare_size;
+               }
+
                /* Second command setting for large pages */
                if (mtd->writesize > PAGE_CHUNK_SIZE) {
                        /*
@@ -1024,14 +1059,14 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
                        info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
                                        | NDCB0_LEN_OVRD
                                        | NDCB0_EXT_CMD_TYPE(ext_cmd_type);
-                       info->ndcb3 = info->chunk_size +
-                                     info->oob_size;
+                       info->ndcb3 = info->step_chunk_size +
+                                     info->step_spare_size;
 
                        /*
                         * This is the command dispatch that completes a chunked
                         * page program operation.
                         */
-                       if (info->data_size == 0) {
+                       if (info->cur_chunk == info->ntotalchunks) {
                                info->ndcb0 = NDCB0_CMD_TYPE(0x1)
                                        | NDCB0_EXT_CMD_TYPE(ext_cmd_type)
                                        | command;
@@ -1058,7 +1093,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
                                | command;
                info->ndcb1 = (column & 0xFF);
                info->ndcb3 = INIT_BUFFER_SIZE;
-               info->data_size = INIT_BUFFER_SIZE;
+               info->step_chunk_size = INIT_BUFFER_SIZE;
                break;
 
        case NAND_CMD_READID:
@@ -1068,7 +1103,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
                                | command;
                info->ndcb1 = (column & 0xFF);
 
-               info->data_size = 8;
+               info->step_chunk_size = 8;
                break;
        case NAND_CMD_STATUS:
                info->buf_count = 1;
@@ -1076,7 +1111,7 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
                                | NDCB0_ADDR_CYC(1)
                                | command;
 
-               info->data_size = 8;
+               info->step_chunk_size = 8;
                break;
 
        case NAND_CMD_ERASE1:
@@ -1217,6 +1252,7 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd,
        init_completion(&info->dev_ready);
        do {
                info->state = STATE_PREPARED;
+
                exec_cmd = prepare_set_command(info, command, ext_cmd_type,
                                               column, page_addr);
                if (!exec_cmd) {
@@ -1236,22 +1272,30 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd,
                        break;
                }
 
+               /* Only a few commands need several steps */
+               if (command != NAND_CMD_PAGEPROG &&
+                   command != NAND_CMD_READ0    &&
+                   command != NAND_CMD_READOOB)
+                       break;
+
+               info->cur_chunk++;
+
                /* Check if the sequence is complete */
-               if (info->data_size == 0 && command != NAND_CMD_PAGEPROG)
+               if (info->cur_chunk == info->ntotalchunks && command != NAND_CMD_PAGEPROG)
                        break;
 
                /*
                 * After a splitted program command sequence has issued
                 * the command dispatch, the command sequence is complete.
                 */
-               if (info->data_size == 0 &&
+               if (info->cur_chunk == (info->ntotalchunks + 1) &&
                    command == NAND_CMD_PAGEPROG &&
                    ext_cmd_type == EXT_CMD_TYPE_DISPATCH)
                        break;
 
                if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) {
                        /* Last read: issue a 'last naked read' */
-                       if (info->data_size == info->chunk_size)
+                       if (info->cur_chunk == info->ntotalchunks - 1)
                                ext_cmd_type = EXT_CMD_TYPE_LAST_RW;
                        else
                                ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
@@ -1261,7 +1305,7 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd,
                 * the command dispatch must be issued to complete.
                 */
                } else if (command == NAND_CMD_PAGEPROG &&
-                          info->data_size == 0) {
+                          info->cur_chunk == info->ntotalchunks) {
                                ext_cmd_type = EXT_CMD_TYPE_DISPATCH;
                }
        } while (1);
@@ -1506,6 +1550,8 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
                        int strength, int ecc_stepsize, int page_size)
 {
        if (strength == 1 && ecc_stepsize == 512 && page_size == 2048) {
+               info->nfullchunks = 1;
+               info->ntotalchunks = 1;
                info->chunk_size = 2048;
                info->spare_size = 40;
                info->ecc_size = 24;
@@ -1514,6 +1560,8 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
                ecc->strength = 1;
 
        } else if (strength == 1 && ecc_stepsize == 512 && page_size == 512) {
+               info->nfullchunks = 1;
+               info->ntotalchunks = 1;
                info->chunk_size = 512;
                info->spare_size = 8;
                info->ecc_size = 8;
@@ -1527,6 +1575,8 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
         */
        } else if (strength == 4 && ecc_stepsize == 512 && page_size == 2048) {
                info->ecc_bch = 1;
+               info->nfullchunks = 1;
+               info->ntotalchunks = 1;
                info->chunk_size = 2048;
                info->spare_size = 32;
                info->ecc_size = 32;
@@ -1537,6 +1587,8 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
 
        } else if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) {
                info->ecc_bch = 1;
+               info->nfullchunks = 2;
+               info->ntotalchunks = 2;
                info->chunk_size = 2048;
                info->spare_size = 32;
                info->ecc_size = 32;
@@ -1551,8 +1603,12 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
         */
        } else if (strength == 8 && ecc_stepsize == 512 && page_size == 4096) {
                info->ecc_bch = 1;
+               info->nfullchunks = 4;
+               info->ntotalchunks = 5;
                info->chunk_size = 1024;
                info->spare_size = 0;
+               info->last_chunk_size = 0;
+               info->last_spare_size = 64;
                info->ecc_size = 32;
                ecc->mode = NAND_ECC_HW;
                ecc->size = info->chunk_size;
@@ -1738,7 +1794,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
-       if (use_dma) {
+       if (!np && use_dma) {
                r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
                if (r == NULL) {
                        dev_err(&pdev->dev,
@@ -1747,15 +1803,6 @@ static int alloc_nand_resource(struct platform_device *pdev)
                        goto fail_disable_clk;
                }
                info->drcmr_dat = r->start;
-
-               r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-               if (r == NULL) {
-                       dev_err(&pdev->dev,
-                               "no resource defined for cmd DMA\n");
-                       ret = -ENXIO;
-                       goto fail_disable_clk;
-               }
-               info->drcmr_cmd = r->start;
        }
 
        irq = platform_get_irq(pdev, 0);