[PATCH 22/25] pxa3xx_nand: reimplement the read oob logic
From: Lei Wen <hidden>
Date: 2010-06-08 08:37:35
Subsystem:
memory technology devices (mtd), nand flash subsystem, the rest · Maintainers:
Miquel Raynal, Richard Weinberger, Vignesh Raghavendra, Linus Torvalds
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 <redacted> --- 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(structpxa3xx_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(structpxa3xx_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(structpxa3xx_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(structpxa3xx_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(structpxa3xx_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(structpxa3xx_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(structpxa3xx_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(structpxa3xx_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(structpxa3xx_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(structpxa3xx_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