From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 74392C4321E for ; Wed, 2 Nov 2022 11:29:34 +0000 (UTC) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id C31C0850B2; Wed, 2 Nov 2022 12:28:57 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="NUci/Isd"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id ED93184E74; Wed, 2 Nov 2022 07:15:38 +0100 (CET) Received: from mail-pl1-x629.google.com (mail-pl1-x629.google.com [IPv6:2607:f8b0:4864:20::629]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 7742884E74 for ; Wed, 2 Nov 2022 07:15:34 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=liangyanyu13@gmail.com Received: by mail-pl1-x629.google.com with SMTP id j12so15635071plj.5 for ; Tue, 01 Nov 2022 23:15:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=references:in-reply-to:message-id:date:subject:cc:to:from:from:to :cc:subject:date:message-id:reply-to; bh=bMxkz3Y/ev9W3wKi/UG2B+dx9yCn2eWhiHBiqdhTFAU=; b=NUci/IsdUhFMggpw0uQ9KH5XxaGv0LYjYwL5MMHhVCUbBeBCdaIZcwfot0QVARYE7U +c7Oq9LGstnbyW0VBzjjiL9d3yrfD5AXm5PbDW+C6P/OWlpHs0DXhCWPYWjHo6cYBjW0 sxOtrAoPwm6Mz915JcDg4Jd/aGCLGydg4R/LCC2/Al9YXK//uxGlxrIiHS16odda3OYC yZC/7ANwUctN19zHR/PZP/MBE7sHVMdrTDk9OtcrUHdaQronbpy15vfxzjw/EcrFFzfW iIEcYtRkaUy2GrsQfH7NQbortktgauVcrzGWU6De7xz+RCAeAbu3RZMwX+3osve3bpDG +UOQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=references:in-reply-to:message-id:date:subject:cc:to:from :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=bMxkz3Y/ev9W3wKi/UG2B+dx9yCn2eWhiHBiqdhTFAU=; b=Bdx/mr5nib9+zBE27cmuNFaEqAP181tplK5NIiM4qhCjY4QZq3d0odLn7xDsNtonm7 Hs+jNtH5kOMhv/HeQ1LqhRHdQiXk7Zdl4yCk5GJfJC66mCD8lqN3gZ5eM8a/kr0lQRxN hFKY7KRJbTVN3EHTVYMJSzqmnoZht/Ygoaqqm0BzGnn0uFg0VaEt3egoKeOEsR2cLIrU 9lxa2r424sh+3B2cL1Tk7RQGFhVWLHhF4f5vuRtnCwUT7E1HNvdkgzf78Hz7fts3hBwP UW7FmIO1HlOjSJm7XCY0nJBnYSG3mk9CD5CLfrFvYn3r3II/AqQ+BcRlJ1e1ZiiQbp9e G3hw== X-Gm-Message-State: ACrzQf2LnPCRI+Oigd96TxWc5mDpAYH6DwWnhrnmWJ7ITU6gJrqrtl09 4HR3JAdh0HC2f4lSERlW5zSLWBzbVoI= X-Google-Smtp-Source: AMsMyM5/g+xdJdsMWYTgfGdKDQS36WtAQP09WYE1sW/6XJPp4xZIn9SZey3aCZfRO/e6VjiXhf2dog== X-Received: by 2002:a17:903:1112:b0:179:ce23:dd57 with SMTP id n18-20020a170903111200b00179ce23dd57mr23800416plh.114.1667369732680; Tue, 01 Nov 2022 23:15:32 -0700 (PDT) Received: from localhost.localdomain ([123.51.145.88]) by smtp.gmail.com with ESMTPSA id v128-20020a626186000000b0056328e516f4sm7805882pfb.148.2022.11.01.23.15.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Nov 2022 23:15:32 -0700 (PDT) From: Leo Yu To: dario.binacchi@amarulasolutions.com, michael@amarulasolutions.com, miquel.raynal@bootlin.com, u-boot@lists.denx.de Cc: jaimeliao.tw@gmail.com, Leo Yu Subject: [PATCH v2 4/5] mtd: spinand: Add continuous read operation Date: Wed, 2 Nov 2022 14:14:31 +0800 Message-Id: <20221102061432.7113-5-liangyanyu13@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20221102061432.7113-1-liangyanyu13@gmail.com> References: <20221102061432.7113-1-liangyanyu13@gmail.com> X-Mailman-Approved-At: Wed, 02 Nov 2022 12:28:41 +0100 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean The flow of continuous read operation is: firstly, starting with the page read command and the 1st page data will be read into the cache after the read latency tRD. Secondly, issuing the Read From Cache commands (03h/0Bh/3Bh/6Bh/BBh/EBh) to read out the data from cache continuously. After all the data is read out, the host should pull CS# high to terminate this continuous read operation and wait tRST for the NAND device resets read operation. The continuous read usage is enabled by reading multiple pages (at least greater than 1 page size) and the column address is "don't care" in this operation, since the data output for each page will always start from byte 0 and a full page data should be read out for each page. On the other hand, since the continuous read mode can only read the entire page of data and cannot read the oob data, the dynamic mode switching is added to enable continuous read mode and disable continuous read mode in spinand_continuous_read to avoid abnormal writing and erasing operations. The performance of continuous read mode is as follows. Set the flash to QSPI mode and run 25MHz direct mapping mode on the SPI bus and use the MTD test module to show the performance of continuous reads. Signed-off-by: Leo Yu --- drivers/mtd/nand/spi/core.c | 120 +++++++++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 9d628f6f26..b28962f921 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -269,7 +269,10 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand, u16 column = 0; int ret; - if (req->datalen) { + if (spinand->use_continuous_read) { + buf = req->databuf.in; + nbytes = req->datalen; + } else if (req->datalen) { adjreq.datalen = nanddev_page_size(nand); adjreq.dataoffs = 0; adjreq.databuf.in = spinand->databuf; @@ -312,6 +315,9 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand, op.addr.val += op.data.nbytes; } + if (spinand->use_continuous_read) + return 0; + if (req->datalen) memcpy(req->databuf.in, spinand->databuf + req->dataoffs, req->datalen); @@ -577,6 +583,105 @@ static int spinand_write_page(struct spinand_device *spinand, return ret; } +static int spinand_continuous_read(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *req, + struct nand_io_iter *iter) +{ + struct spinand_device *spinand = mtd_to_spinand(mtd); + struct nand_device *nand = mtd_to_nanddev(mtd); + int ret = 0; + + bool enable_cont_read = true; + bool enable_ecc = false; + + /* + * Since the continuous read mode can only read the entire page of data + * and cannot read the oob data, therefore, only ECC-Free SPI-NAND support + * continuous read mode now. + */ + iter->req.mode = MTD_OPS_RAW; + iter->req.ooblen = 0; + + req->retlen = 0; + + /* Read the first unaligned page with conventional read */ + if (from & (nanddev_page_size(nand) - 1)) { + pr_debug("address not aligned\n"); + + iter->req.databuf.in = req->datbuf; + iter->req.dataoffs = nanddev_offs_to_pos(nand, from, &iter->req.pos); + iter->req.datalen = nanddev_page_size(nand) - iter->req.dataoffs; + + schedule(); + ret = spinand_select_target(spinand, iter->req.pos.target); + if (ret) + return ret; + + spinand_read_page(spinand, &iter->req, enable_ecc); + if (ret) + return ret; + + req->retlen += iter->req.datalen; + } + + iter->req.dataoffs = nanddev_offs_to_pos(nand, from + req->retlen, &iter->req.pos); + iter->req.databuf.in = req->datbuf + req->retlen; + iter->req.datalen = req->totallen - req->retlen; + + schedule(); + ret = spinand_continuous_read_enable(spinand, enable_cont_read); + if (ret) + return ret; + + ret = spinand_select_target(spinand, iter->req.pos.target); + if (ret) { + req->retlen = 0; + goto continuous_read_error; + } + + /* + * The continuous read operation including: firstly, starting with the + * page read command and the 1 st page data will be read into the cache + * after the read latency tRD. Secondly, Issuing the Read From Cache + * commands (03h/0Bh/3Bh/6Bh/BBh/EBh) to read out the data from cache + * continuously. + * + * The cache is divided into two halves, while one half of the cache is + * outputting the data, the other half will be loaded for the new data; + * therefore, the host can read out the data continuously from page to + * page. Multiple of Read From Cache commands can be issued in one + * continuous read operation, each Read From Cache command is required + * to read multiple 4-byte data exactly; otherwise, the data output will + * be out of sequence from one Read From Cache command to another Read + * From Cache command. + * + * After all the data is read out, the host should pull CS# high to + * terminate this continuous read operation and wait a 6us of tRST for + * the NAND device resets read operation. The data output for each page + * will always start from byte 0 and a full page data should be read out + * for each page. + */ + ret = spinand_read_page(spinand, &iter->req, enable_ecc); + if (ret) { + req->retlen = 0; + goto continuous_read_error; + } + + ret = spinand_reset_op(spinand); + if (ret) { + req->retlen = 0; + goto continuous_read_error; + } + + req->retlen += iter->req.datalen; + +continuous_read_error: + enable_cont_read = false; + ret = spinand_continuous_read_enable(spinand, enable_cont_read); + + return ret; +} + static int spinand_mtd_read(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { @@ -594,6 +699,18 @@ static int spinand_mtd_read(struct mtd_info *mtd, loff_t from, #ifndef __UBOOT__ mutex_lock(&spinand->lock); #endif + /* + * If the device supports continuous read mode and the read length is greater + * than one page size, the device will enter the continuous read mode. This mode + * helps avoiding issuing a page read command and read from cache command + * again, and improves the performance of reading continuous pages. + */ + if ((spinand->flags & SPINAND_HAS_CONT_READ_BIT) && + (ops->totallen > nanddev_page_size(nand))) { + ret = spinand_continuous_read(mtd, from, ops, &iter); + + goto continuous_read_finish; + } nanddev_io_for_each_page(nand, from, ops, &iter) { schedule(); @@ -622,6 +739,7 @@ static int spinand_mtd_read(struct mtd_info *mtd, loff_t from, ops->oobretlen += iter.req.ooblen; } +continuous_read_finish: #ifndef __UBOOT__ mutex_unlock(&spinand->lock); #endif -- 2.17.1