From patchwork Fri Oct 18 23:02:50 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ezequiel Garcia X-Patchwork-Id: 3070561 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 99C0B9F243 for ; Fri, 18 Oct 2013 23:58:15 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id B9F0B204E7 for ; Fri, 18 Oct 2013 23:58:14 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A3D0E2047C for ; Fri, 18 Oct 2013 23:58:13 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1VXJBm-0006Rj-TR; Fri, 18 Oct 2013 23:10:39 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1VXJAs-0001cn-Ic; Fri, 18 Oct 2013 23:09:42 +0000 Received: from top.free-electrons.com ([176.31.233.9] helo=mail.free-electrons.com) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1VXJ5r-00017A-NA; Fri, 18 Oct 2013 23:04:34 +0000 Received: by mail.free-electrons.com (Postfix, from userid 106) id A9E5C8B8; Sat, 19 Oct 2013 01:04:16 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-4.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from localhost.localdomain (unknown [190.2.98.212]) by mail.free-electrons.com (Postfix) with ESMTPA id 17B68895; Sat, 19 Oct 2013 01:04:12 +0200 (CEST) From: Ezequiel Garcia To: , Subject: [PATCH v2 23/27] mtd: nand: pxa3xx: Add multiple chunk write support Date: Fri, 18 Oct 2013 20:02:50 -0300 Message-Id: <1382137374-21251-24-git-send-email-ezequiel.garcia@free-electrons.com> X-Mailer: git-send-email 1.8.1.5 In-Reply-To: <1382137374-21251-1-git-send-email-ezequiel.garcia@free-electrons.com> References: <1382137374-21251-1-git-send-email-ezequiel.garcia@free-electrons.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20131018_190432_121559_EC1F2807 X-CRM114-Status: GOOD ( 16.16 ) X-Spam-Score: -1.7 (-) Cc: Lior Amsalem , Thomas Petazzoni , Jason Cooper , Tawfik Bayouk , Daniel Mack , Ezequiel Garcia , Gregory Clement , Brian Norris , Willy Tarreau X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP This commit adds write support for large pages (4 KiB, 8 KiB). Such support is implemented by issuing a multiple command sequence, transfering a set of 2 KiB chunks per transaction. The splitted command sequence requires to send the SEQIN command independently of the PAGEPROG command and therefore it's set as an execution command. Since PAGEPROG enables ECC, each 2 KiB chunk of data is written together with ECC code at a controller-fixed location within the flash page. Currently, only devices with a 4 KiB page size has been tested. Signed-off-by: Ezequiel Garcia --- drivers/mtd/nand/pxa3xx_nand.c | 83 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index b297b22..5e92ef8 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -780,6 +780,20 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, info->buf_start = column; set_command_address(info, mtd->writesize, 0, page_addr); + + /* + * Multiple page programming needs to execute the initial + * SEQIN command that sets the page address. + */ + if (mtd->writesize > PAGE_CHUNK_SIZE) { + info->ndcb0 |= NDCB0_CMD_TYPE(0x1) + | NDCB0_EXT_CMD_TYPE(ext_cmd_type) + | addr_cycle + | command; + /* No data transfer in this case */ + info->data_size = 0; + exec_cmd = 1; + } break; case NAND_CMD_PAGEPROG: @@ -789,13 +803,40 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, break; } - info->ndcb0 |= NDCB0_CMD_TYPE(0x1) - | NDCB0_AUTO_RS - | NDCB0_ST_ROW_EN - | NDCB0_DBC - | (NAND_CMD_PAGEPROG << 8) - | NAND_CMD_SEQIN - | addr_cycle; + /* Second command setting for large pages */ + if (mtd->writesize > PAGE_CHUNK_SIZE) { + /* + * Multiple page write uses the 'extended command' + * field. This can be used to issue a command dispatch + * or a naked-write depending on the current stage. + */ + info->ndcb0 |= NDCB0_CMD_TYPE(0x1) + | NDCB0_LEN_OVRD + | NDCB0_EXT_CMD_TYPE(ext_cmd_type); + info->ndcb3 = info->chunk_size + + info->oob_size; + + /* + * This is the command dispatch that completes a chunked + * page program operation. + */ + if (info->data_size == 0) { + info->ndcb0 = NDCB0_CMD_TYPE(0x1) + | NDCB0_EXT_CMD_TYPE(ext_cmd_type) + | command; + info->ndcb1 = 0; + info->ndcb2 = 0; + info->ndcb3 = 0; + } + } else { + info->ndcb0 |= NDCB0_CMD_TYPE(0x1) + | NDCB0_AUTO_RS + | NDCB0_ST_ROW_EN + | NDCB0_DBC + | (NAND_CMD_PAGEPROG << 8) + | NAND_CMD_SEQIN + | addr_cycle; + } break; case NAND_CMD_PARAM: @@ -942,6 +983,15 @@ static void armada370_nand_cmdfunc(struct mtd_info *mtd, case NAND_CMD_READOOB: ext_cmd_type = EXT_CMD_TYPE_MONO; break; + case NAND_CMD_SEQIN: + ext_cmd_type = EXT_CMD_TYPE_DISPATCH; + break; + case NAND_CMD_PAGEPROG: + ext_cmd_type = EXT_CMD_TYPE_NAKED_RW; + break; + default: + ext_cmd_type = -1; + break; } prepare_start_command(info, command); @@ -979,7 +1029,16 @@ static void armada370_nand_cmdfunc(struct mtd_info *mtd, } /* Check if the sequence is complete */ - if (info->data_size == 0) + if (info->data_size == 0 && command != NAND_CMD_PAGEPROG) + break; + + /* + * After a splitted program command sequence has issued + * the command dispatch, the command sequence is complete. + */ + if (info->data_size == 0 && + command == NAND_CMD_PAGEPROG && + ext_cmd_type == EXT_CMD_TYPE_DISPATCH) break; if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) { @@ -988,6 +1047,14 @@ static void armada370_nand_cmdfunc(struct mtd_info *mtd, ext_cmd_type = EXT_CMD_TYPE_LAST_RW; else ext_cmd_type = EXT_CMD_TYPE_NAKED_RW; + + /* + * If a splitted program command has no more data to transfer, + * the command dispatch must be issued to complete. + */ + } else if (command == NAND_CMD_PAGEPROG && + info->data_size == 0) { + ext_cmd_type = EXT_CMD_TYPE_DISPATCH; } } while (1);