From patchwork Wed Jun 7 11:52:10 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103233 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1714701obh; Wed, 7 Jun 2017 04:55:25 -0700 (PDT) X-Received: by 10.84.132.42 with SMTP id 39mr17400290ple.226.1496836525149; Wed, 07 Jun 2017 04:55:25 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836525; cv=none; d=google.com; s=arc-20160816; b=QWXUt5c9zFeeAYOzJ0gTQS0qPGP9faTAA8V4Fe4ImgcixplYK4KQI90Wiik87qhfb/ U1y6FlPZgL7trgfR5dIDG/DOnoC528f/mElBwLFdA0SwrAh7JMwe2Sm9fEScewtHPKts 4Zc+rzUwRrnZSIU9PMLQU4/Le1dDATb39vFz2UBH7jzWKRI/Ie2qOljOi/fitj/twFf8 8QkJvp1H9RhPhxsQ0zJajMZxK8VX+1RWljRWx0IHN3hZ05wk6eP+/wlYlmBZfItii/Oq lA1ZWXdQlY0fnqPjqCWFxMYAtj36qGYO3qE1h22WJZTK0BueZ4LRvcL+HIP6SlcS0SwM HIbA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=jUlxjC/Xaihv0QkagYWdPNFZwtUsTd1odHnwxuR5iP8=; b=YLgplYAWpyxbm0wyCiUfAbTcCf1PoogiS63EsamGwqDlSeN8CWrUWco7tHcQLHM2QA K0ITuXyuws/2qbe3A9b/P4YIAh+I9FgZym2Zdf16htQJA/O/38Guxkt87QApm8Bu2I+T /L2VybES48MEWpNYmJf4euU8dzvMvXGdd8I3PyxZqDyLmrk3hPrODog9qFRocJosgmZu jrNaRdP9UDz0u4uZg2M0shf2TJU9laDR4KyhgoWF5kf65AipJa4xTlorJwQEm+gVUJHP MSgVxAneeZhVSOIqz8QIq/TCGY0fegUzYsrL9Swhw5EwFYKawtLGdOUw2Yn6LMTTeX4c 7Clw== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id s25si1146992pfe.397.2017.06.07.04.55.24; Wed, 07 Jun 2017 04:55:25 -0700 (PDT) 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 S1751545AbdFGLzW (ORCPT + 25 others); Wed, 7 Jun 2017 07:55:22 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42353 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751403AbdFGLzT (ORCPT ); Wed, 7 Jun 2017 07:55:19 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZQ014276; Wed, 7 Jun 2017 20:52:47 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZQ014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836368; bh=jUlxjC/Xaihv0QkagYWdPNFZwtUsTd1odHnwxuR5iP8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uG1+MG8VB5/6ygnQtHxzpzE+oNlOwtBAsvUPRDour9dNCp8R/Xl5IpIHRqQy9q933 +OrWfQcyJrWzaiy2Bm21B9iirtoWG1hv74efz32SGhtsBpbhK0HrPC4xgAaAEJxBVX zxt/9BExsKQNuD9AJFDfC3bTXUzFVC8KZL4T17s7MVAy19QZgsER9uZZlsLL70NYqz Qss50yKtiKYAsohLfwIXjJJ428WbQeX6w4twD/Aez+Mgp2OqtZINxV6Fexxni9X/jA 1cb7o8xvu5trOTW3LWkaFJZ5H+XeprjuJxmTrw1m34MU5Lf07kujH/8Lajr4yz5YX5 Z4O5i/EkMCMxQ== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 01/23] mtd: nand: add generic helpers to check, match, maximize ECC settings Date: Wed, 7 Jun 2017 20:52:10 +0900 Message-Id: <1496836352-8016-2-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 Driver are responsible for setting up ECC parameters correctly. Those include: - Check if ECC parameters specified (usually by DT) are valid - Meet the chip's ECC requirement - Maximize ECC strength if NAND_ECC_MAXIMIZE flag is set The logic can be generalized by factoring out common code. This commit adds 3 helpers to the NAND framework: nand_check_ecc_caps - Check if preset step_size and strength are valid nand_match_ecc_req - Match the chip's requirement nand_maximize_ecc - Maximize the ECC strength To use the helpers above, a driver needs to provide: - Data array of supported ECC step size and strength - A hook that calculates ECC bytes from the combination of step_size and strength. By using those helpers, code duplication among drivers will be reduced. Signed-off-by: Masahiro Yamada --- Changes in v5: - Move oobavail from struct nand_ecc_caps to function argument - Do not use goto label - Drop mtd_info from func args - Remove extra blank line Changes in v4: - Newly added Changes in v3: None Changes in v2: None drivers/mtd/nand/nand_base.c | 220 +++++++++++++++++++++++++++++++++++++++++++ include/linux/mtd/nand.h | 33 +++++++ 2 files changed, 253 insertions(+) -- 2.7.4 diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index bdfa903cd355..dc0db1011761 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -4509,6 +4509,226 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd) } } +/** + * nand_check_ecc_caps - check the sanity of preset ECC settings + * @chip: nand chip info structure + * @caps: ECC caps info structure + * @oobavail: OOB size that the ECC engine can use + * + * When ECC step size and strength are already set, check if they are supported + * by the controller and the calculated ECC bytes fit within the chip's OOB. + * On success, the calculated ECC bytes is set. + */ +int nand_check_ecc_caps(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + const struct nand_ecc_step_info *stepinfo; + int preset_step = chip->ecc.size; + int preset_strength = chip->ecc.strength; + int nsteps, ecc_bytes; + int i, j; + + if (WARN_ON(oobavail < 0)) + return -EINVAL; + + if (!preset_step || !preset_strength) + return -ENODATA; + + nsteps = mtd->writesize / preset_step; + + for (i = 0; i < caps->nstepinfos; i++) { + stepinfo = &caps->stepinfos[i]; + + if (stepinfo->stepsize != preset_step) + continue; + + for (j = 0; j < stepinfo->nstrengths; j++) { + if (stepinfo->strengths[j] != preset_strength) + continue; + + ecc_bytes = caps->calc_ecc_bytes(preset_step, + preset_strength); + if (WARN_ON_ONCE(ecc_bytes < 0)) + return ecc_bytes; + + if (ecc_bytes * nsteps > oobavail) { + pr_err("ECC (step, strength) = (%d, %d) does not fit in OOB", + preset_step, preset_strength); + return -ENOSPC; + } + + chip->ecc.bytes = ecc_bytes; + + return 0; + } + } + + pr_err("ECC (step, strength) = (%d, %d) not supported on this controller", + preset_step, preset_strength); + + return -ENOTSUPP; +} +EXPORT_SYMBOL_GPL(nand_check_ecc_caps); + +/** + * nand_match_ecc_req - meet the chip's requirement with least ECC bytes + * @chip: nand chip info structure + * @caps: ECC engine caps info structure + * @oobavail: OOB size that the ECC engine can use + * + * If a chip's ECC requirement is provided, try to meet it with the least + * number of ECC bytes (i.e. with the largest number of OOB-free bytes). + * On success, the chosen ECC settings are set. + */ +int nand_match_ecc_req(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + const struct nand_ecc_step_info *stepinfo; + int req_step = chip->ecc_step_ds; + int req_strength = chip->ecc_strength_ds; + int req_corr, step_size, strength, nsteps, ecc_bytes, ecc_bytes_total; + int best_step, best_strength, best_ecc_bytes; + int best_ecc_bytes_total = INT_MAX; + int i, j; + + if (WARN_ON(oobavail < 0)) + return -EINVAL; + + /* No information provided by the NAND chip */ + if (!req_step || !req_strength) + return -ENOTSUPP; + + /* number of correctable bits the chip requires in a page */ + req_corr = mtd->writesize / req_step * req_strength; + + for (i = 0; i < caps->nstepinfos; i++) { + stepinfo = &caps->stepinfos[i]; + step_size = stepinfo->stepsize; + + for (j = 0; j < stepinfo->nstrengths; j++) { + strength = stepinfo->strengths[j]; + + /* + * If both step size and strength are smaller than the + * chip's requirement, it is not easy to compare the + * resulted reliability. + */ + if (step_size < req_step && strength < req_strength) + continue; + + if (mtd->writesize % step_size) + continue; + + nsteps = mtd->writesize / step_size; + + ecc_bytes = caps->calc_ecc_bytes(step_size, strength); + if (WARN_ON_ONCE(ecc_bytes < 0)) + continue; + ecc_bytes_total = ecc_bytes * nsteps; + + if (ecc_bytes_total > oobavail || + strength * nsteps < req_corr) + continue; + + /* + * We assume the best is to meet the chip's requrement + * with the least number of ECC bytes. + */ + if (ecc_bytes_total < best_ecc_bytes_total) { + best_ecc_bytes_total = ecc_bytes_total; + best_step = step_size; + best_strength = strength; + best_ecc_bytes = ecc_bytes; + } + } + } + + if (best_ecc_bytes_total == INT_MAX) + return -ENOTSUPP; + + chip->ecc.size = best_step; + chip->ecc.strength = best_strength; + chip->ecc.bytes = best_ecc_bytes; + + return 0; +} +EXPORT_SYMBOL_GPL(nand_match_ecc_req); + +/** + * nand_maximize_ecc - choose the max ECC strength available + * @chip: nand chip info structure + * @caps: ECC engine caps info structure + * @oobavail: OOB size that the ECC engine can use + * + * Choose the max ECC strength that is supported on the controller, and can fit + * within the chip's OOB. On success, the chosen ECC settings are set. + */ +int nand_maximize_ecc(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + const struct nand_ecc_step_info *stepinfo; + int step_size, strength, nsteps, ecc_bytes, corr; + int best_corr = 0; + int best_step = 0; + int best_strength, best_ecc_bytes; + int i, j; + + if (WARN_ON(oobavail < 0)) + return -EINVAL; + + for (i = 0; i < caps->nstepinfos; i++) { + stepinfo = &caps->stepinfos[i]; + step_size = stepinfo->stepsize; + + /* If chip->ecc.size is already set, respect it */ + if (chip->ecc.size && step_size != chip->ecc.size) + continue; + + for (j = 0; j < stepinfo->nstrengths; j++) { + strength = stepinfo->strengths[j]; + + if (mtd->writesize % step_size) + continue; + + nsteps = mtd->writesize / step_size; + + ecc_bytes = caps->calc_ecc_bytes(step_size, strength); + if (WARN_ON_ONCE(ecc_bytes < 0)) + continue; + + if (ecc_bytes * nsteps > oobavail) + continue; + + corr = strength * nsteps; + + /* + * If the number of correctable bits is the same, + * bigger step_size has more reliability. + */ + if (corr > best_corr || + (corr == best_corr && step_size > best_step)) { + best_corr = corr; + best_step = step_size; + best_strength = strength; + best_ecc_bytes = ecc_bytes; + } + } + } + + if (!best_corr) + return -ENOTSUPP; + + chip->ecc.size = best_step; + chip->ecc.strength = best_strength; + chip->ecc.bytes = best_ecc_bytes; + + return 0; +} +EXPORT_SYMBOL_GPL(nand_maximize_ecc); + /* * Check if the chip configuration meet the datasheet requirements. diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 8f67b1581683..c28a5792eed6 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -477,6 +477,30 @@ static inline void nand_hw_control_init(struct nand_hw_control *nfc) } /** + * struct nand_ecc_step_info - ECC step information of ECC engine + * @stepsize: data bytes per ECC step + * @strengths: array of supported strengths + * @nstrengths: number of supported strengths + */ +struct nand_ecc_step_info { + int stepsize; + const int *strengths; + int nstrengths; +}; + +/** + * struct nand_ecc_caps - capability of ECC engine + * @stepinfos: array of ECC step information + * @nstepinfos: number of ECC step information + * @calc_ecc_bytes: driver's hook to calculate ECC bytes per step + */ +struct nand_ecc_caps { + const struct nand_ecc_step_info *stepinfos; + int nstepinfos; + int (*calc_ecc_bytes)(int step_size, int strength); +}; + +/** * struct nand_ecc_ctrl - Control structure for ECC * @mode: ECC mode * @algo: ECC algorithm @@ -1244,6 +1268,15 @@ int nand_check_erased_ecc_chunk(void *data, int datalen, void *extraoob, int extraooblen, int threshold); +int nand_check_ecc_caps(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail); + +int nand_match_ecc_req(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail); + +int nand_maximize_ecc(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail); + /* Default write_oob implementation */ int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page); From patchwork Wed Jun 7 11:52:11 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103255 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1716887obh; Wed, 7 Jun 2017 05:00:43 -0700 (PDT) X-Received: by 10.84.229.6 with SMTP id b6mr28093299plk.4.1496836843628; Wed, 07 Jun 2017 05:00:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836843; cv=none; d=google.com; s=arc-20160816; b=ixZf9o11kH0USnXC1DQdyt2WFmGYJf8sEsCM0MzcZ7GoCLl8KFQ3M/kBI91e6kqz2l WexFkKc46b1wdLE8uQzYrOzho7Z9D7sAjHQUP8jzOxjH7zIdGF3c1blPkZ87YPWUcxQi D/vl1L8Io6K85Gn+ZDhC/qR4NzqdV31VahmmCJ6NXgo6iGz0Y+ZjSlIMbqYY6uySWg6y bqu8BantF8PyoL76VSvM5nfiSpAzBzNo65Q8cQ39lekd9AKvmI7hKseInSIYT1wGbDil Q3Iiuet6E06fMfjLJHwYKyt3na1yQTQcD5ZaJDK5odIf5vSJ6/YAphez1sHJKvg/ipPz JA7Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=8CP48yiUuqqsCTTnQfu6j5chAmIPWK2W22bnFQ5bzBw=; b=r1U/vZeOKJaN0lB3xmM87KAsILuQGnVPQ1H9M0H7mpP2F+A0duvJTM8wWg5VwV2j1C WdlOpWcUlT48QRTxh3F8OogIQ4FQDehGT6u5WlrZqY+Fp3+Gk6eym+mUnCc1MZj9xQCY n+SCWlIzHSow7WMovM0x3AGKARYwU953zaCU99c6MxgpEYdD9QiCwSByOxCxbABG0IWd SxCjrhJ5cwunkDJOgzCr5As5bUfsi2sBF1SgomU3SEGcF1WxNtz5UbTWOOBvIeoyGRlg MjBi0FTJC7mDx4OSqwULU6TdtNTuwsRWHGjrNdayT5cNCdnCfVr4TIKZ20o0wi/bgA6i vmEQ== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id j3si1624610pgs.370.2017.06.07.05.00.43; Wed, 07 Jun 2017 05:00:43 -0700 (PDT) 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 S1751932AbdFGMAU (ORCPT + 25 others); Wed, 7 Jun 2017 08:00:20 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42393 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751502AbdFGLzU (ORCPT ); Wed, 7 Jun 2017 07:55:20 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZR014276; Wed, 7 Jun 2017 20:52:48 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZR014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836369; bh=8CP48yiUuqqsCTTnQfu6j5chAmIPWK2W22bnFQ5bzBw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=0U7DjHSF+5ldD3R/5CNq/5upvQ3ktCQ3QhI4+NJg3/AUMGE9EmxyioIH538RQdUAH Nt6mo5IqhOvA2nRwUSC/GG6Fjj9Tvqd/+5/yUbkPIRmSyAERy2sq4xQexAzUfMwKYk dLyHKLcypwaGG7Bo9GXElds62Xc3qm+xuvc0l8NinQV/R0YxKHnNxpK8j4F5WTJx5e ZaR6cIiftD5CvqIKhi7vLCOd6NfqkzQSjYcvhSqEvfmTz5ADdiVWY+L5e7eybWrGBy IJYqnDdvDjodiV9HW8w9b9alnlygsiouIyyjsp+yXUdpJO0028U59LDze2X0nntEva rAl/fIXPPNjsg== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 02/23] mtd: nand: add a shorthand to generate nand_ecc_caps structure Date: Wed, 7 Jun 2017 20:52:11 +0900 Message-Id: <1496836352-8016-3-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 struct nand_ecc_caps was designed as flexible as possible to support multiple stepsizes (like sunxi_nand.c). So, we need to write multiple arrays even for the simplest case. I guess many controllers support a single stepsize, so here is a shorthand macro for the case. It allows to describe like ... NAND_ECC_CAPS_SINGLE(denali_pci_ecc_caps, denali_calc_ecc_bytes, 512, 8, 15); ... instead of static const int denali_pci_ecc_strengths[] = {8, 15}; static const struct nand_ecc_step_info denali_pci_ecc_stepinfo = { .stepsize = 512, .strengths = denali_pci_ecc_strengths, .nstrengths = ARRAY_SIZE(denali_pci_ecc_strengths), }; static const struct nand_ecc_caps denali_pci_ecc_caps = { .stepinfos = &denali_pci_ecc_stepinfo, .nstepinfos = 1, .calc_ecc_bytes = denali_calc_ecc_bytes, }; Signed-off-by: Masahiro Yamada --- Changes in v5: - Newly added Changes in v4: None Changes in v3: None Changes in v2: None include/linux/mtd/nand.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) -- 2.7.4 diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index c28a5792eed6..c08954a39657 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -500,6 +500,20 @@ struct nand_ecc_caps { int (*calc_ecc_bytes)(int step_size, int strength); }; +/* a shorthand to generate struct nand_ecc_caps with only one ECC stepsize */ +#define NAND_ECC_CAPS_SINGLE(__name, __calc, __step, ...) \ +static const int __name##_strengths[] = { __VA_ARGS__ }; \ +static const struct nand_ecc_step_info __name##_stepinfo = { \ + .stepsize = __step, \ + .strengths = __name##_strengths, \ + .nstrengths = ARRAY_SIZE(__name##_strengths), \ +}; \ +static const struct nand_ecc_caps __name = { \ + .stepinfos = &__name##_stepinfo, \ + .nstepinfos = 1, \ + .calc_ecc_bytes = __calc, \ +} + /** * struct nand_ecc_ctrl - Control structure for ECC * @mode: ECC mode From patchwork Wed Jun 7 11:52:12 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103256 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1716893obh; Wed, 7 Jun 2017 05:00:44 -0700 (PDT) X-Received: by 10.84.232.8 with SMTP id h8mr27341923plk.278.1496836844047; Wed, 07 Jun 2017 05:00:44 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836844; cv=none; d=google.com; s=arc-20160816; b=yvX9wB+1U5ZTL4UpXXtiw/YukIASX6A5G2dUiA0g9nwiAXy82m56SckwZe8cZxmuIi JHX28/wSrmxOJYQcLYuwLzq7ZgqPb8pZ3+no5rL1lai3x4FSkv40ndyoEq1Ou7E1CmtD M56R45G7JmAaQvWKwuyiPGFb00f+2KDka25MMvtik/W0YAyqyM9ncgu0QdaCPMqmjS8L CI+ug6VEGQGU2SlEJy0/5FBH77Gqetf1gtEDy9j3uyaa/+NhjrfCMwlUALBetQua7+S3 Yw/zv19YzxIdMD/WqWY6nZ0z/NgYj5HvDUbUjmHst8jzB9s+gSCKDEPpMnvhBRizU07Z Zz6Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=n3OaNqaxoJUjyhGe4J+tcVZGHGiTPyEM5cFns/rUEz8=; b=Q9pqcMCgTl8NEhZQE29MsVGOiFIruIyraWop9PmYddwBj3oVSIqKo0uCjgQwVVItws VrJD/gq0+39echmE0xA5xPKQiMQCGV1BbRLAAVPhUV7YXhanmTbWzg4ZM8eQN8Cf7ZeC kXJGrHFn6A+SgTFdefgz9TSfZCU9CHDO+Pz8uuoT3ReyfTsjUu9Vwq/fCs4ko1dOgXcC RxY339INEiWfD5KhpwhNtsPb/w22sKbEDU3Urzd9R4LQOrQ3f0wRA782X+TXHjfUdE2M Mz2KIiTsheydQNcpZ9KWl9r95YIc5ni9e5vWT+vimdwNE5o3+OSuhXFUMPvv5z97Dss3 JdCw== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id j3si1624610pgs.370.2017.06.07.05.00.43; Wed, 07 Jun 2017 05:00:44 -0700 (PDT) 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 S1751921AbdFGMAS (ORCPT + 25 others); Wed, 7 Jun 2017 08:00:18 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42396 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751505AbdFGLzU (ORCPT ); Wed, 7 Jun 2017 07:55:20 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZS014276; Wed, 7 Jun 2017 20:52:49 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZS014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836370; bh=n3OaNqaxoJUjyhGe4J+tcVZGHGiTPyEM5cFns/rUEz8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aBS8zZ4ptIho4+Ceg42jy5hYIRh4bjFJKj6eIG4IflTtqtR1EqIcis4Jh2alakKnt E/Bh8HxxxJtyYFxR0XOMMBwxQMODIxQZm7x+AW4+6PSv9NF44cJeBuSgNrfVykzg5W b3cX8pce3mODn6xG9wnkAA0+58UCW/GaRgnUVJtEb1ewsp3nn1CKpTUbPXg+24NTEW NING/4oydg0COT4BuybzLeeSRUI4gA2w2Hw87w2FyQQ/oS/Gc7ooGQyQZkBXcz4gfy c1aRXZNCTmZKUfQPFrmhUjvNq4Ha4Wbo9xOdbu/6M/TIsyvTtYZVdgBLXdt7MPyb9H bRcJoCldbY0Dw== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger , Rob Herring , Mark Rutland Subject: [PATCH v5 03/23] mtd: nand: denali: avoid hard-coding ECC step, strength, bytes Date: Wed, 7 Jun 2017 20:52:12 +0900 Message-Id: <1496836352-8016-4-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 This driver was originally written for the Intel MRST platform with several platform-specific parameters hard-coded. Currently, the ECC settings are hard-coded as follows: #define ECC_SECTOR_SIZE 512 #define ECC_8BITS 14 #define ECC_15BITS 26 Therefore, the driver can only support two cases. - 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 to handle the ECC 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) For DT platforms, it would be reasonable to allow DT to specify ECC strength by either "nand-ecc-strength" or "nand-ecc-maximize". If none of them is specified, the driver will try to meet the chip's ECC requirement. For PCI platforms, the max ECC strength is used to keep the original behavior. Newer versions of this IP need ecc.size and ecc.steps explicitly set up via the following registers: CFG_DATA_BLOCK_SIZE (0x6b0) CFG_LAST_DATA_BLOCK_SIZE (0x6c0) CFG_NUM_DATA_BLOCKS (0x6d0) For older IP versions, write accesses to these registers are just ignored. Signed-off-by: Masahiro Yamada Acked-by: Rob Herring --- Changes in v5: - Simplify denali_calc_ecc_bytes() - Adjust to the udpate of generic helpers - export denali_calc_ecc_bytes() Changes in v4: - Rewrite by using generic helpers, nand_check_caps(), nand_match_ecc_req(), nand_maximize_ecc(). Changes in v3: - Move DENALI_CAP_ define out of struct denali_nand_info - Use chip->ecc_step_ds as a hint to choose chip->ecc.size where possible Changes in v2: - Change the capability prefix DENALI_CAPS_ -> DENALI_CAP_ - Make ECC 512 cap and ECC 1024 cap independent - Set up three CFG_... registers .../devicetree/bindings/mtd/denali-nand.txt | 7 ++ drivers/mtd/nand/denali.c | 87 +++++++++++++--------- drivers/mtd/nand/denali.h | 12 ++- drivers/mtd/nand/denali_dt.c | 5 ++ drivers/mtd/nand/denali_pci.c | 4 + 5 files changed, 78 insertions(+), 37 deletions(-) -- 2.7.4 diff --git a/Documentation/devicetree/bindings/mtd/denali-nand.txt b/Documentation/devicetree/bindings/mtd/denali-nand.txt index e593bbeb2115..b7742a7363ea 100644 --- a/Documentation/devicetree/bindings/mtd/denali-nand.txt +++ b/Documentation/devicetree/bindings/mtd/denali-nand.txt @@ -7,6 +7,13 @@ Required properties: - reg-names: Should contain the reg names "nand_data" and "denali_reg" - interrupts : The interrupt number. +Optional properties: + - nand-ecc-step-size: see nand.txt for details. If present, the value must be + 512 for "altr,socfpga-denali-nand" + - nand-ecc-strength: see nand.txt for details. Valid values are: + 8, 15 for "altr,socfpga-denali-nand" + - nand-ecc-maximize: see nand.txt for details + The device tree may optionally contain sub-nodes describing partitions of the address space. See partition.txt for more detail. diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 16634df2e39a..0fff11faf603 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -886,8 +886,6 @@ static int denali_hw_ecc_fixup(struct mtd_info *mtd, return max_bitflips; } -#define ECC_SECTOR_SIZE 512 - #define ECC_SECTOR(x) (((x) & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12) #define ECC_BYTE(x) (((x) & ECC_ERROR_ADDRESS__OFFSET)) #define ECC_CORRECTION_VALUE(x) ((x) & ERR_CORRECTION_INFO__BYTEMASK) @@ -899,6 +897,7 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd, struct denali_nand_info *denali, unsigned long *uncor_ecc_flags, uint8_t *buf) { + unsigned int ecc_size = denali->nand.ecc.size; unsigned int bitflips = 0; unsigned int max_bitflips = 0; uint32_t err_addr, err_cor_info; @@ -928,9 +927,9 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd, * an erased sector. */ *uncor_ecc_flags |= BIT(err_sector); - } else if (err_byte < ECC_SECTOR_SIZE) { + } else if (err_byte < ecc_size) { /* - * If err_byte is larger than ECC_SECTOR_SIZE, means error + * If err_byte is larger than ecc_size, means error * happened in OOB, so we ignore it. It's no need for * us to correct it err_device is represented the NAND * error bits are happened in if there are more than @@ -939,7 +938,7 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd, int offset; unsigned int flips_in_byte; - offset = (err_sector * ECC_SECTOR_SIZE + err_byte) * + offset = (err_sector * ecc_size + err_byte) * denali->devnum + err_device; /* correct the ECC error */ @@ -1345,13 +1344,39 @@ 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 +int denali_calc_ecc_bytes(int step_size, int strength) +{ + /* BCH code. Denali requires ecc.bytes to be multiple of 2 */ + return DIV_ROUND_UP(strength * fls(step_size * 8), 16) * 2; +} +EXPORT_SYMBOL(denali_calc_ecc_bytes); + +static int denali_ecc_setup(struct mtd_info *mtd, struct nand_chip *chip, + struct denali_nand_info *denali) +{ + int oobavail = mtd->oobsize - denali->bbtskipbytes; + int ret; + + /* + * If .size and .strength are already set (usually by DT), + * check if they are supported by this controller. + */ + if (chip->ecc.size && chip->ecc.strength) + return nand_check_ecc_caps(chip, denali->ecc_caps, oobavail); + + /* + * We want .size and .strength closest to the chip's requirement + * unless NAND_ECC_MAXIMIZE is requested. + */ + if (!(chip->ecc.options & NAND_ECC_MAXIMIZE)) { + ret = nand_match_ecc_req(chip, denali->ecc_caps, oobavail); + if (!ret) + return 0; + } + + /* Max ECC strength is the last thing we can do */ + return nand_maximize_ecc(chip, denali->ecc_caps, oobavail); +} static int denali_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) @@ -1586,34 +1611,26 @@ int denali_init(struct denali_nand_info *denali) /* no subpage writes on denali */ chip->options |= NAND_NO_SUBPAGE_WRITE; - /* - * 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 / - ECC_SECTOR_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 / - ECC_SECTOR_SIZE))) { - pr_err("Your NAND chip OOB is not large enough to contain 8bit ECC correction codes"); + ret = denali_ecc_setup(mtd, chip, denali); + if (ret) { + dev_err(denali->dev, "Failed to setup ECC settings.\n"); goto failed_req_irq; - } else { - chip->ecc.strength = 8; - chip->ecc.bytes = ECC_8BITS; - iowrite32(8, denali->flash_reg + ECC_CORRECTION); } + dev_dbg(denali->dev, + "chosen ECC settings: step=%d, strength=%d, bytes=%d\n", + chip->ecc.size, chip->ecc.strength, chip->ecc.bytes); + + 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); + /* chip->ecc.steps is set by nand_scan_tail(); not available here */ + iowrite32(mtd->writesize / chip->ecc.size, + denali->flash_reg + CFG_NUM_DATA_BLOCKS); + mtd_set_ooblayout(mtd, &denali_ooblayout_ops); - /* override the default read operations */ - chip->ecc.size = ECC_SECTOR_SIZE; chip->ecc.read_page = denali_read_page; chip->ecc.read_page_raw = denali_read_page_raw; chip->ecc.write_page = denali_write_page; diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 37833535a7a3..a06ed741b550 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -259,6 +259,14 @@ #define ECC_COR_INFO__MAX_ERRORS GENMASK(6, 0) #define ECC_COR_INFO__UNCOR_ERR BIT(7) +#define CFG_DATA_BLOCK_SIZE 0x6b0 + +#define CFG_LAST_DATA_BLOCK_SIZE 0x6c0 + +#define CFG_NUM_DATA_BLOCKS 0x6d0 + +#define CFG_META_DATA_SIZE 0x6e0 + #define DMA_ENABLE 0x700 #define DMA_ENABLE__FLAG BIT(0) @@ -301,8 +309,6 @@ #define MODE_10 0x08000000 #define MODE_11 0x0C000000 -#define ECC_SECTOR_SIZE 512 - struct nand_buf { int head; int tail; @@ -337,11 +343,13 @@ struct denali_nand_info { int max_banks; unsigned int revision; unsigned int caps; + const struct nand_ecc_caps *ecc_caps; }; #define DENALI_CAP_HW_ECC_FIXUP BIT(0) #define DENALI_CAP_DMA_64BIT BIT(1) +int denali_calc_ecc_bytes(int step_size, int strength); extern int denali_init(struct denali_nand_info *denali); extern void denali_remove(struct denali_nand_info *denali); diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index b48430fe3cd4..bd1aa4cf4457 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -32,10 +32,14 @@ struct denali_dt { struct denali_dt_data { unsigned int revision; unsigned int caps; + const struct nand_ecc_caps *ecc_caps; }; +NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes, + 512, 8, 15); static const struct denali_dt_data denali_socfpga_data = { .caps = DENALI_CAP_HW_ECC_FIXUP, + .ecc_caps = &denali_socfpga_ecc_caps, }; static const struct of_device_id denali_nand_dt_ids[] = { @@ -64,6 +68,7 @@ static int denali_dt_probe(struct platform_device *pdev) if (data) { denali->revision = data->revision; denali->caps = data->caps; + denali->ecc_caps = data->ecc_caps; } denali->platform = DT; diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c index ac843238b77e..37dc0934c24c 100644 --- a/drivers/mtd/nand/denali_pci.c +++ b/drivers/mtd/nand/denali_pci.c @@ -27,6 +27,8 @@ static const struct pci_device_id denali_pci_ids[] = { }; MODULE_DEVICE_TABLE(pci, denali_pci_ids); +NAND_ECC_CAPS_SINGLE(denali_pci_ecc_caps, denali_calc_ecc_bytes, 512, 8, 15); + static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { int ret; @@ -65,6 +67,8 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) pci_set_master(dev); denali->dev = &dev->dev; denali->irq = dev->irq; + denali->ecc_caps = &denali_pci_ecc_caps; + denali->nand.ecc.options |= NAND_ECC_MAXIMIZE; ret = pci_request_regions(dev, DENALI_NAND_NAME); if (ret) { From patchwork Wed Jun 7 11:52:13 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103251 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1716141obh; Wed, 7 Jun 2017 04:59:16 -0700 (PDT) X-Received: by 10.84.174.67 with SMTP id q61mr27347275plb.97.1496836756652; Wed, 07 Jun 2017 04:59:16 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836756; cv=none; d=google.com; s=arc-20160816; b=b4eNCIvK4p3GqjDkUY6uMwwsYGSBLIYlppBW8lUNJml1did10sBDocv+9a/U5vm2wp 2Ihv5+/kORr4cwnoQ5RZthgg8aY7aHhLgVHaPD661tPz5JyNJpCgN7J5g7JWoyG1KH/b apUH4WkLwojc5OO1BTyVrzJYP0vE0ntf8zjw+mafms1qNfnToH0W77Sflar4lUFYKSkh 71GDwlYJq0slkY+AgPHs4VhvhU73cgyxBu7dy76vd9o75D1EzMAM4iSNgazeuVsps/Lb fNYqzCm13ZCnjbqy7o40OtyqD/MuhSN6Dyjaa+MrQlSkTT1xRwpo65kXENEkWCzWoNJX GRIw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=NOvNx5hl2aVmS0yPYHowxukHg/fjLu4rQqDitN+B9Gc=; b=UPOb/u3wJ0BPy/F+tCw1N1N/p2EPC7FaFYTcDqdhiqY8d5yyJr7FyLXrk7ufzjca/q fh1pTSLFmgWJtPhVrAvfzYakvfXYai6G1neFWN1MXhA5QaJcEjmUBhuXdcbqGQddgh7G L3kDAPjbf25+FIPYGIBjI9ofXy0+x6RrQbaD0wyXzsRX2hYr7Mh+VTN9xbgd2ZJxjWnx RsZUHdONOy6oWuf67Z44XBgAYZmdzmD7vqFOuwiELAoqIedVgvtJxRKjFAV/FmTN5ERl MJe8CrDTOf4cDqU3hzVOfv8bYHcFYg4BVGx+D4AOxAJi6EqQ52+EDufe0Zb/eHCNZ+vE BwoQ== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id a187si1589687pge.160.2017.06.07.04.59.16; Wed, 07 Jun 2017 04:59:16 -0700 (PDT) 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 S1751868AbdFGL7J (ORCPT + 25 others); Wed, 7 Jun 2017 07:59:09 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42481 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751550AbdFGLzY (ORCPT ); Wed, 7 Jun 2017 07:55:24 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZT014276; Wed, 7 Jun 2017 20:52:50 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZT014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836371; bh=NOvNx5hl2aVmS0yPYHowxukHg/fjLu4rQqDitN+B9Gc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LNLOCTbmUPCd51fs2BJphbmUp+f/0N6jdBmJb/nzi6HHahfYlTjS8cmPsRok94SAp /v4ISRfN0H5lgfu7v12onNUYOr+VXbT041rlQq7MOBp+yZ1GkNsI+dTfLJhbrWyb7H O9UkSY5fC/k6TNSxMCXjnNElQccjtQCLgS2Yt0oza48vquzUBlLALcGihMcS+7PCHm hMXSa0ilEeVm2x92VesCJrl8Q/hZS+5lbwEV6z8oXXOxhxCMkcsvSQoXTVg2ITwDgP NU6iqOXfSXsmzlyjX1CrWCLZFgKrqIdJYXAr7FH5w93XcamPWs4BFYb5mQn61VnlVQ 9P2+WFb8UV0FQ== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 04/23] mtd: nand: denali: remove Toshiba and Hynix specific fixup code Date: Wed, 7 Jun 2017 20:52:13 +0900 Message-Id: <1496836352-8016-5-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 The Denali IP can automatically detect device parameters such as page size, oob size, device width, etc. and this driver currently relies on it. However, this hardware function is known to be problematic. [1] Due to a hardware bug, various misdetected cases were reported. That is why get_toshiba_nand_para() and get_hynix_nand_para() exist to fix-up the misdetected parameters. It is not realistic to add a new NAND device to the *black list* every time we are hit by a misdetected case. We would never be able to guarantee that all cases are covered. [2] Because this feature is unreliable, it is disabled on some platforms. The nand_scan_ident() detects device parameters in a more tested way. The hardware should not set the device parameter registers in a different, unreliable way. Instead, set the parameters from the nand_scan_ident() back to the registers. Signed-off-by: Masahiro Yamada --- Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None drivers/mtd/nand/denali.c | 40 ++++++---------------------------------- 1 file changed, 6 insertions(+), 34 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 0fff11faf603..991924b9ae2c 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -337,36 +337,6 @@ static void get_samsung_nand_para(struct denali_nand_info *denali, } } -static void get_toshiba_nand_para(struct denali_nand_info *denali) -{ - /* - * Workaround to fix a controller bug which reports a wrong - * spare area size for some kind of Toshiba NAND device - */ - if ((ioread32(denali->flash_reg + DEVICE_MAIN_AREA_SIZE) == 4096) && - (ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64)) - iowrite32(216, denali->flash_reg + DEVICE_SPARE_AREA_SIZE); -} - -static void get_hynix_nand_para(struct denali_nand_info *denali, - uint8_t device_id) -{ - switch (device_id) { - case 0xD5: /* Hynix H27UAG8T2A, H27UBG8U5A or H27UCG8VFA */ - case 0xD7: /* Hynix H27UDG8VEM, H27UCG8UDM or H27UCG8V5A */ - iowrite32(128, denali->flash_reg + PAGES_PER_BLOCK); - iowrite32(4096, denali->flash_reg + DEVICE_MAIN_AREA_SIZE); - iowrite32(224, denali->flash_reg + DEVICE_SPARE_AREA_SIZE); - iowrite32(0, denali->flash_reg + DEVICE_WIDTH); - break; - default: - dev_warn(denali->dev, - "Unknown Hynix NAND (Device ID: 0x%x).\n" - "Will use default parameter values instead.\n", - device_id); - } -} - /* * determines how many NAND chips are connected to the controller. Note for * Intel CE4100 devices we don't support more than one device. @@ -453,10 +423,6 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) return FAIL; } else if (maf_id == 0xEC) { /* Samsung NAND */ get_samsung_nand_para(denali, device_id); - } else if (maf_id == 0x98) { /* Toshiba NAND */ - get_toshiba_nand_para(denali); - } else if (maf_id == 0xAD) { /* Hynix NAND */ - get_hynix_nand_para(denali, device_id); } dev_info(denali->dev, @@ -1622,6 +1588,12 @@ int denali_init(struct denali_nand_info *denali) chip->ecc.size, chip->ecc.strength, chip->ecc.bytes); iowrite32(chip->ecc.strength, denali->flash_reg + ECC_CORRECTION); + iowrite32(mtd->erasesize / mtd->writesize, + denali->flash_reg + PAGES_PER_BLOCK); + iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0, + denali->flash_reg + DEVICE_WIDTH); + iowrite32(mtd->writesize, denali->flash_reg + DEVICE_MAIN_AREA_SIZE); + iowrite32(mtd->oobsize, denali->flash_reg + DEVICE_SPARE_AREA_SIZE); iowrite32(chip->ecc.size, denali->flash_reg + CFG_DATA_BLOCK_SIZE); iowrite32(chip->ecc.size, denali->flash_reg + CFG_LAST_DATA_BLOCK_SIZE); From patchwork Wed Jun 7 11:52:14 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103249 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1715965obh; Wed, 7 Jun 2017 04:58:49 -0700 (PDT) X-Received: by 10.99.113.11 with SMTP id m11mr31780159pgc.45.1496836729620; Wed, 07 Jun 2017 04:58:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836729; cv=none; d=google.com; s=arc-20160816; b=RhDE2VIuUcvn3AOl6UU35b/kCAzxaD7StynhIh4PmPXrdPeGQmCh3pBc+VIPdXXRVx DnnWLyQgmOC9uJj17IgijptZitG8WO8IlpPM0pJxhgHmaHS2qEcsQvlzerPZKb0updYg 5pe9sEArE7kRTA8d7dlqnlIWLiwE1SYILas3hbkolzuIM0l+OoPDDsYo8grzOjyPEdsq hRipijPTQrXNmhlulXl6tWq03Xne4Zjr/Z1Y+CU2/B7pCzSFkdiLMXsNIRoOhNQxvXh5 7Uc22NbAL8GgGTvRzMMIJ3K5O7ESNvu4Ec71OrRnfmNgFnQKWb8EOkMRmayzMciVmBEc QJWw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=uOJHNKp4so4H96UNDprKdt/KpMY+35eVDLg4DjTEL/4=; b=ccbSTAsq7LzINqQF4y8Gvd2EDgE8xtx+HavvtVCHji2+mbNSYBEQF4gIl9VbDOuA+M jSOLAZUczDq8CcGgm83RGYAlQg9cfoQ6wgAxOCSG1yqUA6xNMueduVYgASag6llwPDv6 HzzANEbqxsvMFr1uJnNBQtLXOK2HFBolTB2oAui/VZMUqZJQe74jUoyc+JS5OdTyd+r5 KJ4KSMRJ0J5ivMeMRhtc3V7EsLI3dzi1A13wlnJ/18Way3i7GZoDb/mzcDzUUpu+4MeP oUim23KTG+drlcF5tzx0SujDTVuCuy9LpTUTjtG+rvIUrNT7iQEv4/A3lCejyLwxKOEz FunA== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m24si1627578pfa.242.2017.06.07.04.58.49; Wed, 07 Jun 2017 04:58:49 -0700 (PDT) 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 S1751894AbdFGL61 (ORCPT + 25 others); Wed, 7 Jun 2017 07:58:27 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42497 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751553AbdFGLzY (ORCPT ); Wed, 7 Jun 2017 07:55:24 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZU014276; Wed, 7 Jun 2017 20:52:51 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZU014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836372; bh=uOJHNKp4so4H96UNDprKdt/KpMY+35eVDLg4DjTEL/4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RlNwhUsV97hZ1jHQKjw0iPBQl9dJO7WUrWvHe4JbHAyUtFIPdmsBRoqBEAs2mLlM6 5cLPkMxSe2r3vUkBWjU5DM9B9Y+Lzzj3T9W20WAP1tuLit+KdQ7ZkwknY0peyxvs1X l2yKdVOjwHxB8l1WtCY3rYbMcnCK41u6M1VZtolfm4Ln0QhRqTDYTJsIaiqWZRK2rA JmzwxTM4RhYN9PcOgHN/8bv/qMth7sKnppZ0TQd3RVEWnqfBQv32glDd+w9EI0+Hpi K8WJWloLiRdlv9ysJpZaJlvcyvaeLkTTtu/n+8nzAmErfnb3BtUyPsCqQVXdmpPM1u SpQ2FajqLn8dQ== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger , Rob Herring , Mark Rutland Subject: [PATCH v5 05/23] mtd: nand: denali_dt: add compatible strings for UniPhier SoC variants Date: Wed, 7 Jun 2017 20:52:14 +0900 Message-Id: <1496836352-8016-6-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 Add two compatible strings for UniPhier SoC family. "socionext,uniphier-denali-nand-v5a" is used on UniPhier sLD3, LD4, Pro4, sLD8. "socionext,uniphier-denali-nand-v5b" is used on UniPhier Pro5, PXs2, LD6b, LD11, LD20. Signed-off-by: Masahiro Yamada --- Changes in v5: - Adjust to the update of generic helpers Changes in v4: - Adjusted to generic helpers for ECC engine caps Changes in v3: None Changes in v2: - Change the compatible strings - Fix the ecc_strength_capability - Override revision number for the newer one .../devicetree/bindings/mtd/denali-nand.txt | 6 ++++++ drivers/mtd/nand/denali_dt.c | 25 ++++++++++++++++++++++ 2 files changed, 31 insertions(+) -- 2.7.4 diff --git a/Documentation/devicetree/bindings/mtd/denali-nand.txt b/Documentation/devicetree/bindings/mtd/denali-nand.txt index b7742a7363ea..504291d2e5c2 100644 --- a/Documentation/devicetree/bindings/mtd/denali-nand.txt +++ b/Documentation/devicetree/bindings/mtd/denali-nand.txt @@ -3,6 +3,8 @@ Required properties: - compatible : should be one of the following: "altr,socfpga-denali-nand" - for Altera SOCFPGA + "socionext,uniphier-denali-nand-v5a" - for Socionext UniPhier (v5a) + "socionext,uniphier-denali-nand-v5b" - for Socionext UniPhier (v5b) - reg : should contain registers location and length for data and reg. - reg-names: Should contain the reg names "nand_data" and "denali_reg" - interrupts : The interrupt number. @@ -10,8 +12,12 @@ Required properties: Optional properties: - nand-ecc-step-size: see nand.txt for details. If present, the value must be 512 for "altr,socfpga-denali-nand" + 1024 for "socionext,uniphier-denali-nand-v5a" + 1024 for "socionext,uniphier-denali-nand-v5b" - nand-ecc-strength: see nand.txt for details. Valid values are: 8, 15 for "altr,socfpga-denali-nand" + 8, 16, 24 for "socionext,uniphier-denali-nand-v5a" + 8, 16 for "socionext,uniphier-denali-nand-v5b" - nand-ecc-maximize: see nand.txt for details The device tree may optionally contain sub-nodes describing partitions of the diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index bd1aa4cf4457..be598230c108 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -42,11 +42,36 @@ static const struct denali_dt_data denali_socfpga_data = { .ecc_caps = &denali_socfpga_ecc_caps, }; +NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes, + 1024, 8, 16, 24); +static const struct denali_dt_data denali_uniphier_v5a_data = { + .caps = DENALI_CAP_HW_ECC_FIXUP | + DENALI_CAP_DMA_64BIT, + .ecc_caps = &denali_uniphier_v5a_ecc_caps, +}; + +NAND_ECC_CAPS_SINGLE(denali_uniphier_v5b_ecc_caps, denali_calc_ecc_bytes, + 1024, 8, 16); +static const struct denali_dt_data denali_uniphier_v5b_data = { + .revision = 0x0501, + .caps = DENALI_CAP_HW_ECC_FIXUP | + DENALI_CAP_DMA_64BIT, + .ecc_caps = &denali_uniphier_v5b_ecc_caps, +}; + static const struct of_device_id denali_nand_dt_ids[] = { { .compatible = "altr,socfpga-denali-nand", .data = &denali_socfpga_data, }, + { + .compatible = "socionext,uniphier-denali-nand-v5a", + .data = &denali_uniphier_v5a_data, + }, + { + .compatible = "socionext,uniphier-denali-nand-v5b", + .data = &denali_uniphier_v5b_data, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, denali_nand_dt_ids); From patchwork Wed Jun 7 11:52:15 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103250 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1715962obh; Wed, 7 Jun 2017 04:58:49 -0700 (PDT) X-Received: by 10.98.75.79 with SMTP id y76mr14637750pfa.39.1496836729214; Wed, 07 Jun 2017 04:58:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836729; cv=none; d=google.com; s=arc-20160816; b=tqmaHNdk4CJMdNq/0AEvXOlMlJVLvlVXHuySTznTFcoEFPVQ/1zC/xl2vB5fX6bfx9 n5+8NAdHahPv/UN/mB6liKQ7GnCC8cwf/pwt0yNwZKoN89PKHn1wBfyG14OeWhR2CBO9 8p7hx5mjU+Pf6WL3VwJCvlxW6z7HbB/NRcin/K0fc+ZNGxF19iGRHST//6r0SoUfElIS L+u/415Ka5oUyflUj+vFdMlfEgk9yJTjjPwI0FYTiFld+wU+ZC8yigdH2ehEf0fXGEgt ZmmK/ojwhOosTkEUH7a6TMqMfl6JciKUwVb6ikyx6mUeDo534F4GFlDRxhepYFeT46ET Ldag== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=AaubtptUPbGdXkYYMr2/r9oWlwE8fZyaPX5iV82l618=; b=gPPXuxg83RWinmE4KXDj+GpAw9qlR4e5FzGFcbcFxXwkaw4RFi1+a6B1FuZqi7Kz3S SvzFRst73SGxeHUAI3THtpXeNh9nRNXY5HJNDV8t7oOcT7OfKNG9C2swy/HV5vqlvnY3 iKP7/1RrpsSbjsyjzJRVXPzglQwmULT050H9k0UA+QXaJUQPVi7C2keWzQF2yDuJsdrp EiDbXPhWvtMWEuFDd7kA8z4DZqaU+5mu0O1Z5UXlmwr0V4CJ3tenje+tpWhGk7N+3m0z SlwgYso4Ft7CIH81gUkGQq8lsGwWO9lgcP0GRe47r+hEn+GIYu5Pg4vCA0e5UObpfDNN HcVA== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m24si1627578pfa.242.2017.06.07.04.58.48; Wed, 07 Jun 2017 04:58:49 -0700 (PDT) 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 S1751908AbdFGL63 (ORCPT + 25 others); Wed, 7 Jun 2017 07:58:29 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42480 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751552AbdFGLzY (ORCPT ); Wed, 7 Jun 2017 07:55:24 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZV014276; Wed, 7 Jun 2017 20:52:53 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZV014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836374; bh=AaubtptUPbGdXkYYMr2/r9oWlwE8fZyaPX5iV82l618=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=1mCcDGFLVP5sHGdXhpkDujgM+rF7ZBhmF2gwEE3OQHmdWwvvZyIWA2ngz4xJj4Gfk YNPQi3kv8zzv03wbRudMA96dUGI7kWuR2tLW3mVktLfQaLpcAG6llSuGi5fakaLXdh h8Q3EOFfkrDeM8yfXyE/7wzIsevOhboUzwxiyS2tH8I9yOFKEOnC9fAb+JTQhZ+ULO xJj3jR6fZwl/rWR1zceZQrRgn0JJaxHyeTdDOcQM+unHSSXou6XMauqkzFB7D4Q8bO mGSnOfu9WrEHgNKMxD6Bi+8NQ/gaRX+Q4nRhO5NVXLimfSn4nLsm67DBBFudaTEhO7 oFefC5fehE+Xw== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 06/23] mtd: nand: denali: set NAND_ECC_CUSTOM_PAGE_ACCESS Date: Wed, 7 Jun 2017 20:52:15 +0900 Message-Id: <1496836352-8016-7-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 The denali_cmdfunc() actually does nothing valuable for NAND_CMD_{PAGEPROG,READ0,SEQIN}. For NAND_CMD_{READ0,SEQIN}, it copies "page" to "denali->page", then denali_read_page() and denali_read_page_raw() compare them to check if the NAND framework called the callbacks in correct order. (Inconsistently, this check is missing from the denali_write_page() and denali_write_page_raw().) The framework is widely tested by many drivers, so this kind of sanity check is unneeded. The Denali controller is equipped with high level interface for read/write, so let's skip unneeded call of cmdfunc(). Signed-off-by: Masahiro Yamada --- Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 991924b9ae2c..1897fe238290 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -998,7 +998,7 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op) * configuration details. */ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, bool raw_xfer) + const uint8_t *buf, int page, bool raw_xfer) { struct denali_nand_info *denali = mtd_to_denali(mtd); dma_addr_t addr = denali->buf.dma_buf; @@ -1006,6 +1006,8 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, uint32_t irq_status; uint32_t irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL; + denali->page = page; + /* * if it is a raw xfer, we want to disable ecc and send the spare area. * !raw_xfer - enable ecc @@ -1059,7 +1061,7 @@ static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, * for regular page writes, we let HW handle all the ECC * data written to the device. */ - return write_page(mtd, chip, buf, false); + return write_page(mtd, chip, buf, page, false); } /* @@ -1075,7 +1077,7 @@ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, * for raw page writes, we want to disable ECC and simply write * whatever data is in the buffer. */ - return write_page(mtd, chip, buf, true); + return write_page(mtd, chip, buf, page, true); } static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip, @@ -1105,12 +1107,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, unsigned long uncor_ecc_flags = 0; int stat = 0; - if (page != denali->page) { - dev_err(denali->dev, - "IN %s: page %d is not equal to denali->page %d", - __func__, page, denali->page); - BUG(); - } + denali->page = page; setup_ecc_for_xfer(denali, true, false); @@ -1154,12 +1151,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, size_t size = mtd->writesize + mtd->oobsize; uint32_t irq_mask = INTR__DMA_CMD_COMP; - if (page != denali->page) { - dev_err(denali->dev, - "IN %s: page %d is not equal to denali->page %d", - __func__, page, denali->page); - BUG(); - } + denali->page = page; setup_ecc_for_xfer(denali, false, true); denali_enable_dma(denali, true); @@ -1238,8 +1230,6 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, int i; switch (cmd) { - case NAND_CMD_PAGEPROG: - break; case NAND_CMD_STATUS: read_status(denali); break; @@ -1259,10 +1249,6 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, write_byte_to_buf(denali, id); } break; - case NAND_CMD_READ0: - case NAND_CMD_SEQIN: - denali->page = page; - break; case NAND_CMD_RESET: reset_bank(denali); break; @@ -1603,6 +1589,7 @@ int denali_init(struct denali_nand_info *denali) mtd_set_ooblayout(mtd, &denali_ooblayout_ops); + chip->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS; chip->ecc.read_page = denali_read_page; chip->ecc.read_page_raw = denali_read_page_raw; chip->ecc.write_page = denali_write_page; From patchwork Wed Jun 7 11:52:16 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103254 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1716601obh; Wed, 7 Jun 2017 05:00:19 -0700 (PDT) X-Received: by 10.98.85.130 with SMTP id j124mr25887974pfb.196.1496836818979; Wed, 07 Jun 2017 05:00:18 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836818; cv=none; d=google.com; s=arc-20160816; b=WgY7C+Y6iEy+Oo+w3JCJEbbOQcqLiRCRCEkXcLmpHicgVLJKuI31fjgKh8DPZ7yfTW bnsgaMS0N1T3plz1XM6klz9QRkeVqJ9KIXaYQzESw6+DZcjLxyS2jRzzYzyFcadMkw7j ebHbczZ+Smu6BmXjqIzYXlgkqprRONEbmlROlBxqBFzml+YwusRTliJnjZCvx2r43jyX FcqJAzmFFjG938wQfp6c17FmMCQwxMIbuLZAjKTjNZRLSaJ9bOzqbRMeT9zt5iEUYL9S gA8C9+AV8lPGHMrpLPHq/8zZY06mues53rp1Bc8N9TSaRFEkQ3ormAW6nFjIgzxpRoRD E3pw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=EDOumMIY/Jq+Ck0TYXEGYmMT8ZvU2P2N2MaQXRl+GVg=; b=mHJfu1e4Tepl3SKOPJEl0CLgtpjSnjbqUU55gc/qpiDRRX+MkQi5quNp7BpGJ6Dtqy hcAtsRjKGosy1P1KjEX0y7vjuFXSCTykMRghi7tUiaXUlriOBuX+n4vp/LbljTD11eFj x4NEr0wwISOldfloChV6PPgrgsMpHXvdbAD0/gKxNNP6wfbXCDctPAEt3/iFXbXsknM8 JcW5FMasxIfBrSsLOrfyOeT+fC3Zp96jjItb2GXbDqC7MgScz868wMYpe9z3AX8uRPDS RX+QtutTbrJGrGUO4Js3+e/Djx5+ZF+tTBPXsKQv2aFC5kMbuh6UljSZtHKppz27s5/o jwlw== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id w63si1614604pfj.165.2017.06.07.05.00.18; Wed, 07 Jun 2017 05:00:18 -0700 (PDT) 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 S1751801AbdFGMAB (ORCPT + 25 others); Wed, 7 Jun 2017 08:00:01 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42433 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751520AbdFGLzV (ORCPT ); Wed, 7 Jun 2017 07:55:21 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZW014276; Wed, 7 Jun 2017 20:52:54 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZW014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836375; bh=EDOumMIY/Jq+Ck0TYXEGYmMT8ZvU2P2N2MaQXRl+GVg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=orLv55xvKivyY+JPOhbu2Np50DVQh+GnANb5vdiJtKVa86ddaItNj7xq8d/40h2sl JanSEMOJPS2wbD59RuaLid7I8R2K24czmrPEpDI3yHfjk7cY2RNy3aLKwKp6r57V+O R+DR3qjlFBKQUKH+/XkP11SlcTCujOqSYYDCAtWnlZ+T353X3MOPIp6Q8Wwse4ZziM 9HkzwatLCebssRQxgYmmaxbCE8iflB42lTzdB6YeE8KzaFeJSo/ueGOBFVaOpIxU+8 iXzG+8ifMPqxGjhYxqdSxOSgl6P5/8sT4v79eIrFkIv+loj9RDUiq8pN9VGJvlt/3V /zoNIP09qVWjA== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 07/23] mtd: nand: denali: do not propagate NAND_STATUS_FAIL to waitfunc() Date: Wed, 7 Jun 2017 20:52:16 +0900 Message-Id: <1496836352-8016-8-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 Currently, the error handling of denali_write_page(_raw) is a bit complicated. If the program command fails, NAND_STATUS_FAIL is set to the driver internal denali->status, then read out later by denali_waitfunc(). We can avoid it by exploiting the nand_write_page() implementation. If chip->ecc.write_page(_raw) returns negative code (i.e. -EIO), it errors out immediately. This gives the same result as returning NAND_STATUS_FAIL from chip->waitfunc. In either way, -EIO is returned to the upper MTD layer. Signed-off-by: Masahiro Yamada --- Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 12 ++++-------- drivers/mtd/nand/denali.h | 1 - 2 files changed, 4 insertions(+), 9 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 1897fe238290..22acfc34b546 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1005,6 +1005,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, size_t size = mtd->writesize + mtd->oobsize; uint32_t irq_status; uint32_t irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL; + int ret = 0; denali->page = page; @@ -1038,13 +1039,13 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, if (irq_status == 0) { dev_err(denali->dev, "timeout on write_page (type = %d)\n", raw_xfer); - denali->status = NAND_STATUS_FAIL; + ret = -EIO; } denali_enable_dma(denali, false); dma_sync_single_for_cpu(denali->dev, addr, size, DMA_TO_DEVICE); - return 0; + return ret; } /* NAND core entry points */ @@ -1196,12 +1197,7 @@ static void denali_select_chip(struct mtd_info *mtd, int chip) static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) { - struct denali_nand_info *denali = mtd_to_denali(mtd); - int status = denali->status; - - denali->status = 0; - - return status; + return 0; } static int denali_erase(struct mtd_info *mtd, int page) diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index a06ed741b550..352d8328b94a 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -323,7 +323,6 @@ struct nand_buf { struct denali_nand_info { struct nand_chip nand; int flash_bank; /* currently selected chip */ - int status; int platform; struct nand_buf buf; struct device *dev; From patchwork Wed Jun 7 11:52:17 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103236 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1714814obh; Wed, 7 Jun 2017 04:55:43 -0700 (PDT) X-Received: by 10.99.120.202 with SMTP id t193mr32522923pgc.35.1496836543301; Wed, 07 Jun 2017 04:55:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836543; cv=none; d=google.com; s=arc-20160816; b=a6Fa4uQP1sbu+BmdbjCGs66exvs7y6pHQXm48cvGJz9rUyNUzRadxD5ugJ1q1xlqyo fStFwX0+5uPyCHDePVdqtDe84u0GyUBADr9/mtihcP1H+nfEOP+cn2jnyFngv92jEMDR 5AbrpQvc6kdkKrAEvPDG6hP8e335Ow+Ro+Q1UaMOwitjzOhLfc2vpPGNEGvibD8fiPEY CGnZxOSYz+coLm5vA5aSUiN6zaIV8sagfT9Mh5+11ErTj6721pKI9IpVf/O8WymOcint gAUfvhbgSKn7pT9ikOsq1x8RWgE0jfeWIa+8obyz38J3DYLMIUy1/NcE0IWHz9PzDr/J qlHw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=YUI6RJg0N9jANXL1fLoc/WOqWZ7tCMe+sQx1OwrliVg=; b=Gcf4T8jz1L46eOaW5j7pE0NGixyoWGq2bHuwOAiBQK43zpd1K9ZCWb+5/13gxIw3d4 UVD8fbL/lTbU8S71/QJps8/Z+pvVVEB2P3oHW0e2FWXONBQWIdemafcbMSgr0KZaZzju lqV7Be5LQKa/HY25TYXMV+suSY9hIpH5CpPUL9QqXOxaLxde3jqV3O6wu5TWKKHUK9dI QSsXhuSJ8yysmM+MSaEHVc0tBIfE7vEoOssYQypp+y6JksrA+mLdvIQ96GVbgJuONOEK faZE4vR7jW4/4CUgm9vVkpgKtg9TW5PG2U1ug9pM6uis0Y5iNheVVWhl24S0s51wSqy0 JMBA== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id e186si1569105pgc.163.2017.06.07.04.55.43; Wed, 07 Jun 2017 04:55:43 -0700 (PDT) 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 S1751702AbdFGLzd (ORCPT + 25 others); Wed, 7 Jun 2017 07:55:33 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42608 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751613AbdFGLz2 (ORCPT ); Wed, 7 Jun 2017 07:55:28 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZX014276; Wed, 7 Jun 2017 20:52:55 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZX014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836376; bh=YUI6RJg0N9jANXL1fLoc/WOqWZ7tCMe+sQx1OwrliVg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bTmeBYvMf9uRiuCCjwNDLPVnu1AY7uv1fKbSICSm0Ekp5lIbslecqTzZIRAf3OMxi ljmA4qTrlYN7AOjYTht74sDzVbABhaugKsJ1mqICmSTQnRXx8TQ7Qxve9bf93NjuM7 BEVACGX7MzeyH49A9B3T+vWlPXXQQPoJN83OftIOyOLJ2IVhYFncQrHDs1LYrFcAS6 AHr3/fp46ZaiHD8ijF1eHFSYHdEuKWQivfLadfFUVxplzM+O5JxuNfBXdkIC9B2aBJ tGd9HvmiS5jHnC5uLqHFgvhQonvpIiBtZOIEutesQFu6BGjMLaITzNw3cwq6TCqDmR Rkl5WMckhm/Kw== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 08/23] mtd: nand: denali: remove unneeded find_valid_banks() Date: Wed, 7 Jun 2017 20:52:17 +0900 Message-Id: <1496836352-8016-9-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 The function find_valid_banks() issues the Read ID (0x90) command, then compares the first byte (Manufacturer ID) of each bank with the one of bank0. This is equivalent to what nand_scan_ident() does. The number of chips is detected there, so this is unneeded. What is worse for find_valid_banks() is that, if multiple chips are connected to INTEL_CE4100 platform, it crashes the kernel by BUG(). This is what we should avoid. This function is just harmful and unneeded. Signed-off-by: Masahiro Yamada --- Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 47 ----------------------------------------------- drivers/mtd/nand/denali.h | 1 - 2 files changed, 48 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 22acfc34b546..f090486cab66 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -338,51 +338,6 @@ static void get_samsung_nand_para(struct denali_nand_info *denali, } /* - * determines how many NAND chips are connected to the controller. Note for - * Intel CE4100 devices we don't support more than one device. - */ -static void find_valid_banks(struct denali_nand_info *denali) -{ - uint32_t id[denali->max_banks]; - int i; - - denali->total_used_banks = 1; - for (i = 0; i < denali->max_banks; i++) { - index_addr(denali, MODE_11 | (i << 24) | 0, 0x90); - index_addr(denali, MODE_11 | (i << 24) | 1, 0); - index_addr_read_data(denali, MODE_11 | (i << 24) | 2, &id[i]); - - dev_dbg(denali->dev, - "Return 1st ID for bank[%d]: %x\n", i, id[i]); - - if (i == 0) { - if (!(id[i] & 0x0ff)) - break; /* WTF? */ - } else { - if ((id[i] & 0x0ff) == (id[0] & 0x0ff)) - denali->total_used_banks++; - else - break; - } - } - - if (denali->platform == INTEL_CE4100) { - /* - * Platform limitations of the CE4100 device limit - * users to a single chip solution for NAND. - * Multichip support is not enabled. - */ - if (denali->total_used_banks != 1) { - dev_err(denali->dev, - "Sorry, Intel CE4100 only supports a single NAND device.\n"); - BUG(); - } - } - dev_dbg(denali->dev, - "denali->total_used_banks: %d\n", denali->total_used_banks); -} - -/* * Use the configuration feature register to determine the maximum number of * banks that the hardware supports. */ @@ -439,8 +394,6 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) ioread32(denali->flash_reg + RDWR_EN_HI_CNT), ioread32(denali->flash_reg + CS_SETUP_CNT)); - find_valid_banks(denali); - /* * If the user specified to override the default timings * with a specific ONFI mode, we apply those changes here. diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 352d8328b94a..0e4a8965f6f1 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -326,7 +326,6 @@ struct denali_nand_info { int platform; struct nand_buf buf; struct device *dev; - int total_used_banks; int page; void __iomem *flash_reg; /* Register Interface */ void __iomem *flash_mem; /* Host Data/Command Interface */ From patchwork Wed Jun 7 11:52:18 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103235 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1714807obh; Wed, 7 Jun 2017 04:55:43 -0700 (PDT) X-Received: by 10.84.198.3 with SMTP id o3mr27168758pld.60.1496836542909; Wed, 07 Jun 2017 04:55:42 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836542; cv=none; d=google.com; s=arc-20160816; b=0x9E1tLblSXFWUPCfcPQJUIWJIoabWgsfDK8CGZakP2URVFBC6I5oQehLsL9zeQAGC B/xCGjiZs/WPc+f/4szHn6eSgu7vku65ykdZ54bY08q7YLzZpU1LLVSRoct2eDpv8kXy ND+VpnTXKxK62PwAPeMwNJJ2tjbzMG6z0jBG+LuuopWP/yTja5BgxfHeJVytJwRr3fCl OOmCtbighAuODaP+BBD/SzdWWRc1lJ2BKW5GM1hPp4tWgYO66v6k3ciZWT8JpQxaFMrS 9i4qWtlaQQ6z9Nu0yL5PBY44SpegMcV0qajlIWPk5cqANIjH2+hyfGlUT//aIUyq+1S6 GPIg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=OYuu09SXsNUlVprdDSVc95yH9yLynLwZnnipp9PQVXU=; b=IsrTZVroPDr0r3sBrcu5CHsAjqccShCZPBlzPolji4e5dPHVefCMv0hevmpi1hGVeO JDTJSuMSAv5FAWI9eULnwEwH4tJ6Iofvv2Mn5Ri+fdqECz8rWz2NhnBhGKCQM9zl9DIx epo16rYhUn77J3mCEVH/Mxe/MZepCJ0C3feO+mCbKvkY4cfzYUEtTTMQsXlkORk6IUn5 dqGLehde/HjFIPdeG60fiQBv4pc618l4Tci99X7ubSR+KVtzAmiY2Xs+Bi7J9UavzZwk U6HEUWSCO4wrnmmpsFPTUQ0dC3+egWNvaqOBX8l9X9PHZXQ0uKdYK6Tlr7E5tPNflUQY Iozg== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id e186si1569105pgc.163.2017.06.07.04.55.42; Wed, 07 Jun 2017 04:55:42 -0700 (PDT) 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 S1751680AbdFGLza (ORCPT + 25 others); Wed, 7 Jun 2017 07:55:30 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42591 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751591AbdFGLz2 (ORCPT ); Wed, 7 Jun 2017 07:55:28 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZY014276; Wed, 7 Jun 2017 20:52:56 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZY014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836377; bh=OYuu09SXsNUlVprdDSVc95yH9yLynLwZnnipp9PQVXU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FZrdnAUyEhcfjXpJVREqWCwycDDMza2vPCwFwdCbnHakPGWjyNbJb+WxDFgaZebkP q2qh2mJ3wo2mX08kKwVjKA+ubiisYYvvg0vieeYpmd74DDRb7umGr5VKwXmbymDpDv 4iSKDFDKBGTUqRcVV3xR9fu5LclLyzx+I6U4oscGFuNACbkHuhfdgEge1ueGhqmEcF Wb7a4jDeOIpZoURhSKqseJRee/IHWE0r1LuFcaBybDomgg0IsGEES/NL0tkVKyS884 APBeZ4jzGcDsIGL0YAalhiZX0s2XKOGQJPBxUUrmNWPfZnPj/3WLuh6zABv+WRagvx DUrybWfW0N8ow== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 09/23] mtd: nand: denali: handle timing parameters by setup_data_interface() Date: Wed, 7 Jun 2017 20:52:18 +0900 Message-Id: <1496836352-8016-10-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 Handling timing parameters in a driver's own way should be avoided because it duplicates efforts of drivers/mtd/nand/nand_timings.c Besides, this driver hard-codes Intel specific parameters such as CLK_X=5, CLK_MULTI=4. Taking a certain device (Samsung K9WAG08U1A) into account by get_samsung_nand_para() is weird as well. Now, the core framework provides .setup_data_interface() hook, which handles timing parameters in a generic manner. While I am working on this, I found even more issues in the current code, so fixed the following as well: - In recent IP versions, WE_2_RE and TWHR2 share the same register. Likewise for ADDR_2_DATA and TCWAW, CS_SETUP_CNT and TWB. When updating one, the other must be masked. Otherwise, the other will be set to 0, then timing settings will be broken. - The recent IP release expanded the ADDR_2_DATA to 7-bit wide. This register is related to tADL. As commit 74a332e78e8f ("mtd: nand: timings: Fix tADL_min for ONFI 4.0 chips") addressed, the ONFi 4.0 increased the minimum of tADL to 400 nsec. This may not fit in the 6-bit ADDR_2_DATA in older versions. Check the IP revision and handle this correctly, otherwise the register value would wrap around. Signed-off-by: Masahiro Yamada --- Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 351 +++++++++++++++--------------------------- drivers/mtd/nand/denali.h | 26 ++-- drivers/mtd/nand/denali_dt.c | 3 +- drivers/mtd/nand/denali_pci.c | 6 +- 4 files changed, 142 insertions(+), 244 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index f090486cab66..8ad1e96f6d03 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -28,17 +28,6 @@ MODULE_LICENSE("GPL"); -/* - * We define a module parameter that allows the user to override - * the hardware and decide what timing mode should be used. - */ -#define NAND_DEFAULT_TIMINGS -1 - -static int onfi_timing_mode = NAND_DEFAULT_TIMINGS; -module_param(onfi_timing_mode, int, S_IRUGO); -MODULE_PARM_DESC(onfi_timing_mode, - "Overrides default ONFI setting. -1 indicates use default timings"); - #define DENALI_NAND_NAME "denali-nand" /* @@ -63,12 +52,6 @@ MODULE_PARM_DESC(onfi_timing_mode, #define CHIP_SELECT_INVALID -1 /* - * This macro divides two integers and rounds fractional values up - * to the nearest integer value. - */ -#define CEIL_DIV(X, Y) (((X)%(Y)) ? ((X)/(Y)+1) : ((X)/(Y))) - -/* * this macro allows us to convert from an MTD structure to our own * device context (denali) structure. */ @@ -103,6 +86,14 @@ static void denali_irq_enable(struct denali_nand_info *denali, static uint32_t read_interrupt_status(struct denali_nand_info *denali); /* + * The bus interface clock, clk_x, is phase aligned with the core clock. The + * clk_x is an integral multiple N of the core clk. The value N is configured + * at IP delivery time, and its available value is 4, 5, or 6. We need to align + * to the largest value to make it work with any possible configuration. + */ +#define DENALI_CLK_X_MULT 6 + +/* * Certain operations for the denali NAND controller use an indexed mode to * read/write data. The operation is performed by writing the address value * of the command to the device memory followed by the data. This function @@ -196,148 +187,6 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali) } /* - * this routine calculates the ONFI timing values for a given mode and - * programs the clocking register accordingly. The mode is determined by - * the get_onfi_nand_para routine. - */ -static void nand_onfi_timing_set(struct denali_nand_info *denali, - uint16_t mode) -{ - uint16_t Trea[6] = {40, 30, 25, 20, 20, 16}; - uint16_t Trp[6] = {50, 25, 17, 15, 12, 10}; - uint16_t Treh[6] = {30, 15, 15, 10, 10, 7}; - uint16_t Trc[6] = {100, 50, 35, 30, 25, 20}; - uint16_t Trhoh[6] = {0, 15, 15, 15, 15, 15}; - uint16_t Trloh[6] = {0, 0, 0, 0, 5, 5}; - uint16_t Tcea[6] = {100, 45, 30, 25, 25, 25}; - uint16_t Tadl[6] = {200, 100, 100, 100, 70, 70}; - uint16_t Trhw[6] = {200, 100, 100, 100, 100, 100}; - uint16_t Trhz[6] = {200, 100, 100, 100, 100, 100}; - uint16_t Twhr[6] = {120, 80, 80, 60, 60, 60}; - uint16_t Tcs[6] = {70, 35, 25, 25, 20, 15}; - - uint16_t data_invalid_rhoh, data_invalid_rloh, data_invalid; - uint16_t dv_window = 0; - uint16_t en_lo, en_hi; - uint16_t acc_clks; - uint16_t addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt; - - en_lo = CEIL_DIV(Trp[mode], CLK_X); - en_hi = CEIL_DIV(Treh[mode], CLK_X); -#if ONFI_BLOOM_TIME - if ((en_hi * CLK_X) < (Treh[mode] + 2)) - en_hi++; -#endif - - if ((en_lo + en_hi) * CLK_X < Trc[mode]) - en_lo += CEIL_DIV((Trc[mode] - (en_lo + en_hi) * CLK_X), CLK_X); - - if ((en_lo + en_hi) < CLK_MULTI) - en_lo += CLK_MULTI - en_lo - en_hi; - - while (dv_window < 8) { - data_invalid_rhoh = en_lo * CLK_X + Trhoh[mode]; - - data_invalid_rloh = (en_lo + en_hi) * CLK_X + Trloh[mode]; - - data_invalid = data_invalid_rhoh < data_invalid_rloh ? - data_invalid_rhoh : data_invalid_rloh; - - dv_window = data_invalid - Trea[mode]; - - if (dv_window < 8) - en_lo++; - } - - acc_clks = CEIL_DIV(Trea[mode], CLK_X); - - while (acc_clks * CLK_X - Trea[mode] < 3) - acc_clks++; - - if (data_invalid - acc_clks * CLK_X < 2) - dev_warn(denali->dev, "%s, Line %d: Warning!\n", - __FILE__, __LINE__); - - addr_2_data = CEIL_DIV(Tadl[mode], CLK_X); - re_2_we = CEIL_DIV(Trhw[mode], CLK_X); - re_2_re = CEIL_DIV(Trhz[mode], CLK_X); - we_2_re = CEIL_DIV(Twhr[mode], CLK_X); - cs_cnt = CEIL_DIV((Tcs[mode] - Trp[mode]), CLK_X); - if (cs_cnt == 0) - cs_cnt = 1; - - if (Tcea[mode]) { - while (cs_cnt * CLK_X + Trea[mode] < Tcea[mode]) - cs_cnt++; - } - -#if MODE5_WORKAROUND - if (mode == 5) - acc_clks = 5; -#endif - - /* Sighting 3462430: Temporary hack for MT29F128G08CJABAWP:B */ - if (ioread32(denali->flash_reg + MANUFACTURER_ID) == 0 && - ioread32(denali->flash_reg + DEVICE_ID) == 0x88) - acc_clks = 6; - - iowrite32(acc_clks, denali->flash_reg + ACC_CLKS); - iowrite32(re_2_we, denali->flash_reg + RE_2_WE); - iowrite32(re_2_re, denali->flash_reg + RE_2_RE); - iowrite32(we_2_re, denali->flash_reg + WE_2_RE); - iowrite32(addr_2_data, denali->flash_reg + ADDR_2_DATA); - iowrite32(en_lo, denali->flash_reg + RDWR_EN_LO_CNT); - iowrite32(en_hi, denali->flash_reg + RDWR_EN_HI_CNT); - iowrite32(cs_cnt, denali->flash_reg + CS_SETUP_CNT); -} - -/* queries the NAND device to see what ONFI modes it supports. */ -static uint16_t get_onfi_nand_para(struct denali_nand_info *denali) -{ - int i; - - /* - * we needn't to do a reset here because driver has already - * reset all the banks before - */ - if (!(ioread32(denali->flash_reg + ONFI_TIMING_MODE) & - ONFI_TIMING_MODE__VALUE)) - return FAIL; - - for (i = 5; i > 0; i--) { - if (ioread32(denali->flash_reg + ONFI_TIMING_MODE) & - (0x01 << i)) - break; - } - - nand_onfi_timing_set(denali, i); - - /* - * By now, all the ONFI devices we know support the page cache - * rw feature. So here we enable the pipeline_rw_ahead feature - */ - /* iowrite32(1, denali->flash_reg + CACHE_WRITE_ENABLE); */ - /* iowrite32(1, denali->flash_reg + CACHE_READ_ENABLE); */ - - return PASS; -} - -static void get_samsung_nand_para(struct denali_nand_info *denali, - uint8_t device_id) -{ - if (device_id == 0xd3) { /* Samsung K9WAG08U1A */ - /* Set timing register values according to datasheet */ - iowrite32(5, denali->flash_reg + ACC_CLKS); - iowrite32(20, denali->flash_reg + RE_2_WE); - iowrite32(12, denali->flash_reg + WE_2_RE); - iowrite32(14, denali->flash_reg + ADDR_2_DATA); - iowrite32(3, denali->flash_reg + RDWR_EN_LO_CNT); - iowrite32(2, denali->flash_reg + RDWR_EN_HI_CNT); - iowrite32(2, denali->flash_reg + CS_SETUP_CNT); - } -} - -/* * Use the configuration feature register to determine the maximum number of * banks that the hardware supports. */ @@ -352,58 +201,6 @@ static void detect_max_banks(struct denali_nand_info *denali) denali->max_banks <<= 1; } -static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) -{ - uint16_t status = PASS; - uint32_t id_bytes[8], addr; - uint8_t maf_id, device_id; - int i; - - /* - * Use read id method to get device ID and other params. - * For some NAND chips, controller can't report the correct - * device ID by reading from DEVICE_ID register - */ - addr = MODE_11 | BANK(denali->flash_bank); - index_addr(denali, addr | 0, 0x90); - index_addr(denali, addr | 1, 0); - for (i = 0; i < 8; i++) - index_addr_read_data(denali, addr | 2, &id_bytes[i]); - maf_id = id_bytes[0]; - device_id = id_bytes[1]; - - if (ioread32(denali->flash_reg + ONFI_DEVICE_NO_OF_LUNS) & - ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE) { /* ONFI 1.0 NAND */ - if (FAIL == get_onfi_nand_para(denali)) - return FAIL; - } else if (maf_id == 0xEC) { /* Samsung NAND */ - get_samsung_nand_para(denali, device_id); - } - - dev_info(denali->dev, - "Dump timing register values:\n" - "acc_clks: %d, re_2_we: %d, re_2_re: %d\n" - "we_2_re: %d, addr_2_data: %d, rdwr_en_lo_cnt: %d\n" - "rdwr_en_hi_cnt: %d, cs_setup_cnt: %d\n", - ioread32(denali->flash_reg + ACC_CLKS), - ioread32(denali->flash_reg + RE_2_WE), - ioread32(denali->flash_reg + RE_2_RE), - ioread32(denali->flash_reg + WE_2_RE), - ioread32(denali->flash_reg + ADDR_2_DATA), - ioread32(denali->flash_reg + RDWR_EN_LO_CNT), - ioread32(denali->flash_reg + RDWR_EN_HI_CNT), - ioread32(denali->flash_reg + CS_SETUP_CNT)); - - /* - * If the user specified to override the default timings - * with a specific ONFI mode, we apply those changes here. - */ - if (onfi_timing_mode != NAND_DEFAULT_TIMINGS) - nand_onfi_timing_set(denali, onfi_timing_mode); - - return status; -} - static void denali_set_intr_modes(struct denali_nand_info *denali, uint16_t INT_ENABLE) { @@ -1209,7 +1006,122 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, break; } } -/* end NAND core entry points */ + +#define DIV_ROUND_DOWN_ULL(ll, d) \ + ({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; }) + +static int denali_setup_data_interface(struct mtd_info *mtd, + const struct nand_data_interface *conf, + bool check_only) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + const struct nand_sdr_timings *timings; + unsigned long t_clk; + int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data; + int rdwr_en_lo, rdwr_en_hi, rdwr_en_lo_hi, cs_setup; + int addr_2_data_mask; + uint32_t tmp; + + timings = nand_get_sdr_timings(conf); + if (IS_ERR(timings)) + return PTR_ERR(timings); + + /* clk_x period in picoseconds */ + t_clk = DIV_ROUND_DOWN_ULL(1000000000000ULL, denali->clk_x_rate); + if (!t_clk) + return -EINVAL; + + if (check_only) + return 0; + + /* tREA -> ACC_CLKS */ + acc_clks = DIV_ROUND_UP(timings->tREA_max, t_clk); + acc_clks = min_t(int, acc_clks, ACC_CLKS__VALUE); + + tmp = ioread32(denali->flash_reg + ACC_CLKS); + tmp &= ~ACC_CLKS__VALUE; + tmp |= acc_clks; + iowrite32(tmp, denali->flash_reg + ACC_CLKS); + + /* tRWH -> RE_2_WE */ + re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_clk); + re_2_we = min_t(int, re_2_we, RE_2_WE__VALUE); + + tmp = ioread32(denali->flash_reg + RE_2_WE); + tmp &= ~RE_2_WE__VALUE; + tmp |= re_2_we; + iowrite32(tmp, denali->flash_reg + RE_2_WE); + + /* tRHZ -> RE_2_RE */ + re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_clk); + re_2_re = min_t(int, re_2_re, RE_2_RE__VALUE); + + tmp = ioread32(denali->flash_reg + RE_2_RE); + tmp &= ~RE_2_RE__VALUE; + tmp |= re_2_re; + iowrite32(tmp, denali->flash_reg + RE_2_RE); + + /* tWHR -> WE_2_RE */ + we_2_re = DIV_ROUND_UP(timings->tWHR_min, t_clk); + we_2_re = min_t(int, we_2_re, TWHR2_AND_WE_2_RE__WE_2_RE); + + tmp = ioread32(denali->flash_reg + TWHR2_AND_WE_2_RE); + tmp &= ~TWHR2_AND_WE_2_RE__WE_2_RE; + tmp |= we_2_re; + iowrite32(tmp, denali->flash_reg + TWHR2_AND_WE_2_RE); + + /* tADL -> ADDR_2_DATA */ + + /* for older versions, ADDR_2_DATA is only 6 bit wide */ + addr_2_data_mask = TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA; + if (denali->revision < 0x0501) + addr_2_data_mask >>= 1; + + addr_2_data = DIV_ROUND_UP(timings->tADL_min, t_clk); + addr_2_data = min_t(int, addr_2_data, addr_2_data_mask); + + tmp = ioread32(denali->flash_reg + TCWAW_AND_ADDR_2_DATA); + tmp &= ~addr_2_data_mask; + tmp |= addr_2_data; + iowrite32(tmp, denali->flash_reg + TCWAW_AND_ADDR_2_DATA); + + /* tREH, tWH -> RDWR_EN_HI_CNT */ + rdwr_en_hi = DIV_ROUND_UP(max(timings->tREH_min, timings->tWH_min), + t_clk); + rdwr_en_hi = min_t(int, rdwr_en_hi, RDWR_EN_HI_CNT__VALUE); + + tmp = ioread32(denali->flash_reg + RDWR_EN_HI_CNT); + tmp &= ~RDWR_EN_HI_CNT__VALUE; + tmp |= rdwr_en_hi; + iowrite32(tmp, denali->flash_reg + RDWR_EN_HI_CNT); + + /* tRP, tWP -> RDWR_EN_LO_CNT */ + rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min), + t_clk); + rdwr_en_lo_hi = DIV_ROUND_UP(max(timings->tRC_min, timings->tWC_min), + t_clk); + rdwr_en_lo_hi = max(rdwr_en_lo_hi, DENALI_CLK_X_MULT); + rdwr_en_lo = max(rdwr_en_lo, rdwr_en_lo_hi - rdwr_en_hi); + rdwr_en_lo = min_t(int, rdwr_en_lo, RDWR_EN_LO_CNT__VALUE); + + tmp = ioread32(denali->flash_reg + RDWR_EN_LO_CNT); + tmp &= ~RDWR_EN_LO_CNT__VALUE; + tmp |= rdwr_en_lo; + iowrite32(tmp, denali->flash_reg + RDWR_EN_LO_CNT); + + /* tCS, tCEA -> CS_SETUP_CNT */ + cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_clk) - rdwr_en_lo, + (int)DIV_ROUND_UP(timings->tCEA_max, t_clk) - acc_clks, + 0); + cs_setup = min_t(int, cs_setup, CS_SETUP_CNT__VALUE); + + tmp = ioread32(denali->flash_reg + CS_SETUP_CNT); + tmp &= ~CS_SETUP_CNT__VALUE; + tmp |= cs_setup; + iowrite32(tmp, denali->flash_reg + CS_SETUP_CNT); + + return 0; +} /* Initialization code to bring the device up to a known good state */ static void denali_hw_init(struct denali_nand_info *denali) @@ -1241,7 +1153,6 @@ static void denali_hw_init(struct denali_nand_info *denali) /* Should set value for these registers when init */ iowrite32(0, denali->flash_reg + TWO_ROW_ADDR_CYCLES); iowrite32(1, denali->flash_reg + ECC_ENABLE); - denali_nand_timing_set(denali); denali_irq_init(denali); } @@ -1416,17 +1327,6 @@ int denali_init(struct denali_nand_info *denali) struct mtd_info *mtd = nand_to_mtd(chip); int ret; - if (denali->platform == INTEL_CE4100) { - /* - * Due to a silicon limitation, we can only support - * ONFI timing mode 1 and below. - */ - if (onfi_timing_mode < -1 || onfi_timing_mode > 1) { - pr_err("Intel CE4100 only supports ONFI timing mode 1 or below\n"); - return -EINVAL; - } - } - /* allocate a temporary buffer for nand_scan_ident() */ denali->buf.buf = devm_kzalloc(denali->dev, PAGE_SIZE, GFP_DMA | GFP_KERNEL); @@ -1457,6 +1357,9 @@ int denali_init(struct denali_nand_info *denali) chip->cmdfunc = denali_cmdfunc; chip->read_byte = denali_read_byte; chip->waitfunc = denali_waitfunc; + /* clk rate info is needed for setup_data_interface */ + if (denali->clk_x_rate) + chip->setup_data_interface = denali_setup_data_interface; /* * scan for NAND devices attached to the controller diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 0e4a8965f6f1..fb473895a79d 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -72,11 +72,14 @@ #define GLOBAL_INT_ENABLE 0xf0 #define GLOBAL_INT_EN_FLAG BIT(0) -#define WE_2_RE 0x100 -#define WE_2_RE__VALUE GENMASK(5, 0) +#define TWHR2_AND_WE_2_RE 0x100 +#define TWHR2_AND_WE_2_RE__WE_2_RE GENMASK(5, 0) +#define TWHR2_AND_WE_2_RE__TWHR2 GENMASK(13, 8) -#define ADDR_2_DATA 0x110 -#define ADDR_2_DATA__VALUE GENMASK(5, 0) +#define TCWAW_AND_ADDR_2_DATA 0x110 +/* The width of ADDR_2_DATA is 6 bit for old IP, 7 bit for new IP */ +#define TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA GENMASK(6, 0) +#define TCWAW_AND_ADDR_2_DATA__TCWAW GENMASK(13, 8) #define RE_2_WE 0x120 #define RE_2_WE__VALUE GENMASK(5, 0) @@ -128,6 +131,7 @@ #define CS_SETUP_CNT 0x220 #define CS_SETUP_CNT__VALUE GENMASK(4, 0) +#define CS_SETUP_CNT__TWB GENMASK(17, 12) #define SPARE_AREA_SKIP_BYTES 0x230 #define SPARE_AREA_SKIP_BYTES__VALUE GENMASK(5, 0) @@ -294,16 +298,8 @@ #define CHNL_ACTIVE__CHANNEL2 BIT(2) #define CHNL_ACTIVE__CHANNEL3 BIT(3) -#define FAIL 1 /*failed flag*/ #define PASS 0 /*success flag*/ -#define CLK_X 5 -#define CLK_MULTI 4 - -#define ONFI_BLOOM_TIME 1 -#define MODE5_WORKAROUND 0 - - #define MODE_00 0x00000000 #define MODE_01 0x04000000 #define MODE_10 0x08000000 @@ -316,14 +312,10 @@ struct nand_buf { dma_addr_t dma_buf; }; -#define INTEL_CE4100 1 -#define INTEL_MRST 2 -#define DT 3 - struct denali_nand_info { struct nand_chip nand; + unsigned long clk_x_rate; /* bus interface clock rate */ int flash_bank; /* currently selected chip */ - int platform; struct nand_buf buf; struct device *dev; int page; diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index be598230c108..ebcce50f4005 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -96,7 +96,6 @@ static int denali_dt_probe(struct platform_device *pdev) denali->ecc_caps = data->ecc_caps; } - denali->platform = DT; denali->dev = &pdev->dev; denali->irq = platform_get_irq(pdev, 0); if (denali->irq < 0) { @@ -121,6 +120,8 @@ static int denali_dt_probe(struct platform_device *pdev) } clk_prepare_enable(dt->clk); + denali->clk_x_rate = clk_get_rate(dt->clk); + ret = denali_init(denali); if (ret) goto out_disable_clk; diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c index 37dc0934c24c..6217525c1000 100644 --- a/drivers/mtd/nand/denali_pci.c +++ b/drivers/mtd/nand/denali_pci.c @@ -19,6 +19,9 @@ #define DENALI_NAND_NAME "denali-nand-pci" +#define INTEL_CE4100 1 +#define INTEL_MRST 2 + /* List of platforms this NAND controller has be integrated into */ static const struct pci_device_id denali_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 }, @@ -47,13 +50,11 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) } if (id->driver_data == INTEL_CE4100) { - denali->platform = INTEL_CE4100; mem_base = pci_resource_start(dev, 0); mem_len = pci_resource_len(dev, 1); csr_base = pci_resource_start(dev, 1); csr_len = pci_resource_len(dev, 1); } else { - denali->platform = INTEL_MRST; csr_base = pci_resource_start(dev, 0); csr_len = pci_resource_len(dev, 0); mem_base = pci_resource_start(dev, 1); @@ -69,6 +70,7 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) denali->irq = dev->irq; denali->ecc_caps = &denali_pci_ecc_caps; denali->nand.ecc.options |= NAND_ECC_MAXIMIZE; + denali->clk_x_rate = 200000000; /* 200 MHz */ ret = pci_request_regions(dev, DENALI_NAND_NAME); if (ret) { From patchwork Wed Jun 7 11:52:19 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103252 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1716219obh; Wed, 7 Jun 2017 04:59:30 -0700 (PDT) X-Received: by 10.84.171.195 with SMTP id l61mr27341134plb.147.1496836770494; Wed, 07 Jun 2017 04:59:30 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836770; cv=none; d=google.com; s=arc-20160816; b=j+P4PXMla6l2ME+lSw3sUoFR1spXH5p0/HqptfW6B+YfnYGKhqSCkvl+z5C+ar0qrq ZvdwhxOKLlzo92gHgm+9AHa2kct+HH2GBM953hu1DdeGqARQWWOxgyWJTLWqZAuC4VO5 bxXAzT4gMLW6j+a3LXCkIWN1i+UkEAgtV10f+l9ntviYuZ3OWQg0RNd8C1o77TBzji77 Ymbscznem8pwD2XnumBMx73gYIVrob2uyZPzEgVQxcXl06jIuonqE9msoWiOM95kCwUA 3GHiZMectxd1a8tX7I8FjVPnSghYDdDGnzgF5x89YasgHlB5j9GEvDyTEjkAOpTuXAyw 5pJA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=+Hc70FmY0qdM61fyW54XoITUlGIDSjPPLXe0n+RRsWs=; b=b4ylVXIy4Oblynn9YtvRzgNOxh9zuoy/3tnQW4BL0pSONVUGdxdbHUyd5j4eoEhSrt hAUgFqjEjXvI5i2LDhiAirnloYcd54I25qZjXtfzIW178TdsK4NqbDqw0eiBQtSULa1L lBvgDsDVLbSBJoj+dPyVv3xz3wUXbk8QYF5rvRENS/s9ySJEZeMUpV4BJokwNTmpFicy x4miq30ReHKbAM8y9AoFLCpdpU8Hc5cyVCyYAhqfBjvNcreSOQl+iFU6yAoRLD3sUgYq 6TZzXzyo+35UrBV+uDW05rhbL7VFSO0KH3eiH4iJuMaOTEZye3Yr2wEMZKkHl/YdCtyp ls4w== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id a187si1589687pge.160.2017.06.07.04.59.30; Wed, 07 Jun 2017 04:59:30 -0700 (PDT) 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 S1751911AbdFGL71 (ORCPT + 25 others); Wed, 7 Jun 2017 07:59:27 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42462 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751547AbdFGLzX (ORCPT ); Wed, 7 Jun 2017 07:55:23 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZZ014276; Wed, 7 Jun 2017 20:52:57 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZZ014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836378; bh=+Hc70FmY0qdM61fyW54XoITUlGIDSjPPLXe0n+RRsWs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uuPgdfzJ11Y3vbYJ9RkBt37CVWCJZGaEpTRx3IwPr/g1WWsoROkL8xrUtIuggOeMR JpnYVT+xyXZWWopy5t+olnMeWvQoS7Oa70c5/tUyu/MwVOs3dRjNQ+1N+XRNi657xh PXZ3/D08gGAofKyK4dpVe11kr88QyVc6MP+k3SUdRI/Zv0IczSe0g7azXN6Coy7E0s eiCEITpCTRIF+WoEpakM3pcIjypfuI5vZbJ42urFRkBF9h0C21VC/sqEOH+A2Uzyht ib7P5X4U4zMb5ZGT5yfGJJCPqBVZaQWDnAXS5K2DD6+LR5dtx0IitQhHR+8319HqLG SEP1S+cFCEMgA== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 10/23] mtd: nand: denali: rework interrupt handling Date: Wed, 7 Jun 2017 20:52:19 +0900 Message-Id: <1496836352-8016-11-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 Simplify the interrupt handling and fix issues: - The register field view of INTR_EN / INTR_STATUS is different among IP versions. The global macro DENALI_IRQ_ALL is hard-coded for Intel platforms. The interrupt mask should be determined at run-time depending on the running platform. - wait_for_irq() loops do {} while() until interested flags are asserted. The logic can be simplified. - The spin_lock() guard seems too complex (and suspicious in a race condition if wait_for_completion_timeout() bails out by timeout). - denali->complete is reused again and again, but reinit_completion() is missing. Add it. Re-work the code to make it more robust and easier to handle. While we are here, also rename the jump label "failed_req_irq" to more appropriate "disable_irq". Signed-off-by: Masahiro Yamada --- Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 316 +++++++++++++++++----------------------------- drivers/mtd/nand/denali.h | 1 + 2 files changed, 116 insertions(+), 201 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 8ad1e96f6d03..62798e6d7009 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -31,21 +31,6 @@ MODULE_LICENSE("GPL"); #define DENALI_NAND_NAME "denali-nand" /* - * We define a macro here that combines all interrupts this driver uses into - * a single constant value, for convenience. - */ -#define DENALI_IRQ_ALL (INTR__DMA_CMD_COMP | \ - INTR__ECC_TRANSACTION_DONE | \ - INTR__ECC_ERR | \ - INTR__PROGRAM_FAIL | \ - INTR__LOAD_COMP | \ - INTR__PROGRAM_COMP | \ - INTR__TIME_OUT | \ - INTR__ERASE_FAIL | \ - INTR__RST_COMP | \ - INTR__ERASE_COMP) - -/* * indicates whether or not the internal value for the flash bank is * valid or not */ @@ -71,20 +56,14 @@ static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd) #define DENALI_READ 0 #define DENALI_WRITE 0x100 +#define DENALI_NR_BANKS 4 + /* * this is a helper macro that allows us to * format the bank into the proper bits for the controller */ #define BANK(x) ((x) << 24) -/* forward declarations */ -static void clear_interrupts(struct denali_nand_info *denali); -static uint32_t wait_for_irq(struct denali_nand_info *denali, - uint32_t irq_mask); -static void denali_irq_enable(struct denali_nand_info *denali, - uint32_t int_mask); -static uint32_t read_interrupt_status(struct denali_nand_info *denali); - /* * The bus interface clock, clk_x, is phase aligned with the core clock. The * clk_x is an integral multiple N of the core clk. The value N is configured @@ -143,22 +122,6 @@ static void read_status(struct denali_nand_info *denali) write_byte_to_buf(denali, 0); } -/* resets a specific device connected to the core */ -static void reset_bank(struct denali_nand_info *denali) -{ - uint32_t irq_status; - uint32_t irq_mask = INTR__RST_COMP | INTR__TIME_OUT; - - clear_interrupts(denali); - - iowrite32(1 << denali->flash_bank, denali->flash_reg + DEVICE_RESET); - - irq_status = wait_for_irq(denali, irq_mask); - - if (irq_status & INTR__TIME_OUT) - dev_err(denali->dev, "reset bank failed.\n"); -} - /* Reset the flash controller */ static uint16_t denali_nand_reset(struct denali_nand_info *denali) { @@ -201,169 +164,123 @@ static void detect_max_banks(struct denali_nand_info *denali) denali->max_banks <<= 1; } -static void denali_set_intr_modes(struct denali_nand_info *denali, - uint16_t INT_ENABLE) +static void denali_enable_irq(struct denali_nand_info *denali) { - if (INT_ENABLE) - iowrite32(1, denali->flash_reg + GLOBAL_INT_ENABLE); - else - iowrite32(0, denali->flash_reg + GLOBAL_INT_ENABLE); -} + int i; -/* - * validation function to verify that the controlling software is making - * a valid request - */ -static inline bool is_flash_bank_valid(int flash_bank) -{ - return flash_bank >= 0 && flash_bank < 4; + for (i = 0; i < DENALI_NR_BANKS; i++) + iowrite32(U32_MAX, denali->flash_reg + INTR_EN(i)); + iowrite32(GLOBAL_INT_EN_FLAG, denali->flash_reg + GLOBAL_INT_ENABLE); } -static void denali_irq_init(struct denali_nand_info *denali) +static void denali_disable_irq(struct denali_nand_info *denali) { - uint32_t int_mask; int i; - /* Disable global interrupts */ - denali_set_intr_modes(denali, false); - - int_mask = DENALI_IRQ_ALL; - - /* Clear all status bits */ - for (i = 0; i < denali->max_banks; ++i) - iowrite32(0xFFFF, denali->flash_reg + INTR_STATUS(i)); - - denali_irq_enable(denali, int_mask); + for (i = 0; i < DENALI_NR_BANKS; i++) + iowrite32(0, denali->flash_reg + INTR_EN(i)); + iowrite32(0, denali->flash_reg + GLOBAL_INT_ENABLE); } -static void denali_irq_cleanup(int irqnum, struct denali_nand_info *denali) +static void denali_clear_irq(struct denali_nand_info *denali, + int bank, uint32_t irq_status) { - denali_set_intr_modes(denali, false); + /* write one to clear bits */ + iowrite32(irq_status, denali->flash_reg + INTR_STATUS(bank)); } -static void denali_irq_enable(struct denali_nand_info *denali, - uint32_t int_mask) +static void denali_clear_irq_all(struct denali_nand_info *denali) { int i; - for (i = 0; i < denali->max_banks; ++i) - iowrite32(int_mask, denali->flash_reg + INTR_EN(i)); + for (i = 0; i < DENALI_NR_BANKS; i++) + denali_clear_irq(denali, i, U32_MAX); } -/* - * This function only returns when an interrupt that this driver cares about - * occurs. This is to reduce the overhead of servicing interrupts - */ -static inline uint32_t denali_irq_detected(struct denali_nand_info *denali) +static irqreturn_t denali_isr(int irq, void *dev_id) { - return read_interrupt_status(denali) & DENALI_IRQ_ALL; -} + struct denali_nand_info *denali = dev_id; + irqreturn_t ret = IRQ_NONE; + uint32_t irq_status; + int i; -/* Interrupts are cleared by writing a 1 to the appropriate status bit */ -static inline void clear_interrupt(struct denali_nand_info *denali, - uint32_t irq_mask) -{ - uint32_t intr_status_reg; + spin_lock(&denali->irq_lock); - intr_status_reg = INTR_STATUS(denali->flash_bank); + for (i = 0; i < DENALI_NR_BANKS; i++) { + irq_status = ioread32(denali->flash_reg + INTR_STATUS(i)); + if (irq_status) + ret = IRQ_HANDLED; - iowrite32(irq_mask, denali->flash_reg + intr_status_reg); -} + denali_clear_irq(denali, i, irq_status); -static void clear_interrupts(struct denali_nand_info *denali) -{ - uint32_t status; + if (i != denali->flash_bank) + continue; + + denali->irq_status |= irq_status; - spin_lock_irq(&denali->irq_lock); + if (denali->irq_status & denali->irq_mask) + complete(&denali->complete); + } - status = read_interrupt_status(denali); - clear_interrupt(denali, status); + spin_unlock(&denali->irq_lock); - denali->irq_status = 0x0; - spin_unlock_irq(&denali->irq_lock); + return ret; } -static uint32_t read_interrupt_status(struct denali_nand_info *denali) +static void denali_reset_irq(struct denali_nand_info *denali) { - uint32_t intr_status_reg; - - intr_status_reg = INTR_STATUS(denali->flash_bank); + unsigned long flags; - return ioread32(denali->flash_reg + intr_status_reg); + spin_lock_irqsave(&denali->irq_lock, flags); + denali->irq_status = 0; + denali->irq_mask = 0; + spin_unlock_irqrestore(&denali->irq_lock, flags); } -/* - * This is the interrupt service routine. It handles all interrupts - * sent to this device. Note that on CE4100, this is a shared interrupt. - */ -static irqreturn_t denali_isr(int irq, void *dev_id) +static uint32_t denali_wait_for_irq(struct denali_nand_info *denali, + uint32_t irq_mask) { - struct denali_nand_info *denali = dev_id; + unsigned long time_left, flags; uint32_t irq_status; - irqreturn_t result = IRQ_NONE; - spin_lock(&denali->irq_lock); + spin_lock_irqsave(&denali->irq_lock, flags); - /* check to see if a valid NAND chip has been selected. */ - if (is_flash_bank_valid(denali->flash_bank)) { - /* - * check to see if controller generated the interrupt, - * since this is a shared interrupt - */ - irq_status = denali_irq_detected(denali); - if (irq_status != 0) { - /* handle interrupt */ - /* first acknowledge it */ - clear_interrupt(denali, irq_status); - /* - * store the status in the device context for someone - * to read - */ - denali->irq_status |= irq_status; - /* notify anyone who cares that it happened */ - complete(&denali->complete); - /* tell the OS that we've handled this */ - result = IRQ_HANDLED; - } + irq_status = denali->irq_status; + + if (irq_mask & irq_status) { + spin_unlock_irqrestore(&denali->irq_lock, flags); + return irq_status; } - spin_unlock(&denali->irq_lock); - return result; + + denali->irq_mask = irq_mask; + reinit_completion(&denali->complete); + spin_unlock_irqrestore(&denali->irq_lock, flags); + + time_left = wait_for_completion_timeout(&denali->complete, + msecs_to_jiffies(1000)); + if (!time_left) { + dev_err(denali->dev, "timeout while waiting for irq 0x%x\n", + denali->irq_mask); + return 0; + } + + return denali->irq_status; } -static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) +/* resets a specific device connected to the core */ +static void reset_bank(struct denali_nand_info *denali) { - unsigned long comp_res; - uint32_t intr_status; - unsigned long timeout = msecs_to_jiffies(1000); + uint32_t irq_status; - do { - comp_res = - wait_for_completion_timeout(&denali->complete, timeout); - spin_lock_irq(&denali->irq_lock); - intr_status = denali->irq_status; - - if (intr_status & irq_mask) { - denali->irq_status &= ~irq_mask; - spin_unlock_irq(&denali->irq_lock); - /* our interrupt was detected */ - break; - } + denali_reset_irq(denali); - /* - * these are not the interrupts you are looking for - - * need to wait again - */ - spin_unlock_irq(&denali->irq_lock); - } while (comp_res != 0); + iowrite32(1 << denali->flash_bank, denali->flash_reg + DEVICE_RESET); - if (comp_res == 0) { - /* timeout */ - pr_err("timeout occurred, status = 0x%x, mask = 0x%x\n", - intr_status, irq_mask); + irq_status = denali_wait_for_irq(denali, + INTR__RST_COMP | INTR__TIME_OUT); - intr_status = 0; - } - return intr_status; + if (!(irq_status & INTR__RST_COMP)) + dev_err(denali->dev, "reset bank failed.\n"); } /* @@ -397,7 +314,7 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, setup_ecc_for_xfer(denali, ecc_en, transfer_spare); - clear_interrupts(denali); + denali_reset_irq(denali); addr = BANK(denali->flash_bank) | denali->page; @@ -479,9 +396,9 @@ static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) write_data_to_flash_mem(denali, buf, mtd->oobsize); /* wait for operation to complete */ - irq_status = wait_for_irq(denali, irq_mask); + irq_status = denali_wait_for_irq(denali, irq_mask); - if (irq_status == 0) { + if (!(irq_status & INTR__PROGRAM_COMP)) { dev_err(denali->dev, "OOB write failed\n"); status = -EIO; } @@ -510,9 +427,9 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) * can always use status0 bit as the * mask is identical for each bank. */ - irq_status = wait_for_irq(denali, irq_mask); + irq_status = denali_wait_for_irq(denali, irq_mask); - if (irq_status == 0) + if (!(irq_status & INTR__LOAD_COMP)) dev_err(denali->dev, "page on OOB timeout %d\n", denali->page); @@ -620,9 +537,9 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd, unsigned int err_byte, err_sector, err_device; uint8_t err_cor_value; unsigned int prev_sector = 0; + uint32_t irq_status; - /* read the ECC errors. we'll ignore them for now */ - denali_set_intr_modes(denali, false); + denali_reset_irq(denali); do { err_addr = ioread32(denali->flash_reg + ECC_ERROR_ADDRESS); @@ -674,10 +591,9 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd, * ECC_TRANSACTION_DONE interrupt, so here just wait for * a while for this interrupt */ - while (!(read_interrupt_status(denali) & INTR__ECC_TRANSACTION_DONE)) - cpu_relax(); - clear_interrupts(denali); - denali_set_intr_modes(denali, true); + irq_status = denali_wait_for_irq(denali, INTR__ECC_TRANSACTION_DONE); + if (!(irq_status & INTR__ECC_TRANSACTION_DONE)) + return -EIO; return max_bitflips; } @@ -778,15 +694,14 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, dma_sync_single_for_device(denali->dev, addr, size, DMA_TO_DEVICE); - clear_interrupts(denali); + denali_reset_irq(denali); denali_enable_dma(denali, true); denali_setup_dma(denali, DENALI_WRITE); /* wait for operation to complete */ - irq_status = wait_for_irq(denali, irq_mask); - - if (irq_status == 0) { + irq_status = denali_wait_for_irq(denali, irq_mask); + if (!(irq_status & INTR__DMA_CMD_COMP)) { dev_err(denali->dev, "timeout on write_page (type = %d)\n", raw_xfer); ret = -EIO; @@ -865,11 +780,11 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, denali_enable_dma(denali, true); dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE); - clear_interrupts(denali); + denali_reset_irq(denali); denali_setup_dma(denali, DENALI_READ); /* wait for operation to complete */ - irq_status = wait_for_irq(denali, irq_mask); + irq_status = denali_wait_for_irq(denali, irq_mask); dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE); @@ -901,6 +816,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, dma_addr_t addr = denali->buf.dma_buf; size_t size = mtd->writesize + mtd->oobsize; uint32_t irq_mask = INTR__DMA_CMD_COMP; + uint32_t irq_status; denali->page = page; @@ -909,11 +825,13 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE); - clear_interrupts(denali); + denali_reset_irq(denali); denali_setup_dma(denali, DENALI_READ); /* wait for operation to complete */ - wait_for_irq(denali, irq_mask); + irq_status = denali_wait_for_irq(denali, irq_mask); + if (irq_status & INTR__DMA_CMD_COMP) + return -ETIMEDOUT; dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE); @@ -940,9 +858,7 @@ static void denali_select_chip(struct mtd_info *mtd, int chip) { struct denali_nand_info *denali = mtd_to_denali(mtd); - spin_lock_irq(&denali->irq_lock); denali->flash_bank = chip; - spin_unlock_irq(&denali->irq_lock); } static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) @@ -953,19 +869,19 @@ static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) static int denali_erase(struct mtd_info *mtd, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t cmd, irq_status; - clear_interrupts(denali); + denali_reset_irq(denali); /* setup page read request for access type */ cmd = MODE_10 | BANK(denali->flash_bank) | page; index_addr(denali, cmd, 0x1); /* wait for erase to complete or failure to occur */ - irq_status = wait_for_irq(denali, INTR__ERASE_COMP | INTR__ERASE_FAIL); + irq_status = denali_wait_for_irq(denali, + INTR__ERASE_COMP | INTR__ERASE_FAIL); - return irq_status & INTR__ERASE_FAIL ? NAND_STATUS_FAIL : PASS; + return irq_status & INTR__ERASE_COMP ? 0 : NAND_STATUS_FAIL; } static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, @@ -1153,7 +1069,6 @@ static void denali_hw_init(struct denali_nand_info *denali) /* Should set value for these registers when init */ iowrite32(0, denali->flash_reg + TWO_ROW_ADDR_CYCLES); iowrite32(1, denali->flash_reg + ECC_ENABLE); - denali_irq_init(denali); } int denali_calc_ecc_bytes(int step_size, int strength) @@ -1265,9 +1180,6 @@ static void denali_drv_init(struct denali_nand_info *denali) /* indicate that MTD has not selected a valid bank yet */ denali->flash_bank = CHIP_SELECT_INVALID; - - /* initialize our irq_status variable to indicate no interrupts */ - denali->irq_status = 0; } static int denali_multidev_fixup(struct denali_nand_info *denali) @@ -1337,6 +1249,8 @@ int denali_init(struct denali_nand_info *denali) denali_hw_init(denali); denali_drv_init(denali); + denali_clear_irq_all(denali); + /* Request IRQ after all the hardware initialization is finished */ ret = devm_request_irq(denali->dev, denali->irq, denali_isr, IRQF_SHARED, DENALI_NAND_NAME, denali); @@ -1345,8 +1259,8 @@ int denali_init(struct denali_nand_info *denali) return ret; } - /* now that our ISR is registered, we can enable interrupts */ - denali_set_intr_modes(denali, true); + denali_enable_irq(denali); + nand_set_flash_node(chip, denali->dev->of_node); /* Fallback to the default name if DT did not give "label" property */ if (!mtd->name) @@ -1368,7 +1282,7 @@ int denali_init(struct denali_nand_info *denali) */ ret = nand_scan_ident(mtd, denali->max_banks, NULL); if (ret) - goto failed_req_irq; + goto disable_irq; /* allocate the right size buffer now */ devm_kfree(denali->dev, denali->buf.buf); @@ -1377,7 +1291,7 @@ int denali_init(struct denali_nand_info *denali) GFP_KERNEL); if (!denali->buf.buf) { ret = -ENOMEM; - goto failed_req_irq; + goto disable_irq; } ret = dma_set_mask(denali->dev, @@ -1385,7 +1299,7 @@ int denali_init(struct denali_nand_info *denali) 64 : 32)); if (ret) { dev_err(denali->dev, "No usable DMA configuration\n"); - goto failed_req_irq; + goto disable_irq; } denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf, @@ -1394,7 +1308,7 @@ int denali_init(struct denali_nand_info *denali) if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) { dev_err(denali->dev, "Failed to map DMA buffer\n"); ret = -EIO; - goto failed_req_irq; + goto disable_irq; } /* @@ -1418,7 +1332,7 @@ int denali_init(struct denali_nand_info *denali) ret = denali_ecc_setup(mtd, chip, denali); if (ret) { dev_err(denali->dev, "Failed to setup ECC settings.\n"); - goto failed_req_irq; + goto disable_irq; } dev_dbg(denali->dev, @@ -1452,21 +1366,21 @@ int denali_init(struct denali_nand_info *denali) ret = denali_multidev_fixup(denali); if (ret) - goto failed_req_irq; + goto disable_irq; ret = nand_scan_tail(mtd); if (ret) - goto failed_req_irq; + goto disable_irq; ret = mtd_device_register(mtd, NULL, 0); if (ret) { dev_err(denali->dev, "Failed to register MTD: %d\n", ret); - goto failed_req_irq; + goto disable_irq; } return 0; -failed_req_irq: - denali_irq_cleanup(denali->irq, denali); +disable_irq: + denali_disable_irq(denali); return ret; } @@ -1484,7 +1398,7 @@ void denali_remove(struct denali_nand_info *denali) int bufsize = mtd->writesize + mtd->oobsize; nand_release(mtd); - denali_irq_cleanup(denali->irq, denali); + denali_disable_irq(denali); dma_unmap_single(denali->dev, denali->buf.dma_buf, bufsize, DMA_BIDIRECTIONAL); } diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index fb473895a79d..a0ac0f84f8b5 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -325,6 +325,7 @@ struct denali_nand_info { /* elements used by ISR */ struct completion complete; spinlock_t irq_lock; + uint32_t irq_mask; uint32_t irq_status; int irq; From patchwork Wed Jun 7 11:52:20 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103245 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1715504obh; Wed, 7 Jun 2017 04:57:34 -0700 (PDT) X-Received: by 10.99.114.11 with SMTP id n11mr31931938pgc.4.1496836654773; Wed, 07 Jun 2017 04:57:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836654; cv=none; d=google.com; s=arc-20160816; b=Trp+456j4ZvUS4dPXkGM/ki0TRUXyQsRxiLX6hK3Gkda0Tm8zRwbiV9p11kQLjWO1w fQHvwCvf83Y/sw8ie5CyapqhoSfRot9lDG9Mty+YZrJMkvt3m0hfWGlYtLcdvy42Zkt0 omAYrEnO0eGDTDshD2jNYzCFMYGgVHSIIY8dgEJAmmU9kJbTpBRtW8NHqNZef40mT4gS bu1YCWa11beFnTncFKoroCpTOuLbMuUR7VyI/P2dsyQMnv53y5j7TcfSZhZLUH+tEx0N aZcMPYYoFeOySR0IR6BNYNQh45eJNxcdSTc2pn3J3Xz69IPndvM21XkheMFziwU8UsBB L/Cg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=71SlKkvfQGUSE++RNn1+MWQXj5rQ91VX6rRiTCO+YV8=; b=jYADdp5PZHwahrPQWhNBN/lty+JSTtOzuQz2yhtHoZAv9SoV44o/oxYt7pV13sBgXL MoKHkOw06TZ6Ubajlz/9/8NNv9aS0jpCKNq/0hAPya8nixYVedLfUSxhvY/5mkzQaxyA C54dFpeCbLOD9ozGnMC0kZM9Mac/KNUjREDN49XCQOBFJAnTlTsVZPEtrQy/WLbdNgtv icHPLfdSiS7jMVStRv5xDjuyFrQgfEsgJdSKQcdrkda7tIXtAw/sgRbMOlMzJ6RI/jAx zOlRaTzRtesOjO93FQjkF85v94PPy84nY5UeyrIoOX3K5hWkrjnCL+CIzO3I1pkGVmBr 1phQ== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id p68si1629467pfi.108.2017.06.07.04.57.34; Wed, 07 Jun 2017 04:57:34 -0700 (PDT) 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 S1751861AbdFGL5C (ORCPT + 25 others); Wed, 7 Jun 2017 07:57:02 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42683 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751642AbdFGLza (ORCPT ); Wed, 7 Jun 2017 07:55:30 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZa014276; Wed, 7 Jun 2017 20:52:59 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZa014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836380; bh=71SlKkvfQGUSE++RNn1+MWQXj5rQ91VX6rRiTCO+YV8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=iNky5i7KOsTnUH7kaklbqcRRLYEFZkqRyYn+0MJtteKWdJrI738YxhH5lNVP2kXBS kA8BZbzcEHCPrHE3bmE1wlmGCIhMggxrmwGhsDkGGmgIXmgzQuWlBTHbii1Vmt3Ak+ x99cqzYWbDUCCQt3aIjgUmGcwJ0SWdkORp8chHfOKqiyDETmR4hfFFKSKj0U9wBFE9 vZjuQFvGh/GLAyrJ4Rl/S01Nm9eWC0y5TdaZtQsCMcxmXHrZ4UQECG8JSBbiBa9E0n zHzID6mf7ovXXNQqFZv/AS0MsB8L4zU5ZS9+jZnh7MKd433xyh6pGTFb8lSuODYFbJ NPNT4POpGtvbg== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 11/23] mtd: nand: denali: fix NAND_CMD_STATUS handling Date: Wed, 7 Jun 2017 20:52:20 +0900 Message-Id: <1496836352-8016-12-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 The current NAND_CMD_STATUS handling is weird; it just reads the WRITE_PROTECT register, and returns NAND_STATUS_WP if it is set. It does not send Read Status (0x70) command, so it is not helpful for checking the current device status. Signed-off-by: Masahiro Yamada --- Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 62798e6d7009..94beab57c145 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -107,21 +107,6 @@ static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte) denali->buf.buf[denali->buf.tail++] = byte; } -/* reads the status of the device */ -static void read_status(struct denali_nand_info *denali) -{ - uint32_t cmd; - - /* initialize the data buffer to store status */ - reset_buf(denali); - - cmd = ioread32(denali->flash_reg + WRITE_PROTECT); - if (cmd) - write_byte_to_buf(denali, NAND_STATUS_WP); - else - write_byte_to_buf(denali, 0); -} - /* Reset the flash controller */ static uint16_t denali_nand_reset(struct denali_nand_info *denali) { @@ -893,7 +878,11 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, switch (cmd) { case NAND_CMD_STATUS: - read_status(denali); + reset_buf(denali); + addr = MODE_11 | BANK(denali->flash_bank); + index_addr(denali, addr | 0, cmd); + index_addr_read_data(denali, addr | 2, &id); + write_byte_to_buf(denali, id); break; case NAND_CMD_READID: case NAND_CMD_PARAM: From patchwork Wed Jun 7 11:52:21 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103244 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1715499obh; Wed, 7 Jun 2017 04:57:34 -0700 (PDT) X-Received: by 10.84.218.78 with SMTP id f14mr27411640plm.214.1496836654367; Wed, 07 Jun 2017 04:57:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836654; cv=none; d=google.com; s=arc-20160816; b=gKXFk16cgCS6HVvupi9zLExA/rRUi+4zHRjYl2p8VpO8z7/RDTG6fOmG3EeQEKTvLs SDovA9EBxsK5k8gULk4xR4gwqDbk7n6RjiFmL3cEb276rD8Qd7wPxTW5wY8JW+aaMOz2 oA45j/s8HyoRVRqguArcCQ11obE2MG4jTft4ybnMqXAKySBzbFNMRxL+gsBkYjfYEaje CT0YDDyRXevM334RRm4IbxL/eqebXtC47DtLOEQVJek7hNgooOhQlfuXCcLgnEBd+TwK Karwu3Ge/hG5Jomczw2Jgi+lj05vvaNI4ZoebKMNUUFY4syUlGpyteXDCZFSgVjz4a9W I4HA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=g2uirILbk98jVCWPpDfZYVGU4tdYF0tHgDAiTE7Rs5Q=; b=q7TZt8mavV6ci24GNf8X657nrWdiDQa6imfxtXjTtXaDYh8MVGKpF5Halh7QJqxBC4 7FlVwa/5vsn4Z/BjKTs9B5sUgNhHPrHifOJE+NmgKAB5iGehZxhJC+/EYabTJOhT36yl CwOlZH4AGbfVlK6jC9Oclcv4D057nJoM/dKzBbu0lDOTavUy8nzLsZTIMJz086gYyz9y oLExLjBZx3Xwbt7eNYD/VZsVLGq8OKs2zWLmwBGKWi4L+ly9qb6yvrd/cSfoIC1zq+iB M7DbZmYv90KMlC0jeWB3o3WAj9SjdHZ9x2guE2BmRV7kJIBEWzo4YLjzSTAalSVjLFr6 Rrtw== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id p68si1629467pfi.108.2017.06.07.04.57.34; Wed, 07 Jun 2017 04:57:34 -0700 (PDT) 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 S1751873AbdFGL5D (ORCPT + 25 others); Wed, 7 Jun 2017 07:57:03 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42687 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751646AbdFGLza (ORCPT ); Wed, 7 Jun 2017 07:55:30 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZb014276; Wed, 7 Jun 2017 20:53:00 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZb014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836381; bh=g2uirILbk98jVCWPpDfZYVGU4tdYF0tHgDAiTE7Rs5Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=k10fIIpccRwfTm3YK0DM/Er80p6oC0IsHBAjN1fsHx4DwSsaq7dC2Uj9mwiweXtL0 hxugcZIQ4dYPHICQiSDcWQKWkvFtr+uKmj2zrIHanUbKpX3a98u0PZMzu+Nm0bRG4H hxkl66HDDytG9D9+KrbJAhsd9sDjmBvMERmdFn5ZJET3XaV5LeFbSsdFB/6tX7/tlR yZBc/KyBWfTiPsoCfJaHidpZfSUiZNiYBWDBe0K+0bEHL/rJrdVHBC4xc/2f52sPqp /Bm3mtVaUNKIZ65H/FZt7UT59icMxweV/az62mkH+lDfym2BrUgh+Tqj3b48UM+1H7 WT4APbvv7texg== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 12/23] mtd: nand: denali: fix NAND_CMD_PARAM handling Date: Wed, 7 Jun 2017 20:52:21 +0900 Message-Id: <1496836352-8016-13-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 NAND_CMD_PARAM is not working at all due to multiple bugs. [1] The command 0x90 issued instead of 0xec The command code 0x90 is hard-code as index_addr(denali, addr | 0, 0x90) So, Read ID (0x90) command is sent to the device instead of Read Parameter Page (0xec). [2] only first 8 bytes are read Even if [1] is fixed, the current implementation is problematic. The only first 8 bytes are read by MAP11 command, and put into the temporal buffer: for (i = 0; i < 8; i++) { index_addr_read_data(denali, addr | 2, &id); write_byte_to_buf(denali, id); } Obviously, this is not sufficient for NAND_CMD_PARAM; the ONFi parameters are 256-byte long. This is still insufficient. As you see in nand_flash_detect_onfi() reads out (256 * 3) bytes at maximum (Redundant Parameter Pages). However, changing the loop to for (i = 0; i < 768; i++) is a crazy idea. At the point of the chip->cmdfunc() call, we cannot know how many times chip->read_byte() will be called. So, pre-reading enough number of bytes in the chip->cmdfunc() is a design mistake. [3] no wait for R/B# The current code handles NAND_CMD_READID and NAND_CMD_PARAM in the same way, but this is also wrong. The difference between them is that Read ID command does not toggle R/B# whereas the Read Parameter Page command requires R/B#. Without the wait for R/B# interrupt, wrong data are retrieved. In order to fix those problems, data read cycle of the MAP11 command has been moved to chip->read_byte(). Data are read out as needed. Another good thing is early temporal buffer is not needed any more. The ugly devm_kzalloc()/devm_kfree() dance has been killed. Signed-off-by: Masahiro Yamada --- Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 95 +++++++++++++++-------------------------------- drivers/mtd/nand/denali.h | 2 - 2 files changed, 30 insertions(+), 67 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 94beab57c145..c3382954cf27 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -85,28 +85,6 @@ static void index_addr(struct denali_nand_info *denali, iowrite32(data, denali->flash_mem + 0x10); } -/* Perform an indexed read of the device */ -static void index_addr_read_data(struct denali_nand_info *denali, - uint32_t address, uint32_t *pdata) -{ - iowrite32(address, denali->flash_mem); - *pdata = ioread32(denali->flash_mem + 0x10); -} - -/* - * We need to buffer some data for some of the NAND core routines. - * The operations manage buffering that data. - */ -static void reset_buf(struct denali_nand_info *denali) -{ - denali->buf.head = denali->buf.tail = 0; -} - -static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte) -{ - denali->buf.buf[denali->buf.tail++] = byte; -} - /* Reset the flash controller */ static uint16_t denali_nand_reset(struct denali_nand_info *denali) { @@ -286,6 +264,15 @@ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, iowrite32(transfer_spare_flag, denali->flash_reg + TRANSFER_SPARE_REG); } +static uint8_t denali_read_byte(struct mtd_info *mtd) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + + iowrite32(MODE_11 | BANK(denali->flash_bank) | 2, denali->flash_mem); + + return ioread32(denali->flash_mem + 0x10); +} + /* * sends a pipeline command operation to the controller. See the Denali NAND * controller's user guide for more information (section 4.2.3.6). @@ -828,17 +815,6 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, return 0; } -static uint8_t denali_read_byte(struct mtd_info *mtd) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - uint8_t result = 0xff; - - if (denali->buf.head < denali->buf.tail) - result = denali->buf.buf[denali->buf.head++]; - - return result; -} - static void denali_select_chip(struct mtd_info *mtd, int chip) { struct denali_nand_info *denali = mtd_to_denali(mtd); @@ -873,43 +849,40 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t addr, id; - int i; + uint32_t addr, irq_status; + int wait_ready = 0; switch (cmd) { - case NAND_CMD_STATUS: - reset_buf(denali); - addr = MODE_11 | BANK(denali->flash_bank); - index_addr(denali, addr | 0, cmd); - index_addr_read_data(denali, addr | 2, &id); - write_byte_to_buf(denali, id); + case NAND_CMD_PARAM: + wait_ready = 1; break; + case NAND_CMD_STATUS: case NAND_CMD_READID: - case NAND_CMD_PARAM: - reset_buf(denali); - /* - * sometimes ManufactureId read from register is not right - * e.g. some of Micron MT29F32G08QAA MLC NAND chips - * So here we send READID cmd to NAND insteand - */ - addr = MODE_11 | BANK(denali->flash_bank); - index_addr(denali, addr | 0, 0x90); - index_addr(denali, addr | 1, col); - for (i = 0; i < 8; i++) { - index_addr_read_data(denali, addr | 2, &id); - write_byte_to_buf(denali, id); - } break; case NAND_CMD_RESET: reset_bank(denali); break; case NAND_CMD_READOOB: /* TODO: Read OOB data */ - break; + return; default: pr_err(": unsupported command received 0x%x\n", cmd); - break; + return; } + + denali_reset_irq(denali); + + addr = MODE_11 | BANK(denali->flash_bank); + index_addr(denali, addr | 0, cmd); + if (col != -1) + index_addr(denali, addr | 1, col); + + if (!wait_ready) + return; + + irq_status = denali_wait_for_irq(denali, INTR__INT_ACT); + if (!(irq_status & INTR__INT_ACT)) + dev_err(denali->dev, "failed to issue command 0x%x\n", cmd); } #define DIV_ROUND_DOWN_ULL(ll, d) \ @@ -1228,12 +1201,6 @@ int denali_init(struct denali_nand_info *denali) struct mtd_info *mtd = nand_to_mtd(chip); int ret; - /* allocate a temporary buffer for nand_scan_ident() */ - denali->buf.buf = devm_kzalloc(denali->dev, PAGE_SIZE, - GFP_DMA | GFP_KERNEL); - if (!denali->buf.buf) - return -ENOMEM; - mtd->dev.parent = denali->dev; denali_hw_init(denali); denali_drv_init(denali); @@ -1273,8 +1240,6 @@ int denali_init(struct denali_nand_info *denali) if (ret) goto disable_irq; - /* allocate the right size buffer now */ - devm_kfree(denali->dev, denali->buf.buf); denali->buf.buf = devm_kzalloc(denali->dev, mtd->writesize + mtd->oobsize, GFP_KERNEL); diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index a0ac0f84f8b5..a84d8784ee98 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -306,8 +306,6 @@ #define MODE_11 0x0C000000 struct nand_buf { - int head; - int tail; uint8_t *buf; dma_addr_t dma_buf; }; From patchwork Wed Jun 7 11:52:22 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103247 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1715778obh; Wed, 7 Jun 2017 04:58:20 -0700 (PDT) X-Received: by 10.98.21.17 with SMTP id 17mr30418347pfv.71.1496836700483; Wed, 07 Jun 2017 04:58:20 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836700; cv=none; d=google.com; s=arc-20160816; b=prZXvdmulqKfWfzxITTSPpm/5U6aHG1Iwe9LjxM+QU0cMXzFneRr3coHWnqTcmRKzn 1V+3Jxn2MMjxbtSlfwKUndr6k/i+VZ2T/ZpN9p1S44TiE6V4RHkoTIImAa8U0rRZrxPH dq0v5dYnjIedAgz5ypDneSafGjjE4YmC8LyB9lZu4RMEuNCbCNE5AoJtAjptXaU354Ha V7dUiGc3Qn3t1IffzM98RiwwYCK7irljHcgTkFYkWeFRnvwoPQRuTPa+3t6BPYafg6cm q12XznPYxO4nYbP39tEoj/zGrBb2cAwYeiBkXSalAgSxRoki5A/rNbgwXx+nLrhelzdC 7ung== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=XkQ9MNDTKfnQZu+hwJXVy3XifPnRRCHQRc3IG+CSGYY=; b=wQf3iXyRWDZqUoTN2PRcO6BQXq4NtbIjTvndaixFHEB9L7z2WjO4XCcyxTfzj/dQpr OuRqrjgQ4KSKwcP1DhHMcNwSJYHt0fBdGJmg21/qn4S1QIQTLleFpJT6Bpp191lFKjPB EAIVKEj4w62MMjG3qctcSBvhgA/2cwDhA5/9LRHoVQpqVgomM/m/3BJZZreQSj0WYbxq Xj/MjdBFJ/hlTJ2nu6LwXOnYtqD63zR2RFp2cv1QJrwGO5KZUwQVhO2YybKU6Oy1Ibm4 5q29vjYpg1IMoEgrCc5SEguVMz0pUMlCEANQPlawm3z7BjiX9PkVmwpMMZMFaJv2gceB LpFw== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id c41si636611plj.187.2017.06.07.04.58.20; Wed, 07 Jun 2017 04:58:20 -0700 (PDT) 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 S1751798AbdFGL5t (ORCPT + 25 others); Wed, 7 Jun 2017 07:57:49 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42632 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751617AbdFGLz2 (ORCPT ); Wed, 7 Jun 2017 07:55:28 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZc014276; Wed, 7 Jun 2017 20:53:01 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZc014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836382; bh=XkQ9MNDTKfnQZu+hwJXVy3XifPnRRCHQRc3IG+CSGYY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dDTYwUnp+eUNvS+NEI8npzBSWoeXnmTmQz1JLLefXcBK7HcLxweJ8kmier3S+ce8L jvxamYWmXprI41I0/qucjZh2TJlfVX4u3DmBI2E5U5MKsGg6yUaqWoCmONmMNqiTED I8wubQSCG7NkR5rMxFMItYoq1Pc0kGv1A3rQx+skrIlvIlKs2jcgVpaSvHTlqVIJoj ARE91bRnLyg0Ph8aqguoPXVo8EFJ5C6acxGhhayYfaTk/dBEmaTHTvwn9Dm5CTjC4J PICjhXq9e2huFeWqdanL5a2YFU2UasG7/ou/Ji2VYUAyHIMER5r8D+wfWn7Bjk795w 3vEr5rnEJWNIA== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 13/23] mtd: nand: denali: switch over to cmd_ctrl instead of cmdfunc Date: Wed, 7 Jun 2017 20:52:22 +0900 Message-Id: <1496836352-8016-14-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 The NAND_CMD_SET_FEATURES support is missing from denali_cmdfunc(). This is needed for nand_onfi_set_features(). Besides, we see /* TODO: Read OOB data */ comment line. It would be possible to add more commands along with the current implementation, but having ->cmd_ctrl() seems a better approach from the discussion with Boris [1]. Rely on the default ->cmdfunc() from the framework and implement the driver's own ->cmd_ctrl(). Also add ->write_byte(), which is needed for write direction commands. [1] https://lkml.org/lkml/2017/3/15/97 Signed-off-by: Masahiro Yamada --- Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 104 +++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 52 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index c3382954cf27..95bce6b341d7 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -230,20 +230,16 @@ static uint32_t denali_wait_for_irq(struct denali_nand_info *denali, return denali->irq_status; } -/* resets a specific device connected to the core */ -static void reset_bank(struct denali_nand_info *denali) +static uint32_t denali_check_irq(struct denali_nand_info *denali) { + unsigned long flags; uint32_t irq_status; - denali_reset_irq(denali); - - iowrite32(1 << denali->flash_bank, denali->flash_reg + DEVICE_RESET); - - irq_status = denali_wait_for_irq(denali, - INTR__RST_COMP | INTR__TIME_OUT); + spin_lock_irqsave(&denali->irq_lock, flags); + irq_status = denali->irq_status; + spin_unlock_irqrestore(&denali->irq_lock, flags); - if (!(irq_status & INTR__RST_COMP)) - dev_err(denali->dev, "reset bank failed.\n"); + return irq_status; } /* @@ -273,6 +269,42 @@ static uint8_t denali_read_byte(struct mtd_info *mtd) return ioread32(denali->flash_mem + 0x10); } +static void denali_write_byte(struct mtd_info *mtd, uint8_t byte) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + + index_addr(denali, MODE_11 | BANK(denali->flash_bank) | 2, byte); +} + +static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + uint32_t type; + + if (ctrl & NAND_CLE) + type = 0; + else if (ctrl & NAND_ALE) + type = 1; + else + return; + + /* + * Some commands are followed by chip->dev_ready or chip->waitfunc. + * irq_status must be cleared here to catch the R/B# interrupt later. + */ + if (ctrl & NAND_CTRL_CHANGE) + denali_reset_irq(denali); + + index_addr(denali, MODE_11 | BANK(denali->flash_bank) | type, dat); +} + +static int denali_dev_ready(struct mtd_info *mtd) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + + return !!(denali_check_irq(denali) & INTR__INT_ACT); +} + /* * sends a pipeline command operation to the controller. See the Denali NAND * controller's user guide for more information (section 4.2.3.6). @@ -824,7 +856,13 @@ static void denali_select_chip(struct mtd_info *mtd, int chip) static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) { - return 0; + struct denali_nand_info *denali = mtd_to_denali(mtd); + uint32_t irq_status; + + /* R/B# pin transitioned from low to high? */ + irq_status = denali_wait_for_irq(denali, INTR__INT_ACT); + + return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL; } static int denali_erase(struct mtd_info *mtd, int page) @@ -845,46 +883,6 @@ static int denali_erase(struct mtd_info *mtd, int page) return irq_status & INTR__ERASE_COMP ? 0 : NAND_STATUS_FAIL; } -static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, - int page) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t addr, irq_status; - int wait_ready = 0; - - switch (cmd) { - case NAND_CMD_PARAM: - wait_ready = 1; - break; - case NAND_CMD_STATUS: - case NAND_CMD_READID: - break; - case NAND_CMD_RESET: - reset_bank(denali); - break; - case NAND_CMD_READOOB: - /* TODO: Read OOB data */ - return; - default: - pr_err(": unsupported command received 0x%x\n", cmd); - return; - } - - denali_reset_irq(denali); - - addr = MODE_11 | BANK(denali->flash_bank); - index_addr(denali, addr | 0, cmd); - if (col != -1) - index_addr(denali, addr | 1, col); - - if (!wait_ready) - return; - - irq_status = denali_wait_for_irq(denali, INTR__INT_ACT); - if (!(irq_status & INTR__INT_ACT)) - dev_err(denali->dev, "failed to issue command 0x%x\n", cmd); -} - #define DIV_ROUND_DOWN_ULL(ll, d) \ ({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; }) @@ -1224,8 +1222,10 @@ int denali_init(struct denali_nand_info *denali) /* register the driver with the NAND core subsystem */ chip->select_chip = denali_select_chip; - chip->cmdfunc = denali_cmdfunc; chip->read_byte = denali_read_byte; + chip->write_byte = denali_write_byte; + chip->cmd_ctrl = denali_cmd_ctrl; + chip->dev_ready = denali_dev_ready; chip->waitfunc = denali_waitfunc; /* clk rate info is needed for setup_data_interface */ if (denali->clk_x_rate) From patchwork Wed Jun 7 11:52:23 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103246 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1715612obh; Wed, 7 Jun 2017 04:57:53 -0700 (PDT) X-Received: by 10.99.52.1 with SMTP id b1mr31277572pga.91.1496836673768; Wed, 07 Jun 2017 04:57:53 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836673; cv=none; d=google.com; s=arc-20160816; b=H7pJQ3BmF4UdEJ4gE+IswV264uMIeLKKYf28nlll9a/1kDzwU6+yVNt+aPOqCLSjcn vf+X/NA5YFn9QDiWgIBzwoyTZbWM1AvXNPrN8bw33cwgRXNkrHNvmp80XwWXR53/KIi+ E+x3m0uCzOXaVF96Qsiq1WqaoY2NCH2e9uYDy3thDAddI5ZZovhI+fkz+t4UcPWrWKZh aendlNB+mFXgHrVudfASuCzmeNFOzsNEP/AsS+5CNnpYpbkFtEFz6ccsSpYN0N09rgsL YD4PAtIdYWwVu491kDdVBJY6sykwfdv9Ba1wPL+b8n+2ammZhQtFVJYSpWqfSWhzWgyt WN7Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=f+gmoBzMUN5vkvRcy6wnJGcAR7lZvZ4vpC3gTzDoBRM=; b=EBYqFK01RDQYqr+Lmpw88a7kJUFVG7LZfKnXvkt8iTEMBBWFmemHg2r8jwGiDGbVqx 5Ksb+/WO8OHURpvynQlGctdpYT2vTkAB+eJfskJgrCGD9VhVt8DI9SoBPKEMMjcqa7Ci FKVqpKlFPdNEHbfBa70jJde48j0GlUoQARHPa5F793tyWVcegW3xpEK7DO1+36y0Igkr EnMytvPTobhNiS883EA7pReLTWI2jxIgjI8sighEi2SNQ/aHD0iiqXNL1Rte7uE/OB98 TXyqTW8eMY6khlo7mN8UtLbop2SUw0i4jxmoi35oBnT2Jhu2+/gq01loOGJArpeI5i9J sXhQ== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id p68si1629467pfi.108.2017.06.07.04.57.53; Wed, 07 Jun 2017 04:57:53 -0700 (PDT) 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 S1751893AbdFGL5v (ORCPT + 25 others); Wed, 7 Jun 2017 07:57:51 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42625 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751511AbdFGLz2 (ORCPT ); Wed, 7 Jun 2017 07:55:28 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZd014276; Wed, 7 Jun 2017 20:53:02 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZd014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836383; bh=f+gmoBzMUN5vkvRcy6wnJGcAR7lZvZ4vpC3gTzDoBRM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ejcI/+VuQVbWFvEI7gkNbcSZX1Bm0l40l+rvE/xRvtBmRILPk3libV3Ns8z56DXN3 E/CZwMjYjrzK5Thx89A5+CmnvySuBjoTgCvHXv8KfZm3MqokkS/awvRs8lEnjiUKP6 eAKkb56fDoh7BMcaStuoP4pAe8m132Pgmr5kp4uauImlLa3JokmzC4hi2VHFT3h/o5 LE6mgZrjG8xucbkMWpBJxwHAFm1SpqmiSvuv7uBF60piGyi+mFNzOU6qIFm4bAF/YL rhAS1JjFwLTUXFPp0bR78+uLMa8AtM03OL36IPIADtNqHdYNoxusbslC+sauR5xDW4 hjGxj4RSu/zRQ== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 14/23] mtd: nand: denali: fix bank reset function to detect the number of chips Date: Wed, 7 Jun 2017 20:52:23 +0900 Message-Id: <1496836352-8016-15-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 The nand_scan_ident() iterates over maxchips, and calls nand_reset() for each. This driver currently passes the maximum number of banks (=chip selects) supported by the controller as maxchips. So, maxchips is typically 4 or 8. Usually, less number of NAND chips are connected to the controller. This can be a problem for ONFi devices. Now, this driver implements ->setup_data_interface() hook, so nand_setup_data_interface() issues Set Features (0xEF) command, which waits until the chip returns R/B# response. If no chip there, we know it never happens, but the driver still ends up with waiting for a long time. It will finally bail-out with timeout error and the driver will work with existing chips, but unnecessary wait will give a bad user experience. The denali_nand_reset() polls the INTR__RST_COMP and INTR__TIME_OUT bits, but they are always set even if not NAND chip is connected to that bank. To know the chip existence, INTR__INT_ACT bit must be checked; this flag is set only when R/B# is toggled. Since the Reset (0xFF) command toggles the R/B# pin, this can be used to know the actual number of chips, and update denali->max_banks. Signed-off-by: Masahiro Yamada --- Boris mentioned this information can be retrieved from DT (http://patchwork.ozlabs.org/patch/745118/), but I'd like to take time for controller/chip decoupling. I am tackling on that, but not completed yet. I believe this commit stands for denali_pci, at least I do not know how to get the number of chips from PCI. Changes in v5: None Changes in v4: - Reword commit-log Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 52 +++++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 29 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 95bce6b341d7..8e2399ddfe3f 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -85,33 +85,6 @@ static void index_addr(struct denali_nand_info *denali, iowrite32(data, denali->flash_mem + 0x10); } -/* Reset the flash controller */ -static uint16_t denali_nand_reset(struct denali_nand_info *denali) -{ - int i; - - for (i = 0; i < denali->max_banks; i++) - iowrite32(INTR__RST_COMP | INTR__TIME_OUT, - denali->flash_reg + INTR_STATUS(i)); - - for (i = 0; i < denali->max_banks; i++) { - iowrite32(1 << i, denali->flash_reg + DEVICE_RESET); - while (!(ioread32(denali->flash_reg + INTR_STATUS(i)) & - (INTR__RST_COMP | INTR__TIME_OUT))) - cpu_relax(); - if (ioread32(denali->flash_reg + INTR_STATUS(i)) & - INTR__TIME_OUT) - dev_dbg(denali->dev, - "NAND Reset operation timed out on bank %d\n", i); - } - - for (i = 0; i < denali->max_banks; i++) - iowrite32(INTR__RST_COMP | INTR__TIME_OUT, - denali->flash_reg + INTR_STATUS(i)); - - return PASS; -} - /* * Use the configuration feature register to determine the maximum number of * banks that the hardware supports. @@ -999,7 +972,28 @@ static int denali_setup_data_interface(struct mtd_info *mtd, return 0; } -/* Initialization code to bring the device up to a known good state */ +static void denali_reset_banks(struct denali_nand_info *denali) +{ + int i; + + denali_clear_irq_all(denali); + + for (i = 0; i < denali->max_banks; i++) { + iowrite32(1 << i, denali->flash_reg + DEVICE_RESET); + while (!(ioread32(denali->flash_reg + INTR_STATUS(i)) & + (INTR__RST_COMP | INTR__TIME_OUT))) + cpu_relax(); + if (!(ioread32(denali->flash_reg + INTR_STATUS(i)) & + INTR__INT_ACT)) + break; + } + + dev_dbg(denali->dev, "%d chips connected\n", i); + denali->max_banks = i; + + denali_clear_irq_all(denali); +} + static void denali_hw_init(struct denali_nand_info *denali) { /* @@ -1019,7 +1013,7 @@ static void denali_hw_init(struct denali_nand_info *denali) denali->bbtskipbytes = ioread32(denali->flash_reg + SPARE_AREA_SKIP_BYTES); detect_max_banks(denali); - denali_nand_reset(denali); + denali_reset_banks(denali); iowrite32(0x0F, denali->flash_reg + RB_PIN_ENABLED); iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->flash_reg + CHIP_ENABLE_DONT_CARE); From patchwork Wed Jun 7 11:52:24 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103238 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1714945obh; Wed, 7 Jun 2017 04:56:05 -0700 (PDT) X-Received: by 10.84.130.33 with SMTP id 30mr15104072plc.240.1496836565642; Wed, 07 Jun 2017 04:56:05 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836565; cv=none; d=google.com; s=arc-20160816; b=TtZYO71rjE17mOujETmoPgOhvKB6vqHj/U1h24cEmq/1HJEBqTP8+ZGdTe2ftFtzFM bnqrbnl6pMOunr6O8Ppu/Uu4Kj1XIb7f1kY4Jxw634g6mvPnRzWG16kqBZzYUG21WWuy 1TgK+REFrId07HyCsQlkzMl1T5A8xfGbouWXfNDOz0Blwbe3tS6rvx389MXJ9WoTx5kj qglz0mzs7689S0HOj90/TA9nn1w69PJ7DG5N2MKdldT7ac55wOXUXj3ez2CGatHODRN2 nfZyP3IV5VH/rHrc0EQFUfgXRS8qpAT36PMrOUvG2OU1i3MCfN5WD4g0+OYUrZh5uz7s VKAQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=bnuTAPuWbftzIKT5/zkquR0k68ypnWuOc83nS3vUZv4=; b=ayiyqyXro6GGclVwXcvueGe5Jre9r0f9ihYf9RDX3Oa3n/i6zekfjI/ohwXRcM2TpF WWxD/TYD4kOPjB7WV+jyh3srg//VH+3DE+YblNWwbKmkjg7sclAQgreG+xG2OpRGn8tt oFgFbV2SHe7ADe9bHJUvThcxUOZuPc37jLNoMuWvcsQULcQ+ltKyfal49Xu46LmyIWkQ sbaHJqCIZ7ljwXr1wsc5D2+UCTDZlEkpA9zGWf3i+96mc1cW0KmXlS1PQhcd3geSr4g3 WCB1iX/KLTgIEzVzTg18YNRzH1h9tD6uR8tel6Qan+5Z52MpbPR4bhlfol8p/bvXSrk1 d6bw== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m24si1622370pfa.242.2017.06.07.04.56.05; Wed, 07 Jun 2017 04:56:05 -0700 (PDT) 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 S1751771AbdFGLzr (ORCPT + 25 others); Wed, 7 Jun 2017 07:55:47 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42786 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751713AbdFGLzi (ORCPT ); Wed, 7 Jun 2017 07:55:38 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZe014276; Wed, 7 Jun 2017 20:53:03 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZe014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836384; bh=bnuTAPuWbftzIKT5/zkquR0k68ypnWuOc83nS3vUZv4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=HQmSpnTMpLWVAowWTVtEnsX1fjFUDKiJ0dJR5TRluq7XKNPZTKqRuN5E3qZjQHGoN PrawuZxRaNw+fjOREJbYm+qcssKIzkkgsklta5HVDSgwpDZP8/wrLG2JeCDtaHK48q 9DxLQWvkqKq+K1gayvQsZB3AMZ658hmNbwioB7wUIVr4E+ot9sWddnAHmlCuNlIVSM Ly53XsDeTxXpWH6K3oiWmRP8gYoncBdoiQZuDMLwY/Z6Ib1cqFFQ1407aDRNQGJsiH KOklkLEifQZTIAYvhfEh+92eAqa2weL261a6/D8wfCAKny5nlSvyz1rBlGAUITmEbo JV7Ei2z6RS6Bw== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 15/23] mtd: nand: denali: use interrupt instead of polling for bank reset Date: Wed, 7 Jun 2017 20:52:24 +0900 Message-Id: <1496836352-8016-16-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 The current bank reset implementation polls the INTR_STATUS register until interested bits are set. This is not good because: - polling simply wastes time-slice of the thread - The while() loop may continue eternally if no bit is set, for example, due to the controller problem. The denali_wait_for_irq() uses wait_for_completion_timeout(), which is safer. We can use interrupt by moving the denali_reset_bank() call below the interrupt setup. Signed-off-by: Masahiro Yamada --- Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 8e2399ddfe3f..eda206851a4b 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -974,24 +974,25 @@ static int denali_setup_data_interface(struct mtd_info *mtd, static void denali_reset_banks(struct denali_nand_info *denali) { + u32 irq_status; int i; - denali_clear_irq_all(denali); - for (i = 0; i < denali->max_banks; i++) { - iowrite32(1 << i, denali->flash_reg + DEVICE_RESET); - while (!(ioread32(denali->flash_reg + INTR_STATUS(i)) & - (INTR__RST_COMP | INTR__TIME_OUT))) - cpu_relax(); - if (!(ioread32(denali->flash_reg + INTR_STATUS(i)) & - INTR__INT_ACT)) + denali->flash_bank = i; + + denali_reset_irq(denali); + + iowrite32(DEVICE_RESET__BANK(i), + denali->flash_reg + DEVICE_RESET); + + irq_status = denali_wait_for_irq(denali, + INTR__RST_COMP | INTR__INT_ACT | INTR__TIME_OUT); + if (!(irq_status & INTR__INT_ACT)) break; } dev_dbg(denali->dev, "%d chips connected\n", i); denali->max_banks = i; - - denali_clear_irq_all(denali); } static void denali_hw_init(struct denali_nand_info *denali) @@ -1013,7 +1014,6 @@ static void denali_hw_init(struct denali_nand_info *denali) denali->bbtskipbytes = ioread32(denali->flash_reg + SPARE_AREA_SKIP_BYTES); detect_max_banks(denali); - denali_reset_banks(denali); iowrite32(0x0F, denali->flash_reg + RB_PIN_ENABLED); iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->flash_reg + CHIP_ENABLE_DONT_CARE); @@ -1131,9 +1131,6 @@ static void denali_drv_init(struct denali_nand_info *denali) * element that might be access shared data (interrupt status) */ spin_lock_init(&denali->irq_lock); - - /* indicate that MTD has not selected a valid bank yet */ - denali->flash_bank = CHIP_SELECT_INVALID; } static int denali_multidev_fixup(struct denali_nand_info *denali) @@ -1208,6 +1205,9 @@ int denali_init(struct denali_nand_info *denali) } denali_enable_irq(denali); + denali_reset_banks(denali); + + denali->flash_bank = CHIP_SELECT_INVALID; nand_set_flash_node(chip, denali->dev->of_node); /* Fallback to the default name if DT did not give "label" property */ From patchwork Wed Jun 7 11:52:25 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103240 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1714952obh; Wed, 7 Jun 2017 04:56:06 -0700 (PDT) X-Received: by 10.99.156.18 with SMTP id f18mr27767710pge.25.1496836566388; Wed, 07 Jun 2017 04:56:06 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836566; cv=none; d=google.com; s=arc-20160816; b=oEYD914qoaubNZ1le9KS7OSkescEpr46lhouqqHW2rZqn5RwZJUN5mxd4L6fDEn17m LuS79F6zvfenizL+FRwDWmokBujG9NEx7BofBu6xRTtsvDGAH3Iy61M8xhANGqpH+btC 6NRmUX8zrHfvPsuN2scFuEuOTB5QzjFRM3W/ShVNTifDAf0Lz4dYi8Q3rCsUN92ikd2a gJIYvMhvTLjf4NaArgkTSbZy2FYereULSV6i19lah9VyvOSebr2PA+HayV1of8HrcfNH w9rkQ27GRlzW0xqD0DEYiKgFlNrF59xEs6i9EgvV1eQlGrHpdbtCBOS918o5fiz16qEg 4ZYQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=3kmBkmf5oBDdOrR6SA7ofhib4mEWiQQk9AOoGr1+q+Q=; b=a9clkxnH60X9J6cZJOUx8M1YJnkt7m9JDJfKkXsW2WbQe1dm9D5MYu4wA/hAMRm7yh FErClxd4dUYWg8BpEsZd1IIPrv5wyMLaOHV7VNpRqwn5FoX8nM1DQdfqzU6Mwxr1PTRD isy2r2zdmdDR1VgPfQ0931kE9RfFwoWIkBk8H/heFTOPIgd4qZqC1WzTkvEmy9tGfwvs BnoWvXEFtxWFrJdXEcEXg8wX6yudnkbV4ehWBBiHE9SXHrgmBdxvu/bZuz/+aT4pqI5R DD7vdy36neVkmp3fOmD863X8lSRgG37FBUACvN4yibt8vC0L1/ASd0ciplaapFyalAPC Ermw== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m24si1622370pfa.242.2017.06.07.04.56.06; Wed, 07 Jun 2017 04:56:06 -0700 (PDT) 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 S1751803AbdFGLzv (ORCPT + 25 others); Wed, 7 Jun 2017 07:55:51 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42772 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751713AbdFGLzs (ORCPT ); Wed, 7 Jun 2017 07:55:48 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZf014276; Wed, 7 Jun 2017 20:53:04 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZf014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836385; bh=3kmBkmf5oBDdOrR6SA7ofhib4mEWiQQk9AOoGr1+q+Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=1ipyU1GO+cc5+b4E3Bo0gtM2UmqlU4KMSJU4dVgUtSM8/3MB0HCQI52UiJzBnuNnC +P2opYtYbZLrxU4NvG3p5RsJdqw4Q4WKlvJFZMJOnFJ0xBp+b/yXB+ihFtiZarc8M2 6FL1bjcKQZN4x3gUt/pzKbJLzcHiyqPuhH12bNaMrde/mJucBLwAg6HuX/GeSfW9L0 07CYYOOUqnr76ZjQHjLGYF1DZtiEBhCAdxZ1jkPXso7++s0TfFwv6C5GwFET/hbAob MKL2hvwKyjocXjErQYfA2k9X18FptrPLs6YnNqCnBcyA12YwhBhHu5Meyz5f9sIKbx 0Gd//EMtwi2Qw== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 16/23] mtd: nand: denali: propagate page to helpers via function argument Date: Wed, 7 Jun 2017 20:52:25 +0900 Message-Id: <1496836352-8016-17-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 This driver stores the currently addressed page into denali->page, which is later read out by helper functions. While I am tackling on this driver, I often missed to insert "denali->page = page;" where needed. This makes page_read/write callbacks to get access to a wrong page, which is a bug hard to figure out. Instead, I'd rather pass the page via function argument because the compiler's prototype checks will help to detect bugs. For the same reason, propagate dma_addr to the DMA helpers instead of denali->buf.dma_buf . Signed-off-by: Masahiro Yamada --- Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 58 ++++++++++++++++++++--------------------------- drivers/mtd/nand/denali.h | 1 - 2 files changed, 24 insertions(+), 35 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index eda206851a4b..1a96942f62f9 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -282,7 +282,7 @@ static int denali_dev_ready(struct mtd_info *mtd) * sends a pipeline command operation to the controller. See the Denali NAND * controller's user guide for more information (section 4.2.3.6). */ -static int denali_send_pipeline_cmd(struct denali_nand_info *denali, +static int denali_send_pipeline_cmd(struct denali_nand_info *denali, int page, bool ecc_en, bool transfer_spare, int access_type, int op) { @@ -293,7 +293,7 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, denali_reset_irq(denali); - addr = BANK(denali->flash_bank) | denali->page; + addr = BANK(denali->flash_bank) | page; if (op == DENALI_WRITE && access_type != SPARE_ACCESS) { cmd = MODE_01 | addr; @@ -366,9 +366,7 @@ static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) uint32_t irq_mask = INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL; int status = 0; - denali->page = page; - - if (denali_send_pipeline_cmd(denali, false, false, SPARE_ACCESS, + if (denali_send_pipeline_cmd(denali, page, false, false, SPARE_ACCESS, DENALI_WRITE) == PASS) { write_data_to_flash_mem(denali, buf, mtd->oobsize); @@ -393,9 +391,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) uint32_t irq_mask = INTR__LOAD_COMP; uint32_t irq_status, addr, cmd; - denali->page = page; - - if (denali_send_pipeline_cmd(denali, false, true, SPARE_ACCESS, + if (denali_send_pipeline_cmd(denali, page, false, true, SPARE_ACCESS, DENALI_READ) == PASS) { read_data_from_flash_mem(denali, buf, mtd->oobsize); @@ -407,8 +403,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) irq_status = denali_wait_for_irq(denali, irq_mask); if (!(irq_status & INTR__LOAD_COMP)) - dev_err(denali->dev, "page on OOB timeout %d\n", - denali->page); + dev_err(denali->dev, "page on OOB timeout %d\n", page); /* * We set the device back to MAIN_ACCESS here as I observed @@ -417,7 +412,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) * is reliable (according to the MTD test infrastructure) * if you are in MAIN_ACCESS. */ - addr = BANK(denali->flash_bank) | denali->page; + addr = BANK(denali->flash_bank) | page; cmd = MODE_10 | addr; index_addr(denali, cmd, MAIN_ACCESS); } @@ -582,13 +577,13 @@ static void denali_enable_dma(struct denali_nand_info *denali, bool en) ioread32(denali->flash_reg + DMA_ENABLE); } -static void denali_setup_dma64(struct denali_nand_info *denali, int op) +static void denali_setup_dma64(struct denali_nand_info *denali, + dma_addr_t dma_addr, int page, int op) { uint32_t mode; const int page_count = 1; - uint64_t addr = denali->buf.dma_buf; - mode = MODE_10 | BANK(denali->flash_bank) | denali->page; + mode = MODE_10 | BANK(denali->flash_bank) | page; /* DMA is a three step process */ @@ -599,41 +594,42 @@ static void denali_setup_dma64(struct denali_nand_info *denali, int op) index_addr(denali, mode, 0x01002000 | (64 << 16) | op | page_count); /* 2. set memory low address */ - index_addr(denali, mode, addr); + index_addr(denali, mode, dma_addr); /* 3. set memory high address */ - index_addr(denali, mode, addr >> 32); + index_addr(denali, mode, (uint64_t)dma_addr >> 32); } -static void denali_setup_dma32(struct denali_nand_info *denali, int op) +static void denali_setup_dma32(struct denali_nand_info *denali, + dma_addr_t dma_addr, int page, int op) { uint32_t mode; const int page_count = 1; - uint32_t addr = denali->buf.dma_buf; mode = MODE_10 | BANK(denali->flash_bank); /* DMA is a four step process */ /* 1. setup transfer type and # of pages */ - index_addr(denali, mode | denali->page, 0x2000 | op | page_count); + index_addr(denali, mode | page, 0x2000 | op | page_count); /* 2. set memory high address bits 23:8 */ - index_addr(denali, mode | ((addr >> 16) << 8), 0x2200); + index_addr(denali, mode | ((dma_addr >> 16) << 8), 0x2200); /* 3. set memory low address bits 23:8 */ - index_addr(denali, mode | ((addr & 0xffff) << 8), 0x2300); + index_addr(denali, mode | ((dma_addr & 0xffff) << 8), 0x2300); /* 4. interrupt when complete, burst len = 64 bytes */ index_addr(denali, mode | 0x14000, 0x2400); } -static void denali_setup_dma(struct denali_nand_info *denali, int op) +static void denali_setup_dma(struct denali_nand_info *denali, + dma_addr_t dma_addr, int page, int op) { if (denali->caps & DENALI_CAP_DMA_64BIT) - denali_setup_dma64(denali, op); + denali_setup_dma64(denali, dma_addr, page, op); else - denali_setup_dma32(denali, op); + denali_setup_dma32(denali, dma_addr, page, op); } /* @@ -650,8 +646,6 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, uint32_t irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL; int ret = 0; - denali->page = page; - /* * if it is a raw xfer, we want to disable ecc and send the spare area. * !raw_xfer - enable ecc @@ -674,7 +668,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, denali_reset_irq(denali); denali_enable_dma(denali, true); - denali_setup_dma(denali, DENALI_WRITE); + denali_setup_dma(denali, addr, page, DENALI_WRITE); /* wait for operation to complete */ irq_status = denali_wait_for_irq(denali, irq_mask); @@ -750,15 +744,13 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, unsigned long uncor_ecc_flags = 0; int stat = 0; - denali->page = page; - setup_ecc_for_xfer(denali, true, false); denali_enable_dma(denali, true); dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE); denali_reset_irq(denali); - denali_setup_dma(denali, DENALI_READ); + denali_setup_dma(denali, addr, page, DENALI_READ); /* wait for operation to complete */ irq_status = denali_wait_for_irq(denali, irq_mask); @@ -777,7 +769,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, return stat; if (uncor_ecc_flags) { - read_oob_data(mtd, chip->oob_poi, denali->page); + read_oob_data(mtd, chip->oob_poi, page); stat = denali_check_erased_page(mtd, chip, buf, uncor_ecc_flags, stat); @@ -795,15 +787,13 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint32_t irq_mask = INTR__DMA_CMD_COMP; uint32_t irq_status; - denali->page = page; - setup_ecc_for_xfer(denali, false, true); denali_enable_dma(denali, true); dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE); denali_reset_irq(denali); - denali_setup_dma(denali, DENALI_READ); + denali_setup_dma(denali, addr, page, DENALI_READ); /* wait for operation to complete */ irq_status = denali_wait_for_irq(denali, irq_mask); diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index a84d8784ee98..ad2223d179d0 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -316,7 +316,6 @@ struct denali_nand_info { int flash_bank; /* currently selected chip */ struct nand_buf buf; struct device *dev; - int page; void __iomem *flash_reg; /* Register Interface */ void __iomem *flash_mem; /* Host Data/Command Interface */ From patchwork Wed Jun 7 11:52:26 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103243 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1715494obh; Wed, 7 Jun 2017 04:57:34 -0700 (PDT) X-Received: by 10.84.128.68 with SMTP id 62mr28201170pla.184.1496836653936; Wed, 07 Jun 2017 04:57:33 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836653; cv=none; d=google.com; s=arc-20160816; b=AetLN9VWGNLWkEGDQNSBsc/W5suu2BKY6hTdncRY0faRbCZnp8OQm8aRlgDdXQzJb7 OXLkSxdoGFPEUuECJdZNVqO6Maz6ZzWJ6eRMXbwLi6DCzG3tGBHSvYPsQkSO1MjllWk2 UbvZzBgEgqDKs8YHGL4jT8UhWf3VLohHy/4XRN8U/h/kCglb4L6aPRze30YFcjZi4et1 IrsQnX3Z1eP9PJr20PK9Fi5jA/S6sXwb1hunZPdqADT9fOcbyROrH03QxT0CTON8yVIO iSZLXPAsJ7M6+1E9vsmWF7sv6VRscK309KszV+NH40fzlNp6ghDQAhzYsPuE1ANLY4xB 59dg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=B31W5Sc22ECRSoX5bepTB7Y2r/VMF/i51txM25kJQyo=; b=nkuo1/7JheKx1fS+YQ001sHNwBA838xIdnHYxSxS58lrtb1vUA+MhH4nlEJEq7gGBV eQNFTzJr37QMmr0C5SA7LLV+sQ3UoGyvpMeQ08jvz2LiHahuT32KkAYAud7tAfHHGnjR tWpV7c3f2uBM5PwsAHz1jeBskZsJFd9B7yef0e2CO9BnWHd3f5dxYja8gazVMg/r5XZz poVk5hTfkrNozzm+2wy/X4s/bSA1fSk5uTIVA15vDuvIqdj3fy2qSkDpbSZAErMYB6jM d/zQ6FKmytDvKkSZfUla/MQiuH5H3ujJey7wezPwacQ+FH5i3An1EOBi6pe5tZSImaq6 HSSw== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id p68si1629467pfi.108.2017.06.07.04.57.33; Wed, 07 Jun 2017 04:57:33 -0700 (PDT) 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 S1751886AbdFGL5E (ORCPT + 25 others); Wed, 7 Jun 2017 07:57:04 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42682 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751637AbdFGLza (ORCPT ); Wed, 7 Jun 2017 07:55:30 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZg014276; Wed, 7 Jun 2017 20:53:06 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZg014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836387; bh=B31W5Sc22ECRSoX5bepTB7Y2r/VMF/i51txM25kJQyo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=J8s4JZwE26juJlqgU7q0uHkk2iK7hAQAo+KLi0wx5o6cKzJ7ZPyA+q3ffFM6qS0HT aFcGOT93oO4ExIJ3LXuPX3kG9ApE/E8/Cg0dLel8zjdXWzQnsKWlC7UQjznRqr8cq1 HcSembQuOC92j/14jtbLcIIC+nniKjlThAdw3zpNPcNypjBISPiRcphtMhDYCrGtZs AsLSW0q7rBdGOTUPR/VLsY6gJbwIxp/5V0E40ZH3Au8A7g60D4XPZZbmGk6DKG5cr9 ej6CYC8XBrv3jT2I2APBisp1IeGOFoLNIVVBeo0MFEmK7je5kzlckTzW8sldmN0Jkk 2Duasp1SMSrmg== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 17/23] mtd: nand: denali: merge struct nand_buf into struct denali_nand_info Date: Wed, 7 Jun 2017 20:52:26 +0900 Message-Id: <1496836352-8016-18-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 Now struct nand_buf has only two members, so I see no reason for the separation. Signed-off-by: Masahiro Yamada --- Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 29 ++++++++++++++--------------- drivers/mtd/nand/denali.h | 8 ++------ 2 files changed, 16 insertions(+), 21 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 1a96942f62f9..d8d207125701 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -640,7 +640,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int page, bool raw_xfer) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->buf.dma_buf; + dma_addr_t addr = denali->dma_addr; size_t size = mtd->writesize + mtd->oobsize; uint32_t irq_status; uint32_t irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL; @@ -654,11 +654,11 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, setup_ecc_for_xfer(denali, !raw_xfer, raw_xfer); /* copy buffer into DMA buffer */ - memcpy(denali->buf.buf, buf, mtd->writesize); + memcpy(denali->buf, buf, mtd->writesize); if (raw_xfer) { /* transfer the data to the spare area */ - memcpy(denali->buf.buf + mtd->writesize, + memcpy(denali->buf + mtd->writesize, chip->oob_poi, mtd->oobsize); } @@ -735,7 +735,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->buf.dma_buf; + dma_addr_t addr = denali->dma_addr; size_t size = mtd->writesize + mtd->oobsize; uint32_t irq_status; uint32_t irq_mask = denali->caps & DENALI_CAP_HW_ECC_FIXUP ? @@ -757,7 +757,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE); - memcpy(buf, denali->buf.buf, mtd->writesize); + memcpy(buf, denali->buf, mtd->writesize); if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) stat = denali_hw_ecc_fixup(mtd, denali, &uncor_ecc_flags); @@ -782,7 +782,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->buf.dma_buf; + dma_addr_t addr = denali->dma_addr; size_t size = mtd->writesize + mtd->oobsize; uint32_t irq_mask = INTR__DMA_CMD_COMP; uint32_t irq_status; @@ -804,8 +804,8 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, denali_enable_dma(denali, false); - memcpy(buf, denali->buf.buf, mtd->writesize); - memcpy(chip->oob_poi, denali->buf.buf + mtd->writesize, mtd->oobsize); + memcpy(buf, denali->buf, mtd->writesize); + memcpy(chip->oob_poi, denali->buf + mtd->writesize, mtd->oobsize); return 0; } @@ -1224,10 +1224,9 @@ int denali_init(struct denali_nand_info *denali) if (ret) goto disable_irq; - denali->buf.buf = devm_kzalloc(denali->dev, - mtd->writesize + mtd->oobsize, - GFP_KERNEL); - if (!denali->buf.buf) { + denali->buf = devm_kzalloc(denali->dev, mtd->writesize + mtd->oobsize, + GFP_KERNEL); + if (!denali->buf) { ret = -ENOMEM; goto disable_irq; } @@ -1240,10 +1239,10 @@ int denali_init(struct denali_nand_info *denali) goto disable_irq; } - denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf, + denali->dma_addr = dma_map_single(denali->dev, denali->buf, mtd->writesize + mtd->oobsize, DMA_BIDIRECTIONAL); - if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) { + if (dma_mapping_error(denali->dev, denali->dma_addr)) { dev_err(denali->dev, "Failed to map DMA buffer\n"); ret = -EIO; goto disable_irq; @@ -1337,7 +1336,7 @@ void denali_remove(struct denali_nand_info *denali) nand_release(mtd); denali_disable_irq(denali); - dma_unmap_single(denali->dev, denali->buf.dma_buf, bufsize, + dma_unmap_single(denali->dev, denali->dma_addr, bufsize, DMA_BIDIRECTIONAL); } EXPORT_SYMBOL(denali_remove); diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index ad2223d179d0..1b991d3016f8 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -305,16 +305,10 @@ #define MODE_10 0x08000000 #define MODE_11 0x0C000000 -struct nand_buf { - uint8_t *buf; - dma_addr_t dma_buf; -}; - struct denali_nand_info { struct nand_chip nand; unsigned long clk_x_rate; /* bus interface clock rate */ int flash_bank; /* currently selected chip */ - struct nand_buf buf; struct device *dev; void __iomem *flash_reg; /* Register Interface */ void __iomem *flash_mem; /* Host Data/Command Interface */ @@ -326,6 +320,8 @@ struct denali_nand_info { uint32_t irq_status; int irq; + void *buf; + dma_addr_t dma_addr; int devnum; /* represent how many nands connected */ int bbtskipbytes; int max_banks; From patchwork Wed Jun 7 11:52:27 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103237 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1714816obh; Wed, 7 Jun 2017 04:55:43 -0700 (PDT) X-Received: by 10.98.5.130 with SMTP id 124mr30824999pff.209.1496836543743; Wed, 07 Jun 2017 04:55:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836543; cv=none; d=google.com; s=arc-20160816; b=fog3SckWSHwC5ertKTD/tyURdwEZTUhtdv/ue1JjCiPVSQF8yC16U6CfrZlT+xqSq/ h6JDoqPoIXJ6mq2A1nPe28HmvlhUn/ecZfHAdfZSRir/Fi4yTBTkla4NokK3bEeCEVAS krN5AtlIoiY7z9deEhircNxWIo2lN2WMQboIV3r14Mx2/pt9oD3KiJoMM6310O7wohKv tN4ucdMwga3LmQIxLqTO17n273t3hfne9Pm5DdZ0LHjqeNQOdk13YL57PZwEJvXy277u MruSp7+sqpKbK7eV+D9iYXs2B3K9qU+Ucy1iFt5k7Z37s50Z+uyeAxVVAt9Mfr4SyOs9 1Knw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=aAEh++VVVxJI05TySbNB12PLkWL7nCG73zseBkVCTiA=; b=nFjAUYMDwbVpE0a2nmMWUUr2Nb7s1WhkbpsjxCSfk1EU3yH07hc4qjNqbvYEM/dnJz VPgvRhJspYKioVNptkuXbtQCwKokCMqp3pg6+hDtrbN/mzWwHYkVOv4X5xltxYaCJqOU RJih18Wk7fmO/EmT/8VDxTEefLVUiQdppLmNvAuGAD3ijcIqs74Ygwe9NLhrLTRoAh2W M7zDgfy760JU7TZTrYuQGyjgZHcvOE1e1toGssQFAUfDjYXOxO0sXzx7CoErvsuOyLfJ rtpDe5DtO+e6iRpedtPZYAD1B6RuS6p23znAsC4155K4g+5wOsJmTp6m/5Dm1BUuNklj qilw== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id e186si1569105pgc.163.2017.06.07.04.55.43; Wed, 07 Jun 2017 04:55:43 -0700 (PDT) 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 S1751734AbdFGLzj (ORCPT + 25 others); Wed, 7 Jun 2017 07:55:39 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42824 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751707AbdFGLze (ORCPT ); Wed, 7 Jun 2017 07:55:34 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZh014276; Wed, 7 Jun 2017 20:53:07 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZh014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836388; bh=aAEh++VVVxJI05TySbNB12PLkWL7nCG73zseBkVCTiA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=K2xQ8pnf+ptWPNYEzmQGzXbd7wRgyUqVxDXa4maz1PmukTbGOHwx/Ew3tFoCl4J5q 819o4Tq32YzNncE2dZ81J5jOm0NEDlM9ogROyNDJ3wjWpCWsuwpfITZ2Tsqm6pG4nJ +/yOkCsKatta1hfkt0an719DAW+T3YO2sQrS0Wp3IjAXnJ+f5c0qKWaxSzXYHt0TDP NwEAluWvryH0yX3VQQa0bLsfaloU6a18RYBRuLiYqD4tK4oCd8ec+WL0FYlvBD1yPU nIsKhMN6afhLtCwJJKAJmYgNNJxr5I/EnLDDQrFcgAWtNI7s2nGwML6WFCsw+MC17T tvTr58BiDjHyg== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 18/23] mtd: nand: denali: use flag instead of register macro for direction Date: Wed, 7 Jun 2017 20:52:27 +0900 Message-Id: <1496836352-8016-19-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 It is not a good idea to re-use macros that represent a specific register bit field for the transfer direction. It is true that bit 8 indicates the direction for the MAP10 pipeline operation and the data DMA operation, but this is not valid across the IP. Use a simple flag (write: 1, read: 0) for the direction. Signed-off-by: Masahiro Yamada --- Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index d8d207125701..735dcbdbb1b4 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -53,9 +53,6 @@ static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd) #define MAIN_ACCESS 0x42 #define MAIN_SPARE_ACCESS 0x43 -#define DENALI_READ 0 -#define DENALI_WRITE 0x100 - #define DENALI_NR_BANKS 4 /* @@ -284,7 +281,7 @@ static int denali_dev_ready(struct mtd_info *mtd) */ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, int page, bool ecc_en, bool transfer_spare, - int access_type, int op) + int access_type, int write) { int status = PASS; uint32_t addr, cmd; @@ -295,17 +292,17 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, int page, addr = BANK(denali->flash_bank) | page; - if (op == DENALI_WRITE && access_type != SPARE_ACCESS) { + if (write && access_type != SPARE_ACCESS) { cmd = MODE_01 | addr; iowrite32(cmd, denali->flash_mem); - } else if (op == DENALI_WRITE && access_type == SPARE_ACCESS) { + } else if (write && access_type == SPARE_ACCESS) { /* read spare area */ cmd = MODE_10 | addr; index_addr(denali, cmd, access_type); cmd = MODE_01 | addr; iowrite32(cmd, denali->flash_mem); - } else if (op == DENALI_READ) { + } else { /* setup page read request for access type */ cmd = MODE_10 | addr; index_addr(denali, cmd, access_type); @@ -367,7 +364,7 @@ static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) int status = 0; if (denali_send_pipeline_cmd(denali, page, false, false, SPARE_ACCESS, - DENALI_WRITE) == PASS) { + 1) == PASS) { write_data_to_flash_mem(denali, buf, mtd->oobsize); /* wait for operation to complete */ @@ -392,7 +389,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) uint32_t irq_status, addr, cmd; if (denali_send_pipeline_cmd(denali, page, false, true, SPARE_ACCESS, - DENALI_READ) == PASS) { + 0) == PASS) { read_data_from_flash_mem(denali, buf, mtd->oobsize); /* @@ -578,7 +575,7 @@ static void denali_enable_dma(struct denali_nand_info *denali, bool en) } static void denali_setup_dma64(struct denali_nand_info *denali, - dma_addr_t dma_addr, int page, int op) + dma_addr_t dma_addr, int page, int write) { uint32_t mode; const int page_count = 1; @@ -591,7 +588,8 @@ static void denali_setup_dma64(struct denali_nand_info *denali, * 1. setup transfer type, interrupt when complete, * burst len = 64 bytes, the number of pages */ - index_addr(denali, mode, 0x01002000 | (64 << 16) | op | page_count); + index_addr(denali, mode, + 0x01002000 | (64 << 16) | (write << 8) | page_count); /* 2. set memory low address */ index_addr(denali, mode, dma_addr); @@ -601,7 +599,7 @@ static void denali_setup_dma64(struct denali_nand_info *denali, } static void denali_setup_dma32(struct denali_nand_info *denali, - dma_addr_t dma_addr, int page, int op) + dma_addr_t dma_addr, int page, int write) { uint32_t mode; const int page_count = 1; @@ -611,7 +609,7 @@ static void denali_setup_dma32(struct denali_nand_info *denali, /* DMA is a four step process */ /* 1. setup transfer type and # of pages */ - index_addr(denali, mode | page, 0x2000 | op | page_count); + index_addr(denali, mode | page, 0x2000 | (write << 8) | page_count); /* 2. set memory high address bits 23:8 */ index_addr(denali, mode | ((dma_addr >> 16) << 8), 0x2200); @@ -624,12 +622,12 @@ static void denali_setup_dma32(struct denali_nand_info *denali, } static void denali_setup_dma(struct denali_nand_info *denali, - dma_addr_t dma_addr, int page, int op) + dma_addr_t dma_addr, int page, int write) { if (denali->caps & DENALI_CAP_DMA_64BIT) - denali_setup_dma64(denali, dma_addr, page, op); + denali_setup_dma64(denali, dma_addr, page, write); else - denali_setup_dma32(denali, dma_addr, page, op); + denali_setup_dma32(denali, dma_addr, page, write); } /* @@ -668,7 +666,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, denali_reset_irq(denali); denali_enable_dma(denali, true); - denali_setup_dma(denali, addr, page, DENALI_WRITE); + denali_setup_dma(denali, addr, page, 1); /* wait for operation to complete */ irq_status = denali_wait_for_irq(denali, irq_mask); @@ -750,7 +748,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE); denali_reset_irq(denali); - denali_setup_dma(denali, addr, page, DENALI_READ); + denali_setup_dma(denali, addr, page, 0); /* wait for operation to complete */ irq_status = denali_wait_for_irq(denali, irq_mask); @@ -793,7 +791,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE); denali_reset_irq(denali); - denali_setup_dma(denali, addr, page, DENALI_READ); + denali_setup_dma(denali, addr, page, 0); /* wait for operation to complete */ irq_status = denali_wait_for_irq(denali, irq_mask); From patchwork Wed Jun 7 11:52:28 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103253 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1716409obh; Wed, 7 Jun 2017 05:00:00 -0700 (PDT) X-Received: by 10.98.59.212 with SMTP id w81mr31086923pfj.107.1496836800323; Wed, 07 Jun 2017 05:00:00 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836800; cv=none; d=google.com; s=arc-20160816; b=Cc6g0FfsGrD0vdvcCFmQhReQcAB8CFNpLYV5q8hmt6/C2fSwL4/Tj7zlxv2k6iplG9 8lUbu9GjJWCQpzDGY/HZGvKENNDrDwg9pTzb67Ht0IaahXj+3uBrh4dMGw5kBp8l+cgY /tZTIhOACDVggCzCBqBcTN5Pvm+fU/g+PDp7ZyUELoAJXClAiAUKzhWAI5S9QjuwwSGa SADte3COMjw3yUoZ9pupWTpMCWu0aw9dRZyx9EQf6Yf3R3/PknFJeJRAfc4/S0GRVlVo hlEXQ08RkpAjfHlJUZKPWhafJy3gNhvhTiPLp6a2qrw9Q4NboIq5ir690R21c0wFiXEQ JuZg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=3cigQyUZ9sctNtnXvfyBdL4gj3bNoQ6rL2rauLU5SG8=; b=PPppvHmMmCS0KRus8tqhlpnazcsgaSi/SK8zNFAeKPS1cstR/soBGmFXiMhqQHePPf HuNr8r6w3n2ei8haP12uvmEq9mZLh0/MaygInLQlDhEVvksKJ3i8VFw8hVmcsXKao7Bk swwdN1Ene4O5DqJnI4cQoSj0iT1B4NtPMqrgH/cuiFtwrpZ94BIcZekT3sJfFrlt4yhx Y2srf3Ab+bmE4MWf9uuo2n2NNPu+WiZhM6+cr4h+8rfqAi2NhN/gOOwiVXzmCrsbTlfO KtNv9C5pfSkeX+rVn8Kj5tq0YH2TK7JQT40BlhiNNTSiSEKVCXhwp+jE/41dobrS0ENJ KRlg== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 33si1533344plk.543.2017.06.07.04.59.59; Wed, 07 Jun 2017 05:00:00 -0700 (PDT) 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 S1751870AbdFGL7m (ORCPT + 25 others); Wed, 7 Jun 2017 07:59:42 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42463 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751543AbdFGLzX (ORCPT ); Wed, 7 Jun 2017 07:55:23 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZi014276; Wed, 7 Jun 2017 20:53:08 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZi014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836389; bh=3cigQyUZ9sctNtnXvfyBdL4gj3bNoQ6rL2rauLU5SG8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dJOu6HdDwjduHb05tWAf0sk/hXmGaT1BYCsvYN7Y9RsDP77JxhtRBF1/i28DE/WMq szdmBXfziLFVcmjIDFw9inW+slPERtyEEXLHsT/xjFQvL+QrpD4aKqqgj2mMNenQfH S7uVfnk6jHNDBstpzmfCt8zfn3ZI+ZLbehB7BRgdq5HwwIGQdWY/5skYHtpgXqoa6v HHq0m4tQy8uH/6As4yfUMl4MYcE31No/W1OHJvHZR4u5TtT/ezugsiFDK2/gXBorfZ YO9Erb6jnKhoB9hJE7yRP67QXUFt+X+ctVTq03GNNl4JyxZ/SomUFmqi6fpRNIZ7k5 BdMzARZfpNZqg== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 19/23] mtd: nand: denali: fix raw and oob accessors for syndrome page layout Date: Wed, 7 Jun 2017 20:52:28 +0900 Message-Id: <1496836352-8016-20-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 The Denali IP adopts the syndrome page layout; payload and ECC are interleaved, with BBM area always placed at the beginning of OOB. The figure below shows the page organization for ecc->steps == 2: |----------------| |-----------| | | | | | | | | | Payload0 | | | | | | | | | | | | | | | |----------------| | in-band | | ECC0 | | area | |----------------| | | | | | | | | | | | Payload1 | | | | | | | | | | | |----------------| |-----------| | BBM | | | |----------------| | | |Payload1 (cont.)| | | |----------------| |out-of-band| | ECC1 | | area | |----------------| | | | OOB free | | | |----------------| |-----------| The current raw / oob accessors do not take that into consideration, so in-band and out-of-band data are transferred as stored in the device. In the case above, in-band: Payload0 + ECC0 + Payload1(partial) out-of-band: BBM + Payload1(cont.) + ECC1 + OOB-free This is wrong. As the comment block of struct nand_ecc_ctrl says, driver callbacks must hide the specific layout used by the hardware and always return contiguous in-band and out-of-band data. The current implementation is completely screwed-up, so read/write callbacks must be re-worked. Also, it is reasonable to support PIO transfer in case DMA may not work for some reasons. Actually, the Data DMA may not be equipped depending on the configuration of the RTL. This can be checked by reading the bit 4 of the FEATURES register. Even if the controller has the DMA support, dma_set_mask() and dma_map_single() could fail. In either case, the driver can fall back to the PIO transfer. Slower access would be better than giving up. Signed-off-by: Masahiro Yamada --- Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 613 ++++++++++++++++++++++++++++++---------------- drivers/mtd/nand/denali.h | 3 +- 2 files changed, 397 insertions(+), 219 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 735dcbdbb1b4..dcadf9655d7a 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -246,6 +246,53 @@ static void denali_write_byte(struct mtd_info *mtd, uint8_t byte) index_addr(denali, MODE_11 | BANK(denali->flash_bank) | 2, byte); } +static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + int i; + + iowrite32(MODE_11 | BANK(denali->flash_bank) | 2, denali->flash_mem); + + for (i = 0; i < len; i++) + buf[i] = ioread32(denali->flash_mem + 0x10); +} + +static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + int i; + + iowrite32(MODE_11 | BANK(denali->flash_bank) | 2, denali->flash_mem); + + for (i = 0; i < len; i++) + iowrite32(buf[i], denali->flash_mem + 0x10); +} + +static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + uint16_t *buf16 = (uint16_t *)buf; + int i; + + iowrite32(MODE_11 | BANK(denali->flash_bank) | 2, denali->flash_mem); + + for (i = 0; i < len / 2; i++) + buf16[i] = ioread32(denali->flash_mem + 0x10); +} + +static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf, + int len) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + const uint16_t *buf16 = (const uint16_t *)buf; + int i; + + iowrite32(MODE_11 | BANK(denali->flash_bank) | 2, denali->flash_mem); + + for (i = 0; i < len / 2; i++) + iowrite32(buf16[i], denali->flash_mem + 0x10); +} + static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) { struct denali_nand_info *denali = mtd_to_denali(mtd); @@ -275,44 +322,6 @@ static int denali_dev_ready(struct mtd_info *mtd) return !!(denali_check_irq(denali) & INTR__INT_ACT); } -/* - * sends a pipeline command operation to the controller. See the Denali NAND - * controller's user guide for more information (section 4.2.3.6). - */ -static int denali_send_pipeline_cmd(struct denali_nand_info *denali, int page, - bool ecc_en, bool transfer_spare, - int access_type, int write) -{ - int status = PASS; - uint32_t addr, cmd; - - setup_ecc_for_xfer(denali, ecc_en, transfer_spare); - - denali_reset_irq(denali); - - addr = BANK(denali->flash_bank) | page; - - if (write && access_type != SPARE_ACCESS) { - cmd = MODE_01 | addr; - iowrite32(cmd, denali->flash_mem); - } else if (write && access_type == SPARE_ACCESS) { - /* read spare area */ - cmd = MODE_10 | addr; - index_addr(denali, cmd, access_type); - - cmd = MODE_01 | addr; - iowrite32(cmd, denali->flash_mem); - } else { - /* setup page read request for access type */ - cmd = MODE_10 | addr; - index_addr(denali, cmd, access_type); - - cmd = MODE_01 | addr; - iowrite32(cmd, denali->flash_mem); - } - return status; -} - /* helper function that simply writes a buffer to the flash */ static int write_data_to_flash_mem(struct denali_nand_info *denali, const uint8_t *buf, int len) @@ -355,66 +364,6 @@ static int read_data_from_flash_mem(struct denali_nand_info *denali, return i * 4; /* intent is to return the number of bytes read */ } -/* writes OOB data to the device */ -static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t irq_status; - uint32_t irq_mask = INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL; - int status = 0; - - if (denali_send_pipeline_cmd(denali, page, false, false, SPARE_ACCESS, - 1) == PASS) { - write_data_to_flash_mem(denali, buf, mtd->oobsize); - - /* wait for operation to complete */ - irq_status = denali_wait_for_irq(denali, irq_mask); - - if (!(irq_status & INTR__PROGRAM_COMP)) { - dev_err(denali->dev, "OOB write failed\n"); - status = -EIO; - } - } else { - dev_err(denali->dev, "unable to send pipeline command\n"); - status = -EIO; - } - return status; -} - -/* reads OOB data from the device */ -static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t irq_mask = INTR__LOAD_COMP; - uint32_t irq_status, addr, cmd; - - if (denali_send_pipeline_cmd(denali, page, false, true, SPARE_ACCESS, - 0) == PASS) { - read_data_from_flash_mem(denali, buf, mtd->oobsize); - - /* - * wait for command to be accepted - * can always use status0 bit as the - * mask is identical for each bank. - */ - irq_status = denali_wait_for_irq(denali, irq_mask); - - if (!(irq_status & INTR__LOAD_COMP)) - dev_err(denali->dev, "page on OOB timeout %d\n", page); - - /* - * We set the device back to MAIN_ACCESS here as I observed - * instability with the controller if you do a block erase - * and the last transaction was a SPARE_ACCESS. Block erase - * is reliable (according to the MTD test infrastructure) - * if you are in MAIN_ACCESS. - */ - addr = BANK(denali->flash_bank) | page; - cmd = MODE_10 | addr; - index_addr(denali, cmd, MAIN_ACCESS); - } -} - static int denali_check_erased_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, unsigned long uncor_ecc_flags, @@ -630,144 +579,302 @@ static void denali_setup_dma(struct denali_nand_info *denali, denali_setup_dma32(denali, dma_addr, page, write); } -/* - * writes a page. user specifies type, and this function handles the - * configuration details. - */ -static int write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int page, bool raw_xfer) +static int denali_pio_read(struct denali_nand_info *denali, void *buf, + size_t size, int page, int raw) { - struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->dma_addr; - size_t size = mtd->writesize + mtd->oobsize; - uint32_t irq_status; - uint32_t irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL; - int ret = 0; + uint32_t addr = BANK(denali->flash_bank) | page; + uint32_t irq_status, ecc_err_mask; - /* - * if it is a raw xfer, we want to disable ecc and send the spare area. - * !raw_xfer - enable ecc - * raw_xfer - transfer spare - */ - setup_ecc_for_xfer(denali, !raw_xfer, raw_xfer); + /* setup page read request for access type */ + index_addr(denali, MODE_10 | addr, + raw ? MAIN_SPARE_ACCESS : MAIN_ACCESS); - /* copy buffer into DMA buffer */ - memcpy(denali->buf, buf, mtd->writesize); + iowrite32(MODE_01 | addr, denali->flash_mem); - if (raw_xfer) { - /* transfer the data to the spare area */ - memcpy(denali->buf + mtd->writesize, - chip->oob_poi, - mtd->oobsize); - } + if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) + ecc_err_mask = INTR__ECC_UNCOR_ERR; + else + ecc_err_mask = INTR__ECC_ERR; - dma_sync_single_for_device(denali->dev, addr, size, DMA_TO_DEVICE); + denali_reset_irq(denali); + + read_data_from_flash_mem(denali, buf, size); + + irq_status = denali_wait_for_irq(denali, INTR__PAGE_XFER_INC); + if (!(irq_status & INTR__PAGE_XFER_INC)) + return -EIO; + + return irq_status & ecc_err_mask ? -EBADMSG : 0; +} + +static int denali_pio_write(struct denali_nand_info *denali, + const void *buf, size_t size, int page, int raw) +{ + uint32_t addr = BANK(denali->flash_bank) | page; + uint32_t irq_status; + + /* setup page read request for access type */ + index_addr(denali, MODE_10 | addr, + raw ? MAIN_SPARE_ACCESS : MAIN_ACCESS); + + iowrite32(MODE_01 | addr, denali->flash_mem); denali_reset_irq(denali); + + write_data_to_flash_mem(denali, buf, size); + + irq_status = denali_wait_for_irq(denali, + INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL); + if (!(irq_status & INTR__PROGRAM_COMP)) + return -EIO; + + return 0; +} + +static int denali_pio_xfer(struct denali_nand_info *denali, void *buf, + size_t size, int page, int raw, int write) +{ + if (write) + return denali_pio_write(denali, buf, size, page, raw); + else + return denali_pio_read(denali, buf, size, page, raw); +} + +static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, + size_t size, int page, int raw, int write) +{ + dma_addr_t dma_addr = denali->dma_addr; + uint32_t irq_mask, irq_status, ecc_err_mask; + enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + int ret = 0; + + dma_sync_single_for_device(denali->dev, dma_addr, size, dir); + + if (write) { + irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL; + ecc_err_mask = 0; + } else if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) { + irq_mask = INTR__DMA_CMD_COMP; + ecc_err_mask = INTR__ECC_UNCOR_ERR; + } else { + irq_mask = INTR__DMA_CMD_COMP; + ecc_err_mask = INTR__ECC_ERR; + } + denali_enable_dma(denali, true); - denali_setup_dma(denali, addr, page, 1); + denali_reset_irq(denali); + denali_setup_dma(denali, dma_addr, page, write); /* wait for operation to complete */ irq_status = denali_wait_for_irq(denali, irq_mask); - if (!(irq_status & INTR__DMA_CMD_COMP)) { - dev_err(denali->dev, "timeout on write_page (type = %d)\n", - raw_xfer); + if (!(irq_status & INTR__DMA_CMD_COMP)) ret = -EIO; - } + else if (irq_status & ecc_err_mask) + ret = -EBADMSG; denali_enable_dma(denali, false); - dma_sync_single_for_cpu(denali->dev, addr, size, DMA_TO_DEVICE); + dma_sync_single_for_cpu(denali->dev, dma_addr, size, dir); return ret; } -/* NAND core entry points */ - -/* - * this is the callback that the NAND core calls to write a page. Since - * writing a page with ECC or without is similar, all the work is done - * by write_page above. - */ -static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, int page) +static int denali_data_xfer(struct denali_nand_info *denali, void *buf, + size_t size, int page, int raw, int write) { - /* - * for regular page writes, we let HW handle all the ECC - * data written to the device. - */ - return write_page(mtd, chip, buf, page, false); + setup_ecc_for_xfer(denali, !raw, raw); + + if (denali->dma_avail) + return denali_dma_xfer(denali, buf, size, page, raw, write); + else + return denali_pio_xfer(denali, buf, size, page, raw, write); } -/* - * This is the callback that the NAND core calls to write a page without ECC. - * raw access is similar to ECC page writes, so all the work is done in the - * write_page() function above. - */ -static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, - int page) +static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip, + int page, int write) { - /* - * for raw page writes, we want to disable ECC and simply write - * whatever data is in the buffer. - */ - return write_page(mtd, chip, buf, page, true); + struct denali_nand_info *denali = mtd_to_denali(mtd); + unsigned int start_cmd = write ? NAND_CMD_SEQIN : NAND_CMD_READ0; + unsigned int rnd_cmd = write ? NAND_CMD_RNDIN : NAND_CMD_RNDOUT; + int writesize = mtd->writesize; + int oobsize = mtd->oobsize; + uint8_t *bufpoi = chip->oob_poi; + int ecc_steps = chip->ecc.steps; + int ecc_size = chip->ecc.size; + int ecc_bytes = chip->ecc.bytes; + int oob_skip = denali->bbtskipbytes; + size_t size = writesize + oobsize; + int i, pos, len; + + /* BBM at the beginning of the OOB area */ + chip->cmdfunc(mtd, start_cmd, writesize, page); + if (write) + chip->write_buf(mtd, bufpoi, oob_skip); + else + chip->read_buf(mtd, bufpoi, oob_skip); + bufpoi += oob_skip; + + /* OOB ECC */ + for (i = 0; i < ecc_steps; i++) { + pos = ecc_size + i * (ecc_size + ecc_bytes); + len = ecc_bytes; + + if (pos >= writesize) + pos += oob_skip; + else if (pos + len > writesize) + len = writesize - pos; + + chip->cmdfunc(mtd, rnd_cmd, pos, -1); + if (write) + chip->write_buf(mtd, bufpoi, len); + else + chip->read_buf(mtd, bufpoi, len); + bufpoi += len; + if (len < ecc_bytes) { + len = ecc_bytes - len; + chip->cmdfunc(mtd, rnd_cmd, writesize + oob_skip, -1); + if (write) + chip->write_buf(mtd, bufpoi, len); + else + chip->read_buf(mtd, bufpoi, len); + bufpoi += len; + } + } + + /* OOB free */ + len = oobsize - (bufpoi - chip->oob_poi); + chip->cmdfunc(mtd, rnd_cmd, size - len, -1); + if (write) + chip->write_buf(mtd, bufpoi, len); + else + chip->read_buf(mtd, bufpoi, len); } -static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) { - return write_oob_data(mtd, chip->oob_poi, page); + struct denali_nand_info *denali = mtd_to_denali(mtd); + int writesize = mtd->writesize; + int oobsize = mtd->oobsize; + int ecc_steps = chip->ecc.steps; + int ecc_size = chip->ecc.size; + int ecc_bytes = chip->ecc.bytes; + void *dma_buf = denali->buf; + int oob_skip = denali->bbtskipbytes; + size_t size = writesize + oobsize; + int ret, i, pos, len; + + ret = denali_data_xfer(denali, dma_buf, size, page, 1, 0); + if (ret) + return ret; + + /* Arrange the buffer for syndrome payload/ecc layout */ + if (buf) { + for (i = 0; i < ecc_steps; i++) { + pos = i * (ecc_size + ecc_bytes); + len = ecc_size; + + if (pos >= writesize) + pos += oob_skip; + else if (pos + len > writesize) + len = writesize - pos; + + memcpy(buf, dma_buf + pos, len); + buf += len; + if (len < ecc_size) { + len = ecc_size - len; + memcpy(buf, dma_buf + writesize + oob_skip, + len); + buf += len; + } + } + } + + if (oob_required) { + uint8_t *oob = chip->oob_poi; + + /* BBM at the beginning of the OOB area */ + memcpy(oob, dma_buf + writesize, oob_skip); + oob += oob_skip; + + /* OOB ECC */ + for (i = 0; i < ecc_steps; i++) { + pos = ecc_size + i * (ecc_size + ecc_bytes); + len = ecc_bytes; + + if (pos >= writesize) + pos += oob_skip; + else if (pos + len > writesize) + len = writesize - pos; + + memcpy(oob, dma_buf + pos, len); + oob += len; + if (len < ecc_bytes) { + len = ecc_bytes - len; + memcpy(oob, dma_buf + writesize + oob_skip, + len); + oob += len; + } + } + + /* OOB free */ + len = oobsize - (oob - chip->oob_poi); + memcpy(oob, dma_buf + size - len, len); + } + + return 0; } static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) { - read_oob_data(mtd, chip->oob_poi, page); + denali_oob_xfer(mtd, chip, page, 0); return 0; } -static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->dma_addr; - size_t size = mtd->writesize + mtd->oobsize; - uint32_t irq_status; - uint32_t irq_mask = denali->caps & DENALI_CAP_HW_ECC_FIXUP ? - INTR__DMA_CMD_COMP | INTR__ECC_UNCOR_ERR : - INTR__ECC_TRANSACTION_DONE | INTR__ECC_ERR; - unsigned long uncor_ecc_flags = 0; - int stat = 0; + int status; - setup_ecc_for_xfer(denali, true, false); + denali_reset_irq(denali); - denali_enable_dma(denali, true); - dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE); + denali_oob_xfer(mtd, chip, page, 1); - denali_reset_irq(denali); - denali_setup_dma(denali, addr, page, 0); + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + status = chip->waitfunc(mtd, chip); - /* wait for operation to complete */ - irq_status = denali_wait_for_irq(denali, irq_mask); + return status & NAND_STATUS_FAIL ? -EIO : 0; +} - dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE); +static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + unsigned long uncor_ecc_flags = 0; + int stat = 0; + int ret; + + ret = denali_data_xfer(denali, denali->buf, mtd->writesize, page, 0, 0); + if (ret && ret != -EBADMSG) + return ret; memcpy(buf, denali->buf, mtd->writesize); if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) stat = denali_hw_ecc_fixup(mtd, denali, &uncor_ecc_flags); - else if (irq_status & INTR__ECC_ERR) + else if (ret == -EBADMSG) stat = denali_sw_ecc_fixup(mtd, denali, &uncor_ecc_flags, buf); - denali_enable_dma(denali, false); if (stat < 0) return stat; if (uncor_ecc_flags) { - read_oob_data(mtd, chip->oob_poi, page); + ret = denali_read_oob(mtd, chip, page); + if (ret) + return ret; stat = denali_check_erased_page(mtd, chip, buf, uncor_ecc_flags, stat); @@ -776,36 +883,93 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, return stat; } -static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->dma_addr; - size_t size = mtd->writesize + mtd->oobsize; - uint32_t irq_mask = INTR__DMA_CMD_COMP; - uint32_t irq_status; - - setup_ecc_for_xfer(denali, false, true); - denali_enable_dma(denali, true); + int writesize = mtd->writesize; + int oobsize = mtd->oobsize; + int ecc_steps = chip->ecc.steps; + int ecc_size = chip->ecc.size; + int ecc_bytes = chip->ecc.bytes; + void *dma_buf = denali->buf; + int oob_skip = denali->bbtskipbytes; + size_t size = writesize + oobsize; + int i, pos, len; - dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE); + /* + * Fill the buffer with 0xff first except the full page transfer. + * This simplifies the logic. + */ + if (!buf || !oob_required) + memset(dma_buf, 0xff, size); + + /* Arrange the buffer for syndrome payload/ecc layout */ + if (buf) { + for (i = 0; i < ecc_steps; i++) { + pos = i * (ecc_size + ecc_bytes); + len = ecc_size; + + if (pos >= writesize) + pos += oob_skip; + else if (pos + len > writesize) + len = writesize - pos; + + memcpy(dma_buf + pos, buf, len); + buf += len; + if (len < ecc_size) { + len = ecc_size - len; + memcpy(dma_buf + writesize + oob_skip, buf, + len); + buf += len; + } + } + } - denali_reset_irq(denali); - denali_setup_dma(denali, addr, page, 0); + if (oob_required) { + const uint8_t *oob = chip->oob_poi; + + /* BBM at the beginning of the OOB area */ + memcpy(dma_buf + writesize, oob, oob_skip); + oob += oob_skip; + + /* OOB ECC */ + for (i = 0; i < ecc_steps; i++) { + pos = ecc_size + i * (ecc_size + ecc_bytes); + len = ecc_bytes; + + if (pos >= writesize) + pos += oob_skip; + else if (pos + len > writesize) + len = writesize - pos; + + memcpy(dma_buf + pos, oob, len); + oob += len; + if (len < ecc_bytes) { + len = ecc_bytes - len; + memcpy(dma_buf + writesize + oob_skip, oob, + len); + oob += len; + } + } - /* wait for operation to complete */ - irq_status = denali_wait_for_irq(denali, irq_mask); - if (irq_status & INTR__DMA_CMD_COMP) - return -ETIMEDOUT; + /* OOB free */ + len = oobsize - (oob - chip->oob_poi); + memcpy(dma_buf + size - len, oob, len); + } - dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE); + return denali_data_xfer(denali, dma_buf, size, page, 1, 1); +} - denali_enable_dma(denali, false); +static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required, int page) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); - memcpy(buf, denali->buf, mtd->writesize); - memcpy(chip->oob_poi, denali->buf + mtd->writesize, mtd->oobsize); + memcpy(denali->buf, buf, mtd->writesize); - return 0; + return denali_data_xfer(denali, denali->buf, mtd->writesize, page, + 0, 1); } static void denali_select_chip(struct mtd_info *mtd, int chip) @@ -1229,21 +1393,29 @@ int denali_init(struct denali_nand_info *denali) goto disable_irq; } - ret = dma_set_mask(denali->dev, - DMA_BIT_MASK(denali->caps & DENALI_CAP_DMA_64BIT ? - 64 : 32)); - if (ret) { - dev_err(denali->dev, "No usable DMA configuration\n"); - goto disable_irq; + if (ioread32(denali->flash_reg + FEATURES) & FEATURES__DMA) + denali->dma_avail = 1; + + if (denali->dma_avail) { + int dma_bit = denali->caps & DENALI_CAP_DMA_64BIT ? 64 : 32; + + ret = dma_set_mask(denali->dev, DMA_BIT_MASK(dma_bit)); + if (ret) { + dev_info(denali->dev, + "Failed to set DMA mask. Disabling DMA.\n"); + denali->dma_avail = 0; + } } - denali->dma_addr = dma_map_single(denali->dev, denali->buf, - mtd->writesize + mtd->oobsize, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(denali->dev, denali->dma_addr)) { - dev_err(denali->dev, "Failed to map DMA buffer\n"); - ret = -EIO; - goto disable_irq; + if (denali->dma_avail) { + denali->dma_addr = dma_map_single(denali->dev, denali->buf, + mtd->writesize + mtd->oobsize, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(denali->dev, denali->dma_addr)) { + dev_info(denali->dev, + "Failed to map DMA buffer. Disabling DMA.\n"); + denali->dma_avail = 0; + }; } /* @@ -1290,6 +1462,13 @@ int denali_init(struct denali_nand_info *denali) mtd_set_ooblayout(mtd, &denali_ooblayout_ops); + if (chip->options & NAND_BUSWIDTH_16) { + chip->read_buf = denali_read_buf16; + chip->write_buf = denali_write_buf16; + } else { + chip->read_buf = denali_read_buf; + chip->write_buf = denali_write_buf; + } chip->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS; chip->ecc.read_page = denali_read_page; chip->ecc.read_page_raw = denali_read_page_raw; diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 1b991d3016f8..f5da52f09e34 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -298,8 +298,6 @@ #define CHNL_ACTIVE__CHANNEL2 BIT(2) #define CHNL_ACTIVE__CHANNEL3 BIT(3) -#define PASS 0 /*success flag*/ - #define MODE_00 0x00000000 #define MODE_01 0x04000000 #define MODE_10 0x08000000 @@ -322,6 +320,7 @@ struct denali_nand_info { void *buf; dma_addr_t dma_addr; + int dma_avail; int devnum; /* represent how many nands connected */ int bbtskipbytes; int max_banks; From patchwork Wed Jun 7 11:52:29 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103242 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1715319obh; Wed, 7 Jun 2017 04:57:07 -0700 (PDT) X-Received: by 10.84.238.139 with SMTP id v11mr27939292plk.182.1496836627516; Wed, 07 Jun 2017 04:57:07 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836627; cv=none; d=google.com; s=arc-20160816; b=ux48uVWdkVhnc/knAjWRqUHdKgrDrqs9Trjn24bULwU2CbAH98onjRLuZkCJL7MbCi De897L3RJiiXn850KYkMbA4YcAhyauO2g7kj9fmCiQJegQejkxULq9ob9Q0AKKlAw92u lRThFffPb1oStGm/nRJr89qc0Pg1H8cx/lj05RnB+/nulv4KUjwPjl4f9KMbigQZyaOh 9lNWnRg0tY4iFMUolWl9YmyMxoWPJx1ZBud56eylGpAlwCRDNdpUAWMBJM6okjBF4Au6 wt719GUXF6dykHGKNclB+t/htuhA2DYtBezzOcg4McAsSe+gxShFJOZrA9WOlPjVrLAc 94Gg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=0FwFRQi7EAKQabrKJ5ddlEfq5+0GR43mgsG5+Kxm0kw=; b=iCdJ8rm64M7/b2+6p5SctoXq1RG2VvxqdNStiiQBrUg1OSfVDuNYuSvdUowf5U/m/S 34gryiqfguRM3Ybpj3uTZMiiEvO3cHlZyt2kEa+j/jjMp+q2eeuUFAwBg3Js5HKBFEXC nkp0Hdb9wql1wDU8bts0QhIFCfGgHM4L3pAcZHXea741BWFmdLy8xzqMS5pJ5wQ1Uvk6 XFagPpwF0yCD2PNSsJOUJdONnvUmrRI7tXYmwPknvZ+COBR09lolviOtMYnSfKex39Qb RAunT/p2z+QU4tOZWTjYxrMj0TlK8UorgJwEyKT78An5yL/LrUuvTX9njCGRxO5WlzkY ZwAQ== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l1si1540778pld.70.2017.06.07.04.57.07; Wed, 07 Jun 2017 04:57:07 -0700 (PDT) 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 S1751840AbdFGL4t (ORCPT + 25 others); Wed, 7 Jun 2017 07:56:49 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42698 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751666AbdFGLzb (ORCPT ); Wed, 7 Jun 2017 07:55:31 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZj014276; Wed, 7 Jun 2017 20:53:09 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZj014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836390; bh=0FwFRQi7EAKQabrKJ5ddlEfq5+0GR43mgsG5+Kxm0kw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YX+L4IqMaTQWMDppAh6QfkyG79CTRZK/PyTuX/RGcAkc5A4gJFnvA18ztm1uGcU6l NL1MyhLi7HkbHTYaQBZ4RMqN0GsQvOjU5zrJTxt7wTWmiKrAUardY3UWKWUHsR6Icd OgPb3rhJKBOhbgUtLaJl5vcj7AAekWiTEHVJQsAVFb4+fC25arbVKGIsNl5NnIR7wi 2eEOEDfRZmrEnWL3db6yuF4P6Y+/qb7kJPp3NKZ4c2RkZp30YaaWDvg3GCt2ic4Jyk GGeNu4mqfXgKvxOAE0ukOlVYpIab308seXdc8xorgCgCaes2vbxE6HekdmSgt59l1E nRCdZ8vVP5MsA== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 20/23] mtd: nand: denali: support hardware-assisted erased page detection Date: Wed, 7 Jun 2017 20:52:29 +0900 Message-Id: <1496836352-8016-21-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 Recent versions of this IP support automatic erased page detection. If an erased page is detected on reads, the controller does not set INTR__ECC_UNCOR_ERR, but INTR__ERASED_PAGE. The detection of erased page is based on the number of zeros in a page; if the number of zeros is less than the value in the field ERASED_THRESHOLD, the page is assumed as erased. Please note ERASED_THRESHOLD specifies the number of zeros in a _page_ instead of an ECC chunk. Moreover, the controller does not provide a way to know the actual number of bitflips. Actually, an erased page (all 0xff) is not an ECC correctable pattern on the Denali ECC engine. In other words, there is overlap between the following two: [1] a bit pattern reachable from a valid payload + ECC pattern within ecc.strength bitflips [2] a bit pattern reachable from an erased state (all 0xff) within ecc.strength bitflips So, this feature may intercept ECC correctable patterns, then replace [1] with [2]. After all, this feature can work safely only when ECC_THRESHOLD == 1, i.e. detect erased pages without any bitflips. This should be the case most of the time. If there are some bitflips, the driver will fallback to the software method by using nand_check_erased_ecc_chunk(). Signed-off-by: Masahiro Yamada --- Changes in v5: - Set ECC_THRESHOLD to 1 Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 3 ++- drivers/mtd/nand/denali.h | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index dcadf9655d7a..90c702b9f14c 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1446,7 +1446,8 @@ int denali_init(struct denali_nand_info *denali) "chosen ECC settings: step=%d, strength=%d, bytes=%d\n", chip->ecc.size, chip->ecc.strength, chip->ecc.bytes); - iowrite32(chip->ecc.strength, denali->flash_reg + ECC_CORRECTION); + iowrite32(MAKE_ECC_CORRECTION(chip->ecc.strength, 1), + denali->flash_reg + ECC_CORRECTION); iowrite32(mtd->erasesize / mtd->writesize, denali->flash_reg + PAGES_PER_BLOCK); iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0, diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index f5da52f09e34..657a794af695 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -110,6 +110,10 @@ #define ECC_CORRECTION 0x1b0 #define ECC_CORRECTION__VALUE GENMASK(4, 0) +#define ECC_CORRECTION__ERASE_THRESHOLD GENMASK(31, 16) +#define MAKE_ECC_CORRECTION(val, thresh) \ + (((val) & (ECC_CORRECTION__VALUE)) | \ + (((thresh) << 16) & (ECC_CORRECTION__ERASE_THRESHOLD))) #define READ_MODE 0x1c0 #define READ_MODE__VALUE GENMASK(3, 0) @@ -233,6 +237,7 @@ #define INTR__RST_COMP BIT(13) #define INTR__PIPE_CMD_ERR BIT(14) #define INTR__PAGE_XFER_INC BIT(15) +#define INTR__ERASED_PAGE BIT(16) #define PAGE_CNT(bank) (0x430 + (bank) * 0x50) #define ERR_PAGE_ADDR(bank) (0x440 + (bank) * 0x50) From patchwork Wed Jun 7 11:52:30 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103239 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1714948obh; Wed, 7 Jun 2017 04:56:06 -0700 (PDT) X-Received: by 10.84.215.148 with SMTP id l20mr3313244pli.79.1496836566022; Wed, 07 Jun 2017 04:56:06 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836566; cv=none; d=google.com; s=arc-20160816; b=fAkwkmIE18K72tLRNXp5ihIm6KaT5Iwp2RzCjzSpES9P1rrYXeSX4dpWZZpMXlN2jH SrR9ZwqBSGX2XRgNQ7EW5gpFwS2VgtlDTlGtSt6j4lZV0q48Xdyuc2eCNFy6Nbb5YrkK OJgNSShLcPY9AQ1IGnRhXYJD4uvNv7qP97U0UuZe0MbHKgIKkkMiwED4wvXTaC5dIdWY 15pSQoHaBo091VC3j4lx6KnsBmzBSTF4h3h+B5avFUxsKX0VBxaiXehkn4MYTzqMN1ud HYlyDbQ4hvMaI3T1SdyF65xjntIs6eJg6vhbR0QCxR19fLC90pvKwU2cq19Ovly6eU71 6pog== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=1DzbAkNew2LV6VLBZ02RZlu73kX1MqAtvBmplDn4Vic=; b=VZ0Q/hO3qpc5rxb0k6FT1uwXoAnK86xZvbXkfBXCG1GqeQy15S/E0aYiHzcaSXAn7H /RORaD+FydDCAXYWu9UpVxzoUJXg2v3rmwuYN4SXvDc2rVqmf0TYK/BsZydX8BgkiSHZ 1NKBRL4ccpLQVyzjJUYnOFb2dhsruaeCdk06LbZuem41pFK7peRr5EgO63eSWrLcLeEW EzVDMe3I9GOw0PZ1D0dq76+FAQIXLK1Xqiwf/3Dm0aJ2/G+oLTWlr5rV6x2PRApP3K6L WKWv1alhgT0CDx5HtlIbyCakvxFOwt7afyIX7RSnp9wQvZpQbzEb2ZV7UKIiZaGu6y+u AvjA== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m24si1622370pfa.242.2017.06.07.04.56.05; Wed, 07 Jun 2017 04:56:06 -0700 (PDT) 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 S1751788AbdFGLzt (ORCPT + 25 others); Wed, 7 Jun 2017 07:55:49 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42713 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751758AbdFGLzr (ORCPT ); Wed, 7 Jun 2017 07:55:47 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZk014276; Wed, 7 Jun 2017 20:53:10 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZk014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836391; bh=1DzbAkNew2LV6VLBZ02RZlu73kX1MqAtvBmplDn4Vic=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=1nWV9KVu0v5+bOuNwjzf4QxotFPNT/FvmwcixDx4ZuKhPdysICheV85UOrUhLiH2r cOPwc8T8k1CTRUVyOPZoh9nnKgMO+ECEy2ZPWmNN6RRTuRWsed0unORxZ9p2Dag165 ELGMixB3ENtERSRGxQgpCyU3jtdAqxROxLvxXWI0AiSFAFQjfrp93LKE/wEFtHfb67 aN4T0t2ALMch0OcOc6QV/Xw3Zc0wXg8k4TA3BIEu7D8xYb0leTA2lcSv3nc+aOrIyT jpjxssc6CDsi9S/dCkWJQCeQ3uRmj/5szfxLVhBS+ofr4pRptkKvAyQhwer0dl7MAO Jz7AQWvQncXZA== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 21/23] mtd: nand: denali: skip driver internal bounce buffer when possible Date: Wed, 7 Jun 2017 20:52:30 +0900 Message-Id: <1496836352-8016-22-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 For ecc->read_page() and ecc->write_page(), it is possible to call dma_map_single() against the given buffer. This bypasses the driver internal bounce buffer and save the memcpy(). Signed-off-by: Masahiro Yamada --- Changes in v5: None Changes in v4: - Remove dma_unmap_single() from denali_remove() Changes in v3: - Set chip->buf_align to 16 Changes in v2: - Newly added drivers/mtd/nand/denali.c | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 90c702b9f14c..963638693850 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -643,12 +643,16 @@ static int denali_pio_xfer(struct denali_nand_info *denali, void *buf, static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, size_t size, int page, int raw, int write) { - dma_addr_t dma_addr = denali->dma_addr; + dma_addr_t dma_addr; uint32_t irq_mask, irq_status, ecc_err_mask; enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE; int ret = 0; - dma_sync_single_for_device(denali->dev, dma_addr, size, dir); + dma_addr = dma_map_single(denali->dev, buf, size, dir); + if (dma_mapping_error(denali->dev, dma_addr)) { + dev_dbg(denali->dev, "Failed to DMA-map buffer. Trying PIO.\n"); + return denali_pio_xfer(denali, buf, size, page, raw, write); + } if (write) { irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL; @@ -674,7 +678,7 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, ret = -EBADMSG; denali_enable_dma(denali, false); - dma_sync_single_for_cpu(denali->dev, dma_addr, size, dir); + dma_unmap_single(denali->dev, dma_addr, size, dir); return ret; } @@ -857,12 +861,10 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, int stat = 0; int ret; - ret = denali_data_xfer(denali, denali->buf, mtd->writesize, page, 0, 0); + ret = denali_data_xfer(denali, buf, mtd->writesize, page, 0, 0); if (ret && ret != -EBADMSG) return ret; - memcpy(buf, denali->buf, mtd->writesize); - if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) stat = denali_hw_ecc_fixup(mtd, denali, &uncor_ecc_flags); else if (ret == -EBADMSG) @@ -966,10 +968,8 @@ static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, { struct denali_nand_info *denali = mtd_to_denali(mtd); - memcpy(denali->buf, buf, mtd->writesize); - - return denali_data_xfer(denali, denali->buf, mtd->writesize, page, - 0, 1); + return denali_data_xfer(denali, (void *)buf, mtd->writesize, + page, 0, 1); } static void denali_select_chip(struct mtd_info *mtd, int chip) @@ -1408,14 +1408,8 @@ int denali_init(struct denali_nand_info *denali) } if (denali->dma_avail) { - denali->dma_addr = dma_map_single(denali->dev, denali->buf, - mtd->writesize + mtd->oobsize, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(denali->dev, denali->dma_addr)) { - dev_info(denali->dev, - "Failed to map DMA buffer. Disabling DMA.\n"); - denali->dma_avail = 0; - }; + chip->options |= NAND_USE_BOUNCE_BUFFER; + chip->buf_align = 16; } /* @@ -1505,16 +1499,8 @@ EXPORT_SYMBOL(denali_init); void denali_remove(struct denali_nand_info *denali) { struct mtd_info *mtd = nand_to_mtd(&denali->nand); - /* - * Pre-compute DMA buffer size to avoid any problems in case - * nand_release() ever changes in a way that mtd->writesize and - * mtd->oobsize are not reliable after this call. - */ - int bufsize = mtd->writesize + mtd->oobsize; nand_release(mtd); denali_disable_irq(denali); - dma_unmap_single(denali->dev, denali->dma_addr, bufsize, - DMA_BIDIRECTIONAL); } EXPORT_SYMBOL(denali_remove); From patchwork Wed Jun 7 11:52:31 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103241 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1715075obh; Wed, 7 Jun 2017 04:56:24 -0700 (PDT) X-Received: by 10.84.208.102 with SMTP id f35mr23783437plh.92.1496836584554; Wed, 07 Jun 2017 04:56:24 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836584; cv=none; d=google.com; s=arc-20160816; b=T+3qA5691jmT0ShW1F4U31ozKLKYvSFx5lNs66ldwhuF2Wm3YSuePd178Qb83pnIGZ 59Z7lLoCiwnzvc8ORxnqCvU136mgICuo7NtLD/g8p6ty1R6EHjfZwNhy1elH/lnHQp3t 92TIs4Q/kvr0HfkveKE5x5f2SYPzVaJ2XbDvyUVaV3sIYZhYlkhEcgtX9JOlZDCu8uEV JfjF11G/nE4OsureqcFtNg9tE/LPqGtCHb/U69k5g8/4Ml7U0T19whOZkSM1Rx1Ll/1l OGvsBcHOZdWMs1DupPwXk2TsR2kpKO52MKqgqHFHMPFU2+vyHWfLvAxvk9soxf1Rxqsd YMaA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=IGtzcXChHR8L6XB3tbuR6nceT3T4zeLYQMP519Y7uuk=; b=d8j2gtsP8Een17ZU3XzBeaqYHNHD7RNA3XWScjHofPy7eRFV5a5TmNxMCnsll16oM0 +E7mUHC1JZ3E4ta6EywqdcVPcSTOEqs0lzc8ZB6lHTX+9vbqVarqatah53xuMdOBUdIb Esm3EOJ/AOikeeKkt8ifsDBWb18gb+FpaZBw1b+USx9ceUEmvxva25meQamrxdbufWMe nJBXIc3fgcKeyFAENHeUJB813/DQELknRHksK0CeiTHViOeeDsA7KNRHG3/a7J126yo/ sEf6B85tPi/li2Bsm2K9kWGPrv8sDGbHCEsOZY5HWtKJo5BOPjIEbBFdZTrypZi8QzZA lKMA== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id g77si1675645pfb.41.2017.06.07.04.56.24; Wed, 07 Jun 2017 04:56:24 -0700 (PDT) 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 S1751816AbdFGL4G (ORCPT + 25 others); Wed, 7 Jun 2017 07:56:06 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:43591 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751457AbdFGL4D (ORCPT ); Wed, 7 Jun 2017 07:56:03 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZl014276; Wed, 7 Jun 2017 20:53:12 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZl014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836393; bh=IGtzcXChHR8L6XB3tbuR6nceT3T4zeLYQMP519Y7uuk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bqulELfkqsM39nc6r7tthRZInZDRwiBvHqIgKwJpNaTwIb6JnBtIfK2tzDsZDM0tB 5TZjl99rwOVKmQkkwhdTQEL4fgt8XAcQOOXXSkPr7KjTilQVZognkq4lEcg9kf0psb rbi5oUhC0VswTQ3yK8mw8IrauuHgJcqJRkUneaNjaF8fuqkSCoxjCAjO+DSOz0tlwr 8qcySsjU6B7qZu1+wyg+kPAXYqpNOSZsKrbGuAQrTR5oV661bnzwmp5jpMT8sa7PNj SMMIa1CaTU4dXU7Gxq4p8ZX7Mf9U8Vlw4hKSzBdT90+Bj7Z4C76qkcN0igwXhCssXn 3l7WsVhUdQBKA== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Russell King , Lars-Peter Clausen , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 22/23] mtd: nand: denali: use non-managed kmalloc() for DMA buffer Date: Wed, 7 Jun 2017 20:52:31 +0900 Message-Id: <1496836352-8016-23-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 As Russell and Lars stated in the discussion [1], using devm_k*alloc() with DMA is not a good idea. Let's use kmalloc (not kzalloc because no need for zero-out). Also, allocate the buffer as late as possible because it must be freed for any error that follows. [1] https://lkml.org/lkml/2017/3/8/693 Signed-off-by: Masahiro Yamada Cc: Russell King Cc: Lars-Peter Clausen Acked-by: Robin Murphy --- Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 963638693850..904f859e19b6 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "denali.h" @@ -1386,13 +1387,6 @@ int denali_init(struct denali_nand_info *denali) if (ret) goto disable_irq; - denali->buf = devm_kzalloc(denali->dev, mtd->writesize + mtd->oobsize, - GFP_KERNEL); - if (!denali->buf) { - ret = -ENOMEM; - goto disable_irq; - } - if (ioread32(denali->flash_reg + FEATURES) & FEATURES__DMA) denali->dma_avail = 1; @@ -1477,17 +1471,30 @@ int denali_init(struct denali_nand_info *denali) if (ret) goto disable_irq; + /* + * This buffer is DMA-mapped by denali_{read,write}_page_raw. Do not + * use devm_kmalloc() because the memory allocated by devm_ does not + * guarantee DMA-safe alignment. + */ + denali->buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); + if (!denali->buf) { + ret = -ENOMEM; + goto disable_irq; + } + ret = nand_scan_tail(mtd); if (ret) - goto disable_irq; + goto free_buf; ret = mtd_device_register(mtd, NULL, 0); if (ret) { dev_err(denali->dev, "Failed to register MTD: %d\n", ret); - goto disable_irq; + goto free_buf; } return 0; +free_buf: + kfree(denali->buf); disable_irq: denali_disable_irq(denali); @@ -1501,6 +1508,7 @@ void denali_remove(struct denali_nand_info *denali) struct mtd_info *mtd = nand_to_mtd(&denali->nand); nand_release(mtd); + kfree(denali->buf); denali_disable_irq(denali); } EXPORT_SYMBOL(denali_remove); From patchwork Wed Jun 7 11:52:32 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103234 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1714804obh; Wed, 7 Jun 2017 04:55:42 -0700 (PDT) X-Received: by 10.84.237.9 with SMTP id s9mr27177355plk.255.1496836542500; Wed, 07 Jun 2017 04:55:42 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496836542; cv=none; d=google.com; s=arc-20160816; b=brB2egr3wj/T1mNV2reb6mUYSR9nWwNDOaESaK+CrWMUuowbEVRVcZodmraIUcYKRo dDAagw5j0TKwqz5+5q6DBwwA+OA4NM/MOU2t07ezaAvMziU6iHMBrfZPJs3Nbqj4LVCD j7YRHWKyw08TCO9xGoh3HmBetm0ZNOHLgyv4JRJ/26Otdqpo9VHEByiYxiOrT7Yan5v6 njlqoAArgF8Dz+XEkGewufdoRDjbZeWYaM54wkTbNadkrsdoH4VX5AYslaJ3KTTKWxS9 6mvXqPhG5SNHJFLXvZK22zgw2nYvDJixfAltCWc++l1sNRnH3NyjzrMWZZX5hxnaTpd2 taHA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=yUEF1Bi2JCjOEu2HXa97CPrt7xX5wVWrvRlJrmNsWlk=; b=lMNoLvmmsbBsUict0dqyr+wZ0EWjrY0TlRN35Y3h6vrhc3tFI8diYbKnfXK6TnmOEj fygGCJM2mmrA4C181S3yZNLGFAZDCtZ4U+XOs2DBYmz4Ghw/DksjSFTusgY/+xx/aaZg F9adjKVlIkZNdInbHi98o3PL6qsjv7I9elBAAzvsbYeK5cU36xZJ9xqZUdq9Ia+mQIbi y1IvsAVQlz/FHURsJ5Fr++Qi1gFMMmxo8ZNcDLvXGN2ICb8d2gLWi0nqm+4/KgizbqY1 0FM8heeXFeP3DObWym4h6YIitkDphZGFlcdRGRJoEuBl56JZrHc4CHeyDmcNgy/1pJyP RdfA== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id e186si1569105pgc.163.2017.06.07.04.55.42; Wed, 07 Jun 2017 04:55:42 -0700 (PDT) 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 S1751615AbdFGLz1 (ORCPT + 25 others); Wed, 7 Jun 2017 07:55:27 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:42432 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751511AbdFGLzW (ORCPT ); Wed, 7 Jun 2017 07:55:22 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-10.nifty.com with ESMTP id v57BqjZm014276; Wed, 7 Jun 2017 20:53:13 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v57BqjZm014276 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496836394; bh=yUEF1Bi2JCjOEu2HXa97CPrt7xX5wVWrvRlJrmNsWlk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rMrE/3kLTD/sCIxaP+zG4+ACafhsI2ncxNOeNAJ+/C8JW6nwmL/lrmyLDWf5R375v 689GKgHPml2hP0N3tEy662K4T6aT0Al1XkS8ZWoLSvzU7aSP0+0e5e4Z4kPpHULaLH KHzhLSmU9OecYdoqLxuFf0dyW2dZzCMqwG5ZjiCyJaxETUMIdWY/j1TuEevb3UtT0S 5RP+kR3eOn4CpJ8244lci9teCGN3sMXi2t4o5a9xnzRcsR24zdkWi/uNZVt6JAI7E6 cp0SbIAM9gC/cUMwyXISUhwwL2/v3+OtF4zwKaqPH6WKcnw7vfYdfa4FxbuehfqzMX Y5LoODgWC6k5Q== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v5 23/23] mtd: nand: denali: enable bad block table scan Date: Wed, 7 Jun 2017 20:52:32 +0900 Message-Id: <1496836352-8016-24-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496836352-8016-1-git-send-email-yamada.masahiro@socionext.com> References: <1496836352-8016-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 Now this driver is ready to remove NAND_SKIP_BBTSCAN. The BBT descriptors in denali.c are equivalent to the ones in nand_bbt.c. There is no need to duplicate the equivalent structures. The with-oob decriptors do not work for this driver anyway. The bbt_pattern (offs = 8) and the version (veroffs = 12) area overlaps the ECC area. Set NAND_BBT_NO_OOB flag to use the no_oob variant of the BBT descriptors. Signed-off-by: Masahiro Yamada --- Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 904f859e19b6..43006c506a6b 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1247,29 +1247,6 @@ static const struct mtd_ooblayout_ops denali_ooblayout_ops = { .free = denali_ooblayout_free, }; -static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; -static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; - -static struct nand_bbt_descr bbt_main_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE - | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 8, - .len = 4, - .veroffs = 12, - .maxblocks = 4, - .pattern = bbt_pattern, -}; - -static struct nand_bbt_descr bbt_mirror_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE - | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 8, - .len = 4, - .veroffs = 12, - .maxblocks = 4, - .pattern = mirror_pattern, -}; - /* initialize driver data structures */ static void denali_drv_init(struct denali_nand_info *denali) { @@ -1412,13 +1389,9 @@ int denali_init(struct denali_nand_info *denali) * bad block management. */ - /* Bad block management */ - chip->bbt_td = &bbt_main_descr; - chip->bbt_md = &bbt_mirror_descr; - - /* skip the scan for now until we have OOB read and write support */ chip->bbt_options |= NAND_BBT_USE_FLASH; - chip->options |= NAND_SKIP_BBTSCAN; + chip->bbt_options |= NAND_BBT_NO_OOB; + chip->ecc.mode = NAND_ECC_HW_SYNDROME; /* no subpage writes on denali */