From patchwork Fri May 14 06:16:00 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Haojian Zhuang X-Patchwork-Id: 52551 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 1B140B7E6A for ; Fri, 14 May 2010 16:17:37 +1000 (EST) Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux)) id 1OCoC1-0007IQ-BU; Fri, 14 May 2010 06:16:17 +0000 Received: from mail-px0-f177.google.com ([209.85.212.177]) by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux)) id 1OCoBl-0006Pu-RH; Fri, 14 May 2010 06:16:03 +0000 Received: by pxi1 with SMTP id 1so1195171pxi.36 for ; Thu, 13 May 2010 23:16:00 -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=ySXPag8gseGvO2OTBh3Vo4ZIXDF3lJSyRnwDWvfqkU0=; b=CGYfIZ4L1qqUcyfofCMoqcU2leAyECBSMngTEjBl+dqSkFo6+6Rold8if5zhoR2GgC 4VEtn/w6uJ1VmLqaktlMKiqWlCqyqUDT8jC5POWAhJVx8DuAIQAyroTEUsMRQh9gRmqo WvENhjhyNwOXGYzuxcU1cgF6zVw/6q5zVg1kg= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:date:message-id:subject:from:to:content-type; b=bHBAs40+wyKpC9wIQwLyQ26Hiv07XnNI7UqWM1JkHr21cc74FRPXdItDPF62LxamAT ja8vzQQK8FGBBwLgvrC9exOVFwSmTSCKUql3VyGVg4xZqTWiKdKVVB1pXSU/xjBFs22g G2IyMI+V/wiPcqbr9OXnLnFpeGL5MTdG6P7wM= MIME-Version: 1.0 Received: by 10.142.201.11 with SMTP id y11mr401352wff.118.1273817760525; Thu, 13 May 2010 23:16:00 -0700 (PDT) Received: by 10.142.252.16 with HTTP; Thu, 13 May 2010 23:16:00 -0700 (PDT) Date: Fri, 14 May 2010 14:16:00 +0800 Message-ID: Subject: [PATCH 06/20] mtd: pxa3xx_nand: unify prepare command From: Haojian Zhuang To: Marc Kleine-Budde , David Woodhouse , David Woodhouse , Eric Miao , linux-arm-kernel , linux-mtd@lists.infradead.org X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20100514_021602_113414_DB639BA7 X-CRM114-Status: GOOD ( 23.88 ) 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.212.177 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 805911c6b0f1f0c1f5f4d9395bb16366fa4d5ea1 Mon Sep 17 00:00:00 2001 From: Lei Wen Date: Mon, 22 Mar 2010 12:04:22 +0800 Subject: [PATCH] mtd: pxa3xx_nand: unify prepare command Make the interface simpler which could make both debug and enhancement easier. Signed-off-by: Lei Wen Signed-off-by: Haojian Zhuang --- drivers/mtd/nand/pxa3xx_nand.c | 256 +++++++++++++++++++++------------------- 1 files changed, 136 insertions(+), 120 deletions(-) diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 85de7f7..854adad 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -28,6 +28,7 @@ #define CHIP_DELAY_TIMEOUT (2 * HZ/10) #define NAND_STOP_DELAY (2 * HZ/50) +#define PAGE_CHUNK_SIZE (2048) /* registers and bit definitions */ #define NDCR (0x00) /* Control register */ @@ -78,6 +79,7 @@ #define NDSR_RDDREQ (0x1 << 1) #define NDSR_WRCMDREQ (0x1) +#define NDCB0_ST_ROW_EN (0x1 << 26) #define NDCB0_AUTO_RS (0x1 << 25) #define NDCB0_CSEL (0x1 << 24) #define NDCB0_CMD_TYPE_MASK (0x7 << 21) @@ -334,7 +336,7 @@ static void pxa3xx_nand_start(struct pxa3xx_nand_info *info) uint32_t ndcr; ndcr = info->reg_ndcr; - ndcr |= NDCR_ECC_EN; + ndcr |= info->use_ecc ? NDCR_ECC_EN : 0; ndcr |= info->use_dma ? NDCR_DMA_EN : NDCR_STOP_ON_UNCOR; ndcr |= NDCR_ND_RUN; @@ -363,61 +365,6 @@ static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info) } } -static void prepare_read_prog_cmd(struct pxa3xx_nand_info *info, - uint16_t cmd, int column, int page_addr) -{ - pxa3xx_set_datasize(info); - - /* generate values for NDCBx registers */ - info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); - info->ndcb1 = 0; - info->ndcb2 = 0; - info->ndcb0 |= NDCB0_ADDR_CYC(info->row_addr_cycles + info->col_addr_cycles); - - if (info->col_addr_cycles == 2) { - /* large block, 2 cycles for column address - * row address starts from 3rd cycle - */ - info->ndcb1 |= page_addr << 16; - if (info->row_addr_cycles == 3) - info->ndcb2 = (page_addr >> 16) & 0xff; - } else - /* small block, 1 cycles for column address - * row address starts from 2nd cycle - */ - info->ndcb1 = page_addr << 8; - - if (cmd == cmdset.program) - info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS; -} - -static void prepare_erase_cmd(struct pxa3xx_nand_info *info, - uint16_t cmd, int page_addr) -{ - info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); - info->ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS | NDCB0_ADDR_CYC(3); - info->ndcb1 = page_addr; - info->ndcb2 = 0; -} - -static void prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd) -{ - info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); - info->ndcb1 = 0; - info->ndcb2 = 0; - - if (cmd == cmdset.read_id) { - info->ndcb0 |= NDCB0_CMD_TYPE(3); - info->data_size = 8; - } else if (cmd == cmdset.read_status) { - info->ndcb0 |= NDCB0_CMD_TYPE(4); - info->data_size = 8; - } else if (cmd == cmdset.reset || cmd == cmdset.lock || - cmd == cmdset.unlock) { - info->ndcb0 |= NDCB0_CMD_TYPE(5); - } -} - static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) { uint32_t ndcr; @@ -555,94 +502,167 @@ static inline int is_buf_blank(uint8_t *buf, size_t len) return 1; } -static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, - int column, int page_addr) +static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, + uint16_t column, int page_addr) { - struct pxa3xx_nand_info *info = mtd->priv; - int ret, exec_cmd = 0; + uint16_t cmd; + int addr_cycle, exec_cmd, ndcb0; + struct mtd_info *mtd = info->mtd; + + ndcb0 = 0; + addr_cycle = 0; + exec_cmd = 1; - info->use_dma = (use_dma) ? 1 : 0; - info->use_ecc = 0; - info->data_size = 0; - info->state = 0; + /* reset data and oob column point to handle data */ + info->buf_start = 0; + info->buf_count = 0; + info->oob_size = 0; + info->use_ecc = 0; switch (command) { + case NAND_CMD_READ0: + case NAND_CMD_PAGEPROG: + info->use_ecc = 1; case NAND_CMD_READOOB: - /* disable HW ECC to get all the OOB data */ - info->buf_count = mtd->writesize + mtd->oobsize; - info->buf_start = mtd->writesize + column; - memset(info->data_buff, 0xFF, info->buf_count); + pxa3xx_set_datasize(info); + break; + case NAND_CMD_SEQIN: + exec_cmd = 0; + break; + default: + info->ndcb1 = 0; + info->ndcb2 = 0; + break; + } - prepare_read_prog_cmd(info, cmdset.read1, column, page_addr); + info->ndcb0 = ndcb0; + addr_cycle = NDCB0_ADDR_CYC(info->row_addr_cycles + + info->col_addr_cycles); - /* We only are OOB, so if the data has error, does not matter */ - if (info->retcode == ERR_DBERR) - info->retcode = ERR_NONE; + switch (command) { + case NAND_CMD_READOOB: + case NAND_CMD_READ0: - exec_cmd = 1; - break; + cmd = cmdset.read1; + if (command == NAND_CMD_READOOB) + info->buf_start = mtd->writesize + column; + else + info->buf_start = column; + + if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) + info->ndcb0 |= NDCB0_CMD_TYPE(0) + | addr_cycle + | (cmd & NDCB0_CMD1_MASK); + else + info->ndcb0 |= NDCB0_CMD_TYPE(0) + | NDCB0_DBC + | addr_cycle + | cmd; - case NAND_CMD_READ0: - info->use_ecc = 1; - info->retcode = ERR_NONE; - info->buf_start = column; - info->buf_count = mtd->writesize + mtd->oobsize; - memset(info->data_buff, 0xFF, info->buf_count); + case NAND_CMD_SEQIN: + /* small page addr setting */ + if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) { + info->ndcb1 = ((page_addr & 0xFFFFFF) << 8) + | (column & 0xFF); - prepare_read_prog_cmd(info, cmdset.read1, column, page_addr); - if (info->retcode == ERR_DBERR) { - /* for blank page (all 0xff), HW will calculate its ECC as - * 0, which is different from the ECC information within - * OOB, ignore such double bit errors - */ - if (is_buf_blank(info->data_buff, mtd->writesize)) - info->retcode = ERR_NONE; + info->ndcb2 = 0; + } + else { + info->ndcb1 = ((page_addr & 0xFFFF) << 16) + | (column & 0xFFFF); + + if (page_addr & 0xFF0000) + info->ndcb2 = (page_addr & 0xFF0000) >> 16; + else + info->ndcb2 = 0; } - exec_cmd = 1; - break; - case NAND_CMD_SEQIN: - info->buf_start = column; info->buf_count = mtd->writesize + mtd->oobsize; - memset(info->data_buff, 0xff, info->buf_count); + memset(info->data_buff, 0xFF, info->buf_count); - /* save column/page_addr for next CMD_PAGEPROG */ - info->seqin_column = column; - info->seqin_page_addr = page_addr; break; + case NAND_CMD_PAGEPROG: - info->use_ecc = (info->seqin_column >= mtd->writesize) ? 0 : 1; + if (is_buf_blank(info->data_buff, (mtd->writesize + mtd->oobsize))) { + exec_cmd = 0; + break; + } - prepare_read_prog_cmd(info, cmdset.program, - info->seqin_column, info->seqin_page_addr); + cmd = cmdset.program; info->state |= STATE_IS_WRITE; - exec_cmd = 1; - break; - case NAND_CMD_ERASE1: - prepare_erase_cmd(info, cmdset.erase, page_addr); - exec_cmd = 1; - case NAND_CMD_ERASE2: + info->ndcb0 |= NDCB0_CMD_TYPE(0x1) + | NDCB0_AUTO_RS + | NDCB0_ST_ROW_EN + | NDCB0_DBC + | cmd + | addr_cycle; break; + case NAND_CMD_READID: + cmd = cmdset.read_id; + info->buf_count = info->read_id_bytes; + info->ndcb0 |= NDCB0_CMD_TYPE(3) + | NDCB0_ADDR_CYC(1) + | cmd; + + info->data_size = 8; + break; + case NAND_CMD_STATUS: - info->use_dma = 0; /* force PIO read */ - info->buf_start = 0; - info->buf_count = (command == NAND_CMD_READID) ? - info->read_id_bytes : 1; - - prepare_other_cmd(info, (command == NAND_CMD_READID) ? - cmdset.read_id : cmdset.read_status); - exec_cmd = 1; + cmd = cmdset.read_status; + info->buf_count = 1; + info->ndcb0 |= NDCB0_CMD_TYPE(4) + | NDCB0_ADDR_CYC(1) + | cmd; + + info->data_size = 8; + break; + + case NAND_CMD_ERASE1: + cmd = cmdset.erase; + info->ndcb0 |= NDCB0_CMD_TYPE(2) + | NDCB0_AUTO_RS + | NDCB0_ADDR_CYC(3) + | NDCB0_DBC + | cmd; + info->ndcb1 = page_addr; + info->ndcb2 = 0; + break; case NAND_CMD_RESET: - prepare_other_cmd(info, cmdset.reset); - exec_cmd = 1; + cmd = cmdset.reset; + info->ndcb0 |= NDCB0_CMD_TYPE(5) + | cmd; + break; + + case NAND_CMD_ERASE2: + exec_cmd = 0; + break; + default: - printk(KERN_ERR "non-supported command.\n"); + exec_cmd = 0; + printk(KERN_ERR "pxa3xx-nand: non-supported command %x\n", command); break; } + return exec_cmd; +} + +static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, + int column, int page_addr) +{ + struct pxa3xx_nand_info *info = mtd->priv; + int ret, exec_cmd; + + /* if this is a x16 device ,then convert the input + * "byte" address into a "word" address appropriate + * for indexing a word-oriented device + */ + if (info->reg_ndcr & NDCR_DWIDTH_M) + column /= 2; + + exec_cmd = prepare_command_pool(info, command, column, page_addr); if (exec_cmd) { init_completion(&info->cmd_complete); info->state |= STATE_CMD_PREPARED; @@ -657,10 +677,6 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, pxa3xx_nand_stop(info); disable_int(info, NDCR_INT_MASK); info->state &= ~STATE_CMD_PREPARED; - if (info->retcode == ERR_DBERR) { - printk(KERN_ERR "double bit error @ page %08x\n", page_addr); - info->retcode = ERR_NONE; - } } }