From patchwork Mon Jun 5 23:21:40 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103116 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1009581obh; Mon, 5 Jun 2017 16:29:30 -0700 (PDT) X-Received: by 10.84.140.164 with SMTP id 33mr18196553plt.142.1496705370880; Mon, 05 Jun 2017 16:29:30 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705370; cv=none; d=google.com; s=arc-20160816; b=vi9oyzX5dUSU3CdaWJZg9HFRr4yFdOE/jFfWond1GBTXC+STM3u1XXX7sKFAf03oFC GOfb9Q5HBvpnuyVSSZDS8GZIS8+yQoPrTHTugyw1yCm5xu0DMBS9x+rhHQLJVJDMKc9r xVTEDC2KIo9CHfssoeTAR5N9aAr/oqfO2XtB64mZC0khYOHsoEYw6nGffOvnz6YhYTkU fW+L8aPJayrLcTpUa30pL1EvCHXL9ppntZeBK5mdcMOGh8V7T32Psk1tM3jGLGOgC00Q hr1+DPpOznYMiKQ4ej1WdzuUyUQp4RyaDgt26OzRTAxRDrpwqnMfCTnnOv5ZRMolRlAv d+0A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=+JAiBXs6pizrciLh8xUqAMzXGQ5fXL+vhEEFoVp7No8=; b=VEsoYJhJGe+XDLonCaLz7h1gUwsE9nfc3XQBE8LmUMxO+kRqpkxxF83//bWT6/AaYJ x0wgiTIqpuNU6dXZYtm4dET2EleZzefcJKv5uaLbZF03MvY8ARMBTVkDI81B7jooAeGh CLbUaw0Gujo4b/TvfuKXZiAWu1xnQaBIl28ytGugV2YHVsMsbCzHjlNnZDImrpgYSErd 3ssfXgZ3pB5hIZJrs8kppWD1vmAHUJZ7o9J1/EaY8oa/PW1/fkoWexphM8OFoPTwx1Hu DEE7vhifwt+vwwjUBrJAt9s0Slt+GnjA/n29t1tHFaGs8wZiiiXXQxKLToYo0Gj2Gsra GtGA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id s4si2756254pfi.251.2017.06.05.16.29.30; Mon, 05 Jun 2017 16:29:30 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751462AbdFEX2G (ORCPT + 25 others); Mon, 5 Jun 2017 19:28:06 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:32196 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751303AbdFEXZS (ORCPT ); Mon, 5 Jun 2017 19:25:18 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5b004412; Tue, 6 Jun 2017 08:22:28 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5b004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704949; bh=+JAiBXs6pizrciLh8xUqAMzXGQ5fXL+vhEEFoVp7No8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Ebg+C7Ca8UXkAhflYIW3jfOdqSoGACE/PgN0LenYyzYDi/DLqqScZ/To8MQl3b5l5 BAR9h0RhWT2nVHsapPDe7L1kYq5S5L5aknYhSUn7NKuDVmvvvA4XzyiOsXK4vbR7nH qWGElzYfj2o7lMJG8YPqotq4Vc8bO1CJLyyavldnwgTLw0KO6hgX5oJRqAGQm1JPOH C3NxKitL3k8HhDtZxdKq6m3PXpBBKyVcystgOrZmENAZHsz/F5nq7XAv0iGtqR4ZLt Cuu5BEp/ylC/2sd9NxH8lZG21C64jcxIpsLmp48gpct8wOujjCj2CxtCFxKUgL6zei OxPRPC9GwECrw== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v4 01/23] mtd: nand: denali_dt: clean up resource ioremap Date: Tue, 6 Jun 2017 08:21:40 +0900 Message-Id: <1496704922-12261-2-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org No need to use two struct resource pointers. Just reuse one. Signed-off-by: Masahiro Yamada --- Changes in v4: - Newly added Changes in v3: None Changes in v2: None drivers/mtd/nand/denali_dt.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index df9ef36..b48430f 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -49,7 +49,7 @@ MODULE_DEVICE_TABLE(of, denali_nand_dt_ids); static int denali_dt_probe(struct platform_device *pdev) { - struct resource *denali_reg, *nand_data; + struct resource *res; struct denali_dt *dt; const struct denali_dt_data *data; struct denali_nand_info *denali; @@ -74,15 +74,13 @@ static int denali_dt_probe(struct platform_device *pdev) return denali->irq; } - denali_reg = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "denali_reg"); - denali->flash_reg = devm_ioremap_resource(&pdev->dev, denali_reg); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "denali_reg"); + denali->flash_reg = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(denali->flash_reg)) return PTR_ERR(denali->flash_reg); - nand_data = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "nand_data"); - denali->flash_mem = devm_ioremap_resource(&pdev->dev, nand_data); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data"); + denali->flash_mem = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(denali->flash_mem)) return PTR_ERR(denali->flash_mem); From patchwork Mon Jun 5 23:21:41 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103114 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1009289obh; Mon, 5 Jun 2017 16:28:29 -0700 (PDT) X-Received: by 10.84.216.24 with SMTP id m24mr17542844pli.281.1496705309653; Mon, 05 Jun 2017 16:28:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705309; cv=none; d=google.com; s=arc-20160816; b=LTBk/ay2OdTiQOeRVQNKMYywY8MZKsK8x2Zn7VIipDfchpWV4uQDSTegHU603Xap2v XAP5Btq6VVeSiiRdbD8fp6O74WTqjbQLsozaNi7i98lRiOubzRQakTOdkI52furxhp73 ZKqt6hEx6A5iUGLLycaP91aen2CaDv2j8CqE3cs01342u7yQ/gtKM27lyD9ErhgSFyxR q9jEtTSp6/nD06l5vkjUJpl/2WtVe/5JOsw5iGgWiCczawh7LKhRj+ckNFrhH+OePnPv OKafTLo+ZcozuqFfMlaxHHvwpIDboJl3uF59RKdQRbz73KVqvL6rYTDI5tUfGRFQbI2P UnMA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=UcCTgpsz3ibt3hpu2icA6vfxYbU5jncjOdsMV8qp8Po=; b=V8qzLsihPQXsx3huEz//VFDODVPecKPt3cwr8ST8QtP29R1KEdOuFkA91BoCkTHMc7 rypivpfdxmKVrf0vqEcUFQ8bLJXQ5MmcB2G3bm4ZpgThTXWeU0HBq/KOcX4Pb+DJMiqB lxf4hBQnLhEkOmJ5h56E3sy8UnhKirs+mPwJ6c2/PsZKp4PD6+7Sv48tuGVTGUdKkLCb DTepoBJd9l+bdtaP8ju3e6yUXjtZf1KKTUEvQUj2OyoYQHyxlBtt6I5+F0GqUU0C6Z+j KAWMeMBbZm1oSxY4ySQOzyY/pvS6QmuoWpNnL8xB6MsG8ewwtdzhMd7L9EgYIRqC5wNT 9aCQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id b5si32117983pfc.53.2017.06.05.16.28.28; Mon, 05 Jun 2017 16:28:29 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751542AbdFEX2L (ORCPT + 25 others); Mon, 5 Jun 2017 19:28:11 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:32164 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751291AbdFEXZS (ORCPT ); Mon, 5 Jun 2017 19:25:18 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5c004412; Tue, 6 Jun 2017 08:22:29 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5c004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704950; bh=UcCTgpsz3ibt3hpu2icA6vfxYbU5jncjOdsMV8qp8Po=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=B4IWhR8exNiCBG0NETHgFjGZ/ycU2lTBuhQY04PZ/tZu0qB8a43wmCKEg8nkQdEmt f7vBdwQ70uN1SGbRfAcb1B+ZDPYBQZRjl/Rxu/CHmhHtT1QLaaQoiP5IDAOc5GWI4f +q097HZLQTx+TYrTBLLIfC2wDRGnLa2ooZ58CJ/2X7l1gnRETTbR0mkjDkeieuzwgf ihw9kcl1jXbBnMERDVGSwaEUgTHnMoJh34itBYl8HMlb4+9M8j28EiD7KMhAQSoeWv xQefonetsw/8ABxwI+JBx/MRuR14jrjniN/GkGzFi/Dgao3y6sUqXom3KA3PVeT1mt +dW4ZlnHKFZwA== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v4 02/23] mtd: nand: denali: use BIT() and GENMASK() for register macros Date: Tue, 6 Jun 2017 08:21:41 +0900 Message-Id: <1496704922-12261-3-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Use BIT() and GENMASK() for register field macros. This will make it easier to compare the macros with the register description in the Denali User's Guide. Signed-off-by: Masahiro Yamada --- Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.h | 244 ++++++++++++++++++++++------------------------ 1 file changed, 119 insertions(+), 125 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index ec00485..3783353 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -24,273 +24,267 @@ #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 WE_2_RE__VALUE GENMASK(5, 0) #define ADDR_2_DATA 0x110 -#define ADDR_2_DATA__VALUE 0x003f +#define ADDR_2_DATA__VALUE GENMASK(5, 0) #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 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 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 TRANSFER_MODE__VALUE GENMASK(1, 0) -#define INTR_STATUS(__bank) (0x410 + ((__bank) * 0x50)) -#define INTR_EN(__bank) (0x420 + ((__bank) * 0x50)) +#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 0x0001 /* new IP */ -#define INTR__ECC_TRANSACTION_DONE 0x0001 /* old IP */ -#define INTR__ECC_ERR 0x0002 /* old IP */ -#define INTR__DMA_CMD_COMP 0x0004 -#define INTR__TIME_OUT 0x0008 -#define INTR__PROGRAM_FAIL 0x0010 -#define INTR__ERASE_FAIL 0x0020 -#define INTR__LOAD_COMP 0x0040 -#define INTR__PROGRAM_COMP 0x0080 -#define INTR__ERASE_COMP 0x0100 -#define INTR__PIPE_CPYBCK_CMD_COMP 0x0200 -#define INTR__LOCKED_BLK 0x0400 -#define INTR__UNSUP_CMD 0x0800 -#define INTR__INT_ACT 0x1000 -#define INTR__RST_COMP 0x2000 -#define INTR__PIPE_CMD_ERR 0x4000 -#define INTR__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 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 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_NR 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__BYTEMASK GENMASK(7, 0) +#define ERR_CORRECTION_INFO__DEVICE_NR GENMASK(11, 8) +#define ERR_CORRECTION_INFO__ERROR_TYPE BIT(14) +#define ERR_CORRECTION_INFO__LAST_ERR_INFO 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 0x007f -#define ECC_COR_INFO__UNCOR_ERR 0x0080 +#define ECC_COR_INFO__MAX_ERRORS GENMASK(6, 0) +#define ECC_COR_INFO__UNCOR_ERR BIT(7) #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_EN 0x730 -#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__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 CHNL_ACTIVE__CHANNEL0 BIT(0) +#define CHNL_ACTIVE__CHANNEL1 BIT(1) +#define CHNL_ACTIVE__CHANNEL2 BIT(2) +#define CHNL_ACTIVE__CHANNEL3 BIT(3) #define FAIL 1 /*failed flag*/ #define PASS 0 /*success flag*/ From patchwork Mon Jun 5 23:21:42 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103107 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1008952obh; Mon, 5 Jun 2017 16:27:17 -0700 (PDT) X-Received: by 10.84.129.132 with SMTP id b4mr7707246plb.0.1496705236948; Mon, 05 Jun 2017 16:27:16 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705236; cv=none; d=google.com; s=arc-20160816; b=IXHIZba/efIv5p+0hqRE7Iv50UIKjlXhPjhaR8MAMLmVUL8IdjzRG6G4Y/40aFhIbz RcuGFmCcX00VK/QOnyE+bKEhnEgL7bhDhfvay0tJpe/N4x5p4tSc4wn+rqPCOmkfELKM 7zzH0HX39QH8OGz0x/vJT5Q9kW33QryHxfA7sZEdaKo6UYA+TF+jJao4eDqARxcILeyX DXyCzSzV74ACG+FHxshuqZoOJpI4L/rZbXRnL2DXPTRFZi+9WPMvKQfiiKv048C9SQPZ CuDBmtOhtpDpQ5o42L6RSCSzO6Iac8kQrzCmHMfg+s2dnAlGuUOsDGtzynMpJrK3zm3K V8mw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=A/NeolnhRM2kX9EmFk1LqpCRFndB6xF6oHRcjPyEjWs=; b=XD15eVRQ+0J39n1O4r9mJiGB3rZh9tfGE9Q1filOc5R+YWSHoZR7ssoOVhmXkvGH2P Ed3h5O2s0aSINUPhHyB1EFeIRd5MYu6fUW91xbg9JR+yx37uKi6bEdlX6C9OSlZVL6dS 71/aTb23RsuUXEVtdvO3ytmLVjkotj4BwVCiHqe6IoheGrndUDwuctyT1tsjysBdQ8+K 2E3zE3wGI5a4q9XhsOimdYEDINVP+GOtMJwbtNIsmrH428gQQLYZB+d5xVKrX0XWLpBP JrfLFVZHSu0ZYfLzHvByQ4Qxxv4pjaSzt//QZuAhyl/qrdvUZpEnEcTJ0kKEmRghe8FI LaGw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id i7si32017216pfi.233.2017.06.05.16.27.16; Mon, 05 Jun 2017 16:27:16 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751477AbdFEX0j (ORCPT + 25 others); Mon, 5 Jun 2017 19:26:39 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:32371 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751274AbdFEXZY (ORCPT ); Mon, 5 Jun 2017 19:25:24 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5d004412; Tue, 6 Jun 2017 08:22:30 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5d004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704951; bh=A/NeolnhRM2kX9EmFk1LqpCRFndB6xF6oHRcjPyEjWs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=oYnUW7nFeZx2yJ81nwGAZHsKG8HYD7/y7WUtzwvumrhJ9Tsgoe9Lf49vHBgXxKpxf IQTy+vzFAQeyO7z35ykQTknL/6zuXvnbWQeRdMN3DecX7G6XtewccjGVT/XFgBf9Y+ u8ZMdkd61DHEvoOY75Ylc7J7yeYu86I35rg3k7YXB0gTnRI3vTrV/6e36I00+tiZ+o FOmV7mjOBAT3lwKSyaZdQCRCJx2biHarI16aEskAjr0XXAdmCh+5d61yCZRTlxKsTC 2cEKFFaZZt45BCKQAexPUUMKPewfAeNSZgo3oacdvrPLmycPtmbSLrm3Q/+yzhRL7F MgAFy0ujI1hmQ== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v4 03/23] mtd: nand: add generic helpers to check, match, maximize ECC settings Date: Tue, 6 Jun 2017 08:21:42 +0900 Message-Id: <1496704922-12261-4-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Driver are responsible for setting up ECC parameters correctly. Those include: - Check if ECC parameters specified (usually by DT) are valid - Meet the chip's ECC requirement - Maximize ECC strength if NAND_ECC_MAXIMIZE flag is set The logic can be generalized by factoring out common code. This commit adds 3 helpers to the NAND framework: nand_check_ecc_caps - Check if preset step_size and strength are valid nand_match_ecc_req - Match the chip's requirement nand_maximize_ecc - Maximize the ECC strength To use the helpers above, a driver needs to provide: - Data array of supported ECC step size and strength - A hook that calculates ECC bytes from the combination of step_size and strength. By using those helpers, code duplication among drivers will be reduced. Signed-off-by: Masahiro Yamada --- Changes since the previous version: - Step size info holds an array of associated strengths - nand_match_ecc_req() does not take care of the case where ecc_size/strength is already set - Reflect more comments from Boris Previous version: http://patchwork.ozlabs.org/patch/752107/ Changes in v4: None Changes in v3: None Changes in v2: None drivers/mtd/nand/nand_base.c | 219 +++++++++++++++++++++++++++++++++++++++++++ include/linux/mtd/nand.h | 35 +++++++ 2 files changed, 254 insertions(+) -- 2.7.4 diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index bdfa903..f2da4f2 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -4509,6 +4509,225 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd) } } +/** + * nand_check_ecc_caps - check the sanity of preset ECC settings + * @mtd: mtd info structure + * @chip: nand chip info structure + * @caps: ECC caps info structure + * + * 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 mtd_info *mtd, struct nand_chip *chip, + const struct nand_ecc_caps *caps) +{ + const struct nand_ecc_step_info *stepinfo; + int avail_oobsize = mtd->oobsize - caps->oob_reserve_bytes; + int preset_step = chip->ecc.size; + int preset_strength = chip->ecc.strength; + int ecc_bytes; + int i, j; + + if (WARN_ON(avail_oobsize < 0)) + return -EINVAL; + + if (!preset_step || !preset_strength) + return -ENODATA; + + 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) + goto found; + } + } + + pr_err("ECC (step, strength) = (%d, %d) not supported on this controller", + preset_step, preset_strength); + + return -ENOTSUPP; + +found: + ecc_bytes = caps->calc_ecc_bytes(preset_step, preset_strength); + if (WARN_ON_ONCE(ecc_bytes < 0)) + return ecc_bytes; + + if (ecc_bytes * mtd->writesize / preset_step > avail_oobsize) { + 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; +} +EXPORT_SYMBOL_GPL(nand_check_ecc_caps); + +/** + * nand_match_ecc_req - meet the chip's requirement with least ECC bytes + * @mtd: mtd info structure + * @chip: nand chip info structure + * @caps: ECC engine caps info structure + * + * 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 mtd_info *mtd, struct nand_chip *chip, + const struct nand_ecc_caps *caps) +{ + const struct nand_ecc_step_info *stepinfo; + int avail_oobsize = mtd->oobsize - caps->oob_reserve_bytes; + int req_step = chip->ecc_step_ds; + int req_strength = chip->ecc_strength_ds; + int req_corr, step_size, strength, steps, 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(avail_oobsize < 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; + + steps = 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 * steps; + + if (ecc_bytes_total > avail_oobsize || + strength * steps < 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 + * @mtd: mtd info structure + * @chip: nand chip info structure + * @caps: ECC engine caps info structure + * + * 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 mtd_info *mtd, struct nand_chip *chip, + const struct nand_ecc_caps *caps) +{ + const struct nand_ecc_step_info *stepinfo; + int avail_oobsize = mtd->oobsize - caps->oob_reserve_bytes; + int step_size, strength, steps, ecc_bytes, corr; + int best_corr = 0; + int best_step = 0; + int best_strength, best_ecc_bytes; + int i, j; + + if (WARN_ON(avail_oobsize < 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; + + steps = mtd->writesize / step_size; + + ecc_bytes = caps->calc_ecc_bytes(step_size, strength); + if (WARN_ON_ONCE(ecc_bytes < 0)) + continue; + + if (ecc_bytes * steps > avail_oobsize) + continue; + + corr = strength * steps; + + /* + * 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 8f67b15..97ccb76 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -477,6 +477,32 @@ static inline void nand_hw_control_init(struct nand_hw_control *nfc) } /** + * struct nand_ecc_step_info - ECC step information of ECC engine + * @stepsize: data bytes per ECC step + * @strengths: array of supported strengths + * @nstrengths: number of supported strengths + */ +struct nand_ecc_step_info { + int stepsize; + const int *strengths; + int nstrengths; +}; + +/** + * struct nand_ecc_caps - capability of ECC engine + * @stepinfos: array of ECC step information + * @nstepinfos: number of ECC step information + * @calc_ecc_bytes: driver's hook to calculate ECC bytes per step + * @oob_reserve_bytes: number of bytes in OOB that must be reserved + */ +struct nand_ecc_caps { + const struct nand_ecc_step_info *stepinfos; + int nstepinfos; + int (*calc_ecc_bytes)(int step_size, int strength); + int oob_reserve_bytes; +}; + +/** * struct nand_ecc_ctrl - Control structure for ECC * @mode: ECC mode * @algo: ECC algorithm @@ -1244,6 +1270,15 @@ int nand_check_erased_ecc_chunk(void *data, int datalen, void *extraoob, int extraooblen, int threshold); +int nand_check_ecc_caps(struct mtd_info *mtd, struct nand_chip *chip, + const struct nand_ecc_caps *caps); + +int nand_match_ecc_req(struct mtd_info *mtd, struct nand_chip *chip, + const struct nand_ecc_caps *caps); + +int nand_maximize_ecc(struct mtd_info *mtd, struct nand_chip *chip, + const struct nand_ecc_caps *caps); + /* Default write_oob implementation */ int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page); From patchwork Mon Jun 5 23:21:43 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103109 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1008955obh; Mon, 5 Jun 2017 16:27:17 -0700 (PDT) X-Received: by 10.84.131.2 with SMTP id 2mr3425911pld.61.1496705237738; Mon, 05 Jun 2017 16:27:17 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705237; cv=none; d=google.com; s=arc-20160816; b=hvDIjpYXwKOXYM4fj5NuDtUWCUD8xLt77O9VDdmPrWdQcPYx8UPHVzGgGrh8bWPoSO hDQU9xpvb2KNDU7u5Bidnx396TGCgnWSuJfLId4icpNcqowtlKJ1sk98H1NETE3mzfM0 kc6FMM9V8xvLxorWkDC/NNLU/vklcVDSvZpvQbB0qrOz9RHaieVZlYozeQfR2W2pirf6 ym8rSjim1q/Une/a0mYcPSx/RUnibV086WVrN2DOD/cDqwcB/J8evJWFWYjIQqXPa7sB 78lv9YaVnzbBwppkgETTNkc5ImZ89pOahlp11YVKRrGHZpqkaFQEYkpT/Y3xchoaplW4 DfAQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=6zgWEN+ZHIXdfQsz4L7D1LWGvy6iPWvpunCXriw/b3w=; b=azatJkeTooIfbYGUHs1QvnNjJfnZbZyDi5AtqzbBScv23/+A6ArOABXVaIuZUdYAkO qOnYggDQmKTwnppkpO7d0ojRSnaNXcmq7wDRnO1CGR78B4Q11KQubypITc/xo0rmXQoM s8b+/azBPfL2t77tLug7kOfG71TyT54w5ki48cxiU8Grw0nvfjCB3uZySLbOao9UbJYo 5oKVQYhNbqz36jDMQJ9Z0mCTUpvbQo/JadlRT5+lRLJ01bqzoqFrLtzMLvxCrcHHDfNw 61kBmq32E9yVX/4cOV2SBqy9ALZ77KlLr7MVR8qlLtxA8NGEZyLgImnykIhpiEkmm1L1 vRwQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id i7si32017216pfi.233.2017.06.05.16.27.17; Mon, 05 Jun 2017 16:27:17 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751500AbdFEX1K (ORCPT + 25 others); Mon, 5 Jun 2017 19:27:10 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:32313 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751345AbdFEXZW (ORCPT ); Mon, 5 Jun 2017 19:25:22 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5e004412; Tue, 6 Jun 2017 08:22:31 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5e004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704952; bh=6zgWEN+ZHIXdfQsz4L7D1LWGvy6iPWvpunCXriw/b3w=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=z9qFYKC6Mcbyl/EKX9p16lSD4ZOCjIW4ZmY6AePawWWfA23oyKNxls/EryL2HgQ7A 785c4iIX60OzvQlvYAkId7Tt+kpElvaOysVJvszPRifPBMVcHwwWD507PwrnmHl6tG T1o03MeXONoNOy85H2ea+/RDakdgnes7kl5S5WKF91XLmdSuEr9WfMYuI9uwL76t0n oDB8ulKNzVrgNSRyxKfaou+dFf6ogJAvdI7FJocxYjBUr+sIL5WnsPhm4ZxwQUcH+m uu+n0YtnV5lbpHmbXht9axKW0NWN6M5GMNiGEPqYW81cS3ZnwH4Ek1e8a4gSlFmMIm nQiI2P9nTmmhQ== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger , Rob Herring , Mark Rutland Subject: [PATCH v4 04/23] mtd: nand: denali: avoid hard-coding ECC step, strength, bytes Date: Tue, 6 Jun 2017 08:21:43 +0900 Message-Id: <1496704922-12261-5-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This driver was originally written for the Intel MRST platform with several platform-specific parameters hard-coded. Currently, the ECC settings are hard-coded as follows: #define ECC_SECTOR_SIZE 512 #define ECC_8BITS 14 #define ECC_15BITS 26 Therefore, the driver can only support two cases. - ecc.size = 512, ecc.strength = 8 --> ecc.bytes = 14 - ecc.size = 512, ecc.strength = 15 --> ecc.bytes = 26 However, these are actually customizable parameters, for example, UniPhier platform supports the following: - ecc.size = 1024, ecc.strength = 8 --> ecc.bytes = 14 - ecc.size = 1024, ecc.strength = 16 --> ecc.bytes = 28 - ecc.size = 1024, ecc.strength = 24 --> ecc.bytes = 42 So, we need to handle the ECC parameters in a more generic manner. Fortunately, the Denali User's Guide explains how to calculate the ecc.bytes. The formula is: ecc.bytes = 2 * CEIL(13 * ecc.strength / 16) (for ecc.size = 512) ecc.bytes = 2 * CEIL(14 * ecc.strength / 16) (for ecc.size = 1024) For DT platforms, it would be reasonable to allow DT to specify ECC strength by either "nand-ecc-strength" or "nand-ecc-maximize". If none of them is specified, the driver will try to meet the chip's ECC requirement. For PCI platforms, the max ECC strength is used to keep the original behavior. Newer versions of this IP need ecc.size and ecc.steps explicitly set up via the following registers: CFG_DATA_BLOCK_SIZE (0x6b0) CFG_LAST_DATA_BLOCK_SIZE (0x6c0) CFG_NUM_DATA_BLOCKS (0x6d0) For older IP versions, write accesses to these registers are just ignored. Signed-off-by: Masahiro Yamada Acked-by: Rob Herring --- Changes in v4: - Rewrite by using generic helpers, nand_check_caps(), nand_match_ecc_req(), nand_maximize_ecc(). Changes in v3: - Move DENALI_CAP_ define out of struct denali_nand_info - Use chip->ecc_step_ds as a hint to choose chip->ecc.size where possible Changes in v2: - Change the capability prefix DENALI_CAPS_ -> DENALI_CAP_ - Make ECC 512 cap and ECC 1024 cap independent - Set up three CFG_... registers .../devicetree/bindings/mtd/denali-nand.txt | 7 ++ drivers/mtd/nand/denali.c | 103 ++++++++++++++------- drivers/mtd/nand/denali.h | 11 ++- drivers/mtd/nand/denali_dt.c | 8 ++ drivers/mtd/nand/denali_pci.c | 9 ++ 5 files changed, 101 insertions(+), 37 deletions(-) -- 2.7.4 diff --git a/Documentation/devicetree/bindings/mtd/denali-nand.txt b/Documentation/devicetree/bindings/mtd/denali-nand.txt index e593bbe..b7742a7 100644 --- a/Documentation/devicetree/bindings/mtd/denali-nand.txt +++ b/Documentation/devicetree/bindings/mtd/denali-nand.txt @@ -7,6 +7,13 @@ Required properties: - reg-names: Should contain the reg names "nand_data" and "denali_reg" - interrupts : The interrupt number. +Optional properties: + - nand-ecc-step-size: see nand.txt for details. If present, the value must be + 512 for "altr,socfpga-denali-nand" + - nand-ecc-strength: see nand.txt for details. Valid values are: + 8, 15 for "altr,socfpga-denali-nand" + - nand-ecc-maximize: see nand.txt for details + The device tree may optionally contain sub-nodes describing partitions of the address space. See partition.txt for more detail. diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 16634df..3204c51 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -886,8 +886,6 @@ static int denali_hw_ecc_fixup(struct mtd_info *mtd, return max_bitflips; } -#define ECC_SECTOR_SIZE 512 - #define ECC_SECTOR(x) (((x) & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12) #define ECC_BYTE(x) (((x) & ECC_ERROR_ADDRESS__OFFSET)) #define ECC_CORRECTION_VALUE(x) ((x) & ERR_CORRECTION_INFO__BYTEMASK) @@ -899,6 +897,7 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd, struct denali_nand_info *denali, unsigned long *uncor_ecc_flags, uint8_t *buf) { + unsigned int ecc_size = denali->nand.ecc.size; unsigned int bitflips = 0; unsigned int max_bitflips = 0; uint32_t err_addr, err_cor_info; @@ -928,9 +927,9 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd, * an erased sector. */ *uncor_ecc_flags |= BIT(err_sector); - } else if (err_byte < ECC_SECTOR_SIZE) { + } else if (err_byte < ecc_size) { /* - * If err_byte is larger than ECC_SECTOR_SIZE, means error + * If err_byte is larger than ecc_size, means error * happened in OOB, so we ignore it. It's no need for * us to correct it err_device is represented the NAND * error bits are happened in if there are more than @@ -939,7 +938,7 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd, int offset; unsigned int flips_in_byte; - offset = (err_sector * ECC_SECTOR_SIZE + err_byte) * + offset = (err_sector * ecc_size + err_byte) * denali->devnum + err_device; /* correct the ECC error */ @@ -1345,13 +1344,55 @@ static void denali_hw_init(struct denali_nand_info *denali) denali_irq_init(denali); } -/* - * Althogh controller spec said SLC ECC is forceb to be 4bit, - * but denali controller in MRST only support 15bit and 8bit ECC - * correction - */ -#define ECC_8BITS 14 -#define ECC_15BITS 26 +static int denali_calc_ecc_bytes(int step_size, int strength) +{ + int coef; + + switch (step_size) { + case 512: + coef = 13; + break; + case 1024: + coef = 14; + break; + default: + return -ENOTSUPP; + } + + return DIV_ROUND_UP(strength * coef, 16) * 2; +} + +static int denali_ecc_setup(struct mtd_info *mtd, struct nand_chip *chip, + struct denali_nand_info *denali) +{ + struct nand_ecc_caps caps; + int ret; + + caps.stepinfos = denali->stepinfo; + caps.nstepinfos = 1; + caps.calc_ecc_bytes = denali_calc_ecc_bytes; + caps.oob_reserve_bytes = denali->bbtskipbytes; + + /* + * 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(mtd, chip, &caps); + + /* + * 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(mtd, chip, &caps); + if (!ret) + return 0; + } + + /* Max ECC strength is the last thing we can do */ + return nand_maximize_ecc(mtd, chip, &caps); +} static int denali_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) @@ -1586,34 +1627,26 @@ int denali_init(struct denali_nand_info *denali) /* no subpage writes on denali */ chip->options |= NAND_NO_SUBPAGE_WRITE; - /* - * Denali Controller only support 15bit and 8bit ECC in MRST, - * so just let controller do 15bit ECC for MLC and 8bit ECC for - * SLC if possible. - * */ - if (!nand_is_slc(chip) && - (mtd->oobsize > (denali->bbtskipbytes + - ECC_15BITS * (mtd->writesize / - ECC_SECTOR_SIZE)))) { - /* if MLC OOB size is large enough, use 15bit ECC*/ - chip->ecc.strength = 15; - chip->ecc.bytes = ECC_15BITS; - iowrite32(15, denali->flash_reg + ECC_CORRECTION); - } else if (mtd->oobsize < (denali->bbtskipbytes + - ECC_8BITS * (mtd->writesize / - ECC_SECTOR_SIZE))) { - pr_err("Your NAND chip OOB is not large enough to contain 8bit ECC correction codes"); + ret = denali_ecc_setup(mtd, chip, denali); + if (ret) { + dev_err(denali->dev, "Failed to setup ECC settings.\n"); goto failed_req_irq; - } else { - chip->ecc.strength = 8; - chip->ecc.bytes = ECC_8BITS; - iowrite32(8, denali->flash_reg + ECC_CORRECTION); } + dev_dbg(denali->dev, + "chosen ECC settings: step=%d, strength=%d, bytes=%d\n", + chip->ecc.size, chip->ecc.strength, chip->ecc.bytes); + + iowrite32(chip->ecc.strength, denali->flash_reg + ECC_CORRECTION); + + iowrite32(chip->ecc.size, denali->flash_reg + CFG_DATA_BLOCK_SIZE); + iowrite32(chip->ecc.size, denali->flash_reg + CFG_LAST_DATA_BLOCK_SIZE); + /* chip->ecc.steps is set by nand_scan_tail(); not available here */ + iowrite32(mtd->writesize / chip->ecc.size, + denali->flash_reg + CFG_NUM_DATA_BLOCKS); + mtd_set_ooblayout(mtd, &denali_ooblayout_ops); - /* override the default read operations */ - chip->ecc.size = ECC_SECTOR_SIZE; chip->ecc.read_page = denali_read_page; chip->ecc.read_page_raw = denali_read_page_raw; chip->ecc.write_page = denali_write_page; diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 3783353..5f08691 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -259,6 +259,14 @@ #define ECC_COR_INFO__MAX_ERRORS GENMASK(6, 0) #define ECC_COR_INFO__UNCOR_ERR BIT(7) +#define CFG_DATA_BLOCK_SIZE 0x6b0 + +#define CFG_LAST_DATA_BLOCK_SIZE 0x6c0 + +#define CFG_NUM_DATA_BLOCKS 0x6d0 + +#define CFG_META_DATA_SIZE 0x6e0 + #define DMA_ENABLE 0x700 #define DMA_ENABLE__FLAG BIT(0) @@ -301,8 +309,6 @@ #define MODE_10 0x08000000 #define MODE_11 0x0C000000 -#define ECC_SECTOR_SIZE 512 - struct nand_buf { int head; int tail; @@ -337,6 +343,7 @@ struct denali_nand_info { int max_banks; unsigned int revision; unsigned int caps; + const struct nand_ecc_step_info *stepinfo; }; #define DENALI_CAP_HW_ECC_FIXUP BIT(0) diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index b48430f..8c09bbe 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -32,10 +32,17 @@ struct denali_dt { struct denali_dt_data { unsigned int revision; unsigned int caps; + struct nand_ecc_step_info stepinfo; }; +static const int denali_socfpga_strengths[] = {8, 15}; static const struct denali_dt_data denali_socfpga_data = { .caps = DENALI_CAP_HW_ECC_FIXUP, + .stepinfo = { + .stepsize = 512, + .strengths = denali_socfpga_strengths, + .nstrengths = ARRAY_SIZE(denali_socfpga_strengths), + }, }; static const struct of_device_id denali_nand_dt_ids[] = { @@ -64,6 +71,7 @@ static int denali_dt_probe(struct platform_device *pdev) if (data) { denali->revision = data->revision; denali->caps = data->caps; + denali->stepinfo = &data->stepinfo; } denali->platform = DT; diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c index ac84323..e0d50b6 100644 --- a/drivers/mtd/nand/denali_pci.c +++ b/drivers/mtd/nand/denali_pci.c @@ -27,6 +27,13 @@ static const struct pci_device_id denali_pci_ids[] = { }; MODULE_DEVICE_TABLE(pci, denali_pci_ids); +static const int denali_pci_strengths[] = {8, 15}; +static const struct nand_ecc_step_info denali_pci_stepinfo = { + .stepsize = 512, + .strengths = denali_pci_strengths, + .nstrengths = ARRAY_SIZE(denali_pci_strengths), +}; + static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { int ret; @@ -65,6 +72,8 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) pci_set_master(dev); denali->dev = &dev->dev; denali->irq = dev->irq; + denali->stepinfo = &denali_pci_stepinfo; + denali->nand.ecc.options |= NAND_ECC_MAXIMIZE; ret = pci_request_regions(dev, DENALI_NAND_NAME); if (ret) { From patchwork Mon Jun 5 23:21:44 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103117 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1009586obh; Mon, 5 Jun 2017 16:29:31 -0700 (PDT) X-Received: by 10.84.238.137 with SMTP id v9mr11585863plk.154.1496705371272; Mon, 05 Jun 2017 16:29:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705371; cv=none; d=google.com; s=arc-20160816; b=EwKCsUTg85JCSDl6Eh7Z13gwbnJgoO7Ug4dfJKi6kJgCIseL1ki5+VWvg2snOsoSAI nNOD6nFRQZkhyfxYixERTozZtEAJkhEemR7RIGzCtmmfJdWag85HjgCDasxqKNFlf0P1 jMYPYcHcUukLxbdAYvO298/UAx0hHDsKqzdJhygeh61+b9jqZCa61YwdPQuHNdsDm283 R3FAT9j+ylGP+iLWxtO+oPzZOVRAkviPYJgl+9zQ+47H/0VpNFULik0D3q85imsyj4KQ Q63HqpUp1aUvZpFsgTA+RpneA7ukmS9oT7ry+MnnD3/XHF03mwWg98mBo/mcz3IW082x aPEQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=OKXdUUeiuqhfGZ5u+LL+R2zGxIGklUpMmz/CpChup5U=; b=HqFt64lOT+UL1P4x2J/Mhf9oGukcvdsuLOOCjihJRD1gA2cP5e3OB7dVyZAoLByH9L GvPGUn7rc6Z6eZs6sZLpOJpBGJLAxVw/VKCInaY6qLM1OynMHypPcUy9sbDy0MZq2ayz eNt5Ii2TE9QCqIbVZGsZ2tSPQEapkj644m5FA8SjR1q/QDq5cFaeyN9QKqeVl3hUnORl 9Zs2uAH94Z7yowPRtHUHRMFIYaR6hYl1wzPCZsH7m47g/QHPThvD0f6AxvQmeJuQqj0g dYg4825+Afd9n7y9sLAofOtf17qskaZ/EnhLrisXR7WAVxfyfNnMVznUBfFtpCSwtsZr yD2w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id s4si2756254pfi.251.2017.06.05.16.29.30; Mon, 05 Jun 2017 16:29:31 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751470AbdFEX3R (ORCPT + 25 others); Mon, 5 Jun 2017 19:29:17 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:32143 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751289AbdFEXZR (ORCPT ); Mon, 5 Jun 2017 19:25:17 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5f004412; Tue, 6 Jun 2017 08:22:33 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5f004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704954; bh=OKXdUUeiuqhfGZ5u+LL+R2zGxIGklUpMmz/CpChup5U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=iLckzanfegJJk87oUbkiGMu6ek8Pe3G/pnj7ePFzcD3v1jHkVJJfxO9SNOvt6TmZE kTQNAuyEDLLNdeH4IqPePuq+c3gDKoj+gJcMCEzNCUGctadobJEyavtXH8W6zpsRPO KGjkyvjKB4I4iwJbICWMERyQODXKtMZnBrXDXW6zriIqSTArSZYZG7VduRxUv57iiG vEbeg37gePuO2v7HWkCZs+KjOZ2Y4nf++hqL+HtesOQGhd9XHP1ETY+AXmLWwgwJsw bQVCnYY8S/zkd5t0KzXpb5nn+6qffO7wSMFLy3qjLk4yCrI0yDHJRGQhdmqyd01qu1 g+oP7jvtlJw6A== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v4 05/23] mtd: nand: denali: remove Toshiba and Hynix specific fixup code Date: Tue, 6 Jun 2017 08:21:44 +0900 Message-Id: <1496704922-12261-6-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The Denali IP can automatically detect device parameters such as page size, oob size, device width, etc. and this driver currently relies on it. However, this hardware function is known to be problematic. [1] Due to a hardware bug, various misdetected cases were reported. That is why get_toshiba_nand_para() and get_hynix_nand_para() exist to fix-up the misdetected parameters. It is not realistic to add a new NAND device to the *black list* every time we are hit by a misdetected case. We would never be able to guarantee that all cases are covered. [2] Because this feature is unreliable, it is disabled on some platforms. The nand_scan_ident() detects device parameters in a more tested way. The hardware should not set the device parameter registers in a different, unreliable way. Instead, set the parameters from the nand_scan_ident() back to the registers. Signed-off-by: Masahiro Yamada --- Changes in v4: None Changes in v3: None Changes in v2: None drivers/mtd/nand/denali.c | 40 ++++++---------------------------------- 1 file changed, 6 insertions(+), 34 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 3204c51..422b6e4 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -337,36 +337,6 @@ static void get_samsung_nand_para(struct denali_nand_info *denali, } } -static void get_toshiba_nand_para(struct denali_nand_info *denali) -{ - /* - * Workaround to fix a controller bug which reports a wrong - * spare area size for some kind of Toshiba NAND device - */ - if ((ioread32(denali->flash_reg + DEVICE_MAIN_AREA_SIZE) == 4096) && - (ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64)) - iowrite32(216, denali->flash_reg + DEVICE_SPARE_AREA_SIZE); -} - -static void get_hynix_nand_para(struct denali_nand_info *denali, - uint8_t device_id) -{ - switch (device_id) { - case 0xD5: /* Hynix H27UAG8T2A, H27UBG8U5A or H27UCG8VFA */ - case 0xD7: /* Hynix H27UDG8VEM, H27UCG8UDM or H27UCG8V5A */ - iowrite32(128, denali->flash_reg + PAGES_PER_BLOCK); - iowrite32(4096, denali->flash_reg + DEVICE_MAIN_AREA_SIZE); - iowrite32(224, denali->flash_reg + DEVICE_SPARE_AREA_SIZE); - iowrite32(0, denali->flash_reg + DEVICE_WIDTH); - break; - default: - dev_warn(denali->dev, - "Unknown Hynix NAND (Device ID: 0x%x).\n" - "Will use default parameter values instead.\n", - device_id); - } -} - /* * determines how many NAND chips are connected to the controller. Note for * Intel CE4100 devices we don't support more than one device. @@ -453,10 +423,6 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) return FAIL; } else if (maf_id == 0xEC) { /* Samsung NAND */ get_samsung_nand_para(denali, device_id); - } else if (maf_id == 0x98) { /* Toshiba NAND */ - get_toshiba_nand_para(denali); - } else if (maf_id == 0xAD) { /* Hynix NAND */ - get_hynix_nand_para(denali, device_id); } dev_info(denali->dev, @@ -1638,6 +1604,12 @@ int denali_init(struct denali_nand_info *denali) chip->ecc.size, chip->ecc.strength, chip->ecc.bytes); iowrite32(chip->ecc.strength, denali->flash_reg + ECC_CORRECTION); + iowrite32(mtd->erasesize / mtd->writesize, + denali->flash_reg + PAGES_PER_BLOCK); + iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0, + denali->flash_reg + DEVICE_WIDTH); + iowrite32(mtd->writesize, denali->flash_reg + DEVICE_MAIN_AREA_SIZE); + iowrite32(mtd->oobsize, denali->flash_reg + DEVICE_SPARE_AREA_SIZE); iowrite32(chip->ecc.size, denali->flash_reg + CFG_DATA_BLOCK_SIZE); iowrite32(chip->ecc.size, denali->flash_reg + CFG_LAST_DATA_BLOCK_SIZE); From patchwork Mon Jun 5 23:21:46 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103119 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1009676obh; Mon, 5 Jun 2017 16:29:45 -0700 (PDT) X-Received: by 10.99.167.15 with SMTP id d15mr2831674pgf.42.1496705385773; Mon, 05 Jun 2017 16:29:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705385; cv=none; d=google.com; s=arc-20160816; b=nDD3hOze+uNtIuvz6j9QCzw9bbZB7m/vB0OfGy+3cJjfmYL+/2/Lp9SJmknAo7CsP7 zFl+w36zW2lUlAqPLjuDloK9qWgXkwSN3YaL9csE/ukekbRLwo87y8yc49WwhDJ9gkUJ IDbqYvnlcPPS71cB+zaVq7v/nqXuhXoidR6YgRkBXDUxfDNCZUIC1RmEer0O6/DW8rU+ Av91vA2YWHeu1hDkKsLAVaMg5XxZw3/uVplpExIu62f6a7wt62E18HWUjpmETGBMHTOL TOl2XAy3k8z1GPTB/NT3sT/Gi1PyW4CgyC4Zg9KuUE3CteeL/IIegeOgarsUn1XFybFy RrJw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=hSP1u0Mt7s97GkydJVKzQAERrnfuZ9G+S898KAg/yW0=; b=kRjsJqXvaN8DTdEYLnJGxM46xyMthv+YAf0BrzsQNkoM0Ql/cHQMfYdDV5w/EeIsns oMzT+u9lqYQdXpxS9p8DYb35C5rQzn383NhQfWyIuOt0AwVgkKQ6cqAAOUWOyqho1VUg +G6cYjtuFNnthYxXcZCtXuygP2+VgBZQrO/sfZbF2ZOhKEdtQAsgi0K4Tn7eh1ltSlqI MwqiB2rSVuosr6W/fcd2e9x48o+pAou4i2z0AI/6McVYgW2tCIfbjxhaoSzsXFgPiBI9 0k9pi+5ftrSsq7/yxNYdvElRfDAVfmrs6WWLrwyf1nv1w8cFDU7Yv6mYAEgxOwGPQms2 k5+A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id s4si2756254pfi.251.2017.06.05.16.29.45; Mon, 05 Jun 2017 16:29:45 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751355AbdFEX3Q (ORCPT + 25 others); Mon, 5 Jun 2017 19:29:16 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:32148 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751290AbdFEXZR (ORCPT ); Mon, 5 Jun 2017 19:25:17 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5h004412; Tue, 6 Jun 2017 08:22:35 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5h004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704956; bh=hSP1u0Mt7s97GkydJVKzQAERrnfuZ9G+S898KAg/yW0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=xI0N3SvTsKX8qui5Z9J+z5t7BiMQGGSPKZjDPecbbtv1AoFow+tU8vS9zI/xe23x1 hCEmgovC6sOhGdspwSvDjHNd3pv/qI/814msy7BAp8xG6+lVrWl7lHsDbdYFla1unz z9dKmkk89BIjiz8KZSn47SQ7AX91jSlKlPU8q7WXTIr02Yc0YKeULWHmxmc3znov7z 1dzi5k5tH+QvmbbEUEe/TkOmVD90lM/nGFR8SmBEq3kzxdVDtIAw7yjEu2guliGdXh gzXCemvs1PVYlqYnh7f4XvcWPY/rPqLjhqe0VeMv1mRTwD87gTkDTvZY5fcuND99v0 HdEXwm5j8C0og== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v4 07/23] mtd: nand: denali: set NAND_ECC_CUSTOM_PAGE_ACCESS Date: Tue, 6 Jun 2017 08:21:46 +0900 Message-Id: <1496704922-12261-8-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The denali_cmdfunc() actually does nothing valuable for NAND_CMD_{PAGEPROG,READ0,SEQIN}. For NAND_CMD_{READ0,SEQIN}, it copies "page" to "denali->page", then denali_read_page() and denali_read_page_raw() compare them to check if the NAND framework called the callbacks in correct order. (Inconsistently, this check is missing from the denali_write_page() and denali_write_page_raw().) The framework is widely tested by many drivers, so this kind of sanity check is unneeded. The Denali controller is equipped with high level interface for read/write, so let's skip unneeded call of cmdfunc(). Signed-off-by: Masahiro Yamada --- Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 422b6e4..3655284 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -998,7 +998,7 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op) * configuration details. */ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, bool raw_xfer) + const uint8_t *buf, int page, bool raw_xfer) { struct denali_nand_info *denali = mtd_to_denali(mtd); dma_addr_t addr = denali->buf.dma_buf; @@ -1006,6 +1006,8 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, uint32_t irq_status; uint32_t irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL; + denali->page = page; + /* * if it is a raw xfer, we want to disable ecc and send the spare area. * !raw_xfer - enable ecc @@ -1059,7 +1061,7 @@ static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, * for regular page writes, we let HW handle all the ECC * data written to the device. */ - return write_page(mtd, chip, buf, false); + return write_page(mtd, chip, buf, page, false); } /* @@ -1075,7 +1077,7 @@ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, * for raw page writes, we want to disable ECC and simply write * whatever data is in the buffer. */ - return write_page(mtd, chip, buf, true); + return write_page(mtd, chip, buf, page, true); } static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip, @@ -1105,12 +1107,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, unsigned long uncor_ecc_flags = 0; int stat = 0; - if (page != denali->page) { - dev_err(denali->dev, - "IN %s: page %d is not equal to denali->page %d", - __func__, page, denali->page); - BUG(); - } + denali->page = page; setup_ecc_for_xfer(denali, true, false); @@ -1154,12 +1151,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, size_t size = mtd->writesize + mtd->oobsize; uint32_t irq_mask = INTR__DMA_CMD_COMP; - if (page != denali->page) { - dev_err(denali->dev, - "IN %s: page %d is not equal to denali->page %d", - __func__, page, denali->page); - BUG(); - } + denali->page = page; setup_ecc_for_xfer(denali, false, true); denali_enable_dma(denali, true); @@ -1238,8 +1230,6 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, int i; switch (cmd) { - case NAND_CMD_PAGEPROG: - break; case NAND_CMD_STATUS: read_status(denali); break; @@ -1259,10 +1249,6 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, write_byte_to_buf(denali, id); } break; - case NAND_CMD_READ0: - case NAND_CMD_SEQIN: - denali->page = page; - break; case NAND_CMD_RESET: reset_bank(denali); break; @@ -1619,6 +1605,7 @@ int denali_init(struct denali_nand_info *denali) mtd_set_ooblayout(mtd, &denali_ooblayout_ops); + chip->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS; chip->ecc.read_page = denali_read_page; chip->ecc.read_page_raw = denali_read_page_raw; chip->ecc.write_page = denali_write_page; From patchwork Mon Jun 5 23:21:47 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103112 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1009156obh; Mon, 5 Jun 2017 16:28:01 -0700 (PDT) X-Received: by 10.98.57.78 with SMTP id g75mr12659663pfa.9.1496705281459; Mon, 05 Jun 2017 16:28:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705281; cv=none; d=google.com; s=arc-20160816; b=JS+byhfcGHGJUivF1tscB5s+PjipN0yUdF3CeLlM9MaXhj3UqTRi496r1/KMCVNCie Djpw1C0A/vxPFGitOXzmJsmBaiLe27iqqfVdBPOMQfB3L9aXVoWCdAUVQWzAbaJzebmG E5+DSgncEwiOgV+ZPNBJ/bsaAkN5HzZ38Rg+bDBLg8U6RDbAu8nHlkQIcST6FJ4zSPGu z6OlU5vmiGzdwddF+lZSMCog8FCkX0Ax72m5lWnMxQHEnjL+xWYQCStqbnstjFDNo5Km HKkieX2z+T8+oEzPkLb7ac85li+mMTEBIFcHZLh0HXZdX7h2+TMuRz3I6Sr6T11ilReQ fEcw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=lO3TPqzkN5H0BMAkw+GIFN611bf2lQu/4gkON1i0E5Y=; b=hIWMGjmFEDv2ggIk45iSksbrlomHK2KVrM0HVaQdd4vrQ7LYnRZlL3iEAEJk67wpsT V7Os0REGQ4drcKfYhxiHZy3KWIobWwR50r+apTW0Xqrj9Re++xso4FBhG9FGFAeRhulv 1bbuKHxu0ux8fLbChV81rquhvs3IxV2UTR87hX6i4KA6x09SHp4S0vxn9pespY+7rH0n ktF6M1wr/lkwl6qp0l7fR8QUWL9ulqYY5BwVwnGYqZDMKAIDCTabi+nOGOMFkS5qFUzh PrJ53ErsffaeWPyoev1iHs/Y/mUWkbHAvMwZvHKOmNo79k959x296ZVcxr/2fv+FGjpJ etVA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id b11si2641077pgr.410.2017.06.05.16.28.01; Mon, 05 Jun 2017 16:28:01 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751321AbdFEXZT (ORCPT + 25 others); Mon, 5 Jun 2017 19:25:19 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:32110 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751216AbdFEXZQ (ORCPT ); Mon, 5 Jun 2017 19:25:16 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5i004412; Tue, 6 Jun 2017 08:22:36 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5i004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704957; bh=lO3TPqzkN5H0BMAkw+GIFN611bf2lQu/4gkON1i0E5Y=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dX+xStOPCWuUg2lK3MTJh3g2dB2TQYICvM972UgdUA0SVVmq9JIvx93NhRkIgCWi3 W4YKSrPhHRsufKpwhHfFVmlVIMBEeFGQmRQR6dxBqpQ4DqS6w6gz4gU+M9/+W9juCa TSw3Ebgh/UeUvwY1E2ukWYgQ40E7PuX4zCi7Q5yxZth+FfhKOGOL0QUNXsVpIOw2KS OxMmx7P89md0hVyu2XzxUSERBJvLmWfkfPgxI+6fqb3NebNsZM7xN52huEDAEJOhhm tJGeEWSfCyIXiK2HxXze+T52DnGi+8FvBBaRQ/w/6RO2TxuMpO6fNWiMmkZESPQPVA jrus3JNeW9jrw== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v4 08/23] mtd: nand: denali: do not propagate NAND_STATUS_FAIL to waitfunc() Date: Tue, 6 Jun 2017 08:21:47 +0900 Message-Id: <1496704922-12261-9-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Currently, the error handling of denali_write_page(_raw) is a bit complicated. If the program command fails, NAND_STATUS_FAIL is set to the driver internal denali->status, then read out later by denali_waitfunc(). We can avoid it by exploiting the nand_write_page() implementation. If chip->ecc.write_page(_raw) returns negative code (i.e. -EIO), it errors out immediately. This gives the same result as returning NAND_STATUS_FAIL from chip->waitfunc. In either way, -EIO is returned to the upper MTD layer. Signed-off-by: Masahiro Yamada --- Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 12 ++++-------- drivers/mtd/nand/denali.h | 1 - 2 files changed, 4 insertions(+), 9 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 3655284..4017262 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1005,6 +1005,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, size_t size = mtd->writesize + mtd->oobsize; uint32_t irq_status; uint32_t irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL; + int ret = 0; denali->page = page; @@ -1038,13 +1039,13 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, if (irq_status == 0) { dev_err(denali->dev, "timeout on write_page (type = %d)\n", raw_xfer); - denali->status = NAND_STATUS_FAIL; + ret = -EIO; } denali_enable_dma(denali, false); dma_sync_single_for_cpu(denali->dev, addr, size, DMA_TO_DEVICE); - return 0; + return ret; } /* NAND core entry points */ @@ -1196,12 +1197,7 @@ static void denali_select_chip(struct mtd_info *mtd, int chip) static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) { - struct denali_nand_info *denali = mtd_to_denali(mtd); - int status = denali->status; - - denali->status = 0; - - return status; + return 0; } static int denali_erase(struct mtd_info *mtd, int page) diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 5f08691..0e9297d 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -323,7 +323,6 @@ struct nand_buf { struct denali_nand_info { struct nand_chip nand; int flash_bank; /* currently selected chip */ - int status; int platform; struct nand_buf buf; struct device *dev; From patchwork Mon Jun 5 23:21:48 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103113 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1009159obh; Mon, 5 Jun 2017 16:28:01 -0700 (PDT) X-Received: by 10.99.174.77 with SMTP id e13mr23584652pgp.145.1496705281835; Mon, 05 Jun 2017 16:28:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705281; cv=none; d=google.com; s=arc-20160816; b=ZSPChDvkuDIY3XkQlzwFLKdJKqGL/F1CHLIXST+gEF94Tf73zfWh74KWJ6TMPJGF+f WkDRuI5eWV3qJABpoBsw9ZAucaksEFos7CcnvCn2jr5TR+0RNxTHXvLr8vU8TwMYw3lr Z2r97J1F6pA5wzQShnInUHD7X1OWSPCHeFjC+bA15ko9Yxf+5dy2EWtpbzq0Ky8WOPhg sy0rJPtuTqutROLT6A9+Dpd72U29g4we6WrkD5p1aWa8q5v5yygULM7MdUUnvZOyz1Bf H+Uie6sVTC2pxQzm/uVYii0YsKlhmwtApv26iAqRTVPsbBQwGTdD+G0oFHdIjAQ41aHt xI2g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=yCUlg6Ob4EhYIvjzRqgNlUoFDqU6iOh/2f8twq+jTr8=; b=u7qpSI8IphIxYhDXM2Egq3CJCN/2UTZ4nsdrXzNxqksJJSJCCSBy293A9/yPGfkjUo NR8zk5mQnqQKDEHu55olBxAYy/hVg4gPyXDM3SbWi+wYoJOcEymvnfhtP86pdEGJxH/E 82eWQdfVxlRsxopoQAXT7BP0ksdAnrZDNKgqwLI5gaF8LZsumbCHAIrWiVBkWc6DN6Zp LjqB0xdrt3NSTk2PxhGkFKCFDR3NEt3M7yEIUdIaGe9yOYjJ+gstQH2+ipEWwAFNapfQ ZabocJtDjtKibG71NzNp8ox83iu+r89z9egeX4oJp/pTRSpGHOgMOkhqwTdweai9aEuE +Kwg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id b11si2641077pgr.410.2017.06.05.16.28.01; Mon, 05 Jun 2017 16:28:01 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751456AbdFEX1u (ORCPT + 25 others); Mon, 5 Jun 2017 19:27:50 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:32212 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751313AbdFEXZT (ORCPT ); Mon, 5 Jun 2017 19:25:19 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5j004412; Tue, 6 Jun 2017 08:22:38 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5j004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704959; bh=yCUlg6Ob4EhYIvjzRqgNlUoFDqU6iOh/2f8twq+jTr8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ULITL8I2xT9gYAMBxoi7u+J+STmxbHWKgjw4e5ddam1BK0bNFr7oaAB942PYVjdpA Y4+1TKOajDzddsojWJbQOCP88PkTSgpLRuJSrFtgm8kYbTRzQTDWkRc1a9+i44qFem Z2eajIcCgowizbrBeLYtyUIjNJbDnA8pKPudvGldaULRCKa1gDEa7FYclCAfF7UGZh i8OzfZo8cHgQJ4k6IbOkcSCN/Gg2z9cb21NiqgkhTaHhxMh3NA1L3mjZ9y9OIVVRdY epwdL4dqEByPmXC5UB0q8ODEofB7iaFMCeCcnvPwQLUjrORooq7hzat3yDxkZKgPB/ Pq2pzBs5WoEaQ== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v4 09/23] mtd: nand: denali: remove unneeded find_valid_banks() Date: Tue, 6 Jun 2017 08:21:48 +0900 Message-Id: <1496704922-12261-10-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The function find_valid_banks() issues the Read ID (0x90) command, then compares the first byte (Manufacturer ID) of each bank with the one of bank0. This is equivalent to what nand_scan_ident() does. The number of chips is detected there, so this is unneeded. What is worse for find_valid_banks() is that, if multiple chips are connected to INTEL_CE4100 platform, it crashes the kernel by BUG(). This is what we should avoid. This function is just harmful and unneeded. Signed-off-by: Masahiro Yamada --- Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 47 ----------------------------------------------- drivers/mtd/nand/denali.h | 1 - 2 files changed, 48 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 4017262..a289011 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -338,51 +338,6 @@ static void get_samsung_nand_para(struct denali_nand_info *denali, } /* - * determines how many NAND chips are connected to the controller. Note for - * Intel CE4100 devices we don't support more than one device. - */ -static void find_valid_banks(struct denali_nand_info *denali) -{ - uint32_t id[denali->max_banks]; - int i; - - denali->total_used_banks = 1; - for (i = 0; i < denali->max_banks; i++) { - index_addr(denali, MODE_11 | (i << 24) | 0, 0x90); - index_addr(denali, MODE_11 | (i << 24) | 1, 0); - index_addr_read_data(denali, MODE_11 | (i << 24) | 2, &id[i]); - - dev_dbg(denali->dev, - "Return 1st ID for bank[%d]: %x\n", i, id[i]); - - if (i == 0) { - if (!(id[i] & 0x0ff)) - break; /* WTF? */ - } else { - if ((id[i] & 0x0ff) == (id[0] & 0x0ff)) - denali->total_used_banks++; - else - break; - } - } - - if (denali->platform == INTEL_CE4100) { - /* - * Platform limitations of the CE4100 device limit - * users to a single chip solution for NAND. - * Multichip support is not enabled. - */ - if (denali->total_used_banks != 1) { - dev_err(denali->dev, - "Sorry, Intel CE4100 only supports a single NAND device.\n"); - BUG(); - } - } - dev_dbg(denali->dev, - "denali->total_used_banks: %d\n", denali->total_used_banks); -} - -/* * Use the configuration feature register to determine the maximum number of * banks that the hardware supports. */ @@ -439,8 +394,6 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) ioread32(denali->flash_reg + RDWR_EN_HI_CNT), ioread32(denali->flash_reg + CS_SETUP_CNT)); - find_valid_banks(denali); - /* * If the user specified to override the default timings * with a specific ONFI mode, we apply those changes here. diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 0e9297d..80767cf 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -326,7 +326,6 @@ struct denali_nand_info { int platform; struct nand_buf buf; struct device *dev; - int total_used_banks; int page; void __iomem *flash_reg; /* Register Interface */ void __iomem *flash_mem; /* Host Data/Command Interface */ From patchwork Mon Jun 5 23:21:49 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103115 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1009455obh; Mon, 5 Jun 2017 16:29:04 -0700 (PDT) X-Received: by 10.84.217.11 with SMTP id o11mr17854289pli.299.1496705344354; Mon, 05 Jun 2017 16:29:04 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705344; cv=none; d=google.com; s=arc-20160816; b=Oj/yKVvX1WeVCdrAA+cAQnELf7qgja6TMYMWI9WgFKtOekKFqXhFGvVqu4R2fZqtYB GjM4NjKj0eOo7Sob3iN+vUQ/ZVanCLjHuyYBvOqevlHd6f5aSwmcjLwyiUmO7efXK3Gt hpUgFjTlPXoJX0o61HdBm8inqRa8AoD3/DjoADKh1x8yYpJ7nolNw/x1ljf09cbcVTLB k833SXy5gKDh2xrJg4NCUhxDmQxnO5LzVBLNsvzqFMGQvcC0rYg3EmoogpOsSa+PR5gT xttoDSv5VS5rcqL7uJmJObbvXrj41Ki7Lb2VlLOrFZhRMzRP9am91SDN2lOkK+FTst76 859Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=Yv2ttUKu/e5roGaKNaZ0vIp08ZxY9w4jhuSnNzS5/WQ=; b=N8mhUy4XAElVEM2vcxzv5gYi7dNWYr4WU4taA3/CJ2HgoufVK3dKu62E0S4iGhMxUL jLQmSt7jWXFGvoURUiorpdzO/RRJKdWa5WS1wv9EEuLwuzmle7WyiWy9DwmjCsM3W6w4 DQopTbJCUgB3g7lFisQTPdQxQ3idLC/aWSwtJ6b8Qk3TY6wJgQn5Y34JCFgJwJ8+XTes uk7qkqd4TD6HUu55neopkRQ/EToJwrl049RR4mXpG/MRtewFN2tfDtFT+E72NIuWDPl8 5g3oH9YQW9p/0RZdruXZAIZjQvMOYWurEtJahW9OpfTntbsYntZ3zYaUdYtsI49wx+Oa tYXQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id b1si8302122pll.359.2017.06.05.16.29.04; Mon, 05 Jun 2017 16:29:04 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751511AbdFEX2I (ORCPT + 25 others); Mon, 5 Jun 2017 19:28:08 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:32182 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751294AbdFEXZS (ORCPT ); Mon, 5 Jun 2017 19:25:18 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5k004412; Tue, 6 Jun 2017 08:22:39 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5k004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704960; bh=Yv2ttUKu/e5roGaKNaZ0vIp08ZxY9w4jhuSnNzS5/WQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Zndek0uo9rwJRFgMw6u7LDuvFRDvUydAkpbOXe0x8mD2d/KSF12Z4BjrpQXfJYtx1 w4bE5kLt+pv9B1Y8YPa59xTLkpaylwGMDz57NuwXAvb9VdBoIp4kvFUgk+18247wRA l7DsBahTdwN1tlMeAitnNnkmR+GRlmRpFzNZLtkCnzLJ9bIc2iGnwLLK4N0s73lCjo JJkTJp652Si1wRthROqVLXsnQ/p2ALWiCvAb9rdw80RjfxTmI60cR3yGJrLoxQ3XRG oKTQH3NMTrOSrGUy/pFt6S1NFWCEKJalYxEPIhQwIsZjf2ZwJaWhZFVhZ6Syl1QCKJ 94F4UWaEUliCg== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v4 10/23] mtd: nand: denali: handle timing parameters by setup_data_interface() Date: Tue, 6 Jun 2017 08:21:49 +0900 Message-Id: <1496704922-12261-11-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Handling timing parameters in a driver's own way should be avoided because it duplicates efforts of drivers/mtd/nand/nand_timings.c Besides, this driver hard-codes Intel specific parameters such as CLK_X=5, CLK_MULTI=4. Taking a certain device (Samsung K9WAG08U1A) into account by get_samsung_nand_para() is weird as well. Now, the core framework provides .setup_data_interface() hook, which handles timing parameters in a generic manner. While I am working on this, I found even more issues in the current code, so fixed the following as well: - In recent IP versions, WE_2_RE and TWHR2 share the same register. Likewise for ADDR_2_DATA and TCWAW, CS_SETUP_CNT and TWB. When updating one, the other must be masked. Otherwise, the other will be set to 0, then timing settings will be broken. - The recent IP release expanded the ADDR_2_DATA to 7-bit wide. This register is related to tADL. As commit 74a332e78e8f ("mtd: nand: timings: Fix tADL_min for ONFI 4.0 chips") addressed, the ONFi 4.0 increased the minimum of tADL to 400 nsec. This may not fit in the 6-bit ADDR_2_DATA in older versions. Check the IP revision and handle this correctly, otherwise the register value would wrap around. Signed-off-by: Masahiro Yamada --- Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 351 +++++++++++++++--------------------------- drivers/mtd/nand/denali.h | 26 ++-- drivers/mtd/nand/denali_dt.c | 3 +- drivers/mtd/nand/denali_pci.c | 6 +- 4 files changed, 142 insertions(+), 244 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index a289011..1bb57de 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -28,17 +28,6 @@ MODULE_LICENSE("GPL"); -/* - * We define a module parameter that allows the user to override - * the hardware and decide what timing mode should be used. - */ -#define NAND_DEFAULT_TIMINGS -1 - -static int onfi_timing_mode = NAND_DEFAULT_TIMINGS; -module_param(onfi_timing_mode, int, S_IRUGO); -MODULE_PARM_DESC(onfi_timing_mode, - "Overrides default ONFI setting. -1 indicates use default timings"); - #define DENALI_NAND_NAME "denali-nand" /* @@ -63,12 +52,6 @@ MODULE_PARM_DESC(onfi_timing_mode, #define CHIP_SELECT_INVALID -1 /* - * This macro divides two integers and rounds fractional values up - * to the nearest integer value. - */ -#define CEIL_DIV(X, Y) (((X)%(Y)) ? ((X)/(Y)+1) : ((X)/(Y))) - -/* * this macro allows us to convert from an MTD structure to our own * device context (denali) structure. */ @@ -103,6 +86,14 @@ static void denali_irq_enable(struct denali_nand_info *denali, static uint32_t read_interrupt_status(struct denali_nand_info *denali); /* + * The bus interface clock, clk_x, is phase aligned with the core clock. The + * clk_x is an integral multiple N of the core clk. The value N is configured + * at IP delivery time, and its available value is 4, 5, or 6. We need to align + * to the largest value to make it work with any possible configuration. + */ +#define DENALI_CLK_X_MULT 6 + +/* * Certain operations for the denali NAND controller use an indexed mode to * read/write data. The operation is performed by writing the address value * of the command to the device memory followed by the data. This function @@ -196,148 +187,6 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali) } /* - * this routine calculates the ONFI timing values for a given mode and - * programs the clocking register accordingly. The mode is determined by - * the get_onfi_nand_para routine. - */ -static void nand_onfi_timing_set(struct denali_nand_info *denali, - uint16_t mode) -{ - uint16_t Trea[6] = {40, 30, 25, 20, 20, 16}; - uint16_t Trp[6] = {50, 25, 17, 15, 12, 10}; - uint16_t Treh[6] = {30, 15, 15, 10, 10, 7}; - uint16_t Trc[6] = {100, 50, 35, 30, 25, 20}; - uint16_t Trhoh[6] = {0, 15, 15, 15, 15, 15}; - uint16_t Trloh[6] = {0, 0, 0, 0, 5, 5}; - uint16_t Tcea[6] = {100, 45, 30, 25, 25, 25}; - uint16_t Tadl[6] = {200, 100, 100, 100, 70, 70}; - uint16_t Trhw[6] = {200, 100, 100, 100, 100, 100}; - uint16_t Trhz[6] = {200, 100, 100, 100, 100, 100}; - uint16_t Twhr[6] = {120, 80, 80, 60, 60, 60}; - uint16_t Tcs[6] = {70, 35, 25, 25, 20, 15}; - - uint16_t data_invalid_rhoh, data_invalid_rloh, data_invalid; - uint16_t dv_window = 0; - uint16_t en_lo, en_hi; - uint16_t acc_clks; - uint16_t addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt; - - en_lo = CEIL_DIV(Trp[mode], CLK_X); - en_hi = CEIL_DIV(Treh[mode], CLK_X); -#if ONFI_BLOOM_TIME - if ((en_hi * CLK_X) < (Treh[mode] + 2)) - en_hi++; -#endif - - if ((en_lo + en_hi) * CLK_X < Trc[mode]) - en_lo += CEIL_DIV((Trc[mode] - (en_lo + en_hi) * CLK_X), CLK_X); - - if ((en_lo + en_hi) < CLK_MULTI) - en_lo += CLK_MULTI - en_lo - en_hi; - - while (dv_window < 8) { - data_invalid_rhoh = en_lo * CLK_X + Trhoh[mode]; - - data_invalid_rloh = (en_lo + en_hi) * CLK_X + Trloh[mode]; - - data_invalid = data_invalid_rhoh < data_invalid_rloh ? - data_invalid_rhoh : data_invalid_rloh; - - dv_window = data_invalid - Trea[mode]; - - if (dv_window < 8) - en_lo++; - } - - acc_clks = CEIL_DIV(Trea[mode], CLK_X); - - while (acc_clks * CLK_X - Trea[mode] < 3) - acc_clks++; - - if (data_invalid - acc_clks * CLK_X < 2) - dev_warn(denali->dev, "%s, Line %d: Warning!\n", - __FILE__, __LINE__); - - addr_2_data = CEIL_DIV(Tadl[mode], CLK_X); - re_2_we = CEIL_DIV(Trhw[mode], CLK_X); - re_2_re = CEIL_DIV(Trhz[mode], CLK_X); - we_2_re = CEIL_DIV(Twhr[mode], CLK_X); - cs_cnt = CEIL_DIV((Tcs[mode] - Trp[mode]), CLK_X); - if (cs_cnt == 0) - cs_cnt = 1; - - if (Tcea[mode]) { - while (cs_cnt * CLK_X + Trea[mode] < Tcea[mode]) - cs_cnt++; - } - -#if MODE5_WORKAROUND - if (mode == 5) - acc_clks = 5; -#endif - - /* Sighting 3462430: Temporary hack for MT29F128G08CJABAWP:B */ - if (ioread32(denali->flash_reg + MANUFACTURER_ID) == 0 && - ioread32(denali->flash_reg + DEVICE_ID) == 0x88) - acc_clks = 6; - - iowrite32(acc_clks, denali->flash_reg + ACC_CLKS); - iowrite32(re_2_we, denali->flash_reg + RE_2_WE); - iowrite32(re_2_re, denali->flash_reg + RE_2_RE); - iowrite32(we_2_re, denali->flash_reg + WE_2_RE); - iowrite32(addr_2_data, denali->flash_reg + ADDR_2_DATA); - iowrite32(en_lo, denali->flash_reg + RDWR_EN_LO_CNT); - iowrite32(en_hi, denali->flash_reg + RDWR_EN_HI_CNT); - iowrite32(cs_cnt, denali->flash_reg + CS_SETUP_CNT); -} - -/* queries the NAND device to see what ONFI modes it supports. */ -static uint16_t get_onfi_nand_para(struct denali_nand_info *denali) -{ - int i; - - /* - * we needn't to do a reset here because driver has already - * reset all the banks before - */ - if (!(ioread32(denali->flash_reg + ONFI_TIMING_MODE) & - ONFI_TIMING_MODE__VALUE)) - return FAIL; - - for (i = 5; i > 0; i--) { - if (ioread32(denali->flash_reg + ONFI_TIMING_MODE) & - (0x01 << i)) - break; - } - - nand_onfi_timing_set(denali, i); - - /* - * By now, all the ONFI devices we know support the page cache - * rw feature. So here we enable the pipeline_rw_ahead feature - */ - /* iowrite32(1, denali->flash_reg + CACHE_WRITE_ENABLE); */ - /* iowrite32(1, denali->flash_reg + CACHE_READ_ENABLE); */ - - return PASS; -} - -static void get_samsung_nand_para(struct denali_nand_info *denali, - uint8_t device_id) -{ - if (device_id == 0xd3) { /* Samsung K9WAG08U1A */ - /* Set timing register values according to datasheet */ - iowrite32(5, denali->flash_reg + ACC_CLKS); - iowrite32(20, denali->flash_reg + RE_2_WE); - iowrite32(12, denali->flash_reg + WE_2_RE); - iowrite32(14, denali->flash_reg + ADDR_2_DATA); - iowrite32(3, denali->flash_reg + RDWR_EN_LO_CNT); - iowrite32(2, denali->flash_reg + RDWR_EN_HI_CNT); - iowrite32(2, denali->flash_reg + CS_SETUP_CNT); - } -} - -/* * Use the configuration feature register to determine the maximum number of * banks that the hardware supports. */ @@ -352,58 +201,6 @@ static void detect_max_banks(struct denali_nand_info *denali) denali->max_banks <<= 1; } -static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) -{ - uint16_t status = PASS; - uint32_t id_bytes[8], addr; - uint8_t maf_id, device_id; - int i; - - /* - * Use read id method to get device ID and other params. - * For some NAND chips, controller can't report the correct - * device ID by reading from DEVICE_ID register - */ - addr = MODE_11 | BANK(denali->flash_bank); - index_addr(denali, addr | 0, 0x90); - index_addr(denali, addr | 1, 0); - for (i = 0; i < 8; i++) - index_addr_read_data(denali, addr | 2, &id_bytes[i]); - maf_id = id_bytes[0]; - device_id = id_bytes[1]; - - if (ioread32(denali->flash_reg + ONFI_DEVICE_NO_OF_LUNS) & - ONFI_DEVICE_NO_OF_LUNS__ONFI_DEVICE) { /* ONFI 1.0 NAND */ - if (FAIL == get_onfi_nand_para(denali)) - return FAIL; - } else if (maf_id == 0xEC) { /* Samsung NAND */ - get_samsung_nand_para(denali, device_id); - } - - dev_info(denali->dev, - "Dump timing register values:\n" - "acc_clks: %d, re_2_we: %d, re_2_re: %d\n" - "we_2_re: %d, addr_2_data: %d, rdwr_en_lo_cnt: %d\n" - "rdwr_en_hi_cnt: %d, cs_setup_cnt: %d\n", - ioread32(denali->flash_reg + ACC_CLKS), - ioread32(denali->flash_reg + RE_2_WE), - ioread32(denali->flash_reg + RE_2_RE), - ioread32(denali->flash_reg + WE_2_RE), - ioread32(denali->flash_reg + ADDR_2_DATA), - ioread32(denali->flash_reg + RDWR_EN_LO_CNT), - ioread32(denali->flash_reg + RDWR_EN_HI_CNT), - ioread32(denali->flash_reg + CS_SETUP_CNT)); - - /* - * If the user specified to override the default timings - * with a specific ONFI mode, we apply those changes here. - */ - if (onfi_timing_mode != NAND_DEFAULT_TIMINGS) - nand_onfi_timing_set(denali, onfi_timing_mode); - - return status; -} - static void denali_set_intr_modes(struct denali_nand_info *denali, uint16_t INT_ENABLE) { @@ -1209,7 +1006,122 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, break; } } -/* end NAND core entry points */ + +#define DIV_ROUND_DOWN_ULL(ll, d) \ + ({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; }) + +static int denali_setup_data_interface(struct mtd_info *mtd, + const struct nand_data_interface *conf, + bool check_only) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + const struct nand_sdr_timings *timings; + unsigned long t_clk; + int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data; + int rdwr_en_lo, rdwr_en_hi, rdwr_en_lo_hi, cs_setup; + int addr_2_data_mask; + uint32_t tmp; + + timings = nand_get_sdr_timings(conf); + if (IS_ERR(timings)) + return PTR_ERR(timings); + + /* clk_x period in picoseconds */ + t_clk = DIV_ROUND_DOWN_ULL(1000000000000ULL, denali->clk_x_rate); + if (!t_clk) + return -EINVAL; + + if (check_only) + return 0; + + /* tREA -> ACC_CLKS */ + acc_clks = DIV_ROUND_UP(timings->tREA_max, t_clk); + acc_clks = min_t(int, acc_clks, ACC_CLKS__VALUE); + + tmp = ioread32(denali->flash_reg + ACC_CLKS); + tmp &= ~ACC_CLKS__VALUE; + tmp |= acc_clks; + iowrite32(tmp, denali->flash_reg + ACC_CLKS); + + /* tRWH -> RE_2_WE */ + re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_clk); + re_2_we = min_t(int, re_2_we, RE_2_WE__VALUE); + + tmp = ioread32(denali->flash_reg + RE_2_WE); + tmp &= ~RE_2_WE__VALUE; + tmp |= re_2_we; + iowrite32(tmp, denali->flash_reg + RE_2_WE); + + /* tRHZ -> RE_2_RE */ + re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_clk); + re_2_re = min_t(int, re_2_re, RE_2_RE__VALUE); + + tmp = ioread32(denali->flash_reg + RE_2_RE); + tmp &= ~RE_2_RE__VALUE; + tmp |= re_2_re; + iowrite32(tmp, denali->flash_reg + RE_2_RE); + + /* tWHR -> WE_2_RE */ + we_2_re = DIV_ROUND_UP(timings->tWHR_min, t_clk); + we_2_re = min_t(int, we_2_re, TWHR2_AND_WE_2_RE__WE_2_RE); + + tmp = ioread32(denali->flash_reg + TWHR2_AND_WE_2_RE); + tmp &= ~TWHR2_AND_WE_2_RE__WE_2_RE; + tmp |= we_2_re; + iowrite32(tmp, denali->flash_reg + TWHR2_AND_WE_2_RE); + + /* tADL -> ADDR_2_DATA */ + + /* for older versions, ADDR_2_DATA is only 6 bit wide */ + addr_2_data_mask = TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA; + if (denali->revision < 0x0501) + addr_2_data_mask >>= 1; + + addr_2_data = DIV_ROUND_UP(timings->tADL_min, t_clk); + addr_2_data = min_t(int, addr_2_data, addr_2_data_mask); + + tmp = ioread32(denali->flash_reg + TCWAW_AND_ADDR_2_DATA); + tmp &= ~addr_2_data_mask; + tmp |= addr_2_data; + iowrite32(tmp, denali->flash_reg + TCWAW_AND_ADDR_2_DATA); + + /* tREH, tWH -> RDWR_EN_HI_CNT */ + rdwr_en_hi = DIV_ROUND_UP(max(timings->tREH_min, timings->tWH_min), + t_clk); + rdwr_en_hi = min_t(int, rdwr_en_hi, RDWR_EN_HI_CNT__VALUE); + + tmp = ioread32(denali->flash_reg + RDWR_EN_HI_CNT); + tmp &= ~RDWR_EN_HI_CNT__VALUE; + tmp |= rdwr_en_hi; + iowrite32(tmp, denali->flash_reg + RDWR_EN_HI_CNT); + + /* tRP, tWP -> RDWR_EN_LO_CNT */ + rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min), + t_clk); + rdwr_en_lo_hi = DIV_ROUND_UP(max(timings->tRC_min, timings->tWC_min), + t_clk); + rdwr_en_lo_hi = max(rdwr_en_lo_hi, DENALI_CLK_X_MULT); + rdwr_en_lo = max(rdwr_en_lo, rdwr_en_lo_hi - rdwr_en_hi); + rdwr_en_lo = min_t(int, rdwr_en_lo, RDWR_EN_LO_CNT__VALUE); + + tmp = ioread32(denali->flash_reg + RDWR_EN_LO_CNT); + tmp &= ~RDWR_EN_LO_CNT__VALUE; + tmp |= rdwr_en_lo; + iowrite32(tmp, denali->flash_reg + RDWR_EN_LO_CNT); + + /* tCS, tCEA -> CS_SETUP_CNT */ + cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_clk) - rdwr_en_lo, + (int)DIV_ROUND_UP(timings->tCEA_max, t_clk) - acc_clks, + 0); + cs_setup = min_t(int, cs_setup, CS_SETUP_CNT__VALUE); + + tmp = ioread32(denali->flash_reg + CS_SETUP_CNT); + tmp &= ~CS_SETUP_CNT__VALUE; + tmp |= cs_setup; + iowrite32(tmp, denali->flash_reg + CS_SETUP_CNT); + + return 0; +} /* Initialization code to bring the device up to a known good state */ static void denali_hw_init(struct denali_nand_info *denali) @@ -1241,7 +1153,6 @@ static void denali_hw_init(struct denali_nand_info *denali) /* Should set value for these registers when init */ iowrite32(0, denali->flash_reg + TWO_ROW_ADDR_CYCLES); iowrite32(1, denali->flash_reg + ECC_ENABLE); - denali_nand_timing_set(denali); denali_irq_init(denali); } @@ -1432,17 +1343,6 @@ int denali_init(struct denali_nand_info *denali) struct mtd_info *mtd = nand_to_mtd(chip); int ret; - if (denali->platform == INTEL_CE4100) { - /* - * Due to a silicon limitation, we can only support - * ONFI timing mode 1 and below. - */ - if (onfi_timing_mode < -1 || onfi_timing_mode > 1) { - pr_err("Intel CE4100 only supports ONFI timing mode 1 or below\n"); - return -EINVAL; - } - } - /* allocate a temporary buffer for nand_scan_ident() */ denali->buf.buf = devm_kzalloc(denali->dev, PAGE_SIZE, GFP_DMA | GFP_KERNEL); @@ -1473,6 +1373,9 @@ int denali_init(struct denali_nand_info *denali) chip->cmdfunc = denali_cmdfunc; chip->read_byte = denali_read_byte; chip->waitfunc = denali_waitfunc; + /* clk rate info is needed for setup_data_interface */ + if (denali->clk_x_rate) + chip->setup_data_interface = denali_setup_data_interface; /* * scan for NAND devices attached to the controller diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 80767cf..f0f4d75 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -72,11 +72,14 @@ #define GLOBAL_INT_ENABLE 0xf0 #define GLOBAL_INT_EN_FLAG BIT(0) -#define WE_2_RE 0x100 -#define WE_2_RE__VALUE GENMASK(5, 0) +#define TWHR2_AND_WE_2_RE 0x100 +#define TWHR2_AND_WE_2_RE__WE_2_RE GENMASK(5, 0) +#define TWHR2_AND_WE_2_RE__TWHR2 GENMASK(13, 8) -#define ADDR_2_DATA 0x110 -#define ADDR_2_DATA__VALUE GENMASK(5, 0) +#define TCWAW_AND_ADDR_2_DATA 0x110 +/* The width of ADDR_2_DATA is 6 bit for old IP, 7 bit for new IP */ +#define TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA GENMASK(6, 0) +#define TCWAW_AND_ADDR_2_DATA__TCWAW GENMASK(13, 8) #define RE_2_WE 0x120 #define RE_2_WE__VALUE GENMASK(5, 0) @@ -128,6 +131,7 @@ #define CS_SETUP_CNT 0x220 #define CS_SETUP_CNT__VALUE GENMASK(4, 0) +#define CS_SETUP_CNT__TWB GENMASK(17, 12) #define SPARE_AREA_SKIP_BYTES 0x230 #define SPARE_AREA_SKIP_BYTES__VALUE GENMASK(5, 0) @@ -294,16 +298,8 @@ #define CHNL_ACTIVE__CHANNEL2 BIT(2) #define CHNL_ACTIVE__CHANNEL3 BIT(3) -#define FAIL 1 /*failed flag*/ #define PASS 0 /*success flag*/ -#define CLK_X 5 -#define CLK_MULTI 4 - -#define ONFI_BLOOM_TIME 1 -#define MODE5_WORKAROUND 0 - - #define MODE_00 0x00000000 #define MODE_01 0x04000000 #define MODE_10 0x08000000 @@ -316,14 +312,10 @@ struct nand_buf { dma_addr_t dma_buf; }; -#define INTEL_CE4100 1 -#define INTEL_MRST 2 -#define DT 3 - struct denali_nand_info { struct nand_chip nand; + unsigned long clk_x_rate; /* bus interface clock rate */ int flash_bank; /* currently selected chip */ - int platform; struct nand_buf buf; struct device *dev; int page; diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index 38800ae..56bfff0 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -105,7 +105,6 @@ static int denali_dt_probe(struct platform_device *pdev) denali->stepinfo = &data->stepinfo; } - denali->platform = DT; denali->dev = &pdev->dev; denali->irq = platform_get_irq(pdev, 0); if (denali->irq < 0) { @@ -130,6 +129,8 @@ static int denali_dt_probe(struct platform_device *pdev) } clk_prepare_enable(dt->clk); + denali->clk_x_rate = clk_get_rate(dt->clk); + ret = denali_init(denali); if (ret) goto out_disable_clk; diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c index e0d50b6..8a66254 100644 --- a/drivers/mtd/nand/denali_pci.c +++ b/drivers/mtd/nand/denali_pci.c @@ -19,6 +19,9 @@ #define DENALI_NAND_NAME "denali-nand-pci" +#define INTEL_CE4100 1 +#define INTEL_MRST 2 + /* List of platforms this NAND controller has be integrated into */ static const struct pci_device_id denali_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 }, @@ -52,13 +55,11 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) } if (id->driver_data == INTEL_CE4100) { - denali->platform = INTEL_CE4100; mem_base = pci_resource_start(dev, 0); mem_len = pci_resource_len(dev, 1); csr_base = pci_resource_start(dev, 1); csr_len = pci_resource_len(dev, 1); } else { - denali->platform = INTEL_MRST; csr_base = pci_resource_start(dev, 0); csr_len = pci_resource_len(dev, 0); mem_base = pci_resource_start(dev, 1); @@ -74,6 +75,7 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) denali->irq = dev->irq; denali->stepinfo = &denali_pci_stepinfo; denali->nand.ecc.options |= NAND_ECC_MAXIMIZE; + denali->clk_x_rate = 200000000; /* 200 MHz */ ret = pci_request_regions(dev, DENALI_NAND_NAME); if (ret) { From patchwork Mon Jun 5 23:21:50 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103103 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1008524obh; Mon, 5 Jun 2017 16:25:46 -0700 (PDT) X-Received: by 10.84.216.84 with SMTP id f20mr18176815plj.177.1496705145960; Mon, 05 Jun 2017 16:25:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705145; cv=none; d=google.com; s=arc-20160816; b=XjFe0rAO7gRbhcnWbHnE8jEimpv4Laoo0HDxNd6T5I0tTapsJ1v+/GW7TlqZgJ5jib 7HtOYv/KSqsznaoEDAgv/f8OilZNjcHuWpsiVfi5sjfLgRnCECFjhTGjPPwTggUNME8G EqRQIZNXMRFkfH3mFJ0CE2chv6Pnig+/06e986u5iQUwDWaaM1+0Vsv/9mFkX7XjmmMK omiwSasRcAdcMi76qDJjZ50ESSnje0CRXz78FZ8hjquKDbxT5nXPFd1ohTTik72vPuuq keoBbg/T48JMUiVDtqnxVMd1/Rm39Mrnhr/5MF6NSZY2fQkQ/v91X8PqYOPmrCPeTsfs WL+A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=bi561hcCivDTERSSh97h2qn1wWavmtZO6WAubrePEg0=; b=MZCIBEUYPauWBqmpPx9xJb64OV2WSJSIhzFnAi/VMU2+34++ERoQB9szS/4OwE/FzR JcH0Q+J+QndvrqywC7O744uExwJm89xAWtLWgeh1FNKZ2am0zfjb31KL2/AU80zF6xT+ 4eURUQSCHoqRgdqSljgiaVLVDi/xwSpQEB7A6OVam/MhfB0vjmAKS/u1ZzwoswJvj7ML f0AC/ETbtM7/WbZVM8iMO3TEDQzLzWNYp6ueEs4Jy/YYTm9wI4muASlkLjBvu9oDAecm r936B9gD/xRKDan/4V2n8L/Ymh1zQDuFAXgiLCqN2ubepxBU2BOVZkXTYdlwFR8oszJw i30Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id q20si10759518pfl.414.2017.06.05.16.25.45; Mon, 05 Jun 2017 16:25:45 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751416AbdFEXZh (ORCPT + 25 others); Mon, 5 Jun 2017 19:25:37 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:32527 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751194AbdFEXZf (ORCPT ); Mon, 5 Jun 2017 19:25:35 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5l004412; Tue, 6 Jun 2017 08:22:40 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5l004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704961; bh=bi561hcCivDTERSSh97h2qn1wWavmtZO6WAubrePEg0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XDMeKwqnt7nZ+WjTk0dbE9lMRiX0TeUHIr2hPNKwG+KdbWU8KOmBF60/qtJ7WCVy6 UMBOwEwkyrGa6Q6V8+wJafdFKKARhSklFg4FfQh1bCvl8nvNJQPszduamtb0Ghcaun 6a8in9X4PPo5AIdA4NxhCu/juCeFu1kYuZFSJfmAdNWQoTB4pgDL24daz6U1FvvPgL P7wbJ5gyogJ2fhu2uK7DE1FOzZUUXFO/McnCRuj0Yx1wzeU8nagEpMkIi4kaRbbzRd MKgv9ScHPc3gh9OfFlPp8Eejeyh5UHwQRNCeICENOEfcdCnLcmx6nuSR/R13QT+Mz5 bMD9PkigslUBA== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v4 11/23] mtd: nand: denali: rework interrupt handling Date: Tue, 6 Jun 2017 08:21:50 +0900 Message-Id: <1496704922-12261-12-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Simplify the interrupt handling and fix issues: - The register field view of INTR_EN / INTR_STATUS is different among IP versions. The global macro DENALI_IRQ_ALL is hard-coded for Intel platforms. The interrupt mask should be determined at run-time depending on the running platform. - wait_for_irq() loops do {} while() until interested flags are asserted. The logic can be simplified. - The spin_lock() guard seems too complex (and suspicious in a race condition if wait_for_completion_timeout() bails out by timeout). - denali->complete is reused again and again, but reinit_completion() is missing. Add it. Re-work the code to make it more robust and easier to handle. While we are here, also rename the jump label "failed_req_irq" to more appropriate "disable_irq". Signed-off-by: Masahiro Yamada --- Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 316 +++++++++++++++++----------------------------- drivers/mtd/nand/denali.h | 1 + 2 files changed, 116 insertions(+), 201 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 1bb57de..e8e6667 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -31,21 +31,6 @@ MODULE_LICENSE("GPL"); #define DENALI_NAND_NAME "denali-nand" /* - * We define a macro here that combines all interrupts this driver uses into - * a single constant value, for convenience. - */ -#define DENALI_IRQ_ALL (INTR__DMA_CMD_COMP | \ - INTR__ECC_TRANSACTION_DONE | \ - INTR__ECC_ERR | \ - INTR__PROGRAM_FAIL | \ - INTR__LOAD_COMP | \ - INTR__PROGRAM_COMP | \ - INTR__TIME_OUT | \ - INTR__ERASE_FAIL | \ - INTR__RST_COMP | \ - INTR__ERASE_COMP) - -/* * indicates whether or not the internal value for the flash bank is * valid or not */ @@ -71,20 +56,14 @@ static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd) #define DENALI_READ 0 #define DENALI_WRITE 0x100 +#define DENALI_NR_BANKS 4 + /* * this is a helper macro that allows us to * format the bank into the proper bits for the controller */ #define BANK(x) ((x) << 24) -/* forward declarations */ -static void clear_interrupts(struct denali_nand_info *denali); -static uint32_t wait_for_irq(struct denali_nand_info *denali, - uint32_t irq_mask); -static void denali_irq_enable(struct denali_nand_info *denali, - uint32_t int_mask); -static uint32_t read_interrupt_status(struct denali_nand_info *denali); - /* * The bus interface clock, clk_x, is phase aligned with the core clock. The * clk_x is an integral multiple N of the core clk. The value N is configured @@ -143,22 +122,6 @@ static void read_status(struct denali_nand_info *denali) write_byte_to_buf(denali, 0); } -/* resets a specific device connected to the core */ -static void reset_bank(struct denali_nand_info *denali) -{ - uint32_t irq_status; - uint32_t irq_mask = INTR__RST_COMP | INTR__TIME_OUT; - - clear_interrupts(denali); - - iowrite32(1 << denali->flash_bank, denali->flash_reg + DEVICE_RESET); - - irq_status = wait_for_irq(denali, irq_mask); - - if (irq_status & INTR__TIME_OUT) - dev_err(denali->dev, "reset bank failed.\n"); -} - /* Reset the flash controller */ static uint16_t denali_nand_reset(struct denali_nand_info *denali) { @@ -201,169 +164,123 @@ static void detect_max_banks(struct denali_nand_info *denali) denali->max_banks <<= 1; } -static void denali_set_intr_modes(struct denali_nand_info *denali, - uint16_t INT_ENABLE) +static void denali_enable_irq(struct denali_nand_info *denali) { - if (INT_ENABLE) - iowrite32(1, denali->flash_reg + GLOBAL_INT_ENABLE); - else - iowrite32(0, denali->flash_reg + GLOBAL_INT_ENABLE); -} + int i; -/* - * validation function to verify that the controlling software is making - * a valid request - */ -static inline bool is_flash_bank_valid(int flash_bank) -{ - return flash_bank >= 0 && flash_bank < 4; + for (i = 0; i < DENALI_NR_BANKS; i++) + iowrite32(U32_MAX, denali->flash_reg + INTR_EN(i)); + iowrite32(GLOBAL_INT_EN_FLAG, denali->flash_reg + GLOBAL_INT_ENABLE); } -static void denali_irq_init(struct denali_nand_info *denali) +static void denali_disable_irq(struct denali_nand_info *denali) { - uint32_t int_mask; int i; - /* Disable global interrupts */ - denali_set_intr_modes(denali, false); - - int_mask = DENALI_IRQ_ALL; - - /* Clear all status bits */ - for (i = 0; i < denali->max_banks; ++i) - iowrite32(0xFFFF, denali->flash_reg + INTR_STATUS(i)); - - denali_irq_enable(denali, int_mask); + for (i = 0; i < DENALI_NR_BANKS; i++) + iowrite32(0, denali->flash_reg + INTR_EN(i)); + iowrite32(0, denali->flash_reg + GLOBAL_INT_ENABLE); } -static void denali_irq_cleanup(int irqnum, struct denali_nand_info *denali) +static void denali_clear_irq(struct denali_nand_info *denali, + int bank, uint32_t irq_status) { - denali_set_intr_modes(denali, false); + /* write one to clear bits */ + iowrite32(irq_status, denali->flash_reg + INTR_STATUS(bank)); } -static void denali_irq_enable(struct denali_nand_info *denali, - uint32_t int_mask) +static void denali_clear_irq_all(struct denali_nand_info *denali) { int i; - for (i = 0; i < denali->max_banks; ++i) - iowrite32(int_mask, denali->flash_reg + INTR_EN(i)); + for (i = 0; i < DENALI_NR_BANKS; i++) + denali_clear_irq(denali, i, U32_MAX); } -/* - * This function only returns when an interrupt that this driver cares about - * occurs. This is to reduce the overhead of servicing interrupts - */ -static inline uint32_t denali_irq_detected(struct denali_nand_info *denali) +static irqreturn_t denali_isr(int irq, void *dev_id) { - return read_interrupt_status(denali) & DENALI_IRQ_ALL; -} + struct denali_nand_info *denali = dev_id; + irqreturn_t ret = IRQ_NONE; + uint32_t irq_status; + int i; -/* Interrupts are cleared by writing a 1 to the appropriate status bit */ -static inline void clear_interrupt(struct denali_nand_info *denali, - uint32_t irq_mask) -{ - uint32_t intr_status_reg; + spin_lock(&denali->irq_lock); - intr_status_reg = INTR_STATUS(denali->flash_bank); + for (i = 0; i < DENALI_NR_BANKS; i++) { + irq_status = ioread32(denali->flash_reg + INTR_STATUS(i)); + if (irq_status) + ret = IRQ_HANDLED; - iowrite32(irq_mask, denali->flash_reg + intr_status_reg); -} + denali_clear_irq(denali, i, irq_status); -static void clear_interrupts(struct denali_nand_info *denali) -{ - uint32_t status; + if (i != denali->flash_bank) + continue; + + denali->irq_status |= irq_status; - spin_lock_irq(&denali->irq_lock); + if (denali->irq_status & denali->irq_mask) + complete(&denali->complete); + } - status = read_interrupt_status(denali); - clear_interrupt(denali, status); + spin_unlock(&denali->irq_lock); - denali->irq_status = 0x0; - spin_unlock_irq(&denali->irq_lock); + return ret; } -static uint32_t read_interrupt_status(struct denali_nand_info *denali) +static void denali_reset_irq(struct denali_nand_info *denali) { - uint32_t intr_status_reg; - - intr_status_reg = INTR_STATUS(denali->flash_bank); + unsigned long flags; - return ioread32(denali->flash_reg + intr_status_reg); + spin_lock_irqsave(&denali->irq_lock, flags); + denali->irq_status = 0; + denali->irq_mask = 0; + spin_unlock_irqrestore(&denali->irq_lock, flags); } -/* - * This is the interrupt service routine. It handles all interrupts - * sent to this device. Note that on CE4100, this is a shared interrupt. - */ -static irqreturn_t denali_isr(int irq, void *dev_id) +static uint32_t denali_wait_for_irq(struct denali_nand_info *denali, + uint32_t irq_mask) { - struct denali_nand_info *denali = dev_id; + unsigned long time_left, flags; uint32_t irq_status; - irqreturn_t result = IRQ_NONE; - spin_lock(&denali->irq_lock); + spin_lock_irqsave(&denali->irq_lock, flags); - /* check to see if a valid NAND chip has been selected. */ - if (is_flash_bank_valid(denali->flash_bank)) { - /* - * check to see if controller generated the interrupt, - * since this is a shared interrupt - */ - irq_status = denali_irq_detected(denali); - if (irq_status != 0) { - /* handle interrupt */ - /* first acknowledge it */ - clear_interrupt(denali, irq_status); - /* - * store the status in the device context for someone - * to read - */ - denali->irq_status |= irq_status; - /* notify anyone who cares that it happened */ - complete(&denali->complete); - /* tell the OS that we've handled this */ - result = IRQ_HANDLED; - } + irq_status = denali->irq_status; + + if (irq_mask & irq_status) { + spin_unlock_irqrestore(&denali->irq_lock, flags); + return irq_status; } - spin_unlock(&denali->irq_lock); - return result; + + denali->irq_mask = irq_mask; + reinit_completion(&denali->complete); + spin_unlock_irqrestore(&denali->irq_lock, flags); + + time_left = wait_for_completion_timeout(&denali->complete, + msecs_to_jiffies(1000)); + if (!time_left) { + dev_err(denali->dev, "timeout while waiting for irq 0x%x\n", + denali->irq_mask); + return 0; + } + + return denali->irq_status; } -static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) +/* resets a specific device connected to the core */ +static void reset_bank(struct denali_nand_info *denali) { - unsigned long comp_res; - uint32_t intr_status; - unsigned long timeout = msecs_to_jiffies(1000); + uint32_t irq_status; - do { - comp_res = - wait_for_completion_timeout(&denali->complete, timeout); - spin_lock_irq(&denali->irq_lock); - intr_status = denali->irq_status; - - if (intr_status & irq_mask) { - denali->irq_status &= ~irq_mask; - spin_unlock_irq(&denali->irq_lock); - /* our interrupt was detected */ - break; - } + denali_reset_irq(denali); - /* - * these are not the interrupts you are looking for - - * need to wait again - */ - spin_unlock_irq(&denali->irq_lock); - } while (comp_res != 0); + iowrite32(1 << denali->flash_bank, denali->flash_reg + DEVICE_RESET); - if (comp_res == 0) { - /* timeout */ - pr_err("timeout occurred, status = 0x%x, mask = 0x%x\n", - intr_status, irq_mask); + irq_status = denali_wait_for_irq(denali, + INTR__RST_COMP | INTR__TIME_OUT); - intr_status = 0; - } - return intr_status; + if (!(irq_status & INTR__RST_COMP)) + dev_err(denali->dev, "reset bank failed.\n"); } /* @@ -397,7 +314,7 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, setup_ecc_for_xfer(denali, ecc_en, transfer_spare); - clear_interrupts(denali); + denali_reset_irq(denali); addr = BANK(denali->flash_bank) | denali->page; @@ -479,9 +396,9 @@ static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) write_data_to_flash_mem(denali, buf, mtd->oobsize); /* wait for operation to complete */ - irq_status = wait_for_irq(denali, irq_mask); + irq_status = denali_wait_for_irq(denali, irq_mask); - if (irq_status == 0) { + if (!(irq_status & INTR__PROGRAM_COMP)) { dev_err(denali->dev, "OOB write failed\n"); status = -EIO; } @@ -510,9 +427,9 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) * can always use status0 bit as the * mask is identical for each bank. */ - irq_status = wait_for_irq(denali, irq_mask); + irq_status = denali_wait_for_irq(denali, irq_mask); - if (irq_status == 0) + if (!(irq_status & INTR__LOAD_COMP)) dev_err(denali->dev, "page on OOB timeout %d\n", denali->page); @@ -620,9 +537,9 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd, unsigned int err_byte, err_sector, err_device; uint8_t err_cor_value; unsigned int prev_sector = 0; + uint32_t irq_status; - /* read the ECC errors. we'll ignore them for now */ - denali_set_intr_modes(denali, false); + denali_reset_irq(denali); do { err_addr = ioread32(denali->flash_reg + ECC_ERROR_ADDRESS); @@ -674,10 +591,9 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd, * ECC_TRANSACTION_DONE interrupt, so here just wait for * a while for this interrupt */ - while (!(read_interrupt_status(denali) & INTR__ECC_TRANSACTION_DONE)) - cpu_relax(); - clear_interrupts(denali); - denali_set_intr_modes(denali, true); + irq_status = denali_wait_for_irq(denali, INTR__ECC_TRANSACTION_DONE); + if (!(irq_status & INTR__ECC_TRANSACTION_DONE)) + return -EIO; return max_bitflips; } @@ -778,15 +694,14 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, dma_sync_single_for_device(denali->dev, addr, size, DMA_TO_DEVICE); - clear_interrupts(denali); + denali_reset_irq(denali); denali_enable_dma(denali, true); denali_setup_dma(denali, DENALI_WRITE); /* wait for operation to complete */ - irq_status = wait_for_irq(denali, irq_mask); - - if (irq_status == 0) { + irq_status = denali_wait_for_irq(denali, irq_mask); + if (!(irq_status & INTR__DMA_CMD_COMP)) { dev_err(denali->dev, "timeout on write_page (type = %d)\n", raw_xfer); ret = -EIO; @@ -865,11 +780,11 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, denali_enable_dma(denali, true); dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE); - clear_interrupts(denali); + denali_reset_irq(denali); denali_setup_dma(denali, DENALI_READ); /* wait for operation to complete */ - irq_status = wait_for_irq(denali, irq_mask); + irq_status = denali_wait_for_irq(denali, irq_mask); dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE); @@ -901,6 +816,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, dma_addr_t addr = denali->buf.dma_buf; size_t size = mtd->writesize + mtd->oobsize; uint32_t irq_mask = INTR__DMA_CMD_COMP; + uint32_t irq_status; denali->page = page; @@ -909,11 +825,13 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE); - clear_interrupts(denali); + denali_reset_irq(denali); denali_setup_dma(denali, DENALI_READ); /* wait for operation to complete */ - wait_for_irq(denali, irq_mask); + irq_status = denali_wait_for_irq(denali, irq_mask); + if (irq_status & INTR__DMA_CMD_COMP) + return -ETIMEDOUT; dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE); @@ -940,9 +858,7 @@ static void denali_select_chip(struct mtd_info *mtd, int chip) { struct denali_nand_info *denali = mtd_to_denali(mtd); - spin_lock_irq(&denali->irq_lock); denali->flash_bank = chip; - spin_unlock_irq(&denali->irq_lock); } static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) @@ -953,19 +869,19 @@ static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) static int denali_erase(struct mtd_info *mtd, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t cmd, irq_status; - clear_interrupts(denali); + denali_reset_irq(denali); /* setup page read request for access type */ cmd = MODE_10 | BANK(denali->flash_bank) | page; index_addr(denali, cmd, 0x1); /* wait for erase to complete or failure to occur */ - irq_status = wait_for_irq(denali, INTR__ERASE_COMP | INTR__ERASE_FAIL); + irq_status = denali_wait_for_irq(denali, + INTR__ERASE_COMP | INTR__ERASE_FAIL); - return irq_status & INTR__ERASE_FAIL ? NAND_STATUS_FAIL : PASS; + return irq_status & INTR__ERASE_COMP ? 0 : NAND_STATUS_FAIL; } static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, @@ -1153,7 +1069,6 @@ static void denali_hw_init(struct denali_nand_info *denali) /* Should set value for these registers when init */ iowrite32(0, denali->flash_reg + TWO_ROW_ADDR_CYCLES); iowrite32(1, denali->flash_reg + ECC_ENABLE); - denali_irq_init(denali); } static int denali_calc_ecc_bytes(int step_size, int strength) @@ -1281,9 +1196,6 @@ static void denali_drv_init(struct denali_nand_info *denali) /* indicate that MTD has not selected a valid bank yet */ denali->flash_bank = CHIP_SELECT_INVALID; - - /* initialize our irq_status variable to indicate no interrupts */ - denali->irq_status = 0; } static int denali_multidev_fixup(struct denali_nand_info *denali) @@ -1353,6 +1265,8 @@ int denali_init(struct denali_nand_info *denali) denali_hw_init(denali); denali_drv_init(denali); + denali_clear_irq_all(denali); + /* Request IRQ after all the hardware initialization is finished */ ret = devm_request_irq(denali->dev, denali->irq, denali_isr, IRQF_SHARED, DENALI_NAND_NAME, denali); @@ -1361,8 +1275,8 @@ int denali_init(struct denali_nand_info *denali) return ret; } - /* now that our ISR is registered, we can enable interrupts */ - denali_set_intr_modes(denali, true); + denali_enable_irq(denali); + nand_set_flash_node(chip, denali->dev->of_node); /* Fallback to the default name if DT did not give "label" property */ if (!mtd->name) @@ -1384,7 +1298,7 @@ int denali_init(struct denali_nand_info *denali) */ ret = nand_scan_ident(mtd, denali->max_banks, NULL); if (ret) - goto failed_req_irq; + goto disable_irq; /* allocate the right size buffer now */ devm_kfree(denali->dev, denali->buf.buf); @@ -1393,7 +1307,7 @@ int denali_init(struct denali_nand_info *denali) GFP_KERNEL); if (!denali->buf.buf) { ret = -ENOMEM; - goto failed_req_irq; + goto disable_irq; } ret = dma_set_mask(denali->dev, @@ -1401,7 +1315,7 @@ int denali_init(struct denali_nand_info *denali) 64 : 32)); if (ret) { dev_err(denali->dev, "No usable DMA configuration\n"); - goto failed_req_irq; + goto disable_irq; } denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf, @@ -1410,7 +1324,7 @@ int denali_init(struct denali_nand_info *denali) if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) { dev_err(denali->dev, "Failed to map DMA buffer\n"); ret = -EIO; - goto failed_req_irq; + goto disable_irq; } /* @@ -1434,7 +1348,7 @@ int denali_init(struct denali_nand_info *denali) ret = denali_ecc_setup(mtd, chip, denali); if (ret) { dev_err(denali->dev, "Failed to setup ECC settings.\n"); - goto failed_req_irq; + goto disable_irq; } dev_dbg(denali->dev, @@ -1468,21 +1382,21 @@ int denali_init(struct denali_nand_info *denali) ret = denali_multidev_fixup(denali); if (ret) - goto failed_req_irq; + goto disable_irq; ret = nand_scan_tail(mtd); if (ret) - goto failed_req_irq; + goto disable_irq; ret = mtd_device_register(mtd, NULL, 0); if (ret) { dev_err(denali->dev, "Failed to register MTD: %d\n", ret); - goto failed_req_irq; + goto disable_irq; } return 0; -failed_req_irq: - denali_irq_cleanup(denali->irq, denali); +disable_irq: + denali_disable_irq(denali); return ret; } @@ -1500,7 +1414,7 @@ void denali_remove(struct denali_nand_info *denali) int bufsize = mtd->writesize + mtd->oobsize; nand_release(mtd); - denali_irq_cleanup(denali->irq, denali); + denali_disable_irq(denali); dma_unmap_single(denali->dev, denali->buf.dma_buf, bufsize, DMA_BIDIRECTIONAL); } diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index f0f4d75..a46473a 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -325,6 +325,7 @@ struct denali_nand_info { /* elements used by ISR */ struct completion complete; spinlock_t irq_lock; + uint32_t irq_mask; uint32_t irq_status; int irq; From patchwork Mon Jun 5 23:21:51 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103100 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1008420obh; Mon, 5 Jun 2017 16:25:26 -0700 (PDT) X-Received: by 10.98.207.132 with SMTP id b126mr22512210pfg.167.1496705126689; Mon, 05 Jun 2017 16:25:26 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705126; cv=none; d=google.com; s=arc-20160816; b=mMq8iBaIYVNDNgmB47SLk3bdqIr3C4g21Pywr+mtQcC0L31a7T/vutxHtTG4afZyFF cw3dDfPDzfJXIFAMuRZ+mo80kFSmWg9vS4YVpdPbhG/Yufs68sMSY2LuadN3q1ROH4FJ QGVdSRWzTK3ozQaqv5yjZYtCEZmoCUC7pTeK9plQUVbwWbRMzxfJpYBL97D0+ryUuWN6 /AuMTJP2FhhJwGQcSR9iGwlI5pM6w90BDEJWzajvUnh7CO3vbED18JvhQ6bAOUq0v2v9 57HadrVBrFzyGw2rkUeXZhWWDFnaUkoN1CzFjc423g/HDMIIGi9ikbFWwPLZ7NoampOl Ae3w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=NtSvSeVv15pVY2ZikNkM95O6qOU+MOA0wssg7wKIZo8=; b=p4AyjyuS6Fx+gGICLei05o1vmMEt1WiNB+/uvya8Bnvu8GdSH8zRnCTLTvE1prNpUv sa+VXg++iCahOlt5KfrFMCJXIBsoauQEvo5rDyJiLOLQBBItNjTPwix9V27VLkietdiC dzYOHWXtTZBP6PlQEJVGWxqC2qcji+SdlL1r4pTMFcmapAD9Zs80p4kxfxwRIKEVNybK XcQpOyJMtGfQwOxukP9yWMiHf1K3MfPhTh25AtGbCUEX5iUdG2ZkOOnIMqDruiTvO7bR Js4EDg06AoI44G2svwKktdHmapIYrzALN+6+uSUP3Z0Rxd2HjWrqb2+28qHunwnwcXnQ i30w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id v3si8432971plb.504.2017.06.05.16.25.26; Mon, 05 Jun 2017 16:25:26 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751361AbdFEXZX (ORCPT + 25 others); Mon, 5 Jun 2017 19:25:23 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:32120 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751274AbdFEXZQ (ORCPT ); Mon, 5 Jun 2017 19:25:16 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5m004412; Tue, 6 Jun 2017 08:22:41 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5m004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704962; bh=NtSvSeVv15pVY2ZikNkM95O6qOU+MOA0wssg7wKIZo8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Q6kFUAuBElgybqKb8+gJ6/LpXqRt+nr0AfHNdrc6Vk2xHt/ko0i0y6WJApQhgeDuv dSuuXNwc1S9sF2OPHagxLtZK5SQxv2RB7rvLeprO0SULk5c1ziToFtwgLwx6Mhtwt3 CVuostdSY6ekvyDf/ziLxQeCYra0d8q55SUfhDb6MIXF0VAUt7rSc80SoNAYI/SYwV edaXD0GRdKDr2wTNObIeQtnMnyyLfjZSymJZGOoxaxyP5zbDQKFDYNryl8R4Wtksxn rgPQ5OcfUQe6rGQs95ZBRVHCBYSi/WEnvhDOEsPdeePdAkynFY7PNPQROX5H7lwGw5 bH3fBdqc/zY6Q== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v4 12/23] mtd: nand: denali: fix NAND_CMD_STATUS handling Date: Tue, 6 Jun 2017 08:21:51 +0900 Message-Id: <1496704922-12261-13-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The current NAND_CMD_STATUS handling is weird; it just reads the WRITE_PROTECT register, and returns NAND_STATUS_WP if it is set. It does not send Read Status (0x70) command, so it is not helpful for checking the current device status. Signed-off-by: Masahiro Yamada --- Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index e8e6667..372c871 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -107,21 +107,6 @@ static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte) denali->buf.buf[denali->buf.tail++] = byte; } -/* reads the status of the device */ -static void read_status(struct denali_nand_info *denali) -{ - uint32_t cmd; - - /* initialize the data buffer to store status */ - reset_buf(denali); - - cmd = ioread32(denali->flash_reg + WRITE_PROTECT); - if (cmd) - write_byte_to_buf(denali, NAND_STATUS_WP); - else - write_byte_to_buf(denali, 0); -} - /* Reset the flash controller */ static uint16_t denali_nand_reset(struct denali_nand_info *denali) { @@ -893,7 +878,11 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, switch (cmd) { case NAND_CMD_STATUS: - read_status(denali); + reset_buf(denali); + addr = MODE_11 | BANK(denali->flash_bank); + index_addr(denali, addr | 0, cmd); + index_addr_read_data(denali, addr | 2, &id); + write_byte_to_buf(denali, id); break; case NAND_CMD_READID: case NAND_CMD_PARAM: From patchwork Mon Jun 5 23:21:52 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103121 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1009894obh; Mon, 5 Jun 2017 16:30:22 -0700 (PDT) X-Received: by 10.101.72.207 with SMTP id o15mr23733240pgs.212.1496705422743; Mon, 05 Jun 2017 16:30:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705422; cv=none; d=google.com; s=arc-20160816; b=IFOFmURv7rDn+9xoxLKxrvoC5ZGMKSxI0UfoBt+kqBBTwrXuDE4dyW1n9ee5OgDjzT Z7sEiutM2JRHng/ym6uSE1zPaknYOKI2jNbfteaPb76douJ5Q/MlmK6HGEbfcl1eL12O 2ohDUhq7Rhz+2jhCi1+kJBPzTd5I+dYXdLoV4kwDbEYhSklDuLl9NASbBzfZmDsZqiVg hW+w7rqi5+yoAS2e3+cvM/ACMiItHobKrkBDHhN3lFEdRga2wswEZEziU0wr4df6avTN pJqFPR4+AfuKhG8HXfZp3ZCaUMM136AW6lCioABToJdmayRJbNRAzJnYC2/ScIA3a796 q71A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=DSIxLbvLjPd/ns94v8fBY8T4LolKvoCqGEefiQK1RJM=; b=Z0fvIGTu5KDrQfMK6KMhChHwxRFl6nRil80WPYEomelm+ySdKano1kY1JHI8YXZ33W /aEHrnAiVFM2KUAUzTTugUbVm8ZKt6glj0fXvjhti7qRRWPS9A4nx3rqLAW75iYQWIzs fNeHiJwJRDXQcjgbS/i+i2z+VZpSEpvVAlVyZG6Hp1XRZD9Nn446/9UNbIuPRXP66heE m7b7a5+3h3NOhxUbTb9AIsTy9NLFXCYEozSs0HV+OMNt1FM5/1WSsnlEYAk91Exy2vmN XrraQUqllcUn5eUv/1Eh7BhcQO1lgy58OXQdu89xAomK/Ku4Fs4M1tYbGxMu9pVOIgkY RUJw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id z2si9975978pge.206.2017.06.05.16.30.22; Mon, 05 Jun 2017 16:30:22 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751388AbdFEX3y (ORCPT + 25 others); Mon, 5 Jun 2017 19:29:54 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:32133 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751279AbdFEXZR (ORCPT ); Mon, 5 Jun 2017 19:25:17 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5n004412; Tue, 6 Jun 2017 08:22:42 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5n004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704963; bh=DSIxLbvLjPd/ns94v8fBY8T4LolKvoCqGEefiQK1RJM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dYy3dqGz7tzTbbGOaFIeSR6/QtEdAMXkv8+8+6haQ+u9LTMa4tOS22txDlHNhE02t jBhY71d6ATMegJCYFX+su6s0/FKSc0IChF0SV0I4YZhHYrIt1K6HWEolL9dA2kk6fH ETAP5u/Ka6z4mB4+2BnnArgy6aQ/Cp3ITArBM9FwymShHpI4qE+HBAkvDTwsCskSDo 6zRwTB9x3r9ZZSL/GbE0U1whU2CRnkCNbECAFdkJoBBI2WhKfQN3BO10bkN/EJ+mN7 xByircnjdZ/Lv2Ybh4Q1L9TsE4e8VScYek1aF2UxitezqoD97zOCfOW3jKZEP8nLGD Y+8+qmjieNDrQ== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v4 13/23] mtd: nand: denali: fix NAND_CMD_PARAM handling Date: Tue, 6 Jun 2017 08:21:52 +0900 Message-Id: <1496704922-12261-14-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org NAND_CMD_PARAM is not working at all due to multiple bugs. [1] The command 0x90 issued instead of 0xec The command code 0x90 is hard-code as index_addr(denali, addr | 0, 0x90) So, Read ID (0x90) command is sent to the device instead of Read Parameter Page (0xec). [2] only first 8 bytes are read Even if [1] is fixed, the current implementation is problematic. The only first 8 bytes are read by MAP11 command, and put into the temporal buffer: for (i = 0; i < 8; i++) { index_addr_read_data(denali, addr | 2, &id); write_byte_to_buf(denali, id); } Obviously, this is not sufficient for NAND_CMD_PARAM; the ONFi parameters are 256-byte long. This is still insufficient. As you see in nand_flash_detect_onfi() reads out (256 * 3) bytes at maximum (Redundant Parameter Pages). However, changing the loop to for (i = 0; i < 768; i++) is a crazy idea. At the point of the chip->cmdfunc() call, we cannot know how many times chip->read_byte() will be called. So, pre-reading enough number of bytes in the chip->cmdfunc() is a design mistake. [3] no wait for R/B# The current code handles NAND_CMD_READID and NAND_CMD_PARAM in the same way, but this is also wrong. The difference between them is that Read ID command does not toggle R/B# whereas the Read Parameter Page command requires R/B#. Without the wait for R/B# interrupt, wrong data are retrieved. In order to fix those problems, data read cycle of the MAP11 command has been moved to chip->read_byte(). Data are read out as needed. Another good thing is early temporal buffer is not needed any more. The ugly devm_kzalloc()/devm_kfree() dance has been killed. Signed-off-by: Masahiro Yamada --- Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 95 +++++++++++++++-------------------------------- drivers/mtd/nand/denali.h | 2 - 2 files changed, 30 insertions(+), 67 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 372c871..4d46202 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -85,28 +85,6 @@ static void index_addr(struct denali_nand_info *denali, iowrite32(data, denali->flash_mem + 0x10); } -/* Perform an indexed read of the device */ -static void index_addr_read_data(struct denali_nand_info *denali, - uint32_t address, uint32_t *pdata) -{ - iowrite32(address, denali->flash_mem); - *pdata = ioread32(denali->flash_mem + 0x10); -} - -/* - * We need to buffer some data for some of the NAND core routines. - * The operations manage buffering that data. - */ -static void reset_buf(struct denali_nand_info *denali) -{ - denali->buf.head = denali->buf.tail = 0; -} - -static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte) -{ - denali->buf.buf[denali->buf.tail++] = byte; -} - /* Reset the flash controller */ static uint16_t denali_nand_reset(struct denali_nand_info *denali) { @@ -286,6 +264,15 @@ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, iowrite32(transfer_spare_flag, denali->flash_reg + TRANSFER_SPARE_REG); } +static uint8_t denali_read_byte(struct mtd_info *mtd) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + + iowrite32(MODE_11 | BANK(denali->flash_bank) | 2, denali->flash_mem); + + return ioread32(denali->flash_mem + 0x10); +} + /* * sends a pipeline command operation to the controller. See the Denali NAND * controller's user guide for more information (section 4.2.3.6). @@ -828,17 +815,6 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, return 0; } -static uint8_t denali_read_byte(struct mtd_info *mtd) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - uint8_t result = 0xff; - - if (denali->buf.head < denali->buf.tail) - result = denali->buf.buf[denali->buf.head++]; - - return result; -} - static void denali_select_chip(struct mtd_info *mtd, int chip) { struct denali_nand_info *denali = mtd_to_denali(mtd); @@ -873,43 +849,40 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t addr, id; - int i; + uint32_t addr, irq_status; + int wait_ready = 0; switch (cmd) { - case NAND_CMD_STATUS: - reset_buf(denali); - addr = MODE_11 | BANK(denali->flash_bank); - index_addr(denali, addr | 0, cmd); - index_addr_read_data(denali, addr | 2, &id); - write_byte_to_buf(denali, id); + case NAND_CMD_PARAM: + wait_ready = 1; break; + case NAND_CMD_STATUS: case NAND_CMD_READID: - case NAND_CMD_PARAM: - reset_buf(denali); - /* - * sometimes ManufactureId read from register is not right - * e.g. some of Micron MT29F32G08QAA MLC NAND chips - * So here we send READID cmd to NAND insteand - */ - addr = MODE_11 | BANK(denali->flash_bank); - index_addr(denali, addr | 0, 0x90); - index_addr(denali, addr | 1, col); - for (i = 0; i < 8; i++) { - index_addr_read_data(denali, addr | 2, &id); - write_byte_to_buf(denali, id); - } break; case NAND_CMD_RESET: reset_bank(denali); break; case NAND_CMD_READOOB: /* TODO: Read OOB data */ - break; + return; default: pr_err(": unsupported command received 0x%x\n", cmd); - break; + return; } + + denali_reset_irq(denali); + + addr = MODE_11 | BANK(denali->flash_bank); + index_addr(denali, addr | 0, cmd); + if (col != -1) + index_addr(denali, addr | 1, col); + + if (!wait_ready) + return; + + irq_status = denali_wait_for_irq(denali, INTR__INT_ACT); + if (!(irq_status & INTR__INT_ACT)) + dev_err(denali->dev, "failed to issue command 0x%x\n", cmd); } #define DIV_ROUND_DOWN_ULL(ll, d) \ @@ -1244,12 +1217,6 @@ int denali_init(struct denali_nand_info *denali) struct mtd_info *mtd = nand_to_mtd(chip); int ret; - /* allocate a temporary buffer for nand_scan_ident() */ - denali->buf.buf = devm_kzalloc(denali->dev, PAGE_SIZE, - GFP_DMA | GFP_KERNEL); - if (!denali->buf.buf) - return -ENOMEM; - mtd->dev.parent = denali->dev; denali_hw_init(denali); denali_drv_init(denali); @@ -1289,8 +1256,6 @@ int denali_init(struct denali_nand_info *denali) if (ret) goto disable_irq; - /* allocate the right size buffer now */ - devm_kfree(denali->dev, denali->buf.buf); denali->buf.buf = devm_kzalloc(denali->dev, mtd->writesize + mtd->oobsize, GFP_KERNEL); diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index a46473a..54f21f4 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -306,8 +306,6 @@ #define MODE_11 0x0C000000 struct nand_buf { - int head; - int tail; uint8_t *buf; dma_addr_t dma_buf; }; From patchwork Mon Jun 5 23:21:53 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103101 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1008517obh; Mon, 5 Jun 2017 16:25:45 -0700 (PDT) X-Received: by 10.84.218.8 with SMTP id q8mr17832179pli.135.1496705145154; Mon, 05 Jun 2017 16:25:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705145; cv=none; d=google.com; s=arc-20160816; b=CGRFLQCUUB31TUMPl/lQ7y70SHYWLOup7jpNUAwK9wvbqNwDbjdAbNpia5FttZekCq 7AI+JNhnTR2LTm3KJKjk+NM4Jn9UNrrbVoHz/GYG3m9AelGucowTTf0mx5Togf2/rq/v qzpxpey+lia8AEjTpns4zM/oaAlkjWLIZoH9O3htkNMkhqnrrL5rhoFoi+r8OsckXo3c yIU7R5I22vRI5sfEiWcOTrkGAWGUTC0AqNmjXdLAqTZyx84fDq3HEvWw7NTc2FshWaDK p350cYKtbw3XteoErSuFnwvhExlL5dz0IQhwmmQoU5o6xCK1Opm5Cn2CO7iuoVlDrJyJ QQKw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=/fsVBEcNz1BAkf+t3CMO31hBKIYSvE9lyaCGs7G3+WY=; b=nO640yl5fW/+fmh+CurcN80axk1zrvhpYy5nC5oi9CteseyZNv8QRMy6o94a2U72zj qt2pLqWUXIFGGz7tkrYJ94L0VZvBSohJJmm07n1nHpTyBszmmLlTEiQZZzPELhYzEvI3 O74O1JgamGFva3WEZWvXovXwTRJcxaqdrFd1Y1BgXYj5Y7g5Ug3quUaE9IYJWvzlpvvd ixJE/lsjvZH2DjwXGb0Imh8DZ2CctB2CDCxowGWEx2ONgjFMlayiGYpWt9K7J9dpriO3 EsjmFYLW/5oxt89DVjCPxZRkbSlX8+mpgMYZJ7MCPY8gbfCJv8DdSWomxYsVa2oU+MDx 3T1Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id q20si10759518pfl.414.2017.06.05.16.25.44; Mon, 05 Jun 2017 16:25:45 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751380AbdFEXZZ (ORCPT + 25 others); Mon, 5 Jun 2017 19:25:25 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:32337 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751350AbdFEXZX (ORCPT ); Mon, 5 Jun 2017 19:25:23 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5o004412; Tue, 6 Jun 2017 08:22:44 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5o004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704964; bh=/fsVBEcNz1BAkf+t3CMO31hBKIYSvE9lyaCGs7G3+WY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=x56mIGQ1B4VCpsacELNKvuxlaPr9m6qYUNZyIC9XwbF3zA+EgKqURRL2yuBjSC81q fFxveju7SrbttCScUyOnT5eGpybtJu7iFmFJ4SCuViLg0ZBESkPVJbs9LQcZvl+s6e 7tUK9Yzgl/W0a5uPAozGuIe8c6FjXa21NzRou38I+YOingpmRdvJ97pkFmt+5yw1Pt DOa93D3l7rkWZv6T6zOMiJSNvew7+XozGYLOxSK0lccRXfv20XAuOuoeldUHlIyvew fEwaF+h1YqWWVPtQ+4U1tMkMV9YznJ7yk+MVHcgioOzZr49PgQLCgulFJOgkBBEt6h z+G7gW01i3s0A== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v4 14/23] mtd: nand: denali: switch over to cmd_ctrl instead of cmdfunc Date: Tue, 6 Jun 2017 08:21:53 +0900 Message-Id: <1496704922-12261-15-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The NAND_CMD_SET_FEATURES support is missing from denali_cmdfunc(). This is needed for nand_onfi_set_features(). Besides, we see /* TODO: Read OOB data */ comment line. It would be possible to add more commands along with the current implementation, but having ->cmd_ctrl() seems a better approach from the discussion with Boris [1]. Rely on the default ->cmdfunc() from the framework and implement the driver's own ->cmd_ctrl(). Also add ->write_byte(), which is needed for write direction commands. [1] https://lkml.org/lkml/2017/3/15/97 Signed-off-by: Masahiro Yamada --- Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 104 +++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 52 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 4d46202..083dfc7 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -230,20 +230,16 @@ static uint32_t denali_wait_for_irq(struct denali_nand_info *denali, return denali->irq_status; } -/* resets a specific device connected to the core */ -static void reset_bank(struct denali_nand_info *denali) +static uint32_t denali_check_irq(struct denali_nand_info *denali) { + unsigned long flags; uint32_t irq_status; - denali_reset_irq(denali); - - iowrite32(1 << denali->flash_bank, denali->flash_reg + DEVICE_RESET); - - irq_status = denali_wait_for_irq(denali, - INTR__RST_COMP | INTR__TIME_OUT); + spin_lock_irqsave(&denali->irq_lock, flags); + irq_status = denali->irq_status; + spin_unlock_irqrestore(&denali->irq_lock, flags); - if (!(irq_status & INTR__RST_COMP)) - dev_err(denali->dev, "reset bank failed.\n"); + return irq_status; } /* @@ -273,6 +269,42 @@ static uint8_t denali_read_byte(struct mtd_info *mtd) return ioread32(denali->flash_mem + 0x10); } +static void denali_write_byte(struct mtd_info *mtd, uint8_t byte) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + + index_addr(denali, MODE_11 | BANK(denali->flash_bank) | 2, byte); +} + +static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + uint32_t type; + + if (ctrl & NAND_CLE) + type = 0; + else if (ctrl & NAND_ALE) + type = 1; + else + return; + + /* + * Some commands are followed by chip->dev_ready or chip->waitfunc. + * irq_status must be cleared here to catch the R/B# interrupt later. + */ + if (ctrl & NAND_CTRL_CHANGE) + denali_reset_irq(denali); + + index_addr(denali, MODE_11 | BANK(denali->flash_bank) | type, dat); +} + +static int denali_dev_ready(struct mtd_info *mtd) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + + return !!(denali_check_irq(denali) & INTR__INT_ACT); +} + /* * sends a pipeline command operation to the controller. See the Denali NAND * controller's user guide for more information (section 4.2.3.6). @@ -824,7 +856,13 @@ static void denali_select_chip(struct mtd_info *mtd, int chip) static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) { - return 0; + struct denali_nand_info *denali = mtd_to_denali(mtd); + uint32_t irq_status; + + /* R/B# pin transitioned from low to high? */ + irq_status = denali_wait_for_irq(denali, INTR__INT_ACT); + + return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL; } static int denali_erase(struct mtd_info *mtd, int page) @@ -845,46 +883,6 @@ static int denali_erase(struct mtd_info *mtd, int page) return irq_status & INTR__ERASE_COMP ? 0 : NAND_STATUS_FAIL; } -static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, - int page) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t addr, irq_status; - int wait_ready = 0; - - switch (cmd) { - case NAND_CMD_PARAM: - wait_ready = 1; - break; - case NAND_CMD_STATUS: - case NAND_CMD_READID: - break; - case NAND_CMD_RESET: - reset_bank(denali); - break; - case NAND_CMD_READOOB: - /* TODO: Read OOB data */ - return; - default: - pr_err(": unsupported command received 0x%x\n", cmd); - return; - } - - denali_reset_irq(denali); - - addr = MODE_11 | BANK(denali->flash_bank); - index_addr(denali, addr | 0, cmd); - if (col != -1) - index_addr(denali, addr | 1, col); - - if (!wait_ready) - return; - - irq_status = denali_wait_for_irq(denali, INTR__INT_ACT); - if (!(irq_status & INTR__INT_ACT)) - dev_err(denali->dev, "failed to issue command 0x%x\n", cmd); -} - #define DIV_ROUND_DOWN_ULL(ll, d) \ ({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; }) @@ -1240,8 +1238,10 @@ int denali_init(struct denali_nand_info *denali) /* register the driver with the NAND core subsystem */ chip->select_chip = denali_select_chip; - chip->cmdfunc = denali_cmdfunc; chip->read_byte = denali_read_byte; + chip->write_byte = denali_write_byte; + chip->cmd_ctrl = denali_cmd_ctrl; + chip->dev_ready = denali_dev_ready; chip->waitfunc = denali_waitfunc; /* clk rate info is needed for setup_data_interface */ if (denali->clk_x_rate) From patchwork Mon Jun 5 23:21:54 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103111 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1009064obh; Mon, 5 Jun 2017 16:27:42 -0700 (PDT) X-Received: by 10.84.178.4 with SMTP id y4mr18186376plb.158.1496705262502; Mon, 05 Jun 2017 16:27:42 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705262; cv=none; d=google.com; s=arc-20160816; b=MrJgCH1Rl2YnP9sYnlO+s0uijqmUxVePQIazCAx1nNYBSwwED2eRxGnPtEfQctKr0k stkxqnt8XyVf2lAgAkamffnY+blhPsjPNqA07YzxlSmBxG1sGIgQ8/eRp16APJ/mnlC9 1/JvNwOfp/6f0BUD0nkSgYY5YWUyW++e7IDrXZoxra6WUfxMB+r1c75gyk+Mwdo7HRhP tn1uiW1z2OyywLjCR37kSmhF6hKCcNAhXyb5GU21NwfJC54ESPE9WTcUpb5ARxtHxuGJ SBRkDK1vlSOHdW5p+avBEkzmWuDXN39her9W43VdQZIYrVzGsD48KDuKkrJZvfBTdRbK ZxLA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=FHqmp2kVG0rcDHKXNVG+Q/0fotjs/HIOXTrh55tzCqk=; b=a1eQqrYSTbhybt8rKBDdBHESngyGJLZr3hcCbF0bSDgSBeZEqH/wkPjOCEIvqNxLyg lk8C3nDUQz9ZNShxkmjatkgFuL9j7me7yc5rwxRh+slj7nuZMu+s0hQcNeVE6Pds54KC frg6TKwLiOYzF/W/ykcoyonMEuPqdoqbSIVtx9H52RKCv1FD0DnP1YYN4ak7DKK8ZGWg GFv2ikLP8F5UKzaFTJzx8gWjRoIm3AFmAlw5s/y7TpkLoMmSM1eEvuhJr6DvdpLm3h8T 6HjmRMK+UP6JYD3xi72vunIqHHQUwdwvU9KUz9f0KPSy5OPx06teiG676ASk2goVTnnL pr1A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 84si31596096pfa.395.2017.06.05.16.27.42; Mon, 05 Jun 2017 16:27:42 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751342AbdFEXZV (ORCPT + 25 others); Mon, 5 Jun 2017 19:25:21 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:32119 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751264AbdFEXZQ (ORCPT ); Mon, 5 Jun 2017 19:25:16 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5p004412; Tue, 6 Jun 2017 08:22:45 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5p004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704966; bh=FHqmp2kVG0rcDHKXNVG+Q/0fotjs/HIOXTrh55tzCqk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Jtqs8CjW4MdWgd/Np4CTvKbJHtRuvXbcwO7ONIGFtpwzrP++SJuXKBxKyeq/m6whd 8zcpkr2hEoXR9C5VZr/SkiMtkE3sS3l3Chxga2X+sDPZ8QUdOiIowOzwuT7E17iTke Pg7m7Nik6HzQHhvfXpp/sAvpqQlvrIjGWIg3AMuSivwg49uVCMkJ+ObAhNEtBrtULz 2S2G/0VAIKchm/HXUJWueoMUy5KLuu2Avv9DvKrUUvvyZF+WfloJqfKu6aIIT3E1p4 t00UpTMkLq10INj1W3dOQutT7se2E7Aaq4YWfUUlCFsTqoJcq1pTbPxAV6cjxQ0rP0 X3lAUR0oX4kWA== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v4 15/23] mtd: nand: denali: fix bank reset function to detect the number of chips Date: Tue, 6 Jun 2017 08:21:54 +0900 Message-Id: <1496704922-12261-16-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The nand_scan_ident() iterates over maxchips, and calls nand_reset() for each. This driver currently passes the maximum number of banks (=chip selects) supported by the controller as maxchips. So, maxchips is typically 4 or 8. Usually, less number of NAND chips are connected to the controller. This can be a problem for ONFi devices. Now, this driver implements ->setup_data_interface() hook, so nand_setup_data_interface() issues Set Features (0xEF) command, which waits until the chip returns R/B# response. If no chip there, we know it never happens, but the driver still ends up with waiting for a long time. It will finally bail-out with timeout error and the driver will work with existing chips, but unnecessary wait will give a bad user experience. The denali_nand_reset() polls the INTR__RST_COMP and INTR__TIME_OUT bits, but they are always set even if not NAND chip is connected to that bank. To know the chip existence, INTR__INT_ACT bit must be checked; this flag is set only when R/B# is toggled. Since the Reset (0xFF) command toggles the R/B# pin, this can be used to know the actual number of chips, and update denali->max_banks. Signed-off-by: Masahiro Yamada --- Boris mentioned this information can be retrieved from DT (http://patchwork.ozlabs.org/patch/745118/), but I'd like to take time for controller/chip decoupling. I am tackling on that, but not completed yet. I believe this commit stands for denali_pci, at least I do not know how to get the number of chips from PCI. Changes in v4: - Reword commit-log Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 52 +++++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 29 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 083dfc7..775387e 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -85,33 +85,6 @@ static void index_addr(struct denali_nand_info *denali, iowrite32(data, denali->flash_mem + 0x10); } -/* Reset the flash controller */ -static uint16_t denali_nand_reset(struct denali_nand_info *denali) -{ - int i; - - for (i = 0; i < denali->max_banks; i++) - iowrite32(INTR__RST_COMP | INTR__TIME_OUT, - denali->flash_reg + INTR_STATUS(i)); - - for (i = 0; i < denali->max_banks; i++) { - iowrite32(1 << i, denali->flash_reg + DEVICE_RESET); - while (!(ioread32(denali->flash_reg + INTR_STATUS(i)) & - (INTR__RST_COMP | INTR__TIME_OUT))) - cpu_relax(); - if (ioread32(denali->flash_reg + INTR_STATUS(i)) & - INTR__TIME_OUT) - dev_dbg(denali->dev, - "NAND Reset operation timed out on bank %d\n", i); - } - - for (i = 0; i < denali->max_banks; i++) - iowrite32(INTR__RST_COMP | INTR__TIME_OUT, - denali->flash_reg + INTR_STATUS(i)); - - return PASS; -} - /* * Use the configuration feature register to determine the maximum number of * banks that the hardware supports. @@ -999,7 +972,28 @@ static int denali_setup_data_interface(struct mtd_info *mtd, return 0; } -/* Initialization code to bring the device up to a known good state */ +static void denali_reset_banks(struct denali_nand_info *denali) +{ + int i; + + denali_clear_irq_all(denali); + + for (i = 0; i < denali->max_banks; i++) { + iowrite32(1 << i, denali->flash_reg + DEVICE_RESET); + while (!(ioread32(denali->flash_reg + INTR_STATUS(i)) & + (INTR__RST_COMP | INTR__TIME_OUT))) + cpu_relax(); + if (!(ioread32(denali->flash_reg + INTR_STATUS(i)) & + INTR__INT_ACT)) + break; + } + + dev_dbg(denali->dev, "%d chips connected\n", i); + denali->max_banks = i; + + denali_clear_irq_all(denali); +} + static void denali_hw_init(struct denali_nand_info *denali) { /* @@ -1019,7 +1013,7 @@ static void denali_hw_init(struct denali_nand_info *denali) denali->bbtskipbytes = ioread32(denali->flash_reg + SPARE_AREA_SKIP_BYTES); detect_max_banks(denali); - denali_nand_reset(denali); + denali_reset_banks(denali); iowrite32(0x0F, denali->flash_reg + RB_PIN_ENABLED); iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->flash_reg + CHIP_ENABLE_DONT_CARE); From patchwork Mon Jun 5 23:21:55 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103122 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1010052obh; Mon, 5 Jun 2017 16:30:42 -0700 (PDT) X-Received: by 10.84.140.3 with SMTP id 3mr18220308pls.113.1496705442720; Mon, 05 Jun 2017 16:30:42 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705442; cv=none; d=google.com; s=arc-20160816; b=gBk6cmnbcXnFhkt5UTR8wdHNNFKjehu+16G0xegYwNw7TfBoDE2zKZ++XISMJuZdWl yETFyUI2xrfpn0siCkZn0yTh+aTRLYe+1n809j+1dNfik6MBnfifGaJr9REYTTT0PQNC 4SQX2A2Ept6Fa7u1jJZn37NMLitaxYDXDJ/aRWYV+7naaOCrswpLYHqtwBsO2JPHm+9e B4iHVvC2yEKpivNRocVYv6e8BV6BpTBc+A1LZ/Sd+aS3vkj77Xbe+/PLRjB5B3B8Qyen 1EWSaL9Z17udhLJGrVsPFWBU6KMjiIIYL+J5OrecxoJ6zCqghiqWYM9RlVOrifxJTnFs 41TA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=ioHATIe0D4te+RJYsAFe1Fb/iNacXfw8H5EyHEusCc8=; b=iO06cSgOuFtFyBYijpBV0GGNDtC6P0UcJQaoKPStdefh67BGCkRvrRN0brW5Tb26D2 iVKtM+IDZDJD4Fupj/nqv0VK52B816bI+jmD/znE71VNkvn8obhO0G1JYn/A0WPcRYXn wunJKm4fxdsCdxQusMD/aJdKv39rZtRL6ZU3nkvN1AJfwEoIhq7oGim9btCxZUHxc9Wa mPmoayXHo2FbnXHWEO/9f/FUUCuoMz0WLMPkkKuw3Bn4xvlrgwIvgkhTHaDcijcbEUoN e/n2v21Gd2In3FQA9ozHv5RmqYpz6tNoACwCtjuyORQ+y3XW0SnNLYrwgDnpLFqnh8V4 gRzg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id a3si8396013plc.494.2017.06.05.16.30.42; Mon, 05 Jun 2017 16:30:42 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751357AbdFEXaL (ORCPT + 25 others); Mon, 5 Jun 2017 19:30:11 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:32130 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751278AbdFEXZQ (ORCPT ); Mon, 5 Jun 2017 19:25:16 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5q004412; Tue, 6 Jun 2017 08:22:46 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5q004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704967; bh=ioHATIe0D4te+RJYsAFe1Fb/iNacXfw8H5EyHEusCc8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bWWN0dyWHicjtySADcQG/3no65t92pnbAd/iY7kDsqv4AdRdxr6gAwrRLEjCZezpi 1/5y7L4Ejt7WylwGyxGpgHAjsGb6mhBJ49TXne0J74ap6US5EydyaCQeQcLF3Cs6WC T4Z3Ao2tID2VDLORgbXt+er99UD032Ou161h+Q8zS1iwonHn3EvudHEy6h34hcCrak kZM9ahBAQisKAKcqwDG4IHqc+7pV6m9sfRvlTcB5Ld7ALiOOmww3tggk44PhFg0iL1 F8rqX5cJ9PRs4GAADFDE6RSrCrS+wZQfLfs07cvWv+EuPz/8pSXfEMgD+bhzzLsf4u Oz3Gy7LgJ/3Sw== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v4 16/23] mtd: nand: denali: use interrupt instead of polling for bank reset Date: Tue, 6 Jun 2017 08:21:55 +0900 Message-Id: <1496704922-12261-17-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The current bank reset implementation polls the INTR_STATUS register until interested bits are set. This is not good because: - polling simply wastes time-slice of the thread - The while() loop may continue eternally if no bit is set, for example, due to the controller problem. The denali_wait_for_irq() uses wait_for_completion_timeout(), which is safer. We can use interrupt by moving the denali_reset_bank() call below the interrupt setup. Signed-off-by: Masahiro Yamada --- Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 775387e..6dee168 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -974,24 +974,25 @@ static int denali_setup_data_interface(struct mtd_info *mtd, static void denali_reset_banks(struct denali_nand_info *denali) { + u32 irq_status; int i; - denali_clear_irq_all(denali); - for (i = 0; i < denali->max_banks; i++) { - iowrite32(1 << i, denali->flash_reg + DEVICE_RESET); - while (!(ioread32(denali->flash_reg + INTR_STATUS(i)) & - (INTR__RST_COMP | INTR__TIME_OUT))) - cpu_relax(); - if (!(ioread32(denali->flash_reg + INTR_STATUS(i)) & - INTR__INT_ACT)) + denali->flash_bank = i; + + denali_reset_irq(denali); + + iowrite32(DEVICE_RESET__BANK(i), + denali->flash_reg + DEVICE_RESET); + + irq_status = denali_wait_for_irq(denali, + INTR__RST_COMP | INTR__INT_ACT | INTR__TIME_OUT); + if (!(irq_status & INTR__INT_ACT)) break; } dev_dbg(denali->dev, "%d chips connected\n", i); denali->max_banks = i; - - denali_clear_irq_all(denali); } static void denali_hw_init(struct denali_nand_info *denali) @@ -1013,7 +1014,6 @@ static void denali_hw_init(struct denali_nand_info *denali) denali->bbtskipbytes = ioread32(denali->flash_reg + SPARE_AREA_SKIP_BYTES); detect_max_banks(denali); - denali_reset_banks(denali); iowrite32(0x0F, denali->flash_reg + RB_PIN_ENABLED); iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->flash_reg + CHIP_ENABLE_DONT_CARE); @@ -1147,9 +1147,6 @@ static void denali_drv_init(struct denali_nand_info *denali) * element that might be access shared data (interrupt status) */ spin_lock_init(&denali->irq_lock); - - /* indicate that MTD has not selected a valid bank yet */ - denali->flash_bank = CHIP_SELECT_INVALID; } static int denali_multidev_fixup(struct denali_nand_info *denali) @@ -1224,6 +1221,9 @@ int denali_init(struct denali_nand_info *denali) } denali_enable_irq(denali); + denali_reset_banks(denali); + + denali->flash_bank = CHIP_SELECT_INVALID; nand_set_flash_node(chip, denali->dev->of_node); /* Fallback to the default name if DT did not give "label" property */ From patchwork Mon Jun 5 23:21:56 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103118 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1009591obh; Mon, 5 Jun 2017 16:29:31 -0700 (PDT) X-Received: by 10.98.157.74 with SMTP id i71mr13022581pfd.141.1496705371654; Mon, 05 Jun 2017 16:29:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705371; cv=none; d=google.com; s=arc-20160816; b=qlHfDY80lxcy+YUxVqxAeOqnp3tOMhjPygsWtiNRjoYDAhqoOmaJw1yQ8BaetoZpHj Pvav8rY0I7npIOgQS7dEIomQQkGMsN3WCaS9x1S6RKVAagr475etEiWlDfiuHhpy6zHE jkpkeYRFCA4mw6NiR6yJP8UgvzHToY1MOJ2WaJW53jLEQm08t7o7CYWn3ObKSPcJyEpG RhkgQ9xRkXHWjTnBXpOd0Qh+7KDjb6yMoWJl4xlyKRvsNg8ndSTYe8zN95gJIW+JZj2Y TyNG7WvFECvVLxEar6VtmO3y0k95tssw/mSb8G6AxAY/PRNjXU8hB3uLq6XYYWG6Au3E UNxA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=R6ogoj9mWINYONarnwUY8tVwnNURaUuQLR5ceaPKiwM=; b=We+7npk5PoMAUGnbgRiMjYHOqyUAHaLmxFn3iBqR3y0MUkkljfHBl2ZV+21LMXzLa6 kJ3KyqzutmfyQQlbowl89vVJxPYxrsLME3OZ4iyRfn9a20sUV38onZJL5aXjBxblgL0o HoJkOTTsfpfb/fbu1ka+WPlXjd7KM8nL7kIFv01X45secRWYYk+VoKsDcJnHg+Q8RvWM v3G9hNuPSvERhDZNLuyjCDUD+No7GJdg3VoF05LKTJFMxouDIXyMsmsCwYvMj5b3wEG/ h/ogy36O/ZTGijgp+mDONYfkd70soK7wU6OMuGXTaJTT7DZxRomU0nONjvtXqcUie9EM TEbQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id s4si2756254pfi.251.2017.06.05.16.29.31; Mon, 05 Jun 2017 16:29:31 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751577AbdFEX3S (ORCPT + 25 others); Mon, 5 Jun 2017 19:29:18 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:32139 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751284AbdFEXZR (ORCPT ); Mon, 5 Jun 2017 19:25:17 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5r004412; Tue, 6 Jun 2017 08:22:47 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5r004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704968; bh=R6ogoj9mWINYONarnwUY8tVwnNURaUuQLR5ceaPKiwM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=q1xpVVZOypnqCrQXy0qC8ydacM0riBPb5p0+xG/uG/X7nGNjVMqHkeJ9ItvdnXJ6g DmI9PDsgrhL3n7R7I+1vpwevSDcG/D77j9I6jE0mm3TG5PblZL543AAsFC5FfkEDL+ No2m7l4TifHI+4FMzYbBSmHiLSSMhsM63s8eK1pqZP+FKH+pP63vzvfVLgB36sjio0 PPbeZ9l+fqPDTa1TYAhMc7S9F/vSRoFiDpRMGv2uel2dkEA+43VDBw30Qi0/zonLiU wj4SzBjHPu8lmGyvXfQ8t3XdLxyGNrx64uFx6ifDnDmfJ6G9yW3uOLFFw0ZgNVPurT Ete2E+gHIVsDw== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v4 17/23] mtd: nand: denali: propagate page to helpers via function argument Date: Tue, 6 Jun 2017 08:21:56 +0900 Message-Id: <1496704922-12261-18-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This driver stores the currently addressed page into denali->page, which is later read out by helper functions. While I am tackling on this driver, I often missed to insert "denali->page = page;" where needed. This makes page_read/write callbacks to get access to a wrong page, which is a bug hard to figure out. Instead, I'd rather pass the page via function argument because the compiler's prototype checks will help to detect bugs. For the same reason, propagate dma_addr to the DMA helpers instead of denali->buf.dma_buf . Signed-off-by: Masahiro Yamada --- Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 58 ++++++++++++++++++++--------------------------- drivers/mtd/nand/denali.h | 1 - 2 files changed, 24 insertions(+), 35 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 6dee168..af60b1e 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -282,7 +282,7 @@ static int denali_dev_ready(struct mtd_info *mtd) * sends a pipeline command operation to the controller. See the Denali NAND * controller's user guide for more information (section 4.2.3.6). */ -static int denali_send_pipeline_cmd(struct denali_nand_info *denali, +static int denali_send_pipeline_cmd(struct denali_nand_info *denali, int page, bool ecc_en, bool transfer_spare, int access_type, int op) { @@ -293,7 +293,7 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, denali_reset_irq(denali); - addr = BANK(denali->flash_bank) | denali->page; + addr = BANK(denali->flash_bank) | page; if (op == DENALI_WRITE && access_type != SPARE_ACCESS) { cmd = MODE_01 | addr; @@ -366,9 +366,7 @@ static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) uint32_t irq_mask = INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL; int status = 0; - denali->page = page; - - if (denali_send_pipeline_cmd(denali, false, false, SPARE_ACCESS, + if (denali_send_pipeline_cmd(denali, page, false, false, SPARE_ACCESS, DENALI_WRITE) == PASS) { write_data_to_flash_mem(denali, buf, mtd->oobsize); @@ -393,9 +391,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) uint32_t irq_mask = INTR__LOAD_COMP; uint32_t irq_status, addr, cmd; - denali->page = page; - - if (denali_send_pipeline_cmd(denali, false, true, SPARE_ACCESS, + if (denali_send_pipeline_cmd(denali, page, false, true, SPARE_ACCESS, DENALI_READ) == PASS) { read_data_from_flash_mem(denali, buf, mtd->oobsize); @@ -407,8 +403,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) irq_status = denali_wait_for_irq(denali, irq_mask); if (!(irq_status & INTR__LOAD_COMP)) - dev_err(denali->dev, "page on OOB timeout %d\n", - denali->page); + dev_err(denali->dev, "page on OOB timeout %d\n", page); /* * We set the device back to MAIN_ACCESS here as I observed @@ -417,7 +412,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) * is reliable (according to the MTD test infrastructure) * if you are in MAIN_ACCESS. */ - addr = BANK(denali->flash_bank) | denali->page; + addr = BANK(denali->flash_bank) | page; cmd = MODE_10 | addr; index_addr(denali, cmd, MAIN_ACCESS); } @@ -582,13 +577,13 @@ static void denali_enable_dma(struct denali_nand_info *denali, bool en) ioread32(denali->flash_reg + DMA_ENABLE); } -static void denali_setup_dma64(struct denali_nand_info *denali, int op) +static void denali_setup_dma64(struct denali_nand_info *denali, + dma_addr_t dma_addr, int page, int op) { uint32_t mode; const int page_count = 1; - uint64_t addr = denali->buf.dma_buf; - mode = MODE_10 | BANK(denali->flash_bank) | denali->page; + mode = MODE_10 | BANK(denali->flash_bank) | page; /* DMA is a three step process */ @@ -599,41 +594,42 @@ static void denali_setup_dma64(struct denali_nand_info *denali, int op) index_addr(denali, mode, 0x01002000 | (64 << 16) | op | page_count); /* 2. set memory low address */ - index_addr(denali, mode, addr); + index_addr(denali, mode, dma_addr); /* 3. set memory high address */ - index_addr(denali, mode, addr >> 32); + index_addr(denali, mode, (uint64_t)dma_addr >> 32); } -static void denali_setup_dma32(struct denali_nand_info *denali, int op) +static void denali_setup_dma32(struct denali_nand_info *denali, + dma_addr_t dma_addr, int page, int op) { uint32_t mode; const int page_count = 1; - uint32_t addr = denali->buf.dma_buf; mode = MODE_10 | BANK(denali->flash_bank); /* DMA is a four step process */ /* 1. setup transfer type and # of pages */ - index_addr(denali, mode | denali->page, 0x2000 | op | page_count); + index_addr(denali, mode | page, 0x2000 | op | page_count); /* 2. set memory high address bits 23:8 */ - index_addr(denali, mode | ((addr >> 16) << 8), 0x2200); + index_addr(denali, mode | ((dma_addr >> 16) << 8), 0x2200); /* 3. set memory low address bits 23:8 */ - index_addr(denali, mode | ((addr & 0xffff) << 8), 0x2300); + index_addr(denali, mode | ((dma_addr & 0xffff) << 8), 0x2300); /* 4. interrupt when complete, burst len = 64 bytes */ index_addr(denali, mode | 0x14000, 0x2400); } -static void denali_setup_dma(struct denali_nand_info *denali, int op) +static void denali_setup_dma(struct denali_nand_info *denali, + dma_addr_t dma_addr, int page, int op) { if (denali->caps & DENALI_CAP_DMA_64BIT) - denali_setup_dma64(denali, op); + denali_setup_dma64(denali, dma_addr, page, op); else - denali_setup_dma32(denali, op); + denali_setup_dma32(denali, dma_addr, page, op); } /* @@ -650,8 +646,6 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, uint32_t irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL; int ret = 0; - denali->page = page; - /* * if it is a raw xfer, we want to disable ecc and send the spare area. * !raw_xfer - enable ecc @@ -674,7 +668,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, denali_reset_irq(denali); denali_enable_dma(denali, true); - denali_setup_dma(denali, DENALI_WRITE); + denali_setup_dma(denali, addr, page, DENALI_WRITE); /* wait for operation to complete */ irq_status = denali_wait_for_irq(denali, irq_mask); @@ -750,15 +744,13 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, unsigned long uncor_ecc_flags = 0; int stat = 0; - denali->page = page; - setup_ecc_for_xfer(denali, true, false); denali_enable_dma(denali, true); dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE); denali_reset_irq(denali); - denali_setup_dma(denali, DENALI_READ); + denali_setup_dma(denali, addr, page, DENALI_READ); /* wait for operation to complete */ irq_status = denali_wait_for_irq(denali, irq_mask); @@ -777,7 +769,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, return stat; if (uncor_ecc_flags) { - read_oob_data(mtd, chip->oob_poi, denali->page); + read_oob_data(mtd, chip->oob_poi, page); stat = denali_check_erased_page(mtd, chip, buf, uncor_ecc_flags, stat); @@ -795,15 +787,13 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint32_t irq_mask = INTR__DMA_CMD_COMP; uint32_t irq_status; - denali->page = page; - setup_ecc_for_xfer(denali, false, true); denali_enable_dma(denali, true); dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE); denali_reset_irq(denali); - denali_setup_dma(denali, DENALI_READ); + denali_setup_dma(denali, addr, page, DENALI_READ); /* wait for operation to complete */ irq_status = denali_wait_for_irq(denali, irq_mask); diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 54f21f4..cb49eb5 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -316,7 +316,6 @@ struct denali_nand_info { int flash_bank; /* currently selected chip */ struct nand_buf buf; struct device *dev; - int page; void __iomem *flash_reg; /* Register Interface */ void __iomem *flash_mem; /* Host Data/Command Interface */ From patchwork Mon Jun 5 23:21:57 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103105 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1008556obh; Mon, 5 Jun 2017 16:25:53 -0700 (PDT) X-Received: by 10.99.218.69 with SMTP id l5mr24132674pgj.88.1496705153146; Mon, 05 Jun 2017 16:25:53 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705153; cv=none; d=google.com; s=arc-20160816; b=lb4wDBvCRcAmrE1eXXCS5ybBh2Jbx/6DAvn83PFC6TyRDfdms18mUfCydUGPRCuZSR eD40cn9AH3kGmA457eROxkukOA923wC2w91uhkgnU9rr/3z9DM9Cy9/hEsCd4t9BKHCY LHyAjiieS7u3AWb6avQ/YsC7WuJ2D4BUWYjS6C4HH3yMeZ2kHOXSlINEXi/3sLjQ1YtD +3WOUAF1lCdsDVegCuGf8Kyoty1Qj+6eNj3RMwtg4yKCoz7LCozX+v8UIz0f4YRIenPo gxcmyoqPVburG/Hmtad7IxxQBAKAOS+kQWSXOmi0ca4II0EPabY2Hi1+U6zuMoezna6B AT1Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=aMSl4znU2Sd4bzA0jvC79sButN8q58mS6YTOjQXNG14=; b=YlVY+l8kLxRsk5HEmpDgqYkKioFEO+47yjx20vyavcYn9XNKYCZdHhl1YYHGYkPNZb KcbFsQk7ur9Rse5ti6Tpt6mt6BIbfKh5MHvjiOUZVb8bkRAbGNG2DHQ9lEt8lZdiWBjJ QLQfHbBxztan5Se4VcesLye7NR8fVpGSbbYlPCtBFolQomzlSO3tGqmDzoWCAUASFO42 qK86YpMrNA1O5bWhAB+X1DxztD6ZonUo6hvzBGNjbHmFydPRxzVyAZx4MESHUQVxjV5p K15oFCpH3Nuh0qSUh165WdQno2SSQckM9L7CQ8uZmRkNaXimI2hfKrHGCZIyY5Bwz9bm IvvA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r137si14116710pgr.73.2017.06.05.16.25.52; Mon, 05 Jun 2017 16:25:53 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751448AbdFEXZo (ORCPT + 25 others); Mon, 5 Jun 2017 19:25:44 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:32829 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751246AbdFEXZm (ORCPT ); Mon, 5 Jun 2017 19:25:42 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5s004412; Tue, 6 Jun 2017 08:22:48 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5s004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704969; bh=aMSl4znU2Sd4bzA0jvC79sButN8q58mS6YTOjQXNG14=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=v+wvRGWYVJ6sA9o1pr8pwki2X+UrR8Wn6W1mqCK+7cknVbOL8g8O3HT7gKLVRVNIw ZdRPk6W1wXorGsANYnacQUKHn4/ba6OZJDxvmPUEbikQIPZve9yt2oVICK3iWuiscJ H/zazoOGYwGVfxAUhR2Taj/YogkNqXwOD3QnujbcOTyOaQeLbzYsJiEyqp7dY57mOj AIGK72bl32W/j78lugduIbRBTU32DbUD5IaG6jSarVzHxmJGAeyXgzSOlyzD6BJsGx P2R3W2O3f2ixMptNza8fF5pLc6n6QCJnPd4sBNm5ZRARHOIoO8C4zOYTkWy0TpY1JV sMTYd+BzLn4JQ== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v4 18/23] mtd: nand: denali: merge struct nand_buf into struct denali_nand_info Date: Tue, 6 Jun 2017 08:21:57 +0900 Message-Id: <1496704922-12261-19-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Now struct nand_buf has only two members, so I see no reason for the separation. Signed-off-by: Masahiro Yamada --- Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 29 ++++++++++++++--------------- drivers/mtd/nand/denali.h | 8 ++------ 2 files changed, 16 insertions(+), 21 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index af60b1e..755825d 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -640,7 +640,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int page, bool raw_xfer) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->buf.dma_buf; + dma_addr_t addr = denali->dma_addr; size_t size = mtd->writesize + mtd->oobsize; uint32_t irq_status; uint32_t irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL; @@ -654,11 +654,11 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, setup_ecc_for_xfer(denali, !raw_xfer, raw_xfer); /* copy buffer into DMA buffer */ - memcpy(denali->buf.buf, buf, mtd->writesize); + memcpy(denali->buf, buf, mtd->writesize); if (raw_xfer) { /* transfer the data to the spare area */ - memcpy(denali->buf.buf + mtd->writesize, + memcpy(denali->buf + mtd->writesize, chip->oob_poi, mtd->oobsize); } @@ -735,7 +735,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->buf.dma_buf; + dma_addr_t addr = denali->dma_addr; size_t size = mtd->writesize + mtd->oobsize; uint32_t irq_status; uint32_t irq_mask = denali->caps & DENALI_CAP_HW_ECC_FIXUP ? @@ -757,7 +757,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE); - memcpy(buf, denali->buf.buf, mtd->writesize); + memcpy(buf, denali->buf, mtd->writesize); if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) stat = denali_hw_ecc_fixup(mtd, denali, &uncor_ecc_flags); @@ -782,7 +782,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->buf.dma_buf; + dma_addr_t addr = denali->dma_addr; size_t size = mtd->writesize + mtd->oobsize; uint32_t irq_mask = INTR__DMA_CMD_COMP; uint32_t irq_status; @@ -804,8 +804,8 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, denali_enable_dma(denali, false); - memcpy(buf, denali->buf.buf, mtd->writesize); - memcpy(chip->oob_poi, denali->buf.buf + mtd->writesize, mtd->oobsize); + memcpy(buf, denali->buf, mtd->writesize); + memcpy(chip->oob_poi, denali->buf + mtd->writesize, mtd->oobsize); return 0; } @@ -1240,10 +1240,9 @@ int denali_init(struct denali_nand_info *denali) if (ret) goto disable_irq; - denali->buf.buf = devm_kzalloc(denali->dev, - mtd->writesize + mtd->oobsize, - GFP_KERNEL); - if (!denali->buf.buf) { + denali->buf = devm_kzalloc(denali->dev, mtd->writesize + mtd->oobsize, + GFP_KERNEL); + if (!denali->buf) { ret = -ENOMEM; goto disable_irq; } @@ -1256,10 +1255,10 @@ int denali_init(struct denali_nand_info *denali) goto disable_irq; } - denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf, + denali->dma_addr = dma_map_single(denali->dev, denali->buf, mtd->writesize + mtd->oobsize, DMA_BIDIRECTIONAL); - if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) { + if (dma_mapping_error(denali->dev, denali->dma_addr)) { dev_err(denali->dev, "Failed to map DMA buffer\n"); ret = -EIO; goto disable_irq; @@ -1353,7 +1352,7 @@ void denali_remove(struct denali_nand_info *denali) nand_release(mtd); denali_disable_irq(denali); - dma_unmap_single(denali->dev, denali->buf.dma_buf, bufsize, + dma_unmap_single(denali->dev, denali->dma_addr, bufsize, DMA_BIDIRECTIONAL); } EXPORT_SYMBOL(denali_remove); diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index cb49eb5..49dc4ba 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -305,16 +305,10 @@ #define MODE_10 0x08000000 #define MODE_11 0x0C000000 -struct nand_buf { - uint8_t *buf; - dma_addr_t dma_buf; -}; - struct denali_nand_info { struct nand_chip nand; unsigned long clk_x_rate; /* bus interface clock rate */ int flash_bank; /* currently selected chip */ - struct nand_buf buf; struct device *dev; void __iomem *flash_reg; /* Register Interface */ void __iomem *flash_mem; /* Host Data/Command Interface */ @@ -326,6 +320,8 @@ struct denali_nand_info { uint32_t irq_status; int irq; + void *buf; + dma_addr_t dma_addr; int devnum; /* represent how many nands connected */ int bbtskipbytes; int max_banks; From patchwork Mon Jun 5 23:21:59 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103102 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1008521obh; Mon, 5 Jun 2017 16:25:45 -0700 (PDT) X-Received: by 10.84.160.197 with SMTP id v5mr17845179plg.30.1496705145542; Mon, 05 Jun 2017 16:25:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705145; cv=none; d=google.com; s=arc-20160816; b=p1zI8I/hOs0aJsznUDC+TlmTg0Oe1bde/mTgpcVyP2yXDIGiGB6hQMojoacrBIi26T 6frgo+L5m9h9WUhgOH31XIqD7+5atDGNoqU0kH6WAo7sYYQvmzsZQNG9vwFItin8mC/u GaZLACzaLItU5bi+LyY+Y7GN9u9iULwdCX5eR4cKzOfrGrlfiujuH8KCh0QrkPGYXhzG jbPM+3NQ9GOhA1bBMrM16YA7RdQgIJcDQHcg5bimnDT+TZRB72e3N3nc7sarZjR3hgjj 8vnmG8d5ez65JOCcfn0yFkYvbPd2jW+3JXr5vMFVz38IaXA4/mUh/eBlc+viG6sVSvzc qAQg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=sF6aLIXjAKRiENDfjDjOxgpbE/n0LGWbZ5MQsClm2l8=; b=NZ3VmAIBq1l4t18yV9oE0TzqmPNbLcxXZFB2J3KgBt6gmuVAORHDg62Bybg5+olMsQ TkuVdqGhLBvowCUeAOU6cWTMzM0Uk/kXLM+BFZEbC3xCpTRM3hhsp4aCHHj063KsLsPi 3ceOxdn0Dj9vD6mtLh5Q+BH91za0LuphFCOuFxvLb4eRzPphskJhb+eKVbrEWUO0Zzmn Az6V7vq6Bh6prs+xS4UxIN+1v4ow01iCsVxIU0PiX0/qW+0wtbpATx5Afj2f4TxcOTGs FOGsCnwy+0/nNOg21wn0AyJwFptQbeow0nGzg5zXlxfO5MlRKVQZS4RVEPgKqt9mKd7r MwRg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id q20si10759518pfl.414.2017.06.05.16.25.45; Mon, 05 Jun 2017 16:25:45 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751397AbdFEXZb (ORCPT + 25 others); Mon, 5 Jun 2017 19:25:31 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:32501 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751266AbdFEXZ3 (ORCPT ); Mon, 5 Jun 2017 19:25:29 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5u004412; Tue, 6 Jun 2017 08:22:51 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5u004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704972; bh=sF6aLIXjAKRiENDfjDjOxgpbE/n0LGWbZ5MQsClm2l8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EIhdUEQRURvjr5J8DAsDs171UeAxugiStzOZ8v358Fx38k2+ZHtOmXtUJrtl9cw1O gSTsjcRTvg1ODGbS5yURrUocfTy5dCtT68nf8ypoVSmFoArRiPW1eqzyHICpzD5W6v duOkYsIHwT5QaYtXfFM3l3AddLtjJTCaZB+CewgMajkcH8ZyNofAgdUPvZELJsKZ6W Zs94CkGJcjd5Km8m0QljEVwqQfUYsjiOaysENLCTGO9I0tx5M3g4m6nvGZ33CmpFTp u39Mso2rlZQ2Gt7fPJJlm0h+zBrVvQVaz9UiVVBm8bs6XW0kHPgFMuyNu4inPfFbil ES9ic2gvY33yg== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v4 20/23] mtd: nand: denali: fix raw and oob accessors for syndrome page layout Date: Tue, 6 Jun 2017 08:21:59 +0900 Message-Id: <1496704922-12261-21-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The Denali IP adopts the syndrome page layout; payload and ECC are interleaved, with BBM area always placed at the beginning of OOB. The figure below shows the page organization for ecc->steps == 2: |----------------| |-----------| | | | | | | | | | Payload0 | | | | | | | | | | | | | | | |----------------| | in-band | | ECC0 | | area | |----------------| | | | | | | | | | | | Payload1 | | | | | | | | | | | |----------------| |-----------| | BBM | | | |----------------| | | |Payload1 (cont.)| | | |----------------| |out-of-band| | ECC1 | | area | |----------------| | | | OOB free | | | |----------------| |-----------| The current raw / oob accessors do not take that into consideration, so in-band and out-of-band data are transferred as stored in the device. In the case above, in-band: Payload0 + ECC0 + Payload1(partial) out-of-band: BBM + Payload1(cont.) + ECC1 + OOB-free This is wrong. As the comment block of struct nand_ecc_ctrl says, driver callbacks must hide the specific layout used by the hardware and always return contiguous in-band and out-of-band data. The current implementation is completely screwed-up, so read/write callbacks must be re-worked. Also, it is reasonable to support PIO transfer in case DMA may not work for some reasons. Actually, the Data DMA may not be equipped depending on the configuration of the RTL. This can be checked by reading the bit 4 of the FEATURES register. Even if the controller has the DMA support, dma_set_mask() and dma_map_single() could fail. In either case, the driver can fall back to the PIO transfer. Slower access would be better than giving up. Signed-off-by: Masahiro Yamada --- Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 613 ++++++++++++++++++++++++++++++---------------- drivers/mtd/nand/denali.h | 3 +- 2 files changed, 397 insertions(+), 219 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index d156d95..42e0620 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -246,6 +246,53 @@ static void denali_write_byte(struct mtd_info *mtd, uint8_t byte) index_addr(denali, MODE_11 | BANK(denali->flash_bank) | 2, byte); } +static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + int i; + + iowrite32(MODE_11 | BANK(denali->flash_bank) | 2, denali->flash_mem); + + for (i = 0; i < len; i++) + buf[i] = ioread32(denali->flash_mem + 0x10); +} + +static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + int i; + + iowrite32(MODE_11 | BANK(denali->flash_bank) | 2, denali->flash_mem); + + for (i = 0; i < len; i++) + iowrite32(buf[i], denali->flash_mem + 0x10); +} + +static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + uint16_t *buf16 = (uint16_t *)buf; + int i; + + iowrite32(MODE_11 | BANK(denali->flash_bank) | 2, denali->flash_mem); + + for (i = 0; i < len / 2; i++) + buf16[i] = ioread32(denali->flash_mem + 0x10); +} + +static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf, + int len) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + const uint16_t *buf16 = (const uint16_t *)buf; + int i; + + iowrite32(MODE_11 | BANK(denali->flash_bank) | 2, denali->flash_mem); + + for (i = 0; i < len / 2; i++) + iowrite32(buf16[i], denali->flash_mem + 0x10); +} + static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) { struct denali_nand_info *denali = mtd_to_denali(mtd); @@ -275,44 +322,6 @@ static int denali_dev_ready(struct mtd_info *mtd) return !!(denali_check_irq(denali) & INTR__INT_ACT); } -/* - * sends a pipeline command operation to the controller. See the Denali NAND - * controller's user guide for more information (section 4.2.3.6). - */ -static int denali_send_pipeline_cmd(struct denali_nand_info *denali, int page, - bool ecc_en, bool transfer_spare, - int access_type, int write) -{ - int status = PASS; - uint32_t addr, cmd; - - setup_ecc_for_xfer(denali, ecc_en, transfer_spare); - - denali_reset_irq(denali); - - addr = BANK(denali->flash_bank) | page; - - if (write && access_type != SPARE_ACCESS) { - cmd = MODE_01 | addr; - iowrite32(cmd, denali->flash_mem); - } else if (write && access_type == SPARE_ACCESS) { - /* read spare area */ - cmd = MODE_10 | addr; - index_addr(denali, cmd, access_type); - - cmd = MODE_01 | addr; - iowrite32(cmd, denali->flash_mem); - } else { - /* setup page read request for access type */ - cmd = MODE_10 | addr; - index_addr(denali, cmd, access_type); - - cmd = MODE_01 | addr; - iowrite32(cmd, denali->flash_mem); - } - return status; -} - /* helper function that simply writes a buffer to the flash */ static int write_data_to_flash_mem(struct denali_nand_info *denali, const uint8_t *buf, int len) @@ -355,66 +364,6 @@ static int read_data_from_flash_mem(struct denali_nand_info *denali, return i * 4; /* intent is to return the number of bytes read */ } -/* writes OOB data to the device */ -static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t irq_status; - uint32_t irq_mask = INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL; - int status = 0; - - if (denali_send_pipeline_cmd(denali, page, false, false, SPARE_ACCESS, - 1) == PASS) { - write_data_to_flash_mem(denali, buf, mtd->oobsize); - - /* wait for operation to complete */ - irq_status = denali_wait_for_irq(denali, irq_mask); - - if (!(irq_status & INTR__PROGRAM_COMP)) { - dev_err(denali->dev, "OOB write failed\n"); - status = -EIO; - } - } else { - dev_err(denali->dev, "unable to send pipeline command\n"); - status = -EIO; - } - return status; -} - -/* reads OOB data from the device */ -static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) -{ - struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t irq_mask = INTR__LOAD_COMP; - uint32_t irq_status, addr, cmd; - - if (denali_send_pipeline_cmd(denali, page, false, true, SPARE_ACCESS, - 0) == PASS) { - read_data_from_flash_mem(denali, buf, mtd->oobsize); - - /* - * wait for command to be accepted - * can always use status0 bit as the - * mask is identical for each bank. - */ - irq_status = denali_wait_for_irq(denali, irq_mask); - - if (!(irq_status & INTR__LOAD_COMP)) - dev_err(denali->dev, "page on OOB timeout %d\n", page); - - /* - * We set the device back to MAIN_ACCESS here as I observed - * instability with the controller if you do a block erase - * and the last transaction was a SPARE_ACCESS. Block erase - * is reliable (according to the MTD test infrastructure) - * if you are in MAIN_ACCESS. - */ - addr = BANK(denali->flash_bank) | page; - cmd = MODE_10 | addr; - index_addr(denali, cmd, MAIN_ACCESS); - } -} - static int denali_check_erased_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, unsigned long uncor_ecc_flags, @@ -630,144 +579,302 @@ static void denali_setup_dma(struct denali_nand_info *denali, denali_setup_dma32(denali, dma_addr, page, write); } -/* - * writes a page. user specifies type, and this function handles the - * configuration details. - */ -static int write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int page, bool raw_xfer) +static int denali_pio_read(struct denali_nand_info *denali, void *buf, + size_t size, int page, int raw) { - struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->dma_addr; - size_t size = mtd->writesize + mtd->oobsize; - uint32_t irq_status; - uint32_t irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL; - int ret = 0; + uint32_t addr = BANK(denali->flash_bank) | page; + uint32_t irq_status, ecc_err_mask; - /* - * if it is a raw xfer, we want to disable ecc and send the spare area. - * !raw_xfer - enable ecc - * raw_xfer - transfer spare - */ - setup_ecc_for_xfer(denali, !raw_xfer, raw_xfer); + /* setup page read request for access type */ + index_addr(denali, MODE_10 | addr, + raw ? MAIN_SPARE_ACCESS : MAIN_ACCESS); - /* copy buffer into DMA buffer */ - memcpy(denali->buf, buf, mtd->writesize); + iowrite32(MODE_01 | addr, denali->flash_mem); - if (raw_xfer) { - /* transfer the data to the spare area */ - memcpy(denali->buf + mtd->writesize, - chip->oob_poi, - mtd->oobsize); - } + if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) + ecc_err_mask = INTR__ECC_UNCOR_ERR; + else + ecc_err_mask = INTR__ECC_ERR; - dma_sync_single_for_device(denali->dev, addr, size, DMA_TO_DEVICE); + denali_reset_irq(denali); + + read_data_from_flash_mem(denali, buf, size); + + irq_status = denali_wait_for_irq(denali, INTR__PAGE_XFER_INC); + if (!(irq_status & INTR__PAGE_XFER_INC)) + return -EIO; + + return irq_status & ecc_err_mask ? -EBADMSG : 0; +} + +static int denali_pio_write(struct denali_nand_info *denali, + const void *buf, size_t size, int page, int raw) +{ + uint32_t addr = BANK(denali->flash_bank) | page; + uint32_t irq_status; + + /* setup page read request for access type */ + index_addr(denali, MODE_10 | addr, + raw ? MAIN_SPARE_ACCESS : MAIN_ACCESS); + + iowrite32(MODE_01 | addr, denali->flash_mem); denali_reset_irq(denali); + + write_data_to_flash_mem(denali, buf, size); + + irq_status = denali_wait_for_irq(denali, + INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL); + if (!(irq_status & INTR__PROGRAM_COMP)) + return -EIO; + + return 0; +} + +static int denali_pio_xfer(struct denali_nand_info *denali, void *buf, + size_t size, int page, int raw, int write) +{ + if (write) + return denali_pio_write(denali, buf, size, page, raw); + else + return denali_pio_read(denali, buf, size, page, raw); +} + +static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, + size_t size, int page, int raw, int write) +{ + dma_addr_t dma_addr = denali->dma_addr; + uint32_t irq_mask, irq_status, ecc_err_mask; + enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + int ret = 0; + + dma_sync_single_for_device(denali->dev, dma_addr, size, dir); + + if (write) { + irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL; + ecc_err_mask = 0; + } else if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) { + irq_mask = INTR__DMA_CMD_COMP; + ecc_err_mask = INTR__ECC_UNCOR_ERR; + } else { + irq_mask = INTR__DMA_CMD_COMP; + ecc_err_mask = INTR__ECC_ERR; + } + denali_enable_dma(denali, true); - denali_setup_dma(denali, addr, page, 1); + denali_reset_irq(denali); + denali_setup_dma(denali, dma_addr, page, write); /* wait for operation to complete */ irq_status = denali_wait_for_irq(denali, irq_mask); - if (!(irq_status & INTR__DMA_CMD_COMP)) { - dev_err(denali->dev, "timeout on write_page (type = %d)\n", - raw_xfer); + if (!(irq_status & INTR__DMA_CMD_COMP)) ret = -EIO; - } + else if (irq_status & ecc_err_mask) + ret = -EBADMSG; denali_enable_dma(denali, false); - dma_sync_single_for_cpu(denali->dev, addr, size, DMA_TO_DEVICE); + dma_sync_single_for_cpu(denali->dev, dma_addr, size, dir); return ret; } -/* NAND core entry points */ - -/* - * this is the callback that the NAND core calls to write a page. Since - * writing a page with ECC or without is similar, all the work is done - * by write_page above. - */ -static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, int page) +static int denali_data_xfer(struct denali_nand_info *denali, void *buf, + size_t size, int page, int raw, int write) { - /* - * for regular page writes, we let HW handle all the ECC - * data written to the device. - */ - return write_page(mtd, chip, buf, page, false); + setup_ecc_for_xfer(denali, !raw, raw); + + if (denali->dma_avail) + return denali_dma_xfer(denali, buf, size, page, raw, write); + else + return denali_pio_xfer(denali, buf, size, page, raw, write); } -/* - * This is the callback that the NAND core calls to write a page without ECC. - * raw access is similar to ECC page writes, so all the work is done in the - * write_page() function above. - */ -static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, - int page) +static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip, + int page, int write) { - /* - * for raw page writes, we want to disable ECC and simply write - * whatever data is in the buffer. - */ - return write_page(mtd, chip, buf, page, true); + struct denali_nand_info *denali = mtd_to_denali(mtd); + unsigned int start_cmd = write ? NAND_CMD_SEQIN : NAND_CMD_READ0; + unsigned int rnd_cmd = write ? NAND_CMD_RNDIN : NAND_CMD_RNDOUT; + int writesize = mtd->writesize; + int oobsize = mtd->oobsize; + uint8_t *bufpoi = chip->oob_poi; + int ecc_steps = chip->ecc.steps; + int ecc_size = chip->ecc.size; + int ecc_bytes = chip->ecc.bytes; + int oob_skip = denali->bbtskipbytes; + size_t size = writesize + oobsize; + int i, pos, len; + + /* BBM at the beginning of the OOB area */ + chip->cmdfunc(mtd, start_cmd, writesize, page); + if (write) + chip->write_buf(mtd, bufpoi, oob_skip); + else + chip->read_buf(mtd, bufpoi, oob_skip); + bufpoi += oob_skip; + + /* OOB ECC */ + for (i = 0; i < ecc_steps; i++) { + pos = ecc_size + i * (ecc_size + ecc_bytes); + len = ecc_bytes; + + if (pos >= writesize) + pos += oob_skip; + else if (pos + len > writesize) + len = writesize - pos; + + chip->cmdfunc(mtd, rnd_cmd, pos, -1); + if (write) + chip->write_buf(mtd, bufpoi, len); + else + chip->read_buf(mtd, bufpoi, len); + bufpoi += len; + if (len < ecc_bytes) { + len = ecc_bytes - len; + chip->cmdfunc(mtd, rnd_cmd, writesize + oob_skip, -1); + if (write) + chip->write_buf(mtd, bufpoi, len); + else + chip->read_buf(mtd, bufpoi, len); + bufpoi += len; + } + } + + /* OOB free */ + len = oobsize - (bufpoi - chip->oob_poi); + chip->cmdfunc(mtd, rnd_cmd, size - len, -1); + if (write) + chip->write_buf(mtd, bufpoi, len); + else + chip->read_buf(mtd, bufpoi, len); } -static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) +static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) { - return write_oob_data(mtd, chip->oob_poi, page); + struct denali_nand_info *denali = mtd_to_denali(mtd); + int writesize = mtd->writesize; + int oobsize = mtd->oobsize; + int ecc_steps = chip->ecc.steps; + int ecc_size = chip->ecc.size; + int ecc_bytes = chip->ecc.bytes; + void *dma_buf = denali->buf; + int oob_skip = denali->bbtskipbytes; + size_t size = writesize + oobsize; + int ret, i, pos, len; + + ret = denali_data_xfer(denali, dma_buf, size, page, 1, 0); + if (ret) + return ret; + + /* Arrange the buffer for syndrome payload/ecc layout */ + if (buf) { + for (i = 0; i < ecc_steps; i++) { + pos = i * (ecc_size + ecc_bytes); + len = ecc_size; + + if (pos >= writesize) + pos += oob_skip; + else if (pos + len > writesize) + len = writesize - pos; + + memcpy(buf, dma_buf + pos, len); + buf += len; + if (len < ecc_size) { + len = ecc_size - len; + memcpy(buf, dma_buf + writesize + oob_skip, + len); + buf += len; + } + } + } + + if (oob_required) { + uint8_t *oob = chip->oob_poi; + + /* BBM at the beginning of the OOB area */ + memcpy(oob, dma_buf + writesize, oob_skip); + oob += oob_skip; + + /* OOB ECC */ + for (i = 0; i < ecc_steps; i++) { + pos = ecc_size + i * (ecc_size + ecc_bytes); + len = ecc_bytes; + + if (pos >= writesize) + pos += oob_skip; + else if (pos + len > writesize) + len = writesize - pos; + + memcpy(oob, dma_buf + pos, len); + oob += len; + if (len < ecc_bytes) { + len = ecc_bytes - len; + memcpy(oob, dma_buf + writesize + oob_skip, + len); + oob += len; + } + } + + /* OOB free */ + len = oobsize - (oob - chip->oob_poi); + memcpy(oob, dma_buf + size - len, len); + } + + return 0; } static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) { - read_oob_data(mtd, chip->oob_poi, page); + denali_oob_xfer(mtd, chip, page, 0); return 0; } -static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->dma_addr; - size_t size = mtd->writesize + mtd->oobsize; - uint32_t irq_status; - uint32_t irq_mask = denali->caps & DENALI_CAP_HW_ECC_FIXUP ? - INTR__DMA_CMD_COMP | INTR__ECC_UNCOR_ERR : - INTR__ECC_TRANSACTION_DONE | INTR__ECC_ERR; - unsigned long uncor_ecc_flags = 0; - int stat = 0; + int status; - setup_ecc_for_xfer(denali, true, false); + denali_reset_irq(denali); - denali_enable_dma(denali, true); - dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE); + denali_oob_xfer(mtd, chip, page, 1); - denali_reset_irq(denali); - denali_setup_dma(denali, addr, page, 0); + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + status = chip->waitfunc(mtd, chip); - /* wait for operation to complete */ - irq_status = denali_wait_for_irq(denali, irq_mask); + return status & NAND_STATUS_FAIL ? -EIO : 0; +} - dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE); +static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); + unsigned long uncor_ecc_flags = 0; + int stat = 0; + int ret; + + ret = denali_data_xfer(denali, denali->buf, mtd->writesize, page, 0, 0); + if (ret && ret != -EBADMSG) + return ret; memcpy(buf, denali->buf, mtd->writesize); if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) stat = denali_hw_ecc_fixup(mtd, denali, &uncor_ecc_flags); - else if (irq_status & INTR__ECC_ERR) + else if (ret == -EBADMSG) stat = denali_sw_ecc_fixup(mtd, denali, &uncor_ecc_flags, buf); - denali_enable_dma(denali, false); if (stat < 0) return stat; if (uncor_ecc_flags) { - read_oob_data(mtd, chip->oob_poi, page); + ret = denali_read_oob(mtd, chip, page); + if (ret) + return ret; stat = denali_check_erased_page(mtd, chip, buf, uncor_ecc_flags, stat); @@ -776,36 +883,93 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, return stat; } -static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->dma_addr; - size_t size = mtd->writesize + mtd->oobsize; - uint32_t irq_mask = INTR__DMA_CMD_COMP; - uint32_t irq_status; - - setup_ecc_for_xfer(denali, false, true); - denali_enable_dma(denali, true); + int writesize = mtd->writesize; + int oobsize = mtd->oobsize; + int ecc_steps = chip->ecc.steps; + int ecc_size = chip->ecc.size; + int ecc_bytes = chip->ecc.bytes; + void *dma_buf = denali->buf; + int oob_skip = denali->bbtskipbytes; + size_t size = writesize + oobsize; + int i, pos, len; - dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE); + /* + * Fill the buffer with 0xff first except the full page transfer. + * This simplifies the logic. + */ + if (!buf || !oob_required) + memset(dma_buf, 0xff, size); + + /* Arrange the buffer for syndrome payload/ecc layout */ + if (buf) { + for (i = 0; i < ecc_steps; i++) { + pos = i * (ecc_size + ecc_bytes); + len = ecc_size; + + if (pos >= writesize) + pos += oob_skip; + else if (pos + len > writesize) + len = writesize - pos; + + memcpy(dma_buf + pos, buf, len); + buf += len; + if (len < ecc_size) { + len = ecc_size - len; + memcpy(dma_buf + writesize + oob_skip, buf, + len); + buf += len; + } + } + } - denali_reset_irq(denali); - denali_setup_dma(denali, addr, page, 0); + if (oob_required) { + const uint8_t *oob = chip->oob_poi; + + /* BBM at the beginning of the OOB area */ + memcpy(dma_buf + writesize, oob, oob_skip); + oob += oob_skip; + + /* OOB ECC */ + for (i = 0; i < ecc_steps; i++) { + pos = ecc_size + i * (ecc_size + ecc_bytes); + len = ecc_bytes; + + if (pos >= writesize) + pos += oob_skip; + else if (pos + len > writesize) + len = writesize - pos; + + memcpy(dma_buf + pos, oob, len); + oob += len; + if (len < ecc_bytes) { + len = ecc_bytes - len; + memcpy(dma_buf + writesize + oob_skip, oob, + len); + oob += len; + } + } - /* wait for operation to complete */ - irq_status = denali_wait_for_irq(denali, irq_mask); - if (irq_status & INTR__DMA_CMD_COMP) - return -ETIMEDOUT; + /* OOB free */ + len = oobsize - (oob - chip->oob_poi); + memcpy(dma_buf + size - len, oob, len); + } - dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE); + return denali_data_xfer(denali, dma_buf, size, page, 1, 1); +} - denali_enable_dma(denali, false); +static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required, int page) +{ + struct denali_nand_info *denali = mtd_to_denali(mtd); - memcpy(buf, denali->buf, mtd->writesize); - memcpy(chip->oob_poi, denali->buf + mtd->writesize, mtd->oobsize); + memcpy(denali->buf, buf, mtd->writesize); - return 0; + return denali_data_xfer(denali, denali->buf, mtd->writesize, page, + 0, 1); } static void denali_select_chip(struct mtd_info *mtd, int chip) @@ -1245,21 +1409,29 @@ int denali_init(struct denali_nand_info *denali) goto disable_irq; } - ret = dma_set_mask(denali->dev, - DMA_BIT_MASK(denali->caps & DENALI_CAP_DMA_64BIT ? - 64 : 32)); - if (ret) { - dev_err(denali->dev, "No usable DMA configuration\n"); - goto disable_irq; + if (ioread32(denali->flash_reg + FEATURES) & FEATURES__DMA) + denali->dma_avail = 1; + + if (denali->dma_avail) { + int dma_bit = denali->caps & DENALI_CAP_DMA_64BIT ? 64 : 32; + + ret = dma_set_mask(denali->dev, DMA_BIT_MASK(dma_bit)); + if (ret) { + dev_info(denali->dev, + "Failed to set DMA mask. Disabling DMA.\n"); + denali->dma_avail = 0; + } } - denali->dma_addr = dma_map_single(denali->dev, denali->buf, - mtd->writesize + mtd->oobsize, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(denali->dev, denali->dma_addr)) { - dev_err(denali->dev, "Failed to map DMA buffer\n"); - ret = -EIO; - goto disable_irq; + if (denali->dma_avail) { + denali->dma_addr = dma_map_single(denali->dev, denali->buf, + mtd->writesize + mtd->oobsize, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(denali->dev, denali->dma_addr)) { + dev_info(denali->dev, + "Failed to map DMA buffer. Disabling DMA.\n"); + denali->dma_avail = 0; + }; } /* @@ -1306,6 +1478,13 @@ int denali_init(struct denali_nand_info *denali) mtd_set_ooblayout(mtd, &denali_ooblayout_ops); + if (chip->options & NAND_BUSWIDTH_16) { + chip->read_buf = denali_read_buf16; + chip->write_buf = denali_write_buf16; + } else { + chip->read_buf = denali_read_buf; + chip->write_buf = denali_write_buf; + } chip->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS; chip->ecc.read_page = denali_read_page; chip->ecc.read_page_raw = denali_read_page_raw; diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 49dc4ba..f953cb4 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -298,8 +298,6 @@ #define CHNL_ACTIVE__CHANNEL2 BIT(2) #define CHNL_ACTIVE__CHANNEL3 BIT(3) -#define PASS 0 /*success flag*/ - #define MODE_00 0x00000000 #define MODE_01 0x04000000 #define MODE_10 0x08000000 @@ -322,6 +320,7 @@ struct denali_nand_info { void *buf; dma_addr_t dma_addr; + int dma_avail; int devnum; /* represent how many nands connected */ int bbtskipbytes; int max_banks; From patchwork Mon Jun 5 23:22:00 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103104 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1008526obh; Mon, 5 Jun 2017 16:25:46 -0700 (PDT) X-Received: by 10.99.140.83 with SMTP id q19mr5749645pgn.225.1496705146360; Mon, 05 Jun 2017 16:25:46 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705146; cv=none; d=google.com; s=arc-20160816; b=SOqk42qwO1p08Uw8KL4ISLfOhnBeyCsnFpDKDem+OaLtbxhUZR9gqxET7LLbVmELVL ip7wCdazzrzuzvQUjT9iUqES4LNH844A7hXxaMlzckd3rtIq5hP6KeMDlqJWMa3rWdxM sgzmlHv0InSlZuYfdkc0fa3qcTzrY9BKKguM2sjqlQtqzBgPvpkr/J5zn7WRs1iaIIDd FbGiuDzkhgwBxcZE4sZxaA2Xugs173bwOEuvWcIIbm7AbRvYzroDx6PcI1guRaZilzhn cWzB/GxAJs5UX4WC0XaoxZFFcKSjgtXPmOEEGaUx0d77TxPA5ieQMpK2SFgaeUcc1/sj aNVg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=208EqcWGerFdyZNvLo19pHYwq+AKnfE8I6ZnxNf1qnU=; b=GNVDaQ6tFSWmeRmAv3Av5zrjWb0w+SRmDPYGwT2DXOU8J1nW7RdL5Bsv5jP2FESNdG HfPNdhR/ye0/UZPiW7KKdyR1JRQDfHbx7Sg0vURO2YosgO9zNpUlJ8AC9AQfKDoxjDS9 /LoRAJ55NaaJuoqYYwQL7k4GTVJ1/1qA56eH/4Dv4rhY8k6+e0jKvAF1ProIC37RqvWi VB7cePD/GZWusRDBX2e1YK29wM0U3nKBgiojaxugGiBYF+NGuATxzQvfHdsfnEp4LPUP 2Wjh8iAWPezULum6vZ5KzKBJ6ujFAIRmGobA5EO7hNaJtrQVWuHsQfAMEpZu1uN3L+Ml kZ7Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id q20si10759518pfl.414.2017.06.05.16.25.46; Mon, 05 Jun 2017 16:25:46 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751432AbdFEXZj (ORCPT + 25 others); Mon, 5 Jun 2017 19:25:39 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:32500 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751266AbdFEXZe (ORCPT ); Mon, 5 Jun 2017 19:25:34 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5v004412; Tue, 6 Jun 2017 08:22:52 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5v004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704973; bh=208EqcWGerFdyZNvLo19pHYwq+AKnfE8I6ZnxNf1qnU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MpFuJwD+Ku89uHXTptJi1hs6DE1ZmoaqWQY9t8gsJX3ni9dN7TIpgG228hDQY33zg 5OAowNrpCFN4jsX3ACo4BhdP1lQKqgwgzLY185gF8Skl2zhyeXfP9EVmoni2a8qxJr iHRlLOhxGjLeGHehhGl9wb4HoVbOU+sJAGQYq14lkeN4ZD1vol7Haa7QXJ94HW7eoS 59xi3iJNg1yfPMANrTxrfi1IS3MRiW2b+zbm1aYIHRZCLTnXPZ6zimy3Txmbcr+4qC lybbaig9n1m1f8KD3sqAB4ZHG2/EBSkcxl/K1kO9UKmcjh2LzkhIeukWMHvmbAyumO D+/Ke4hRGfYOw== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v4 21/23] mtd: nand: denali: skip driver internal bounce buffer when possible Date: Tue, 6 Jun 2017 08:22:00 +0900 Message-Id: <1496704922-12261-22-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org For ecc->read_page() and ecc->write_page(), it is possible to call dma_map_single() against the given buffer. This bypasses the driver internal bounce buffer and save the memcpy(). Signed-off-by: Masahiro Yamada --- Changes in v4: - Remove dma_unmap_single() from denali_remove() Changes in v3: - Set chip->buf_align to 16 Changes in v2: - Newly added drivers/mtd/nand/denali.c | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 42e0620..e4ab397 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -643,12 +643,16 @@ static int denali_pio_xfer(struct denali_nand_info *denali, void *buf, static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, size_t size, int page, int raw, int write) { - dma_addr_t dma_addr = denali->dma_addr; + dma_addr_t dma_addr; uint32_t irq_mask, irq_status, ecc_err_mask; enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE; int ret = 0; - dma_sync_single_for_device(denali->dev, dma_addr, size, dir); + dma_addr = dma_map_single(denali->dev, buf, size, dir); + if (dma_mapping_error(denali->dev, dma_addr)) { + dev_dbg(denali->dev, "Failed to DMA-map buffer. Trying PIO.\n"); + return denali_pio_xfer(denali, buf, size, page, raw, write); + } if (write) { irq_mask = INTR__DMA_CMD_COMP | INTR__PROGRAM_FAIL; @@ -674,7 +678,7 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, ret = -EBADMSG; denali_enable_dma(denali, false); - dma_sync_single_for_cpu(denali->dev, dma_addr, size, dir); + dma_unmap_single(denali->dev, dma_addr, size, dir); return ret; } @@ -857,12 +861,10 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, int stat = 0; int ret; - ret = denali_data_xfer(denali, denali->buf, mtd->writesize, page, 0, 0); + ret = denali_data_xfer(denali, buf, mtd->writesize, page, 0, 0); if (ret && ret != -EBADMSG) return ret; - memcpy(buf, denali->buf, mtd->writesize); - if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) stat = denali_hw_ecc_fixup(mtd, denali, &uncor_ecc_flags); else if (ret == -EBADMSG) @@ -966,10 +968,8 @@ static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, { struct denali_nand_info *denali = mtd_to_denali(mtd); - memcpy(denali->buf, buf, mtd->writesize); - - return denali_data_xfer(denali, denali->buf, mtd->writesize, page, - 0, 1); + return denali_data_xfer(denali, (void *)buf, mtd->writesize, + page, 0, 1); } static void denali_select_chip(struct mtd_info *mtd, int chip) @@ -1424,14 +1424,8 @@ int denali_init(struct denali_nand_info *denali) } if (denali->dma_avail) { - denali->dma_addr = dma_map_single(denali->dev, denali->buf, - mtd->writesize + mtd->oobsize, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(denali->dev, denali->dma_addr)) { - dev_info(denali->dev, - "Failed to map DMA buffer. Disabling DMA.\n"); - denali->dma_avail = 0; - }; + chip->options |= NAND_USE_BOUNCE_BUFFER; + chip->buf_align = 16; } /* @@ -1520,16 +1514,8 @@ EXPORT_SYMBOL(denali_init); void denali_remove(struct denali_nand_info *denali) { struct mtd_info *mtd = nand_to_mtd(&denali->nand); - /* - * Pre-compute DMA buffer size to avoid any problems in case - * nand_release() ever changes in a way that mtd->writesize and - * mtd->oobsize are not reliable after this call. - */ - int bufsize = mtd->writesize + mtd->oobsize; nand_release(mtd); denali_disable_irq(denali); - dma_unmap_single(denali->dev, denali->dma_addr, bufsize, - DMA_BIDIRECTIONAL); } EXPORT_SYMBOL(denali_remove); From patchwork Mon Jun 5 23:22:01 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103106 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1008681obh; Mon, 5 Jun 2017 16:26:16 -0700 (PDT) X-Received: by 10.84.130.99 with SMTP id 90mr17920726plc.165.1496705176858; Mon, 05 Jun 2017 16:26:16 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705176; cv=none; d=google.com; s=arc-20160816; b=Q7fMEKtdqwLWfVmgFqJXUZX9aNSICdR9lj5HbF8t4RxvnHD6zpEv8vC5MugPIR9FYf xo5CRdEatVtDZxGgcVUCir2u4LlHz77VWUMY7Egd4tEazMnR644w+m5DdQo1RfqxkbIN IeFVPWga4RxbkmChvygvQ9plolOak7tQfyQyAv567l6O3QpF1pDaupSf29lTjlQcWk27 JoYpSQofwSd091j192Xa1Gi+M+m3sYU185G25/orvGbYWc+zd+0st6j80Mr0902bci5D JMNzT6kPjma1Ja0sXv5YcQOD1SNA5PLainOZi+MCTpmD/bXKUXgFCWAYyJZMgYej8fux yf6w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=X8h7KinnPluL+lW1v2CJ7MKtlc/wGtCugyJkh29v8uY=; b=x0LR5YVm49DIKGqCfldn56IwJVJ4nEYIzAq8Ys3fCYvipW47PmKt1bne1ciaV4BBE7 PdGTTxnT4+nRyIhfYMn0CBaKXDgjioTYs7qCbpgeOY/XBpH4fOUT5HZnlN2F9GLwYZ1r RccVdJalZ6NZgZt/BE0IljYeDxtuWn1uq3vTVTR366U2DaAY8yAZTQ0odBttrwwj9Mpr IyPobP7+fhGCi8Wkldp9LmI85Y7qEPMrz/JF89Po3zTEOzQxXGiNsVLBPLLK3bGztFAZ 0OXUpY+2TNe5x/xhPf2iEamD00phOKJNwXEIbgk2n2ZpUWM8if+2e48N9STcOhXt4VaF Cusw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id v61si8327189plb.188.2017.06.05.16.26.16; Mon, 05 Jun 2017 16:26:16 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751471AbdFEXZx (ORCPT + 25 others); Mon, 5 Jun 2017 19:25:53 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:33068 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751246AbdFEXZv (ORCPT ); Mon, 5 Jun 2017 19:25:51 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5w004412; Tue, 6 Jun 2017 08:22:53 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5w004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704974; bh=X8h7KinnPluL+lW1v2CJ7MKtlc/wGtCugyJkh29v8uY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pnV9ErzQCnpkiSF2MOotd6Ki0oyg0BtJc5YLYHvyTEmgu/FrAV/gFWOf5MqyOYxZR BYa1nPCQsP49TUkm95HsOPs651/X971GSqXHPOroQfTGkGUYmpAbLgjVXmI5Zb8RBc ttGpt4DMrbThg0o5xMX76yVK/AwZ5/doCbtzyw5oyn57MbX64Y5j9buUse9Qils7+b meR7XclVc/yH7T4bo32rNY43Jc7pkSBhnBnHNpBXGn4qwPWFDfm07F+o9mDscY+Y6H L1uLPW4B0A9Y4kFTgIAScSBdeGHEB0tNI4PyyO20bN612yRU1vigfC9PoK/QfOgwyo My4inj02JE+Og== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Russell King , Lars-Peter Clausen , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v4 22/23] mtd: nand: denali: use non-managed kmalloc() for DMA buffer Date: Tue, 6 Jun 2017 08:22:01 +0900 Message-Id: <1496704922-12261-23-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org As Russell and Lars stated in the discussion [1], using devm_k*alloc() with DMA is not a good idea. Let's use kmalloc (not kzalloc because no need for zero-out). Also, allocate the buffer as late as possible because it must be freed for any error that follows. [1] https://lkml.org/lkml/2017/3/8/693 Signed-off-by: Masahiro Yamada Cc: Russell King Cc: Lars-Peter Clausen Acked-by: Robin Murphy --- Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index e4ab397..f2b1592 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "denali.h" @@ -1402,13 +1403,6 @@ int denali_init(struct denali_nand_info *denali) if (ret) goto disable_irq; - denali->buf = devm_kzalloc(denali->dev, mtd->writesize + mtd->oobsize, - GFP_KERNEL); - if (!denali->buf) { - ret = -ENOMEM; - goto disable_irq; - } - if (ioread32(denali->flash_reg + FEATURES) & FEATURES__DMA) denali->dma_avail = 1; @@ -1492,17 +1486,30 @@ int denali_init(struct denali_nand_info *denali) if (ret) goto disable_irq; + /* + * This buffer is DMA-mapped by denali_{read,write}_page_raw. Do not + * use devm_kmalloc() because the memory allocated by devm_ does not + * guarantee DMA-safe alignment. + */ + denali->buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); + if (!denali->buf) { + ret = -ENOMEM; + goto disable_irq; + } + ret = nand_scan_tail(mtd); if (ret) - goto disable_irq; + goto free_buf; ret = mtd_device_register(mtd, NULL, 0); if (ret) { dev_err(denali->dev, "Failed to register MTD: %d\n", ret); - goto disable_irq; + goto free_buf; } return 0; +free_buf: + kfree(denali->buf); disable_irq: denali_disable_irq(denali); @@ -1516,6 +1523,7 @@ void denali_remove(struct denali_nand_info *denali) struct mtd_info *mtd = nand_to_mtd(&denali->nand); nand_release(mtd); + kfree(denali->buf); denali_disable_irq(denali); } EXPORT_SYMBOL(denali_remove); From patchwork Mon Jun 5 23:22:02 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 103108 Delivered-To: patch@linaro.org Received: by 10.182.29.35 with SMTP id g3csp1008954obh; Mon, 5 Jun 2017 16:27:17 -0700 (PDT) X-Received: by 10.101.83.143 with SMTP id x15mr13825808pgq.205.1496705237331; Mon, 05 Jun 2017 16:27:17 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1496705237; cv=none; d=google.com; s=arc-20160816; b=u8M9SkicJiaAeG76g5AyIFTYIG3W+q1+kCWGPpxxXNykJTvHy1ENV5o/8YBqc/Uauj wqKuBijqKjYw8pcZWcDZdAqxyDXjXEh4CRCc61lQc5KFYhmiqdi/l2Cn3sYc3m2Vzv2k h69MeesJcrhGGbwPLENbPXWbB1EpUanvwdgEd9lqLfYo+XylRm7MOGhlPycT8R0TB+gX /trSRwgxzRqTLSPeH6Lyd9aWC+j6VwxhLYWwJegGRL1dwyEn2cUSIVqlvyNAvV7bwOMx 6LglObyzET2FtrEHG0mKK4XDLcIEAQ43vQn25xTpyGoqqngWsVEonhgSCD5jbNa9zqCP oW9w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=pSQIQQPbnzDx4Brpq0HoAJS6AnQqzqXm60jWxZfUhDs=; b=kDCcbsCqVPahegNhFqCSG2lsWv03PLudX0u4F/Y5H7Xjq6XSIbx/PTF6crex1RwE2Z sdLbh5qTzyl0b+jbJYdXY4LX9aPgoB7xHwQmPKMBXf2QRXzAqUh4WeHgMkZj+DgY+kbv 5ZXGkp70mDUwQthbtj3K+45nQyp/PrQmhQvV/guXtmTQ2RsXWF2XDM0hirfvZ0IigsQy 0Q2ByxXpPgaSKwaWNTct6Wi9DlbMnPWedciTGtMw4v70YXy0qqq1gmkNx58R7FMF2cnw YDM7n4k5Yw5sVjIX2qK2WtjoEMkjw7g7s/XIVjv7Qsp0dgJRk/E/Nf2A/sCyVoQxsdQP ypOA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id i7si32017216pfi.233.2017.06.05.16.27.17; Mon, 05 Jun 2017 16:27:17 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751483AbdFEX0x (ORCPT + 25 others); Mon, 5 Jun 2017 19:26:53 -0400 Received: from conuserg-10.nifty.com ([210.131.2.77]:32327 "EHLO conuserg-10.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751348AbdFEXZX (ORCPT ); Mon, 5 Jun 2017 19:25:23 -0400 Received: from grover.sesame (FL1-118-110-19-204.osk.mesh.ad.jp [118.110.19.204]) (authenticated) by conuserg-10.nifty.com with ESMTP id v55NMD5x004412; Tue, 6 Jun 2017 08:22:54 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-10.nifty.com v55NMD5x004412 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1496704975; bh=pSQIQQPbnzDx4Brpq0HoAJS6AnQqzqXm60jWxZfUhDs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qj99ugpepQP3G9SzRNFEUrwBJq4ata2rZJ2P0YFcuLP7N+bHPtquqB3AtOj1Hna1w 25xghXNrnYXI4UXzKap+il5FTJuJ7gFXDTDfvbRoqrCfxqnujdkVf9r85u5Ch5cBHS S/FG60N9aZPJ68WamYaYmDX8to70gfi0Av0QRVixsyc1AFspkimT14XifADUSJIovS Zsg+oaJEMbcMF5yTL4GPkr4D1QlEt/wca4VjyHmSsGuYo2PSRuXFQUWX0EO1ek5ScW d1so5zYgiSA2AwP4uTCxe1SdhvT2i+DWasvxZ5A2BZpNKSBjqw0Oe5zh0zin5Je7we yBdxjZbI5IS3Q== X-Nifty-SrcIP: [118.110.19.204] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Cc: Enrico Jorns , Artem Bityutskiy , Dinh Nguyen , Boris Brezillon , Marek Vasut , Graham Moore , David Woodhouse , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Masahiro Yamada , Cyrille Pitchen , linux-kernel@vger.kernel.org, Brian Norris , Richard Weinberger Subject: [PATCH v4 23/23] mtd: nand: denali: enable bad block table scan Date: Tue, 6 Jun 2017 08:22:02 +0900 Message-Id: <1496704922-12261-24-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> References: <1496704922-12261-1-git-send-email-yamada.masahiro@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Now this driver is ready to remove NAND_SKIP_BBTSCAN. The BBT descriptors in denali.c are equivalent to the ones in nand_bbt.c. There is no need to duplicate the equivalent structures. The with-oob decriptors do not work for this driver anyway. The bbt_pattern (offs = 8) and the version (veroffs = 12) area overlaps the ECC area. Set NAND_BBT_NO_OOB flag to use the no_oob variant of the BBT descriptors. Signed-off-by: Masahiro Yamada --- Changes in v4: None Changes in v3: None Changes in v2: - Newly added drivers/mtd/nand/denali.c | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) -- 2.7.4 diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index f2b1592..5a58bd7 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1263,29 +1263,6 @@ static const struct mtd_ooblayout_ops denali_ooblayout_ops = { .free = denali_ooblayout_free, }; -static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; -static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; - -static struct nand_bbt_descr bbt_main_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE - | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 8, - .len = 4, - .veroffs = 12, - .maxblocks = 4, - .pattern = bbt_pattern, -}; - -static struct nand_bbt_descr bbt_mirror_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE - | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 8, - .len = 4, - .veroffs = 12, - .maxblocks = 4, - .pattern = mirror_pattern, -}; - /* initialize driver data structures */ static void denali_drv_init(struct denali_nand_info *denali) { @@ -1428,13 +1405,9 @@ int denali_init(struct denali_nand_info *denali) * bad block management. */ - /* Bad block management */ - chip->bbt_td = &bbt_main_descr; - chip->bbt_md = &bbt_mirror_descr; - - /* skip the scan for now until we have OOB read and write support */ chip->bbt_options |= NAND_BBT_USE_FLASH; - chip->options |= NAND_SKIP_BBTSCAN; + chip->bbt_options |= NAND_BBT_NO_OOB; + chip->ecc.mode = NAND_ECC_HW_SYNDROME; /* no subpage writes on denali */