From patchwork Fri May 14 06:25:03 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Haojian Zhuang X-Patchwork-Id: 52565 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from bombadil.infradead.org (bombadil.infradead.org [18.85.46.34]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 67ABEB7E8E for ; Fri, 14 May 2010 16:37:25 +1000 (EST) Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux)) id 1OCoU8-0004SO-Is; Fri, 14 May 2010 06:35:01 +0000 Received: from mail-pw0-f49.google.com ([209.85.160.49]) by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux)) id 1OCoKX-0006J5-4A; Fri, 14 May 2010 06:25:07 +0000 Received: by pwi3 with SMTP id 3so11541pwi.36 for ; Thu, 13 May 2010 23:25:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:received:date:message-id :subject:from:to:content-type; bh=lwCrAZT5cFoOOLQ6/Naeww4jkLxmmq6We0TQ5kSMs/c=; b=E1TA93zHXnYfPex2bvkd4CEAU1v7JokwuLJXXKxWZ7D2rpKbocRIxtmzim4WXpAS4V m+/WhhgnmZQgZFOUIgGPmIz8DKyo+cme3LXpHKf1Av1LRyuN4+LHra09kAVTSkWujNWI HBFYMwsXikYqoHb83jfuPVI+6xe+qeBdbsMZI= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:date:message-id:subject:from:to:content-type; b=IuxRHgdzoKZVi+N9voct+FmGoqOPaFyORUX4L2VrWbX0Z+WyeG++LzhQlwG9rnnkin wMQmBB5xNll5EbWyzpfCH1AcvRRhTYcpgdWjFBkeXz3UihzH+2RXZYONLLaANdRD8HZ6 nIZFSgZshoR7X9+Sj4aVfAJm3k72xtk4gggPw= MIME-Version: 1.0 Received: by 10.142.56.4 with SMTP id e4mr384504wfa.308.1273818303508; Thu, 13 May 2010 23:25:03 -0700 (PDT) Received: by 10.142.252.16 with HTTP; Thu, 13 May 2010 23:25:03 -0700 (PDT) Date: Fri, 14 May 2010 14:25:03 +0800 Message-ID: Subject: [PATCH 19/20] mtd: pxa3xx_nand: reimplment read oob command to increase performance From: Haojian Zhuang To: Marc Kleine-Budde , David Woodhouse , David Woodhouse , linux-mtd@lists.infradead.org, Eric Miao , linux-arm-kernel X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20100514_022505_846019_1838759E X-CRM114-Status: GOOD ( 21.10 ) X-Spam-Score: -0.1 (/) X-Spam-Report: SpamAssassin version 3.3.1 on bombadil.infradead.org summary: Content analysis details: (-0.1 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.160.49 listed in list.dnswl.org] 0.0 FREEMAIL_FROM Sender email is freemail (haojian.zhuang[at]gmail.com) -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-mtd-bounces@lists.infradead.org Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From 3c0c62b577c9540083d87f8200c2beb3f36f2656 Mon Sep 17 00:00:00 2001 From: Lei Wen Date: Thu, 6 May 2010 10:43:57 +0800 Subject: [PATCH] mtd: pxa3xx_nand: reimplment read oob command to increase performance For read oob command only care about the spare area part, we truly need not to transfer all page data to the controller side. By random data out, we could do the naked read first to let one page data transfer from NAND chip to its internal ram. Then we use random data out command to change the offset to the start of oob part. After all this, we toggle only oob size of RE# to the controller side. Signed-off-by: Lei Wen Signed-off-by: Haojian Zhuang --- drivers/mtd/nand/pxa3xx_nand.c | 122 ++++++++++++++++++++++++++++++---------- 1 files changed, 92 insertions(+), 30 deletions(-) cs = nand->chip_select; @@ -842,24 +844,20 @@ static int pxa3xx_nand_transaction(struct pxa3xx_nand *nand) nand_writel(nand, NDSR, NDSR_WRCMDREQ); if (cmd_seqs < info->total_cmds) { - info->cmd_seqs ++; - if (cmd_seqs == 0) { - ndcb1 = info->ndcb1; - ndcb2 = info->ndcb2; - } - else { - ndcb1 = 0; - ndcb2 = 0; - } + info->cmd_seqs++; nand->state &= ~STATE_MASK; nand->state |= STATE_CMD_WAIT_DONE; nand_writel(nand, NDCB0, info->ndcb0[cmd_seqs]); - nand_writel(nand, NDCB0, ndcb1); - nand_writel(nand, NDCB0, ndcb2); - DBG_NAND(printk("\tndcb0 %x ndcb1 %x ndcb2 %x\n", - info->ndcb0[cmd_seqs], ndcb1, ndcb2)); - } - else + nand_writel(nand, NDCB0, info->ndcb1[cmd_seqs]); + nand_writel(nand, NDCB0, info->ndcb2[cmd_seqs]); + if (info->ndcb0[cmd_seqs] & NDCB0_LEN_OVRD) + nand_writel(nand, NDCB0, info->ndcb3[cmd_seqs]); + DBG_NAND(printk("\tndcb0 %x ndcb1 %x ndcb2 %x, ndcb3 %x\n", + info->ndcb0[cmd_seqs], + info->ndcb1[cmd_seqs], + info->ndcb2[cmd_seqs], + info->ndcb3[cmd_seqs])); + } else is_completed = 1; } @@ -938,6 +936,7 @@ static int prepare_command_pool(struct pxa3xx_nand *nand, int command, case NAND_CMD_PAGEPROG: nand->use_ecc = info->use_ecc; case NAND_CMD_READOOB: + case NAND_CMD_RNDOUT: pxa3xx_set_datasize(info); nand->use_dma = use_dma; chunks = info->page_size / nand->data_size; @@ -946,8 +945,8 @@ static int prepare_command_pool(struct pxa3xx_nand *nand, int command, exec_cmd = 0; break; default: - info->ndcb1 = 0; - info->ndcb2 = 0; + info->ndcb1[0] = 0; + info->ndcb2[0] = 0; break; } @@ -1005,26 +1004,73 @@ static int prepare_command_pool(struct pxa3xx_nand *nand, int command, case NAND_CMD_SEQIN: /* small page addr setting */ if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) { - info->ndcb1 = ((page_addr & 0xFFFFFF) << 8) + info->ndcb1[0] = ((page_addr & 0xFFFFFF) << 8) | (column & 0xFF); - info->ndcb2 = 0; + info->ndcb2[0] = 0; } else { - info->ndcb1 = ((page_addr & 0xFFFF) << 16) + info->ndcb1[0] = ((page_addr & 0xFFFF) << 16) | (column & 0xFFFF); if (page_addr & 0xFF0000) - info->ndcb2 = (page_addr & 0xFF0000) >> 16; + info->ndcb2[0] = (page_addr & 0xFF0000) >> 16; else - info->ndcb2 = 0; + info->ndcb2[0] = 0; } + for (i = 1; i <=chunks; i ++) { + info->ndcb1[i] = info->ndcb1[0]; + info->ndcb2[i] = info->ndcb2[0]; + } info->buf_count = mtd->writesize + mtd->oobsize; memset(info->data_buff, 0xFF, info->buf_count); break; + case NAND_CMD_RNDOUT: + /* current RNDOUT only support 2k nand */ + if (info->page_size > PAGE_CHUNK_SIZE) + BUG(); + + cmd = cmdset.read1; + info->total_cmds = 3; + info->ndcb0[0] |= NDCB0_CMD_XTYPE(0x6) + | NDCB0_CMD_TYPE(0) + | NDCB0_DBC + | NDCB0_NC + | addr_cycle + | cmd; + + info->ndcb0[1] |= NDCB0_CMD_XTYPE(0x6) + | NDCB0_CMD_TYPE(0) + | NDCB0_DBC + | NDCB0_NC + | NDCB0_ADDR_CYC(info->col_addr_cycles) + | (NAND_CMD_RNDOUTSTART << 8) + | NAND_CMD_RNDOUT; + + info->ndcb0[2] |= NDCB0_CMD_XTYPE(0x5) + | NDCB0_LEN_OVRD; + + info->ndcb1[0] = ((page_addr & 0xFFFF) << 16) + | (column & 0xFFFF); + info->ndcb1[1] = mtd->writesize; + info->ndcb1[2] = 0; + + if (page_addr & 0xFF0000) + info->ndcb2[0] = (page_addr & 0xFF0000) >> 16; + else + info->ndcb2[0] = 0; + info->ndcb2[1] = info->ndcb2[2] = 0; + info->ndcb3[0] = info->ndcb3[1] = 0; + info->ndcb3[2] = mtd->oobsize; + info->buf_count = mtd->oobsize; + info->wait_ready[1] = 1; + nand->data_size = mtd->oobsize; + nand->oob_size = 0; + break; + case NAND_CMD_PAGEPROG: if (is_buf_blank(info->data_buff, (mtd->writesize + mtd->oobsize))) { exec_cmd = 0; @@ -1096,8 +1142,8 @@ static int prepare_command_pool(struct pxa3xx_nand *nand, int command, | NDCB0_ADDR_CYC(3) | NDCB0_DBC | cmd; - info->ndcb1 = page_addr; - info->ndcb2 = 0; + info->ndcb1[0] = page_addr; + info->ndcb2[0] = 0; break; case NAND_CMD_RESET: @@ -1245,6 +1291,21 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) return 0; } +static int pxa3xx_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page, int sndcmd) +{ + struct pxa3xx_nand_info *info = (struct pxa3xx_nand_info *)chip; + if (sndcmd) { + if ((info->page_size <= PAGE_CHUNK_SIZE) && naked_cmd_support) + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, page); + else + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + sndcmd = 0; + } + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + return sndcmd; +} + static void pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, struct pxa3xx_nand_flash *f, int show_timing) { @@ -1626,6 +1687,7 @@ static int alloc_nand_resource(struct platform_device *pdev) chip->controller = &nand->controller; chip->ecc.read_page = pxa3xx_nand_read_page_hwecc; chip->ecc.write_page = pxa3xx_nand_write_page_hwecc; + chip->ecc.read_oob = pxa3xx_nand_read_oob; chip->waitfunc = pxa3xx_nand_waitfunc; chip->select_chip = pxa3xx_nand_select_chip; chip->cmdfunc = pxa3xx_nand_cmdfunc; diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 7c871af..2e1c8b6 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -129,6 +129,7 @@ #define NDCB0_CMD_XTYPE_MASK (0x7 << 29) #define NDCB0_CMD_XTYPE(x) (((x) << 29) & NDCB0_CMD_XTYPE_MASK) +#define NDCB0_LEN_OVRD (0x1 << 28) #define NDCB0_ST_ROW_EN (0x1 << 26) #define NDCB0_AUTO_RS (0x1 << 25) #define NDCB0_CSEL (0x1 << 24) @@ -257,8 +258,9 @@ struct pxa3xx_nand_info { uint8_t total_cmds; uint8_t wait_ready[CMD_POOL_SIZE]; uint32_t ndcb0[CMD_POOL_SIZE]; - uint32_t ndcb1; - uint32_t ndcb2; + uint32_t ndcb1[CMD_POOL_SIZE]; + uint32_t ndcb2[CMD_POOL_SIZE]; + uint32_t ndcb3[CMD_POOL_SIZE]; uint32_t reg_ndcr; uint32_t ndtr0cs0; uint32_t ndtr1cs0; @@ -646,9 +648,9 @@ static void nand_error_dump(struct pxa3xx_nand *nand) printk(KERN_ERR "Totally %d command for sending\n", info->total_cmds); for (i = 0; i < info->total_cmds; i ++) - printk(KERN_ERR "NDCB0:%d: %x\n", - i, info->ndcb0[i]); - printk(KERN_ERR "NDCB1: %x; NDCB2 %x\n", info->ndcb1, info->ndcb2); + printk(KERN_ERR "==%d: NDCB0 %x, NDCB1 %x, NDCB2 %x, NDCB3 %x\n", + i, info->ndcb0[i], info->ndcb1[i], + info->ndcb2[i], info->ndcb3[i]); printk(KERN_ERR "\nRegister DUMPing ##############\n"); printk(KERN_ERR "NDCR %x\n" @@ -775,7 +777,7 @@ 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 status, is_completed = 0, cs, cmd_seqs; unsigned int ready, cmd_done, page_done, badblock_detect;