From patchwork Sat Nov 26 18:06:21 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 84301 Delivered-To: patch@linaro.org Received: by 10.182.1.168 with SMTP id 8csp788074obn; Sat, 26 Nov 2016 10:14:25 -0800 (PST) X-Received: by 10.98.148.26 with SMTP id m26mr13579853pfe.17.1480184065610; Sat, 26 Nov 2016 10:14:25 -0800 (PST) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id z70si49409105pff.228.2016.11.26.10.14.25; Sat, 26 Nov 2016 10:14:25 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753943AbcKZSOO (ORCPT + 25 others); Sat, 26 Nov 2016 13:14:14 -0500 Received: from conuserg-11.nifty.com ([210.131.2.78]:48176 "EHLO conuserg-11.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753198AbcKZSIX (ORCPT ); Sat, 26 Nov 2016 13:08:23 -0500 Received: from grover.sesame (FL1-111-169-71-157.osk.mesh.ad.jp [111.169.71.157]) (authenticated) by conuserg-11.nifty.com with ESMTP id uAQI6Uf7018512; Sun, 27 Nov 2016 03:07:01 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-11.nifty.com uAQI6Uf7018512 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1480183622; bh=B2ZvsG7bif5GXsuspAm5dq+nzb/XCCepNX5jqaT2yaU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=OprU12biKWOcP7IVtmx7jmtOlqiAXwKjJzGfw0F2zlsMVFFkZQdpnHL9jdjpuCNCO uX6YP6UbNqyTwUx7RS4w1eClczVzKBdoS7NXhovzx+sFOpaXsy5XWHR9ZvEw0+CoKt ObzXuLB3/29FQ2rMEhlU3392wfvZ8dsJUvU/ga6y33PlLsIq6Yec0XK0GpouQBz/iN +M6Zk1fLh3tDiUQQbVWjDqVnG1mJ1yLBmuSN6C1Eo1HguwBmN6jclEzuQijM35srMZ /oKGOOCsL2JC76+m3J/XgrtXqKS/4OeQklNepLAEvYYXaCEZfIxdD6BYayDZZED4cW t8tM6lc13Z5eQ== X-Nifty-SrcIP: [111.169.71.157] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Masahiro Yamada , linux-kernel@vger.kernel.org, Boris Brezillon , Marek Vasut , Brian Norris , Richard Weinberger , David Woodhouse , Cyrille Pitchen Subject: [PATCH 35/39] mtd: nand: denali: calculate ecc.strength and ecc.bytes generically Date: Sun, 27 Nov 2016 03:06:21 +0900 Message-Id: <1480183585-592-36-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1480183585-592-1-git-send-email-yamada.masahiro@socionext.com> References: <1480183585-592-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Another problem of this driver is hard-coded ecc.strength and ecc.bytes. Currently ecc.bytes is defined as follows: #define ECC_8BITS 14 #define ECC_15BITS 26 Such parameters were hard-coded because only the following two cases are possible on Intel platforms: - ecc.size = 512, ecc.strength = 8 --> ecc.bytes = 14 - ecc.size = 512, ecc.strength = 15 --> ecc.bytes = 26 However, these are actually customizable parameters, for example, UniPhier platform supports the following: - ecc.size = 1024, ecc.strength = 8 --> ecc.bytes = 14 - ecc.size = 1024, ecc.strength = 16 --> ecc.bytes = 28 - ecc.size = 1024, ecc.strength = 24 --> ecc.bytes = 42 So, we need somehow a generic way to calculate these parameters. Fortunately, the Denali User's Guide explains how to calculate the ecc.bytes. The formula is: ecc.bytes = 2 * CEIL(13 * ecc.strength / 16) (for ecc.size = 512) ecc.bytes = 2 * CEIL(14 * ecc.strength / 16) (for ecc.size = 1024) This commit implements two functions denali_calc_ecc_bytes() and denali_set_max_ecc_strength() to prepare for the next commit, where I will allow to use SoC-dependent ecc.strength values. Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/denali.c | 72 +++++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 27 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index c17e92b..f2ed3f8 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1354,13 +1354,44 @@ static void denali_hw_init(struct denali_nand_info *denali) denali_irq_init(denali); } -/* - * Althogh controller spec said SLC ECC is forceb to be 4bit, - * but denali controller in MRST only support 15bit and 8bit ECC - * correction - */ -#define ECC_8BITS 14 -#define ECC_15BITS 26 +/* default of supported ECC strength for Intel platforms. */ +static const int denali_default_ecc_strength[] = { + 15, 8, 0, +}; + +static int denali_calc_ecc_bytes(int ecc_size, int ecc_strength) +{ + WARN_ON(ecc_size != 512 && ecc_size != 1024); + + return DIV_ROUND_UP(ecc_strength * (ecc_size == 512 ? 13 : 14), 16) * 2; +} + +static int denali_set_max_ecc_strength(struct denali_nand_info *denali) +{ + struct nand_chip *chip = &denali->nand; + struct mtd_info *mtd = nand_to_mtd(chip); + int oobsize = mtd->oobsize; + int ecc_size = chip->ecc.size; + int ecc_steps = mtd->writesize / chip->ecc.size; + const int *ecc_strength = denali_default_ecc_strength; + int ecc_bytes; + + /* carve out the BBM area */ + oobsize -= denali->bbtskipbytes; + + for (; *ecc_strength; ecc_strength++) { + ecc_bytes = denali_calc_ecc_bytes(ecc_size, *ecc_strength); + if (oobsize >= ecc_bytes * ecc_steps) { + chip->ecc.strength = *ecc_strength; + return 0; + } + } + + dev_err(denali->dev, + "Your NAND chip OOB is too small. No available ECC strength.\n"); + + return -EINVAL; +} static int denali_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) @@ -1594,27 +1625,14 @@ int denali_init(struct denali_nand_info *denali) chip->ecc.size = denali->caps & DENALI_CAPS_ECC_SIZE_1024 ? 1024 : 512; - /* - * Denali Controller only support 15bit and 8bit ECC in MRST, - * so just let controller do 15bit ECC for MLC and 8bit ECC for - * SLC if possible. - * */ - if (!nand_is_slc(chip) && - mtd->oobsize >= denali->bbtskipbytes + - ECC_15BITS * (mtd->writesize / chip->ecc.size)) { - /* if MLC OOB size is large enough, use 15bit ECC*/ - chip->ecc.strength = 15; - chip->ecc.bytes = ECC_15BITS; - iowrite32(15, denali->flash_reg + ECC_CORRECTION); - } else if (mtd->oobsize < - denali->bbtskipbytes + ECC_8BITS * (mtd->writesize / chip->ecc.size)) { - pr_err("Your NAND chip OOB is not large enough to contain 8bit ECC correction codes"); + ret = denali_set_max_ecc_strength(denali); + if (ret) goto failed_req_irq; - } else { - chip->ecc.strength = 8; - chip->ecc.bytes = ECC_8BITS; - iowrite32(8, denali->flash_reg + ECC_CORRECTION); - } + + chip->ecc.bytes = denali_calc_ecc_bytes(chip->ecc.size, + chip->ecc.strength); + + iowrite32(chip->ecc.strength, denali->flash_reg + ECC_CORRECTION); mtd_set_ooblayout(mtd, &denali_ooblayout_ops);