linux-mtd.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: Miquel Raynal <miquel.raynal@bootlin.com>
To: Richard Weinberger <richard@nod.at>,
	Vignesh Raghavendra <vigneshr@ti.com>,
	Tudor Ambarus <Tudor.Ambarus@microchip.com>,
	<linux-mtd@lists.infradead.org>
Cc: Thomas Petazzoni <thomas.petazzoni@bootlin.com>,
	Michal Simek <monstr@monstr.eu>,
	Naga Sureshkumar Relli <nagasure@xilinx.com>,
	Amit Kumar Mahapatra <akumarma@xilinx.com>,
	Miquel Raynal <miquel.raynal@bootlin.com>
Subject: [PATCH 14/22] mtd: rawnand: Handle the double bytes in NV-DDR mode
Date: Wed,  5 May 2021 23:37:42 +0200	[thread overview]
Message-ID: <20210505213750.257417-15-miquel.raynal@bootlin.com> (raw)
In-Reply-To: <20210505213750.257417-1-miquel.raynal@bootlin.com>

As explained in chapter "NV-DDR / NV-DDR2 / NV-DDR3 and Repeat Bytes" of
the ONFI specification, with some commands (mainly the commands which do
not transfer actual data) the data bytes are repeated twice and it is
the responsibility of the receiver to discard them properly. The
concerned commands are: SET_FEATURES, READ_ID, GET_FEATURES,
READ_STATUS, READ_STATUS_ENHANCED, ODT_CONFIGURE. Hence, in the NAND
core we are only impacted by the implementation of READ_ID, GET_FEATURES
and READ_STATUS.

The logic is the same for all:
2/ Check if it is relevant to read all data bytes twice.
1/ Allocate a buffer with twice the requested size (may be done
   statically).
2/ Update the instruction structure to read these extra bytes in the
   allocated buffer.
3/ Copy the even bytes into the original buffer. The performance hit is
   negligible on such small data transfers anyway and we don't really
   care about performances at this stage anyway.
4/ Free the allocated buffer, if any.

Note: nand_data_read_op() is also impacted because it is theoretically
possible to run the command/address cycles first, and, as another
operation, do the data transfers. In this case we can easily identify
the impacted commands because the force_8bit flag will be set (due to
the same reason: their data does not go through the same pipeline).

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/raw/nand_base.c | 93 +++++++++++++++++++++++++++++---
 1 file changed, 85 insertions(+), 8 deletions(-)

diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 6606882a3e77..9bde1a7c312c 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -1600,7 +1600,7 @@ int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
 		   unsigned int len)
 {
 	unsigned int i;
-	u8 *id = buf;
+	u8 *id = buf, *ddrbuf = NULL;
 
 	if (len && !buf)
 		return -EINVAL;
@@ -1615,12 +1615,31 @@ int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
 			NAND_OP_8BIT_DATA_IN(len, buf, 0),
 		};
 		struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
+		int ret;
+
+		/* READ_ID data bytes are received twice in NV-DDR mode */
+		if (len && nand_interface_is_nvddr(conf)) {
+			ddrbuf = kzalloc(len * 2, GFP_KERNEL);
+			if (!ddrbuf)
+				return -ENOMEM;
+
+			instrs[2].ctx.data.len *= 2;
+			instrs[2].ctx.data.buf.in = ddrbuf;
+		}
 
 		/* Drop the DATA_IN instruction if len is set to 0. */
 		if (!len)
 			op.ninstrs--;
 
-		return nand_exec_op(chip, &op);
+		ret = nand_exec_op(chip, &op);
+		if (!ret && len && nand_interface_is_nvddr(conf)) {
+			for (i = 0; i < len; i++)
+				id[i] = ddrbuf[i * 2];
+		}
+
+		kfree(ddrbuf);
+
+		return ret;
 	}
 
 	chip->legacy.cmdfunc(chip, NAND_CMD_READID, addr, -1);
