From patchwork Tue Jun 13 05:03:54 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103694 Delivered-To: patch@linaro.org Received: by 10.140.91.77 with SMTP id y71csp236037qgd; Mon, 12 Jun 2017 22:07:16 -0700 (PDT) X-Received: by 10.98.220.193 with SMTP id c62mr54645628pfl.140.1497330436330; Mon, 12 Jun 2017 22:07:16 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1497330436; cv=none; d=google.com; s=arc-20160816; b=k1mMHY6kPrDXhmIr9CqeKfCSRZKrSvPo/faKndeJvDxU+dTwueFZT0IdoiyGjLsmDy dJ0cpM3qQxP6fpaQbAA4bPabT3l51emYvxZ7ZB1S19A0fr7zdQpAXmtVWfQkA5sFyRM7 arNLspbwbj9COtxL038sjIZC/Tsrxl7GaqSjP7ldsVjoJJYOfrScLzsfCj+x52xR2TWw qiD7wJs5o+Bi0G3RG4Xi4kGakQSU3p+BxZXBHgyl0SvZ2QQ+fusm7v8dbPsMl5D9V9VJ RNyz5UgcCedRWDF1Yj2D3X5tX7AoQ1pLbuGmi6/EPOxNCgevLtsbrvEMlo7Bc8z+V++8 oheg== 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=M9NjZTP1c+EM0BiTqQ2i6FmXVV/MtM3btNdhU1qdlGU=; b=M7t0DhmqVcOqia3z86G27l2DGxiNzjZsX7uhD0Emj5b2sf81pWhK2ExDCQYMpeiMoe 8nj0YorhZS0xbztV4g3WiuD94qJ7sga7y8FHW5uQ0CobdPG/3Hq4Fc2XSruxQoSroDlF biFJn7d1PbNZdJttqZg/TDvJrJGyojfPBs4pC0YFFAGBfgEH2pujeE14D/3qYOTjPc/h jKXANr3rpxyKvZfRiJerXnCLT1l7d/tgEp0AwgPy3IBlgLlfH6oU0WomY4kYff/FczWb KrgaFFweAHdp4X2N8xBUoF/+p9KsNWqLEmYmeUZRbalDocwQcZU5phyd88BNHb3/o580 7NjQ== 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 a3si8423410pld.102.2017.06.12.22.07.16; Mon, 12 Jun 2017 22:07: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 S1752216AbdFMFGz (ORCPT + 25 others); Tue, 13 Jun 2017 01:06:55 -0400 Received: from conuserg-09.nifty.com ([210.131.2.76]:46732 "EHLO conuserg-09.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752183AbdFMFGx (ORCPT ); Tue, 13 Jun 2017 01:06:53 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-09.nifty.com with ESMTP id v5D54ENg023096; Tue, 13 Jun 2017 14:04:17 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-09.nifty.com v5D54ENg023096 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1497330258; bh=M9NjZTP1c+EM0BiTqQ2i6FmXVV/MtM3btNdhU1qdlGU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fm4NRBuJO37HlAacFXtEpg3omyiU4ppyvlvtQev+SDemrcM2cZLzxkjim2GtXee60 FLngAHyZtHvxeVEN2Z0GIKIh/oQDVVW+y32DeXgbWt3xzs4Y0znhp/2AtDXXQ0ttrq 27HMbBk//yEw4RnUk8sslQ8zOoUZJ0HUIEnz773jMUsgzMHcnMaoqBFg70w+cr+hML KlaLxoXpWVNK0PdUOCufSPEKP0lJpeJeJtTd8YX4jJIBR7QVNb2T7Ov/Gg9bLdJO7I ar/vTB7kBDqE9JGYMvzNbNeqo4+FfBdEilOM7lqK+LyFK1CARgEnKU/z8/OoUGfIwk k6clnxScNJwLw== 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 v6 02/18] mtd: nand: denali: remove unneeded find_valid_banks() Date: Tue, 13 Jun 2017 14:03:54 +0900 Message-Id: <1497330250-17348-3-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1497330250-17348-1-git-send-email-yamada.masahiro@socionext.com> References: <1497330250-17348-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 v6: None 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 7133a33b4ad3..122df4c6126d 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 Tue Jun 13 05:03:55 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103702 Delivered-To: patch@linaro.org Received: by 10.140.91.77 with SMTP id y71csp236602qgd; Mon, 12 Jun 2017 22:09:12 -0700 (PDT) X-Received: by 10.98.50.129 with SMTP id y123mr59167291pfy.53.1497330552100; Mon, 12 Jun 2017 22:09:12 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1497330552; cv=none; d=google.com; s=arc-20160816; b=ASTuebHdeV3vTJvN0A/Gsrut1gOOLlOiLbQ+Q8uV4LBY+mLIrBFfTyA5MP6uJM4Y4I ORGhpIUBV4U0E98jCTye/OhqybhDYwDjT6sFYgSOxwNleiS88CiW8mlOiTprQTZ0u/vx 2vMP71w0kHu1Fh7r8CNfQvJSB6WQaQaw2ddb+bVvvMOQlENknlDGimWTzehJGGLo6vYt hXT68TN2UkHzJFLP+1uOzQAPbknSVBuCt1Aw4dRDV1X1+IQz1dWogXEEI8rlW3pblz6E rEULBHOVad/MVa47uVDhBWhEXCUI7iQYSdHRAhcmEPOUslInqsS2TcSPkKORaP/ql/vt GB/A== 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=VnRlsMeHSa4piNeoUSyIfnn5IJqQ5NYJ+ezv8eAwvL8=; b=R1VufVZ4qleq12sgfVgrNmQQ/thJNfp4XWo1Kk8naXux2xdjFDVLgx5G4crpyRU/rb LXMcxXrxFrZT6ROvK8OnAnxo1vBezfyLd9VuwqrwYQoL1+kZXk0DVFuYG9zCFMbwiBcC OZFwNWofCYFS1S9DWFVfwZ30tFFQtuaYJP9waBniGTod20CwONDPGIH5InOSPMWr+jZl qh50TZJsDY4EsB8xxdWAeE9JchnJGVFsvsXQe4mAHsE2qTtLAWRKIRoC+TpNDxFaEhJ5 zImQXkCIYqiMmpvtwwA2f/aTdY6GhEbE6opYn5s8cdcTI+k+ngwBZjyvtKRZK7+EcetH ylpg== 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 n20si594026pgf.161.2017.06.12.22.09.11; Mon, 12 Jun 2017 22:09:12 -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 S1752596AbdFMFIw (ORCPT + 25 others); Tue, 13 Jun 2017 01:08:52 -0400 Received: from conuserg-09.nifty.com ([210.131.2.76]:46800 "EHLO conuserg-09.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752192AbdFMFGz (ORCPT ); Tue, 13 Jun 2017 01:06:55 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-09.nifty.com with ESMTP id v5D54ENh023096; Tue, 13 Jun 2017 14:04:18 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-09.nifty.com v5D54ENh023096 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1497330259; bh=VnRlsMeHSa4piNeoUSyIfnn5IJqQ5NYJ+ezv8eAwvL8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=z9MMRCj2+3ZbgVQya8D3pqco6dzd8DK2qzi7p4cQo4ag5c+ItMoLu5mRlobULQppd rywQFET7FJlFMuZ0rSgX/kvMFM3Nps7Z8z8usPfnJVCu08ySBpZifjIOlpGier7oPT EHBe27jKNwBih3Yi9/rDcIHIG4RQhFZttYOBdIKCpogNbcmT9hLJ7q9fC2YhEN7Hsu skepZetdSx6AyqZs+g1AbID3JBkoroYU0SjFDMWdUlR1SUNkYLfiSEqxE5n9WuwBGO i/yQxobWWsv1Ttq89y0VPKVs/OXMINFEg5MjHibS5JXO3hD0d6ttXm3fkreLMNbVDW KGZFlmYzYN31Q== 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 v6 03/18] mtd: nand: denali: handle timing parameters by setup_data_interface() Date: Tue, 13 Jun 2017 14:03:55 +0900 Message-Id: <1497330250-17348-4-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1497330250-17348-1-git-send-email-yamada.masahiro@socionext.com> References: <1497330250-17348-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 v6: - Rebase on commit 104e442a67cfba4d0cc982384761befb917fb6a1 (mtd: nand: Pass the CS line to ->setup_data_interface() ) Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 345 +++++++++++++++--------------------------- drivers/mtd/nand/denali.h | 26 ++-- drivers/mtd/nand/denali_dt.c | 3 +- drivers/mtd/nand/denali_pci.c | 6 +- 4 files changed, 139 insertions(+), 241 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 122df4c6126d..ca2b6b8850ba 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,10 +52,12 @@ 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. + * 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 CEIL_DIV(X, Y) (((X)%(Y)) ? ((X)/(Y)+1) : ((X)/(Y))) +#define DENALI_CLK_X_MULT 6 /* * this macro allows us to convert from an MTD structure to our own @@ -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,121 @@ 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, int chipnr, + const struct nand_data_interface *conf) +{ + 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 (chipnr == NAND_DATA_IFACE_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 +1152,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 +1326,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); @@ -1460,6 +1359,10 @@ int denali_init(struct denali_nand_info *denali) chip->onfi_set_features = nand_onfi_get_set_features_notsupp; chip->onfi_get_features = nand_onfi_get_set_features_notsupp; + /* 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 * this is the first stage in a two step process to register 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 Tue Jun 13 05:04:00 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103690 Delivered-To: patch@linaro.org Received: by 10.140.91.77 with SMTP id y71csp235915qgd; Mon, 12 Jun 2017 22:06:54 -0700 (PDT) X-Received: by 10.98.2.151 with SMTP id 145mr18123753pfc.52.1497330414081; Mon, 12 Jun 2017 22:06:54 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1497330414; cv=none; d=google.com; s=arc-20160816; b=miZn33RMj3hO3/XaLiMQMXaztoVNAVK5Mmq3fmdmRvveBPbpQpQ5xYLHyHT6YziIKf f+z7fZ1YDXXLKPeME1gC46jfZ31SW6Gytd7/HG9De3uzJrmslSZoAdnbSGke8czASUCd YeU9uOkVFokVprW/QyeCdUfn3KbmB5OW7JscqRohUBFmP+CCGMRlHjFJzXHR9yTqERpZ WCTsRR3cC8FSzoRTc121reQLhq6GkhjmbPUbxYZc+rJcX82b0kjjfxpuG6Ztz0KFtgFj wg3Mkpdh5/fB7ZWckAoHKGtFlpdPnOj/yjgsHZJ9WruRdYS0wpVXHgiSeCOLCaaR+GIB FBxw== 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=r/kifhc2gMfg1QVb0fNcHrZok4+Z68NvnFhx42jTy3M=; b=qhofRygrgNTThGuFxM2GvRMYq9EN7b59TeDI8lpn08qJ/qrM78JxBIvuYhKBWm8RJr AUsbHf3NEGDX7z+H/nshNF2GDmsAJHVYlSI1v1xlPTVBSeW0l+3cccyxdOY7jE7HfnjS /DucfRcWiRh36sCHe2B2SUswMrSrVyHoEapdRaZhFeplw/a5gU/b2RUB0qMjsRwoZCMe yhd+DKmcl8uAWg99zVAIGbjx6Fc5DRwkOQdCK5cBgl9bHipbD5zs2X3pn+ConPTSOy4g LeTqWM/MKpXFJh3XOFZ657WtfUrFYM6znUBppSPASc0MEPXBVaf//RhvIfPacS7c8IQ8 qT5Q== 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 z129si576391pgz.402.2017.06.12.22.06.53; Mon, 12 Jun 2017 22:06:54 -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 S1752148AbdFMFGr (ORCPT + 25 others); Tue, 13 Jun 2017 01:06:47 -0400 Received: from conuserg-09.nifty.com ([210.131.2.76]:46427 "EHLO conuserg-09.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752003AbdFMFGo (ORCPT ); Tue, 13 Jun 2017 01:06:44 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-09.nifty.com with ESMTP id v5D54ENm023096; Tue, 13 Jun 2017 14:04:24 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-09.nifty.com v5D54ENm023096 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1497330265; bh=r/kifhc2gMfg1QVb0fNcHrZok4+Z68NvnFhx42jTy3M=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=NOIbm6bmJKb3t2uPizXULpinOChcLSZa4vgaW6j0h7mmy1IAd0Zva81b3M+D8Zpro qiBaIzgo5RCVvMThdqkB5cvnOxPcWkVQxyFsm++JojASOD5Kx+SLkmI207MS8nqG9k mbqClILn+1hAnx7bFfvR8qDUd+QJrG43Zo2GFv7RTyfehKpvNh/E3tA16eXpQoKQBB ciPuQLsnplMeUHRj1eydKJjibqktUtwy1BKeXIiQd1iHidDtepA/FdgSCiTPZSz6vH d2h15ynOzQokdnBFNkpIfEgZaM4Tak1q86oaGdRPqQOQ3qysAiTgQSXDjgXSe8pg7I bG7GUVT9yCiVQ== 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 v6 08/18] mtd: nand: denali: fix bank reset function to detect the number of chips Date: Tue, 13 Jun 2017 14:04:00 +0900 Message-Id: <1497330250-17348-9-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1497330250-17348-1-git-send-email-yamada.masahiro@socionext.com> References: <1497330250-17348-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 v6: None 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 09a14fafa967..61a2ee9fb367 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. @@ -998,7 +971,28 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr, 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) { /* @@ -1018,7 +1012,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 Tue Jun 13 05:04:01 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103703 Delivered-To: patch@linaro.org Received: by 10.140.91.77 with SMTP id y71csp236704qgd; Mon, 12 Jun 2017 22:09:35 -0700 (PDT) X-Received: by 10.99.44.68 with SMTP id s65mr50551478pgs.73.1497330574955; Mon, 12 Jun 2017 22:09:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1497330574; cv=none; d=google.com; s=arc-20160816; b=fTSs166sgbDbCzPi1hZ5naw/HSX95k3SLZ4pCkPB/ShI2vdJRHbaJNb4Fonki1DNy6 D0PIafoPd8jhYWwWA8L6kCgv8+9rneed0DlKIuegXiTGyWX4Z79+fleSe3Ji5trglOMY uELxP6CpdWEniQZFl3sZqfT/TkM+S+x+I4JMB7w/IGPMvrxM5mAw8Ze9uWsdM3myu5+7 rPQNkY98w18lTy++JE7H7QGEPehaFht38Q/v1KEBMRwV1nH9BrfCOETwFyInmmpoJiY4 j6KR0VX3iZm6hzd1QEYwCgqD2kvtt7WeyVF6qOtFuHv6V6vmBtsVXs894RIpVvcbC0q4 GoCw== 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=sY4q5YPzgAhvAPo40SABqIMnVg33E9VtBSEIn7mW++c=; b=gEyTWKX4NN2RJf9nIs7cSjnx89AmOwJyBm5P7go8vz/dtaF/waazQjnUlnRxQmUWuq G73O7OSkPBOa/pOZWnCsF1sThlSGbjWvz08EdLd3G5bw2I808p9J3wXYgLDJWsuCiA3Z 4IQqYKTXUc4hhxUJPjzndGHQ14cwH00tPovUZsqfLz8TrNHSs8JmcSgPfZ2wBl98fXfi gtPYhWuxLcF8ZPQSkyQ701Sed9vlR4KpcSCxOW74e4CTVmEQqITtrxnBlLGLMLJ9RN4P R1J/I3xSjiHnOrJqlprilPKRjoC9HlkEYdB4ATDm3jMMcNRZKIa3yj+VomKbXW9bNDxb kJAQ== 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 n20si594026pgf.161.2017.06.12.22.09.34; Mon, 12 Jun 2017 22:09: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 S1752488AbdFMFJc (ORCPT + 25 others); Tue, 13 Jun 2017 01:09:32 -0400 Received: from conuserg-09.nifty.com ([210.131.2.76]:46767 "EHLO conuserg-09.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752187AbdFMFGy (ORCPT ); Tue, 13 Jun 2017 01:06:54 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-09.nifty.com with ESMTP id v5D54ENn023096; Tue, 13 Jun 2017 14:04:25 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-09.nifty.com v5D54ENn023096 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1497330266; bh=sY4q5YPzgAhvAPo40SABqIMnVg33E9VtBSEIn7mW++c=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aQFfC39xooQnIzY5F2JLL81ADpoZyXrYq1ivqKe4yFmR6FmQ88oBBqChH7W3GFw9v STHUiHhJN5MWSOgUbaH77L7GgVUCgFm8Ks56Hwk9mdhcEwKQAhZ7qk9F1sCgcw9+FI zLjIXz3JswHfK96wvKYUsZ/02HLKvDHp6RdAEUiUGYEFDcis1AHK7tM2GUOOqlXzde YcyihEatO2+YhMFjznm0Eb8q9yAgTKBWjkUNHuW59z6L0TFQ2BuGbmmlVWS3dDxflb 2ekwQpfanUeuFfr5UtaHq7dP5CBLZxz+duwf6WjQ744w3V3+KZc0k2UlkydV+BVGXy gQpReAcW6um9A== 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 v6 09/18] mtd: nand: denali: use interrupt instead of polling for bank reset Date: Tue, 13 Jun 2017 14:04:01 +0900 Message-Id: <1497330250-17348-10-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1497330250-17348-1-git-send-email-yamada.masahiro@socionext.com> References: <1497330250-17348-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 v6: None 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 61a2ee9fb367..7ae2fa65d601 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -973,24 +973,25 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr, 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) @@ -1012,7 +1013,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); @@ -1130,9 +1130,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) @@ -1207,6 +1204,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 Tue Jun 13 05:04:03 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103691 Delivered-To: patch@linaro.org Received: by 10.140.91.77 with SMTP id y71csp235919qgd; Mon, 12 Jun 2017 22:06:54 -0700 (PDT) X-Received: by 10.99.167.15 with SMTP id d15mr39625704pgf.42.1497330414696; Mon, 12 Jun 2017 22:06:54 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1497330414; cv=none; d=google.com; s=arc-20160816; b=o8wCX9YJ2S9TauN0/37/PhX3y0ENA/fdQzHgQ4hf9kGCKgwLIXrtpadrbFWTucgBwb WlraihR3yH8l8d6rzqLnNXn3D8lOe9280pGkZwsjljKeJpIqdp9dKIo9H6L4+G1pUd08 Tx1SOJIoXJeahS+kJ8bpEgPmpFYg9Bcay6Zz4t0cWEjVNTncAfe6A2Xz/UQPAMHfrKap MzitJbrjD29nxxGIuSwTw86eV9Uh30X0zPiJsNRQsRNkoA9Jdgj/N3NUpVRXWud8GiUC TNVxzafW82Z29fPO9TqPxOvSNaFPlhoLSnaUgzBykp9pGVuzdADirafQDtwKeVbX7FzN TlCw== 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=Yt0AMPd+HCO2fT2DOGCzPVM86cjM8i+ssx7jX6P7fuw=; b=GJUDXHXP5mOPT1Yg5SfuOqpsZn7FlovGgg+CGVV9ETTBKnR8R7HACHn2dX4E2XQpKt vDk2vHJ3j42hnYBk3J/Ai9XvyooEzx29pMNVuF7syoQ/5xOy19veEdyEtqQWdcTzdBPc wsMzbV8zj0mOeKW1/7nRJJlQbuNgkJAM6RgG0PyW74LgxmYr4M7ni9qWjKD8dcNqiXvB KR2j2w2qH9IDZFQDmx9zeZ94SZi5/GZla6dkiD8Bxs346OaWWTv554Ay/v7VHBIL5L/N OyaZxVeJHJm8wnQNWJWkt931Bodb79zqChgTE3pioez+EIGBdGK5cNM7d0nY6yxlpO+A w3ew== 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 z129si576391pgz.402.2017.06.12.22.06.54; Mon, 12 Jun 2017 22:06:54 -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 S1752181AbdFMFGv (ORCPT + 25 others); Tue, 13 Jun 2017 01:06:51 -0400 Received: from conuserg-09.nifty.com ([210.131.2.76]:46575 "EHLO conuserg-09.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752003AbdFMFGs (ORCPT ); Tue, 13 Jun 2017 01:06:48 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-09.nifty.com with ESMTP id v5D54ENp023096; Tue, 13 Jun 2017 14:04:27 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-09.nifty.com v5D54ENp023096 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1497330268; bh=Yt0AMPd+HCO2fT2DOGCzPVM86cjM8i+ssx7jX6P7fuw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=thv2jKogxRp9FKR6XXJcq3eMQ79WH4ZqW7F9pvVstjQuNy9H2beArKkPariLqF7fk SNWNG8vTlDXRb2gQNqafkLjoW6ws9l9OrLExp6jzpzhnjP61qUsSJ0SN8WluAtL5i7 YLc0+hQDjGp+HjSloSYXwzq7s7iop/58IEXYe2mboI4OTXdiy/ZitBV1IynzyZjpQa 8ZWhQSUQw9vVYGEqvyTS0VJlJsmxG9IV0x3gVuHA9V1tuP7KMXdqXt29kZBkewiDJM G5c/mhi4OmYjjSHvQiLUBOwkXHIDZARwGXIB9SyX5NTV3jcU+zgtnQYV+2IZt7SgFB lt37arukKd2Lg== 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 v6 11/18] mtd: nand: denali: merge struct nand_buf into struct denali_nand_info Date: Tue, 13 Jun 2017 14:04:03 +0900 Message-Id: <1497330250-17348-12-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1497330250-17348-1-git-send-email-yamada.masahiro@socionext.com> References: <1497330250-17348-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 v6: None 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 f2e50c5856f3..caf5ce64b185 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 Tue Jun 13 05:04:04 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103689 Delivered-To: patch@linaro.org Received: by 10.140.91.77 with SMTP id y71csp235913qgd; Mon, 12 Jun 2017 22:06:53 -0700 (PDT) X-Received: by 10.84.201.74 with SMTP id t10mr18097701plh.44.1497330413720; Mon, 12 Jun 2017 22:06:53 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1497330413; cv=none; d=google.com; s=arc-20160816; b=Q6Qsy/oF74t2EDC16uDmZmCMJvVjnnNWLsWlSwnzntqY9TWDmAYpomqD9AjaMqMGv0 H0LR5glvy/AhVidl6YnxlAVXa98TiHdqQmZUytR5G1rUtp+kPv/vEiCTOk0UUs+Jf7Rg PCGpe51xNhTgbFw6ZT5oKwVxkHvBF9ko1NlO/G8CJ49sJjshyd2DxCslwSVkt6Qag+LD IqyRpsOk/anE2l6LuPTl37jQ1lBRWcfj/MHMuJQmcA/TfCYrbv1te8VeNIl45I0tdsRC AXKU+mLtFwhPuxtXwUpCeOo6G1vuNSKdEzEPlNnvJ5SL/ZFxJ0mI9WGqSz/o/da2yPTx pbFQ== 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=KxnXCwCCyluO99DqwT3yrjYvPNaXgp7uyg0qtdhFR+I=; b=yQCUG7X7MdKm24hp8IJ0B2rF6KRKE2STOHbXZL8fNWkbGKMWyruuTdUO5lTSD561Zu +qdHOCMfr00CIN3Ipy/98soBIcLAAXBGcDiElgQ8HqAl51UPwIXqgNziYftMqgVZB7Ov cmfDbFajMyRiLz/SV2kOwuhlPm5QMhgb1XyVzshZjVsUD0fZLegHdaoX5DN1hNuc7zZD GEMOMljU91QgT+V9ZPrR2e+1UKJqIB7oy0++75KvtrCLsUqEzV30rTn5S8pjr3BQLJA6 V58iYCOLEtzSRsNoS4vdSItTIExdEgCZGpLygWuy9RmdOGVrtilfm9sEkRiH6JRnAuwH OQ5g== 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 z129si576391pgz.402.2017.06.12.22.06.53; Mon, 12 Jun 2017 22:06: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 S1752110AbdFMFGq (ORCPT + 25 others); Tue, 13 Jun 2017 01:06:46 -0400 Received: from conuserg-09.nifty.com ([210.131.2.76]:46412 "EHLO conuserg-09.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751921AbdFMFGo (ORCPT ); Tue, 13 Jun 2017 01:06:44 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-09.nifty.com with ESMTP id v5D54ENq023096; Tue, 13 Jun 2017 14:04:28 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-09.nifty.com v5D54ENq023096 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1497330269; bh=KxnXCwCCyluO99DqwT3yrjYvPNaXgp7uyg0qtdhFR+I=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=OarCnkIwudpGPcfbDD58z+2Dhxzn75EFweuro0a04BtMpLFyoG6HED4IVsSkCd4xH jX+qvMG+VEh3N17UKxcoGnju37ZFU9LoR8rtOAahwdghzh01r8U6XBbG4UyLy+uhhz 3v5SMXXYKjtemszELLJnCnFTg7jFB4AudxoI7u0HemhA13wxCQRJi2Cws6FlnSoi2V ANskGxClJ2+pRqAbBcyjsL0/eYJAc0YI3JpdebQwF8QKSiWIz7sngD4X9FbE4mJnqY YlXHXm9pgEqs4kNgym/vKJn0qoyo05YQ1d54mnYAbQcr56mh26I0izyVKSWbltjIn3 aWT2Ab75Njzuw== 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 v6 12/18] mtd: nand: denali: use flag instead of register macro for direction Date: Tue, 13 Jun 2017 14:04:04 +0900 Message-Id: <1497330250-17348-13-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1497330250-17348-1-git-send-email-yamada.masahiro@socionext.com> References: <1497330250-17348-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 v6: - Delete unused DENALI_{READ,WRITE} 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 caf5ce64b185..03b75045d603 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -63,9 +63,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 - /* * this is a helper macro that allows us to * format the bank into the proper bits for the controller @@ -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 Tue Jun 13 05:04:05 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103698 Delivered-To: patch@linaro.org Received: by 10.140.91.77 with SMTP id y71csp236127qgd; Mon, 12 Jun 2017 22:07:35 -0700 (PDT) X-Received: by 10.84.233.141 with SMTP id l13mr61268146plk.298.1497330455367; Mon, 12 Jun 2017 22:07:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1497330455; cv=none; d=google.com; s=arc-20160816; b=t6VRteZGo6JI/z14RSjy100kVnjRChYX5EPuiYQk4TpCoMThOiDYTdSyVTYel+VGLG 4TJIb8NZPz5e7PZW/KnYktFAmzymx84pi5bGaF/GtdRj4x3UhLLE4i+3TC8owATzCW6L pVKpTnQKYaI1yR0MyfI7/atAGfJNAttvZ9k09u0XmiPkVTpJZbTpM7WB3ItjhfGusiTF J5wXg+97fWJ8JW8QlDkZsxsALvhnUNnQPW7lvezZzFlXY3mymHzK+rgYlHmzMj2Q5rv6 jJcJvzU9nDeFjtf76NPz1KJlacWsXbnCwdf4GHEsXPa4aL5zzvBKgMfxw217GkEqExsZ YVzw== 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=5no+bcwV1WpEDcH1xW8DBTRh3iU2l4sS+PpqzhMj7T0=; b=EI22E4hJ9i68Qm1rS7EJbIs2iOZ6yVaDAa8j1/aFWt8iNolYiL1o84ibl/Y5PkWABB RpQc8VOhMiAKGH2FIpdVX2iT3hsWmqkG7EQpGix0ZDEvVW0n16ZAbie2NwUEsye6ghL0 QCU4UZ/Rx6Fwcu5WFTn05NuSaHIL6YrZ2uGIu2MHjqgFwY1mNXOD8J/YIfZFzffkGgB3 hco8xUd2WcucvM8F/O8l8mT16i0Gfi6h90mi30vyl/OMYiY11udQdfya4nJBtxq6xJ+K vZSKLIAdXvG6W9y9xByI7+JUmueiETbPnJ4xNAntYxr9LRgleW5rHAQ0Y7LkaYj7tpVW jEPQ== 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 d1si8488967pli.110.2017.06.12.22.07.35; Mon, 12 Jun 2017 22:07:35 -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 S1752478AbdFMFH0 (ORCPT + 25 others); Tue, 13 Jun 2017 01:07:26 -0400 Received: from conuserg-09.nifty.com ([210.131.2.76]:47817 "EHLO conuserg-09.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752432AbdFMFHX (ORCPT ); Tue, 13 Jun 2017 01:07:23 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-09.nifty.com with ESMTP id v5D54ENr023096; Tue, 13 Jun 2017 14:04:29 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-09.nifty.com v5D54ENr023096 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1497330270; bh=5no+bcwV1WpEDcH1xW8DBTRh3iU2l4sS+PpqzhMj7T0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=F8dd/SiYI5s4/6dpR/UwAN1lGZSWJ+xVJubUQ0zb0At2q24QkPzOkW+Wye52EmP0p rm1jhGxphPBF4Q3YPryl/A+1btznKryP45iHT6MrL237z8WJydxvNeUGyiDlzuMzZz VX24A45+/3VwJ1Fg9fbUS5AYLHavYgGkZipmcry5UFC0rmwSvVEixDbf78ANmf0o2j mSwOXRD7Qip0adLdViDCsfe8ERCmkxup52BKUi09xOtEpIVw/3EZyrhr7Pvb31Hf1l LjBYjOswqgN33a8rOKQFcD5gWHhzxvFNzG8+eaGDE2zaGnCka6I5UfZ+/HJ4yI7crO l/CCMrDX8Ctmw== 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 v6 13/18] mtd: nand: denali: fix raw and oob accessors for syndrome page layout Date: Tue, 13 Jun 2017 14:04:05 +0900 Message-Id: <1497330250-17348-14-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1497330250-17348-1-git-send-email-yamada.masahiro@socionext.com> References: <1497330250-17348-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 v6: - Minor cleanup to deprecate {write,read}_data_{to,from}_flash_mem - Remove unnecessary MAP10 command for MAIN_(SPARE_)ACCESS Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 650 +++++++++++++++++++++++++++------------------- drivers/mtd/nand/denali.h | 3 +- 2 files changed, 391 insertions(+), 262 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 03b75045d603..d58ea17c0a69 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -56,14 +56,6 @@ static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd) } /* - * These constants are defined by the driver to enable common driver - * configuration options. - */ -#define SPARE_ACCESS 0x41 -#define MAIN_ACCESS 0x42 -#define MAIN_SPARE_ACCESS 0x43 - -/* * this is a helper macro that allows us to * format the bank into the proper bits for the controller */ @@ -246,173 +238,80 @@ 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_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) +static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { 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; + int i; - /* - * 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); + iowrite32(MODE_11 | BANK(denali->flash_bank) | 2, denali->flash_mem); - index_addr(denali, MODE_11 | BANK(denali->flash_bank) | type, dat); + for (i = 0; i < len; i++) + buf[i] = ioread32(denali->flash_mem + 0x10); } -static int denali_dev_ready(struct mtd_info *mtd) +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; - 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); + iowrite32(MODE_11 | BANK(denali->flash_bank) | 2, denali->flash_mem); - cmd = MODE_01 | addr; - iowrite32(cmd, denali->flash_mem); - } - return status; + for (i = 0; i < len; i++) + iowrite32(buf[i], denali->flash_mem + 0x10); } -/* 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) +static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) { - uint32_t *buf32; + struct denali_nand_info *denali = mtd_to_denali(mtd); + uint16_t *buf16 = (uint16_t *)buf; int i; - /* - * verify that the len is a multiple of 4. - * see comment in read_data_from_flash_mem() - */ - BUG_ON((len % 4) != 0); + iowrite32(MODE_11 | BANK(denali->flash_bank) | 2, denali->flash_mem); - /* write the data to the flash memory */ - buf32 = (uint32_t *)buf; - for (i = 0; i < len / 4; i++) - iowrite32(*buf32++, denali->flash_mem + 0x10); - return i * 4; /* intent is to return the number of bytes read */ + for (i = 0; i < len / 2; i++) + buf16[i] = ioread32(denali->flash_mem + 0x10); } -/* helper function that simply reads a buffer from the flash */ -static int read_data_from_flash_mem(struct denali_nand_info *denali, - uint8_t *buf, int len) +static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf, + int len) { - uint32_t *buf32; + struct denali_nand_info *denali = mtd_to_denali(mtd); + const uint16_t *buf16 = (const uint16_t *)buf; int i; - /* - * we assume that len will be a multiple of 4, if not it would be nice - * to know about it ASAP rather than have random failures... - * This assumption is based on the fact that this function is designed - * to be used to read flash pages, which are typically multiples of 4. - */ - BUG_ON((len % 4) != 0); + iowrite32(MODE_11 | BANK(denali->flash_bank) | 2, denali->flash_mem); - /* transfer the data from the flash */ - buf32 = (uint32_t *)buf; - for (i = 0; i < len / 4; i++) - *buf32++ = ioread32(denali->flash_mem + 0x10); - return i * 4; /* intent is to return the number of bytes read */ + for (i = 0; i < len / 2; i++) + iowrite32(buf16[i], denali->flash_mem + 0x10); } -/* writes OOB data to the device */ -static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) +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 irq_status; - uint32_t irq_mask = INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL; - int status = 0; + uint32_t type; - if (denali_send_pipeline_cmd(denali, page, false, false, SPARE_ACCESS, - 1) == PASS) { - write_data_to_flash_mem(denali, buf, mtd->oobsize); + if (ctrl & NAND_CLE) + type = 0; + else if (ctrl & NAND_ALE) + type = 1; + else + return; - /* wait for operation to complete */ - irq_status = denali_wait_for_irq(denali, irq_mask); + /* + * 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); - 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; + index_addr(denali, MODE_11 | BANK(denali->flash_bank) | type, dat); } -/* reads OOB data from the device */ -static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) +static int denali_dev_ready(struct mtd_info *mtd) { 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); - } + return !!(denali_check_irq(denali) & INTR__INT_ACT); } static int denali_check_erased_page(struct mtd_info *mtd, @@ -630,144 +529,303 @@ 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 *buf32 = (uint32_t *)buf; + uint32_t irq_status, ecc_err_mask; + int i; - /* - * 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); + if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) + ecc_err_mask = INTR__ECC_UNCOR_ERR; + else + ecc_err_mask = INTR__ECC_ERR; - /* copy buffer into DMA buffer */ - memcpy(denali->buf, buf, mtd->writesize); + denali_reset_irq(denali); - if (raw_xfer) { - /* transfer the data to the spare area */ - memcpy(denali->buf + mtd->writesize, - chip->oob_poi, - mtd->oobsize); - } + iowrite32(MODE_01 | addr, denali->flash_mem); + for (i = 0; i < size / 4; i++) + *buf32++ = ioread32(denali->flash_mem + 0x10); - dma_sync_single_for_device(denali->dev, addr, size, DMA_TO_DEVICE); + 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; + const uint32_t *buf32 = (uint32_t *)buf; + uint32_t irq_status; + int i; denali_reset_irq(denali); + + iowrite32(MODE_01 | addr, denali->flash_mem); + for (i = 0; i < size / 4; i++) + iowrite32(*buf32++, denali->flash_mem + 0x10); + + 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) { + /* + * INTR__PROGRAM_COMP is never asserted for the DMA transfer. + * We can use INTR__DMA_CMD_COMP instead. This flag is asserted + * when the page program is completed. + */ + 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; +} + +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; - dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE); + 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 +834,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 +1344,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 +1413,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 Tue Jun 13 05:04:06 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103699 Delivered-To: patch@linaro.org Received: by 10.140.91.77 with SMTP id y71csp236168qgd; Mon, 12 Jun 2017 22:07:43 -0700 (PDT) X-Received: by 10.99.129.66 with SMTP id t63mr33928180pgd.28.1497330462948; Mon, 12 Jun 2017 22:07:42 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1497330462; cv=none; d=google.com; s=arc-20160816; b=LRJhRpOCgVWf2G0LOtaC2KjsbwYKW9sJyFM1ft7S9agyxFZOY5hq90XQfRFB+aWlmC 1iHgBQrS0Eleg1K5GyW6a/SkScE8A7DziNbiy6wkw2iQ7fdRQj63WM3WQ3cheQZjQQy1 DBJkFgy7mwybBd2gHjfwzv9psN3LyQAt9CgArNHs4jcHUy+G+zS7n1VxTljPEDIKmZFq 8id6Gps/hQGmr5dXVYQcUhGTixW4J3zfe04Y83RpzoIZtNRv07wXlekSvHzDk0Q+ESRN PVTKirzNsYzpJFaaM+1ojmzj9MaRzpkIhxQMoaFOWPhHLy5Y0hhPLCsQTEhjKXfXkI0g 5G8w== 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=t//WkJGgtIURlAFYnf14igJX6ojQBKdCoXKQ4jzyvpw=; b=LkOcXS8QORLj+x5MqpPvX3MKpyrMPIVhAe6OeMUzLaj1fBHJ9FDh7sr9JPI3eNkzbB H1Jm7R4xunFtG2uz8vTzhzwAVBGr7ZVaqcTI+vPjA7557rxrcA3gDLvNrBE+SVGTovnX incIngtWa79vklp/ILNsU/Ok7KoOitT+4grzuV+ff7zkmmtR3XsErnVKlpf6l705HQPT 7fQJ4B0J/VoKEzj31F8F24YvESvR8xV+0jQ5+TX8el/3sZmYHVyccSlIEXKKQWEaJcN2 z/l5qKFQFjC2HBz8ntX07oKUG9HBNEz8dbpKrHSSJZJV1noqLP69YAApoqH+eNAkpIe8 LFLQ== 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 1si8251437plx.88.2017.06.12.22.07.42; Mon, 12 Jun 2017 22:07: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 S1752517AbdFMFHc (ORCPT + 25 others); Tue, 13 Jun 2017 01:07:32 -0400 Received: from conuserg-09.nifty.com ([210.131.2.76]:47956 "EHLO conuserg-09.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752479AbdFMFH1 (ORCPT ); Tue, 13 Jun 2017 01:07:27 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-09.nifty.com with ESMTP id v5D54ENs023096; Tue, 13 Jun 2017 14:04:31 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-09.nifty.com v5D54ENs023096 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1497330271; bh=t//WkJGgtIURlAFYnf14igJX6ojQBKdCoXKQ4jzyvpw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=wLQKxJOIHztf9S0yzSsuaBkZaHkb8WN2vBVTdul12F0/D+cGNVccXgCGzbuIhWOMt EJ5MoAKfwcD/7JxvOl4Ngk+yeTpjxfw9J0mXqoPeUlwbOQ2GoBWZOSmrtBwlBBnmkP INALJRXKqbHDjfChQyqL98JJ1cCTYcJBKnULirtuiGqixdiivNQ7tw9E5AksJnWNRG dJV7avVIcte6hCb5Q42NEPdpydXOLVQ4RTbDAQh0pWPueuqC+A0/CGVujWBIHicEGA tQqBaxJR9blNVMD/nTJ4pHDMBaAZMJzrWNWbXR3zF5KhtdvjbTHxPG/RQ5PVufLZEi aswkBwrr/SPoA== 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 v6 14/18] mtd: nand: denali: support hardware-assisted erased page detection Date: Tue, 13 Jun 2017 14:04:06 +0900 Message-Id: <1497330250-17348-15-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1497330250-17348-1-git-send-email-yamada.masahiro@socionext.com> References: <1497330250-17348-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 pages 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 may be 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 is a bitflip or more, the driver will fallback to the software method by using nand_check_erased_ecc_chunk(). Strangely enough, the driver still has to fill the buffer with 0xff in case of INTR__ERASED_PAGE because the ECC correction engine has already manipulated the data in the buffer before it judges erased pages. Signed-off-by: Masahiro Yamada --- Changes in v6: - memset(buf, 0xff, size) is necessary even if the page is completely erased (all 0xff), strangely. 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 | 9 ++++++++- drivers/mtd/nand/denali.h | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index d58ea17c0a69..1ded7cc00b1a 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -552,6 +552,9 @@ static int denali_pio_read(struct denali_nand_info *denali, void *buf, if (!(irq_status & INTR__PAGE_XFER_INC)) return -EIO; + if (irq_status & INTR__ERASED_PAGE) + memset(buf, 0xff, size); + return irq_status & ecc_err_mask ? -EBADMSG : 0; } @@ -627,6 +630,9 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, denali_enable_dma(denali, false); dma_sync_single_for_cpu(denali->dev, dma_addr, size, dir); + if (irq_status & INTR__ERASED_PAGE) + memset(buf, 0xff, size); + return ret; } @@ -1397,7 +1403,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 Tue Jun 13 05:04:07 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103695 Delivered-To: patch@linaro.org Received: by 10.140.91.77 with SMTP id y71csp236123qgd; Mon, 12 Jun 2017 22:07:34 -0700 (PDT) X-Received: by 10.84.133.162 with SMTP id f31mr24408377plf.83.1497330454607; Mon, 12 Jun 2017 22:07:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1497330454; cv=none; d=google.com; s=arc-20160816; b=MHmwIeCRoAgXpuUKKK9KGr6CVbtzQi0p/nJPjNYC4XWrxbSLtZAnn3wOzeUeG83cwH df2aLLENnV8bhm/D4ALQHkSHBMe4gAM5vSQuQEYHsLe9MPiJKfqBykWenTZL/vqDodT0 6imLqj3kIwLeBz/H3dUZALWgEbjsHPtBs0QgC2tc9IOsRLj9lfEI7x4N+0PwbfKocDeO n90lKSI6/wqPzkYh9hH7rb201YdMS/WDtzfp8AMOZGLLnuKaW4qMqkCfLP+IFS0ySYCI +duZmFkV2njuikrfMc46PYme8HyPWSCUO+bwi+8GFdS8qQJ4jxRaiLoWd9Eo+TzgllTc TI0Q== 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=F322FTLwIWqCo24BEOoCsk75MXxka1nNSAdFN2jZIQ4=; b=Z3J3Dy/fi08cKEn9APF5vO9AtVuE7gHvGAl92NmrtZ5U5kUVBzfPA332vMuIZEm0AW /oOK3nSDHaG4EY6rdF4DD+26WbqlYDg8W5oE+2W6stQy5MkXbnoj2P/8Lq3Ro04R2W8O 0rn3ZamBpRpj3wh/iYVk1U6h37nArWTksbHlxwaUu66Al58FDLRmduu2vM+561HFKCU1 nREgiTMoDD+iPRBXhj6dQFEFOXrwc8vN73QfmgFxjGuz7gjCgMNTSMNTV3TzSdC++ZHG LIJrzdlpjcmieno6PjVGGRf49L1JyYZMx1PhiJ/7lXgp5qZK6LK26GQJvpGfoRYF4F73 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 d1si8488967pli.110.2017.06.12.22.07.34; Mon, 12 Jun 2017 22:07: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 S1752389AbdFMFHR (ORCPT + 25 others); Tue, 13 Jun 2017 01:07:17 -0400 Received: from conuserg-09.nifty.com ([210.131.2.76]:47513 "EHLO conuserg-09.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752349AbdFMFHO (ORCPT ); Tue, 13 Jun 2017 01:07:14 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-09.nifty.com with ESMTP id v5D54ENt023096; Tue, 13 Jun 2017 14:04:32 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-09.nifty.com v5D54ENt023096 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1497330273; bh=F322FTLwIWqCo24BEOoCsk75MXxka1nNSAdFN2jZIQ4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Mr/HVoSTRoC1lvrvZiSuczmGf1Fu1jAKadYsSPWx8aa65/foSIi0KFJNNl0zY43nk oKMoiH9pQ3YVYWswLbanaGAVTglVlfBgmKnFcjmem3Ouq18EyOzpYHmBPcB3ClmeKi Pbmi1TVB9R770Hr0fKgiwAlVzCE2tDsiC05QrNne70AhY8E4+S7bwWg5uLb0kXYOMZ Wtnhgfql51cq2z9th3WneeerIPPDrdRBqX9ciqGLKQeKxi0bCS5CfCes/1+VSv8FHP f+c2pJSSjrOHtaKfHkrbNrxmAdBLskC6n8a83o9+lMR4I+hXVOFuxEYI4U1T626xN2 dj95pUTrJWG7g== 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 v6 15/18] mtd: nand: denali: skip driver internal bounce buffer when possible Date: Tue, 13 Jun 2017 14:04:07 +0900 Message-Id: <1497330250-17348-16-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1497330250-17348-1-git-send-email-yamada.masahiro@socionext.com> References: <1497330250-17348-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 v6: None 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 1ded7cc00b1a..918b9b9bbe53 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -592,12 +592,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) { /* @@ -628,7 +632,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); if (irq_status & INTR__ERASED_PAGE) memset(buf, 0xff, size); @@ -814,12 +818,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) @@ -923,10 +925,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) @@ -1365,14 +1365,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; } /* @@ -1462,16 +1456,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 Tue Jun 13 05:04:08 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103700 Delivered-To: patch@linaro.org Received: by 10.140.91.77 with SMTP id y71csp236338qgd; Mon, 12 Jun 2017 22:08:18 -0700 (PDT) X-Received: by 10.101.70.70 with SMTP id k6mr60528510pgr.39.1497330498162; Mon, 12 Jun 2017 22:08:18 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1497330498; cv=none; d=google.com; s=arc-20160816; b=ZPI0zp5WQRGqBRuvT9JRB/8SatTTQ7JBmAv3qunng7EcJtqmHpbWNwuf46MtxtBmTL VpEev9nj8+Fo6GatL238zvyLs4JqpjcQxxFqjWVWGljrlZWSOnymqWJ2+LTUF7H2wMgV Qx/+CNrSutaHORTWptY/yUv94sbHjbZB8nB7eypTZ3LRbUWtRVF78LabWsxN9nuzUZOF d6Puv/iScrqxyvxTU2jkJ4/UUBUSil6vfDF1mIHrzTR2Mba5yt2iqpc0qhkOvWoWTPm3 AheRuxxnqm1p0YWVSzkmEcaxl8Ax8kWZBdZie9cCRSd4BmcpTCstxKxyvmx22BDtpdlA jFsQ== 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=+N/Lh4wla0YPpJKHh//TpnMBYOjIAoc8Qu5K+4qrsWI=; b=O4MGWrpRqZe6Qp92L5LyKviIkaPxfl9gWPMoG+ClOoWPw4AaOAPLBZkdJ5ZjNTjXdW SAItttP+WuayMfJdn2XcR7j+QBwkXxp6XZ4QerrfHb/lAGnU95XONrSjAioP1MkUnTfU 5+alo2QS7WMOBakeajru5nhedK2kGK8U9Y/lGN/mHmef43yh1/tAoejvjiWY7PHw4ZcG 4GGAgNmZE7KbbdNp6mvGLx74W79W8+W18FWpYuh97w2HAY0JROrZdG4M/u39SAwqBpis tvwN85sa0saNLikzuHVC11osja1YhIFMF5rP9F7JJbAbHH9QdRIceTHbmqoVsApG/TFu BugQ== 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 k130si8390134pfc.300.2017.06.12.22.08.17; Mon, 12 Jun 2017 22:08: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 S1752543AbdFMFHp (ORCPT + 25 others); Tue, 13 Jun 2017 01:07:45 -0400 Received: from conuserg-09.nifty.com ([210.131.2.76]:48477 "EHLO conuserg-09.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752518AbdFMFHn (ORCPT ); Tue, 13 Jun 2017 01:07:43 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-09.nifty.com with ESMTP id v5D54ENu023096; Tue, 13 Jun 2017 14:04:33 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-09.nifty.com v5D54ENu023096 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1497330274; bh=+N/Lh4wla0YPpJKHh//TpnMBYOjIAoc8Qu5K+4qrsWI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MA8vZKPBm+Z1oNzRDdRhGX51YUwAT00N9N/b5AEJZoI4MdQEkt70e0K4mOHh3uF25 yMt+jch5mqkSUrSaFe3XE+iNxSjs5XqgHripuA/q/0dgArkrP2+7ub2Njc7OsZVXDL 5DC/IZhc+E+miXXM4kMCQbMQwxcZF31TT9EVgm1cIRuzFT62ESsrLqvYndZWglDPd2 ow1zCItfSqaykw1CiB32m7+Mumxx+vdxx1uf9KjHK3F8somvuiP7evDU+IpPy61ZLi QOQlTminiOChlRchbezdDf4N876S3KL21kZ67RQAlAxMJQst0X2W+MCcXD+AQQcxbE kEJEhCdC5crXA== 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 v6 16/18] mtd: nand: denali: use non-managed kmalloc() for DMA buffer Date: Tue, 13 Jun 2017 14:04:08 +0900 Message-Id: <1497330250-17348-17-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1497330250-17348-1-git-send-email-yamada.masahiro@socionext.com> References: <1497330250-17348-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 v6: None 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 918b9b9bbe53..d37fb82f39ed 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "denali.h" @@ -1343,13 +1344,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; @@ -1434,17 +1428,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); @@ -1458,6 +1465,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 Tue Jun 13 05:04:09 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103696 Delivered-To: patch@linaro.org Received: by 10.140.91.77 with SMTP id y71csp236124qgd; Mon, 12 Jun 2017 22:07:35 -0700 (PDT) X-Received: by 10.84.218.134 with SMTP id r6mr60540642pli.288.1497330454973; Mon, 12 Jun 2017 22:07:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1497330454; cv=none; d=google.com; s=arc-20160816; b=fWibhN0ekoieuujHTorsS7/B518KpDqYK4RO4ctj0lJL4X/0NxcMj0c+MGCwWhFct1 lYUNTiR+WTuCtv3Bb3IEMIUhA7+ojPNQjRtqqKOayb7tpN7XHv+vqFrXSUDoI8cw9u3c Y1HuhrTkVjGR/GgLTFMa9oJMDZvd2OnUUhN3+PEheLldNHyd1zF4Mr/epSsZl988/6Cn fzskc838MM2o7TV38gyGdxg7Z6ziTCaDI7VjJvdokUBYjGB0WnlQA5FIaCBNlHCi+Fmt IW+16D6B8edGKwwyFcohUfePTy1bwWjylUFBnC/5LjPqAvoV8U0KTS+2yecS9u3Aq7kb 24fw== 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=blxYdIg4H1+O3T/OAy1KBhvJkZRzdVvCH70HiChkKYo=; b=KwZyCcZ66sWo6H2JPEWhBMR0jJveHz03lUgSIhKYWYX4sTlbV++WbY/dwQQg48hZKn yI8pVQ5nSJb6SJRIBp5zugksTjZIk9+9YuoprGayMWeQO307+hPAXvn41yvvJDxAIBcm 7CutB6yHW5AH+Au3zX1XizgmO4oztq9aodHAY6UnyTDn17P1fUlE/H0QHd+uHspr/vMP 720yB8mGzv7WLjP1uLGgzkIu8575fVcwdwAKPF+WQAuKXjSDT/61T1ywwBU4sv66zy9S NsKj6iOsZXPW+18VVbchKSkcRSYf8f+DldHEmnRL0oD4RqwszGvdY+P5HYdi0s+BjnPF 7fcg== 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 d1si8488967pli.110.2017.06.12.22.07.34; Mon, 12 Jun 2017 22:07: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 S1752426AbdFMFHU (ORCPT + 25 others); Tue, 13 Jun 2017 01:07:20 -0400 Received: from conuserg-09.nifty.com ([210.131.2.76]:47054 "EHLO conuserg-09.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752355AbdFMFHR (ORCPT ); Tue, 13 Jun 2017 01:07:17 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-09.nifty.com with ESMTP id v5D54ENv023096; Tue, 13 Jun 2017 14:04:34 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-09.nifty.com v5D54ENv023096 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1497330275; bh=blxYdIg4H1+O3T/OAy1KBhvJkZRzdVvCH70HiChkKYo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hmDmK/+AEvIWZmqfMgk5PByhOSiYaNqZAq284HOuycQa3014+BOpqO2RJe1RvXXWn 3GVxs7Z/da59pJ06ivlmuTqZBTZG0R+KJDNK5jcsaR/9QUJ5l/+oduQFbgbJQrkXUc HbeFV6g1+Y+FQm7NEtgickC4srTS0QDI+6UfnkWdKi3F5GwD8YAlGajjzI8amn5bqc C5/XIvFNV0qAijPZ9K3CWPRgqZR4dhHDIecE6S0/A1Jya3DkqsY18aiwgkOivBMwGC /Wnre2iRxhGcY1kl+4a58FxzV65AkM4FtCPIY63itKbAZQw/sWU7VDtk7GcSeJS5Pj 80HK1J+Zb7W2Q== 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 v6 17/18] mtd: nand: denali: enable bad block table scan Date: Tue, 13 Jun 2017 14:04:09 +0900 Message-Id: <1497330250-17348-18-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1497330250-17348-1-git-send-email-yamada.masahiro@socionext.com> References: <1497330250-17348-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 v6: None 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 d37fb82f39ed..3bcc886579c8 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1203,29 +1203,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) { @@ -1369,13 +1346,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 */ From patchwork Tue Jun 13 05:04: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: 103701 Delivered-To: patch@linaro.org Received: by 10.140.91.77 with SMTP id y71csp236340qgd; Mon, 12 Jun 2017 22:08:18 -0700 (PDT) X-Received: by 10.98.198.2 with SMTP id m2mr1310165pfg.215.1497330498527; Mon, 12 Jun 2017 22:08:18 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1497330498; cv=none; d=google.com; s=arc-20160816; b=TTktH7ck2NtfP8XbkGDiEs9BPxqjUQ4uFeSKQRc7GNKwZKQ3mjEn8RDDXOQH4bDiHm GJDoSH35U7FmvsqQlqNMansRvd45SvxZlrnPMKc6i2EI/TDoLw2RZC/h+XlQXjtCbTTi vTkdRLFJCUyudb0Sg8l0d7ztpPzobgb8HBXfP52GWG4f2NsLYQfj0ktEXK4sp36id+++ LD9vdTJAcxBxNG7jA7XRTeei6vYIMHtyzBslMPkuMITsS9DOMn8xI1FmIbIOYmOgEsg+ hhuHswDLrArkLrdxES9ekoRmc2xn1cbdR++3gGUM3OHNjwNLv97tZDSeOhZua67FzLvO tCiQ== 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=1yrTqpOUzJnlqnYUBa36o4wXwB8YmarVemawjuik8/A=; b=U4F7KSGqlH70yYPTA1SxWsJoAofP7rpZL1DJtL++/7uAopMSDxVXIt7QfqWxTQ63D6 VBfL2i42xDpS79m0M3BvErlRk0VJzK2+L3WJj4IFTUZJs2ktldFp0vh69B/GB5WSVRYb LkszksyjPq9NpGnyiQdQlKeDYhDDvwlOrUasnynZfgqlF8XggCGOR9Jdb9481kYNxvzO k69vaHflIOGCxIAbovF4lOM4OifgSWuZpsWTBikW/YfMTkl0kWmBpa451SylXVCGj5Km 4Mo4mHlJZ5xmuy0eKEiZeXhpQHtxoYszCPEUxkS+VsWHItHojRNDZKLM1/kbUVWixTMs 6oWw== 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 k130si8390134pfc.300.2017.06.12.22.08.18; Mon, 12 Jun 2017 22:08: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 S1752561AbdFMFH6 (ORCPT + 25 others); Tue, 13 Jun 2017 01:07:58 -0400 Received: from conuserg-09.nifty.com ([210.131.2.76]:47665 "EHLO conuserg-09.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752480AbdFMFH3 (ORCPT ); Tue, 13 Jun 2017 01:07:29 -0400 Received: from pug.e01.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-09.nifty.com with ESMTP id v5D54ENw023096; Tue, 13 Jun 2017 14:04:35 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-09.nifty.com v5D54ENw023096 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1497330276; bh=1yrTqpOUzJnlqnYUBa36o4wXwB8YmarVemawjuik8/A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=phP36Rj9iSHXnnNkZhe9X7ffNwhVHOu4r2Y/iIWGQE2xYdLWr7xxs56aox07e7zfO 7GeZ6s0Ct0NputmyoNlrQ8q/hiCpdGRQ3AtJnC5Cr9RIxYDTNypSpfXf/EtHBXgayk B3ZD2o0RHZEdnP2o679l62kHfix9FkRqGwnCekZo8bLdNlAtE/rLXG7ktmDTgxrsz5 o5m1o3tP7FpysUYoc/eCwSjJVEAYzvbnCuPgltGC+A0wzyGuvaDQUA2HzHVisLx3RL YxGO5Cttp63RCpHRzkVLqBq7gsQXCqqSDLKtrzgX8aYAcpq5cJMhJQHsAny5b0/m43 Y3YeJzjypwrDw== 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 v6 18/18] mtd: nand: denali: avoid magic numbers and rename for clarification Date: Tue, 13 Jun 2017 14:04:10 +0900 Message-Id: <1497330250-17348-19-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1497330250-17348-1-git-send-email-yamada.masahiro@socionext.com> References: <1497330250-17348-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 Introduce some macros and helpers to avoid magic numbers and rename macros/functions for clarification. - We see '| 2' in several places. This means Data Cycle in MAP11 mode. The Denali User's Guide says bit[1:0] of MAP11 is like follows: b'00 = Command Cycle b'01 = Address Cycle b'10 = Data Cycle So, this commit added DENALI_MAP11_{CMD,ADDR,DATA} macros. - We see 'denali->flash_mem + 0x10' in several places, but 0x10 is a magic number. Actually, this accesses the data port of the Host Data/Command Interface. So, this commit added DENALI_HOST_DATA. On the other hand, 'denali->flash_mem' gets access to the address port, so DENALI_HOST_ADDR was also added. - We see 'index_addr(denali, cmd, 0x1)' in denali_erase(), but 0x1 is a magic number. 0x1 means the erase operation. Replace 0x1 with DENALI_ERASE. - Rename index_addr() to denali_host_write() for clarification and add denali_host_read() as a helper. - Denali User's Guide says MAP{00,01,10,11} for access mode. Match the macros with terminology in the IP document. - Rename struct members as follows: flash_bank -> active_bank (currently selected bank) flash_reg -> reg (base address of registers) flash_mem -> host (base address of host interface) devnum -> devs_per_cs (devices connected in parallel) bbtskipbytes -> oob_skip_bytes (number of bytes to skip in OOB) Signed-off-by: Masahiro Yamada --- Changes in v6: - Newly added Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None drivers/mtd/nand/denali.c | 259 ++++++++++++++++++++++-------------------- drivers/mtd/nand/denali.h | 15 +-- drivers/mtd/nand/denali_dt.c | 12 +- drivers/mtd/nand/denali_pci.c | 16 +-- 4 files changed, 153 insertions(+), 149 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 3bcc886579c8..6aa78ca2439b 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -31,12 +31,26 @@ MODULE_LICENSE("GPL"); #define DENALI_NAND_NAME "denali-nand" -/* - * indicates whether or not the internal value for the flash bank is - * valid or not - */ -#define CHIP_SELECT_INVALID -1 +/* Host Data/Command Interface */ +#define DENALI_HOST_ADDR 0x00 +#define DENALI_HOST_DATA 0x10 + +#define DENALI_MAP00 (0 << 26) /* direct access to buffer */ +#define DENALI_MAP01 (1 << 26) /* read/write pages in PIO */ +#define DENALI_MAP10 (2 << 26) /* higher-level control plane */ +#define DENALI_MAP11 (3 << 26) /* direct controller access */ + +/* MAP11 access cycle type */ +#define DENALI_MAP11_CMD ((DENALI_MAP11) | 0) /* command cycle */ +#define DENALI_MAP11_ADDR ((DENALI_MAP11) | 1) /* address cycle */ +#define DENALI_MAP11_DATA ((DENALI_MAP11) | 2) /* data cycle */ +/* MAP11 commands */ +#define DENALI_ERASE 0x01 + +#define DENALI_BANK(denali) ((denali)->active_bank << 24) + +#define DENALI_INVALID_BANK -1 #define DENALI_NR_BANKS 4 /* @@ -56,23 +70,17 @@ static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd) return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand); } -/* - * this is a helper macro that allows us to - * format the bank into the proper bits for the controller - */ -#define BANK(x) ((x) << 24) +static uint32_t denali_host_read(struct denali_nand_info *denali, uint32_t addr) +{ + iowrite32(addr, denali->host + DENALI_HOST_ADDR); + return ioread32(denali->host + DENALI_HOST_DATA); +} -/* - * 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 - * abstracts this common operation. - */ -static void index_addr(struct denali_nand_info *denali, - uint32_t address, uint32_t data) +static void denali_host_write(struct denali_nand_info *denali, + uint32_t addr, uint32_t data) { - iowrite32(address, denali->flash_mem); - iowrite32(data, denali->flash_mem + 0x10); + iowrite32(addr, denali->host + DENALI_HOST_ADDR); + iowrite32(data, denali->host + DENALI_HOST_DATA); } /* @@ -81,7 +89,7 @@ static void index_addr(struct denali_nand_info *denali, */ static void detect_max_banks(struct denali_nand_info *denali) { - uint32_t features = ioread32(denali->flash_reg + FEATURES); + uint32_t features = ioread32(denali->reg + FEATURES); denali->max_banks = 1 << (features & FEATURES__N_BANKS); @@ -95,8 +103,8 @@ static void denali_enable_irq(struct denali_nand_info *denali) int i; 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); + iowrite32(U32_MAX, denali->reg + INTR_EN(i)); + iowrite32(GLOBAL_INT_EN_FLAG, denali->reg + GLOBAL_INT_ENABLE); } static void denali_disable_irq(struct denali_nand_info *denali) @@ -104,15 +112,15 @@ static void denali_disable_irq(struct denali_nand_info *denali) int i; for (i = 0; i < DENALI_NR_BANKS; i++) - iowrite32(0, denali->flash_reg + INTR_EN(i)); - iowrite32(0, denali->flash_reg + GLOBAL_INT_ENABLE); + iowrite32(0, denali->reg + INTR_EN(i)); + iowrite32(0, denali->reg + GLOBAL_INT_ENABLE); } static void denali_clear_irq(struct denali_nand_info *denali, int bank, uint32_t irq_status) { /* write one to clear bits */ - iowrite32(irq_status, denali->flash_reg + INTR_STATUS(bank)); + iowrite32(irq_status, denali->reg + INTR_STATUS(bank)); } static void denali_clear_irq_all(struct denali_nand_info *denali) @@ -133,13 +141,13 @@ static irqreturn_t denali_isr(int irq, void *dev_id) spin_lock(&denali->irq_lock); for (i = 0; i < DENALI_NR_BANKS; i++) { - irq_status = ioread32(denali->flash_reg + INTR_STATUS(i)); + irq_status = ioread32(denali->reg + INTR_STATUS(i)); if (irq_status) ret = IRQ_HANDLED; denali_clear_irq(denali, i, irq_status); - if (i != denali->flash_bank) + if (i != denali->active_bank) continue; denali->irq_status |= irq_status; @@ -219,24 +227,24 @@ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, transfer_spare_flag = transfer_spare ? TRANSFER_SPARE_REG__FLAG : 0; /* Enable spare area/ECC per user's request. */ - iowrite32(ecc_en_flag, denali->flash_reg + ECC_ENABLE); - iowrite32(transfer_spare_flag, denali->flash_reg + TRANSFER_SPARE_REG); + iowrite32(ecc_en_flag, denali->reg + ECC_ENABLE); + iowrite32(transfer_spare_flag, denali->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); + return denali_host_read(denali, + DENALI_MAP11_DATA | DENALI_BANK(denali)); } 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); + denali_host_write(denali, DENALI_MAP11_DATA | DENALI_BANK(denali), + byte); } static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) @@ -244,10 +252,11 @@ 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); + iowrite32(DENALI_MAP11_DATA | DENALI_BANK(denali), + denali->host + DENALI_HOST_ADDR); for (i = 0; i < len; i++) - buf[i] = ioread32(denali->flash_mem + 0x10); + buf[i] = ioread32(denali->host + DENALI_HOST_DATA); } static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) @@ -255,10 +264,11 @@ 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); + iowrite32(DENALI_MAP11_DATA | DENALI_BANK(denali), + denali->host + DENALI_HOST_ADDR); for (i = 0; i < len; i++) - iowrite32(buf[i], denali->flash_mem + 0x10); + iowrite32(buf[i], denali->host + DENALI_HOST_DATA); } static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) @@ -267,10 +277,11 @@ static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) uint16_t *buf16 = (uint16_t *)buf; int i; - iowrite32(MODE_11 | BANK(denali->flash_bank) | 2, denali->flash_mem); + iowrite32(DENALI_MAP11_DATA | DENALI_BANK(denali), + denali->host + DENALI_HOST_ADDR); for (i = 0; i < len / 2; i++) - buf16[i] = ioread32(denali->flash_mem + 0x10); + buf16[i] = ioread32(denali->host + DENALI_HOST_DATA); } static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf, @@ -280,10 +291,11 @@ static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf, const uint16_t *buf16 = (const uint16_t *)buf; int i; - iowrite32(MODE_11 | BANK(denali->flash_bank) | 2, denali->flash_mem); + iowrite32(DENALI_MAP11_DATA | DENALI_BANK(denali), + denali->host + DENALI_HOST_ADDR); for (i = 0; i < len / 2; i++) - iowrite32(buf16[i], denali->flash_mem + 0x10); + iowrite32(buf16[i], denali->host + DENALI_HOST_DATA); } static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) @@ -292,9 +304,9 @@ static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) uint32_t type; if (ctrl & NAND_CLE) - type = 0; + type = DENALI_MAP11_CMD; else if (ctrl & NAND_ALE) - type = 1; + type = DENALI_MAP11_ADDR; else return; @@ -305,7 +317,7 @@ static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) if (ctrl & NAND_CTRL_CHANGE) denali_reset_irq(denali); - index_addr(denali, MODE_11 | BANK(denali->flash_bank) | type, dat); + denali_host_write(denali, DENALI_BANK(denali) | type, dat); } static int denali_dev_ready(struct mtd_info *mtd) @@ -358,11 +370,11 @@ static int denali_hw_ecc_fixup(struct mtd_info *mtd, unsigned long *uncor_ecc_flags) { struct nand_chip *chip = mtd_to_nand(mtd); - int bank = denali->flash_bank; + int bank = denali->active_bank; uint32_t ecc_cor; unsigned int max_bitflips; - ecc_cor = ioread32(denali->flash_reg + ECC_COR_INFO(bank)); + ecc_cor = ioread32(denali->reg + ECC_COR_INFO(bank)); ecc_cor >>= ECC_COR_INFO__SHIFT(bank); if (ecc_cor & ECC_COR_INFO__UNCOR_ERR) { @@ -411,11 +423,11 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd, denali_reset_irq(denali); do { - err_addr = ioread32(denali->flash_reg + ECC_ERROR_ADDRESS); + err_addr = ioread32(denali->reg + ECC_ERROR_ADDRESS); err_sector = ECC_SECTOR(err_addr); err_byte = ECC_BYTE(err_addr); - err_cor_info = ioread32(denali->flash_reg + ERR_CORRECTION_INFO); + err_cor_info = ioread32(denali->reg + ERR_CORRECTION_INFO); err_cor_value = ECC_CORRECTION_VALUE(err_cor_info); err_device = ECC_ERR_DEVICE(err_cor_info); @@ -441,7 +453,7 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd, unsigned int flips_in_byte; offset = (err_sector * ecc_size + err_byte) * - denali->devnum + err_device; + denali->devs_per_cs + err_device; /* correct the ECC error */ flips_in_byte = hweight8(buf[offset] ^ err_cor_value); @@ -470,8 +482,8 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd, /* programs the controller to either enable/disable DMA transfers */ static void denali_enable_dma(struct denali_nand_info *denali, bool en) { - iowrite32(en ? DMA_ENABLE__FLAG : 0, denali->flash_reg + DMA_ENABLE); - ioread32(denali->flash_reg + DMA_ENABLE); + iowrite32(en ? DMA_ENABLE__FLAG : 0, denali->reg + DMA_ENABLE); + ioread32(denali->reg + DMA_ENABLE); } static void denali_setup_dma64(struct denali_nand_info *denali, @@ -480,7 +492,7 @@ static void denali_setup_dma64(struct denali_nand_info *denali, uint32_t mode; const int page_count = 1; - mode = MODE_10 | BANK(denali->flash_bank) | page; + mode = DENALI_MAP10 | DENALI_BANK(denali) | page; /* DMA is a three step process */ @@ -488,14 +500,14 @@ 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) | (write << 8) | page_count); + denali_host_write(denali, mode, + 0x01002000 | (64 << 16) | (write << 8) | page_count); /* 2. set memory low address */ - index_addr(denali, mode, dma_addr); + denali_host_write(denali, mode, dma_addr); /* 3. set memory high address */ - index_addr(denali, mode, (uint64_t)dma_addr >> 32); + denali_host_write(denali, mode, (uint64_t)dma_addr >> 32); } static void denali_setup_dma32(struct denali_nand_info *denali, @@ -504,21 +516,22 @@ static void denali_setup_dma32(struct denali_nand_info *denali, uint32_t mode; const int page_count = 1; - mode = MODE_10 | BANK(denali->flash_bank); + mode = DENALI_MAP10 | DENALI_BANK(denali); /* DMA is a four step process */ /* 1. setup transfer type and # of pages */ - index_addr(denali, mode | page, 0x2000 | (write << 8) | page_count); + denali_host_write(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); + denali_host_write(denali, mode | ((dma_addr >> 16) << 8), 0x2200); /* 3. set memory low address bits 23:8 */ - index_addr(denali, mode | ((dma_addr & 0xffff) << 8), 0x2300); + denali_host_write(denali, mode | ((dma_addr & 0xffff) << 8), 0x2300); /* 4. interrupt when complete, burst len = 64 bytes */ - index_addr(denali, mode | 0x14000, 0x2400); + denali_host_write(denali, mode | 0x14000, 0x2400); } static void denali_setup_dma(struct denali_nand_info *denali, @@ -533,7 +546,7 @@ static void denali_setup_dma(struct denali_nand_info *denali, static int denali_pio_read(struct denali_nand_info *denali, void *buf, size_t size, int page, int raw) { - uint32_t addr = BANK(denali->flash_bank) | page; + uint32_t addr = DENALI_BANK(denali) | page; uint32_t *buf32 = (uint32_t *)buf; uint32_t irq_status, ecc_err_mask; int i; @@ -545,9 +558,9 @@ static int denali_pio_read(struct denali_nand_info *denali, void *buf, denali_reset_irq(denali); - iowrite32(MODE_01 | addr, denali->flash_mem); + iowrite32(DENALI_MAP01 | addr, denali->host + DENALI_HOST_ADDR); for (i = 0; i < size / 4; i++) - *buf32++ = ioread32(denali->flash_mem + 0x10); + *buf32++ = ioread32(denali->host + DENALI_HOST_DATA); irq_status = denali_wait_for_irq(denali, INTR__PAGE_XFER_INC); if (!(irq_status & INTR__PAGE_XFER_INC)) @@ -562,16 +575,16 @@ static int denali_pio_read(struct denali_nand_info *denali, void *buf, 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 addr = DENALI_BANK(denali) | page; const uint32_t *buf32 = (uint32_t *)buf; uint32_t irq_status; int i; denali_reset_irq(denali); - iowrite32(MODE_01 | addr, denali->flash_mem); + iowrite32(DENALI_MAP01 | addr, denali->host + DENALI_HOST_ADDR); for (i = 0; i < size / 4; i++) - iowrite32(*buf32++, denali->flash_mem + 0x10); + iowrite32(*buf32++, denali->host + DENALI_HOST_DATA); irq_status = denali_wait_for_irq(denali, INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL); @@ -664,7 +677,7 @@ static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip, int ecc_steps = chip->ecc.steps; int ecc_size = chip->ecc.size; int ecc_bytes = chip->ecc.bytes; - int oob_skip = denali->bbtskipbytes; + int oob_skip = denali->oob_skip_bytes; size_t size = writesize + oobsize; int i, pos, len; @@ -722,7 +735,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, int ecc_size = chip->ecc.size; int ecc_bytes = chip->ecc.bytes; void *dma_buf = denali->buf; - int oob_skip = denali->bbtskipbytes; + int oob_skip = denali->oob_skip_bytes; size_t size = writesize + oobsize; int ret, i, pos, len; @@ -853,7 +866,7 @@ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, int ecc_size = chip->ecc.size; int ecc_bytes = chip->ecc.bytes; void *dma_buf = denali->buf; - int oob_skip = denali->bbtskipbytes; + int oob_skip = denali->oob_skip_bytes; size_t size = writesize + oobsize; int i, pos, len; @@ -934,7 +947,7 @@ static void denali_select_chip(struct mtd_info *mtd, int chip) { struct denali_nand_info *denali = mtd_to_denali(mtd); - denali->flash_bank = chip; + denali->active_bank = chip; } static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) @@ -951,13 +964,12 @@ 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; + uint32_t irq_status; denali_reset_irq(denali); - /* setup page read request for access type */ - cmd = MODE_10 | BANK(denali->flash_bank) | page; - index_addr(denali, cmd, 0x1); + denali_host_write(denali, DENALI_MAP10 | DENALI_BANK(denali) | page, + DENALI_ERASE); /* wait for erase to complete or failure to occur */ irq_status = denali_wait_for_irq(denali, @@ -996,37 +1008,37 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr, 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 = ioread32(denali->reg + ACC_CLKS); tmp &= ~ACC_CLKS__VALUE; tmp |= acc_clks; - iowrite32(tmp, denali->flash_reg + ACC_CLKS); + iowrite32(tmp, denali->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 = ioread32(denali->reg + RE_2_WE); tmp &= ~RE_2_WE__VALUE; tmp |= re_2_we; - iowrite32(tmp, denali->flash_reg + RE_2_WE); + iowrite32(tmp, denali->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 = ioread32(denali->reg + RE_2_RE); tmp &= ~RE_2_RE__VALUE; tmp |= re_2_re; - iowrite32(tmp, denali->flash_reg + RE_2_RE); + iowrite32(tmp, denali->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 = ioread32(denali->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); + iowrite32(tmp, denali->reg + TWHR2_AND_WE_2_RE); /* tADL -> ADDR_2_DATA */ @@ -1038,20 +1050,20 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr, 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 = ioread32(denali->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); + iowrite32(tmp, denali->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 = ioread32(denali->reg + RDWR_EN_HI_CNT); tmp &= ~RDWR_EN_HI_CNT__VALUE; tmp |= rdwr_en_hi; - iowrite32(tmp, denali->flash_reg + RDWR_EN_HI_CNT); + iowrite32(tmp, denali->reg + RDWR_EN_HI_CNT); /* tRP, tWP -> RDWR_EN_LO_CNT */ rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min), @@ -1062,10 +1074,10 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr, 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 = ioread32(denali->reg + RDWR_EN_LO_CNT); tmp &= ~RDWR_EN_LO_CNT__VALUE; tmp |= rdwr_en_lo; - iowrite32(tmp, denali->flash_reg + RDWR_EN_LO_CNT); + iowrite32(tmp, denali->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, @@ -1073,10 +1085,10 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr, 0); cs_setup = min_t(int, cs_setup, CS_SETUP_CNT__VALUE); - tmp = ioread32(denali->flash_reg + CS_SETUP_CNT); + tmp = ioread32(denali->reg + CS_SETUP_CNT); tmp &= ~CS_SETUP_CNT__VALUE; tmp |= cs_setup; - iowrite32(tmp, denali->flash_reg + CS_SETUP_CNT); + iowrite32(tmp, denali->reg + CS_SETUP_CNT); return 0; } @@ -1087,12 +1099,12 @@ static void denali_reset_banks(struct denali_nand_info *denali) int i; for (i = 0; i < denali->max_banks; i++) { - denali->flash_bank = i; + denali->active_bank = i; denali_reset_irq(denali); iowrite32(DEVICE_RESET__BANK(i), - denali->flash_reg + DEVICE_RESET); + denali->reg + DEVICE_RESET); irq_status = denali_wait_for_irq(denali, INTR__RST_COMP | INTR__INT_ACT | INTR__TIME_OUT); @@ -1111,8 +1123,7 @@ static void denali_hw_init(struct denali_nand_info *denali) * override it. */ if (!denali->revision) - denali->revision = - swab16(ioread32(denali->flash_reg + REVISION)); + denali->revision = swab16(ioread32(denali->reg + REVISION)); /* * tell driver how many bit controller will skip before @@ -1120,18 +1131,16 @@ static void denali_hw_init(struct denali_nand_info *denali) * set by firmware. So we read this value out. * if this value is 0, just let it be. */ - denali->bbtskipbytes = ioread32(denali->flash_reg + - SPARE_AREA_SKIP_BYTES); + denali->oob_skip_bytes = ioread32(denali->reg + SPARE_AREA_SKIP_BYTES); detect_max_banks(denali); - iowrite32(0x0F, denali->flash_reg + RB_PIN_ENABLED); - iowrite32(CHIP_EN_DONT_CARE__FLAG, - denali->flash_reg + CHIP_ENABLE_DONT_CARE); + iowrite32(0x0F, denali->reg + RB_PIN_ENABLED); + iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE); - iowrite32(0xffff, denali->flash_reg + SPARE_AREA_MARKER); + iowrite32(0xffff, denali->reg + SPARE_AREA_MARKER); /* Should set value for these registers when init */ - iowrite32(0, denali->flash_reg + TWO_ROW_ADDR_CYCLES); - iowrite32(1, denali->flash_reg + ECC_ENABLE); + iowrite32(0, denali->reg + TWO_ROW_ADDR_CYCLES); + iowrite32(1, denali->reg + ECC_ENABLE); } int denali_calc_ecc_bytes(int step_size, int strength) @@ -1144,7 +1153,7 @@ 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 oobavail = mtd->oobsize - denali->oob_skip_bytes; int ret; /* @@ -1177,7 +1186,7 @@ static int denali_ooblayout_ecc(struct mtd_info *mtd, int section, if (section) return -ERANGE; - oobregion->offset = denali->bbtskipbytes; + oobregion->offset = denali->oob_skip_bytes; oobregion->length = chip->ecc.total; return 0; @@ -1192,7 +1201,7 @@ static int denali_ooblayout_free(struct mtd_info *mtd, int section, if (section) return -ERANGE; - oobregion->offset = chip->ecc.total + denali->bbtskipbytes; + oobregion->offset = chip->ecc.total + denali->oob_skip_bytes; oobregion->length = mtd->oobsize - oobregion->offset; return 0; @@ -1231,23 +1240,23 @@ static int denali_multidev_fixup(struct denali_nand_info *denali) * In this case, the core framework knows nothing about this fact, * so we should tell it the _logical_ pagesize and anything necessary. */ - denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED); + denali->devs_per_cs = ioread32(denali->reg + DEVICES_CONNECTED); /* * On some SoCs, DEVICES_CONNECTED is not auto-detected. * For those, DEVICES_CONNECTED is left to 0. Set 1 if it is the case. */ - if (denali->devnum == 0) { - denali->devnum = 1; - iowrite32(1, denali->flash_reg + DEVICES_CONNECTED); + if (denali->devs_per_cs == 0) { + denali->devs_per_cs = 1; + iowrite32(1, denali->reg + DEVICES_CONNECTED); } - if (denali->devnum == 1) + if (denali->devs_per_cs == 1) return 0; - if (denali->devnum != 2) { + if (denali->devs_per_cs != 2) { dev_err(denali->dev, "unsupported number of devices %d\n", - denali->devnum); + denali->devs_per_cs); return -EINVAL; } @@ -1265,7 +1274,7 @@ static int denali_multidev_fixup(struct denali_nand_info *denali) chip->ecc.size <<= 1; chip->ecc.bytes <<= 1; chip->ecc.strength <<= 1; - denali->bbtskipbytes <<= 1; + denali->oob_skip_bytes <<= 1; return 0; } @@ -1293,7 +1302,7 @@ int denali_init(struct denali_nand_info *denali) denali_enable_irq(denali); denali_reset_banks(denali); - denali->flash_bank = CHIP_SELECT_INVALID; + denali->active_bank = DENALI_INVALID_BANK; nand_set_flash_node(chip, denali->dev->of_node); /* Fallback to the default name if DT did not give "label" property */ @@ -1321,7 +1330,7 @@ int denali_init(struct denali_nand_info *denali) if (ret) goto disable_irq; - if (ioread32(denali->flash_reg + FEATURES) & FEATURES__DMA) + if (ioread32(denali->reg + FEATURES) & FEATURES__DMA) denali->dma_avail = 1; if (denali->dma_avail) { @@ -1365,19 +1374,19 @@ int denali_init(struct denali_nand_info *denali) chip->ecc.size, chip->ecc.strength, chip->ecc.bytes); iowrite32(MAKE_ECC_CORRECTION(chip->ecc.strength, 1), - denali->flash_reg + ECC_CORRECTION); + denali->reg + ECC_CORRECTION); iowrite32(mtd->erasesize / mtd->writesize, - denali->flash_reg + PAGES_PER_BLOCK); + denali->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); + denali->reg + DEVICE_WIDTH); + iowrite32(mtd->writesize, denali->reg + DEVICE_MAIN_AREA_SIZE); + iowrite32(mtd->oobsize, denali->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); + iowrite32(chip->ecc.size, denali->reg + CFG_DATA_BLOCK_SIZE); + iowrite32(chip->ecc.size, denali->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); + denali->reg + CFG_NUM_DATA_BLOCKS); mtd_set_ooblayout(mtd, &denali_ooblayout_ops); diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 657a794af695..237cc706b0fb 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -303,18 +303,13 @@ #define CHNL_ACTIVE__CHANNEL2 BIT(2) #define CHNL_ACTIVE__CHANNEL3 BIT(3) -#define MODE_00 0x00000000 -#define MODE_01 0x04000000 -#define MODE_10 0x08000000 -#define MODE_11 0x0C000000 - struct denali_nand_info { struct nand_chip nand; unsigned long clk_x_rate; /* bus interface clock rate */ - int flash_bank; /* currently selected chip */ + int active_bank; /* currently selected bank */ struct device *dev; - void __iomem *flash_reg; /* Register Interface */ - void __iomem *flash_mem; /* Host Data/Command Interface */ + void __iomem *reg; /* Register Interface */ + void __iomem *host; /* Host Data/Command Interface */ /* elements used by ISR */ struct completion complete; @@ -326,8 +321,8 @@ struct denali_nand_info { void *buf; dma_addr_t dma_addr; int dma_avail; - int devnum; /* represent how many nands connected */ - int bbtskipbytes; + int devs_per_cs; /* devices connected in parallel */ + int oob_skip_bytes; int max_banks; unsigned int revision; unsigned int caps; diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index ebcce50f4005..47f398edf18f 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -104,14 +104,14 @@ static int denali_dt_probe(struct platform_device *pdev) } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "denali_reg"); - denali->flash_reg = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(denali->flash_reg)) - return PTR_ERR(denali->flash_reg); + denali->reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(denali->reg)) + return PTR_ERR(denali->reg); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data"); - denali->flash_mem = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(denali->flash_mem)) - return PTR_ERR(denali->flash_mem); + denali->host = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(denali->host)) + return PTR_ERR(denali->host); dt->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(dt->clk)) { diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c index 6217525c1000..81370c79aa48 100644 --- a/drivers/mtd/nand/denali_pci.c +++ b/drivers/mtd/nand/denali_pci.c @@ -78,14 +78,14 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) return ret; } - denali->flash_reg = ioremap_nocache(csr_base, csr_len); - if (!denali->flash_reg) { + denali->reg = ioremap_nocache(csr_base, csr_len); + if (!denali->reg) { dev_err(&dev->dev, "Spectra: Unable to remap memory region\n"); return -ENOMEM; } - denali->flash_mem = ioremap_nocache(mem_base, mem_len); - if (!denali->flash_mem) { + denali->host = ioremap_nocache(mem_base, mem_len); + if (!denali->host) { dev_err(&dev->dev, "Spectra: ioremap_nocache failed!"); ret = -ENOMEM; goto failed_remap_reg; @@ -100,9 +100,9 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) return 0; failed_remap_mem: - iounmap(denali->flash_mem); + iounmap(denali->host); failed_remap_reg: - iounmap(denali->flash_reg); + iounmap(denali->reg); return ret; } @@ -112,8 +112,8 @@ static void denali_pci_remove(struct pci_dev *dev) struct denali_nand_info *denali = pci_get_drvdata(dev); denali_remove(denali); - iounmap(denali->flash_reg); - iounmap(denali->flash_mem); + iounmap(denali->reg); + iounmap(denali->host); } static struct pci_driver denali_pci_driver = {