From mboxrd@z Thu Jan 1 00:00:00 1970 From: leiwen@marvell.com (Lei Wen) Date: Tue, 8 Jun 2010 16:37:35 +0800 Subject: [PATCH 22/25] pxa3xx_nand: reimplement the read oob logic Message-ID: To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org For readoob command only need the content of oob part, it certainly don't need the controller transfer the data part, which greatly downgrade the performance. Signed-off-by: Lei Wen --- drivers/mtd/nand/pxa3xx_nand.c | 182 +++++++++++++++++++++------------------- 1 files changed, 96 insertions(+), 86 deletions(-) diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 7f8bae7..e76264c 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -244,30 +244,28 @@ struct pxa3xx_nand { uint32_t command; uint16_t data_size; /* data size in FIFO */ uint16_t oob_size; - uint32_t bad_count; unsigned char *dma_buff; unsigned char *data_buff; unsigned char *oob_buff; + uint8_t chip_select; + uint8_t total_cmds; uint32_t buf_start; uint32_t buf_count; + + uint32_t state; + uint32_t bad_count; uint16_t data_column; uint16_t oob_column; - - /* relate to the command */ - uint8_t chip_select; - uint8_t ecc_strength; - unsigned int state; int use_dma; /* use DMA ? */ int retcode; + uint8_t ecc_strength; /* cached register value */ uint8_t cmd_seqs; - uint8_t total_cmds; uint8_t wait_ready[CMD_POOL_SIZE]; uint32_t ndcb0[CMD_POOL_SIZE]; - uint32_t ndcb1; + uint32_t ndcb1[CMD_POOL_SIZE]; uint32_t ndcb2; - uint32_t ndcb3[CMD_POOL_SIZE]; }; static int use_dma = 1; @@ -396,8 +394,8 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) struct pxa3xx_nand *nand = info->nand_data; int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; - if (info->page_size >= PAGE_CHUNK_SIZE) { - nand->data_size = PAGE_CHUNK_SIZE; + if (info->page_size < PAGE_CHUNK_SIZE) { + nand->data_size = 512; if (!oob_enable) { nand->oob_size = 0; return; @@ -405,32 +403,54 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) switch (nand->ecc_strength) { case 0: - nand->oob_size = 64; + nand->oob_size = 16; break; case HAMMING_STRENGTH: - nand->oob_size = 40; + nand->oob_size = 8; break; default: - nand->oob_size = 32; - } - } else { - nand->data_size = 512; - if (!oob_enable) { - nand->oob_size = 0; - return; + printk("Don't support BCH on small page device!!!\n"); + BUG(); } + return; + } + nand->data_size = PAGE_CHUNK_SIZE; + if (!oob_enable) { + nand->oob_size = 0; + return; + } - switch (nand->ecc_strength) { - case 0: - nand->oob_size = 16; - break; + if (nand->command == NAND_CMD_READOOB) { + switch (info->ecc_strength) { case HAMMING_STRENGTH: - nand->oob_size = 8; + nand->ndcb1[3] = 2 * PAGE_CHUNK_SIZE + OOB_CHUNK_SIZE; + nand->data_size = 40; + break; + case BCH_STRENGTH: + nand->ndcb1[3] = 2 * PAGE_CHUNK_SIZE + OOB_CHUNK_SIZE - 2; + nand->data_size = 32; break; default: - printk("Don't support BCH on small page device!!!\n"); BUG(); } + if (info->reg_ndcr & NDCR_DWIDTH_M) { + nand->ndcb1[1] = PAGE_CHUNK_SIZE / 2; + nand->ndcb1[3] /= 2; + } + else + nand->ndcb1[1] = PAGE_CHUNK_SIZE; + nand->oob_size = 0; + return; + } + switch (nand->ecc_strength) { + case 0: + nand->oob_size = 64; + break; + case HAMMING_STRENGTH: + nand->oob_size = 40; + break; + default: + nand->oob_size = 32; } } @@ -514,9 +534,8 @@ static void nand_error_dump(struct pxa3xx_nand *nand) printk(KERN_ERR "Totally %d command for sending\n", nand->total_cmds); for (i = 0; i < nand->total_cmds; i ++) - printk(KERN_ERR "NDCB0:%d: %x\n", - i, nand->ndcb0[i]); - printk(KERN_ERR "NDCB1: %x; NDCB2 %x\n", nand->ndcb1, nand->ndcb2); + printk(KERN_ERR "%d::NDCB0: %x, NDCB1: %x, NDCB2: %x\n", + i, nand->ndcb0[i], nand->ndcb1[i], nand->ndcb2); printk(KERN_ERR "\nRegister DUMPing ##############\n"); printk(KERN_ERR "NDCR %x\n" @@ -623,8 +642,8 @@ static void pxa3xx_nand_data_dma_irq(int channel, void *data) static int pxa3xx_nand_transaction(struct pxa3xx_nand *nand) { struct pxa3xx_nand_info *info; - unsigned int status, is_completed = 0, cs, cmd_seqs, ndcb1, ndcb2; - unsigned int ready, cmd_done, page_done, badblock_detect; + unsigned int status, is_completed = 0, cs, cmd_seqs; + unsigned int ready, cmd_done, page_done, badblock_detect, ndcb2; cs = nand->chip_select; ready = (cs) ? NDSR_RDY : NDSR_FLASH_RDY; @@ -686,22 +705,19 @@ static int pxa3xx_nand_transaction(struct pxa3xx_nand *nand) nand_writel(nand, NDSR, NDSR_WRCMDREQ); if (cmd_seqs < nand->total_cmds) { - nand->cmd_seqs ++; - if (cmd_seqs == 0) { - ndcb1 = nand->ndcb1; + if (cmd_seqs == 0) ndcb2 = nand->ndcb2; - } - else { - ndcb1 = 0; + else ndcb2 = 0; - } + nand->cmd_seqs ++; nand->state &= ~STATE_MASK; nand->state |= STATE_CMD_WAIT_DONE; nand_writel(nand, NDCB0, nand->ndcb0[cmd_seqs]); - nand_writel(nand, NDCB0, ndcb1); + nand_writel(nand, NDCB0, nand->ndcb1[cmd_seqs]); nand_writel(nand, NDCB0, ndcb2); - if (nand->ndcb3[cmd_seqs]) - nand_writel(nand, NDCB0, nand->ndcb3[cmd_seqs]); + if (nand->ndcb0[cmd_seqs] & NDCB0_LEN_OVRD) + nand_writel(nand, NDCB0, nand->data_size + + nand->oob_size); } else is_completed = 1; @@ -760,24 +776,15 @@ static int prepare_command_pool(struct pxa3xx_nand *nand, int command, exec_cmd = 1; /* reset data and oob column point to handle data */ - nand->data_column = 0; - nand->oob_column = 0; - nand->total_cmds = 1; - nand->cmd_seqs = 0; - nand->data_size = 0; - nand->oob_size = 0; - nand->use_dma = 0; - nand->state = 0; - nand->bad_count = 0; - nand->retcode = ERR_NONE; - nand->buf_start = column; + nand->total_cmds = 1; + nand->buf_start = column; switch (command) { case NAND_CMD_PAGEPROG: case NAND_CMD_RNDOUT: pxa3xx_set_datasize(info); nand->use_dma = use_dma; - chunks = info->page_size / nand->data_size; + chunks = info->page_size / PAGE_CHUNK_SIZE; if (info->ecc_strength > BCH_STRENGTH) { i = info->ecc_strength / BCH_STRENGTH; nand->data_size /= i; @@ -792,9 +799,8 @@ static int prepare_command_pool(struct pxa3xx_nand *nand, int command, BUG(); } default: - nand->ndcb1 = 0; - nand->ndcb2 = 0; - nand->ecc_strength = 0; + i = (uint32_t)(&nand->state) - (uint32_t)nand; + memset(&nand->state, 0, sizeof(struct pxa3xx_nand) - i); break; } if (nand->use_dma) { @@ -803,11 +809,8 @@ static int prepare_command_pool(struct pxa3xx_nand *nand, int command, } /* clear the command buffer */ - for (i = 0; i < CMD_POOL_SIZE; i ++) { + for (i = 0; i < CMD_POOL_SIZE; i ++) nand->ndcb0[i] = ndcb0; - nand->wait_ready[i] = 0; - nand->ndcb3[i] = (ndcb0 & NDCB0_LEN_OVRD)? nand->data_size : 0; - } addr_cycle = NDCB0_ADDR_CYC(info->row_addr_cycles + info->col_addr_cycles); @@ -822,10 +825,10 @@ static int prepare_command_pool(struct pxa3xx_nand *nand, int command, info->page_addr = page_addr; /* small page addr setting */ if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) - nand->ndcb1 = ((page_addr & 0xFFFFFF) << 8) + nand->ndcb1[0] = ((page_addr & 0xFFFFFF) << 8) | (column & 0xFF); else { - nand->ndcb1 = ((page_addr & 0xFFFF) << 16) + nand->ndcb1[0] = ((page_addr & 0xFFFF) << 16) | (column & 0xFFFF); if (page_addr & 0xFF0000) @@ -835,11 +838,6 @@ static int prepare_command_pool(struct pxa3xx_nand *nand, int command, case NAND_CMD_RNDOUT: cmd = cmdset.read1; - if (nand->command == NAND_CMD_READOOB) { - nand->buf_start = mtd->writesize + column; - nand->buf_count = mtd->oobsize; - } - if (unlikely(info->page_size < PAGE_CHUNK_SIZE) || !(pdata->controller_attrs & PXA3XX_NAKED_CMD_EN)) { if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) @@ -851,10 +849,18 @@ static int prepare_command_pool(struct pxa3xx_nand *nand, int command, | NDCB0_DBC | addr_cycle | cmd; + if (nand->command == NAND_CMD_READOOB) { + nand->buf_start = mtd->writesize + column; + nand->buf_count = mtd->oobsize; + } break; } - nand->total_cmds = chunks + 1; + if (nand->command == NAND_CMD_READOOB) + nand->total_cmds = 2 * chunks + 1; + else + nand->total_cmds = chunks + 1; + nand->ndcb0[0] |= NDCB0_CMD_XTYPE(0x6) | NDCB0_CMD_TYPE(0) | NDCB0_DBC @@ -862,15 +868,23 @@ static int prepare_command_pool(struct pxa3xx_nand *nand, int command, | addr_cycle | cmd; nand->ndcb0[0] &= ~NDCB0_LEN_OVRD; - nand->ndcb3[0] = 0; - nand->ndcb0[1] |= NDCB0_CMD_XTYPE(0x5) - | NDCB0_NC - | addr_cycle; - for (i = 2; i <= chunks; i ++) - nand->ndcb0[i] = nand->ndcb0[1]; + for (i = 1; i <= nand->total_cmds - 1;) { + if (nand->command == NAND_CMD_READOOB) { + nand->ndcb0[i ++] |= NDCB0_CMD_XTYPE(0x6) + | NDCB0_CMD_TYPE(0) + | NDCB0_ADDR_CYC(info->col_addr_cycles) + | NDCB0_DBC + | NDCB0_NC + | (NAND_CMD_RNDOUTSTART << 8) + | NAND_CMD_RNDOUT; + nand->ndcb0[i] |= NDCB0_LEN_OVRD; + } + nand->ndcb0[i ++] |= NDCB0_CMD_XTYPE(0x5) + | NDCB0_NC; + } - nand->ndcb0[chunks] &= ~NDCB0_NC; + nand->ndcb0[nand->total_cmds - 1] &= ~NDCB0_NC; /* we should wait RnB go high again * before read out data*/ nand->wait_ready[1] = 1; @@ -908,18 +922,15 @@ static int prepare_command_pool(struct pxa3xx_nand *nand, int command, nand->ndcb0[i] |= NDCB0_CMD_XTYPE(0x5) | NDCB0_NC | NDCB0_AUTO_RS - | NDCB0_CMD_TYPE(0x1) - | addr_cycle; + | NDCB0_CMD_TYPE(0x1); nand->ndcb0[chunks] |= NDCB0_CMD_XTYPE(0x3) - | NDCB0_CMD_TYPE(0x1) - | NDCB0_ST_ROW_EN - | NDCB0_DBC - | (cmd & NDCB0_CMD2_MASK) - | NDCB0_CMD1_MASK - | addr_cycle; + | NDCB0_CMD_TYPE(0x1) + | NDCB0_ST_ROW_EN + | NDCB0_DBC + | (cmd & NDCB0_CMD2_MASK) + | NDCB0_CMD1_MASK; nand->ndcb0[chunks] &= ~NDCB0_LEN_OVRD; - nand->ndcb3[chunks] = 0; /* we should wait for RnB goes high which * indicate the data has been written succesfully*/ nand->wait_ready[nand->total_cmds] = 1; @@ -953,8 +964,7 @@ static int prepare_command_pool(struct pxa3xx_nand *nand, int command, | NDCB0_ADDR_CYC(3) | NDCB0_DBC | cmd; - nand->ndcb1 = page_addr; - nand->ndcb2 = 0; + nand->ndcb1[0] = page_addr; break; case NAND_CMD_RESET: -- 1.7.0.4