@@ -1648,17 +1667,29 @@ int nand_status_op(struct nand_chip *chip, u8 *status)
 	if (nand_has_exec_op(chip)) {
 		const struct nand_interface_config *conf =
 			nand_get_interface_config(chip);
+		u8 ddrstatus[2];
 		struct nand_op_instr instrs[] = {
 			NAND_OP_CMD(NAND_CMD_STATUS,
 				    NAND_COMMON_TIMING_NS(conf, tADL_min)),
 			NAND_OP_8BIT_DATA_IN(1, status, 0),
 		};
 		struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
+		int ret;
+
+		/* The status data byte will be received twice in NV-DDR mode */
+		if (status && nand_interface_is_nvddr(conf)) {
+			instrs[1].ctx.data.len *= 2;
+			instrs[1].ctx.data.buf.in = ddrstatus;
+		}
 
 		if (!status)
 			op.ninstrs--;
 
-		return nand_exec_op(chip, &op);
+		ret = nand_exec_op(chip, &op);
+		if (!ret && status && nand_interface_is_nvddr(conf))
+			*status = ddrstatus[0];
+
+		return ret;
 	}
 
 	chip->legacy.cmdfunc(chip, NAND_CMD_STATUS, -1, -1);
@@ -1821,7 +1852,7 @@ static int nand_set_features_op(struct nand_chip *chip, u8 feature,
 static int nand_get_features_op(struct nand_chip *chip, u8 feature,
 				void *data)
 {
-	u8 *params = data;
+	u8 *params = data, ddrbuf[ONFI_SUBFEATURE_PARAM_LEN * 2];
 	int i;
 
 	if (nand_has_exec_op(chip)) {
@@ -1837,8 +1868,21 @@ static int nand_get_features_op(struct nand_chip *chip, u8 feature,
 					     data, 0),
 		};
 		struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
+		int ret;
 
-		return nand_exec_op(chip, &op);
+		/* GET_FEATURE data bytes are received twice in NV-DDR mode */
+		if (nand_interface_is_nvddr(conf)) {
+			instrs[3].ctx.data.len *= 2;
+			instrs[3].ctx.data.buf.in = ddrbuf;
+		}
+
+		ret = nand_exec_op(chip, &op);
+		if (nand_interface_is_nvddr(conf)) {
+			for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; i++)
+				params[i] = ddrbuf[i * 2];
+		}
+
+		return ret;
 	}
 
 	chip->legacy.cmdfunc(chip, NAND_CMD_GET_FEATURES, feature, -1);
@@ -1924,17 +1968,50 @@ int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
 		return -EINVAL;
 
 	if (nand_has_exec_op(chip)) {
+		const struct nand_interface_config *conf =
+			nand_get_interface_config(chip);
 		struct nand_op_instr instrs[] = {
 			NAND_OP_DATA_IN(len, buf, 0),
 		};
 		struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs);
+		u8 *ddrbuf = NULL;
+		int ret, i;
 
 		instrs[0].ctx.data.force_8bit = force_8bit;
 
-		if (check_only)
-			return nand_check_op(chip, &op);
+		/*
+		 * Parameter payloads (ID, status, features, etc) do not go
+		 * through the same pipeline as regular data, hence the
+		 * force_8bit flag must be set and this also indicates that in
+		 * case NV-DDR timings are being used the data will be received
+		 * twice.
+		 */
+		if (force_8bit && nand_interface_is_nvddr(conf)) {
+			ddrbuf = kzalloc(len * 2, GFP_KERNEL);
+			if (!ddrbuf)
+				return -ENOMEM;
 
-		return nand_exec_op(chip, &op);
+			instrs[0].ctx.data.len *= 2;
+			instrs[0].ctx.data.buf.in = ddrbuf;
+		}
+
+		if (check_only) {
+			ret = nand_check_op(chip, &op);
+			kfree(ddrbuf);
+			return ret;
+		}
+
+		ret = nand_exec_op(chip, &op);
+		if (!ret && force_8bit && nand_interface_is_nvddr(conf)) {
+			u8 *dst = buf;
+
+			for (i = 0; i < len; i++)
+				dst[i] = ddrbuf[i * 2];
+		}
+
+		kfree(ddrbuf);
+
+		return ret;
 	}
 
 	if (check_only)
