From patchwork Thu Mar 23 00:17:36 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 95862 Delivered-To: patch@linaro.org Received: by 10.140.89.233 with SMTP id v96csp496677qgd; Wed, 22 Mar 2017 17:31:37 -0700 (PDT) X-Received: by 10.98.31.20 with SMTP id f20mr49426755pff.193.1490229097133; Wed, 22 Mar 2017 17:31:37 -0700 (PDT) Return-Path: Received: from bombadil.infradead.org (bombadil.infradead.org. [65.50.211.133]) by mx.google.com with ESMTPS id u126si2504139pfu.306.2017.03.22.17.31.36 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 22 Mar 2017 17:31:37 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-mtd-bounces+patch=linaro.org@lists.infradead.org designates 65.50.211.133 as permitted sender) client-ip=65.50.211.133; Authentication-Results: mx.google.com; dkim=pass header.i=@lists.infradead.org; dkim=neutral (body hash did not verify) header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-mtd-bounces+patch=linaro.org@lists.infradead.org designates 65.50.211.133 as permitted sender) smtp.mailfrom=linux-mtd-bounces+patch=linaro.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:Message-Id:Date: Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Owner; bh=SKcpShnAGso+8vlRZV+3+MEseyYU+O7rHch1Dz/stU0=; b=hmx OhVbzYvOe2C+mAwWzVTFfh+yRj/y+QNQUesV12DAXPvTscbpaRjW9Mf/fOJrNK1pxuO/tzvT7qTjc MrSduggXgaGE/OkLiyMAKADNIek/5Cpr/2POosJ97PXMxe2Wc/IJW8EfM4YNwdlCRKEfAZvFrq315 hQxG1xqrhy87fldINLHKlLBfDt/vQrIP5NYbLlul+x+yayxG+LMYKDXKl7972wZsSvqyQs3ahyzTR 6uNJ4+1yZZKc9ykfTn8gAgLCjueB/zWcaFKWh5UnwQam6X2+JDWeTfTkl3Asn0iv4sXvNPB9t7ZFb OzQZx2m/55WPuZ8j6WJs52juucuI3lg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1cqqez-0002z3-TR; Thu, 23 Mar 2017 00:31:25 +0000 Received: from conuserg-09.nifty.com ([210.131.2.76]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1cqqSr-0004Z4-Mk for linux-mtd@lists.infradead.org; Thu, 23 Mar 2017 00:18:56 +0000 Received: from grover.sesame (FL1-111-169-71-157.osk.mesh.ad.jp [111.169.71.157]) (authenticated) by conuserg-09.nifty.com with ESMTP id v2N0I4bd008011; Thu, 23 Mar 2017 09:18:07 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-09.nifty.com v2N0I4bd008011 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1490228287; bh=k1UoNnDGmxSATrlakXr4gkah9wZceemeAJfP/cUTd8s=; h=From:To:Cc:Subject:Date:From; b=aDm0MfvxyN7ZYNN4irSLEG7BNLu05T/IJtzS3vUi1dCgX+b4z8zqfLSZVQKaIwNJH kluizE1iXwFYNaX4fZI5n6aoc6PwC9LmiYHE/N7igXjiZiYyrXnvRop58ygvMhnOn/ t1Wr7S05Um9OwbWKpBdiZrAHHq6SKlUu2SowZW268DVPuZKzVi3KdYESaGThaby1sk 11l2x2lKs9jc51J1HA0D/FuT7nNNv0fEU+QUL0Mnx2CcUQUiaTBHbE1PnP2hQVvZQp Ixx04EAJqgxu3g0dj07yem5OvCNGv06UM/jTu05X15TggOSIYI3b3UkABNv/5XHjRt aTiwuLBYW1JGg== X-Nifty-SrcIP: [111.169.71.157] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Subject: [RESEND PATCH v2 27/53] mtd: nand: denali: avoid hard-coding ecc.strength and ecc.bytes Date: Thu, 23 Mar 2017 09:17:36 +0900 Message-Id: <1490228282-10805-1-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170322_171854_143468_BE438AAC X-CRM114-Status: GOOD ( 17.08 ) X-Spam-Score: -1.2 (-) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-1.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.7 SPF_SOFTFAIL SPF: sender does not match SPF record (softfail) -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] 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.21 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: laurent.monat@idquantique.com, Boris Brezillon , thorsten.christiansson@idquantique.com, Dinh Nguyen , Enrico Jorns , Artem Bityutskiy , Marek Vasut , Masahiro Yamada , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Brian Norris , David Woodhouse , Rob Herring , Graham Moore MIME-Version: 1.0 Sender: "linux-mtd" Errors-To: linux-mtd-bounces+patch=linaro.org@lists.infradead.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 The 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, they 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 to handle these parameters in a more generic manner. 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 allows platforms to specify denali->ecc_strength_avail, each bit of which represents supported ECC strength. I am not using the bitmap here because "unsigned long" should be enough to cover the ECC strength of this IP. Signed-off-by: Masahiro Yamada --- Changes in v2: None drivers/mtd/nand/denali.c | 73 +++++++++++++++++++++++++++---------------- drivers/mtd/nand/denali.h | 1 + drivers/mtd/nand/denali_dt.c | 3 ++ drivers/mtd/nand/denali_pci.c | 1 + 4 files changed, 51 insertions(+), 27 deletions(-) -- 2.7.4 ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index cf8daba..96074b8 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1340,13 +1340,45 @@ 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 +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; + int ecc_strength, ecc_bytes; + int max_strength = 0; + + /* carve out the BBM area */ + oobsize -= denali->bbtskipbytes; + + for_each_set_bit(ecc_strength, &denali->ecc_strength_avail, + sizeof(denali->ecc_strength_avail) * BITS_PER_BYTE) { + ecc_bytes = denali_calc_ecc_bytes(ecc_size, ecc_strength); + if (ecc_bytes * ecc_steps > oobsize) + break; + + max_strength = ecc_strength; + } + + if (!max_strength) { + dev_err(denali->dev, + "Your NAND chip OOB is too small. No available ECC strength.\n"); + return -EINVAL; + } + + chip->ecc.strength = max_strength; + + return 0; +} static int denali_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) @@ -1595,27 +1627,14 @@ int denali_init(struct denali_nand_info *denali) goto failed_req_irq; } - /* - * 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); iowrite32(chip->ecc.size, denali->flash_reg + CFG_DATA_BLOCK_SIZE); iowrite32(chip->ecc.size, denali->flash_reg + CFG_LAST_DATA_BLOCK_SIZE); diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index aa6548a..003d234a 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -353,6 +353,7 @@ struct denali_nand_info { int bbtskipbytes; int max_banks; unsigned int revision; + unsigned long ecc_strength_avail; unsigned int caps; #define DENALI_CAP_HW_ECC_FIXUP BIT(0) #define DENALI_CAP_DMA_64BIT BIT(1) diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index 1681a30..c3bc333 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -31,10 +31,12 @@ struct denali_dt { struct denali_dt_data { unsigned int revision; + unsigned long ecc_strength_avail; unsigned int caps; }; static const struct denali_dt_data denali_socfpga_data = { + .ecc_strength_avail = BIT(15) | BIT(8), .caps = DENALI_CAP_HW_ECC_FIXUP | DENALI_CAP_ECC_SIZE_512, }; @@ -64,6 +66,7 @@ static int denali_dt_probe(struct platform_device *pdev) data = of_device_get_match_data(&pdev->dev); if (data) { denali->revision = data->revision; + denali->ecc_strength_avail = data->ecc_strength_avail; denali->caps = data->caps; } diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c index 5202a11..a1ee9f8 100644 --- a/drivers/mtd/nand/denali_pci.c +++ b/drivers/mtd/nand/denali_pci.c @@ -85,6 +85,7 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) goto failed_remap_reg; } + denali->ecc_strength_avail = BIT(15) | BIT(8); denali->caps |= DENALI_CAP_ECC_SIZE_512; ret = denali_init(denali);