From patchwork Mon Jul 28 15:31:38 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Punnaiah Choudary Kalluri X-Patchwork-Id: 374249 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2001:1868:205::9]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 1D57D140174 for ; Tue, 29 Jul 2014 01:33:57 +1000 (EST) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XBmub-0006bA-93; Mon, 28 Jul 2014 15:32:29 +0000 Received: from mail-bl2lp0203.outbound.protection.outlook.com ([207.46.163.203] helo=na01-bl2-obe.outbound.protection.outlook.com) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1XBmuS-0006JQ-Sa for linux-mtd@lists.infradead.org; Mon, 28 Jul 2014 15:32:22 +0000 Received: from BN1BFFO11FD037.protection.gbl (10.58.144.33) by BN1BFFO11HUB060.protection.gbl (10.58.144.207) with Microsoft SMTP Server (TLS) id 15.0.980.11; Mon, 28 Jul 2014 15:31:51 +0000 Received: from xsj-pvapsmtpgw01 (149.199.60.83) by BN1BFFO11FD037.mail.protection.outlook.com (10.58.144.100) with Microsoft SMTP Server (TLS) id 15.0.990.10 via Frontend Transport; Mon, 28 Jul 2014 15:31:51 +0000 Received: from unknown-38-66.xilinx.com ([149.199.38.66] helo=xsj-smtp1) by xsj-pvapsmtpgw01 with esmtp (Exim 4.63) (envelope-from ) id 1XBmqL-0000PP-Kw; Mon, 28 Jul 2014 08:28:05 -0700 From: Punnaiah Choudary Kalluri To: , , , , , , , , , , , , , , , , , , , Subject: [PATCH RFC v4 2/4] nand: pl353: Add software ecc support Date: Mon, 28 Jul 2014 21:01:38 +0530 X-Mailer: git-send-email 1.7.4 In-Reply-To: <1406561500-18264-1-git-send-email-punnaia@xilinx.com> References: <1406561500-18264-1-git-send-email-punnaia@xilinx.com> X-RCIS-Action: ALLOW Message-ID: <1ed93a4e-8a0e-4caa-a1e8-d39cf9c8e8e2@BN1BFFO11FD037.protection.gbl> X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:149.199.60.83; CTRY:US; IPV:NLI; IPV:NLI; EFV:NLI; SFV:NSPM; SFS:(6009001)(438002)(199002)(189002)(77982001)(104016003)(86362001)(4396001)(229853001)(93916002)(21056001)(6806004)(85852003)(70736001)(77096002)(83072002)(92566001)(31696002)(92726001)(74502001)(99396002)(79102001)(20776003)(81342001)(50226001)(33646002)(47776003)(107046002)(64706001)(1496007)(2201001)(95666004)(76176999)(46102001)(106466001)(85306003)(48376002)(74662001)(76482001)(87936001)(104166001)(80022001)(53416004)(89996001)(74316001)(62966002)(77156001)(88136002)(44976005)(83322001)(50466002)(81542001)(50986999)(87286001)(19580405001)(19580395003)(31966008)(102836001)(921003)(1121002)(107986001)(2101003)(217873001)(83996005); DIR:OUT; SFP:; SCL:1; SRVR:BN1BFFO11HUB060; H:xsj-pvapsmtpgw01; FPR:; MLV:sfv; PTR:unknown-60-83.xilinx.com; A:1; MX:1; LANG:en; MIME-Version: 1.0 X-OriginatorOrg: xilinx.onmicrosoft.com X-Microsoft-Antispam: BCL:0;PCL:0;RULEID: X-Forefront-PRVS: 0286D7B531 Received-SPF: Pass (: domain of xilinx.com designates 149.199.60.83 as permitted sender) receiver=; client-ip=149.199.60.83; helo=xsj-pvapsmtpgw01; Authentication-Results: spf=pass (sender IP is 149.199.60.83) smtp.mailfrom=punnaiah.choudary.kalluri@xilinx.com; X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140728_083221_140378_48345642 X-CRM114-Status: GOOD ( 14.32 ) X-Spam-Score: -1.4 (-) X-Spam-Report: SpamAssassin version 3.4.0 on bombadil.infradead.org summary: Content analysis details: (-1.4 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [207.46.163.203 listed in list.dnswl.org] -0.7 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [207.46.163.203 listed in wl.mailspike.net] -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record Cc: devicetree@vger.kernel.org, linux-doc@vger.kernel.org, svemula@xilinx.com, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, anirudh@xilinx.com, kalluripunnaiahchoudary@gmail.com, kpc528@gmail.com, Punnaiah Choudary Kalluri X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Added software ecc support. Signed-off-by: Punnaiah Choudary Kalluri --- Changes in v4: - Updated the driver to sync with pl353_smc driver APIs --- drivers/mtd/nand/pl353_nand.c | 164 +++++++++++++++++++++++++++++++++++++++++ 1 files changed, 164 insertions(+), 0 deletions(-) diff --git a/drivers/mtd/nand/pl353_nand.c b/drivers/mtd/nand/pl353_nand.c index f97f428..93dc4ca 100644 --- a/drivers/mtd/nand/pl353_nand.c +++ b/drivers/mtd/nand/pl353_nand.c @@ -319,6 +319,71 @@ static int pl353_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, } /** + * pl353_nand_read_page_raw - [Intern] read raw page data without ecc + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @buf: Pointer to the data buffer + * @oob_required: Caller requires OOB data read to chip->oob_poi + * @page: Page number to read + * + * Return: Always return zero + */ +static int pl353_nand_read_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + unsigned long data_phase_addr; + uint8_t *p; + + chip->read_buf(mtd, buf, mtd->writesize); + + p = chip->oob_poi; + chip->read_buf(mtd, p, + (mtd->oobsize - PL353_NAND_LAST_TRANSFER_LENGTH)); + p += (mtd->oobsize - PL353_NAND_LAST_TRANSFER_LENGTH); + + data_phase_addr = (unsigned long __force)chip->IO_ADDR_R; + data_phase_addr |= PL353_NAND_CLEAR_CS; + chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr; + + chip->read_buf(mtd, p, PL353_NAND_LAST_TRANSFER_LENGTH); + return 0; +} + +/** + * pl353_nand_write_page_raw - [Intern] raw page write function + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @buf: Pointer to the data buffer + * @oob_required: Caller requires OOB data read to chip->oob_poi + * + * Return: Always return zero + */ +static int pl353_nand_write_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf, int oob_required) +{ + unsigned long data_phase_addr; + uint8_t *p; + + chip->write_buf(mtd, buf, mtd->writesize); + + p = chip->oob_poi; + chip->write_buf(mtd, p, + (mtd->oobsize - PL353_NAND_LAST_TRANSFER_LENGTH)); + p += (mtd->oobsize - PL353_NAND_LAST_TRANSFER_LENGTH); + + data_phase_addr = (unsigned long __force)chip->IO_ADDR_W; + data_phase_addr |= PL353_NAND_CLEAR_CS; + data_phase_addr |= (1 << END_CMD_VALID_SHIFT); + chip->IO_ADDR_W = (void __iomem * __force)data_phase_addr; + + chip->write_buf(mtd, p, PL353_NAND_LAST_TRANSFER_LENGTH); + + return 0; +} + +/** * nand_write_page_hwecc - Hardware ECC based page write function * @mtd: Pointer to the mtd info structure * @chip: Pointer to the NAND chip info structure @@ -384,6 +449,39 @@ static int pl353_nand_write_page_hwecc(struct mtd_info *mtd, } /** + * pl353_nand_write_page_swecc - [REPLACABLE] software ecc based page write + * function + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @buf: Pointer to the data buffer + * @oob_required: Caller requires OOB data read to chip->oob_poi + * + * Return: Always return zero + */ +static int pl353_nand_write_page_swecc(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf, + int oob_required) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *ecc_calc = chip->buffers->ecccalc; + const uint8_t *p = buf; + uint32_t *eccpos = chip->ecc.layout->eccpos; + + /* Software ecc calculation */ + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) + chip->ecc.calculate(mtd, p, &ecc_calc[i]); + + for (i = 0; i < chip->ecc.total; i++) + chip->oob_poi[eccpos[i]] = ecc_calc[i]; + + chip->ecc.write_page_raw(mtd, chip, buf, 1); + + return 0; +} + +/** * pl353_nand_read_page_hwecc - Hardware ECC based page read function * @mtd: Pointer to the mtd info structure * @chip: Pointer to the NAND chip info structure @@ -465,6 +563,52 @@ static int pl353_nand_read_page_hwecc(struct mtd_info *mtd, } /** + * pl353_nand_read_page_swecc - [REPLACABLE] software ecc based page read + * function + * @mtd: Pointer to the mtd info structure + * @chip: Pointer to the NAND chip info structure + * @buf: Pointer to the buffer to store read data + * @oob_required: Caller requires OOB data read to chip->oob_poi + * @page: Page number to read + * + * Return: Always return zero + */ +static int pl353_nand_read_page_swecc(struct mtd_info *mtd, + struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *p = buf; + uint8_t *ecc_calc = chip->buffers->ecccalc; + uint8_t *ecc_code = chip->buffers->ecccode; + uint32_t *eccpos = chip->ecc.layout->eccpos; + + chip->ecc.read_page_raw(mtd, chip, buf, page, 1); + + for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) + chip->ecc.calculate(mtd, p, &ecc_calc[i]); + + for (i = 0; i < chip->ecc.total; i++) + ecc_code[i] = chip->oob_poi[eccpos[i]]; + + eccsteps = chip->ecc.steps; + p = buf; + + for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + int stat; + + stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + } + return 0; +} + +/** * pl353_nand_select_chip - Select the flash device * @mtd: Pointer to the mtd info structure * @chip: Pointer to the NAND chip info structure @@ -689,6 +833,8 @@ static int pl353_nand_ecc_init(struct mtd_info *mtd) nand_chip->ecc.read_oob = pl353_nand_read_oob; nand_chip->ecc.write_oob = pl353_nand_write_oob; nand_chip->ecc.strength = 1; + nand_chip->ecc.read_page_raw = pl353_nand_read_page_raw; + nand_chip->ecc.write_page_raw = pl353_nand_write_page_raw; switch (xnand->ecc_mode) { case NAND_ECC_HW: @@ -715,6 +861,24 @@ static int pl353_nand_ecc_init(struct mtd_info *mtd) nand_chip->ecc.layout = &nand_oob_64; break; + case NAND_ECC_SOFT: + /* + * The software ECC routines won't work with the + * SMC controller + */ + nand_chip->ecc.mode = NAND_ECC_HW; + nand_chip->ecc.calculate = nand_calculate_ecc; + nand_chip->ecc.correct = nand_correct_data; + nand_chip->ecc.read_page = pl353_nand_read_page_swecc; + nand_chip->ecc.write_page = pl353_nand_write_page_swecc; + nand_chip->ecc.size = 256; + nand_chip->ecc.bytes = 3; + /* Bypass the controller ECC block */ + pl353_smc_set_ecc_pg_size(mtd->dev.parent, mtd->writesize); + pl353_smc_set_ecc_mode(mtd->dev.parent, + PL353_SMC_ECCMODE_BYPASS); + + break; default: return -ENOTSUPP; }