From patchwork Thu Mar 30 06:45:59 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 96223 Delivered-To: patch@linaro.org Received: by 10.140.89.233 with SMTP id v96csp101936qgd; Wed, 29 Mar 2017 23:47:59 -0700 (PDT) X-Received: by 10.99.101.197 with SMTP id z188mr4444132pgb.164.1490856479169; Wed, 29 Mar 2017 23:47:59 -0700 (PDT) Return-Path: Received: from bombadil.infradead.org (bombadil.infradead.org. [65.50.211.133]) by mx.google.com with ESMTPS id t70si1257527pgd.7.2017.03.29.23.47.58 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 29 Mar 2017 23:47:59 -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:References: In-Reply-To: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:List-Owner; bh=G/PAZYh2aeOOzQ8cRDqely/f1Oa902Ke2qeWN3mCo8A=; b=NXhsxK6XHFBeuAVMrQqe++Vj7K pvOwnC7qacAish94FZCHedWMVGNAQ+YFcLPfJdBo/g2EW33Zoh9HkjERZCdxKEh1HaBvC+qeMpHz+ SyrEsOEC7oHMOggOD5YvjUPsIzTkMrYoUw2MmyJ1mMU4HdMKvxrejXxctIdNiqx/Uo8k43zIk7jyv i9iu8epGg4VHmy1pGxzMi5wRxK97J7baaqL900cUNaZzlqWPyUlZfjlipC2RFxDcjwKG9AH8kfhRB Jd6kgc+IfKLRI447ZhHGCAmllbcNPsNeGnSp7G8iEH/VhNsoca4xwWiJsPy5UwaEImE+xyXDJGUa2 0qY71Eew==; 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 1ctTs9-0007O8-Fc; Thu, 30 Mar 2017 06:47:53 +0000 Received: from conuserg-07.nifty.com ([210.131.2.74]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1ctTs2-0007E4-HH for linux-mtd@lists.infradead.org; Thu, 30 Mar 2017 06:47:51 +0000 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-07.nifty.com with ESMTP id v2U6kUcb015463; Thu, 30 Mar 2017 15:46:48 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com v2U6kUcb015463 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1490856409; bh=VB83ZxRiD2pMO5EFls5reBsWMACzXPBpyR7XQ5oJ/a0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rHPsKvgsIVYg8kIjJX8MdKZBkmmwkcoQOzZUPaJqwWLziFddtIoXs1VUucS24K/zW 2Mk3V2c8b0jPCJ2us8cxuh0b2WwDhBZg6mfiS8Ug1LLhcfZDlFmNH0+DhfhOAqixMS QAx44jxWN2F6zMY2/yWOlL4lYq1aGjKgPoE70f4flgnlZiB7I0eFRQX9YND7X3OVO4 WAhI3FPgTfAyZ8+kbTvczVVkuSaVMyGFIHwy897nbrlh8W4TBN17P+5vMEAVIfRhxZ PcjGUqYB19naH1JRsxZIanjNXmDXtR8Fubu2a/qJU9x4sWeluWzTbVAGH9NvFPyfbx srZrrsD8IqDbA== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Subject: [PATCH v3 13/37] mtd: nand: denali: avoid hard-coding ecc.strength and ecc.bytes Date: Thu, 30 Mar 2017 15:45:59 +0900 Message-Id: <1490856383-31560-14-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1490856383-31560-1-git-send-email-yamada.masahiro@socionext.com> References: <1490856383-31560-1-git-send-email-yamada.masahiro@socionext.com> X-Spam-Note: CRM114 invocation failed 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: Boris Brezillon , Richard Weinberger , Dinh Nguyen , Masahiro Yamada , Artem Bityutskiy , Cyrille Pitchen , linux-kernel@vger.kernel.org, Marek Vasut , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Brian Norris , Enrico Jorns , David Woodhouse , 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. Signed-off-by: Masahiro Yamada --- Changes in v3: None 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 78d3b18..ce87b95 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1344,13 +1344,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) @@ -1609,27 +1641,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 7c24d82..00ce04e 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -348,6 +348,7 @@ struct denali_nand_info { int bbtskipbytes; int max_banks; unsigned int revision; + unsigned long ecc_strength_avail; unsigned int caps; }; 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);