From patchwork Tue Nov 21 17:38:11 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119377 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5570666qgn; Tue, 21 Nov 2017 09:43:40 -0800 (PST) X-Google-Smtp-Source: AGs4zMZNBQ763t7YN0sAY3w++f+gY5SsTPdiGNsnqOPi3fS4qLjB/kLqRyiKFbLSGyE3R/n2BzI3 X-Received: by 10.80.149.253 with SMTP id x58mr25088406eda.152.1511286220441; Tue, 21 Nov 2017 09:43:40 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286220; cv=none; d=google.com; s=arc-20160816; b=PUcJZHLPMTRUj9X5Y5chwbKuAgzM1E2CPG5mplBS0a/12apw6ZTA4VPkBwvKGxSzG7 kc2RxZA8TVP9zKwmrHRFVz5xLXvvHHwkiumTkq/bQpmqX7m2TAmCq7TXXmcdaxklp0BX 1KIKX+nO4bDQB1gmmGKMQ/NkSZTaU4+va6VE9PzWBCMa/DuRRri1I7piM/4UOSUsI8mJ PXoJRHKpMWucL0hupweuZuvqZL4cgGoBO/W8sHcclwYhdD9Dpi0TkAIqjPMJR3ZdlOfa mIUFz8gLhnTrUsRmgomzoy7H/AtHhROZbJ7wEd6AUip4yJF9j2Sj19Vcv+esdssbppcN bB6w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=fSG9TXsZh69+sAMFZHNBZFtMofHcWfX9r2RdBlMyKLA=; b=HmxqfojMzRbJjVvptrtskEMmRsDfE8KLgfN2smvkCLD+HbWgB6hvVsIoXwGN5GLLQh 2ckkLCnvZB+agPAouYcsUy2KP7atPFQGGcb/OaQJn1jw69etKoI0ovemRcOk1lKZph8R oNyvoDk7SLtag4YWL46AkXZyDg684qm3QM4Uum+Bip15D29ieiVrJa1ABzTEjpnX2QwS yGdeMFKQET/DNi3LruScUI/7+GNPsgpmmrGjPc+SK8f7gPHKt4yJYxS9mIqHYsHYdpJj nhgR3Hnk2+J5urpGr/Lj0+mkO89rN1dSlW+wYluzLG2O0JOADLNlW52t3+3p6dGOuVTt Z+9A== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=YTIEKnyL; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id l63si4142105edl.104.2017.11.21.09.43.40; Tue, 21 Nov 2017 09:43:40 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=YTIEKnyL; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id DDE4DC21DEF; Tue, 21 Nov 2017 17:42:03 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 14FE5C21F71; Tue, 21 Nov 2017 17:39:26 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 40146C21DF1; Tue, 21 Nov 2017 17:39:07 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id 7FC98C21E4B for ; Tue, 21 Nov 2017 17:39:03 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbtp001225; Wed, 22 Nov 2017 02:38:38 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbtp001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285918; bh=SVoPrbEjFHzDSnLD06gkZULp6gLN2ERKJ38NxYhknh8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YTIEKnyLMPWgyDMewG2Yofmst4AbctVHrbINfF/N49tU20p92+73hVchycFDzskmz 28HCNc5SgzLGap8lBqC4TSMltYaweKgg0lFlHpkVO6JYsHfvEE7T3WuuITQQKi5DaS c4lsIoewf2M1bgRDBIfKDr66K0/iCKZGvxNDOb5WHkSQ472sHx2YWgUQLuZ1j+yFFT Uad/zYuShxQbNyC5zrTBIBQWNTjYTroZKUAsDCtmGzDNk0Vkpwxb+DVFRRJDFPRaDs waJTsUkSdLvsN65T3/oQ9hjq/JOpEeweFa9xtc7/w2xcphGBnuuAW65M1e3ODbWAF0 SUt7MICNBIXoA== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:11 +0900 Message-Id: <1511285912-12452-2-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 01/22] bitops: collect BIT macros to include/linux/bitops.h X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Same macros are defined in various places. Collect them into include/linux/bitops.h like Linux. Signed-off-by: Masahiro Yamada --- arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h | 3 ++- arch/arm/mach-kirkwood/include/mach/gpio.h | 4 ---- drivers/gpio/kw_gpio.c | 2 +- drivers/mtd/nand/nand_base.c | 2 -- include/linux/bitops.h | 7 +++++++ include/usb/lin_gadget_compat.h | 4 +--- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h b/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h index 03fd46b..66e206d 100644 --- a/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h +++ b/arch/arm/include/asm/arch-sunxi/dram_sunxi_dw.h @@ -13,6 +13,8 @@ #ifndef _SUNXI_DRAM_SUN8I_H3_H #define _SUNXI_DRAM_SUN8I_H3_H +#include + struct sunxi_mctl_com_reg { u32 cr; /* 0x00 control register */ u32 cr_r1; /* 0x04 rank 1 control register (R40 only) */ @@ -211,7 +213,6 @@ struct sunxi_mctl_ctl_reg { * the 32-bit wide access consists of. Also three control signals can be * adjusted individually. */ -#define BITS_PER_BYTE 8 #define NR_OF_BYTE_LANES (32 / BITS_PER_BYTE) /* The eight data lines (DQn) plus DM, DQS and DQSN */ #define LINES_PER_BYTE_LANE (BITS_PER_BYTE + 3) diff --git a/arch/arm/mach-kirkwood/include/mach/gpio.h b/arch/arm/mach-kirkwood/include/mach/gpio.h index aa8c5da..ac2397d 100644 --- a/arch/arm/mach-kirkwood/include/mach/gpio.h +++ b/arch/arm/mach-kirkwood/include/mach/gpio.h @@ -15,10 +15,6 @@ #ifndef __KIRKWOOD_GPIO_H #define __KIRKWOOD_GPIO_H -/* got from kernel include/linux/bitops.h */ -#define BITS_PER_BYTE 8 -#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) - #define GPIO_MAX 50 #define GPIO_OFF(pin) (((pin) >> 5) ? 0x0040 : 0x0000) #define GPIO_OUT(pin) (MVEBU_GPIO0_BASE + GPIO_OFF(pin) + 0x00) diff --git a/drivers/gpio/kw_gpio.c b/drivers/gpio/kw_gpio.c index 43b27e3..cc26cc1 100644 --- a/drivers/gpio/kw_gpio.c +++ b/drivers/gpio/kw_gpio.c @@ -14,7 +14,7 @@ */ #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 5bb4ea8..efe3e4f 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -901,8 +901,6 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) return status; } -#define BITS_PER_BYTE 8 - /** * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data * @buf: buffer to test diff --git a/include/linux/bitops.h b/include/linux/bitops.h index 576b15d..a47f6d1 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -5,9 +5,16 @@ #include #include +#ifdef __KERNEL__ #define BIT(nr) (1UL << (nr)) +#define BIT_ULL(nr) (1ULL << (nr)) #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) +#define BIT_ULL_MASK(nr) (1ULL << ((nr) % BITS_PER_LONG_LONG)) +#define BIT_ULL_WORD(nr) ((nr) / BITS_PER_LONG_LONG) +#define BITS_PER_BYTE 8 +#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) +#endif /* * Create a contiguous bitmask starting at bit position @l and ending at diff --git a/include/usb/lin_gadget_compat.h b/include/usb/lin_gadget_compat.h index 4a01585..d0d71f7 100644 --- a/include/usb/lin_gadget_compat.h +++ b/include/usb/lin_gadget_compat.h @@ -10,12 +10,10 @@ #ifndef __LIN_COMPAT_H__ #define __LIN_COMPAT_H__ +#include #include /* common */ -#define BITS_PER_BYTE 8 -#define BITS_TO_LONGS(nr) \ - DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) #define DECLARE_BITMAP(name, bits) \ unsigned long name[BITS_TO_LONGS(bits)] From patchwork Tue Nov 21 17:38:12 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119387 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5580910qgn; Tue, 21 Nov 2017 09:52:26 -0800 (PST) X-Google-Smtp-Source: AGs4zMY+itTi1o6L81Twv2DxcDqZSaRnq4NfO7+x6FDXl6sY2oAxYSyFwLYTfKk6Kk72+LhT4F+I X-Received: by 10.80.165.139 with SMTP id a11mr26230044edc.95.1511286745980; Tue, 21 Nov 2017 09:52:25 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286745; cv=none; d=google.com; s=arc-20160816; b=kKgafq9EdqkRSt2SL341gzVmaHGXiWor96S8zPRRmO/I5r1E2Wj3Wv6eb5tGlcZvRI diEuCuketgLOw87iworwRL3GFJrKZvgI8x1/4+iKAXrjfFF6Xcm2ea2jHyR727je3sUx hRnLByUChzo+V/PDppNRi5rOctzGjl6fYjg8MuQxK2Zh/GVuy+lO0UmJbBFC80ZMBBU5 Jmml2CBnE93CoGEYNFNZoTloms6LHoC5nMcUgpXqgVn/khyf7Cew8ncdFbTaxD9YW3t+ HB6goEF084ld/mb3yHVUQhyNDXaPJ6lXv5wgtU1QNquFA+NJ+P1vZ7jmLkmhvWDANCnp dSgQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=xHNPWvYUhCPnm25/PWJ+3zeQZFv+L5wLxBfn4f5CgYA=; b=HgztXfk9AdyPwv/RArd8bpstJpzkXdSQffvrZxCiE4xLDecDalnJKffEs34MAB/tXD rWn5lREgo8Hn1N1nUxQ0XDZajJPZpnJazWJPxvwPuLLwsSSLnRfE9MA+qCvsLK4/T+I4 0uCSOZkOd+jrlfutbS1lFtrsohNZ/NyQEa8K7vDOg3EFnU5gSP9KFNyNZqG37lQuLoC2 qlJ+2LF2TAoj8FJRULsz8/0Ei7qc1zyeL5hamz2uZ/erOrXiDQjDrLrR07m5iLZS3jsR csOJo+YiMxEODDyEJejrBnf47mA0FBi+qeD/0dxu/TLHQ+4pwqjQ3EDYm7hUab56Ht23 SWuw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=D8GQ8uyU; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id o91si718408eda.419.2017.11.21.09.52.25; Tue, 21 Nov 2017 09:52:25 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=D8GQ8uyU; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id 68669C21F00; Tue, 21 Nov 2017 17:51:51 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 7F680C2200C; Tue, 21 Nov 2017 17:39:45 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 7602BC21FEB; Tue, 21 Nov 2017 17:39:07 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id 13C0DC21F29 for ; Tue, 21 Nov 2017 17:39:03 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbtq001225; Wed, 22 Nov 2017 02:38:39 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbtq001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285919; bh=2dIG2K0q2qCvcGPfoBZB1Qq5lQbd5GXjDndB8bOdyuI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=D8GQ8uyUOSXV08gDTA/AqObCsDPOg2ldybpGKgMRXErkPDixiqwMJ8H4GJGOxjdSw oQaT4wG1PyCbArVoCMkZtJmFou/81LsmNmSbYqm3FGJxR81rAYApLyOfHUvdEuHFDD lG6ONnSe9gNLC40UsEd01GkNLyxRisgqWVXAVHZ/AAhtlCrc1eee9F6rU9zZJ3Jara aEX3nHd9lAYkaaOG32DIHnlSC6OGmJHWOylgx4f8/6KYmUGZwNFfnF8QnSat7DAG2k /Ybaw2s7/TZKLh7dgC+1ZQKiBCayHDUsaqHfLMzwYtpe5U9tH4mI8BKXNOHdEiTQ/d Z9d4QFpEreIQQ== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:12 +0900 Message-Id: <1511285912-12452-3-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 02/22] mtd: nand: add onfi_* stubs in case ONFI_DETECTION is disabled X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Add stubs to the header in case CONFIG_SYS_NAND_ONFI_DETECTION is disabled. This is much easier than adding around #ifdef to the caller side. Also, I removed the #ifdef around onfi_params. In Linux, onfi_params and jedec_params are unified as union. It will be the right thing to do. Signed-off-by: Masahiro Yamada --- include/linux/mtd/nand.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index d55807b..cba6563 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -741,9 +741,7 @@ struct nand_chip { int onfi_version; int jedec_version; -#ifdef CONFIG_SYS_NAND_ONFI_DETECTION struct nand_onfi_params onfi_params; -#endif struct nand_jedec_params jedec_params; int read_retries; @@ -1001,6 +999,21 @@ static inline int onfi_get_sync_timing_mode(struct nand_chip *chip) return ONFI_TIMING_MODE_UNKNOWN; return le16_to_cpu(chip->onfi_params.src_sync_timing_mode); } +#else +static inline int onfi_feature(struct nand_chip *chip) +{ + return 0; +} + +static inline int onfi_get_async_timing_mode(struct nand_chip *chip) +{ + return ONFI_TIMING_MODE_UNKNOWN; +} + +static inline int onfi_get_sync_timing_mode(struct nand_chip *chip) +{ + return ONFI_TIMING_MODE_UNKNOWN; +} #endif /* From patchwork Tue Nov 21 17:38:13 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119394 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5583947qgn; Tue, 21 Nov 2017 09:55:22 -0800 (PST) X-Google-Smtp-Source: AGs4zMbdXME/AE0mQSiXnBFyTiYabk/M6TKS8ahvjrUca+E2cP+WKLSNfeevLZak5LrHPkkKilHo X-Received: by 10.80.140.176 with SMTP id q45mr22166352edq.186.1511286922258; Tue, 21 Nov 2017 09:55:22 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286922; cv=none; d=google.com; s=arc-20160816; b=0uFnRLTxIF+BurN+frZdIm4fF+KcqnAFc/S/6rJuthCJ+bgJHLx0PFIb/OODlMCwRP vyNeSA+VHNicvpI0zBUyqTd+E8EIrQmiB4Dbv8iwqZ1v5pi8z4BrPHfOaq1n+OMImsbx 1KvUKKwBfIwUqZPqq62OnZCzTW4DsKlTGFAlMNiSCBHY4H1bNCofcK4CF2Ezs4VHvSXH 3OPI7d5s4F6qoewVOGaBUwl7N2SoTh02ehbRzb7i7T2sXNgTyhm4EdvDhxVjhYr8RCx9 JArHISYBwZUav1i82ZOs5lEh7ZLaHl0pvdgJ6Z4oTm8MLrK9SN54VwOEGIjTHPu5DWLk OG7w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=+MrRLXVoz7l4EL95sWHfGbKIT8a/nj69ueEbvptGWWA=; b=ilso+uWcV0y2x+kxQuztHMMaC7N8HcrZvK0YRlZA3GleIXXOnmz5dWDiFDqQcZ0M2g wGyIjOf8f6MxVMGb2dDzMMlHEsAZ2DO0JjBiaEHWhkQwy4vMs3jioF1DPX5uRJsI/knO v+thktMDGC8gaP9pYCDBQ8BZzOI3tIpy1YawZyqEeDo6HAyDk9fm5X7l0OioVrUY4PAH WLsEq4Tf6dG+xZbImps8fyuapyKVgbYPMso/8a9XgnNHXTtBeUVtu9Jxu9DpqKQjnsqf DH1ZRHo/R+b3dnJltmYVwmYtCgC0vZqPKW7q09XF50aJjRBjCNXDrftV4JWJ9GeLYjli MFhw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=xllqtWH0; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id i1si471286edl.225.2017.11.21.09.55.22; Tue, 21 Nov 2017 09:55:22 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=xllqtWH0; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id DD6FCC21FA9; Tue, 21 Nov 2017 17:52:52 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 4FC45C21FA9; Tue, 21 Nov 2017 17:39:53 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 654B8C22026; Tue, 21 Nov 2017 17:39:07 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id 59EE2C21F63 for ; Tue, 21 Nov 2017 17:39:04 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbtr001225; Wed, 22 Nov 2017 02:38:39 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbtr001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285919; bh=bbroGEnVbfeY6ugEp7FF+RO+7ZFWtmWZNOxadp3p9WE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=xllqtWH0PW7InNLPvkno41ydOBBqbtFUO64jaNfBCd5Nw/Gck9FTs/qOwqp/zJYId 9iNP1JNp+n9cLi12mDF6KvMw4TGEoOIfP1H+iKnqOwcdtelPFctEEqEsxl/sZ7BG0X HWxmTTEsZ2DBk96hNJXA2k9Bybhz3GTEuS3sH5epBzaKfxG9Wv/n+RxoCMk9uiKH95 JRJIhdcx9o9PUKtXUScBMy26vOnaCn+YeTKFZs45lG+vAe7jnNHdjUnUnolRWddEXr eTMfkkzgnAoR+8hUjecf/bLfX8HznaN9K8LM/kzVZTiKGixb6YEDkSK2Ubdh7VwVMt CPDH2V47KNZlg== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:13 +0900 Message-Id: <1511285912-12452-4-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 03/22] mtd: nand: Add an option to maximize the ECC strength X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Boris Brezillon The generic NAND DT bindings allows one to tweak the ECC strength and step size to their need. It can be used to lower the ECC strength to match a bootloader/firmware config, but might also be used to get a better reliability. In the latter case, the user might want to use the maximum ECC strength without having to explicitly calculate the exact value (this value not only depends on the OOB size, but also on the NAND controller, and can be tricky to extract). Add a generic 'nand-ecc-maximize' DT property and the associated NAND_ECC_MAXIMIZE flag, to let ECC controller drivers select the best ECC strength and step-size on their own. Signed-off-by: Boris Brezillon Acked-by: Rob Herring [Linux commit: ba78ee00e1ff84de9b3ad33edbd3ec599099ee82] [masahiro: of_property_read_bool -> fdt_getprop for U-Boot] Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/nand_base.c | 3 +++ include/linux/mtd/nand.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index efe3e4f..18f4169 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3817,6 +3817,9 @@ static int nand_dt_init(struct mtd_info *mtd, struct nand_chip *chip, int node) if (ecc_step > 0) chip->ecc.size = ecc_step; + if (fdt_getprop(blob, node, "nand-ecc-maximize", NULL)) + chip->ecc.options |= NAND_ECC_MAXIMIZE; + return 0; } #else diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index cba6563..eebfb13 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -153,6 +153,7 @@ typedef enum { * pages and you want to rely on the default implementation. */ #define NAND_ECC_GENERIC_ERASED_CHECK BIT(0) +#define NAND_ECC_MAXIMIZE BIT(1) /* Bit mask for flags passed to do_nand_read_ecc */ #define NAND_GET_DEVICE 0x80 From patchwork Tue Nov 21 17:38:14 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119372 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5566921qgn; Tue, 21 Nov 2017 09:40:03 -0800 (PST) X-Google-Smtp-Source: AGs4zMZ6YRVb+6ksoC8KwCJj9GXfevDd5CQA802yrmAm4Ik9zXy9zB9eIKzgz1qbdDReTCk4xZXj X-Received: by 10.80.138.99 with SMTP id i90mr26359382edi.207.1511286002960; Tue, 21 Nov 2017 09:40:02 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286002; cv=none; d=google.com; s=arc-20160816; b=uiOZiSr1O/1u9aWC2NGSQiPqwFNo2u4qCPaE/95TubSzYmUcp1qzsw9bTFyr/R5BAY CL8uyC6GScprzVVMfTa8wAaFip0c90tBe5WZIGVFopRvGjQOY0HAqJPuGdrhNYgzBiv0 hGcBVTjtlsfbQuEfHEbGgpJQa3CStzuFzpF3lwDmeO3QXMnzZcrNn9v0XGbw6O25reUu UPRVZFqUsXWjA9FBR7M+/JHlvwiPT7oA4P6foMcskt8Oc9Xj1A9olH9u/hPmqIgWdJ+2 VhtpQGbzfiVs3mqKknYDqilIuNFm/YvK6mmsviWlBQeqWw5N0WeKbnmQz9JWn2uVcObI tdFg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=dLd3orQdL2Xdi+8m7Ghql8y/NzPMn1C3JEO5+r7Ld5E=; b=IcMSk7flDYCLMenZut2qe6XHtbx7z6zZ9IcZD7ULfvA162z2DqVGTV/vJB4jpfs3AV Z1I6+jP3PAVw3x/ZJ+oNkkKQEZXuqW7MY2iWoLnvq8Y6Kn3xUFA3reUFNgUHpwmrr8zu 9i2vAr5WDaFI0qiJgMZXiVEM4dTqStveC/KyFfoAkV+Rloti8SDskYKIytULsTEhuEV5 +7VhANgh6EerRyExX26q+POcLO5kQtAVJ67rLHWSpKeh3VPkOjIoTC6sYmmjzG4Kbe/Z bDtINdCIXO5iz2E7GczPbKNCWWeaKp+c3L+xt2bEeANGbw0+4bOVatlTb6hfCWaXmUXt ZHuQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=qrjrePSZ; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id 92si11010186edh.311.2017.11.21.09.40.02; Tue, 21 Nov 2017 09:40:02 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=qrjrePSZ; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id 6D880C21F73; Tue, 21 Nov 2017 17:39:15 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 5C711C21F47; Tue, 21 Nov 2017 17:39:13 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 7864AC21C29; Tue, 21 Nov 2017 17:39:07 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id 409E3C21F00 for ; Tue, 21 Nov 2017 17:39:03 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbts001225; Wed, 22 Nov 2017 02:38:39 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbts001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285920; bh=siIrfW7skdxFxLXsSQa0hBVhmkDUp3kichovhOYUuBk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qrjrePSZyB6v+tAbT3NDz1vqo9YhWis6UAKKhG63apUrxUuYnVe6ohsuZAoAPRHdE AzH9fceEC4Nf86zTARvumTMVe4PH6aMcu9z/ObWArgohrFs45+X79E8YLazoQx4zty 63pztriovMzJ4QftkrEpgN74XG6tHMSxraC+h5FU+MylKe7LSa3KFSP2Dchw+nxsOh TdaltLw8Q9FXQin16zcJlZqE0s/0/zC3asMb6hGcBuyCx0kTnAgoJXsAqAy4qsZOco pegkeolbrbSYEMlMEH8qeTno9f8FUGbc1D6rD6s8aOKTg0JNE+jF3OEajN/UYzIjFU dTahs2oQF8ibw== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:14 +0900 Message-Id: <1511285912-12452-5-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 04/22] mtd: nand: remove unnecessary 'extern' from function declarations X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Sascha Hauer 'extern' is not necessary for function declarations. To prevent people from adding the keyword to new declarations remove the existing ones. Signed-off-by: Sascha Hauer Signed-off-by: Boris Brezillon [Linux commit: 79022591839f110f465cac0223e117b91d47d5db] Signed-off-by: Masahiro Yamada --- include/linux/mtd/nand.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index eebfb13..3facbbd 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -28,20 +28,20 @@ struct nand_flash_dev; struct device_node; /* Scan and identify a NAND device */ -extern int nand_scan(struct mtd_info *mtd, int max_chips); +int nand_scan(struct mtd_info *mtd, int max_chips); /* * Separate phases of nand_scan(), allowing board driver to intervene * and override command or ECC setup according to flash type. */ -extern int nand_scan_ident(struct mtd_info *mtd, int max_chips, +int nand_scan_ident(struct mtd_info *mtd, int max_chips, struct nand_flash_dev *table); -extern int nand_scan_tail(struct mtd_info *mtd); +int nand_scan_tail(struct mtd_info *mtd); /* Free resources held by the NAND device */ -extern void nand_release(struct mtd_info *mtd); +void nand_release(struct mtd_info *mtd); /* Internal helper for board drivers which need to override command function */ -extern void nand_wait_ready(struct mtd_info *mtd); +void nand_wait_ready(struct mtd_info *mtd); /* * This constant declares the max. oobsize / page, which @@ -899,13 +899,13 @@ struct nand_manufacturers { extern struct nand_flash_dev nand_flash_ids[]; extern struct nand_manufacturers nand_manuf_ids[]; -extern int nand_default_bbt(struct mtd_info *mtd); -extern int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs); -extern int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs); -extern int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt); -extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, +int nand_default_bbt(struct mtd_info *mtd); +int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs); +int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs); +int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt); +int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, int allowbbt); -extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, +int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf); /* From patchwork Tue Nov 21 17:38:15 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119392 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5583713qgn; Tue, 21 Nov 2017 09:55:07 -0800 (PST) X-Google-Smtp-Source: AGs4zMbVZsnUQCRiWnklCZhQY6z/fsUltRtietuuhYWcGK30mo8m2rzuod44hh97RB/ZYlRLugq/ X-Received: by 10.80.145.81 with SMTP id f17mr26223943eda.215.1511286907896; Tue, 21 Nov 2017 09:55:07 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286907; cv=none; d=google.com; s=arc-20160816; b=YqEbtjIT3WbKypaNHj96KUlZTxxSlY5/qm3kQNOWvqiJzEw+GURbtcbkBvNWhNT5Mt ha2wkNTKJlbsbPdGTSLquaoviev3MeWaV8sD/7HL5VMt+XJEAsH9b8+E8Y6Ew/9YpBwI kUUT54J5zAD2x4KoFxJ7nog+hor4Emo+tk1DZyGxvuL71dblhmunWirsxl9ztRCFyR3+ CMKHVC4g1m7i6SRB5l7KL98VbV34RNRiKcpCrWWYOdVsa/eM8xRNVBnCAs9sdXvTWUBS Zw6WgNXKt69pAADgRYTXoLsHYZT32Bdu9bwPtI1MifGG/FzyFuvcCsL2+WNN+tRwgA2e lpbA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=bJCsvgSQ3p3E7Mu8fzow4AHHa6vMybIcxR+xQtkKhjM=; b=rjiS9eZDqU5akihEA1nvkjasDL7uBt/V2NvQ9pgQojfwQbLUbh2ehblhH/ajULfcvI N9JKLAJRvyKJuw+5A4ui0OvnlSeUyhym7ie9u7WHvjcy9QafKSgdRSU/pSSm9Nnm/QWt e7Cu/fL+1PDkYpQgGxNWmYs4rV95Z66CMrnqr9ifVjvcNRqci4NxFJvz5DbAoYYesbVP qNYjXfNzlwu/sjcqjVHoT+3yUaaTOonyPvkv1pnYwgVmhOChNcOGn96Uhjl6dT79VcOA 5S3/azbSVxW8BNYk/w/KnUqLClFB4FLt5lzw0Mh5umrPe35takac63TTT7/PYhLnVhHC W2tw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=JzAQaTAR; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id n1si8764132edc.264.2017.11.21.09.55.07; Tue, 21 Nov 2017 09:55:07 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=JzAQaTAR; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id 7201FC21F00; Tue, 21 Nov 2017 17:53:08 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 7E7B5C22016; Tue, 21 Nov 2017 17:39:54 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id ABC2AC2201E; Tue, 21 Nov 2017 17:39:07 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id 3F124C21F53 for ; Tue, 21 Nov 2017 17:39:03 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbtt001225; Wed, 22 Nov 2017 02:38:40 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbtt001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285920; bh=1jQBGU950k/poGnBbnQ1cJXMrxuBLjEU3r1pRaanKlM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JzAQaTARQc7AOV5b7xaVv7u8XDbyjSO510YHlrO3vAkOZJ9EWtsHFZtNNqSgxCzIQ +IMQeGAQQH6H2yAkE091JjTdpXsWkCPxhBBiCeABR75KLl28AaG6HfA1pU85hGqy7B GeO0Eftpu3UQgPoZUjifHdozen2N2txlmbDo6w9uMw1s/731OYkDOOxdD7kYKaZbV/ cjU2JC+7Zbt+7cn+vJOhqBzUfMorCO8stc2JhnCj/v79uma295fPx922mPoYuOPjTd lKT319m98G8ZIUglS69YUi+DTeDSVn4xdZjlZTRfSTEjyI5jyoANwwln/F4hxmvpiZ GivihlM0k5Pvw== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:15 +0900 Message-Id: <1511285912-12452-6-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 05/22] mtd: nand: Create a NAND reset function X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Sascha Hauer When NAND devices are resetted some initialization may have to be done, like for example they have to be configured for the timing mode that shall be used. To get a common place where this initialization can be implemented create a nand_reset() function. This currently only issues a NAND_CMD_RESET to the NAND device. The places issuing this command manually are replaced with a call to nand_reset(). Signed-off-by: Sascha Hauer Signed-off-by: Boris Brezillon [Linux commit: 2f94abfe35b210e7711af9202a3dcfc9e779219a] Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/nand_base.c | 21 ++++++++++++++++++--- include/linux/mtd/nand.h | 4 ++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 18f4169..77da6fa 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -902,6 +902,21 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) } /** + * nand_reset - Reset and initialize a NAND device + * @chip: The NAND chip + * + * Returns 0 for success or negative error code otherwise + */ +int nand_reset(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + + return 0; +} + +/** * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data * @buf: buffer to test * @len: buffer length @@ -2591,7 +2606,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, * if we don't do this. I have no clue why, but I seem to have 'fixed' * it in the doc2000 driver in August 1999. dwmw2. */ - chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + nand_reset(chip); /* Check, if it is write protected */ if (nand_check_wp(mtd)) { @@ -3612,7 +3627,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) * after power-up. */ - chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + nand_reset(chip); /* Send the command for reading device ID */ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); @@ -3873,7 +3888,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, for (i = 1; i < maxchips; i++) { chip->select_chip(mtd, i); /* See comment in nand_get_flash_type for reset */ - chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + nand_reset(chip); /* Send the command for reading device ID */ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 3facbbd..df00fd1 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -1115,4 +1115,8 @@ int nand_check_erased_ecc_chunk(void *data, int datalen, void *ecc, int ecclen, void *extraoob, int extraooblen, int threshold); + +/* Reset and initialize a NAND device */ +int nand_reset(struct nand_chip *chip); + #endif /* __LINUX_MTD_NAND_H */ From patchwork Tue Nov 21 17:38:16 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119386 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5578875qgn; Tue, 21 Nov 2017 09:50:55 -0800 (PST) X-Google-Smtp-Source: AGs4zMbeJYRTTbqAwh/1z7dv2aNppc/sLkB+6neojCsMQto5KvUr9END36a15+1Hp1KZ3GCPvmh8 X-Received: by 10.80.131.38 with SMTP id 35mr25797743edh.291.1511286654918; Tue, 21 Nov 2017 09:50:54 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286654; cv=none; d=google.com; s=arc-20160816; b=hQzi+k2l88npgGNIId9esF8pNf/oawnUSQRG2uU2IqzJjvbUjQ73ehF+0LcPv8C0ZH owklrdVYhckEDd0UWlqkA8PwQ5Xx+lsbdhjGiT7r3G97sXZbIA9CDtFzMemkiCIBkYrm m577GFmgaH6T/I9VdAqpBn6O6QZYxTewObhN+1J+lR4ZGQGtRv0QQktOBpeBMvP2grpT eSfGwYSofQQ2nYlp+lDOpHUpqTmcgvXgWsBOOo+aeKsoEESIjn71egNlP1dE5eqGgw1C wuSMPjilzVAhW85KzJ1hHMYjVUp0c5ObmKzIQ+oY1KFKrDMM0K7I9uBH4TJOF7gdL80f eXug== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=enS+Op/g5bcvTYSwFJNSQYPJCxxzyaz8z91rdfW+wiM=; b=0OIJR5ZLMiX7yAjGiS+jME/8TaDeojHNlju6FI0JtPROi18RHXEH/CphSkdfSOzbxc uvNcfpnr8innZgKspoYqE6c7so2DFKS8HBnvzqxrzgw8KS84Pap4p22mqYl9gK8EUyig nQ+9G423exiI7LvQPW1RfxxQ/PHr9vWaeux9bitovrRO+IQorIxprMsDE8DAxEJQHQeE oBey4jLxai8HsQHfzaAMDqfzKuiGqtMdRlAq9WCqvzuWRoFaFi0OiiUaOjaLflDAik6E 9vu8PljVnrYz/1Y18saxulDLNk1KW3bDgMOz1GUIu7KtNZKZqhTeeX5Lvo7UqlCF3Fap n2CA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=fJbB28UR; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id 5si375526edl.353.2017.11.21.09.50.54; Tue, 21 Nov 2017 09:50:54 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=fJbB28UR; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id 4F908C21EE4; Tue, 21 Nov 2017 17:50:33 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 32632C21FED; Tue, 21 Nov 2017 17:39:40 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 0C2DCC21FC0; Tue, 21 Nov 2017 17:39:07 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id 270EDC21F4F for ; Tue, 21 Nov 2017 17:39:03 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbtu001225; Wed, 22 Nov 2017 02:38:40 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbtu001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285920; bh=EzYJ46V/k8Zkifi7XwEWasaIbCKFk1T7L4+ighi1pnE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fJbB28UROYF3YoL843a3l1zQXdswY/ODRXXkoZSOBGAIZeJXulDR9dyTWgeFCJxv9 20iZIPlOwcOgat6XQTHi8an0Bx2wba/fcxS68ycqK//IV22P09NGoompzwb5mZPeeE q2a5si+tTUW4aNZ17qBWD2h3oID4FpGUjd4+aZGJs1dNqCdgh1hBMIrWJO4vBUAjqp RU/alONSfpUZmY4ZRDNjJZfn4azw7rb/K5B+BbLAvGd1Ty+A5lbocrb3z2WL1An8EU hlX4UmltXzJVSaAScBTCSfldZe4o4u8Xkra23226dNbxRllDakKHNtiol/lVS3eB8B h7IFC8IpupjdQ== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:16 +0900 Message-Id: <1511285912-12452-7-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 06/22] mtd: nand: Introduce nand_data_interface X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Sascha Hauer Currently we have no data structure to fully describe a NAND timing. We only have struct nand_sdr_timings for NAND timings in SDR mode, but nothing for DDR mode and also no container to store both types of timing. This patch adds struct nand_data_interface which stores the timing type and a union of different timings. This can be used to pass to drivers in order to configure the timing. Add kerneldoc for struct nand_sdr_timings while touching it anyway. Signed-off-by: Sascha Hauer Signed-off-by: Boris Brezillon [Linux commit: eee64b700e26b9bcc6fce024681c31f5e12271fc] Signed-off-by: Masahiro Yamada --- include/linux/mtd/nand.h | 166 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 117 insertions(+), 49 deletions(-) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index df00fd1..e321e3e 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -585,6 +585,123 @@ struct nand_buffers { }; /** + * struct nand_sdr_timings - SDR NAND chip timings + * + * This struct defines the timing requirements of a SDR NAND chip. + * These information can be found in every NAND datasheets and the timings + * meaning are described in the ONFI specifications: + * www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf (chapter 4.15 Timing + * Parameters) + * + * All these timings are expressed in picoseconds. + * + * @tALH_min: ALE hold time + * @tADL_min: ALE to data loading time + * @tALS_min: ALE setup time + * @tAR_min: ALE to RE# delay + * @tCEA_max: CE# access time + * @tCEH_min: CE# high hold time + * @tCH_min: CE# hold time + * @tCHZ_max: CE# high to output hi-Z + * @tCLH_min: CLE hold time + * @tCLR_min: CLE to RE# delay + * @tCLS_min: CLE setup time + * @tCOH_min: CE# high to output hold + * @tCS_min: CE# setup time + * @tDH_min: Data hold time + * @tDS_min: Data setup time + * @tFEAT_max: Busy time for Set Features and Get Features + * @tIR_min: Output hi-Z to RE# low + * @tITC_max: Interface and Timing Mode Change time + * @tRC_min: RE# cycle time + * @tREA_max: RE# access time + * @tREH_min: RE# high hold time + * @tRHOH_min: RE# high to output hold + * @tRHW_min: RE# high to WE# low + * @tRHZ_max: RE# high to output hi-Z + * @tRLOH_min: RE# low to output hold + * @tRP_min: RE# pulse width + * @tRR_min: Ready to RE# low (data only) + * @tRST_max: Device reset time, measured from the falling edge of R/B# to the + * rising edge of R/B#. + * @tWB_max: WE# high to SR[6] low + * @tWC_min: WE# cycle time + * @tWH_min: WE# high hold time + * @tWHR_min: WE# high to RE# low + * @tWP_min: WE# pulse width + * @tWW_min: WP# transition to WE# low + */ +struct nand_sdr_timings { + u32 tALH_min; + u32 tADL_min; + u32 tALS_min; + u32 tAR_min; + u32 tCEA_max; + u32 tCEH_min; + u32 tCH_min; + u32 tCHZ_max; + u32 tCLH_min; + u32 tCLR_min; + u32 tCLS_min; + u32 tCOH_min; + u32 tCS_min; + u32 tDH_min; + u32 tDS_min; + u32 tFEAT_max; + u32 tIR_min; + u32 tITC_max; + u32 tRC_min; + u32 tREA_max; + u32 tREH_min; + u32 tRHOH_min; + u32 tRHW_min; + u32 tRHZ_max; + u32 tRLOH_min; + u32 tRP_min; + u32 tRR_min; + u64 tRST_max; + u32 tWB_max; + u32 tWC_min; + u32 tWH_min; + u32 tWHR_min; + u32 tWP_min; + u32 tWW_min; +}; + +/** + * enum nand_data_interface_type - NAND interface timing type + * @NAND_SDR_IFACE: Single Data Rate interface + */ +enum nand_data_interface_type { + NAND_SDR_IFACE, +}; + +/** + * struct nand_data_interface - NAND interface timing + * @type: type of the timing + * @timings: The timing, type according to @type + */ +struct nand_data_interface { + enum nand_data_interface_type type; + union { + struct nand_sdr_timings sdr; + } timings; +}; + +/** + * nand_get_sdr_timings - get SDR timing from data interface + * @conf: The data interface + */ +static inline const struct nand_sdr_timings * +nand_get_sdr_timings(const struct nand_data_interface *conf) +{ + if (conf->type != NAND_SDR_IFACE) + return ERR_PTR(-EINVAL); + + return &conf->timings.sdr; +} + +/** * struct nand_chip - NAND Private Flash Chip Data * @mtd: MTD device registered to the MTD framework * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the @@ -1059,55 +1176,6 @@ void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len); void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len); uint8_t nand_read_byte(struct mtd_info *mtd); -/* - * struct nand_sdr_timings - SDR NAND chip timings - * - * This struct defines the timing requirements of a SDR NAND chip. - * These informations can be found in every NAND datasheets and the timings - * meaning are described in the ONFI specifications: - * www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf (chapter 4.15 Timing - * Parameters) - * - * All these timings are expressed in picoseconds. - */ - -struct nand_sdr_timings { - u32 tALH_min; - u32 tADL_min; - u32 tALS_min; - u32 tAR_min; - u32 tCEA_max; - u32 tCEH_min; - u32 tCH_min; - u32 tCHZ_max; - u32 tCLH_min; - u32 tCLR_min; - u32 tCLS_min; - u32 tCOH_min; - u32 tCS_min; - u32 tDH_min; - u32 tDS_min; - u32 tFEAT_max; - u32 tIR_min; - u32 tITC_max; - u32 tRC_min; - u32 tREA_max; - u32 tREH_min; - u32 tRHOH_min; - u32 tRHW_min; - u32 tRHZ_max; - u32 tRLOH_min; - u32 tRP_min; - u32 tRR_min; - u64 tRST_max; - u32 tWB_max; - u32 tWC_min; - u32 tWH_min; - u32 tWHR_min; - u32 tWP_min; - u32 tWW_min; -}; - /* get timing characteristics from ONFI timing mode. */ const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode); From patchwork Tue Nov 21 17:38:17 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119388 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5581194qgn; Tue, 21 Nov 2017 09:52:39 -0800 (PST) X-Google-Smtp-Source: AGs4zMYEI9zzdOSUe/DY+M9Do+8iF5joQoaTvRpr895O91pajv2YYN1OslqXObZq+Pr71yU7yNMg X-Received: by 10.80.162.103 with SMTP id 94mr25413908edl.159.1511286759019; Tue, 21 Nov 2017 09:52:39 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286759; cv=none; d=google.com; s=arc-20160816; b=1LmKhKR55wD9R62X0+kip5J11qHFy2xOXQ81OGgbWCGZSQc1xt1vilXmXqzwBZM2Ds B8frjfXc+EbKrWfMQcnFe288gMxUnyYbNg1NxvegQPZSp+Qtm4ozLe4f5T7HrNmtpv6h TfciGH44jI1l7tyw8cjKSRBlImW2+xau+H0PH0L4Q3BHXjwf4wEigPCr373odoupe4zj uB/1W5jsmFVxNHxZO3cLq/Ow7BBTav0LKsHNKphNHgZ5XByhLSBOPoi3wxcHzchSN7Xn ZOCV9RYfoKBnX3/2LTpDvdNdM8zGLDFXlqngL3EzA+4XLuVtBJ9TacgaQc0VftjH7/6k ws+Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=o8CpXC1LJtKVRttFEU4RXHPCqZcwJx564+Giqed2wro=; b=SsflCA90MD86hm1fyrPa5fNzDwRNPwMYKKSNAMNQwNq99T3l/gTeo59ZxhHSkGhfBD cYvVPaiK4YpxE+rMJIgQu9QRjfDEbpihJftW09Myc1RgNk+T8gpFYMW20EjV2jOGyq9D Qm5FnPiqsZse0nKFnGsSEnT+nkkWNlb24UntybhAOWqIq3hFd9OKmJOvvZsSQ2KAm0tt TCxyBURMeW1lw4cQE/ih/FswdzASHJ+P49OW0i0KFxrFH/l6nItP9Ntf1yYiOjSl08ry +abtXVEW6Q2fm05SWVsOnwWOB6qSnqHpKNNhpxj/iCZCSZ1OiBuGiiVflg0OEIqFfxW6 uDjg== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=KG35PoU0; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id b35si12092693edb.0.2017.11.21.09.52.38; Tue, 21 Nov 2017 09:52:39 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=KG35PoU0; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id 9A6A1C21E4B; Tue, 21 Nov 2017 17:50:57 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id A393CC21FFC; Tue, 21 Nov 2017 17:39:41 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id B90FEC21F62; Tue, 21 Nov 2017 17:39:08 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id F3858C21EA8 for ; Tue, 21 Nov 2017 17:39:07 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbtv001225; Wed, 22 Nov 2017 02:38:41 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbtv001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285921; bh=6mS6HkM/r64MMmXK1cyVxaRo+iU8tLSwWd8in7CsSUM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KG35PoU02q+00q3jrz6uP/FE7UBmd2OpWH6WJuagooSljjQDa3Oxh4FZubuYMJ9zY wQaya9qqWcvT51p2DbWu/AZV5Y3ffDd371P+1skkSUlYjrpq4zhDDguerN5oLLgtpM GynkqcCde+BTVp0QRql93pBxBXnfKvxn6Z6VEMbamfh0irWsEUZ323btuWpXlKfq3w xRiZ7q0MAEfHtiUSf+UwEfkUvtWtDRDW8pH4xTO/2/ZBsP3uxZv/occ+gICbiVrzav Q8Hr8EeELQ/p85Zr4RPhRGAPW9IagI8oGqldoU+sDzrvmCj7/DSoVCAAeIGA5e0LN3 RA7NEP2/NmHKA== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:17 +0900 Message-Id: <1511285912-12452-8-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 07/22] mtd: nand: convert ONFI mode into data interface X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Sascha Hauer struct nand_data_interface is the designated type to pass to the NAND drivers to configure the timing. To simplify further patches convert the onfi_sdr_timings array from type struct nand_sdr_timings nand_data_interface. Signed-off-by: Sascha Hauer Signed-off-by: Boris Brezillon [Linux commit: b1dd3ca203fccd111926c3f6ac59bf903ec62b05] Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/nand_timings.c | 459 ++++++++++++++++++++++------------------ include/linux/mtd/nand.h | 5 + 2 files changed, 258 insertions(+), 206 deletions(-) diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c index 53dcbd3..b055d27 100644 --- a/drivers/mtd/nand/nand_timings.c +++ b/drivers/mtd/nand/nand_timings.c @@ -12,228 +12,246 @@ #include #include -static const struct nand_sdr_timings onfi_sdr_timings[] = { +static const struct nand_data_interface onfi_sdr_timings[] = { /* Mode 0 */ { - .tADL_min = 200000, - .tALH_min = 20000, - .tALS_min = 50000, - .tAR_min = 25000, - .tCEA_max = 100000, - .tCEH_min = 20000, - .tCH_min = 20000, - .tCHZ_max = 100000, - .tCLH_min = 20000, - .tCLR_min = 20000, - .tCLS_min = 50000, - .tCOH_min = 0, - .tCS_min = 70000, - .tDH_min = 20000, - .tDS_min = 40000, - .tFEAT_max = 1000000, - .tIR_min = 10000, - .tITC_max = 1000000, - .tRC_min = 100000, - .tREA_max = 40000, - .tREH_min = 30000, - .tRHOH_min = 0, - .tRHW_min = 200000, - .tRHZ_max = 200000, - .tRLOH_min = 0, - .tRP_min = 50000, - .tRST_max = 250000000000ULL, - .tWB_max = 200000, - .tRR_min = 40000, - .tWC_min = 100000, - .tWH_min = 30000, - .tWHR_min = 120000, - .tWP_min = 50000, - .tWW_min = 100000, + .type = NAND_SDR_IFACE, + .timings.sdr = { + .tADL_min = 400000, + .tALH_min = 20000, + .tALS_min = 50000, + .tAR_min = 25000, + .tCEA_max = 100000, + .tCEH_min = 20000, + .tCH_min = 20000, + .tCHZ_max = 100000, + .tCLH_min = 20000, + .tCLR_min = 20000, + .tCLS_min = 50000, + .tCOH_min = 0, + .tCS_min = 70000, + .tDH_min = 20000, + .tDS_min = 40000, + .tFEAT_max = 1000000, + .tIR_min = 10000, + .tITC_max = 1000000, + .tRC_min = 100000, + .tREA_max = 40000, + .tREH_min = 30000, + .tRHOH_min = 0, + .tRHW_min = 200000, + .tRHZ_max = 200000, + .tRLOH_min = 0, + .tRP_min = 50000, + .tRR_min = 40000, + .tRST_max = 250000000000ULL, + .tWB_max = 200000, + .tWC_min = 100000, + .tWH_min = 30000, + .tWHR_min = 120000, + .tWP_min = 50000, + .tWW_min = 100000, + }, }, /* Mode 1 */ { - .tADL_min = 100000, - .tALH_min = 10000, - .tALS_min = 25000, - .tAR_min = 10000, - .tCEA_max = 45000, - .tCEH_min = 20000, - .tCH_min = 10000, - .tCHZ_max = 50000, - .tCLH_min = 10000, - .tCLR_min = 10000, - .tCLS_min = 25000, - .tCOH_min = 15000, - .tCS_min = 35000, - .tDH_min = 10000, - .tDS_min = 20000, - .tFEAT_max = 1000000, - .tIR_min = 0, - .tITC_max = 1000000, - .tRC_min = 50000, - .tREA_max = 30000, - .tREH_min = 15000, - .tRHOH_min = 15000, - .tRHW_min = 100000, - .tRHZ_max = 100000, - .tRLOH_min = 0, - .tRP_min = 25000, - .tRR_min = 20000, - .tRST_max = 500000000, - .tWB_max = 100000, - .tWC_min = 45000, - .tWH_min = 15000, - .tWHR_min = 80000, - .tWP_min = 25000, - .tWW_min = 100000, + .type = NAND_SDR_IFACE, + .timings.sdr = { + .tADL_min = 400000, + .tALH_min = 10000, + .tALS_min = 25000, + .tAR_min = 10000, + .tCEA_max = 45000, + .tCEH_min = 20000, + .tCH_min = 10000, + .tCHZ_max = 50000, + .tCLH_min = 10000, + .tCLR_min = 10000, + .tCLS_min = 25000, + .tCOH_min = 15000, + .tCS_min = 35000, + .tDH_min = 10000, + .tDS_min = 20000, + .tFEAT_max = 1000000, + .tIR_min = 0, + .tITC_max = 1000000, + .tRC_min = 50000, + .tREA_max = 30000, + .tREH_min = 15000, + .tRHOH_min = 15000, + .tRHW_min = 100000, + .tRHZ_max = 100000, + .tRLOH_min = 0, + .tRP_min = 25000, + .tRR_min = 20000, + .tRST_max = 500000000, + .tWB_max = 100000, + .tWC_min = 45000, + .tWH_min = 15000, + .tWHR_min = 80000, + .tWP_min = 25000, + .tWW_min = 100000, + }, }, /* Mode 2 */ { - .tADL_min = 100000, - .tALH_min = 10000, - .tALS_min = 15000, - .tAR_min = 10000, - .tCEA_max = 30000, - .tCEH_min = 20000, - .tCH_min = 10000, - .tCHZ_max = 50000, - .tCLH_min = 10000, - .tCLR_min = 10000, - .tCLS_min = 15000, - .tCOH_min = 15000, - .tCS_min = 25000, - .tDH_min = 5000, - .tDS_min = 15000, - .tFEAT_max = 1000000, - .tIR_min = 0, - .tITC_max = 1000000, - .tRC_min = 35000, - .tREA_max = 25000, - .tREH_min = 15000, - .tRHOH_min = 15000, - .tRHW_min = 100000, - .tRHZ_max = 100000, - .tRLOH_min = 0, - .tRR_min = 20000, - .tRST_max = 500000000, - .tWB_max = 100000, - .tRP_min = 17000, - .tWC_min = 35000, - .tWH_min = 15000, - .tWHR_min = 80000, - .tWP_min = 17000, - .tWW_min = 100000, + .type = NAND_SDR_IFACE, + .timings.sdr = { + .tADL_min = 400000, + .tALH_min = 10000, + .tALS_min = 15000, + .tAR_min = 10000, + .tCEA_max = 30000, + .tCEH_min = 20000, + .tCH_min = 10000, + .tCHZ_max = 50000, + .tCLH_min = 10000, + .tCLR_min = 10000, + .tCLS_min = 15000, + .tCOH_min = 15000, + .tCS_min = 25000, + .tDH_min = 5000, + .tDS_min = 15000, + .tFEAT_max = 1000000, + .tIR_min = 0, + .tITC_max = 1000000, + .tRC_min = 35000, + .tREA_max = 25000, + .tREH_min = 15000, + .tRHOH_min = 15000, + .tRHW_min = 100000, + .tRHZ_max = 100000, + .tRLOH_min = 0, + .tRR_min = 20000, + .tRST_max = 500000000, + .tWB_max = 100000, + .tRP_min = 17000, + .tWC_min = 35000, + .tWH_min = 15000, + .tWHR_min = 80000, + .tWP_min = 17000, + .tWW_min = 100000, + }, }, /* Mode 3 */ { - .tADL_min = 100000, - .tALH_min = 5000, - .tALS_min = 10000, - .tAR_min = 10000, - .tCEA_max = 25000, - .tCEH_min = 20000, - .tCH_min = 5000, - .tCHZ_max = 50000, - .tCLH_min = 5000, - .tCLR_min = 10000, - .tCLS_min = 10000, - .tCOH_min = 15000, - .tCS_min = 25000, - .tDH_min = 5000, - .tDS_min = 10000, - .tFEAT_max = 1000000, - .tIR_min = 0, - .tITC_max = 1000000, - .tRC_min = 30000, - .tREA_max = 20000, - .tREH_min = 10000, - .tRHOH_min = 15000, - .tRHW_min = 100000, - .tRHZ_max = 100000, - .tRLOH_min = 0, - .tRP_min = 15000, - .tRR_min = 20000, - .tRST_max = 500000000, - .tWB_max = 100000, - .tWC_min = 30000, - .tWH_min = 10000, - .tWHR_min = 80000, - .tWP_min = 15000, - .tWW_min = 100000, + .type = NAND_SDR_IFACE, + .timings.sdr = { + .tADL_min = 400000, + .tALH_min = 5000, + .tALS_min = 10000, + .tAR_min = 10000, + .tCEA_max = 25000, + .tCEH_min = 20000, + .tCH_min = 5000, + .tCHZ_max = 50000, + .tCLH_min = 5000, + .tCLR_min = 10000, + .tCLS_min = 10000, + .tCOH_min = 15000, + .tCS_min = 25000, + .tDH_min = 5000, + .tDS_min = 10000, + .tFEAT_max = 1000000, + .tIR_min = 0, + .tITC_max = 1000000, + .tRC_min = 30000, + .tREA_max = 20000, + .tREH_min = 10000, + .tRHOH_min = 15000, + .tRHW_min = 100000, + .tRHZ_max = 100000, + .tRLOH_min = 0, + .tRP_min = 15000, + .tRR_min = 20000, + .tRST_max = 500000000, + .tWB_max = 100000, + .tWC_min = 30000, + .tWH_min = 10000, + .tWHR_min = 80000, + .tWP_min = 15000, + .tWW_min = 100000, + }, }, /* Mode 4 */ { - .tADL_min = 70000, - .tALH_min = 5000, - .tALS_min = 10000, - .tAR_min = 10000, - .tCEA_max = 25000, - .tCEH_min = 20000, - .tCH_min = 5000, - .tCHZ_max = 30000, - .tCLH_min = 5000, - .tCLR_min = 10000, - .tCLS_min = 10000, - .tCOH_min = 15000, - .tCS_min = 20000, - .tDH_min = 5000, - .tDS_min = 10000, - .tFEAT_max = 1000000, - .tIR_min = 0, - .tITC_max = 1000000, - .tRC_min = 25000, - .tREA_max = 20000, - .tREH_min = 10000, - .tRHOH_min = 15000, - .tRHW_min = 100000, - .tRHZ_max = 100000, - .tRLOH_min = 5000, - .tRP_min = 12000, - .tRR_min = 20000, - .tRST_max = 500000000, - .tWB_max = 100000, - .tWC_min = 25000, - .tWH_min = 10000, - .tWHR_min = 80000, - .tWP_min = 12000, - .tWW_min = 100000, + .type = NAND_SDR_IFACE, + .timings.sdr = { + .tADL_min = 400000, + .tALH_min = 5000, + .tALS_min = 10000, + .tAR_min = 10000, + .tCEA_max = 25000, + .tCEH_min = 20000, + .tCH_min = 5000, + .tCHZ_max = 30000, + .tCLH_min = 5000, + .tCLR_min = 10000, + .tCLS_min = 10000, + .tCOH_min = 15000, + .tCS_min = 20000, + .tDH_min = 5000, + .tDS_min = 10000, + .tFEAT_max = 1000000, + .tIR_min = 0, + .tITC_max = 1000000, + .tRC_min = 25000, + .tREA_max = 20000, + .tREH_min = 10000, + .tRHOH_min = 15000, + .tRHW_min = 100000, + .tRHZ_max = 100000, + .tRLOH_min = 5000, + .tRP_min = 12000, + .tRR_min = 20000, + .tRST_max = 500000000, + .tWB_max = 100000, + .tWC_min = 25000, + .tWH_min = 10000, + .tWHR_min = 80000, + .tWP_min = 12000, + .tWW_min = 100000, + }, }, /* Mode 5 */ { - .tADL_min = 70000, - .tALH_min = 5000, - .tALS_min = 10000, - .tAR_min = 10000, - .tCEA_max = 25000, - .tCEH_min = 20000, - .tCH_min = 5000, - .tCHZ_max = 30000, - .tCLH_min = 5000, - .tCLR_min = 10000, - .tCLS_min = 10000, - .tCOH_min = 15000, - .tCS_min = 15000, - .tDH_min = 5000, - .tDS_min = 7000, - .tFEAT_max = 1000000, - .tIR_min = 0, - .tITC_max = 1000000, - .tRC_min = 20000, - .tREA_max = 16000, - .tREH_min = 7000, - .tRHOH_min = 15000, - .tRHW_min = 100000, - .tRHZ_max = 100000, - .tRLOH_min = 5000, - .tRP_min = 10000, - .tRR_min = 20000, - .tRST_max = 500000000, - .tWB_max = 100000, - .tWC_min = 20000, - .tWH_min = 7000, - .tWHR_min = 80000, - .tWP_min = 10000, - .tWW_min = 100000, + .type = NAND_SDR_IFACE, + .timings.sdr = { + .tADL_min = 400000, + .tALH_min = 5000, + .tALS_min = 10000, + .tAR_min = 10000, + .tCEA_max = 25000, + .tCEH_min = 20000, + .tCH_min = 5000, + .tCHZ_max = 30000, + .tCLH_min = 5000, + .tCLR_min = 10000, + .tCLS_min = 10000, + .tCOH_min = 15000, + .tCS_min = 15000, + .tDH_min = 5000, + .tDS_min = 7000, + .tFEAT_max = 1000000, + .tIR_min = 0, + .tITC_max = 1000000, + .tRC_min = 20000, + .tREA_max = 16000, + .tREH_min = 7000, + .tRHOH_min = 15000, + .tRHW_min = 100000, + .tRHZ_max = 100000, + .tRLOH_min = 5000, + .tRP_min = 10000, + .tRR_min = 20000, + .tRST_max = 500000000, + .tWB_max = 100000, + .tWC_min = 20000, + .tWH_min = 7000, + .tWHR_min = 80000, + .tWP_min = 10000, + .tWW_min = 100000, + }, }, }; @@ -247,6 +265,35 @@ const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode) if (mode < 0 || mode >= ARRAY_SIZE(onfi_sdr_timings)) return ERR_PTR(-EINVAL); - return &onfi_sdr_timings[mode]; + return &onfi_sdr_timings[mode].timings.sdr; } EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings); + +/** + * onfi_init_data_interface - [NAND Interface] Initialize a data interface from + * given ONFI mode + * @iface: The data interface to be initialized + * @mode: The ONFI timing mode + */ +int onfi_init_data_interface(struct nand_chip *chip, + struct nand_data_interface *iface, + enum nand_data_interface_type type, + int timing_mode) +{ + if (type != NAND_SDR_IFACE) + return -EINVAL; + + if (timing_mode < 0 || timing_mode >= ARRAY_SIZE(onfi_sdr_timings)) + return -EINVAL; + + *iface = onfi_sdr_timings[timing_mode]; + + /* + * TODO: initialize timings that cannot be deduced from timing mode: + * tR, tPROG, tCCS, ... + * These information are part of the ONFI parameter page. + */ + + return 0; +} +EXPORT_SYMBOL(onfi_init_data_interface); diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index e321e3e..a633fd0 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -1134,6 +1134,11 @@ static inline int onfi_get_sync_timing_mode(struct nand_chip *chip) } #endif +int onfi_init_data_interface(struct nand_chip *chip, + struct nand_data_interface *iface, + enum nand_data_interface_type type, + int timing_mode); + /* * Check if it is a SLC nand. * The !nand_is_slc() can be used to check the MLC/TLC nand chips. From patchwork Tue Nov 21 17:38:18 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119373 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5567177qgn; Tue, 21 Nov 2017 09:40:19 -0800 (PST) X-Google-Smtp-Source: AGs4zMbeDv1qKqz0Yp2ViTTDLlupCEP/sqsd22UAyhL4c1h11fD0um7o/Q3aoH7Duohs6tLPn1Uk X-Received: by 10.80.158.196 with SMTP id a62mr25661540edf.307.1511286019102; Tue, 21 Nov 2017 09:40:19 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286019; cv=none; d=google.com; s=arc-20160816; b=X69pUWckz6XXYGEgmq2hdWB9X6cEQ4JvuiEizbpaOE1iqc/sr0sW71PfCYoljn/iAK qRGnYgoEYZFH5ECl8JL9ej45b0uVttLOWtjgcS98CmTDhfHCBmpk6j/blw4H/7Uw10YE kQkoh7Cg5JIBeZdZhGXuLaT5BhCDZJzri+mdnQFy2t+22BhBAApkl4hFsXhVc8QIjinU 3t3XLF+o1JewdtZsp9UxXK48pFPlHt780BHax5FcWKuV7jsyJBus5+3fVA3ybrJiSfgC 8YPnH/julUzFvs/eAaYHu0GCqb0JbDd8M0mS7Wn4aNpCIDRWle8sacHeyQcO3ZxFY8SG nQcQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=SBuWZL5lqZ6YDxWh3x2Jhhw7Kev4Qve6A66nFs/ILuA=; b=Fu2IEGFnpJoBZ8gum/vMge0I/TizbWJ8JQTbK4yBlF2cThsSBJgN4Ewyys1wYqeQYw ftTIyVOqYd+fayl/RyW+i2iagMAHlqGWHraLyMYaNSS9JgYJ6ajwFXCpT2/79WNAJ627 IAeiDTx3DQ/S16gwgVKYz/aphVWu6StJ57c343giuRnrGV775cBJMf4V8n4s/ihrgpW+ 5hIBNr5g8zBBeN7DiKSz1FPXR+zxEqya1JHHGxii6u+JnezUyfvEflez6E3R7ysdzhqf B3KAnQtTJ7lKsvwr7G8AknbiLQs4Zj8oHVZUgDQ8SgSsw5hx0XAoAaaAZ/FDLYvC0GLu hUVw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=F//ENyM+; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id q3si1740208edj.165.2017.11.21.09.40.18; Tue, 21 Nov 2017 09:40:19 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=F//ENyM+; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id B00A2C21FEB; Tue, 21 Nov 2017 17:39:36 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id C1027C21E4B; Tue, 21 Nov 2017 17:39:15 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 44D7CC21EDC; Tue, 21 Nov 2017 17:39:08 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id 91B79C21EE7 for ; Tue, 21 Nov 2017 17:39:06 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbtw001225; Wed, 22 Nov 2017 02:38:41 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbtw001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285921; bh=1QaXQ1MrlG92tduZMe459UA13Y3YeIMEcxABALM5b8M=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=F//ENyM+R7PddsQfVPFeKiUg68FOJ8/Kp0FqjLkWK+LBwV3WOBbb6YfT6Ogb8JcJc ykMg9UesycPaCbBIGR9S992c/4xDnn/08nPx/U/qDJY10KNbj+Fe3Cfjw07m7eB2xi 9TsWNJcPbVSkT4ilcRDSzakuwLt9W4mUoYGC16LquG4PMdatqK4bXP194bccTiuTCA SkjymRSjzvl5UNGSeuRzx2BYU2qxUilHAOdNRYBoBwJfv6S68YGmhr7Mdhc994JMoQ XEh5F5bZGw3YKXuEB9SDJdu8CeeNuDVkcmEyQBpyVaZbCxT9Ny5LyvD72/+T/uC2cc Qpg+uO8cMh0Lw== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:18 +0900 Message-Id: <1511285912-12452-9-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 08/22] mtd: nand: Expose data interface for ONFI mode 0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Sascha Hauer The nand layer will need ONFI mode 0 to use it as timing mode before and right after reset. Signed-off-by: Sascha Hauer Signed-off-by: Boris Brezillon [Linux commit: 6e1f9708dbf3c50a8da93c1952a01a7a2acb5e66] Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/nand_timings.c | 11 +++++++++++ include/linux/mtd/nand.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c index b055d27..ba4f22f 100644 --- a/drivers/mtd/nand/nand_timings.c +++ b/drivers/mtd/nand/nand_timings.c @@ -297,3 +297,14 @@ int onfi_init_data_interface(struct nand_chip *chip, return 0; } EXPORT_SYMBOL(onfi_init_data_interface); + +/** + * nand_get_default_data_interface - [NAND Interface] Retrieve NAND + * data interface for mode 0. This is used as default timing after + * reset. + */ +const struct nand_data_interface *nand_get_default_data_interface(void) +{ + return &onfi_sdr_timings[0]; +} +EXPORT_SYMBOL(nand_get_default_data_interface); diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index a633fd0..0b9fe3f 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -1183,6 +1183,8 @@ uint8_t nand_read_byte(struct mtd_info *mtd); /* get timing characteristics from ONFI timing mode. */ const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode); +/* get data interface from ONFI timing mode 0, used after reset. */ +const struct nand_data_interface *nand_get_default_data_interface(void); int nand_check_erased_ecc_chunk(void *data, int datalen, void *ecc, int ecclen, From patchwork Tue Nov 21 17:38:19 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119383 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5575642qgn; Tue, 21 Nov 2017 09:48:37 -0800 (PST) X-Google-Smtp-Source: AGs4zMayzumtP5ZBO2ujz5noYlv+yjfbDsQKil4PdCdJgwh6bFNhOtyonvQwtrRj0b+TCAaxvsHt X-Received: by 10.80.142.17 with SMTP id 17mr26553846edw.147.1511286516979; Tue, 21 Nov 2017 09:48:36 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286516; cv=none; d=google.com; s=arc-20160816; b=BEEyxs93DNC0et74j18/d0An/rVysbhRSS6Yr/X3lmoE0jEwfPaqp3EXtp2aPRlLuK IF1FSLwsPsb+JZTzAyUcjGGUaK6negGOBQXxUumjLmPh6oubymjdmALI5Wi0u5LceyS/ 3gYxlZsEn+gqnI9We/KYFI0VKilNd3PAc2iWLD9c5lXz5lMBzrZwbNfpi9O49L+mUsHn yqByuUZreQDRt1uToZrAFWJMEzHrOAJJDamxiSmPROseuXdy7Hpi0ttytIThuwjVCwWZ AKkw8GMDr1AmpDEEgcU9d2r+38V/XsSyK842/zKwPz2+zNsgYedCw//D6oPDOLH31Zam zrUg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=ZjNp1mqJbPQaW5/Yg6X2LNhjHWsN6hv3Je+KFyfMHgA=; b=sQOp4niSnuhuaYp+6Y/6kqXQ74EM4FxHbd624U7XslVQb4I4YARwWF//HlNFK0HHp9 yQ+UmmDmlgX+dFcz3in51MAjX3EoBee3S3FqUEdvJhC0HfveHWN4YE5jf1GweVxb1zfR G32CDP0FUKjxjOEpJajN7ySTLkcIfAexa30vcBa8oUyb7JUVp6I/tMsQdZ//lzJab3De Ys3InX0Hz8ATmADHtlrX5tmHZ9ZIiQgEoYAU5LBR0zB4O96WV3/9CVJ6eYJEa8n3pN1a AFGGbXutj4IZyqBmNV/+vZZFblhuryGGjaz6xHsvoxVQQmobOeXZGI5y6qWCskrmINrb 3VPQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=gXpW5YQy; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id m33si4368379ede.423.2017.11.21.09.48.36; Tue, 21 Nov 2017 09:48:36 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=gXpW5YQy; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id 4A5F9C21FC0; Tue, 21 Nov 2017 17:42:21 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id A5B8CC21F7D; Tue, 21 Nov 2017 17:39:28 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 91549C21DDF; Tue, 21 Nov 2017 17:39:07 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id 5F23DC21F64 for ; Tue, 21 Nov 2017 17:39:06 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbtx001225; Wed, 22 Nov 2017 02:38:41 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbtx001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285922; bh=Qf/4JwmQwa+V1nnlF8o6kIlAJiQ2SmS37CaSduz93/Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gXpW5YQyhdtjnYQdNo1z/V4tGKODEdSOgOy7eWAXUuLCn0Yf2de83sy8d2im/HYxH HeMrXEAFEzl+9Q89CryTwM9OL93684tcOd+dMY8Vipra1t+h0Kj9DL2IJVYxeT1iwI nTK9gXXitJffmZiWfPxQZ+SYbqNmnrmKsf27Hha6awL6mniELGeaRstrAklJO3oJOm 6dngFbNSmlf0V3jtNt7GYBIvQzY1eLUzM54r4f/9XilUzoFgq3dy4U1kopNPcPbBwd KJV/SkwambwHyDNFnNaAK4/qfDAfWRlrFaD7iu1pLRRiEhJQju53GffL4pApTJebFJ 24b0i8uaKajGQ== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:19 +0900 Message-Id: <1511285912-12452-10-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 09/22] mtd: nand: automate NAND timings selection X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Boris Brezillon The NAND framework provides several helpers to query timing modes supported by a NAND chip, but this implies that all NAND controller drivers have to implement the same timings selection dance. Also currently NAND devices can be resetted at arbitrary places which also resets the timing for ONFI chips to timing mode 0. Provide a common logic to select the best timings based on ONFI or ->onfi_timing_mode_default information. Hook this into nand_reset() to make sure the new timing is applied each time during a reset. NAND controller willing to support timings adjustment should just implement the ->setup_data_interface() method. Signed-off-by: Boris Brezillon Signed-off-by: Sascha Hauer [Linux commit: d8e725dd831186a3595036b2b1df9f68cbc6efa3] Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/nand_base.c | 155 +++++++++++++++++++++++++++++++++++++++++++ include/linux/mtd/nand.h | 14 ++-- 2 files changed, 165 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 77da6fa..f452f59 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -902,6 +902,148 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) } /** + * nand_reset_data_interface - Reset data interface and timings + * @chip: The NAND chip + * + * Reset the Data interface and timings to ONFI mode 0. + * + * Returns 0 for success or negative error code otherwise. + */ +static int nand_reset_data_interface(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + const struct nand_data_interface *conf; + int ret; + + if (!chip->setup_data_interface) + return 0; + + /* + * The ONFI specification says: + * " + * To transition from NV-DDR or NV-DDR2 to the SDR data + * interface, the host shall use the Reset (FFh) command + * using SDR timing mode 0. A device in any timing mode is + * required to recognize Reset (FFh) command issued in SDR + * timing mode 0. + * " + * + * Configure the data interface in SDR mode and set the + * timings to timing mode 0. + */ + + conf = nand_get_default_data_interface(); + ret = chip->setup_data_interface(mtd, conf, false); + if (ret) + pr_err("Failed to configure data interface to SDR timing mode 0\n"); + + return ret; +} + +/** + * nand_setup_data_interface - Setup the best data interface and timings + * @chip: The NAND chip + * + * Find and configure the best data interface and NAND timings supported by + * the chip and the driver. + * First tries to retrieve supported timing modes from ONFI information, + * and if the NAND chip does not support ONFI, relies on the + * ->onfi_timing_mode_default specified in the nand_ids table. + * + * Returns 0 for success or negative error code otherwise. + */ +static int nand_setup_data_interface(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + int ret; + + if (!chip->setup_data_interface || !chip->data_interface) + return 0; + + /* + * Ensure the timing mode has been changed on the chip side + * before changing timings on the controller side. + */ + if (chip->onfi_version) { + u8 tmode_param[ONFI_SUBFEATURE_PARAM_LEN] = { + chip->onfi_timing_mode_default, + }; + + ret = chip->onfi_set_features(mtd, chip, + ONFI_FEATURE_ADDR_TIMING_MODE, + tmode_param); + if (ret) + goto err; + } + + ret = chip->setup_data_interface(mtd, chip->data_interface, false); +err: + return ret; +} + +/** + * nand_init_data_interface - find the best data interface and timings + * @chip: The NAND chip + * + * Find the best data interface and NAND timings supported by the chip + * and the driver. + * First tries to retrieve supported timing modes from ONFI information, + * and if the NAND chip does not support ONFI, relies on the + * ->onfi_timing_mode_default specified in the nand_ids table. After this + * function nand_chip->data_interface is initialized with the best timing mode + * available. + * + * Returns 0 for success or negative error code otherwise. + */ +static int nand_init_data_interface(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + int modes, mode, ret; + + if (!chip->setup_data_interface) + return 0; + + /* + * First try to identify the best timings from ONFI parameters and + * if the NAND does not support ONFI, fallback to the default ONFI + * timing mode. + */ + modes = onfi_get_async_timing_mode(chip); + if (modes == ONFI_TIMING_MODE_UNKNOWN) { + if (!chip->onfi_timing_mode_default) + return 0; + + modes = GENMASK(chip->onfi_timing_mode_default, 0); + } + + chip->data_interface = kzalloc(sizeof(*chip->data_interface), + GFP_KERNEL); + if (!chip->data_interface) + return -ENOMEM; + + for (mode = fls(modes) - 1; mode >= 0; mode--) { + ret = onfi_init_data_interface(chip, chip->data_interface, + NAND_SDR_IFACE, mode); + if (ret) + continue; + + ret = chip->setup_data_interface(mtd, chip->data_interface, + true); + if (!ret) { + chip->onfi_timing_mode_default = mode; + break; + } + } + + return 0; +} + +static void __maybe_unused nand_release_data_interface(struct nand_chip *chip) +{ + kfree(chip->data_interface); +} + +/** * nand_reset - Reset and initialize a NAND device * @chip: The NAND chip * @@ -910,9 +1052,18 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) int nand_reset(struct nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(chip); + int ret; + + ret = nand_reset_data_interface(chip); + if (ret) + return ret; chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + ret = nand_setup_data_interface(chip); + if (ret) + return ret; + return 0; } @@ -3882,6 +4033,10 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, return PTR_ERR(type); } + ret = nand_init_data_interface(chip); + if (ret) + return ret; + chip->select_chip(mtd, -1); /* Check for a chip array */ diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 0b9fe3f..274bd8d 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -764,10 +764,9 @@ nand_get_sdr_timings(const struct nand_data_interface *conf) * also from the datasheet. It is the recommended ECC step * size, if known; if unknown, set to zero. * @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is - * either deduced from the datasheet if the NAND - * chip is not ONFI compliant or set to 0 if it is - * (an ONFI chip is always configured in mode 0 - * after a NAND reset) + * set to the actually used ONFI mode if the chip is + * ONFI compliant or deduced from the datasheet if + * the NAND chip is not ONFI compliant. * @numchips: [INTERN] number of physical chips * @chipsize: [INTERN] the size of one chip for multichip arrays * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 @@ -787,6 +786,7 @@ nand_get_sdr_timings(const struct nand_data_interface *conf) * @read_retries: [INTERN] the number of read retry modes supported * @onfi_set_features: [REPLACEABLE] set the features for ONFI nand * @onfi_get_features: [REPLACEABLE] get the features for ONFI nand + * @setup_data_interface: [OPTIONAL] setup the data interface and timing * @bbt: [INTERN] bad block table pointer * @bbt_td: [REPLACEABLE] bad block table descriptor for flash * lookup. @@ -835,6 +835,10 @@ struct nand_chip { int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip, int feature_addr, uint8_t *subfeature_para); int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode); + int (*setup_data_interface)(struct mtd_info *mtd, + const struct nand_data_interface *conf, + bool check_only); + int chip_delay; unsigned int options; @@ -862,6 +866,8 @@ struct nand_chip { struct nand_onfi_params onfi_params; struct nand_jedec_params jedec_params; + struct nand_data_interface *data_interface; + int read_retries; flstate_t state; From patchwork Tue Nov 21 17:38:20 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119379 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5572759qgn; Tue, 21 Nov 2017 09:45:44 -0800 (PST) X-Google-Smtp-Source: AGs4zMaXRoBbpMW7dxch/us7i2Z3GXghfooIdkSv4/bRkC6m/0GuU0D520zAcyjrJYDT4dRHShoP X-Received: by 10.80.148.199 with SMTP id t7mr25593470eda.124.1511286344208; Tue, 21 Nov 2017 09:45:44 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286344; cv=none; d=google.com; s=arc-20160816; b=YOKhz422Odnx1jgWGwCLuFd4/aQAFYpRGpapxqBqWV6uS8BPuFcVWlR94a8lzCKXST tsQfwEH3YtZ9v30DTp/AMi9bur3DeRIT8waabwyJJHcn2MyaoSAdh1byLtdVmlyrQOpX xdWE7GO+qZQU9YnSO3CMryIoSYt3mSce3B+fPo8YaQ+JDFeuamEhGUQPCSqzhz2M6vAR MuM50X7Y+vj05vWi0U80PecNspccqoaxf75xFIYx2MtPjGeqnLHnJGwIGFty8+NnSUw0 nS0x6qPsm/ia7zB8RnBHfumH8zJjZic84Mk4YEO2vvo9CvHceE8Grq4nWoDwWh9c1Vcn ePkw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=QASUEzVjHG+qIsgIE2CTTG2bw8OLPRqFpT0kukdV+vE=; b=i72pC1Mc/Zp17wT8oYs8sVwNWYfpy8bgOhXtwnPeHXE6aXGz9COCgaZb/U8VbpkiWB 3UOKQn3SeNv4ZyEdvjL5QVS0m2bOUVdzZtnYnVwLBIND74bzU04+kLUyJc5O3FTSqD70 7aGloB3e1KD9M2QZvFrSFJFvTWIVMX8KDSMTg4/vXzQMUjmfwY+glJaixc7bRiwlOJfv g67jgkIUmjywLY/JBgOEz1C0fX0jkNWuw9ljkh52ruH7hPaDupMTGicKBHcKin7/HEko ijSm+a0/0e07WnMd7pzSrLMEk0aJwf+5+tnRpm42kQcY2IujhKxiOb4QqehWeA85MwGY ekjQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=srsHDine; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id 5si861041edj.439.2017.11.21.09.45.43; Tue, 21 Nov 2017 09:45:44 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=srsHDine; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id 9F766C21F92; Tue, 21 Nov 2017 17:41:41 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id D14E8C21DDF; Tue, 21 Nov 2017 17:39:24 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 85330C21DF1; Tue, 21 Nov 2017 17:39:07 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id 47C78C21F5E for ; Tue, 21 Nov 2017 17:39:04 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbu0001225; Wed, 22 Nov 2017 02:38:42 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbu0001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285922; bh=Qnghw3e/aQA1o/H7OJ+SHKJCeRsCHLwtL36uQwp8P20=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=srsHDinehWGb5V2VpvyFbwIjEaDxmCpct9PnQEzYlQtyytL2DvWYdaU5lgOzklOtj 1PNI/5OfNnFbtGdvXz6lC5TW0dk/3/qx+qdEil1Ruutd3uzCJEtAB5BRIdTSn9fLwY hXTWMMq9bLjFshJpPuIjcI9V+Yom0nsGfYQDjgnmFANKEWnDyOFn+odEnU/8Mo38Up /kThMcNe6aS/2lcILI90mdfm9/eaShemypJ++ikSpDiqHns2CscPyFV2DsI7Nb7Z6h YyK0+yTXk79A3gLGit96ZLakxBeNJpE2qogpWFd3aSdg2/gyEEguo39M3jrjeCr0p5 jE+y/jp9xRqZQ== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:20 +0900 Message-Id: <1511285912-12452-11-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 10/22] mtd: nand: Fix data interface configuration logic X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Boris Brezillon When changing from one data interface setting to another, one has to ensure a specific sequence which is described in the ONFI spec. One of these constraints is that the CE line has go high after a reset before a command can be sent with the new data interface setting, which is not guaranteed by the current implementation. Rework the nand_reset() function and all the call sites to make sure the CE line is asserted and released when required. Also make sure to actually apply the new data interface setting on the first die. Signed-off-by: Boris Brezillon Fixes: d8e725dd8311 ("mtd: nand: automate NAND timings selection") Reviewed-by: Sascha Hauer Tested-by: Marc Gonzalez [Linux commit: 73f907fd5fa56b0066d199bdd7126bbd04f6cd7b] Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/nand_base.c | 48 +++++++++++++++++++++++++++++++++----------- include/linux/mtd/nand.h | 2 +- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index f452f59..5054c0e 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1046,10 +1046,11 @@ static void __maybe_unused nand_release_data_interface(struct nand_chip *chip) /** * nand_reset - Reset and initialize a NAND device * @chip: The NAND chip + * @chipnr: Internal die id * * Returns 0 for success or negative error code otherwise */ -int nand_reset(struct nand_chip *chip) +int nand_reset(struct nand_chip *chip, int chipnr) { struct mtd_info *mtd = nand_to_mtd(chip); int ret; @@ -1058,9 +1059,17 @@ int nand_reset(struct nand_chip *chip) if (ret) return ret; + /* + * The CS line has to be released before we can apply the new NAND + * interface settings, hence this weird ->select_chip() dance. + */ + chip->select_chip(mtd, chipnr); chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + chip->select_chip(mtd, -1); + chip->select_chip(mtd, chipnr); ret = nand_setup_data_interface(chip); + chip->select_chip(mtd, -1); if (ret) return ret; @@ -2746,10 +2755,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, } chipnr = (int)(to >> chip->chip_shift); - chip->select_chip(mtd, chipnr); - - /* Shift to get page */ - page = (int)(to >> chip->page_shift); /* * Reset the chip. Some chips (like the Toshiba TC5832DC found in one @@ -2757,7 +2762,12 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, * if we don't do this. I have no clue why, but I seem to have 'fixed' * it in the doc2000 driver in August 1999. dwmw2. */ - nand_reset(chip); + nand_reset(chip, chipnr); + + chip->select_chip(mtd, chipnr); + + /* Shift to get page */ + page = (int)(to >> chip->page_shift); /* Check, if it is write protected */ if (nand_check_wp(mtd)) { @@ -3771,14 +3781,14 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, int i, maf_idx; u8 id_data[8]; - /* Select the device */ - chip->select_chip(mtd, 0); - /* * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) * after power-up. */ - nand_reset(chip); + nand_reset(chip, 0); + + /* Select the device */ + chip->select_chip(mtd, 0); /* Send the command for reading device ID */ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); @@ -4033,17 +4043,31 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, return PTR_ERR(type); } + /* Initialize the ->data_interface field. */ ret = nand_init_data_interface(chip); if (ret) return ret; + /* + * Setup the data interface correctly on the chip and controller side. + * This explicit call to nand_setup_data_interface() is only required + * for the first die, because nand_reset() has been called before + * ->data_interface and ->default_onfi_timing_mode were set. + * For the other dies, nand_reset() will automatically switch to the + * best mode for us. + */ + ret = nand_setup_data_interface(chip); + if (ret) + return ret; + chip->select_chip(mtd, -1); /* Check for a chip array */ for (i = 1; i < maxchips; i++) { - chip->select_chip(mtd, i); /* See comment in nand_get_flash_type for reset */ - nand_reset(chip); + nand_reset(chip, i); + + chip->select_chip(mtd, i); /* Send the command for reading device ID */ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 274bd8d..8cff83b 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -1198,6 +1198,6 @@ int nand_check_erased_ecc_chunk(void *data, int datalen, int threshold); /* Reset and initialize a NAND device */ -int nand_reset(struct nand_chip *chip); +int nand_reset(struct nand_chip *chip, int chipnr); #endif /* __LINUX_MTD_NAND_H */ From patchwork Tue Nov 21 17:38:21 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119374 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5569424qgn; Tue, 21 Nov 2017 09:42:28 -0800 (PST) X-Google-Smtp-Source: AGs4zMaWiKWqc8DHVjEKu+07uznqzQlRfh/PrmQ0QxDZFSMs14EwXelfdy3et2YGLQElnQiDP1ir X-Received: by 10.80.205.143 with SMTP id p15mr26050760edi.255.1511286145937; Tue, 21 Nov 2017 09:42:25 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286145; cv=none; d=google.com; s=arc-20160816; b=d6y9dB834/mKTZUyps1s1t6yc+JMOtP4FPIul9wcaa79cO5F3XTWjU4CsfUFE8BAmQ C+ev9PR/wWTyEAm1w76N/WbWUw49Y1IuHh66o6ghJb1BdSX5OTA+FSuBy9o06UQsfKGh MwoR0tK0Ps0LQt4jfvX7G/7v7Lms9p4S2RBj7izBcsZ7+Muu1+FMIvnoAIEeZutW0DsN ZtO9Nquwjl2homqANin3BFFkNGv8SbDgIsCMPBjmOl4rL34Q2F+hilOSudpEZJA/Oew3 OX2KP7xSS+zETM7hyQBfE2dxTp6h2a7YxsxvG88e+0K+2RExF49wEferg16YDWpQIDqG jRXA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=HwcU7wYo4H8yqiCfmXAJHyFceHliaP6kAUac08gXHGk=; b=yEct+18ZYncUqnLkyRiGD4oDCV/y+MHybb9YWrVKxVra8O/zfDQDHuJu6U4mBsXxov kITyBss1sIwrIqj0UEN8381r853nqZgBYqtNhiFjTRyzjUH5LBjfEx/5ylEjwZm08xSM 7QSt1ykA1GfA9r4O6rwWIa2UV870UNf29OVqAwpgo8Hh4EhyPITDA9yuxO/7EVG21o7Q WAA7XRzsKf8Sr61/LhZE59gFXXembm+4gDohMLUP1R7N1eaUQ5fqRtdm1/j9n0Cq0+c6 DyZWFupVG87wMvHMvtwTpq3yWo8Iy+M0p3kg2XdT1cHl+l4hJa54BpHCa/XjUqNVhIh9 g+gA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=CD5KBh6G; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id a16si909668edj.480.2017.11.21.09.42.25; Tue, 21 Nov 2017 09:42:25 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=CD5KBh6G; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id 50890C21F71; Tue, 21 Nov 2017 17:41:03 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 90F47C21F76; Tue, 21 Nov 2017 17:39:21 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id CF8FDC21F69; Tue, 21 Nov 2017 17:39:08 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id CD35BC21EE4 for ; Tue, 21 Nov 2017 17:39:06 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbu1001225; Wed, 22 Nov 2017 02:38:42 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbu1001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285922; bh=s+7V6YFcpLKoouG+IOkS/tcYP/wGhsd9PphhFVZt+4U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CD5KBh6G0FKOtM3iPva8sAqTJfG5wHEP4w+zYnJECONi7cCbKLXOYtVF/Nc/M+RPd 3rvLEdKm0NgkOtsxgrzhxliElpzhoY8FsZoG+wSkInDV7iJ5msWCrfrDGdi2klLXE2 ZOwilkuKHmqSWLFxylDxF+nNe6Fb8UIWJWk3RYHN1w7EpaKbll7SsTc+SGFskel0Ir nueFIgAo9/bF8gV4IfsMQg87xHQTnyrCsKkyTBbQDQoP4PzcZUGw/lxXaiW0970sY8 q8yLVpU9Zpvp0oLOCFOOlRhs36ur1vnbHw6D4TBqx58pMprOO1kgEtSmiK/OZMtJZy 6nHAhPRm4WPgA== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:21 +0900 Message-Id: <1511285912-12452-12-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 11/22] mtd: nand: Add a few more timings to nand_sdr_timings X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Boris Brezillon Add the tR_max, tBERS_max, tPROG_max and tCCS_min timings to the nand_sdr_timings struct. Assign default/safe values for the statically defined timings, and extract them from the ONFI parameter table if the NAND is ONFI compliant. Signed-off-by: Boris Brezillon Tested-by: Marc Gonzalez [Linux commit: 204e7ecd47e26cc12d9e8e8a7e7a2eeb9573f0ba Fixup commit: 6d29231000bbe0fb9e4893a9c68151ffdd3b5469] Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/nand_timings.c | 26 +++++++++++++++++++++++++- include/linux/mtd/nand.h | 8 ++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c index ba4f22f..9935557 100644 --- a/drivers/mtd/nand/nand_timings.c +++ b/drivers/mtd/nand/nand_timings.c @@ -17,6 +17,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { { .type = NAND_SDR_IFACE, .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, .tADL_min = 400000, .tALH_min = 20000, .tALS_min = 50000, @@ -57,6 +59,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { { .type = NAND_SDR_IFACE, .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, .tADL_min = 400000, .tALH_min = 10000, .tALS_min = 25000, @@ -97,6 +101,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { { .type = NAND_SDR_IFACE, .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, .tADL_min = 400000, .tALH_min = 10000, .tALS_min = 15000, @@ -137,6 +143,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { { .type = NAND_SDR_IFACE, .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, .tADL_min = 400000, .tALH_min = 5000, .tALS_min = 10000, @@ -177,6 +185,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { { .type = NAND_SDR_IFACE, .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, .tADL_min = 400000, .tALH_min = 5000, .tALS_min = 10000, @@ -217,6 +227,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { { .type = NAND_SDR_IFACE, .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, .tADL_min = 400000, .tALH_min = 5000, .tALS_min = 10000, @@ -289,10 +301,22 @@ int onfi_init_data_interface(struct nand_chip *chip, *iface = onfi_sdr_timings[timing_mode]; /* - * TODO: initialize timings that cannot be deduced from timing mode: + * Initialize timings that cannot be deduced from timing mode: * tR, tPROG, tCCS, ... * These information are part of the ONFI parameter page. */ + if (chip->onfi_version) { + struct nand_onfi_params *params = &chip->onfi_params; + struct nand_sdr_timings *timings = &iface->timings.sdr; + + /* microseconds -> picoseconds */ + timings->tPROG_max = 1000000ULL * le16_to_cpu(params->t_prog); + timings->tBERS_max = 1000000ULL * le16_to_cpu(params->t_bers); + timings->tR_max = 1000000ULL * le16_to_cpu(params->t_r); + + /* nanoseconds -> picoseconds */ + timings->tCCS_min = 1000UL * le16_to_cpu(params->t_ccs); + } return 0; } diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 8cff83b..8b76275 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -595,6 +595,10 @@ struct nand_buffers { * * All these timings are expressed in picoseconds. * + * @tBERS_max: Block erase time + * @tCCS_min: Change column setup time + * @tPROG_max: Page program time + * @tR_max: Page read time * @tALH_min: ALE hold time * @tADL_min: ALE to data loading time * @tALS_min: ALE setup time @@ -632,6 +636,10 @@ struct nand_buffers { * @tWW_min: WP# transition to WE# low */ struct nand_sdr_timings { + u64 tBERS_max; + u32 tCCS_min; + u64 tPROG_max; + u64 tR_max; u32 tALH_min; u32 tADL_min; u32 tALS_min; From patchwork Tue Nov 21 17:38:22 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119382 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5575283qgn; Tue, 21 Nov 2017 09:48:12 -0800 (PST) X-Google-Smtp-Source: AGs4zMaPWVKUNHbde9XiC2GP4oIIdFnFyE95kkJp/3cWYMQ3+1cMt3TGzsysPcJhOjp+Y/bed446 X-Received: by 10.80.190.193 with SMTP id e1mr8609419edk.282.1511286492491; Tue, 21 Nov 2017 09:48:12 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286492; cv=none; d=google.com; s=arc-20160816; b=It/Qjz0H3KFJ07Bdtxx83fUeDObOC2BcDckgCw1FeWQQ62TYIQsSgE5rTFc63YztQS klfzCZGshqWLobyj7ZRnxgbM5YIF9FCi3hYoaaEABvl2URBTK0d/SY9GLgMU7ujDXYos HSqXIIxwRQM8eziRU1iGdYq3f7+8NYJtIjOVIY3W19oNnjkNpC6lLKJeSEjItSgItMOR epiIml3NvvTKuywm63D2LNzNQadsGKy9Y+dlIKPkx8YpJG7wxKxtaCXPZ2ZtFSIaYjo3 a4lcpf8Is8s9sZgO81HwMwfExPlNdTxMliq1NoK3SxooShcRxm4MEwoGkD3SK7UrUAKv ysTw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=va8K2/AP/JPWflyykOUB1sjBK/6ZDnjA60z5zeCP7x4=; b=upcbReBCI3L72dE25pkp/rBzGD7LaetnkGBiU1+YzD+5vXxLtXpDe3SorTK1hwJ1eM yK1rmEJFTxa28kZkN9/Kz8orHdAY64+BaGqCJ2DooJFOdKArjxk+yutLo+2Flqu5IeWG bxtSKLQlLqg8gtSVBeeWi8lvK6p6BqteJGWastZ+1D9E/b1Kk85WCyeeK+qwhJ8xrQao U96FE+86QjHI+v64hJl+JbI6WHGz4sJodD73LHQkcV/BrrTw7+iPlSU4Ze91+XXH+mEc /kiRWWe8e+5W8byaguDLAQfWOXeKtqe5O8rE48Hg/dKEoU4Y1YogaxfN9BTtriaKucir 7ZBQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=SiHNsYI/; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id l35si8387072ede.520.2017.11.21.09.48.12; Tue, 21 Nov 2017 09:48:12 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=SiHNsYI/; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id E6819C21DDF; Tue, 21 Nov 2017 17:43:07 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id E10E4C21F7F; Tue, 21 Nov 2017 17:39:30 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 92740C21F80; Tue, 21 Nov 2017 17:39:07 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id 2B738C21F6A for ; Tue, 21 Nov 2017 17:39:05 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbu2001225; Wed, 22 Nov 2017 02:38:43 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbu2001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285923; bh=2KPYoafeSwy47H+2Kiy1+mQ+uZRTOylyJXqtn1KCw3w=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=SiHNsYI/GrLLNhAId9YWCtbxxOJ33/cDEndqMSqqCu1CqmYiDrCiTme4d/ZjuShHL 4d46TxGr3ZZnaloxKNCWQwjhU4hlUQAuBAkTECtIL7aNGkECQHGbv/uqieC0IIwcwP UbUNfKFFk1J5Y/XL7ITMTx7AalJyKoJIyBFUzcdZyavJDlPBj7Ywq/nxLhUT1oJJba C7VTvtc6/HSunMVKECmm4+qPcxACd890y9KmDFSHCiz5jCmFOSG/EloPdQODPNhb9b rGCI42oSdVLROxBhcpeZtOQC7ihjC0CejTb3Z+bmMBAt6l1nHj9TpItIP38C28WZdF V2ekd0ax/j0Mw== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:22 +0900 Message-Id: <1511285912-12452-13-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 12/22] mtd: nand: Support controllers with custom page X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Marc Gonzalez If your controller already sends the required NAND commands when reading or writing a page, then the framework is not supposed to send READ0 and SEQIN/PAGEPROG respectively. Signed-off-by: Marc Gonzalez Signed-off-by: Boris Brezillon [Linux commit: 3371d663bb4579f1b2003a92162edd6d90edd089] Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/nand_base.c | 34 +++++++++++++++++++++++++++++++--- include/linux/mtd/nand.h | 12 ++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 5054c0e..d9f0a75 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1732,7 +1732,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, __func__, buf); read_retry: - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + if (nand_standard_page_accessors(&chip->ecc)) + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); /* * Now read the page into the buffer. Absent an error, @@ -2423,7 +2424,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, else subpage = 0; - chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); + if (nand_standard_page_accessors(&chip->ecc)) + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); if (unlikely(raw)) status = chip->ecc.write_page_raw(mtd, chip, buf, @@ -2446,7 +2448,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, if (!cached || !NAND_HAS_CACHEPROG(chip)) { - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + if (nand_standard_page_accessors(&chip->ecc)) + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); status = chip->waitfunc(mtd, chip); /* * See if operation failed and additional status checks are @@ -4126,6 +4129,26 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd) return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds; } +static bool invalid_ecc_page_accessors(struct nand_chip *chip) +{ + struct nand_ecc_ctrl *ecc = &chip->ecc; + + if (nand_standard_page_accessors(ecc)) + return false; + + /* + * NAND_ECC_CUSTOM_PAGE_ACCESS flag is set, make sure the NAND + * controller driver implements all the page accessors because + * default helpers are not suitable when the core does not + * send the READ0/PAGEPROG commands. + */ + return (!ecc->read_page || !ecc->write_page || + !ecc->read_page_raw || !ecc->write_page_raw || + (NAND_HAS_SUBPAGE_READ(chip) && !ecc->read_subpage) || + (NAND_HAS_SUBPAGE_WRITE(chip) && !ecc->write_subpage && + ecc->hwctl && ecc->calculate)); +} + /** * nand_scan_tail - [NAND Interface] Scan for the NAND device * @mtd: MTD device structure @@ -4145,6 +4168,11 @@ int nand_scan_tail(struct mtd_info *mtd) BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) && !(chip->bbt_options & NAND_BBT_USE_FLASH)); + if (invalid_ecc_page_accessors(chip)) { + pr_err("Invalid ECC page accessors setup\n"); + return -EINVAL; + } + if (!(chip->options & NAND_OWN_BUFFERS)) { nbuf = kzalloc(sizeof(struct nand_buffers), GFP_KERNEL); chip->buffers = nbuf; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 8b76275..72b2328 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -154,6 +154,12 @@ typedef enum { */ #define NAND_ECC_GENERIC_ERASED_CHECK BIT(0) #define NAND_ECC_MAXIMIZE BIT(1) +/* + * If your controller already sends the required NAND commands when + * reading or writing a page, then the framework is not supposed to + * send READ0 and SEQIN/PAGEPROG respectively. + */ +#define NAND_ECC_CUSTOM_PAGE_ACCESS BIT(2) /* Bit mask for flags passed to do_nand_read_ecc */ #define NAND_GET_DEVICE 0x80 @@ -202,6 +208,7 @@ typedef enum { /* Macros to identify the above */ #define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG)) #define NAND_HAS_SUBPAGE_READ(chip) ((chip->options & NAND_SUBPAGE_READ)) +#define NAND_HAS_SUBPAGE_WRITE(chip) !((chip)->options & NAND_NO_SUBPAGE_WRITE) /* Non chip related options */ /* This option skips the bbt scan during initialization. */ @@ -568,6 +575,11 @@ struct nand_ecc_ctrl { int page); }; +static inline int nand_standard_page_accessors(struct nand_ecc_ctrl *ecc) +{ + return !(ecc->options & NAND_ECC_CUSTOM_PAGE_ACCESS); +} + /** * struct nand_buffers - buffer structure for read/write * @ecccalc: buffer pointer for calculated ECC, size is oobsize. From patchwork Tue Nov 21 17:38:23 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119384 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5575801qgn; Tue, 21 Nov 2017 09:48:45 -0800 (PST) X-Google-Smtp-Source: AGs4zMZXJiO2uCuy+vhBn11e3S0dfosRFicsVyCo6N1B8Fxm5Pwk9lNgpIP0UkiIZauoI1x3aqts X-Received: by 10.80.142.201 with SMTP id x9mr26037469edx.285.1511286525283; Tue, 21 Nov 2017 09:48:45 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286525; cv=none; d=google.com; s=arc-20160816; b=GURy+0O+BTdw/aPM2EJqh2mK9SvGiuG16N8TR3wXY8muZFfxxgNKHkdqc/Z57iuTU2 NRp0RljQlwY0EVGH24D4113dkwrOLEi2RJfcDUI5g1PMrgJxHlH4K4GVQDqksgWixGC5 gsXLILpBcAikQad3Lil5nOri3wWy7VUHZTtWw0JAckH+XeWNxSvIh9b0osh0AQaNWSLy R5YwukqZEkRPoYzp0OgoNRlZ+OL//e/vFFB5j2dD1wyeJsappaqXx1/WO4Su1p5/qC9U HKbK9SrRty41g+w9cG1KeXcohcVkZkS+l7T27S0KIRwd4H79rGmWNJSk0fibLmZhruc+ /Hfg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=QdQAtSLwIIDDuLa+nqkmTx3ZMgU+BCJ33nYf0HL6WFA=; b=l8YZI9MXZBEVskiIsxoe3keCxjrzaK4KUVX7liEZYHOCOI56umiDUAIOfVAWO2CliI oSL1aGRlfQmqoMeZwJe3c+tgrgEqg4Rgy3LEuuUzSZHM4VBivMCjaEXDxK3BoeGFsF/S Zl1yCAkmuX+mlLGT3IB/GN+u2p8emyoTWlWTobFsADGmXeiJFto8FFeR1IQQteAG8eLG eleiPMIPHLtJG1uDZDBvbsAeGGOwlQWIWxOUFalgWQrK9Wg6p0d5uYTex1RxDRwNcefM 6uhfyefAYXjZgy1BeEBR/WtLjm9PFt9QLKrInYUyCZ3EVXxXQpruY/mIhfMpe1SI1bZn 9oUw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=eT3TSE3z; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id 5si865357edj.439.2017.11.21.09.48.45; Tue, 21 Nov 2017 09:48:45 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=eT3TSE3z; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id DB7A0C21DDF; Tue, 21 Nov 2017 17:43:50 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 7F85BC21FAE; Tue, 21 Nov 2017 17:39:33 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 47C2CC21F07; Tue, 21 Nov 2017 17:39:08 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id 64525C21C29 for ; Tue, 21 Nov 2017 17:39:05 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbu3001225; Wed, 22 Nov 2017 02:38:43 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbu3001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285923; bh=/3qAGW/vHF9GucXJAz4vl73MuMKbg5E77ACXQydY1cU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=eT3TSE3zcYR29WLcGKann7to0zdnFPAdrsmlL3sv8PhneTkxvbNNvYv+W0BKMu9fC Crf0GlamRQrSxRvFQIRTPKe6e10QiyHJHC+W6ZXM5MaHYAvIDWVJpYU5XtsXls+EIq s4H/F5NqDREGbXrlYyRVO2bw6z9iRRg4hhYXBwVEVtCHIuGo4tdBvPOgaLTNyWh2uC c6WuudWd3E13eXCTWWBmWD8Bd0kvtVcFT6sK2g5El4pZFWqioybSeVUTTcw5zDC62H jkTbFAPYOpDtQg9bZJIq7LUShdC9m59SNrffcrte4zKBmrAUOLsuiVoSc8V1eZY8aJ O4nwIqzNP/ONA== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:23 +0900 Message-Id: <1511285912-12452-14-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 13/22] mtd: add mtd_ooblayout_xxx() helper functions X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Boris Brezillon In order to make the ecclayout definition completely dynamic we need to rework the way the OOB layout are defined and iterated. Create a few mtd_ooblayout_xxx() helpers to ease OOB bytes manipulation and hide ecclayout internals to their users. Signed-off-by: Boris Brezillon [Linux commit: 75eb2cec251fda33c9bb716ecc372819abb9278a] [masahiro: cherry-pick more code from adbbc3bc827eb1f43a932d783f09ba55c8ec8379] Signed-off-by: Masahiro Yamada --- drivers/mtd/mtdcore.c | 360 ++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/mtd/mtd.h | 57 ++++++++ 2 files changed, 417 insertions(+) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index e3f56e5..2cda051 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1005,6 +1005,366 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) } EXPORT_SYMBOL_GPL(mtd_read_oob); +/** + * mtd_ooblayout_ecc - Get the OOB region definition of a specific ECC section + * @mtd: MTD device structure + * @section: ECC section. Depending on the layout you may have all the ECC + * bytes stored in a single contiguous section, or one section + * per ECC chunk (and sometime several sections for a single ECC + * ECC chunk) + * @oobecc: OOB region struct filled with the appropriate ECC position + * information + * + * This function returns ECC section information in the OOB area. If you want + * to get all the ECC bytes information, then you should call + * mtd_ooblayout_ecc(mtd, section++, oobecc) until it returns -ERANGE. + * + * Returns zero on success, a negative error code otherwise. + */ +int mtd_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobecc) +{ + memset(oobecc, 0, sizeof(*oobecc)); + + if (!mtd || section < 0) + return -EINVAL; + + if (!mtd->ooblayout || !mtd->ooblayout->ecc) + return -ENOTSUPP; + + return mtd->ooblayout->ecc(mtd, section, oobecc); +} +EXPORT_SYMBOL_GPL(mtd_ooblayout_ecc); + +/** + * mtd_ooblayout_free - Get the OOB region definition of a specific free + * section + * @mtd: MTD device structure + * @section: Free section you are interested in. Depending on the layout + * you may have all the free bytes stored in a single contiguous + * section, or one section per ECC chunk plus an extra section + * for the remaining bytes (or other funky layout). + * @oobfree: OOB region struct filled with the appropriate free position + * information + * + * This function returns free bytes position in the OOB area. If you want + * to get all the free bytes information, then you should call + * mtd_ooblayout_free(mtd, section++, oobfree) until it returns -ERANGE. + * + * Returns zero on success, a negative error code otherwise. + */ +int mtd_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobfree) +{ + memset(oobfree, 0, sizeof(*oobfree)); + + if (!mtd || section < 0) + return -EINVAL; + + if (!mtd->ooblayout || !mtd->ooblayout->free) + return -ENOTSUPP; + + return mtd->ooblayout->free(mtd, section, oobfree); +} +EXPORT_SYMBOL_GPL(mtd_ooblayout_free); + +/** + * mtd_ooblayout_find_region - Find the region attached to a specific byte + * @mtd: mtd info structure + * @byte: the byte we are searching for + * @sectionp: pointer where the section id will be stored + * @oobregion: used to retrieve the ECC position + * @iter: iterator function. Should be either mtd_ooblayout_free or + * mtd_ooblayout_ecc depending on the region type you're searching for + * + * This function returns the section id and oobregion information of a + * specific byte. For example, say you want to know where the 4th ECC byte is + * stored, you'll use: + * + * mtd_ooblayout_find_region(mtd, 3, §ion, &oobregion, mtd_ooblayout_ecc); + * + * Returns zero on success, a negative error code otherwise. + */ +static int mtd_ooblayout_find_region(struct mtd_info *mtd, int byte, + int *sectionp, struct mtd_oob_region *oobregion, + int (*iter)(struct mtd_info *, + int section, + struct mtd_oob_region *oobregion)) +{ + int pos = 0, ret, section = 0; + + memset(oobregion, 0, sizeof(*oobregion)); + + while (1) { + ret = iter(mtd, section, oobregion); + if (ret) + return ret; + + if (pos + oobregion->length > byte) + break; + + pos += oobregion->length; + section++; + } + + /* + * Adjust region info to make it start at the beginning at the + * 'start' ECC byte. + */ + oobregion->offset += byte - pos; + oobregion->length -= byte - pos; + *sectionp = section; + + return 0; +} + +/** + * mtd_ooblayout_find_eccregion - Find the ECC region attached to a specific + * ECC byte + * @mtd: mtd info structure + * @eccbyte: the byte we are searching for + * @sectionp: pointer where the section id will be stored + * @oobregion: OOB region information + * + * Works like mtd_ooblayout_find_region() except it searches for a specific ECC + * byte. + * + * Returns zero on success, a negative error code otherwise. + */ +int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte, + int *section, + struct mtd_oob_region *oobregion) +{ + return mtd_ooblayout_find_region(mtd, eccbyte, section, oobregion, + mtd_ooblayout_ecc); +} +EXPORT_SYMBOL_GPL(mtd_ooblayout_find_eccregion); + +/** + * mtd_ooblayout_get_bytes - Extract OOB bytes from the oob buffer + * @mtd: mtd info structure + * @buf: destination buffer to store OOB bytes + * @oobbuf: OOB buffer + * @start: first byte to retrieve + * @nbytes: number of bytes to retrieve + * @iter: section iterator + * + * Extract bytes attached to a specific category (ECC or free) + * from the OOB buffer and copy them into buf. + * + * Returns zero on success, a negative error code otherwise. + */ +static int mtd_ooblayout_get_bytes(struct mtd_info *mtd, u8 *buf, + const u8 *oobbuf, int start, int nbytes, + int (*iter)(struct mtd_info *, + int section, + struct mtd_oob_region *oobregion)) +{ + struct mtd_oob_region oobregion; + int section, ret; + + ret = mtd_ooblayout_find_region(mtd, start, §ion, + &oobregion, iter); + + while (!ret) { + int cnt; + + cnt = min_t(int, nbytes, oobregion.length); + memcpy(buf, oobbuf + oobregion.offset, cnt); + buf += cnt; + nbytes -= cnt; + + if (!nbytes) + break; + + ret = iter(mtd, ++section, &oobregion); + } + + return ret; +} + +/** + * mtd_ooblayout_set_bytes - put OOB bytes into the oob buffer + * @mtd: mtd info structure + * @buf: source buffer to get OOB bytes from + * @oobbuf: OOB buffer + * @start: first OOB byte to set + * @nbytes: number of OOB bytes to set + * @iter: section iterator + * + * Fill the OOB buffer with data provided in buf. The category (ECC or free) + * is selected by passing the appropriate iterator. + * + * Returns zero on success, a negative error code otherwise. + */ +static int mtd_ooblayout_set_bytes(struct mtd_info *mtd, const u8 *buf, + u8 *oobbuf, int start, int nbytes, + int (*iter)(struct mtd_info *, + int section, + struct mtd_oob_region *oobregion)) +{ + struct mtd_oob_region oobregion; + int section, ret; + + ret = mtd_ooblayout_find_region(mtd, start, §ion, + &oobregion, iter); + + while (!ret) { + int cnt; + + cnt = min_t(int, nbytes, oobregion.length); + memcpy(oobbuf + oobregion.offset, buf, cnt); + buf += cnt; + nbytes -= cnt; + + if (!nbytes) + break; + + ret = iter(mtd, ++section, &oobregion); + } + + return ret; +} + +/** + * mtd_ooblayout_count_bytes - count the number of bytes in a OOB category + * @mtd: mtd info structure + * @iter: category iterator + * + * Count the number of bytes in a given category. + * + * Returns a positive value on success, a negative error code otherwise. + */ +static int mtd_ooblayout_count_bytes(struct mtd_info *mtd, + int (*iter)(struct mtd_info *, + int section, + struct mtd_oob_region *oobregion)) +{ + struct mtd_oob_region oobregion; + int section = 0, ret, nbytes = 0; + + while (1) { + ret = iter(mtd, section++, &oobregion); + if (ret) { + if (ret == -ERANGE) + ret = nbytes; + break; + } + + nbytes += oobregion.length; + } + + return ret; +} + +/** + * mtd_ooblayout_get_eccbytes - extract ECC bytes from the oob buffer + * @mtd: mtd info structure + * @eccbuf: destination buffer to store ECC bytes + * @oobbuf: OOB buffer + * @start: first ECC byte to retrieve + * @nbytes: number of ECC bytes to retrieve + * + * Works like mtd_ooblayout_get_bytes(), except it acts on ECC bytes. + * + * Returns zero on success, a negative error code otherwise. + */ +int mtd_ooblayout_get_eccbytes(struct mtd_info *mtd, u8 *eccbuf, + const u8 *oobbuf, int start, int nbytes) +{ + return mtd_ooblayout_get_bytes(mtd, eccbuf, oobbuf, start, nbytes, + mtd_ooblayout_ecc); +} +EXPORT_SYMBOL_GPL(mtd_ooblayout_get_eccbytes); + +/** + * mtd_ooblayout_set_eccbytes - set ECC bytes into the oob buffer + * @mtd: mtd info structure + * @eccbuf: source buffer to get ECC bytes from + * @oobbuf: OOB buffer + * @start: first ECC byte to set + * @nbytes: number of ECC bytes to set + * + * Works like mtd_ooblayout_set_bytes(), except it acts on ECC bytes. + * + * Returns zero on success, a negative error code otherwise. + */ +int mtd_ooblayout_set_eccbytes(struct mtd_info *mtd, const u8 *eccbuf, + u8 *oobbuf, int start, int nbytes) +{ + return mtd_ooblayout_set_bytes(mtd, eccbuf, oobbuf, start, nbytes, + mtd_ooblayout_ecc); +} +EXPORT_SYMBOL_GPL(mtd_ooblayout_set_eccbytes); + +/** + * mtd_ooblayout_get_databytes - extract data bytes from the oob buffer + * @mtd: mtd info structure + * @databuf: destination buffer to store ECC bytes + * @oobbuf: OOB buffer + * @start: first ECC byte to retrieve + * @nbytes: number of ECC bytes to retrieve + * + * Works like mtd_ooblayout_get_bytes(), except it acts on free bytes. + * + * Returns zero on success, a negative error code otherwise. + */ +int mtd_ooblayout_get_databytes(struct mtd_info *mtd, u8 *databuf, + const u8 *oobbuf, int start, int nbytes) +{ + return mtd_ooblayout_get_bytes(mtd, databuf, oobbuf, start, nbytes, + mtd_ooblayout_free); +} +EXPORT_SYMBOL_GPL(mtd_ooblayout_get_databytes); + +/** + * mtd_ooblayout_get_eccbytes - set data bytes into the oob buffer + * @mtd: mtd info structure + * @eccbuf: source buffer to get data bytes from + * @oobbuf: OOB buffer + * @start: first ECC byte to set + * @nbytes: number of ECC bytes to set + * + * Works like mtd_ooblayout_get_bytes(), except it acts on free bytes. + * + * Returns zero on success, a negative error code otherwise. + */ +int mtd_ooblayout_set_databytes(struct mtd_info *mtd, const u8 *databuf, + u8 *oobbuf, int start, int nbytes) +{ + return mtd_ooblayout_set_bytes(mtd, databuf, oobbuf, start, nbytes, + mtd_ooblayout_free); +} +EXPORT_SYMBOL_GPL(mtd_ooblayout_set_databytes); + +/** + * mtd_ooblayout_count_freebytes - count the number of free bytes in OOB + * @mtd: mtd info structure + * + * Works like mtd_ooblayout_count_bytes(), except it count free bytes. + * + * Returns zero on success, a negative error code otherwise. + */ +int mtd_ooblayout_count_freebytes(struct mtd_info *mtd) +{ + return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_free); +} +EXPORT_SYMBOL_GPL(mtd_ooblayout_count_freebytes); + +/** + * mtd_ooblayout_count_freebytes - count the number of ECC bytes in OOB + * @mtd: mtd info structure + * + * Works like mtd_ooblayout_count_bytes(), except it count ECC bytes. + * + * Returns zero on success, a negative error code otherwise. + */ +int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd) +{ + return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_ecc); +} +EXPORT_SYMBOL_GPL(mtd_ooblayout_count_eccbytes); + /* * Method to access the protection register area, present in some flash * devices. The user data is one time programmable but the factory data is read diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 4bde251..ba4cbba 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -103,6 +103,36 @@ struct mtd_oob_ops { #else #define MTD_MAX_ECCPOS_ENTRIES_LARGE 680 #endif +/** + * struct mtd_oob_region - oob region definition + * @offset: region offset + * @length: region length + * + * This structure describes a region of the OOB area, and is used + * to retrieve ECC or free bytes sections. + * Each section is defined by an offset within the OOB area and a + * length. + */ +struct mtd_oob_region { + u32 offset; + u32 length; +}; + +/* + * struct mtd_ooblayout_ops - NAND OOB layout operations + * @ecc: function returning an ECC region in the OOB area. + * Should return -ERANGE if %section exceeds the total number of + * ECC sections. + * @free: function returning a free region in the OOB area. + * Should return -ERANGE if %section exceeds the total number of + * free sections. + */ +struct mtd_ooblayout_ops { + int (*ecc)(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobecc); + int (*free)(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobfree); +}; /* * Internal ECC layout control structure. For historical reasons, there is a @@ -179,6 +209,9 @@ struct mtd_info { #endif int index; + /* OOB layout description */ + const struct mtd_ooblayout_ops *ooblayout; + /* ECC layout structure pointer - read only! */ struct nand_ecclayout *ecclayout; @@ -278,6 +311,30 @@ struct mtd_info { int usecount; }; +int mtd_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobecc); +int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte, + int *section, + struct mtd_oob_region *oobregion); +int mtd_ooblayout_get_eccbytes(struct mtd_info *mtd, u8 *eccbuf, + const u8 *oobbuf, int start, int nbytes); +int mtd_ooblayout_set_eccbytes(struct mtd_info *mtd, const u8 *eccbuf, + u8 *oobbuf, int start, int nbytes); +int mtd_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobfree); +int mtd_ooblayout_get_databytes(struct mtd_info *mtd, u8 *databuf, + const u8 *oobbuf, int start, int nbytes); +int mtd_ooblayout_set_databytes(struct mtd_info *mtd, const u8 *databuf, + u8 *oobbuf, int start, int nbytes); +int mtd_ooblayout_count_freebytes(struct mtd_info *mtd); +int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd); + +static inline void mtd_set_ooblayout(struct mtd_info *mtd, + const struct mtd_ooblayout_ops *ooblayout) +{ + mtd->ooblayout = ooblayout; +} + static inline int mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops) { return ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize; From patchwork Tue Nov 21 17:38:24 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119389 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5582233qgn; Tue, 21 Nov 2017 09:53:41 -0800 (PST) X-Google-Smtp-Source: AGs4zMbvcYheX2HT7dzLwMDZJT/cT3R5MWjKZ/uao3CvpS9yeySjFaX9gG5DDyt8mrXy3h/5aNB3 X-Received: by 10.80.172.197 with SMTP id x63mr26137192edc.3.1511286821240; Tue, 21 Nov 2017 09:53:41 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286821; cv=none; d=google.com; s=arc-20160816; b=QqQtvaQIXfuaBEOJjez1xGogAZBdtrY792d7nwTtsRSy1z5MWs2u/eRhq6zyfHO7Tr w8DKoPuVL3+4N+XEgDIH5TNg3WKj40LxeVm94+1w0324+hy3xF2gSZzz2eRXvjZ9h6wO ic1Hihr5XbjYPoNdw671qLZFchBkiQB+Ga9K0BfBHHp1QWZFWhvFhmKtPvtNcORmi5Hu 4zImMtkAm746j5WzVieWZsg2gdTNjk8SUBjoEEosvnnNBNxq7ccwIN4icztPbMhAzgzX fFbrjxhgrj1y/W5Sgk3NZRTHSd42eMpIFVbr8QZl366V5EUuQmhDH0DgLGUC4hkIfoRx RlrQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=dMsTDLRFG29vSJfB9dkECGWCTWzeViMHa9Mp2EmvEPE=; b=I0mptc9xMVwYfsd3M8e6cw/tlwEZfpkxm7NJlFWTRztFiF8mdbe7imN99qVoOU7d5Z vRCV6DUBWa6okaGXw9KaJ3y3zii9DTfa65K4LR8zzkI0+R9N3fQrxttEAiUBWxemKFm2 oKn7G6oxdaqyFIEzaT+cOfXso4a21O/4Zp2vYfW0YwyLH5r4d/i5KjFHjrAlvDzRHkdk rcXMI1zbrbuPyx7bYSIOFIysKrVyfTYoeFKPTMIoNBZ82aE/632GeeQZqK/nk7TN6Kvi YD6f8cx7zwLSjAVV9raAdaIEjtQhDcugBIMtYnrgtHicpJUq5AnWBk+z1bZlU60jTZ43 OVmg== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=gs8pV9If; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id r7si2176283edc.232.2017.11.21.09.53.40; Tue, 21 Nov 2017 09:53:41 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=gs8pV9If; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id BFE50C21EDC; Tue, 21 Nov 2017 17:51:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id C99AEC22002; Tue, 21 Nov 2017 17:39:42 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 03819C21FF6; Tue, 21 Nov 2017 17:39:07 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id D5FDCC21DF1 for ; Tue, 21 Nov 2017 17:39:03 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbu4001225; Wed, 22 Nov 2017 02:38:43 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbu4001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285924; bh=PSTOerSSjkpTDweyolir/TPfKFPg5EtN3A/z3nIgEsw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gs8pV9IfpoEaoJ5wzvj2vyteQLws7js/rXxQ6lIK7hXFem8TOQFiMOmq8oz3Uc5Nk nVJntZeAQ9GmKsPUDaUh/IMPMr5ufnCUhYcSCfQXAa/EUExqovhVN4RO9UJMS8gfTo ENag1MXJQGSyog3S3YACptbbHaTiimVafIxK5qXIaDx86LvgTDMe0796zpA+hqrH9E Dcgr1ExcmWKXiEYRo4kmU1PGx5UOJ6OoPxe5O/Duv9DMLqYLym4vqU6wUG1El8bj78 m6uIuQzJob0LitkdXsNv6GqLggR9FdDaYKgvWVWM2gztmCIzuwBh4t3eSRBEj5hCmL Kl5IiWGpq8kGw== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:24 +0900 Message-Id: <1511285912-12452-15-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 14/22] mtd: nand: Drop unused cached programming support X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Boris Brezillon Cached programming is always skipped, so drop the associated code until we decide to really support it. Signed-off-by: Boris Brezillon [Linux commit: 0b4773fd1649e0d418275557723a7ef54f769dc9] [masahiro: modify davinci_nand.c for U-Boot] Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/davinci_nand.c | 3 +-- drivers/mtd/nand/nand_base.c | 42 +++++++++++++---------------------------- include/linux/mtd/nand.h | 2 +- 3 files changed, 15 insertions(+), 32 deletions(-) diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 2a01fd3..1e1f4b5 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -358,13 +358,12 @@ static struct nand_ecclayout nand_keystone_rbl_4bit_layout_oobfirst = { * @buf: the data to write * @oob_required: must write chip->oob_poi to OOB * @page: page number to write - * @cached: cached programming * @raw: use _raw version of write_page */ static int nand_davinci_write_page(struct mtd_info *mtd, struct nand_chip *chip, uint32_t offset, int data_len, const uint8_t *buf, int oob_required, - int page, int cached, int raw) + int page, int raw) { int status; int ret = 0; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index d9f0a75..0be427f 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2409,12 +2409,11 @@ static int nand_write_page_syndrome(struct mtd_info *mtd, * @buf: the data to write * @oob_required: must write chip->oob_poi to OOB * @page: page number to write - * @cached: cached programming * @raw: use _raw version of write_page */ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, uint32_t offset, int data_len, const uint8_t *buf, - int oob_required, int page, int cached, int raw) + int oob_required, int page, int raw) { int status, subpage; @@ -2440,31 +2439,19 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, if (status < 0) return status; + if (nand_standard_page_accessors(&chip->ecc)) + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + status = chip->waitfunc(mtd, chip); /* - * Cached progamming disabled for now. Not sure if it's worth the - * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s). + * See if operation failed and additional status checks are + * available. */ - cached = 0; - - if (!cached || !NAND_HAS_CACHEPROG(chip)) { - - if (nand_standard_page_accessors(&chip->ecc)) - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - status = chip->waitfunc(mtd, chip); - /* - * See if operation failed and additional status checks are - * available. - */ - if ((status & NAND_STATUS_FAIL) && (chip->errstat)) - status = chip->errstat(mtd, chip, FL_WRITING, status, - page); + if ((status & NAND_STATUS_FAIL) && (chip->errstat)) + status = chip->errstat(mtd, chip, FL_WRITING, status, + page); - if (status & NAND_STATUS_FAIL) - return -EIO; - } else { - chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1); - status = chip->waitfunc(mtd, chip); - } + if (status & NAND_STATUS_FAIL) + return -EIO; return 0; } @@ -2538,7 +2525,7 @@ static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len, static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { - int chipnr, realpage, page, blockmask, column; + int chipnr, realpage, page, column; struct nand_chip *chip = mtd_to_nand(mtd); uint32_t writelen = ops->len; @@ -2574,7 +2561,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, realpage = (int)(to >> chip->page_shift); page = realpage & chip->pagemask; - blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; /* Invalidate the page cache, when we write to the cached page */ if (to <= ((loff_t)chip->pagebuf << chip->page_shift) && @@ -2589,7 +2575,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, while (1) { int bytes = mtd->writesize; - int cached = writelen > bytes && page != blockmask; uint8_t *wbuf = buf; int use_bufpoi; int part_pagewr = (column || writelen < mtd->writesize); @@ -2604,7 +2589,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, if (use_bufpoi) { pr_debug("%s: using write bounce buffer for buf@%p\n", __func__, buf); - cached = 0; if (part_pagewr) bytes = min_t(int, bytes - column, writelen); chip->pagebuf = -1; @@ -2622,7 +2606,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, memset(chip->oob_poi, 0xff, mtd->oobsize); } ret = chip->write_page(mtd, chip, column, bytes, wbuf, - oob_required, page, cached, + oob_required, page, (ops->mode == MTD_OPS_RAW)); if (ret) break; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 72b2328..c4363cc 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -849,7 +849,7 @@ struct nand_chip { int status, int page); int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, uint32_t offset, int data_len, const uint8_t *buf, - int oob_required, int page, int cached, int raw); + int oob_required, int page, int raw); int (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *chip, int feature_addr, uint8_t *subfeature_para); int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip, From patchwork Tue Nov 21 17:38:25 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119391 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5583073qgn; Tue, 21 Nov 2017 09:54:33 -0800 (PST) X-Google-Smtp-Source: AGs4zMb6KY52QypD8MEP3+BxwCd0Ls176ZPChAz3jb1bKT4mqjX/4KWTHqiJVFMPniKvhxOgp/Jv X-Received: by 10.80.179.246 with SMTP id t51mr25462058edd.176.1511286873892; Tue, 21 Nov 2017 09:54:33 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286873; cv=none; d=google.com; s=arc-20160816; b=NEjJiAw1y4TkP9ATer+NaCk+KAr93V/9JttjBVMx+0F27TjU0aelAyd6zlN3DYyoP7 lnsKOxwx86A9EYbGPUQZJtQhqKIsdBnegS3/elKyZW0djhMS+sjhP6Z8M+oAmbDDA9Pb Cyj6zLNBDJNqYRZOk6C0MdeQOAZU2xvHX+An+nCtNlnvsLo21cHuCoRMyXhPlT673y97 x0CM3sl9zZMjLMftfPhGAEladyKSExExEJmDNkI/YIzDz5kY3AbHt+oF1r/m4hQcJkEf Uz1mpDQzg2Ipn5PR4VujXoSbxIL3niKJsGbSvQSicziQhc6IX2N98ebI80c3rKr8q7h/ WDng== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=ZNEUY9swcBJPVHklTtzb3vTXJ/YwWETV94Ilm9xGqVM=; b=nlSNR1Ml/CcdLw/FuBDlRiR5M8uPJryh/ykYIkkXwEZTE4/9OJ2yjbufe+g033KI2j EwQ5dhok50w8TFAgvBH1+jF6E/KA610uI+IExeubTP66tZC2cJOTvdyThwhB+xL9APwL vp/ZapK/xn3Ys/9HhePYEek1Yg04Wd6ocz/JV/dSNXsyTNfh/MeYF44Ga5zuRGuk+fGZ gL0PxP/Ig49V92YBOTI2JkvhA1U8uA+la7q430XXxzS/J8pd4jM+Qr5AX4yOF5MyvYYy figl8z49Dm7l1G7J/uKJ0gH7yK49Fw08LSDaAn6/O5OUPnq7nSyTtSBpuhmj8nZVLBTa MNAg== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=TIIGFGfo; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id i35si4742871edd.292.2017.11.21.09.54.33; Tue, 21 Nov 2017 09:54:33 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=TIIGFGfo; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id 647DBC21EE3; Tue, 21 Nov 2017 17:52:10 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 735A7C21D95; Tue, 21 Nov 2017 17:39:49 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 73594C21FE2; Tue, 21 Nov 2017 17:39:07 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id B561DC21F20 for ; Tue, 21 Nov 2017 17:39:03 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbu5001225; Wed, 22 Nov 2017 02:38:44 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbu5001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285924; bh=yvkW+Yga9w5eKndYN1zmtXhOwMkII/YdO50sHzaoJd8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TIIGFGfortsp7i+67ut/vfaxt6603IQYB/Ng0soeHlzPpNi6Ijf7DZXkm+7VTKvMa VMtxi5efgHsZKQ+nYy9RXnf25p6R6aLRLBQhgznq1xMEYIyHbkcIiAbECLp7HPBx8o 80ah1V53QiDG/ZdjxUbYFcW9ZDUDAEET04QgkkEA4TvqHg2GNrFmEiAP/jkJXwxYvE giyZAB0EDxohOFBAyHM1Jxq10c5mmPQWUy5SJsFXa6xXh6fkFyuaYujvzTb9u6fwoS R6u93LqWQhXIXMVz54bNdlFxaxL2CaZ/T7trXpTaBG4jodgjCEE/cMteqpHVzu9H2R A9e2UKTuLi6xw== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:25 +0900 Message-Id: <1511285912-12452-16-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 15/22] mtd: nand: Drop the ->errstat() hook X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Boris Brezillon The ->errstat() hook is no longer implemented NAND controller drivers. Get rid of it before someone starts abusing it. Signed-off-by: Boris Brezillon [Linux commit: 7d135bcced20be2b50128432c5426a7278ec4f6d] [masahiro: modify davinci_nand.c for U-Boot] Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/davinci_nand.c | 7 ------- drivers/mtd/nand/nand_base.c | 15 --------------- include/linux/mtd/nand.h | 5 ----- 3 files changed, 27 deletions(-) diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 1e1f4b5..65104c6 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -394,13 +394,6 @@ static int nand_davinci_write_page(struct mtd_info *mtd, struct nand_chip *chip, chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); status = chip->waitfunc(mtd, chip); - /* - * See if operation failed and additional status checks are - * available. - */ - if ((status & NAND_STATUS_FAIL) && (chip->errstat)) - status = chip->errstat(mtd, chip, FL_WRITING, status, page); - if (status & NAND_STATUS_FAIL) { ret = -EIO; goto err; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 0be427f..91afa47 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2442,13 +2442,6 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, if (nand_standard_page_accessors(&chip->ecc)) chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); status = chip->waitfunc(mtd, chip); - /* - * See if operation failed and additional status checks are - * available. - */ - if ((status & NAND_STATUS_FAIL) && (chip->errstat)) - status = chip->errstat(mtd, chip, FL_WRITING, status, - page); if (status & NAND_STATUS_FAIL) return -EIO; @@ -2924,14 +2917,6 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, status = chip->erase(mtd, page & chip->pagemask); - /* - * See if operation failed and additional status checks are - * available - */ - if ((status & NAND_STATUS_FAIL) && (chip->errstat)) - status = chip->errstat(mtd, chip, FL_ERASING, - status, page); - /* See if block erase succeeded */ if (status & NAND_STATUS_FAIL) { pr_debug("%s: failed erase, page 0x%08x\n", diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index c4363cc..be30059 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -817,9 +817,6 @@ nand_get_sdr_timings(const struct nand_data_interface *conf) * structure which is shared among multiple independent * devices. * @priv: [OPTIONAL] pointer to private chip data - * @errstat: [OPTIONAL] hardware specific function to perform - * additional error status checks (determine if errors are - * correctable). * @write_page: [REPLACEABLE] High-level page write function */ @@ -845,8 +842,6 @@ struct nand_chip { int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this); int (*erase)(struct mtd_info *mtd, int page); int (*scan_bbt)(struct mtd_info *mtd); - int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, - int status, int page); int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, uint32_t offset, int data_len, const uint8_t *buf, int oob_required, int page, int raw); From patchwork Tue Nov 21 17:38:26 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119385 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5577799qgn; Tue, 21 Nov 2017 09:50:24 -0800 (PST) X-Google-Smtp-Source: AGs4zMarffdM3ua0d5/9Fc4ShnJk9wJcc3C5Ac8/ZydOwce8YE7IgW+fu9Y+v9PCxO4+OWChc7HN X-Received: by 10.80.214.74 with SMTP id c10mr7886696edj.271.1511286624164; Tue, 21 Nov 2017 09:50:24 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286624; cv=none; d=google.com; s=arc-20160816; b=N6dCsBi9v+PcGEDzQaK/iWnbbEktoc3dLVtR0VcpZmDO4H6SEvzCSknh/e66T+v3N3 fDh5ccmVKnisf5dlPSSYXxZEclL3B3Ndu1GBdulNAP7tm88bb1y3ExscrNKk5aFlh0qD Wo/5Mkw1zH42O4oPeT1Y84ipu7MUBphOUvoEFLYf/0GbnRXGBjov2Kdu5rNcvPN8Dlgb eRe1aaHxycM7iM3Ut+dMWT0Rg9rC6GWxXObJET/Q3vVSChh6SDvFr8K+gekESO4cJpzT k6SbM+hmUom2DwBBzgy/j5wtLc6oIDjDwE4DD6ACeDFgobHmo/JIlOtiqKEQtIse92dK jNwA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=3XptSt+RFTgz+CeXo84XAwFirSfX5kohizaJ82xBdJs=; b=yLMxp28lf3WFTWldnAD3zVDngpS/E5yGi7e3fYjBga5FfzfyRrPyBoz5Kyey6x40qM xhBX1uVKwAX+nU48kZI3pxphGWCJoip7SNFs3vSgtV5jCJ49EIjtz4PWaYyp0aaXDxo8 EKws8h2KWHtbPsy4yhTC5FwbMUtM5IamWrSJp3u0ogwDcW9S1n3ck2mg3l+U6wluquSk 5BrPvXfbJcc4JizK8ANXpfK0w5nofJWqJNC4sR02Jx1gdnd6Y4sIBCfL8RHVzUHXToVW JETwzvuSKE24zruayGrI9sLUyqiYGELWzG+l4bX2e8Y6Bx1M0RQZmCvPTkA+X+wTn2CQ x8ow== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=E+aCzr7b; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id i42si864093ede.137.2017.11.21.09.50.23; Tue, 21 Nov 2017 09:50:24 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=E+aCzr7b; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id ABF62C21E4B; Tue, 21 Nov 2017 17:47:11 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 036F8C21FC4; Tue, 21 Nov 2017 17:39:37 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 01E87C21F0F; Tue, 21 Nov 2017 17:39:07 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id 24C98C21F47 for ; Tue, 21 Nov 2017 17:39:03 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbu6001225; Wed, 22 Nov 2017 02:38:44 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbu6001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285924; bh=YWDOqS+PC/d5dcFnkQ1TiGx3cgHLxYJ3xQITDtHWUc0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=E+aCzr7bie5b7zbBDp/GHurq5TRxc/Io4sM+LVDqc1Pap1HacFXSkyXlWwbRF4drj YMQwMstC4Zp9zg5ilimReHm+Q1cmMWKJDDDCbvcn/o3NSAjq76kC1Yu0r6qP87JHkq o7AOMkkTT0nvVFcNZO9Gj62rI15S+fAaTHW122krJGneyk//4LqJLGCyxBMSK/AM7U 5a0cU58V6XXHuamwrtv2lCmJPZWXrn+nUtk/qzgU0TO1IBC04jh5JqG6IQeuiN6RF1 SvyiHKnPyd2KLkXFjh2soYEPAfgjm8pMMErshibhhRq5BrIy1YjB6kqGo/k6s3VGR2 CkwqNDXFM1ywA== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:26 +0900 Message-Id: <1511285912-12452-17-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 16/22] mtd: nand: Wait for PAGEPROG to finish in drivers setting NAND_ECC_CUSTOM_PAGE_ACCESS X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Boris Brezillon Drivers setting NAND_ECC_CUSTOM_PAGE_ACCESS are supposed to handle the full read/write page sequence, and waiting for a page to actually be programmed is part of this write-page sequence. This is also what is done in ->write_oob_xxx() hooks, so let's do that in ->write_page_xxx() as well to make it consistent. Signed-off-by: Boris Brezillon [Linux commit: 41145649f4acb30249b636b945053db50c9331c5] [masahiro: There is no driver setting NAND_ECC_CUSTOM_PAGE_ACCESS in U-Boot. No driver is affected by this change.] Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/nand_base.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 91afa47..16d4554 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2439,12 +2439,13 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, if (status < 0) return status; - if (nand_standard_page_accessors(&chip->ecc)) + if (nand_standard_page_accessors(&chip->ecc)) { chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - status = chip->waitfunc(mtd, chip); - if (status & NAND_STATUS_FAIL) - return -EIO; + status = chip->waitfunc(mtd, chip); + if (status & NAND_STATUS_FAIL) + return -EIO; + } return 0; } From patchwork Tue Nov 21 17:38:27 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119375 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5569816qgn; Tue, 21 Nov 2017 09:42:51 -0800 (PST) X-Google-Smtp-Source: AGs4zMY+FzcY3GE85r/iOy+Dr/AJDm4tGIqwlBWcv5pThcLw9e4/mqtiS15EWHqd4hlOUmvEonsb X-Received: by 10.80.212.34 with SMTP id t34mr22761455edh.22.1511286171856; Tue, 21 Nov 2017 09:42:51 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286171; cv=none; d=google.com; s=arc-20160816; b=dQ6ZApjNAeyNpUv+9IwbvwWJww4Zvv6MJ6US2Dc6wReMsVe7SA/oSeQlE+gZTRMTMt BbRUeaoUD05OUOovuo0419L/QotafskRXb2Fjuf8wI7KiGqCRG8og18vvyl0EDkFjHLj AiIZhf0hWuTQ1piMJEzKteEmnJGRG0W6m9a0K/wa8U7+A6VW/DtQ4Zh3VhRHPN2zPg97 einH0Gagpe1o1FQT2lBEGwIe6NNNuQrxp2YnTVO3AZ/MBwXc57S1TpCmFG2BViuGiBJR 4H/6cFASjmAqvx6pvI484Cu67I0Nwkz8LLegFS29uWEQFrW5H6g1g5T07Z2BIQgvOi0e Mo4g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=b/fMlfoIHojAJi8xfDsDxefuMyYyI2l+g4Afq5v6F6o=; b=rGdYJ3NghHGZMASZUeXvkvdvaEDg0EdtfERcGPHXjYVnJ+0NO/xmhyI/ieJUEET2uP SopMvIqxvMrumfWiJTVQAsiRCHeb03Y1wOJloRrCJR3merslpVZoE3Xjc2Jkd8J/rdua s26p8MflgaNlOzI5yv/7wnKUe6v215JhpqKiPqyGeLKi70znH/r0a5kwJnbOnKCWlAXI EYG8CX9zXu3OapBvma9geL1/G8XbsH7rmkmic1VG0tYyLpUrIA2XEde/xPQK7w9q/GOc 0OG5zLkCxhlFdmAJvX2GiQi5vLGn1mlyXvl4NF255GE3g2gvkwShIPLmyeMWh3dBn/kt 44/A== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=eFX1BMFp; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id m1si1357174edf.525.2017.11.21.09.42.51; Tue, 21 Nov 2017 09:42:51 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=eFX1BMFp; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id 52BB6C21F00; Tue, 21 Nov 2017 17:40:24 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 5A764C21F5B; Tue, 21 Nov 2017 17:39:19 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 8A2CBC21F63; Tue, 21 Nov 2017 17:39:07 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id 98AECC21F69 for ; Tue, 21 Nov 2017 17:39:04 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbu7001225; Wed, 22 Nov 2017 02:38:45 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbu7001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285925; bh=P7UIeRvGD6ISFDmVSxdF+iQFJq1Kmzt0to3lxC/wTmo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=eFX1BMFpaO2arF4keedIeCgkg8tbuEfpxg223IgikEcV3dIf4DvSwXpuQR72e9n59 Og/7rkBHasFEbIpYZwYuS/eC3qTwLaRaTtOM04sUl2YZduYWN7EI91RyA6AGBQ4BXY JfGO8eeqdR7Q9JyipbgWxJggXEOUsjJWg+Z5QamZmRjVckhbH8vTd/3I2LcVJiFvjH Ei5LKpiCpyFs8uEG6Oeaekq6hx1T6yB8LFTN7nFwEbFM+OvE/kQVOZXHVeFATxct1B EMWULfuccoSZU+OdrxMewL9dsJyHqcSgnKfZYuKL0NDDB3+KFH1a2WaDKlfGL0UAZl 9gCpxXNjx2tDg== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:27 +0900 Message-Id: <1511285912-12452-18-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 17/22] mtd: nand: allow drivers to request minimum alignment for passed buffer X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" In some cases, nand_do_{read,write}_ops is passed with unaligned ops->datbuf. Drivers using DMA will be unhappy about unaligned buffer. The new struct member, buf_align, represents the minimum alignment the driver require for the buffer. If the buffer passed from the upper MTD layer does not have enough alignment, nand_do_*_ops will use bufpoi. Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon [Linux commit: 477544c62a84d3bacd9f90ba75ffc16c04d78071] --- drivers/mtd/nand/nand_base.c | 8 ++++++++ include/linux/mtd/nand.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 16d4554..f3c515b 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1720,6 +1720,9 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, if (!aligned) use_bufpoi = 1; + else if (chip->options & NAND_USE_BOUNCE_BUFFER) + use_bufpoi = !IS_ALIGNED((unsigned long)buf, + chip->buf_align); else use_bufpoi = 0; @@ -2575,6 +2578,9 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, if (part_pagewr) use_bufpoi = 1; + else if (chip->options & NAND_USE_BOUNCE_BUFFER) + use_bufpoi = !IS_ALIGNED((unsigned long)buf, + chip->buf_align); else use_bufpoi = 0; @@ -3119,6 +3125,8 @@ static void nand_set_defaults(struct nand_chip *chip, int busw) init_waitqueue_head(&chip->controller->wq); } + if (!chip->buf_align) + chip->buf_align = 1; } /* Sanitize ONFI strings so we can safely print them */ diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index be30059..90c6010 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -752,6 +752,7 @@ nand_get_sdr_timings(const struct nand_data_interface *conf) * setting the read-retry mode. Mostly needed for MLC NAND. * @ecc: [BOARDSPECIFIC] ECC control structure * @buffers: buffer structure for read/write + * @buf_align: minimum buffer alignment required by a platform * @hwcontrol: platform-specific hardware control structure * @erase: [REPLACEABLE] erase function * @scan_bbt: [REPLACEABLE] function to scan bad block table @@ -893,6 +894,7 @@ struct nand_chip { struct nand_ecc_ctrl ecc; struct nand_buffers *buffers; + unsigned long buf_align; struct nand_hw_control hwcontrol; uint8_t *bbt; From patchwork Tue Nov 21 17:38:28 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119381 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5573120qgn; Tue, 21 Nov 2017 09:46:07 -0800 (PST) X-Google-Smtp-Source: AGs4zMYUAzXea1NY/F0ey3TmoL5wWph7LswLS1w76Cy6HdXvUMQInF9HJqRVDPEV7sO0iu3HreIs X-Received: by 10.80.172.122 with SMTP id w55mr26042461edc.144.1511286367604; Tue, 21 Nov 2017 09:46:07 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286367; cv=none; d=google.com; s=arc-20160816; b=ogNMKw7jVeVD3Tl0yFLF1KtneS0j3Bsf37OOQa/YohefqluyUqrlRMuDr2ycnYkKo1 nvXRKMbzF1UsgKFA0pIUN6IcVKvkWdfO1eCzPZ2w2ZmU3/oafJEjuWUxj+bcTtkG61FB f8JbiugCMw8peW+XDprOwxFiyVb40c+YtUe4md7VhNxKjCVn7FdeP9F2PLSXqhLC/Ncq +wL671HE16MfdlmEGgdLxHO6UJQlJYOH0lT8gSC/zejBEamYwOPYP3bCL5hjXtf8+Pc+ YcmEUTbC8JVlwvtsy1E4jTKAm7VlmeizvL+6VPqh4stPPiB4p6+Hndae3orHQ4I/r7EJ 4qNw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=lZUPajJNt/sekdB35abHQpPB0ZHvw2TikGYzIHGnXls=; b=NT6waT37uDLdAhFgYZHJT77GGkC1gGHjmSmCNFaQOx5lEAIAaf8dArvD0Hqp74euIB fp5ADKO1TU92pLklplpaaTm7edOQzKALgoWzg+Xzvv0yDyPyb5NXuXee2AV56J+/D7YK D9xAar3wV26D1jOKnOx+KQ2xY4bH+bFfYgfB9X6WgWVzdd7fnKUzbddOWYFD+nO2GL2R wreUc4EFJF3kaxiGl5826osMzp6fyGhLEmXWWjzOQi3BUFOAQGvUSSUOFHlYWwvW7ohk qVHQGuGEtSHbvLpbDT/qicGfOFGmjx5mFQ/9QQzgmBQfNwa8d3TtjSZLufHQ/iLkWlm5 PvCw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=tAvJhEgc; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id i17si3095836edg.395.2017.11.21.09.46.07; Tue, 21 Nov 2017 09:46:07 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=tAvJhEgc; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id 213A3C21F31; Tue, 21 Nov 2017 17:43:28 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 66CF0C21F91; Tue, 21 Nov 2017 17:39:32 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 79B33C21F88; Tue, 21 Nov 2017 17:39:07 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id ED6E2C21F0F for ; Tue, 21 Nov 2017 17:39:03 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbu8001225; Wed, 22 Nov 2017 02:38:45 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbu8001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285925; bh=72ytamnGue2OKahVu94xkDaUguCIa2qd8G8mU2Bu4KQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=tAvJhEgc0aNjpWv4xWaoguf7sPRzxMT+M1i/MY1kGgybuggTy5ZvMIPJROqZSE/zG pDvsRxIq87d53f7lfLk1cmMJ8y+cqjt6v2Fj01AXESCyKUvfUZnrwz28OXgfFx5HZp TUl6E56iyW2UNgAJNp66VUJFCHfMmjiulxZdWa8k8bGnj0D5Did+WAF4L9xy/xF9Ir lNHYEHj3qPwoXwcYKGx4s20mZGLW3Go8Mtx5yrFnrq0L/GFAKc7t6d1eLDSNwYZUkY /PynVkxK9jaDZ+hyhdfof46gVVkhm2SQSYoeVAYV1F4iPBwkBmxl0rB0blwk5tueeM 4IM5P9ixJVp6Q== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:28 +0900 Message-Id: <1511285912-12452-19-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 18/22] mtd: nand: Pass the CS line to ->setup_data_interface() X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Boris Brezillon Some NAND controllers can assign different NAND timings to different CS lines. Pass the CS line information to ->setup_data_interface() so that the NAND controller driver knows which CS line is concerned by the setup_data_interface() request. Signed-off-by: Boris Brezillon [Linux commit: 104e442a67cfba4d0cc982384761befb917fb6a1] Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/nand_base.c | 22 +++++++++++++--------- include/linux/mtd/nand.h | 12 ++++++++---- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index f3c515b..e490c84 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -904,12 +904,13 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) /** * nand_reset_data_interface - Reset data interface and timings * @chip: The NAND chip + * @chipnr: Internal die id * * Reset the Data interface and timings to ONFI mode 0. * * Returns 0 for success or negative error code otherwise. */ -static int nand_reset_data_interface(struct nand_chip *chip) +static int nand_reset_data_interface(struct nand_chip *chip, int chipnr) { struct mtd_info *mtd = nand_to_mtd(chip); const struct nand_data_interface *conf; @@ -933,7 +934,7 @@ static int nand_reset_data_interface(struct nand_chip *chip) */ conf = nand_get_default_data_interface(); - ret = chip->setup_data_interface(mtd, conf, false); + ret = chip->setup_data_interface(mtd, chipnr, conf); if (ret) pr_err("Failed to configure data interface to SDR timing mode 0\n"); @@ -943,6 +944,7 @@ static int nand_reset_data_interface(struct nand_chip *chip) /** * nand_setup_data_interface - Setup the best data interface and timings * @chip: The NAND chip + * @chipnr: Internal die id * * Find and configure the best data interface and NAND timings supported by * the chip and the driver. @@ -952,7 +954,7 @@ static int nand_reset_data_interface(struct nand_chip *chip) * * Returns 0 for success or negative error code otherwise. */ -static int nand_setup_data_interface(struct nand_chip *chip) +static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) { struct mtd_info *mtd = nand_to_mtd(chip); int ret; @@ -976,7 +978,7 @@ static int nand_setup_data_interface(struct nand_chip *chip) goto err; } - ret = chip->setup_data_interface(mtd, chip->data_interface, false); + ret = chip->setup_data_interface(mtd, chipnr, chip->data_interface); err: return ret; } @@ -1027,8 +1029,10 @@ static int nand_init_data_interface(struct nand_chip *chip) if (ret) continue; - ret = chip->setup_data_interface(mtd, chip->data_interface, - true); + /* Pass -1 to only */ + ret = chip->setup_data_interface(mtd, + NAND_DATA_IFACE_CHECK_ONLY, + chip->data_interface); if (!ret) { chip->onfi_timing_mode_default = mode; break; @@ -1055,7 +1059,7 @@ int nand_reset(struct nand_chip *chip, int chipnr) struct mtd_info *mtd = nand_to_mtd(chip); int ret; - ret = nand_reset_data_interface(chip); + ret = nand_reset_data_interface(chip, chipnr); if (ret) return ret; @@ -1068,7 +1072,7 @@ int nand_reset(struct nand_chip *chip, int chipnr) chip->select_chip(mtd, -1); chip->select_chip(mtd, chipnr); - ret = nand_setup_data_interface(chip); + ret = nand_setup_data_interface(chip, chipnr); chip->select_chip(mtd, -1); if (ret) return ret; @@ -4037,7 +4041,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, * For the other dies, nand_reset() will automatically switch to the * best mode for us. */ - ret = nand_setup_data_interface(chip); + ret = nand_setup_data_interface(chip, 0); if (ret) return ret; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 90c6010..b1a6648 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -124,6 +124,8 @@ void nand_wait_ready(struct mtd_info *mtd); #define NAND_STATUS_READY 0x40 #define NAND_STATUS_WP 0x80 +#define NAND_DATA_IFACE_CHECK_ONLY -1 + /* * Constants for ECC_MODES */ @@ -807,7 +809,10 @@ nand_get_sdr_timings(const struct nand_data_interface *conf) * @read_retries: [INTERN] the number of read retry modes supported * @onfi_set_features: [REPLACEABLE] set the features for ONFI nand * @onfi_get_features: [REPLACEABLE] get the features for ONFI nand - * @setup_data_interface: [OPTIONAL] setup the data interface and timing + * @setup_data_interface: [OPTIONAL] setup the data interface and timing. If + * chipnr is set to %NAND_DATA_IFACE_CHECK_ONLY this + * means the configuration should not be applied but + * only checked. * @bbt: [INTERN] bad block table pointer * @bbt_td: [REPLACEABLE] bad block table descriptor for flash * lookup. @@ -851,9 +856,8 @@ struct nand_chip { int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip, int feature_addr, uint8_t *subfeature_para); int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode); - int (*setup_data_interface)(struct mtd_info *mtd, - const struct nand_data_interface *conf, - bool check_only); + int (*setup_data_interface)(struct mtd_info *mtd, int chipnr, + const struct nand_data_interface *conf); int chip_delay; From patchwork Tue Nov 21 17:38:29 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119390 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5582732qgn; Tue, 21 Nov 2017 09:54:13 -0800 (PST) X-Google-Smtp-Source: AGs4zMZGljgYCHz9D7zbNJcruh+OOnNfJODqs6hmGfwnjxbxnLj4K0QAYliDFTUoaBptZvBxXbvQ X-Received: by 10.80.207.134 with SMTP id h6mr25740743edk.189.1511286853234; Tue, 21 Nov 2017 09:54:13 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286853; cv=none; d=google.com; s=arc-20160816; b=htXuYy92njj658TI/U6fmLSHEZT986R/fdPFIYdCHyz39MIQwhuOEBbfr0pNVMH2Jm RVlD2yGtAsjALfYPVcAAxX3weFcxjSP/BNogo+7uASKHGa/r9SPMAOOlhtgk5uNVT2mO paJ7tVn7oT/FuPw83Hp+JNFdJRQMYZQLv9FbNBgIzpdwPvnkUpUP2bISKJg/JhWSMJTM imycu3kL+JrM/kPj4xWOLV1z4qUQJO6L3oCPv7JPzVagwLQyMB14YfghDyENqpWbqB2p caO55MM8t+nCD8/GmwIemBOaWW11k23VRIQ6+K/9+KwP+rqfdJuHg400kRwmXznsWvSV 7WhQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=c0Qt+XhIYWDwLTG5d4emht9OdxSwXSZaw+LZ90+t6JY=; b=LYHnP5M/TKlHVSpeeOcSe0ydqPq5HU8INhxGUc0lQh8Rn3PWAZFjGWdyioI15ofwql FzM/sRUpCTzX0kfanvhvX1T3LzlPzvZDd20MakOHNxXgpKAY57ELUwFiGK63bgh3ZHIV 3XGLQQWlOnW5BTW0Mi2mipF10Ni3IjpUfbJxLojZPPuh6zLMDWBktew8onHRi/Cx5RGn ReJcDRovJg6+MV4rZh2oYN1jJQsXxU0cDbwGUaJ2R0O/+cDjEitQ0cfOHAMeFYZy6Bmy xeMz/PwuJ4wo5wKodB0cfKg/vEetZUtnz3UEf/YBgDTXPQYAWfO1noIqJCf/KW1mCJvE opHw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=AZOn1ktz; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id t10si10664215eda.75.2017.11.21.09.54.12; Tue, 21 Nov 2017 09:54:13 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=AZOn1ktz; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id D1844C21F5E; Tue, 21 Nov 2017 17:52:27 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 6C870C2201E; Tue, 21 Nov 2017 17:39:52 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 5AFE3C2201E; Tue, 21 Nov 2017 17:39:07 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id BBB84C21DDF for ; Tue, 21 Nov 2017 17:39:04 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbu9001225; Wed, 22 Nov 2017 02:38:45 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbu9001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285925; bh=vsthWPtVn/aTIEz0b+OTr63okw3+cM1kX7LY6k9eXD4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=AZOn1ktzQJMJR8JnBq888Z/iyCTSwkvDicUfwcqNpZeSqQR2jhafiocVsE+Eooi0x yZFShDNF5Flv8WZrTq7JU8Vsd1XmsDnDhKhjYGP1RgsOFoJDzTfB3y2BOJ8SX3DAI2 NdOw2WBcPZxXwhRm70zo8SurIG5JeGfW5xsGiVpPyb+f04ak1cJo7vq/gzKR6W8+P6 O/n0N/LXoELjUK54NAAmaFdrkyrPPAU8YXIJRjEOdPfNApI8h8ZuCd00JLMkk8i+xt QjhYqcGHY6JF6tpWiPhe00MLE/caZyJc8hhl1feiXqqIZ5hEMKgHpr4zh8FbA19nEk 8JACd2KJxYw0Q== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:29 +0900 Message-Id: <1511285912-12452-20-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 19/22] mtd: nand: add generic helpers to check, match, maximize ECC settings X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Driver are responsible for setting up ECC parameters correctly. Those include: - Check if ECC parameters specified (usually by DT) are valid - Meet the chip's ECC requirement - Maximize ECC strength if NAND_ECC_MAXIMIZE flag is set The logic can be generalized by factoring out common code. This commit adds 3 helpers to the NAND framework: nand_check_ecc_caps - Check if preset step_size and strength are valid nand_match_ecc_req - Match the chip's requirement nand_maximize_ecc - Maximize the ECC strength To use the helpers above, a driver needs to provide: - Data array of supported ECC step size and strength - A hook that calculates ECC bytes from the combination of step_size and strength. By using those helpers, code duplication among drivers will be reduced. Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon [Linux commit: 2c8f8afa7f92acb07641bf95b940d384ed1d0294] --- drivers/mtd/nand/nand_base.c | 220 +++++++++++++++++++++++++++++++++++++++++++ include/linux/mtd/nand.h | 33 +++++++ 2 files changed, 253 insertions(+) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index e490c84..77a3f16 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -4077,6 +4077,226 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, } EXPORT_SYMBOL(nand_scan_ident); +/** + * nand_check_ecc_caps - check the sanity of preset ECC settings + * @chip: nand chip info structure + * @caps: ECC caps info structure + * @oobavail: OOB size that the ECC engine can use + * + * When ECC step size and strength are already set, check if they are supported + * by the controller and the calculated ECC bytes fit within the chip's OOB. + * On success, the calculated ECC bytes is set. + */ +int nand_check_ecc_caps(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + const struct nand_ecc_step_info *stepinfo; + int preset_step = chip->ecc.size; + int preset_strength = chip->ecc.strength; + int nsteps, ecc_bytes; + int i, j; + + if (WARN_ON(oobavail < 0)) + return -EINVAL; + + if (!preset_step || !preset_strength) + return -ENODATA; + + nsteps = mtd->writesize / preset_step; + + for (i = 0; i < caps->nstepinfos; i++) { + stepinfo = &caps->stepinfos[i]; + + if (stepinfo->stepsize != preset_step) + continue; + + for (j = 0; j < stepinfo->nstrengths; j++) { + if (stepinfo->strengths[j] != preset_strength) + continue; + + ecc_bytes = caps->calc_ecc_bytes(preset_step, + preset_strength); + if (WARN_ON_ONCE(ecc_bytes < 0)) + return ecc_bytes; + + if (ecc_bytes * nsteps > oobavail) { + pr_err("ECC (step, strength) = (%d, %d) does not fit in OOB", + preset_step, preset_strength); + return -ENOSPC; + } + + chip->ecc.bytes = ecc_bytes; + + return 0; + } + } + + pr_err("ECC (step, strength) = (%d, %d) not supported on this controller", + preset_step, preset_strength); + + return -ENOTSUPP; +} +EXPORT_SYMBOL_GPL(nand_check_ecc_caps); + +/** + * nand_match_ecc_req - meet the chip's requirement with least ECC bytes + * @chip: nand chip info structure + * @caps: ECC engine caps info structure + * @oobavail: OOB size that the ECC engine can use + * + * If a chip's ECC requirement is provided, try to meet it with the least + * number of ECC bytes (i.e. with the largest number of OOB-free bytes). + * On success, the chosen ECC settings are set. + */ +int nand_match_ecc_req(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + const struct nand_ecc_step_info *stepinfo; + int req_step = chip->ecc_step_ds; + int req_strength = chip->ecc_strength_ds; + int req_corr, step_size, strength, nsteps, ecc_bytes, ecc_bytes_total; + int best_step, best_strength, best_ecc_bytes; + int best_ecc_bytes_total = INT_MAX; + int i, j; + + if (WARN_ON(oobavail < 0)) + return -EINVAL; + + /* No information provided by the NAND chip */ + if (!req_step || !req_strength) + return -ENOTSUPP; + + /* number of correctable bits the chip requires in a page */ + req_corr = mtd->writesize / req_step * req_strength; + + for (i = 0; i < caps->nstepinfos; i++) { + stepinfo = &caps->stepinfos[i]; + step_size = stepinfo->stepsize; + + for (j = 0; j < stepinfo->nstrengths; j++) { + strength = stepinfo->strengths[j]; + + /* + * If both step size and strength are smaller than the + * chip's requirement, it is not easy to compare the + * resulted reliability. + */ + if (step_size < req_step && strength < req_strength) + continue; + + if (mtd->writesize % step_size) + continue; + + nsteps = mtd->writesize / step_size; + + ecc_bytes = caps->calc_ecc_bytes(step_size, strength); + if (WARN_ON_ONCE(ecc_bytes < 0)) + continue; + ecc_bytes_total = ecc_bytes * nsteps; + + if (ecc_bytes_total > oobavail || + strength * nsteps < req_corr) + continue; + + /* + * We assume the best is to meet the chip's requrement + * with the least number of ECC bytes. + */ + if (ecc_bytes_total < best_ecc_bytes_total) { + best_ecc_bytes_total = ecc_bytes_total; + best_step = step_size; + best_strength = strength; + best_ecc_bytes = ecc_bytes; + } + } + } + + if (best_ecc_bytes_total == INT_MAX) + return -ENOTSUPP; + + chip->ecc.size = best_step; + chip->ecc.strength = best_strength; + chip->ecc.bytes = best_ecc_bytes; + + return 0; +} +EXPORT_SYMBOL_GPL(nand_match_ecc_req); + +/** + * nand_maximize_ecc - choose the max ECC strength available + * @chip: nand chip info structure + * @caps: ECC engine caps info structure + * @oobavail: OOB size that the ECC engine can use + * + * Choose the max ECC strength that is supported on the controller, and can fit + * within the chip's OOB. On success, the chosen ECC settings are set. + */ +int nand_maximize_ecc(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + const struct nand_ecc_step_info *stepinfo; + int step_size, strength, nsteps, ecc_bytes, corr; + int best_corr = 0; + int best_step = 0; + int best_strength, best_ecc_bytes; + int i, j; + + if (WARN_ON(oobavail < 0)) + return -EINVAL; + + for (i = 0; i < caps->nstepinfos; i++) { + stepinfo = &caps->stepinfos[i]; + step_size = stepinfo->stepsize; + + /* If chip->ecc.size is already set, respect it */ + if (chip->ecc.size && step_size != chip->ecc.size) + continue; + + for (j = 0; j < stepinfo->nstrengths; j++) { + strength = stepinfo->strengths[j]; + + if (mtd->writesize % step_size) + continue; + + nsteps = mtd->writesize / step_size; + + ecc_bytes = caps->calc_ecc_bytes(step_size, strength); + if (WARN_ON_ONCE(ecc_bytes < 0)) + continue; + + if (ecc_bytes * nsteps > oobavail) + continue; + + corr = strength * nsteps; + + /* + * If the number of correctable bits is the same, + * bigger step_size has more reliability. + */ + if (corr > best_corr || + (corr == best_corr && step_size > best_step)) { + best_corr = corr; + best_step = step_size; + best_strength = strength; + best_ecc_bytes = ecc_bytes; + } + } + } + + if (!best_corr) + return -ENOTSUPP; + + chip->ecc.size = best_step; + chip->ecc.strength = best_strength; + chip->ecc.bytes = best_ecc_bytes; + + return 0; +} +EXPORT_SYMBOL_GPL(nand_maximize_ecc); + /* * Check if the chip configuration meet the datasheet requirements. diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index b1a6648..2d5f9a4 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -488,6 +488,30 @@ struct nand_hw_control { }; /** + * struct nand_ecc_step_info - ECC step information of ECC engine + * @stepsize: data bytes per ECC step + * @strengths: array of supported strengths + * @nstrengths: number of supported strengths + */ +struct nand_ecc_step_info { + int stepsize; + const int *strengths; + int nstrengths; +}; + +/** + * struct nand_ecc_caps - capability of ECC engine + * @stepinfos: array of ECC step information + * @nstepinfos: number of ECC step information + * @calc_ecc_bytes: driver's hook to calculate ECC bytes per step + */ +struct nand_ecc_caps { + const struct nand_ecc_step_info *stepinfos; + int nstepinfos; + int (*calc_ecc_bytes)(int step_size, int strength); +}; + +/** * struct nand_ecc_ctrl - Control structure for ECC * @mode: ECC mode * @steps: number of ECC steps per page @@ -1218,6 +1242,15 @@ int nand_check_erased_ecc_chunk(void *data, int datalen, void *extraoob, int extraooblen, int threshold); +int nand_check_ecc_caps(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail); + +int nand_match_ecc_req(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail); + +int nand_maximize_ecc(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail); + /* Reset and initialize a NAND device */ int nand_reset(struct nand_chip *chip, int chipnr); From patchwork Tue Nov 21 17:38:30 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119378 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5571403qgn; Tue, 21 Nov 2017 09:44:24 -0800 (PST) X-Google-Smtp-Source: AGs4zMYM1d2rBEvkjnbCZJtdyEPkcgQ56xzL0yXSnXJWe/VSaDbwn2ltAe0QBd0pLJ9zooS/7qtU X-Received: by 10.80.216.202 with SMTP id y10mr12867269edj.221.1511286264323; Tue, 21 Nov 2017 09:44:24 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286264; cv=none; d=google.com; s=arc-20160816; b=lmQoXSFueJ2/cUVDCzX2phxCWOiV17UEBvD/7g1i707duLAXN9AM4ikFBYWZN5KCBU BFdITIbxBDHg29P/P5wCDpXSMOHh/eduaWL+RDQhaH+uIMdwKGltS6fUuQuaClDee3Z0 feIovYkT2E0NPcsmuIVi8AB2iUWSrzN6Rp6uzmqXhZvCOcoMJRS0eSglR5T6yUCK5K1u GXjyoeqc8Q1FXYflJYUOU1gGeBFk14hvAuxch9ImNGqozUgokKlTK02aQvPdMqdUfVb8 LydM8ExXM9kRiRQvC8Oyc48FX9Z6eSPYX3a+u2b9J7FGn1rMq7NjMSyuOinwmLmONBH6 uVUw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=uQxC1SlxIWR0eYRUBrDUWZyWsEUeLqohzS4qQBwrJbU=; b=wRhqD1w7k8VF5AhoGz3T9+ck2/UARRyfwqR2wn4d2kKZlIWLxwgKi5f5jR7MVt+EVp ULj73jJRHGQRaIzT5XWBbDihhHr4YHe+tP7znv3txatW8DHVV8DCDs9CjN/3HebNz46+ Q1j7LAY92nSxBn3cgW/XkWGV++AZt61YQE4X0oiR9KkcoIen7x71Bx6zuoFfucEvL3JD ClMOXTFoTpFjeyw0sFiGWAqRnjA6jizmaToKjh7QLAQYCMaOTmxw3l00HUdN8W26DP0Y l9RtT3Fnff14cJGZLi66eGVyXATcCRQmB7M4fPIqYWNgcl1IPuBlbsEFxL8mPMCQo500 BpGw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=1AjRprMn; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id h63si1390394edc.554.2017.11.21.09.44.23; Tue, 21 Nov 2017 09:44:24 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=1AjRprMn; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id B8565C21F6C; Tue, 21 Nov 2017 17:41:22 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 1404CC21F53; Tue, 21 Nov 2017 17:39:23 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 23A49C21F07; Tue, 21 Nov 2017 17:39:07 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id EEDE4C21F2B for ; Tue, 21 Nov 2017 17:39:03 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbuA001225; Wed, 22 Nov 2017 02:38:46 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbuA001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285926; bh=mrL6nEhsOfvfL7YxyGB1OxHyHCJ6XV1T7bnWigtuUcQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=1AjRprMn0K53asnEOwrg0G+cQt5/cgie6XI6xHwNn/uJt1iawykSImzeXS89XSdVl a+dlAJlilHMoP9kY1lG5tBewpz/iKUwJmG41mGZrDfRAMG8FJtzqan7dGDJpt2JJ2o V28TyZ+21A8i5RxtaWr3ikHKt9CHd98MKDr9h26U7nN/5Y/n0YzEzcMR1oN4iifywp ZuKdjs4BEnqbDY0Un4epYrz4M/YTrCwgNUHIQkxY/wQHPnF+iT4Veuie6aU5FXxcsc 090/p5kTpenVdVDq4w49OkC0b/NlfbN4moAd8vnsIeKQXaz43saOZrNH1q0og4nT2f Jduxyk8PzM/RQ== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:30 +0900 Message-Id: <1511285912-12452-21-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 20/22] mtd: nand: add a shorthand to generate nand_ecc_caps structure X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" struct nand_ecc_caps was designed as flexible as possible to support multiple stepsizes (like sunxi_nand.c). So, we need to write multiple arrays even for the simplest case. I guess many controllers support a single stepsize, so here is a shorthand macro for the case. It allows to describe like ... NAND_ECC_CAPS_SINGLE(denali_pci_ecc_caps, denali_calc_ecc_bytes, 512, 8, 15); ... instead of static const int denali_pci_ecc_strengths[] = {8, 15}; static const struct nand_ecc_step_info denali_pci_ecc_stepinfo = { .stepsize = 512, .strengths = denali_pci_ecc_strengths, .nstrengths = ARRAY_SIZE(denali_pci_ecc_strengths), }; static const struct nand_ecc_caps denali_pci_ecc_caps = { .stepinfos = &denali_pci_ecc_stepinfo, .nstepinfos = 1, .calc_ecc_bytes = denali_calc_ecc_bytes, }; Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon [Linux commit: a03c60178c181767ecfb26fb311a88742d228118] --- include/linux/mtd/nand.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 2d5f9a4..150e3b8 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -511,6 +511,20 @@ struct nand_ecc_caps { int (*calc_ecc_bytes)(int step_size, int strength); }; +/* a shorthand to generate struct nand_ecc_caps with only one ECC stepsize */ +#define NAND_ECC_CAPS_SINGLE(__name, __calc, __step, ...) \ +static const int __name##_strengths[] = { __VA_ARGS__ }; \ +static const struct nand_ecc_step_info __name##_stepinfo = { \ + .stepsize = __step, \ + .strengths = __name##_strengths, \ + .nstrengths = ARRAY_SIZE(__name##_strengths), \ +}; \ +static const struct nand_ecc_caps __name = { \ + .stepinfos = &__name##_stepinfo, \ + .nstepinfos = 1, \ + .calc_ecc_bytes = __calc, \ +} + /** * struct nand_ecc_ctrl - Control structure for ECC * @mode: ECC mode From patchwork Tue Nov 21 17:38:31 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119376 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5570454qgn; Tue, 21 Nov 2017 09:43:29 -0800 (PST) X-Google-Smtp-Source: AGs4zMZX0MHs+83gfXRrEd9ak1alQAJAheJXwCt5y9eYIATjGbCGC+31I42dPnRZjegCedBDNowy X-Received: by 10.80.182.138 with SMTP id d10mr25477506ede.131.1511286208640; Tue, 21 Nov 2017 09:43:28 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286208; cv=none; d=google.com; s=arc-20160816; b=m6cRK1FantPGh9aEA93DjQBLAehafPgSlVH1P7EQbzS8WfIJKaVqA9umjEoXbxfZt2 734UYtsn/fEVdv3JnJLeRoJ+R4jMDGyRK63s5k1fRK9AvcwGqSUxEnMbWFbK6JNAIhq/ 5PjVnM7sBIk71Exvc5GrAasFKZhJMa83K1vFN2yPRgpSWDgeo5HG78xG77CemNgFdaNZ 6XC6Yv6lNv48cQMKiPHZ+G/y0PDTJdH2O5W9Pp0ZxXzJtImaOXHvrz/SfPEuyZXb3WO/ GODEsp4hP7JC8gKoA/6qGA1w6/LfQH1lYJb/pirY5vK4uDMm9ldAcQVds+4IiKPL7pnO E/Eg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=OvBmz2GmovKfNNyMv/ktD5rtDhfq7sX5RC8BwE+M3lc=; b=iB4jvqwohO7XwPU16RAA9cEstlwJIfWEiMNIF0ZSrzYUyxp7NjlsH1f92bEHNf82d/ be9lTHBXdmwsqGKdkI5qSE/9c8PMjnQYV4eZQmq0nvuLbgu18VsFt6hwW8NASNlN5f05 oEig0jhc7gtXtUEWWFnwE/ZOCHBcCr7oAjAqUVv2eX8mEF10+2ndTfzfCoGD1WwJ7IWM VLBLTlpqcMn4myROr6WtbUs21zb0WX+JlgNbFmNs3Xpqn3ZhqhRAVMM8AwHl6UA8KZj2 6ce2UtfWzOgi82N90BzRccvfTWhXGii5TS8usidPtKUUoEZd/U8XHKxjHAWlwnax50qN bJiw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=riwyoNjZ; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id b17si4348739edj.328.2017.11.21.09.43.28; Tue, 21 Nov 2017 09:43:28 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=riwyoNjZ; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id 3283BC21EE6; Tue, 21 Nov 2017 17:42:46 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id B611EC21FAC; Tue, 21 Nov 2017 17:39:29 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 4CA47C21F88; Tue, 21 Nov 2017 17:39:08 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id 9C2E7C21F7C for ; Tue, 21 Nov 2017 17:39:06 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbuB001225; Wed, 22 Nov 2017 02:38:46 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbuB001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285926; bh=DpKGn6Wj5zs6PQKr8fg35WIIwCkjToj2FvuA864HU64=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=riwyoNjZ6FmErsx/VPVf7CuHnC+rWFJRiV5vRIXP4E40eSmk0GL3hHMt4/5ApdLug WYFJ03sddNXS3BfLaGlxqNhGHNSm5pgQUgFYA7SuonpULWA7qgPyujHPSOwp0YXN7x aw3kIXF933sqQ6vzoD4Mt52XiSsiWFRHBWw++KbGoSwzrpyWFdK3rroWOHvylw1+8H 5ZVvf9C612XC7bQLvGH4r3Z76DWryTIDA4DwHNQY9v+Myh0hItDO1lEizCmnHbX0PL 5OUlIx4Om3cCBBWo7Qw3qpDHtZML4QlRjd4gP5OuQ0hnZmHAp2aJbhk4Y+EA9Q3es4 MJthQC8y9Jm+g== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:31 +0900 Message-Id: <1511285912-12452-22-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 21/22] mtd: nand: introduce NAND_ROW_ADDR_3 flag X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Several drivers check ->chipsize to see if the third row address cycle is needed. Instead of embedding magic sizes such as 32MB, 128MB in drivers, introduce a new flag NAND_ROW_ADDR_3 for clean-up. Since nand_scan_ident() knows well about the device, it can handle this properly. The flag is set if the row address bit width is greater than 16. Delete comments such as "One more address cycle for ..." because intention is now clear enough from the code. Signed-off-by: Masahiro Yamada Acked-by: Wenyou Yang Signed-off-by: Boris Brezillon [Linux commit: 14157f861437ebe2d624b0a845b91bbdf8ca9a2d] --- drivers/mtd/nand/nand_base.c | 9 +++++---- include/linux/mtd/nand.h | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 77a3f16..aca3231 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -634,8 +634,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, chip->cmd_ctrl(mtd, page_addr, ctrl); ctrl &= ~NAND_CTRL_CHANGE; chip->cmd_ctrl(mtd, page_addr >> 8, ctrl); - /* One more address cycle for devices > 32MiB */ - if (chip->chipsize > (32 << 20)) + if (chip->options & NAND_ROW_ADDR_3) chip->cmd_ctrl(mtd, page_addr >> 16, ctrl); } chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); @@ -729,8 +728,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, chip->cmd_ctrl(mtd, page_addr, ctrl); chip->cmd_ctrl(mtd, page_addr >> 8, NAND_NCE | NAND_ALE); - /* One more address cycle for devices > 128MiB */ - if (chip->chipsize > (128 << 20)) + if (chip->options & NAND_ROW_ADDR_3) chip->cmd_ctrl(mtd, page_addr >> 16, NAND_NCE | NAND_ALE); } @@ -3889,6 +3887,9 @@ ident_done: chip->chip_shift += 32 - 1; } + if (chip->chip_shift - chip->page_shift > 16) + chip->options |= NAND_ROW_ADDR_3; + chip->badblockbits = 8; chip->erase = single_erase; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 150e3b8..d1db34c 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -204,6 +204,9 @@ typedef enum { */ #define NAND_NEED_SCRAMBLING 0x00002000 +/* Device needs 3rd row address cycle */ +#define NAND_ROW_ADDR_3 0x00004000 + /* Options valid for Samsung large page devices */ #define NAND_SAMSUNG_LP_OPTIONS NAND_CACHEPRG From patchwork Tue Nov 21 17:38:32 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 119380 Delivered-To: patch@linaro.org Received: by 10.140.22.164 with SMTP id 33csp5572859qgn; Tue, 21 Nov 2017 09:45:51 -0800 (PST) X-Google-Smtp-Source: AGs4zMbVsVoFe0lAdzIofYKvmvpLqoulUq8f5Gv4D1QkpijWw1Pe6b6vdx2lkCMOwni3DhCx7R90 X-Received: by 10.80.172.197 with SMTP id x63mr26104608edc.3.1511286351767; Tue, 21 Nov 2017 09:45:51 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511286351; cv=none; d=google.com; s=arc-20160816; b=JsBxmdPuQpjfBXhL3v8GjFleyhQodAMkdDki8plMr0Lj0DZwlklukPy3meeJaUb5o6 1Qi6FEscNFRieP93taMjQchhNvdGR4PLeRCJA8Lu7prjWAJtwxCkCWKybewXjDi4K31k M64+0FyaPsKRC5ZXS8h7HiQxK9ko+yomf7UaUn2WotJEdvfwEEqUCgUXdK/jNx1ed1hC WsLaStkzDYl8a2d3MlTWLn5NYvw+mVjAxl81rS2qtUn4bzbHV2F9gHxY1nXLaWcC4GrW Z5jiDZznQM3ol1x05jBxtyEeO3b86eiS/gZsGMh/JOjo74b1dvYQQSgr7CM9STYDiJxA 2LVw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:dkim-filter:arc-authentication-results; bh=bHJTHaLNfnzRMmlRiQGU8M7Mls8pGc80uXfb21y+wBI=; b=oIazSo2qozzrgg+ObN8HTn7sL3YM28KGuYupzQCr8xi6/bG/bIe6xktajwVjWvIl97 tEcmZ5d+z074alO6qntdM32dwmzPn/lKZD7B76K1niAqZDL/Qcp5aAAO6gPudq5tWQaH ffB1C6kUBtguqn9BhshHJaypZgCSV+s1Wc+DwzAA1D9H0D0QLDX/J4sPZHCKoS8dDHqh GBE1NEbnRo01HdtPuIbEzERul99Y+hUhYGhUEAsLxyrpB2oOPlFZ5NqoVZ906tz0EHwO RZKw8gDAqUazFmn3Gel6JIUT36DYBEg9t/mQK3jtMJ1nS4V5Gsr02PzyfkCrUw4GeWgv Yb6g== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=FwVxL6rb; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id n51si3714563edd.38.2017.11.21.09.45.51; Tue, 21 Nov 2017 09:45:51 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=FwVxL6rb; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id 4880FC21DF1; Tue, 21 Nov 2017 17:44:40 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 5241CC21FCD; Tue, 21 Nov 2017 17:39:35 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id DD5A2C21F9B; Tue, 21 Nov 2017 17:39:09 +0000 (UTC) Received: from conuserg-07.nifty.com (conuserg-07.nifty.com [210.131.2.74]) by lists.denx.de (Postfix) with ESMTPS id 8F5A1C21F71 for ; Tue, 21 Nov 2017 17:39:06 +0000 (UTC) Received: from grover.sesame (FL1-125-199-20-195.osk.mesh.ad.jp [125.199.20.195]) (authenticated) by conuserg-07.nifty.com with ESMTP id vALHcbuC001225; Wed, 22 Nov 2017 02:38:46 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com vALHcbuC001225 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1511285927; bh=3DruJ/9/NfXiuI9LuCry9t1LDnzyLr+vO9ewYK+meTA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FwVxL6rbdNgG/XydNsqPEw1Ei6qJa5Ttjc0ym0Ect2g+ZImTshnl6H7+MYj+ZW+6M yiGaW1bYAk6c0CLVuzdSqxsEa4XFu/ARr99qh7Z3EHAqBbmvsDLL+tZxebV5XoGmPV rzKzGeDakHIbKspDNCQA+u3/amfRM9Xj5GhM7zfYOlGKVA/HWMLNhJxg/NEttdYqh/ f9nxVLjE5RwpvHGetKufKlbIQUvaufaTd4FjBIAApUsN2tWtA6G69gAkoVk3AmFa0I e5ePXIIJ1xqEnYGT/dX4BGBo/32d3msQ2Hynr/L2GPDaJzlk3eJIu35rP83CPPgqCJ /Ox6fZEhc8ibw== X-Nifty-SrcIP: [125.199.20.195] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Wed, 22 Nov 2017 02:38:32 +0900 Message-Id: <1511285912-12452-23-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> References: <1511285912-12452-1-git-send-email-yamada.masahiro@socionext.com> Cc: Scott Wood Subject: [U-Boot] [PATCH 22/22] mtd: nand: denali: sync with Linux 4.15-rc1 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" I largely reworked the Denali NAND controller driver in Linux. This commit imports the improvements from Linux. The code is almost synced with Linux 4.15-rc1. Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/Kconfig | 11 - drivers/mtd/nand/denali.c | 2028 +++++++++++++++++++++-------------------- drivers/mtd/nand/denali.h | 473 ++++------ drivers/mtd/nand/denali_dt.c | 17 +- drivers/mtd/nand/denali_spl.c | 14 +- 5 files changed, 1248 insertions(+), 1295 deletions(-) diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index ca98193..cbdbd2f 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -23,17 +23,6 @@ config NAND_DENALI_DT Enable the driver for NAND flash on platforms using a Denali NAND controller as a DT device. -config SYS_NAND_DENALI_64BIT - bool "Use 64-bit variant of Denali NAND controller" - depends on NAND_DENALI - help - The Denali NAND controller IP has some variations in terms of - the bus interface. The DMA setup sequence is completely differenct - between 32bit / 64bit AXI bus variants. - - If your Denali NAND controller is the 64-bit variant, say Y. - Otherwise (32 bit), say N. - config NAND_DENALI_SPARE_AREA_SKIP_BYTES int "Number of bytes skipped in OOB area" depends on NAND_DENALI diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 54718f4..e61cafc 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -9,1144 +9,1076 @@ #include #include #include +#include +#include +#include #include #include #include "denali.h" -#define NAND_DEFAULT_TIMINGS -1 - -static int onfi_timing_mode = NAND_DEFAULT_TIMINGS; - -/* - * We define a macro here that combines all interrupts this driver uses into - * a single constant value, for convenience. - */ -#define DENALI_IRQ_ALL (INTR_STATUS__DMA_CMD_COMP | \ - INTR_STATUS__ECC_TRANSACTION_DONE | \ - INTR_STATUS__ECC_ERR | \ - INTR_STATUS__PROGRAM_FAIL | \ - INTR_STATUS__LOAD_COMP | \ - INTR_STATUS__PROGRAM_COMP | \ - INTR_STATUS__TIME_OUT | \ - INTR_STATUS__ERASE_FAIL | \ - INTR_STATUS__RST_COMP | \ - INTR_STATUS__ERASE_COMP | \ - INTR_STATUS__ECC_UNCOR_ERR | \ - INTR_STATUS__INT_ACT | \ - INTR_STATUS__LOCKED_BLK) +static dma_addr_t dma_map_single(void *dev, void *ptr, size_t size, + enum dma_data_direction dir) +{ + unsigned long addr = (unsigned long)ptr; -/* - * indicates whether or not the internal value for the flash bank is - * valid or not - */ -#define CHIP_SELECT_INVALID -1 + if (dir == DMA_FROM_DEVICE) + invalidate_dcache_range(addr, addr + size); + else + flush_dcache_range(addr, addr + size); -#define SUPPORT_8BITECC 1 + return addr; +} -/* - * this macro allows us to convert from an MTD structure to our own - * device context (denali) structure. - */ -static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd) +static void dma_unmap_single(void *dev, dma_addr_t addr, size_t size, + enum dma_data_direction dir) { - return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand); + if (dir != DMA_TO_DEVICE) + invalidate_dcache_range(addr, addr + size); } -/* - * 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 -#define PIPELINE_ACCESS 0x2000 - -#define DENALI_UNLOCK_START 0x10 -#define DENALI_UNLOCK_END 0x11 -#define DENALI_LOCK 0x21 -#define DENALI_LOCK_TIGHT 0x31 -#define DENALI_BUFFER_LOAD 0x60 -#define DENALI_BUFFER_WRITE 0x62 - -#define DENALI_READ 0 -#define DENALI_WRITE 0x100 - -/* types of device accesses. We can issue commands and get status */ -#define COMMAND_CYCLE 0 -#define ADDR_CYCLE 1 -#define STATUS_CYCLE 2 - -/* - * this is a helper macro that allows us to - * format the bank into the proper bits for the controller - */ -#define BANK(x) ((x) << 24) - -/* Interrupts are cleared by writing a 1 to the appropriate status bit */ -static inline void clear_interrupt(struct denali_nand_info *denali, - uint32_t irq_mask) +static int dma_mapping_error(void *dev, dma_addr_t addr) { - uint32_t intr_status_reg; - - intr_status_reg = INTR_STATUS(denali->flash_bank); - - writel(irq_mask, denali->flash_reg + intr_status_reg); + return 0; } -static uint32_t read_interrupt_status(struct denali_nand_info *denali) -{ - uint32_t intr_status_reg; +#define DENALI_NAND_NAME "denali-nand" - intr_status_reg = INTR_STATUS(denali->flash_bank); +/* for Indexed Addressing */ +#define DENALI_INDEXED_CTRL 0x00 +#define DENALI_INDEXED_DATA 0x10 - return readl(denali->flash_reg + intr_status_reg); -} +#define DENALI_MAP00 (0 << 26) /* direct access to buffer */ +#define DENALI_MAP01 (1 << 26) /* read/write pages in PIO */ +#define DENALI_MAP10 (2 << 26) /* high-level control plane */ +#define DENALI_MAP11 (3 << 26) /* direct controller access */ -static void clear_interrupts(struct denali_nand_info *denali) -{ - uint32_t status; +/* 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 */ - status = read_interrupt_status(denali); - clear_interrupt(denali, status); +/* MAP10 commands */ +#define DENALI_ERASE 0x01 - denali->irq_status = 0; -} +#define DENALI_BANK(denali) ((denali)->active_bank << 24) -static void denali_irq_enable(struct denali_nand_info *denali, - uint32_t int_mask) -{ - int i; +#define DENALI_INVALID_BANK -1 +#define DENALI_NR_BANKS 4 - for (i = 0; i < denali->max_banks; ++i) - writel(int_mask, denali->flash_reg + INTR_EN(i)); -} +/* + * The bus interface clock, clk_x, is phase aligned with the core clock. The + * clk_x is an integral multiple N of the core clk. The value N is configured + * at IP delivery time, and its available value is 4, 5, or 6. We need to align + * to the largest value to make it work with any possible configuration. + */ +#define DENALI_CLK_X_MULT 6 -static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) +static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd) { - unsigned long timeout = 1000000; - uint32_t intr_status; - - do { - intr_status = read_interrupt_status(denali) & DENALI_IRQ_ALL; - if (intr_status & irq_mask) { - denali->irq_status &= ~irq_mask; - /* our interrupt was detected */ - break; - } - udelay(1); - timeout--; - } while (timeout != 0); - - if (timeout == 0) { - /* timeout */ - printf("Denali timeout with interrupt status %08x\n", - read_interrupt_status(denali)); - intr_status = 0; - } - return intr_status; + return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand); } /* - * 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. + * Direct Addressing - the slave address forms the control information (command + * type, bank, block, and page address). The slave data is the actual data to + * be transferred. This mode requires 28 bits of address region allocated. */ -static void index_addr(struct denali_nand_info *denali, - uint32_t address, uint32_t data) +static u32 denali_direct_read(struct denali_nand_info *denali, u32 addr) { - writel(address, denali->flash_mem + INDEX_CTRL_REG); - writel(data, denali->flash_mem + INDEX_DATA_REG); + return ioread32(denali->host + addr); } -/* Perform an indexed read of the device */ -static void index_addr_read_data(struct denali_nand_info *denali, - uint32_t address, uint32_t *pdata) +static void denali_direct_write(struct denali_nand_info *denali, u32 addr, + u32 data) { - writel(address, denali->flash_mem + INDEX_CTRL_REG); - *pdata = readl(denali->flash_mem + INDEX_DATA_REG); + iowrite32(data, denali->host + addr); } /* - * We need to buffer some data for some of the NAND core routines. - * The operations manage buffering that data. + * Indexed Addressing - address translation module intervenes in passing the + * control information. This mode reduces the required address range. The + * control information and transferred data are latched by the registers in + * the translation module. */ -static void reset_buf(struct denali_nand_info *denali) +static u32 denali_indexed_read(struct denali_nand_info *denali, u32 addr) { - denali->buf.head = 0; - denali->buf.tail = 0; + iowrite32(addr, denali->host + DENALI_INDEXED_CTRL); + return ioread32(denali->host + DENALI_INDEXED_DATA); } -static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte) +static void denali_indexed_write(struct denali_nand_info *denali, u32 addr, + u32 data) { - denali->buf.buf[denali->buf.tail++] = byte; + iowrite32(addr, denali->host + DENALI_INDEXED_CTRL); + iowrite32(data, denali->host + DENALI_INDEXED_DATA); } -/* resets a specific device connected to the core */ -static void reset_bank(struct denali_nand_info *denali) +/* + * Use the configuration feature register to determine the maximum number of + * banks that the hardware supports. + */ +static void denali_detect_max_banks(struct denali_nand_info *denali) { - uint32_t irq_status; - uint32_t irq_mask = INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT; - - clear_interrupts(denali); + uint32_t features = ioread32(denali->reg + FEATURES); - writel(1 << denali->flash_bank, denali->flash_reg + DEVICE_RESET); + denali->max_banks = 1 << FIELD_GET(FEATURES__N_BANKS, features); - irq_status = wait_for_irq(denali, irq_mask); - if (irq_status & INTR_STATUS__TIME_OUT) - debug("reset bank failed.\n"); + /* the encoding changed from rev 5.0 to 5.1 */ + if (denali->revision < 0x0501) + denali->max_banks <<= 1; } -/* Reset the flash controller */ -static uint32_t denali_nand_reset(struct denali_nand_info *denali) +static void __maybe_unused denali_enable_irq(struct denali_nand_info *denali) { int i; - for (i = 0; i < denali->max_banks; i++) - writel(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT, - denali->flash_reg + INTR_STATUS(i)); + for (i = 0; i < DENALI_NR_BANKS; i++) + iowrite32(U32_MAX, denali->reg + INTR_EN(i)); + iowrite32(GLOBAL_INT_EN_FLAG, denali->reg + GLOBAL_INT_ENABLE); +} - for (i = 0; i < denali->max_banks; i++) { - writel(1 << i, denali->flash_reg + DEVICE_RESET); - while (!(readl(denali->flash_reg + INTR_STATUS(i)) & - (INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT))) - if (readl(denali->flash_reg + INTR_STATUS(i)) & - INTR_STATUS__TIME_OUT) - debug("NAND Reset operation timed out on bank" - " %d\n", i); - } +static void __maybe_unused denali_disable_irq(struct denali_nand_info *denali) +{ + int i; - for (i = 0; i < denali->max_banks; i++) - writel(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT, - denali->flash_reg + INTR_STATUS(i)); + for (i = 0; i < DENALI_NR_BANKS; i++) + iowrite32(0, denali->reg + INTR_EN(i)); + iowrite32(0, denali->reg + GLOBAL_INT_ENABLE); +} - return 0; +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->reg + INTR_STATUS(bank)); } -/* - * 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) +static void denali_clear_irq_all(struct denali_nand_info *denali) { - uint32_t trea[6] = {40, 30, 25, 20, 20, 16}; - uint32_t trp[6] = {50, 25, 17, 15, 12, 10}; - uint32_t treh[6] = {30, 15, 15, 10, 10, 7}; - uint32_t trc[6] = {100, 50, 35, 30, 25, 20}; - uint32_t trhoh[6] = {0, 15, 15, 15, 15, 15}; - uint32_t trloh[6] = {0, 0, 0, 0, 5, 5}; - uint32_t tcea[6] = {100, 45, 30, 25, 25, 25}; - uint32_t tadl[6] = {200, 100, 100, 100, 70, 70}; - uint32_t trhw[6] = {200, 100, 100, 100, 100, 100}; - uint32_t trhz[6] = {200, 100, 100, 100, 100, 100}; - uint32_t twhr[6] = {120, 80, 80, 60, 60, 60}; - uint32_t tcs[6] = {70, 35, 25, 25, 20, 15}; - - uint32_t data_invalid_rhoh, data_invalid_rloh, data_invalid; - uint32_t dv_window = 0; - uint32_t en_lo, en_hi; - uint32_t acc_clks; - uint32_t addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt; - - en_lo = DIV_ROUND_UP(trp[mode], CLK_X); - en_hi = DIV_ROUND_UP(treh[mode], CLK_X); - if ((en_hi * CLK_X) < (treh[mode] + 2)) - en_hi++; - - if ((en_lo + en_hi) * CLK_X < trc[mode]) - en_lo += DIV_ROUND_UP((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++; - } + int i; - acc_clks = DIV_ROUND_UP(trea[mode], CLK_X); + for (i = 0; i < DENALI_NR_BANKS; i++) + denali_clear_irq(denali, i, U32_MAX); +} - while (acc_clks * CLK_X - trea[mode] < 3) - acc_clks++; +static void __denali_check_irq(struct denali_nand_info *denali) +{ + uint32_t irq_status; + int i; - if (data_invalid - acc_clks * CLK_X < 2) - debug("%s, Line %d: Warning!\n", __FILE__, __LINE__); + for (i = 0; i < DENALI_NR_BANKS; i++) { + irq_status = ioread32(denali->reg + INTR_STATUS(i)); + denali_clear_irq(denali, i, irq_status); - addr_2_data = DIV_ROUND_UP(tadl[mode], CLK_X); - re_2_we = DIV_ROUND_UP(trhw[mode], CLK_X); - re_2_re = DIV_ROUND_UP(trhz[mode], CLK_X); - we_2_re = DIV_ROUND_UP(twhr[mode], CLK_X); - cs_cnt = DIV_ROUND_UP((tcs[mode] - trp[mode]), CLK_X); - if (cs_cnt == 0) - cs_cnt = 1; + if (i != denali->active_bank) + continue; - if (tcea[mode]) { - while (cs_cnt * CLK_X + trea[mode] < tcea[mode]) - cs_cnt++; + denali->irq_status |= irq_status; } +} - /* Sighting 3462430: Temporary hack for MT29F128G08CJABAWP:B */ - if (readl(denali->flash_reg + MANUFACTURER_ID) == 0 && - readl(denali->flash_reg + DEVICE_ID) == 0x88) - acc_clks = 6; - - writel(acc_clks, denali->flash_reg + ACC_CLKS); - writel(re_2_we, denali->flash_reg + RE_2_WE); - writel(re_2_re, denali->flash_reg + RE_2_RE); - writel(we_2_re, denali->flash_reg + WE_2_RE); - writel(addr_2_data, denali->flash_reg + ADDR_2_DATA); - writel(en_lo, denali->flash_reg + RDWR_EN_LO_CNT); - writel(en_hi, denali->flash_reg + RDWR_EN_HI_CNT); - writel(cs_cnt, denali->flash_reg + CS_SETUP_CNT); +static void denali_reset_irq(struct denali_nand_info *denali) +{ + denali->irq_status = 0; + denali->irq_mask = 0; } -/* queries the NAND device to see what ONFI modes it supports. */ -static uint32_t get_onfi_nand_para(struct denali_nand_info *denali) +static uint32_t denali_wait_for_irq(struct denali_nand_info *denali, + uint32_t irq_mask) { - int i; + unsigned long time_left = 1000000; - /* - * we needn't to do a reset here because driver has already - * reset all the banks before - */ - if (!(readl(denali->flash_reg + ONFI_TIMING_MODE) & - ONFI_TIMING_MODE__VALUE)) - return -EIO; + while (time_left) { + __denali_check_irq(denali); - for (i = 5; i > 0; i--) { - if (readl(denali->flash_reg + ONFI_TIMING_MODE) & - (0x01 << i)) - break; + if (irq_mask & denali->irq_status) + return denali->irq_status; + udelay(1); + time_left--; } - 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 - */ + if (!time_left) { + dev_err(denali->dev, "timeout while waiting for irq 0x%x\n", + irq_mask); + return 0; + } - return 0; + return denali->irq_status; } -static void get_samsung_nand_para(struct denali_nand_info *denali, - uint8_t device_id) +static uint32_t denali_check_irq(struct denali_nand_info *denali) { - if (device_id == 0xd3) { /* Samsung K9WAG08U1A */ - /* Set timing register values according to datasheet */ - writel(5, denali->flash_reg + ACC_CLKS); - writel(20, denali->flash_reg + RE_2_WE); - writel(12, denali->flash_reg + WE_2_RE); - writel(14, denali->flash_reg + ADDR_2_DATA); - writel(3, denali->flash_reg + RDWR_EN_LO_CNT); - writel(2, denali->flash_reg + RDWR_EN_HI_CNT); - writel(2, denali->flash_reg + CS_SETUP_CNT); - } + __denali_check_irq(denali); + + return denali->irq_status; } -static void get_toshiba_nand_para(struct denali_nand_info *denali) +static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { - uint32_t tmp; + struct denali_nand_info *denali = mtd_to_denali(mtd); + u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); + int i; - /* - * Workaround to fix a controller bug which reports a wrong - * spare area size for some kind of Toshiba NAND device - */ - if ((readl(denali->flash_reg + DEVICE_MAIN_AREA_SIZE) == 4096) && - (readl(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64)) { - writel(216, denali->flash_reg + DEVICE_SPARE_AREA_SIZE); - tmp = readl(denali->flash_reg + DEVICES_CONNECTED) * - readl(denali->flash_reg + DEVICE_SPARE_AREA_SIZE); - writel(tmp, denali->flash_reg + LOGICAL_PAGE_SPARE_SIZE); - } + for (i = 0; i < len; i++) + buf[i] = denali->host_read(denali, addr); } -static void get_hynix_nand_para(struct denali_nand_info *denali, - uint8_t device_id) +static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { - uint32_t main_size, spare_size; - - switch (device_id) { - case 0xD5: /* Hynix H27UAG8T2A, H27UBG8U5A or H27UCG8VFA */ - case 0xD7: /* Hynix H27UDG8VEM, H27UCG8UDM or H27UCG8V5A */ - writel(128, denali->flash_reg + PAGES_PER_BLOCK); - writel(4096, denali->flash_reg + DEVICE_MAIN_AREA_SIZE); - writel(224, denali->flash_reg + DEVICE_SPARE_AREA_SIZE); - main_size = 4096 * - readl(denali->flash_reg + DEVICES_CONNECTED); - spare_size = 224 * - readl(denali->flash_reg + DEVICES_CONNECTED); - writel(main_size, denali->flash_reg + LOGICAL_PAGE_DATA_SIZE); - writel(spare_size, denali->flash_reg + LOGICAL_PAGE_SPARE_SIZE); - writel(0, denali->flash_reg + DEVICE_WIDTH); - break; - default: - debug("Spectra: Unknown Hynix NAND (Device ID: 0x%x).\n" - "Will use default parameter values instead.\n", - device_id); - } + struct denali_nand_info *denali = mtd_to_denali(mtd); + u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); + int i; + + for (i = 0; i < len; i++) + denali->host_write(denali, addr, buf[i]); } -/* - * 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) +static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) { - uint32_t id[denali->max_banks]; + struct denali_nand_info *denali = mtd_to_denali(mtd); + u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); + uint16_t *buf16 = (uint16_t *)buf; 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]); + for (i = 0; i < len / 2; i++) + buf16[i] = denali->host_read(denali, addr); +} - if (i == 0) { - if (!(id[i] & 0x0ff)) - break; - } else { - if ((id[i] & 0x0ff) == (id[0] & 0x0ff)) - denali->total_used_banks++; - else - break; - } - } +static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf, + int len) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); + const uint16_t *buf16 = (const uint16_t *)buf; + int i; + + for (i = 0; i < len / 2; i++) + denali->host_write(denali, addr, buf16[i]); } -/* - * Use the configuration feature register to determine the maximum number of - * banks that the hardware supports. - */ -static void detect_max_banks(struct denali_nand_info *denali) +static uint8_t denali_read_byte(struct mtd_info *mtd) { - uint32_t features = ioread32(denali->flash_reg + FEATURES); + uint8_t byte; - denali->max_banks = 1 << (features & FEATURES__N_BANKS); + denali_read_buf(mtd, &byte, 1); - /* the encoding changed from rev 5.0 to 5.1 */ - if (denali->revision < 0x0501) - denali->max_banks <<= 1; + return byte; } -static void detect_partition_feature(struct denali_nand_info *denali) +static void denali_write_byte(struct mtd_info *mtd, uint8_t byte) { - /* - * For MRST platform, denali->fwblks represent the - * number of blocks firmware is taken, - * FW is in protect partition and MTD driver has no - * permission to access it. So let driver know how many - * blocks it can't touch. - */ - if (readl(denali->flash_reg + FEATURES) & FEATURES__PARTITION) { - if ((readl(denali->flash_reg + PERM_SRC_ID(1)) & - PERM_SRC_ID__SRCID) == SPECTRA_PARTITION_ID) { - denali->fwblks = - ((readl(denali->flash_reg + MIN_MAX_BANK(1)) & - MIN_MAX_BANK__MIN_VALUE) * - denali->blksperchip) - + - (readl(denali->flash_reg + MIN_BLK_ADDR(1)) & - MIN_BLK_ADDR__VALUE); - } else { - denali->fwblks = SPECTRA_START_BLOCK; - } - } else { - denali->fwblks = SPECTRA_START_BLOCK; - } + denali_write_buf(mtd, &byte, 1); } -static uint32_t denali_nand_timing_set(struct denali_nand_info *denali) +static uint16_t denali_read_word(struct mtd_info *mtd) { - uint32_t id_bytes[8], addr; - uint8_t maf_id, device_id; - int i; + uint16_t word; - /* - * 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 (readl(denali->flash_reg + ONFI_DEVICE_NO_OF_LUNS) & - ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE) { /* ONFI 1.0 NAND */ - if (get_onfi_nand_para(denali)) - return -EIO; - } else if (maf_id == 0xEC) { /* Samsung NAND */ - get_samsung_nand_para(denali, device_id); - } else if (maf_id == 0x98) { /* Toshiba NAND */ - get_toshiba_nand_para(denali); - } else if (maf_id == 0xAD) { /* Hynix NAND */ - get_hynix_nand_para(denali, device_id); - } + denali_read_buf16(mtd, (uint8_t *)&word, 2); - find_valid_banks(denali); + return word; +} - detect_partition_feature(denali); +static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + uint32_t type; + + if (ctrl & NAND_CLE) + type = DENALI_MAP11_CMD; + else if (ctrl & NAND_ALE) + type = DENALI_MAP11_ADDR; + else + return; /* - * If the user specified to override the default timings - * with a specific ONFI mode, we apply those changes here. + * 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 (onfi_timing_mode != NAND_DEFAULT_TIMINGS) - nand_onfi_timing_set(denali, onfi_timing_mode); + if (ctrl & NAND_CTRL_CHANGE) + denali_reset_irq(denali); - return 0; + denali->host_write(denali, DENALI_BANK(denali) | type, dat); } -/* - * validation function to verify that the controlling software is making - * a valid request - */ -static inline bool is_flash_bank_valid(int flash_bank) -{ - return flash_bank >= 0 && flash_bank < 4; -} - -static void denali_irq_init(struct denali_nand_info *denali) +static int denali_dev_ready(struct mtd_info *mtd) { - uint32_t int_mask; - int i; - - /* Disable global interrupts */ - writel(0, denali->flash_reg + GLOBAL_INT_ENABLE); - - int_mask = DENALI_IRQ_ALL; - - /* Clear all status bits */ - for (i = 0; i < denali->max_banks; ++i) - writel(0xFFFF, denali->flash_reg + INTR_STATUS(i)); + struct denali_nand_info *denali = mtd_to_denali(mtd); - denali_irq_enable(denali, int_mask); + return !!(denali_check_irq(denali) & INTR__INT_ACT); } -/* - * This helper function setups the registers for ECC and whether or not - * the spare area will be transferred. - */ -static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, - bool transfer_spare) +static int denali_check_erased_page(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, + unsigned long uncor_ecc_flags, + unsigned int max_bitflips) { - int ecc_en_flag, transfer_spare_flag; + uint8_t *ecc_code = chip->buffers->ecccode; + int ecc_steps = chip->ecc.steps; + int ecc_size = chip->ecc.size; + int ecc_bytes = chip->ecc.bytes; + int i, ret, stat; + + ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, + chip->ecc.total); + if (ret) + return ret; + + for (i = 0; i < ecc_steps; i++) { + if (!(uncor_ecc_flags & BIT(i))) + continue; + + stat = nand_check_erased_ecc_chunk(buf, ecc_size, + ecc_code, ecc_bytes, + NULL, 0, + chip->ecc.strength); + if (stat < 0) { + mtd->ecc_stats.failed++; + } else { + mtd->ecc_stats.corrected += stat; + max_bitflips = max_t(unsigned int, max_bitflips, stat); + } - /* set ECC, transfer spare bits if needed */ - ecc_en_flag = ecc_en ? ECC_ENABLE__FLAG : 0; - transfer_spare_flag = transfer_spare ? TRANSFER_SPARE_REG__FLAG : 0; + buf += ecc_size; + ecc_code += ecc_bytes; + } - /* Enable spare area/ECC per user's request. */ - writel(ecc_en_flag, denali->flash_reg + ECC_ENABLE); - /* applicable for MAP01 only */ - writel(transfer_spare_flag, denali->flash_reg + TRANSFER_SPARE_REG); + return max_bitflips; } -/* - * 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, - bool ecc_en, bool transfer_spare, - int access_type, int op) +static int denali_hw_ecc_fixup(struct mtd_info *mtd, + struct denali_nand_info *denali, + unsigned long *uncor_ecc_flags) { - uint32_t addr, cmd, irq_status; - static uint32_t page_count = 1; - - setup_ecc_for_xfer(denali, ecc_en, transfer_spare); + struct nand_chip *chip = mtd_to_nand(mtd); + int bank = denali->active_bank; + uint32_t ecc_cor; + unsigned int max_bitflips; - clear_interrupts(denali); + ecc_cor = ioread32(denali->reg + ECC_COR_INFO(bank)); + ecc_cor >>= ECC_COR_INFO__SHIFT(bank); - addr = BANK(denali->flash_bank) | denali->page; + if (ecc_cor & ECC_COR_INFO__UNCOR_ERR) { + /* + * This flag is set when uncorrectable error occurs at least in + * one ECC sector. We can not know "how many sectors", or + * "which sector(s)". We need erase-page check for all sectors. + */ + *uncor_ecc_flags = GENMASK(chip->ecc.steps - 1, 0); + return 0; + } - /* setup the acccess type */ - cmd = MODE_10 | addr; - index_addr(denali, cmd, access_type); + max_bitflips = FIELD_GET(ECC_COR_INFO__MAX_ERRORS, ecc_cor); - /* setup the pipeline command */ - index_addr(denali, cmd, 0x2000 | op | page_count); + /* + * The register holds the maximum of per-sector corrected bitflips. + * This is suitable for the return value of the ->read_page() callback. + * Unfortunately, we can not know the total number of corrected bits in + * the page. Increase the stats by max_bitflips. (compromised solution) + */ + mtd->ecc_stats.corrected += max_bitflips; - cmd = MODE_01 | addr; - writel(cmd, denali->flash_mem + INDEX_CTRL_REG); + return max_bitflips; +} - if (op == DENALI_READ) { - /* wait for command to be accepted */ - irq_status = wait_for_irq(denali, INTR_STATUS__LOAD_COMP); +static int denali_sw_ecc_fixup(struct mtd_info *mtd, + struct denali_nand_info *denali, + unsigned long *uncor_ecc_flags, uint8_t *buf) +{ + unsigned int ecc_size = denali->nand.ecc.size; + unsigned int bitflips = 0; + unsigned int max_bitflips = 0; + uint32_t err_addr, err_cor_info; + unsigned int err_byte, err_sector, err_device; + uint8_t err_cor_value; + unsigned int prev_sector = 0; + uint32_t irq_status; - if (irq_status == 0) - return -EIO; - } + denali_reset_irq(denali); - return 0; -} + do { + err_addr = ioread32(denali->reg + ECC_ERROR_ADDRESS); + err_sector = FIELD_GET(ECC_ERROR_ADDRESS__SECTOR, err_addr); + err_byte = FIELD_GET(ECC_ERROR_ADDRESS__OFFSET, err_addr); + + err_cor_info = ioread32(denali->reg + ERR_CORRECTION_INFO); + err_cor_value = FIELD_GET(ERR_CORRECTION_INFO__BYTE, + err_cor_info); + err_device = FIELD_GET(ERR_CORRECTION_INFO__DEVICE, + err_cor_info); + + /* reset the bitflip counter when crossing ECC sector */ + if (err_sector != prev_sector) + bitflips = 0; + + if (err_cor_info & ERR_CORRECTION_INFO__UNCOR) { + /* + * Check later if this is a real ECC error, or + * an erased sector. + */ + *uncor_ecc_flags |= BIT(err_sector); + } else if (err_byte < ecc_size) { + /* + * If err_byte is larger than ecc_size, means error + * happened in OOB, so we ignore it. It's no need for + * us to correct it err_device is represented the NAND + * error bits are happened in if there are more than + * one NAND connected. + */ + int offset; + unsigned int flips_in_byte; + + offset = (err_sector * ecc_size + err_byte) * + denali->devs_per_cs + err_device; + + /* correct the ECC error */ + flips_in_byte = hweight8(buf[offset] ^ err_cor_value); + buf[offset] ^= err_cor_value; + mtd->ecc_stats.corrected += flips_in_byte; + bitflips += flips_in_byte; + + max_bitflips = max(max_bitflips, bitflips); + } -/* 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) -{ - uint32_t *buf32; - int i; + prev_sector = err_sector; + } while (!(err_cor_info & ERR_CORRECTION_INFO__LAST_ERR)); /* - * verify that the len is a multiple of 4. - * see comment in read_data_from_flash_mem() + * Once handle all ECC errors, controller will trigger an + * ECC_TRANSACTION_DONE interrupt. */ - BUG_ON((len % 4) != 0); + irq_status = denali_wait_for_irq(denali, INTR__ECC_TRANSACTION_DONE); + if (!(irq_status & INTR__ECC_TRANSACTION_DONE)) + return -EIO; - /* write the data to the flash memory */ - buf32 = (uint32_t *)buf; - for (i = 0; i < len / 4; i++) - writel(*buf32++, denali->flash_mem + INDEX_DATA_REG); - return i * 4; /* intent is to return the number of bytes read */ + return max_bitflips; } -/* 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_setup_dma64(struct denali_nand_info *denali, + dma_addr_t dma_addr, int page, int write) { - uint32_t *buf32; - int i; + uint32_t mode; + const int page_count = 1; - /* - * 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); + mode = DENALI_MAP10 | DENALI_BANK(denali) | page; - /* transfer the data from the flash */ - buf32 = (uint32_t *)buf; - for (i = 0; i < len / 4; i++) - *buf32++ = readl(denali->flash_mem + INDEX_DATA_REG); + /* DMA is a three step process */ - return i * 4; /* intent is to return the number of bytes read */ -} + /* + * 1. setup transfer type, interrupt when complete, + * burst len = 64 bytes, the number of pages + */ + denali->host_write(denali, mode, + 0x01002000 | (64 << 16) | (write << 8) | page_count); -static void denali_mode_main_access(struct denali_nand_info *denali) -{ - uint32_t addr, cmd; + /* 2. set memory low address */ + denali->host_write(denali, mode, lower_32_bits(dma_addr)); - addr = BANK(denali->flash_bank) | denali->page; - cmd = MODE_10 | addr; - index_addr(denali, cmd, MAIN_ACCESS); + /* 3. set memory high address */ + denali->host_write(denali, mode, upper_32_bits(dma_addr)); } -static void denali_mode_main_spare_access(struct denali_nand_info *denali) +static void denali_setup_dma32(struct denali_nand_info *denali, + dma_addr_t dma_addr, int page, int write) { - uint32_t addr, cmd; + uint32_t mode; + const int page_count = 1; - addr = BANK(denali->flash_bank) | denali->page; - cmd = MODE_10 | addr; - index_addr(denali, cmd, MAIN_SPARE_ACCESS); -} + mode = DENALI_MAP10 | DENALI_BANK(denali); -/* writes OOB data to the device */ -static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t irq_status; - uint32_t irq_mask = INTR_STATUS__PROGRAM_COMP | - INTR_STATUS__PROGRAM_FAIL; - int status = 0; + /* DMA is a four step process */ - denali->page = page; + /* 1. setup transfer type and # of pages */ + denali->host_write(denali, mode | page, + 0x2000 | (write << 8) | page_count); - if (denali_send_pipeline_cmd(denali, false, true, SPARE_ACCESS, - DENALI_WRITE) == 0) { - write_data_to_flash_mem(denali, buf, mtd->oobsize); + /* 2. set memory high address bits 23:8 */ + denali->host_write(denali, mode | ((dma_addr >> 16) << 8), 0x2200); - /* wait for operation to complete */ - irq_status = wait_for_irq(denali, irq_mask); + /* 3. set memory low address bits 23:8 */ + denali->host_write(denali, mode | ((dma_addr & 0xffff) << 8), 0x2300); - if (irq_status == 0) { - dev_err(denali->dev, "OOB write failed\n"); - status = -EIO; - } - } else { - printf("unable to send pipeline command\n"); - status = -EIO; - } - return status; + /* 4. interrupt when complete, burst len = 64 bytes */ + denali->host_write(denali, mode | 0x14000, 0x2400); } -/* reads OOB data from the device */ -static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) +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); - uint32_t irq_mask = INTR_STATUS__LOAD_COMP; - uint32_t irq_status, addr, cmd; + u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page; + uint32_t *buf32 = (uint32_t *)buf; + uint32_t irq_status, ecc_err_mask; + int i; - denali->page = page; + if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) + ecc_err_mask = INTR__ECC_UNCOR_ERR; + else + ecc_err_mask = INTR__ECC_ERR; - if (denali_send_pipeline_cmd(denali, false, true, SPARE_ACCESS, - DENALI_READ) == 0) { - read_data_from_flash_mem(denali, buf, mtd->oobsize); + denali_reset_irq(denali); - /* - * wait for command to be accepted - * can always use status0 bit as the - * mask is identical for each bank. - */ - irq_status = wait_for_irq(denali, irq_mask); + for (i = 0; i < size / 4; i++) + *buf32++ = denali->host_read(denali, addr); - if (irq_status == 0) - printf("page on OOB timeout %d\n", denali->page); + irq_status = denali_wait_for_irq(denali, INTR__PAGE_XFER_INC); + if (!(irq_status & INTR__PAGE_XFER_INC)) + return -EIO; - /* - * 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) | denali->page; - cmd = MODE_10 | addr; - index_addr(denali, cmd, MAIN_ACCESS); - } + if (irq_status & INTR__ERASED_PAGE) + memset(buf, 0xff, size); + + return irq_status & ecc_err_mask ? -EBADMSG : 0; } -/* - * this function examines buffers to see if they contain data that - * indicate that the buffer is part of an erased region of flash. - */ -static bool is_erased(uint8_t *buf, int len) +static int denali_pio_write(struct denali_nand_info *denali, + const void *buf, size_t size, int page, int raw) { + u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page; + const uint32_t *buf32 = (uint32_t *)buf; + uint32_t irq_status; int i; - for (i = 0; i < len; i++) - if (buf[i] != 0xFF) - return false; - return true; + denali_reset_irq(denali); + + for (i = 0; i < size / 4; i++) + denali->host_write(denali, addr, *buf32++); + + irq_status = denali_wait_for_irq(denali, + INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL); + if (!(irq_status & INTR__PROGRAM_COMP)) + return -EIO; + + return 0; } -/* programs the controller to either enable/disable DMA transfers */ -static void denali_enable_dma(struct denali_nand_info *denali, bool en) +static int denali_pio_xfer(struct denali_nand_info *denali, void *buf, + size_t size, int page, int raw, int write) { - writel(en ? DMA_ENABLE__FLAG : 0, denali->flash_reg + DMA_ENABLE); - readl(denali->flash_reg + DMA_ENABLE); + if (write) + return denali_pio_write(denali, buf, size, page, raw); + else + return denali_pio_read(denali, buf, size, page, raw); } -/* setups the HW to perform the data DMA */ -static void denali_setup_dma(struct denali_nand_info *denali, int op) +static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, + size_t size, int page, int raw, int write) { - uint32_t mode; - const int page_count = 1; - uint64_t addr = (unsigned long)denali->buf.dma_buf; - - flush_dcache_range(addr, addr + sizeof(denali->buf.dma_buf)); - -/* For Denali controller that is 64 bit bus IP core */ -#ifdef CONFIG_SYS_NAND_DENALI_64BIT - mode = MODE_10 | BANK(denali->flash_bank) | denali->page; - - /* DMA is a three step process */ + 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_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); + } - /* 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); + 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; + } - /* 2. set memory low address bits 31:0 */ - index_addr(denali, mode, addr); + iowrite32(DMA_ENABLE__FLAG, denali->reg + DMA_ENABLE); - /* 3. set memory high address bits 64:32 */ - index_addr(denali, mode, addr >> 32); -#else - mode = MODE_10 | BANK(denali->flash_bank); + denali_reset_irq(denali); + denali->setup_dma(denali, dma_addr, page, write); - /* DMA is a four step process */ + irq_status = denali_wait_for_irq(denali, irq_mask); + if (!(irq_status & INTR__DMA_CMD_COMP)) + ret = -EIO; + else if (irq_status & ecc_err_mask) + ret = -EBADMSG; - /* 1. setup transfer type and # of pages */ - index_addr(denali, mode | denali->page, 0x2000 | op | page_count); + iowrite32(0, denali->reg + DMA_ENABLE); - /* 2. set memory high address bits 23:8 */ - index_addr(denali, mode | (((addr >> 16) & 0xffff) << 8), 0x2200); + dma_unmap_single(denali->dev, dma_addr, size, dir); - /* 3. set memory low address bits 23:8 */ - index_addr(denali, mode | ((addr & 0xffff) << 8), 0x2300); + if (irq_status & INTR__ERASED_PAGE) + memset(buf, 0xff, size); - /* 4. interrupt when complete, burst len = 64 bytes */ - index_addr(denali, mode | 0x14000, 0x2400); -#endif + return ret; } -/* Common DMA function */ -static uint32_t denali_dma_configuration(struct denali_nand_info *denali, - uint32_t ops, bool raw_xfer, - uint32_t irq_mask, int oob_required) +static int denali_data_xfer(struct denali_nand_info *denali, void *buf, + size_t size, int page, int raw, int write) { - uint32_t irq_status = 0; - /* setup_ecc_for_xfer(bool ecc_en, bool transfer_spare) */ - setup_ecc_for_xfer(denali, !raw_xfer, oob_required); - - /* clear any previous interrupt flags */ - clear_interrupts(denali); - - /* enable the DMA */ - denali_enable_dma(denali, true); - - /* setup the DMA */ - denali_setup_dma(denali, ops); - - /* wait for operation to complete */ - irq_status = wait_for_irq(denali, irq_mask); + iowrite32(raw ? 0 : ECC_ENABLE__FLAG, denali->reg + ECC_ENABLE); + iowrite32(raw ? TRANSFER_SPARE_REG__FLAG : 0, + denali->reg + TRANSFER_SPARE_REG); - /* if ECC fault happen, seems we need delay before turning off DMA. - * If not, the controller will go into non responsive condition */ - if (irq_status & INTR_STATUS__ECC_UNCOR_ERR) - udelay(100); - - /* disable the DMA */ - denali_enable_dma(denali, false); - - return irq_status; + 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); } -static int write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, bool raw_xfer, int oob_required) +static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip, + int page, int write) { 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->oob_skip_bytes; + 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; + } + } - uint32_t irq_status = 0; - uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP; - - denali->status = 0; - - /* copy buffer into DMA buffer */ - memcpy(denali->buf.dma_buf, buf, mtd->writesize); + /* 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); +} - /* need extra memcpy for raw transfer */ - if (raw_xfer) - memcpy(denali->buf.dma_buf + mtd->writesize, - chip->oob_poi, mtd->oobsize); +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); + 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 *tmp_buf = denali->buf; + int oob_skip = denali->oob_skip_bytes; + size_t size = writesize + oobsize; + int ret, i, pos, len; + + ret = denali_data_xfer(denali, tmp_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, tmp_buf + pos, len); + buf += len; + if (len < ecc_size) { + len = ecc_size - len; + memcpy(buf, tmp_buf + writesize + oob_skip, + len); + buf += len; + } + } + } - /* setting up DMA */ - irq_status = denali_dma_configuration(denali, DENALI_WRITE, raw_xfer, - irq_mask, oob_required); + if (oob_required) { + uint8_t *oob = chip->oob_poi; + + /* BBM at the beginning of the OOB area */ + memcpy(oob, tmp_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, tmp_buf + pos, len); + oob += len; + if (len < ecc_bytes) { + len = ecc_bytes - len; + memcpy(oob, tmp_buf + writesize + oob_skip, + len); + oob += len; + } + } - /* if timeout happen, error out */ - if (!(irq_status & INTR_STATUS__DMA_CMD_COMP)) { - debug("DMA timeout for denali write_page\n"); - denali->status = NAND_STATUS_FAIL; - return -EIO; + /* OOB free */ + len = oobsize - (oob - chip->oob_poi); + memcpy(oob, tmp_buf + size - len, len); } - if (irq_status & INTR_STATUS__LOCKED_BLK) { - debug("Failed as write to locked block\n"); - denali->status = NAND_STATUS_FAIL; - return -EIO; - } return 0; } -/* 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_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) { - struct denali_nand_info *denali = mtd_to_denali(mtd); - - /* - * for regular page writes, we let HW handle all the ECC - * data written to the device. - */ - if (oob_required) - /* switch to main + spare access */ - denali_mode_main_spare_access(denali); - else - /* switch to main access only */ - denali_mode_main_access(denali); + denali_oob_xfer(mtd, chip, page, 0); - return write_page(mtd, chip, buf, false, oob_required); + return 0; } -/* - * 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 int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); + int status; - /* - * for raw page writes, we want to disable ECC and simply write - * whatever data is in the buffer. - */ + denali_reset_irq(denali); - if (oob_required) - /* switch to main + spare access */ - denali_mode_main_spare_access(denali); - else - /* switch to main access only */ - denali_mode_main_access(denali); + denali_oob_xfer(mtd, chip, page, 1); - return write_page(mtd, chip, buf, true, oob_required); -} + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + status = chip->waitfunc(mtd, chip); -static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) -{ - return write_oob_data(mtd, chip->oob_poi, page); + return status & NAND_STATUS_FAIL ? -EIO : 0; } -/* raw include ECC value and all the spare area */ -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_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; - uint32_t irq_status, irq_mask = INTR_STATUS__DMA_CMD_COMP; + ret = denali_data_xfer(denali, buf, mtd->writesize, page, 0, 0); + if (ret && ret != -EBADMSG) + return ret; - if (denali->page != page) { - debug("Missing NAND_CMD_READ0 command\n"); - return -EIO; - } + if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) + stat = denali_hw_ecc_fixup(mtd, denali, &uncor_ecc_flags); + else if (ret == -EBADMSG) + stat = denali_sw_ecc_fixup(mtd, denali, &uncor_ecc_flags, buf); - if (oob_required) - /* switch to main + spare access */ - denali_mode_main_spare_access(denali); - else - /* switch to main access only */ - denali_mode_main_access(denali); + if (stat < 0) + return stat; - /* setting up the DMA where ecc_enable is false */ - irq_status = denali_dma_configuration(denali, DENALI_READ, true, - irq_mask, oob_required); + if (uncor_ecc_flags) { + ret = denali_read_oob(mtd, chip, page); + if (ret) + return ret; - /* if timeout happen, error out */ - if (!(irq_status & INTR_STATUS__DMA_CMD_COMP)) { - debug("DMA timeout for denali_read_page_raw\n"); - return -EIO; + stat = denali_check_erased_page(mtd, chip, buf, + uncor_ecc_flags, stat); } - /* splitting the content to destination buffer holder */ - memcpy(chip->oob_poi, (denali->buf.dma_buf + mtd->writesize), - mtd->oobsize); - memcpy(buf, denali->buf.dma_buf, mtd->writesize); - - return 0; + return stat; } -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_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); - uint32_t irq_status, irq_mask = INTR_STATUS__DMA_CMD_COMP; + 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 *tmp_buf = denali->buf; + int oob_skip = denali->oob_skip_bytes; + size_t size = writesize + oobsize; + int i, pos, len; - if (denali->page != page) { - debug("Missing NAND_CMD_READ0 command\n"); - return -EIO; + /* + * Fill the buffer with 0xff first except the full page transfer. + * This simplifies the logic. + */ + if (!buf || !oob_required) + memset(tmp_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(tmp_buf + pos, buf, len); + buf += len; + if (len < ecc_size) { + len = ecc_size - len; + memcpy(tmp_buf + writesize + oob_skip, buf, + len); + buf += len; + } + } } - if (oob_required) - /* switch to main + spare access */ - denali_mode_main_spare_access(denali); - else - /* switch to main access only */ - denali_mode_main_access(denali); - - /* setting up the DMA where ecc_enable is true */ - irq_status = denali_dma_configuration(denali, DENALI_READ, false, - irq_mask, oob_required); - - memcpy(buf, denali->buf.dma_buf, mtd->writesize); - - /* check whether any ECC error */ - if (irq_status & INTR_STATUS__ECC_UNCOR_ERR) { - /* is the ECC cause by erase page, check using read_page_raw */ - debug(" Uncorrected ECC detected\n"); - denali_read_page_raw(mtd, chip, buf, oob_required, - denali->page); - - if (is_erased(buf, mtd->writesize) == true && - is_erased(chip->oob_poi, mtd->oobsize) == true) { - debug(" ECC error cause by erased block\n"); - /* false alarm, return the 0xFF */ - } else { - return -EBADMSG; + if (oob_required) { + const uint8_t *oob = chip->oob_poi; + + /* BBM at the beginning of the OOB area */ + memcpy(tmp_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(tmp_buf + pos, oob, len); + oob += len; + if (len < ecc_bytes) { + len = ecc_bytes - len; + memcpy(tmp_buf + writesize + oob_skip, oob, + len); + oob += len; + } } + + /* OOB free */ + len = oobsize - (oob - chip->oob_poi); + memcpy(tmp_buf + size - len, oob, len); } - memcpy(buf, denali->buf.dma_buf, mtd->writesize); - return 0; + + return denali_data_xfer(denali, tmp_buf, size, page, 1, 1); } -static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required, int page) { - read_oob_data(mtd, chip->oob_poi, page); + struct denali_nand_info *denali = mtd_to_denali(mtd); - return 0; + return denali_data_xfer(denali, (void *)buf, mtd->writesize, + page, 0, 1); } -static uint8_t denali_read_byte(struct mtd_info *mtd) +static void denali_select_chip(struct mtd_info *mtd, int chip) { struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t addr, result; - addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); - index_addr_read_data(denali, addr | 2, &result); - return (uint8_t)result & 0xFF; + denali->active_bank = chip; } -static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) { struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t i, addr, result; - - /* delay for tR (data transfer from Flash array to data register) */ - udelay(25); + uint32_t irq_status; - /* ensure device completed else additional delay and polling */ - wait_for_irq(denali, INTR_STATUS__INT_ACT); + /* R/B# pin transitioned from low to high? */ + irq_status = denali_wait_for_irq(denali, INTR__INT_ACT); - addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); - for (i = 0; i < len; i++) { - index_addr_read_data(denali, (uint32_t)addr | 2, &result); - write_byte_to_buf(denali, result); - } - memcpy(buf, denali->buf.buf, len); + return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL; } -static void denali_select_chip(struct mtd_info *mtd, int chip) +static int denali_erase(struct mtd_info *mtd, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); + uint32_t irq_status; - denali->flash_bank = chip; -} + denali_reset_irq(denali); -static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - int status = denali->status; + denali->host_write(denali, DENALI_MAP10 | DENALI_BANK(denali) | page, + DENALI_ERASE); - denali->status = 0; + /* wait for erase to complete or failure to occur */ + irq_status = denali_wait_for_irq(denali, + INTR__ERASE_COMP | INTR__ERASE_FAIL); - return status; + return irq_status & INTR__ERASE_COMP ? 0 : NAND_STATUS_FAIL; } -static int denali_erase(struct mtd_info *mtd, int page) +static int __maybe_unused 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; - uint32_t cmd, irq_status; + timings = nand_get_sdr_timings(conf); + if (IS_ERR(timings)) + return PTR_ERR(timings); - clear_interrupts(denali); + /* clk_x period in picoseconds */ + t_clk = DIV_ROUND_DOWN_ULL(1000000000000ULL, denali->clk_x_rate); + if (!t_clk) + return -EINVAL; - /* setup page read request for access type */ - cmd = MODE_10 | BANK(denali->flash_bank) | page; - index_addr(denali, cmd, 0x1); + if (chipnr == NAND_DATA_IFACE_CHECK_ONLY) + return 0; - /* wait for erase to complete or failure to occur */ - irq_status = wait_for_irq(denali, INTR_STATUS__ERASE_COMP | - INTR_STATUS__ERASE_FAIL); + /* 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->reg + ACC_CLKS); + tmp &= ~ACC_CLKS__VALUE; + tmp |= FIELD_PREP(ACC_CLKS__VALUE, 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->reg + RE_2_WE); + tmp &= ~RE_2_WE__VALUE; + tmp |= FIELD_PREP(RE_2_WE__VALUE, 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->reg + RE_2_RE); + tmp &= ~RE_2_RE__VALUE; + tmp |= FIELD_PREP(RE_2_RE__VALUE, re_2_re); + iowrite32(tmp, denali->reg + RE_2_RE); + + /* + * tCCS, tWHR -> WE_2_RE + * + * With WE_2_RE properly set, the Denali controller automatically takes + * care of the delay; the driver need not set NAND_WAIT_TCCS. + */ + we_2_re = DIV_ROUND_UP(max(timings->tCCS_min, 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->reg + TWHR2_AND_WE_2_RE); + tmp &= ~TWHR2_AND_WE_2_RE__WE_2_RE; + tmp |= FIELD_PREP(TWHR2_AND_WE_2_RE__WE_2_RE, we_2_re); + iowrite32(tmp, denali->reg + TWHR2_AND_WE_2_RE); + + /* tADL -> ADDR_2_DATA */ - if (irq_status & INTR_STATUS__ERASE_FAIL || - irq_status & INTR_STATUS__LOCKED_BLK) - return NAND_STATUS_FAIL; + /* 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->reg + TCWAW_AND_ADDR_2_DATA); + tmp &= ~TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA; + tmp |= FIELD_PREP(TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA, 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->reg + RDWR_EN_HI_CNT); + tmp &= ~RDWR_EN_HI_CNT__VALUE; + tmp |= FIELD_PREP(RDWR_EN_HI_CNT__VALUE, rdwr_en_hi); + 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), + 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->reg + RDWR_EN_LO_CNT); + tmp &= ~RDWR_EN_LO_CNT__VALUE; + tmp |= FIELD_PREP(RDWR_EN_LO_CNT__VALUE, rdwr_en_lo); + 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, + (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->reg + CS_SETUP_CNT); + tmp &= ~CS_SETUP_CNT__VALUE; + tmp |= FIELD_PREP(CS_SETUP_CNT__VALUE, cs_setup); + iowrite32(tmp, denali->reg + CS_SETUP_CNT); return 0; } -static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, - int page) +static void denali_reset_banks(struct denali_nand_info *denali) { - struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t addr; - - switch (cmd) { - case NAND_CMD_PAGEPROG: - break; - case NAND_CMD_STATUS: - addr = MODE_11 | BANK(denali->flash_bank); - index_addr(denali, addr | 0, cmd); - break; - case NAND_CMD_READID: - case NAND_CMD_PARAM: - reset_buf(denali); - /* - * sometimes ManufactureId read from register is not right - * e.g. some of Micron MT29F32G08QAA MLC NAND chips - * So here we send READID cmd to NAND insteand - */ - addr = MODE_11 | BANK(denali->flash_bank); - index_addr(denali, addr | 0, cmd); - index_addr(denali, addr | 1, col & 0xFF); - if (cmd == NAND_CMD_PARAM) - udelay(50); - break; - case NAND_CMD_RNDOUT: - addr = MODE_11 | BANK(denali->flash_bank); - index_addr(denali, addr | 0, cmd); - index_addr(denali, addr | 1, col & 0xFF); - index_addr(denali, addr | 1, col >> 8); - index_addr(denali, addr | 0, NAND_CMD_RNDOUTSTART); - break; - case NAND_CMD_READ0: - case NAND_CMD_SEQIN: - denali->page = page; - break; - case NAND_CMD_RESET: - reset_bank(denali); - break; - case NAND_CMD_READOOB: - /* TODO: Read OOB data */ - break; - case NAND_CMD_ERASE1: - /* - * supporting block erase only, not multiblock erase as - * it will cross plane and software need complex calculation - * to identify the block count for the cross plane - */ - denali_erase(mtd, page); - break; - case NAND_CMD_ERASE2: - /* nothing to do here as it was done during NAND_CMD_ERASE1 */ - break; - case NAND_CMD_UNLOCK1: - addr = MODE_10 | BANK(denali->flash_bank) | page; - index_addr(denali, addr | 0, DENALI_UNLOCK_START); - break; - case NAND_CMD_UNLOCK2: - addr = MODE_10 | BANK(denali->flash_bank) | page; - index_addr(denali, addr | 0, DENALI_UNLOCK_END); - break; - case NAND_CMD_LOCK: - addr = MODE_10 | BANK(denali->flash_bank); - index_addr(denali, addr | 0, DENALI_LOCK); - break; - default: - printf(": unsupported command received 0x%x\n", cmd); - break; + u32 irq_status; + int i; + + for (i = 0; i < denali->max_banks; i++) { + denali->active_bank = i; + + denali_reset_irq(denali); + + iowrite32(DEVICE_RESET__BANK(i), + denali->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; } -/* end NAND core entry points */ -/* Initialization code to bring the device up to a known good state */ static void denali_hw_init(struct denali_nand_info *denali) { /* @@ -1154,125 +1086,285 @@ 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 writing * ECC code in OOB. This is normally used for bad block marker */ - writel(CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES, - denali->flash_reg + SPARE_AREA_SKIP_BYTES); - detect_max_banks(denali); - denali_nand_reset(denali); - writel(0x0F, denali->flash_reg + RB_PIN_ENABLED); - writel(CHIP_EN_DONT_CARE__FLAG, - denali->flash_reg + CHIP_ENABLE_DONT_CARE); - writel(0xffff, denali->flash_reg + SPARE_AREA_MARKER); - - /* Should set value for these registers when init */ - writel(0, denali->flash_reg + TWO_ROW_ADDR_CYCLES); - writel(1, denali->flash_reg + ECC_ENABLE); - denali_nand_timing_set(denali); - denali_irq_init(denali); + denali->oob_skip_bytes = CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES; + iowrite32(denali->oob_skip_bytes, denali->reg + SPARE_AREA_SKIP_BYTES); + denali_detect_max_banks(denali); + iowrite32(0x0F, denali->reg + RB_PIN_ENABLED); + iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE); + + iowrite32(0xffff, denali->reg + SPARE_AREA_MARKER); } -static struct nand_ecclayout nand_oob; +int denali_calc_ecc_bytes(int step_size, int strength) +{ + /* BCH code. Denali requires ecc.bytes to be multiple of 2 */ + return DIV_ROUND_UP(strength * fls(step_size * 8), 16) * 2; +} +EXPORT_SYMBOL(denali_calc_ecc_bytes); -int denali_init(struct denali_nand_info *denali) +static int denali_ecc_setup(struct mtd_info *mtd, struct nand_chip *chip, + struct denali_nand_info *denali) { - struct mtd_info *mtd = nand_to_mtd(&denali->nand); + int oobavail = mtd->oobsize - denali->oob_skip_bytes; int ret; - denali_hw_init(denali); + /* + * If .size and .strength are already set (usually by DT), + * check if they are supported by this controller. + */ + if (chip->ecc.size && chip->ecc.strength) + return nand_check_ecc_caps(chip, denali->ecc_caps, oobavail); + + /* + * We want .size and .strength closest to the chip's requirement + * unless NAND_ECC_MAXIMIZE is requested. + */ + if (!(chip->ecc.options & NAND_ECC_MAXIMIZE)) { + ret = nand_match_ecc_req(chip, denali->ecc_caps, oobavail); + if (!ret) + return 0; + } + + /* Max ECC strength is the last thing we can do */ + return nand_maximize_ecc(chip, denali->ecc_caps, oobavail); +} + +static struct nand_ecclayout nand_oob; + +static int denali_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + struct nand_chip *chip = mtd_to_nand(mtd); + + if (section) + return -ERANGE; + + oobregion->offset = denali->oob_skip_bytes; + oobregion->length = chip->ecc.total; + + return 0; +} - mtd->name = "denali-nand"; - mtd->owner = THIS_MODULE; +static int denali_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + struct nand_chip *chip = mtd_to_nand(mtd); + + if (section) + return -ERANGE; + + oobregion->offset = chip->ecc.total + denali->oob_skip_bytes; + oobregion->length = mtd->oobsize - oobregion->offset; + + return 0; +} - /* register the driver with the NAND core subsystem */ - denali->nand.select_chip = denali_select_chip; - denali->nand.cmdfunc = denali_cmdfunc; - denali->nand.read_byte = denali_read_byte; - denali->nand.read_buf = denali_read_buf; - denali->nand.waitfunc = denali_waitfunc; +static const struct mtd_ooblayout_ops denali_ooblayout_ops = { + .ecc = denali_ooblayout_ecc, + .free = denali_ooblayout_free, +}; + +static int denali_multidev_fixup(struct denali_nand_info *denali) +{ + struct nand_chip *chip = &denali->nand; + struct mtd_info *mtd = nand_to_mtd(chip); /* - * scan for NAND devices attached to the controller - * this is the first stage in a two step process to register - * with the nand subsystem + * Support for multi device: + * When the IP configuration is x16 capable and two x8 chips are + * connected in parallel, DEVICES_CONNECTED should be set to 2. + * In this case, the core framework knows nothing about this fact, + * so we should tell it the _logical_ pagesize and anything necessary. */ - if (nand_scan_ident(mtd, denali->max_banks, NULL)) { - ret = -ENXIO; - goto fail; - } + denali->devs_per_cs = ioread32(denali->reg + DEVICES_CONNECTED); -#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT - /* check whether flash got BBT table (located at end of flash). As we - * use NAND_BBT_NO_OOB, the BBT page will start with - * bbt_pattern. We will have mirror pattern too */ - denali->nand.bbt_options |= NAND_BBT_USE_FLASH; /* - * We are using main + spare with ECC support. As BBT need ECC support, - * we need to ensure BBT code don't write to OOB for the BBT pattern. - * All BBT info will be stored into data area with ECC support. + * On some SoCs, DEVICES_CONNECTED is not auto-detected. + * For those, DEVICES_CONNECTED is left to 0. Set 1 if it is the case. */ - denali->nand.bbt_options |= NAND_BBT_NO_OOB; -#endif + if (denali->devs_per_cs == 0) { + denali->devs_per_cs = 1; + iowrite32(1, denali->reg + DEVICES_CONNECTED); + } + + if (denali->devs_per_cs == 1) + return 0; + + if (denali->devs_per_cs != 2) { + dev_err(denali->dev, "unsupported number of devices %d\n", + denali->devs_per_cs); + return -EINVAL; + } + + /* 2 chips in parallel */ + mtd->size <<= 1; + mtd->erasesize <<= 1; + mtd->writesize <<= 1; + mtd->oobsize <<= 1; + chip->chipsize <<= 1; + chip->page_shift += 1; + chip->phys_erase_shift += 1; + chip->bbt_erase_shift += 1; + chip->chip_shift += 1; + chip->pagemask <<= 1; + chip->ecc.size <<= 1; + chip->ecc.bytes <<= 1; + chip->ecc.strength <<= 1; + denali->oob_skip_bytes <<= 1; + + return 0; +} + +int denali_init(struct denali_nand_info *denali) +{ + struct nand_chip *chip = &denali->nand; + struct mtd_info *mtd = nand_to_mtd(chip); + u32 features = ioread32(denali->reg + FEATURES); + int ret; + + mtd->dev->parent = denali->dev; + denali_hw_init(denali); + + denali_clear_irq_all(denali); - denali->nand.ecc.mode = NAND_ECC_HW; - denali->nand.ecc.size = CONFIG_NAND_DENALI_ECC_SIZE; + denali_reset_banks(denali); + + denali->active_bank = DENALI_INVALID_BANK; + + chip->flash_node = dev_of_offset(denali->dev); + /* Fallback to the default name if DT did not give "label" property */ + if (!mtd->name) + mtd->name = "denali-nand"; + + chip->select_chip = denali_select_chip; + chip->read_byte = denali_read_byte; + chip->write_byte = denali_write_byte; + chip->read_word = denali_read_word; + chip->cmd_ctrl = denali_cmd_ctrl; + chip->dev_ready = denali_dev_ready; + chip->waitfunc = denali_waitfunc; + + if (features & FEATURES__INDEX_ADDR) { + denali->host_read = denali_indexed_read; + denali->host_write = denali_indexed_write; + } else { + denali->host_read = denali_direct_read; + denali->host_write = denali_direct_write; + } + + /* clk rate info is needed for setup_data_interface */ + if (denali->clk_x_rate) + chip->setup_data_interface = denali_setup_data_interface; + + ret = nand_scan_ident(mtd, denali->max_banks, NULL); + if (ret) + return ret; + + if (ioread32(denali->reg + FEATURES) & FEATURES__DMA) + denali->dma_avail = 1; + + if (denali->dma_avail) { + chip->buf_align = 16; + if (denali->caps & DENALI_CAP_DMA_64BIT) + denali->setup_dma = denali_setup_dma64; + else + denali->setup_dma = denali_setup_dma32; + } else { + chip->buf_align = 4; + } + + chip->options |= NAND_USE_BOUNCE_BUFFER; + chip->bbt_options |= NAND_BBT_USE_FLASH; + chip->bbt_options |= NAND_BBT_NO_OOB; + denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME; /* no subpage writes on denali */ - denali->nand.options |= NAND_NO_SUBPAGE_WRITE; + chip->options |= NAND_NO_SUBPAGE_WRITE; - /* - * Tell driver the ecc strength. This register may be already set - * correctly. So we read this value out. - */ - denali->nand.ecc.strength = readl(denali->flash_reg + ECC_CORRECTION); - switch (denali->nand.ecc.size) { - case 512: - denali->nand.ecc.bytes = - (denali->nand.ecc.strength * 13 + 15) / 16 * 2; - break; - case 1024: - denali->nand.ecc.bytes = - (denali->nand.ecc.strength * 14 + 15) / 16 * 2; - break; - default: - pr_err("Unsupported ECC size\n"); - ret = -EINVAL; - goto fail; + ret = denali_ecc_setup(mtd, chip, denali); + if (ret) { + dev_err(denali->dev, "Failed to setup ECC settings.\n"); + return ret; } + + dev_dbg(denali->dev, + "chosen ECC settings: step=%d, strength=%d, bytes=%d\n", + chip->ecc.size, chip->ecc.strength, chip->ecc.bytes); + + iowrite32(FIELD_PREP(ECC_CORRECTION__ERASE_THRESHOLD, 1) | + FIELD_PREP(ECC_CORRECTION__VALUE, chip->ecc.strength), + denali->reg + ECC_CORRECTION); + iowrite32(mtd->erasesize / mtd->writesize, + denali->reg + PAGES_PER_BLOCK); + iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0, + denali->reg + DEVICE_WIDTH); + iowrite32(chip->options & NAND_ROW_ADDR_3 ? 0 : TWO_ROW_ADDR_CYCLES__FLAG, + denali->reg + TWO_ROW_ADDR_CYCLES); + iowrite32(mtd->writesize, denali->reg + DEVICE_MAIN_AREA_SIZE); + iowrite32(mtd->oobsize, denali->reg + DEVICE_SPARE_AREA_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->reg + CFG_NUM_DATA_BLOCKS); + + mtd_set_ooblayout(mtd, &denali_ooblayout_ops); + nand_oob.eccbytes = denali->nand.ecc.bytes; denali->nand.ecc.layout = &nand_oob; - writel(mtd->erasesize / mtd->writesize, - denali->flash_reg + PAGES_PER_BLOCK); - writel(denali->nand.options & NAND_BUSWIDTH_16 ? 1 : 0, - denali->flash_reg + DEVICE_WIDTH); - writel(mtd->writesize, - denali->flash_reg + DEVICE_MAIN_AREA_SIZE); - writel(mtd->oobsize, - denali->flash_reg + DEVICE_SPARE_AREA_SIZE); - if (readl(denali->flash_reg + DEVICES_CONNECTED) == 0) - writel(1, denali->flash_reg + DEVICES_CONNECTED); - - /* override the default operations */ - denali->nand.ecc.read_page = denali_read_page; - denali->nand.ecc.read_page_raw = denali_read_page_raw; - denali->nand.ecc.write_page = denali_write_page; - denali->nand.ecc.write_page_raw = denali_write_page_raw; - denali->nand.ecc.read_oob = denali_read_oob; - denali->nand.ecc.write_oob = denali_write_oob; - - if (nand_scan_tail(mtd)) { - ret = -ENXIO; - goto fail; + 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; + chip->ecc.write_page = denali_write_page; + chip->ecc.write_page_raw = denali_write_page_raw; + chip->ecc.read_oob = denali_read_oob; + chip->ecc.write_oob = denali_write_oob; + chip->erase = denali_erase; + + ret = denali_multidev_fixup(denali); + if (ret) + return ret; + + /* + * 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) + return -ENOMEM; + + ret = nand_scan_tail(mtd); + if (ret) + goto free_buf; ret = nand_register(0, mtd); + if (ret) { + dev_err(denali->dev, "Failed to register MTD: %d\n", ret); + goto free_buf; + } + return 0; + +free_buf: + kfree(denali->buf); -fail: return ret; } @@ -1289,8 +1381,8 @@ static int __board_nand_init(void) * In the future, these base addresses should be taken from * Device Tree or platform data. */ - denali->flash_reg = (void __iomem *)CONFIG_SYS_NAND_REGS_BASE; - denali->flash_mem = (void __iomem *)CONFIG_SYS_NAND_DATA_BASE; + denali->reg = (void __iomem *)CONFIG_SYS_NAND_REGS_BASE; + denali->host = (void __iomem *)CONFIG_SYS_NAND_DATA_BASE; return denali_init(denali); } diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index f796f0d..04b4ae2 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -8,466 +8,319 @@ #ifndef __DENALI_H__ #define __DENALI_H__ +#include #include +#include #define DEVICE_RESET 0x0 -#define DEVICE_RESET__BANK0 0x0001 -#define DEVICE_RESET__BANK1 0x0002 -#define DEVICE_RESET__BANK2 0x0004 -#define DEVICE_RESET__BANK3 0x0008 +#define DEVICE_RESET__BANK(bank) BIT(bank) #define TRANSFER_SPARE_REG 0x10 -#define TRANSFER_SPARE_REG__FLAG 0x0001 +#define TRANSFER_SPARE_REG__FLAG BIT(0) #define LOAD_WAIT_CNT 0x20 -#define LOAD_WAIT_CNT__VALUE 0xffff +#define LOAD_WAIT_CNT__VALUE GENMASK(15, 0) #define PROGRAM_WAIT_CNT 0x30 -#define PROGRAM_WAIT_CNT__VALUE 0xffff +#define PROGRAM_WAIT_CNT__VALUE GENMASK(15, 0) #define ERASE_WAIT_CNT 0x40 -#define ERASE_WAIT_CNT__VALUE 0xffff +#define ERASE_WAIT_CNT__VALUE GENMASK(15, 0) #define INT_MON_CYCCNT 0x50 -#define INT_MON_CYCCNT__VALUE 0xffff +#define INT_MON_CYCCNT__VALUE GENMASK(15, 0) #define RB_PIN_ENABLED 0x60 -#define RB_PIN_ENABLED__BANK0 0x0001 -#define RB_PIN_ENABLED__BANK1 0x0002 -#define RB_PIN_ENABLED__BANK2 0x0004 -#define RB_PIN_ENABLED__BANK3 0x0008 +#define RB_PIN_ENABLED__BANK(bank) BIT(bank) #define MULTIPLANE_OPERATION 0x70 -#define MULTIPLANE_OPERATION__FLAG 0x0001 +#define MULTIPLANE_OPERATION__FLAG BIT(0) #define MULTIPLANE_READ_ENABLE 0x80 -#define MULTIPLANE_READ_ENABLE__FLAG 0x0001 +#define MULTIPLANE_READ_ENABLE__FLAG BIT(0) #define COPYBACK_DISABLE 0x90 -#define COPYBACK_DISABLE__FLAG 0x0001 +#define COPYBACK_DISABLE__FLAG BIT(0) #define CACHE_WRITE_ENABLE 0xa0 -#define CACHE_WRITE_ENABLE__FLAG 0x0001 +#define CACHE_WRITE_ENABLE__FLAG BIT(0) #define CACHE_READ_ENABLE 0xb0 -#define CACHE_READ_ENABLE__FLAG 0x0001 +#define CACHE_READ_ENABLE__FLAG BIT(0) #define PREFETCH_MODE 0xc0 -#define PREFETCH_MODE__PREFETCH_EN 0x0001 -#define PREFETCH_MODE__PREFETCH_BURST_LENGTH 0xfff0 +#define PREFETCH_MODE__PREFETCH_EN BIT(0) +#define PREFETCH_MODE__PREFETCH_BURST_LENGTH GENMASK(15, 4) #define CHIP_ENABLE_DONT_CARE 0xd0 -#define CHIP_EN_DONT_CARE__FLAG 0x01 +#define CHIP_EN_DONT_CARE__FLAG BIT(0) #define ECC_ENABLE 0xe0 -#define ECC_ENABLE__FLAG 0x0001 +#define ECC_ENABLE__FLAG BIT(0) #define GLOBAL_INT_ENABLE 0xf0 -#define GLOBAL_INT_EN_FLAG 0x01 +#define GLOBAL_INT_EN_FLAG BIT(0) -#define WE_2_RE 0x100 -#define WE_2_RE__VALUE 0x003f +#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 0x003f +#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 0x003f +#define RE_2_WE__VALUE GENMASK(5, 0) #define ACC_CLKS 0x130 -#define ACC_CLKS__VALUE 0x000f +#define ACC_CLKS__VALUE GENMASK(3, 0) #define NUMBER_OF_PLANES 0x140 -#define NUMBER_OF_PLANES__VALUE 0x0007 +#define NUMBER_OF_PLANES__VALUE GENMASK(2, 0) #define PAGES_PER_BLOCK 0x150 -#define PAGES_PER_BLOCK__VALUE 0xffff +#define PAGES_PER_BLOCK__VALUE GENMASK(15, 0) #define DEVICE_WIDTH 0x160 -#define DEVICE_WIDTH__VALUE 0x0003 +#define DEVICE_WIDTH__VALUE GENMASK(1, 0) #define DEVICE_MAIN_AREA_SIZE 0x170 -#define DEVICE_MAIN_AREA_SIZE__VALUE 0xffff +#define DEVICE_MAIN_AREA_SIZE__VALUE GENMASK(15, 0) #define DEVICE_SPARE_AREA_SIZE 0x180 -#define DEVICE_SPARE_AREA_SIZE__VALUE 0xffff +#define DEVICE_SPARE_AREA_SIZE__VALUE GENMASK(15, 0) #define TWO_ROW_ADDR_CYCLES 0x190 -#define TWO_ROW_ADDR_CYCLES__FLAG 0x0001 +#define TWO_ROW_ADDR_CYCLES__FLAG BIT(0) #define MULTIPLANE_ADDR_RESTRICT 0x1a0 -#define MULTIPLANE_ADDR_RESTRICT__FLAG 0x0001 +#define MULTIPLANE_ADDR_RESTRICT__FLAG BIT(0) #define ECC_CORRECTION 0x1b0 -#define ECC_CORRECTION__VALUE 0x001f +#define ECC_CORRECTION__VALUE GENMASK(4, 0) +#define ECC_CORRECTION__ERASE_THRESHOLD GENMASK(31, 16) #define READ_MODE 0x1c0 -#define READ_MODE__VALUE 0x000f +#define READ_MODE__VALUE GENMASK(3, 0) #define WRITE_MODE 0x1d0 -#define WRITE_MODE__VALUE 0x000f +#define WRITE_MODE__VALUE GENMASK(3, 0) #define COPYBACK_MODE 0x1e0 -#define COPYBACK_MODE__VALUE 0x000f +#define COPYBACK_MODE__VALUE GENMASK(3, 0) #define RDWR_EN_LO_CNT 0x1f0 -#define RDWR_EN_LO_CNT__VALUE 0x001f +#define RDWR_EN_LO_CNT__VALUE GENMASK(4, 0) #define RDWR_EN_HI_CNT 0x200 -#define RDWR_EN_HI_CNT__VALUE 0x001f +#define RDWR_EN_HI_CNT__VALUE GENMASK(4, 0) #define MAX_RD_DELAY 0x210 -#define MAX_RD_DELAY__VALUE 0x000f +#define MAX_RD_DELAY__VALUE GENMASK(3, 0) #define CS_SETUP_CNT 0x220 -#define CS_SETUP_CNT__VALUE 0x001f +#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 0x003f +#define SPARE_AREA_SKIP_BYTES__VALUE GENMASK(5, 0) #define SPARE_AREA_MARKER 0x240 -#define SPARE_AREA_MARKER__VALUE 0xffff +#define SPARE_AREA_MARKER__VALUE GENMASK(15, 0) #define DEVICES_CONNECTED 0x250 -#define DEVICES_CONNECTED__VALUE 0x0007 +#define DEVICES_CONNECTED__VALUE GENMASK(2, 0) #define DIE_MASK 0x260 -#define DIE_MASK__VALUE 0x00ff +#define DIE_MASK__VALUE GENMASK(7, 0) #define FIRST_BLOCK_OF_NEXT_PLANE 0x270 -#define FIRST_BLOCK_OF_NEXT_PLANE__VALUE 0xffff +#define FIRST_BLOCK_OF_NEXT_PLANE__VALUE GENMASK(15, 0) #define WRITE_PROTECT 0x280 -#define WRITE_PROTECT__FLAG 0x0001 +#define WRITE_PROTECT__FLAG BIT(0) #define RE_2_RE 0x290 -#define RE_2_RE__VALUE 0x003f +#define RE_2_RE__VALUE GENMASK(5, 0) #define MANUFACTURER_ID 0x300 -#define MANUFACTURER_ID__VALUE 0x00ff +#define MANUFACTURER_ID__VALUE GENMASK(7, 0) #define DEVICE_ID 0x310 -#define DEVICE_ID__VALUE 0x00ff +#define DEVICE_ID__VALUE GENMASK(7, 0) #define DEVICE_PARAM_0 0x320 -#define DEVICE_PARAM_0__VALUE 0x00ff +#define DEVICE_PARAM_0__VALUE GENMASK(7, 0) #define DEVICE_PARAM_1 0x330 -#define DEVICE_PARAM_1__VALUE 0x00ff +#define DEVICE_PARAM_1__VALUE GENMASK(7, 0) #define DEVICE_PARAM_2 0x340 -#define DEVICE_PARAM_2__VALUE 0x00ff +#define DEVICE_PARAM_2__VALUE GENMASK(7, 0) #define LOGICAL_PAGE_DATA_SIZE 0x350 -#define LOGICAL_PAGE_DATA_SIZE__VALUE 0xffff +#define LOGICAL_PAGE_DATA_SIZE__VALUE GENMASK(15, 0) #define LOGICAL_PAGE_SPARE_SIZE 0x360 -#define LOGICAL_PAGE_SPARE_SIZE__VALUE 0xffff +#define LOGICAL_PAGE_SPARE_SIZE__VALUE GENMASK(15, 0) #define REVISION 0x370 -#define REVISION__VALUE 0xffff +#define REVISION__VALUE GENMASK(15, 0) #define ONFI_DEVICE_FEATURES 0x380 -#define ONFI_DEVICE_FEATURES__VALUE 0x003f +#define ONFI_DEVICE_FEATURES__VALUE GENMASK(5, 0) #define ONFI_OPTIONAL_COMMANDS 0x390 -#define ONFI_OPTIONAL_COMMANDS__VALUE 0x003f +#define ONFI_OPTIONAL_COMMANDS__VALUE GENMASK(5, 0) #define ONFI_TIMING_MODE 0x3a0 -#define ONFI_TIMING_MODE__VALUE 0x003f +#define ONFI_TIMING_MODE__VALUE GENMASK(5, 0) #define ONFI_PGM_CACHE_TIMING_MODE 0x3b0 -#define ONFI_PGM_CACHE_TIMING_MODE__VALUE 0x003f +#define ONFI_PGM_CACHE_TIMING_MODE__VALUE GENMASK(5, 0) #define ONFI_DEVICE_NO_OF_LUNS 0x3c0 -#define ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS 0x00ff -#define ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE 0x0100 +#define ONFI_DEVICE_NO_OF_LUNS__NO_OF_LUNS GENMASK(7, 0) +#define ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE BIT(8) #define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L 0x3d0 -#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L__VALUE 0xffff +#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_L__VALUE GENMASK(15, 0) #define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U 0x3e0 -#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U__VALUE 0xffff - -#define FEATURES 0x3f0 -#define FEATURES__N_BANKS 0x0003 -#define FEATURES__ECC_MAX_ERR 0x003c -#define FEATURES__DMA 0x0040 -#define FEATURES__CMD_DMA 0x0080 -#define FEATURES__PARTITION 0x0100 -#define FEATURES__XDMA_SIDEBAND 0x0200 -#define FEATURES__GPREG 0x0400 -#define FEATURES__INDEX_ADDR 0x0800 +#define ONFI_DEVICE_NO_OF_BLOCKS_PER_LUN_U__VALUE GENMASK(15, 0) + +#define FEATURES 0x3f0 +#define FEATURES__N_BANKS GENMASK(1, 0) +#define FEATURES__ECC_MAX_ERR GENMASK(5, 2) +#define FEATURES__DMA BIT(6) +#define FEATURES__CMD_DMA BIT(7) +#define FEATURES__PARTITION BIT(8) +#define FEATURES__XDMA_SIDEBAND BIT(9) +#define FEATURES__GPREG BIT(10) +#define FEATURES__INDEX_ADDR BIT(11) #define TRANSFER_MODE 0x400 -#define TRANSFER_MODE__VALUE 0x0003 - -#define INTR_STATUS(__bank) (0x410 + ((__bank) * 0x50)) -#define INTR_EN(__bank) (0x420 + ((__bank) * 0x50)) - -/* - * Some versions of the IP have the ECC fixup handled in hardware. In this - * configuration we only get interrupted when the error is uncorrectable. - * Unfortunately this bit replaces INTR_STATUS__ECC_TRANSACTION_DONE from the - * old IP. - */ -#define INTR_STATUS__ECC_UNCOR_ERR 0x0001 -#define INTR_STATUS__ECC_TRANSACTION_DONE 0x0001 -#define INTR_STATUS__ECC_ERR 0x0002 -#define INTR_STATUS__DMA_CMD_COMP 0x0004 -#define INTR_STATUS__TIME_OUT 0x0008 -#define INTR_STATUS__PROGRAM_FAIL 0x0010 -#define INTR_STATUS__ERASE_FAIL 0x0020 -#define INTR_STATUS__LOAD_COMP 0x0040 -#define INTR_STATUS__PROGRAM_COMP 0x0080 -#define INTR_STATUS__ERASE_COMP 0x0100 -#define INTR_STATUS__PIPE_CPYBCK_CMD_COMP 0x0200 -#define INTR_STATUS__LOCKED_BLK 0x0400 -#define INTR_STATUS__UNSUP_CMD 0x0800 -#define INTR_STATUS__INT_ACT 0x1000 -#define INTR_STATUS__RST_COMP 0x2000 -#define INTR_STATUS__PIPE_CMD_ERR 0x4000 -#define INTR_STATUS__PAGE_XFER_INC 0x8000 - -#define INTR_EN__ECC_TRANSACTION_DONE 0x0001 -#define INTR_EN__ECC_ERR 0x0002 -#define INTR_EN__DMA_CMD_COMP 0x0004 -#define INTR_EN__TIME_OUT 0x0008 -#define INTR_EN__PROGRAM_FAIL 0x0010 -#define INTR_EN__ERASE_FAIL 0x0020 -#define INTR_EN__LOAD_COMP 0x0040 -#define INTR_EN__PROGRAM_COMP 0x0080 -#define INTR_EN__ERASE_COMP 0x0100 -#define INTR_EN__PIPE_CPYBCK_CMD_COMP 0x0200 -#define INTR_EN__LOCKED_BLK 0x0400 -#define INTR_EN__UNSUP_CMD 0x0800 -#define INTR_EN__INT_ACT 0x1000 -#define INTR_EN__RST_COMP 0x2000 -#define INTR_EN__PIPE_CMD_ERR 0x4000 -#define INTR_EN__PAGE_XFER_INC 0x8000 - -#define PAGE_CNT(__bank) (0x430 + ((__bank) * 0x50)) -#define ERR_PAGE_ADDR(__bank) (0x440 + ((__bank) * 0x50)) -#define ERR_BLOCK_ADDR(__bank) (0x450 + ((__bank) * 0x50)) - -#define DATA_INTR 0x550 -#define DATA_INTR__WRITE_SPACE_AV 0x0001 -#define DATA_INTR__READ_DATA_AV 0x0002 - -#define DATA_INTR_EN 0x560 -#define DATA_INTR_EN__WRITE_SPACE_AV 0x0001 -#define DATA_INTR_EN__READ_DATA_AV 0x0002 - -#define GPREG_0 0x570 -#define GPREG_0__VALUE 0xffff - -#define GPREG_1 0x580 -#define GPREG_1__VALUE 0xffff - -#define GPREG_2 0x590 -#define GPREG_2__VALUE 0xffff - -#define GPREG_3 0x5a0 -#define GPREG_3__VALUE 0xffff +#define TRANSFER_MODE__VALUE GENMASK(1, 0) + +#define INTR_STATUS(bank) (0x410 + (bank) * 0x50) +#define INTR_EN(bank) (0x420 + (bank) * 0x50) +/* bit[1:0] is used differently depending on IP version */ +#define INTR__ECC_UNCOR_ERR BIT(0) /* new IP */ +#define INTR__ECC_TRANSACTION_DONE BIT(0) /* old IP */ +#define INTR__ECC_ERR BIT(1) /* old IP */ +#define INTR__DMA_CMD_COMP BIT(2) +#define INTR__TIME_OUT BIT(3) +#define INTR__PROGRAM_FAIL BIT(4) +#define INTR__ERASE_FAIL BIT(5) +#define INTR__LOAD_COMP BIT(6) +#define INTR__PROGRAM_COMP BIT(7) +#define INTR__ERASE_COMP BIT(8) +#define INTR__PIPE_CPYBCK_CMD_COMP BIT(9) +#define INTR__LOCKED_BLK BIT(10) +#define INTR__UNSUP_CMD BIT(11) +#define INTR__INT_ACT BIT(12) +#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) +#define ERR_BLOCK_ADDR(bank) (0x450 + (bank) * 0x50) #define ECC_THRESHOLD 0x600 -#define ECC_THRESHOLD__VALUE 0x03ff +#define ECC_THRESHOLD__VALUE GENMASK(9, 0) #define ECC_ERROR_BLOCK_ADDRESS 0x610 -#define ECC_ERROR_BLOCK_ADDRESS__VALUE 0xffff +#define ECC_ERROR_BLOCK_ADDRESS__VALUE GENMASK(15, 0) #define ECC_ERROR_PAGE_ADDRESS 0x620 -#define ECC_ERROR_PAGE_ADDRESS__VALUE 0x0fff -#define ECC_ERROR_PAGE_ADDRESS__BANK 0xf000 +#define ECC_ERROR_PAGE_ADDRESS__VALUE GENMASK(11, 0) +#define ECC_ERROR_PAGE_ADDRESS__BANK GENMASK(15, 12) #define ECC_ERROR_ADDRESS 0x630 -#define ECC_ERROR_ADDRESS__OFFSET 0x0fff -#define ECC_ERROR_ADDRESS__SECTOR_NR 0xf000 +#define ECC_ERROR_ADDRESS__OFFSET GENMASK(11, 0) +#define ECC_ERROR_ADDRESS__SECTOR GENMASK(15, 12) #define ERR_CORRECTION_INFO 0x640 -#define ERR_CORRECTION_INFO__BYTEMASK 0x00ff -#define ERR_CORRECTION_INFO__DEVICE_NR 0x0f00 -#define ERR_CORRECTION_INFO__ERROR_TYPE 0x4000 -#define ERR_CORRECTION_INFO__LAST_ERR_INFO 0x8000 +#define ERR_CORRECTION_INFO__BYTE GENMASK(7, 0) +#define ERR_CORRECTION_INFO__DEVICE GENMASK(11, 8) +#define ERR_CORRECTION_INFO__UNCOR BIT(14) +#define ERR_CORRECTION_INFO__LAST_ERR BIT(15) + +#define ECC_COR_INFO(bank) (0x650 + (bank) / 2 * 0x10) +#define ECC_COR_INFO__SHIFT(bank) ((bank) % 2 * 8) +#define ECC_COR_INFO__MAX_ERRORS GENMASK(6, 0) +#define ECC_COR_INFO__UNCOR_ERR BIT(7) + +#define CFG_DATA_BLOCK_SIZE 0x6b0 + +#define CFG_LAST_DATA_BLOCK_SIZE 0x6c0 + +#define CFG_NUM_DATA_BLOCKS 0x6d0 + +#define CFG_META_DATA_SIZE 0x6e0 #define DMA_ENABLE 0x700 -#define DMA_ENABLE__FLAG 0x0001 +#define DMA_ENABLE__FLAG BIT(0) #define IGNORE_ECC_DONE 0x710 -#define IGNORE_ECC_DONE__FLAG 0x0001 +#define IGNORE_ECC_DONE__FLAG BIT(0) #define DMA_INTR 0x720 -#define DMA_INTR__TARGET_ERROR 0x0001 -#define DMA_INTR__DESC_COMP_CHANNEL0 0x0002 -#define DMA_INTR__DESC_COMP_CHANNEL1 0x0004 -#define DMA_INTR__DESC_COMP_CHANNEL2 0x0008 -#define DMA_INTR__DESC_COMP_CHANNEL3 0x0010 -#define DMA_INTR__MEMCOPY_DESC_COMP 0x0020 - #define DMA_INTR_EN 0x730 -#define DMA_INTR_EN__TARGET_ERROR 0x0001 -#define DMA_INTR_EN__DESC_COMP_CHANNEL0 0x0002 -#define DMA_INTR_EN__DESC_COMP_CHANNEL1 0x0004 -#define DMA_INTR_EN__DESC_COMP_CHANNEL2 0x0008 -#define DMA_INTR_EN__DESC_COMP_CHANNEL3 0x0010 -#define DMA_INTR_EN__MEMCOPY_DESC_COMP 0x0020 +#define DMA_INTR__TARGET_ERROR BIT(0) +#define DMA_INTR__DESC_COMP_CHANNEL0 BIT(1) +#define DMA_INTR__DESC_COMP_CHANNEL1 BIT(2) +#define DMA_INTR__DESC_COMP_CHANNEL2 BIT(3) +#define DMA_INTR__DESC_COMP_CHANNEL3 BIT(4) +#define DMA_INTR__MEMCOPY_DESC_COMP BIT(5) #define TARGET_ERR_ADDR_LO 0x740 -#define TARGET_ERR_ADDR_LO__VALUE 0xffff +#define TARGET_ERR_ADDR_LO__VALUE GENMASK(15, 0) #define TARGET_ERR_ADDR_HI 0x750 -#define TARGET_ERR_ADDR_HI__VALUE 0xffff +#define TARGET_ERR_ADDR_HI__VALUE GENMASK(15, 0) #define CHNL_ACTIVE 0x760 -#define CHNL_ACTIVE__CHANNEL0 0x0001 -#define CHNL_ACTIVE__CHANNEL1 0x0002 -#define CHNL_ACTIVE__CHANNEL2 0x0004 -#define CHNL_ACTIVE__CHANNEL3 0x0008 - -#define ACTIVE_SRC_ID 0x800 -#define ACTIVE_SRC_ID__VALUE 0x00ff - -#define PTN_INTR 0x810 -#define PTN_INTR__CONFIG_ERROR 0x0001 -#define PTN_INTR__ACCESS_ERROR_BANK0 0x0002 -#define PTN_INTR__ACCESS_ERROR_BANK1 0x0004 -#define PTN_INTR__ACCESS_ERROR_BANK2 0x0008 -#define PTN_INTR__ACCESS_ERROR_BANK3 0x0010 -#define PTN_INTR__REG_ACCESS_ERROR 0x0020 - -#define PTN_INTR_EN 0x820 -#define PTN_INTR_EN__CONFIG_ERROR 0x0001 -#define PTN_INTR_EN__ACCESS_ERROR_BANK0 0x0002 -#define PTN_INTR_EN__ACCESS_ERROR_BANK1 0x0004 -#define PTN_INTR_EN__ACCESS_ERROR_BANK2 0x0008 -#define PTN_INTR_EN__ACCESS_ERROR_BANK3 0x0010 -#define PTN_INTR_EN__REG_ACCESS_ERROR 0x0020 - -#define PERM_SRC_ID(__bank) (0x830 + ((__bank) * 0x40)) -#define PERM_SRC_ID__SRCID 0x00ff -#define PERM_SRC_ID__DIRECT_ACCESS_ACTIVE 0x0800 -#define PERM_SRC_ID__WRITE_ACTIVE 0x2000 -#define PERM_SRC_ID__READ_ACTIVE 0x4000 -#define PERM_SRC_ID__PARTITION_VALID 0x8000 - -#define MIN_BLK_ADDR(__bank) (0x840 + ((__bank) * 0x40)) -#define MIN_BLK_ADDR__VALUE 0xffff - -#define MAX_BLK_ADDR(__bank) (0x850 + ((__bank) * 0x40)) -#define MAX_BLK_ADDR__VALUE 0xffff - -#define MIN_MAX_BANK(__bank) (0x860 + ((__bank) * 0x40)) -#define MIN_MAX_BANK__MIN_VALUE 0x0003 -#define MIN_MAX_BANK__MAX_VALUE 0x000c - -/* lld.h */ -#define GOOD_BLOCK 0 -#define DEFECTIVE_BLOCK 1 -#define READ_ERROR 2 - -#define CLK_X 5 -#define CLK_MULTI 4 - -/* spectraswconfig.h */ -#define CMD_DMA 0 - -#define SPECTRA_PARTITION_ID 0 -/**** Block Table and Reserved Block Parameters *****/ -#define SPECTRA_START_BLOCK 3 -#define NUM_FREE_BLOCKS_GATE 30 - -/* KBV - Updated to LNW scratch register address */ -#define SCRATCH_REG_ADDR CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR -#define SCRATCH_REG_SIZE 64 - -#define GLOB_HWCTL_DEFAULT_BLKS 2048 - -#define CUSTOM_CONF_PARAMS 0 - -#define INDEX_CTRL_REG 0x0 -#define INDEX_DATA_REG 0x10 - -#define MODE_00 0x00000000 -#define MODE_01 0x04000000 -#define MODE_10 0x08000000 -#define MODE_11 0x0C000000 - - -#define DATA_TRANSFER_MODE 0 -#define PROTECTION_PER_BLOCK 1 -#define LOAD_WAIT_COUNT 2 -#define PROGRAM_WAIT_COUNT 3 -#define ERASE_WAIT_COUNT 4 -#define INT_MONITOR_CYCLE_COUNT 5 -#define READ_BUSY_PIN_ENABLED 6 -#define MULTIPLANE_OPERATION_SUPPORT 7 -#define PRE_FETCH_MODE 8 -#define CE_DONT_CARE_SUPPORT 9 -#define COPYBACK_SUPPORT 10 -#define CACHE_WRITE_SUPPORT 11 -#define CACHE_READ_SUPPORT 12 -#define NUM_PAGES_IN_BLOCK 13 -#define ECC_ENABLE_SELECT 14 -#define WRITE_ENABLE_2_READ_ENABLE 15 -#define ADDRESS_2_DATA 16 -#define READ_ENABLE_2_WRITE_ENABLE 17 -#define TWO_ROW_ADDRESS_CYCLES 18 -#define MULTIPLANE_ADDRESS_RESTRICT 19 -#define ACC_CLOCKS 20 -#define READ_WRITE_ENABLE_LOW_COUNT 21 -#define READ_WRITE_ENABLE_HIGH_COUNT 22 - -#define ECC_SECTOR_SIZE 512 - -#define DENALI_BUF_SIZE (NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE) - -struct nand_buf { - int head; - int tail; - /* seprating dma_buf as buf can be used for status read purpose */ - uint8_t dma_buf[DENALI_BUF_SIZE] __aligned(64); - uint8_t buf[DENALI_BUF_SIZE]; -}; +#define CHNL_ACTIVE__CHANNEL0 BIT(0) +#define CHNL_ACTIVE__CHANNEL1 BIT(1) +#define CHNL_ACTIVE__CHANNEL2 BIT(2) +#define CHNL_ACTIVE__CHANNEL3 BIT(3) -#define INTEL_CE4100 1 -#define INTEL_MRST 2 -#define DT 3 +struct udevice; struct denali_nand_info { struct nand_chip nand; unsigned long clk_x_rate; /* bus interface clock rate */ - int flash_bank; /* currently selected chip */ - int status; - int platform; - struct nand_buf buf; - struct device *dev; - int total_used_banks; - uint32_t block; /* stored for future use */ + int active_bank; /* currently selected bank */ + struct udevice *dev; uint32_t page; - void __iomem *flash_reg; /* Mapped io reg base address */ - void __iomem *flash_mem; /* Mapped io reg base address */ - - /* elements used by ISR */ - /*struct completion complete;*/ - - uint32_t irq_status; - int irq_debug_array[32]; - int idx; + void __iomem *reg; /* Register Interface */ + void __iomem *host; /* Host Data/Command Interface */ + u32 irq_mask; /* interrupts we are waiting for */ + u32 irq_status; /* interrupts that have happened */ int irq; - - uint32_t devnum; /* represent how many nands connected */ - uint32_t fwblks; /* represent how many blocks FW used */ - uint32_t totalblks; - uint32_t blksperchip; - uint32_t bbtskipbytes; - uint32_t max_banks; - unsigned int revision; - unsigned int caps; + void *buf; /* for syndrome layout conversion */ + dma_addr_t dma_addr; + int dma_avail; /* can support DMA? */ + int devs_per_cs; /* devices connected in parallel */ + int oob_skip_bytes; /* number of bytes reserved for BBM */ + int max_banks; + unsigned int revision; /* IP revision */ + unsigned int caps; /* IP capability (or quirk) */ + const struct nand_ecc_caps *ecc_caps; + u32 (*host_read)(struct denali_nand_info *denali, u32 addr); + void (*host_write)(struct denali_nand_info *denali, u32 addr, u32 data); + void (*setup_dma)(struct denali_nand_info *denali, dma_addr_t dma_addr, + int page, int write); }; #define DENALI_CAP_HW_ECC_FIXUP BIT(0) #define DENALI_CAP_DMA_64BIT BIT(1) +int denali_calc_ecc_bytes(int step_size, int strength); int denali_init(struct denali_nand_info *denali); #endif /* __DENALI_H__ */ diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index 805c066..9d6cb09 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -16,21 +16,31 @@ struct denali_dt_data { unsigned int revision; unsigned int caps; + const struct nand_ecc_caps *ecc_caps; }; +NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes, + 512, 8, 15); static const struct denali_dt_data denali_socfpga_data = { .caps = DENALI_CAP_HW_ECC_FIXUP, + .ecc_caps = &denali_socfpga_ecc_caps, }; +NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes, + 1024, 8, 16, 24); static const struct denali_dt_data denali_uniphier_v5a_data = { .caps = DENALI_CAP_HW_ECC_FIXUP | DENALI_CAP_DMA_64BIT, + .ecc_caps = &denali_uniphier_v5a_ecc_caps, }; +NAND_ECC_CAPS_SINGLE(denali_uniphier_v5b_ecc_caps, denali_calc_ecc_bytes, + 1024, 8, 16); static const struct denali_dt_data denali_uniphier_v5b_data = { .revision = 0x0501, .caps = DENALI_CAP_HW_ECC_FIXUP | DENALI_CAP_DMA_64BIT, + .ecc_caps = &denali_uniphier_v5b_ecc_caps, }; static const struct udevice_id denali_nand_dt_ids[] = { @@ -61,19 +71,22 @@ static int denali_dt_probe(struct udevice *dev) if (data) { denali->revision = data->revision; denali->caps = data->caps; + denali->ecc_caps = data->ecc_caps; } + denali->dev = dev; + ret = dev_read_resource_byname(dev, "denali_reg", &res); if (ret) return ret; - denali->flash_reg = devm_ioremap(dev, res.start, resource_size(&res)); + denali->reg = devm_ioremap(dev, res.start, resource_size(&res)); ret = dev_read_resource_byname(dev, "nand_data", &res); if (ret) return ret; - denali->flash_mem = devm_ioremap(dev, res.start, resource_size(&res)); + denali->host = devm_ioremap(dev, res.start, resource_size(&res)); ret = clk_get_by_index(dev, 0, &clk); if (ret) diff --git a/drivers/mtd/nand/denali_spl.c b/drivers/mtd/nand/denali_spl.c index c693032..3cb9849 100644 --- a/drivers/mtd/nand/denali_spl.c +++ b/drivers/mtd/nand/denali_spl.c @@ -11,6 +11,12 @@ #include #include "denali.h" +#define DENALI_MAP01 (1 << 26) /* read/write pages in PIO */ +#define DENALI_MAP10 (2 << 26) /* high-level control plane */ + +#define INDEX_CTRL_REG 0x0 +#define INDEX_DATA_REG 0x10 + #define SPARE_ACCESS 0x41 #define MAIN_ACCESS 0x42 #define PIPELINE_ACCESS 0x2000 @@ -39,7 +45,7 @@ static int wait_for_irq(uint32_t irq_mask) do { intr_status = readl(denali_flash_reg + INTR_STATUS(flash_bank)); - if (intr_status & INTR_STATUS__ECC_UNCOR_ERR) { + if (intr_status & INTR__ECC_UNCOR_ERR) { debug("Uncorrected ECC detected\n"); return -EBADMSG; } @@ -106,16 +112,16 @@ int denali_send_pipeline_cmd(int page, int ecc_en, int access_type) addr = BANK(flash_bank) | page; /* setup the acccess type */ - cmd = MODE_10 | addr; + cmd = DENALI_MAP10 | addr; index_addr(cmd, access_type); /* setup the pipeline command */ index_addr(cmd, PIPELINE_ACCESS | page_count); - cmd = MODE_01 | addr; + cmd = DENALI_MAP01 | addr; writel(cmd, denali_flash_mem + INDEX_CTRL_REG); - return wait_for_irq(INTR_STATUS__LOAD_COMP); + return wait_for_irq(INTR__LOAD_COMP); } static int nand_read_oob(void *buf, int page)