From patchwork Thu May 6 09:14:41 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Haojian Zhuang X-Patchwork-Id: 51818 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 36CB9B7D1B for ; Thu, 6 May 2010 19:16:11 +1000 (EST) Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux)) id 1O9xAP-0002Xs-2C; Thu, 06 May 2010 09:14:49 +0000 Received: from mail-pv0-f177.google.com ([74.125.83.177]) by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux)) id 1O9xAJ-0002Rv-BL; Thu, 06 May 2010 09:14:44 +0000 Received: by pvg16 with SMTP id 16so179521pvg.36 for ; Thu, 06 May 2010 02:14:42 -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=79kvOI+f1ABz51TkMqGW35tMembY4m/GLwL5At2SDM0=; b=fDixeWMGr8HFxbjqg42tamDhGNdDBTG81d+egHuxN9AtgMFSAnfXKg0R//mlz7InsN 8+SHQREiBjX/UDvolqAcSh1Bo8sdYSU+ZGtwK6Hme+PLp9R067MyjS0WB/7zc5CfJwoq mvWdho4ZN4b4BGZuzbVNtXNuS/6gw8onWGHVU= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:date:message-id:subject:from:to:content-type; b=uSnHfTd2NcgoTOwlkyRkZjKb7OkD0d+z6X9MHth/PeJizrnuIaP5719IlQU26r6PQg QoOyhkNRaq2AhPrzWtKc6i5fpnhNPA+yt+k8oGV6pZsxrWQIbHN2rtIrLyODa/8HUgS+ gc+nbSuO5T+EJXM0QA13eAC71Otitu/l8ZBCE= MIME-Version: 1.0 Received: by 10.142.152.34 with SMTP id z34mr2959753wfd.176.1273137281993; Thu, 06 May 2010 02:14:41 -0700 (PDT) Received: by 10.142.252.16 with HTTP; Thu, 6 May 2010 02:14:41 -0700 (PDT) Date: Thu, 6 May 2010 05:14:41 -0400 Message-ID: Subject: [PATCH 19/20] pxa3xx_nand: reimplment read oob command to increase performance From: Haojian Zhuang To: Eric Miao , linux-arm-kernel , David Woodhouse , linux-mtd@lists.infradead.org X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20100506_051443_597014_E4C0A637 X-CRM114-Status: GOOD ( 17.58 ) 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 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 2c4d45810e13f70f682dd95376f23cdd84bafee4 Mon Sep 17 00:00:00 2001 From: Lei Wen Date: Thu, 6 May 2010 10:43:57 +0800 Subject: [PATCH] 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;