-- 
2.27.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

  parent reply	other threads:[~2021-05-05 21:59 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-05 21:37 [PATCH 00/22] mtd: rawnand: NV-DDR support Miquel Raynal
2021-05-05 21:37 ` [PATCH 01/22] mtd: rawnand: Add a helper to clarify the interface configuration Miquel Raynal
2021-05-26  9:05   ` Miquel Raynal
2021-05-05 21:37 ` [PATCH 02/22] mtd: rawnand: arasan: Check the proposed data interface is supported Miquel Raynal
2021-05-26  9:05   ` Miquel Raynal
2021-05-05 21:37 ` [PATCH 03/22] mtd: rawnand: atmel: " Miquel Raynal
2021-05-26  9:05   ` Miquel Raynal
2021-05-05 21:37 ` [PATCH 04/22] mtd: rawnand: onfi: Use the BIT() macro when possible Miquel Raynal
2021-05-26  9:05   ` Miquel Raynal
2021-05-05 21:37 ` [PATCH 05/22] mtd: rawnand: Update dead URL Miquel Raynal
2021-05-26  9:05   ` Miquel Raynal
2021-05-05 21:37 ` [PATCH 06/22] mtd: rawnand: Use more recent ONFI specification wording Miquel Raynal
2021-05-26  9:05   ` Miquel Raynal
2021-05-05 21:37 ` [PATCH 07/22] mtd: rawnand: Clarify the NV-DDR entries in the ONFI structure Miquel Raynal
2021-05-26  9:04   ` Miquel Raynal
2021-05-05 21:37 ` [PATCH 08/22] mtd: rawnand: Add NV-DDR timings Miquel Raynal
2021-05-26  9:04   ` Miquel Raynal
2021-05-05 21:37 ` [PATCH 09/22] mtd: rawnand: Retrieve NV-DDR timing modes from the ONFI parameter page Miquel Raynal
2021-05-26  9:04   ` Miquel Raynal
2021-05-05 21:37 ` [PATCH 10/22] mtd: rawnand: Add an indirection on onfi_fill_interface_config() Miquel Raynal
2021-05-26  9:04   ` Miquel Raynal
2021-05-05 21:37 ` [PATCH 11/22] mtd: rawnand: Add onfi_fill_nvddr_interface_config() helper Miquel Raynal
2021-05-26  9:04   ` Miquel Raynal
2021-05-05 21:37 ` [PATCH 12/22] mtd: rawnand: Avoid accessing NV-DDR timings from legacy code Miquel Raynal
2021-05-26  9:04   ` Miquel Raynal
2021-05-05 21:37 ` [PATCH 13/22] mtd: rawnand: Access SDR and NV-DDR timings through a common macro Miquel Raynal
2021-05-26  9:04   ` Miquel Raynal
2021-05-05 21:37 ` Miquel Raynal [this message]
2021-05-26  9:04   ` [PATCH 14/22] mtd: rawnand: Handle the double bytes in NV-DDR mode Miquel Raynal
2021-05-05 21:37 ` [PATCH 15/22] mtd: rawnand: Add a helper to find the closest ONFI " Miquel Raynal
2021-05-26  9:04   ` Miquel Raynal
2021-05-05 21:37 ` [PATCH 16/22] mtd: rawnand: Support enabling NV-DDR through SET_FEATURES Miquel Raynal
2021-05-05 21:37 ` [PATCH 17/22] mtd: rawnand: Allow SDR timings to be nacked Miquel Raynal
2021-05-26  9:04   ` Miquel Raynal
2021-05-05 21:37 ` [PATCH 18/22] mtd: rawnand: Choose the best timings, NV-DDR included Miquel Raynal
2021-05-26  9:04   ` Miquel Raynal
2021-05-05 21:37 ` [PATCH 19/22] MAINTAINERS: Add myself as co-maintainer of the Arasan NAND controller driver Miquel Raynal
2021-05-26  9:04   ` Miquel Raynal
2021-05-05 21:37 ` [PATCH 20/22] mtd: rawnand: arasan: Fix a macro parameter Miquel Raynal
2021-05-26  9:03   ` Miquel Raynal
2021-05-05 21:37 ` [PATCH 21/22] mtd: rawnand: arasan: Workaround a misbehaving prog type with NV-DDR Miquel Raynal
2021-05-26  9:03   ` Miquel Raynal
2021-05-05 21:37 ` [PATCH 22/22] mtd: rawnand: arasan: Support NV-DDR interface Miquel Raynal
2021-05-26  9:03   ` Miquel Raynal

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210505213750.257417-15-miquel.raynal@bootlin.com \
    --to=miquel.raynal@bootlin.com \
    --cc=Tudor.Ambarus@microchip.com \
    --cc=akumarma@xilinx.com \
    --cc=linux-mtd@lists.infradead.org \
    --cc=monstr@monstr.eu \
    --cc=nagasure@xilinx.com \
    --cc=richard@nod.at \
    --cc=thomas.petazzoni@bootlin.com \
    --cc=vigneshr@ti.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).