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; };