[PATCH] drivers: mtd: nand: Use Cadence-specific onfi_set_feature

dinesh.maniyam at altera.com dinesh.maniyam at altera.com
Tue Jun 17 06:58:42 CEST 2025


From: Dinesh Maniyam <dinesh.maniyam at altera.com>

Implement Cadence-specific onfi_set_features and onfi_get_features ops
to support ONFI optional commands via standard NAND hooks. The Cadence
controller performs 32-bit writes per transaction, different from the
legacy single byte transaction for SET_FEATURES command.
Hence, using legacy byte-wise writes introduces redundant overhead
after a SET_FEATURES command. This specific implementation will use
the single-buffered write for SET_FEATURES cmd.
As  ONFI_SUBFEATURE_PARAM_LEN  also 4bytes, a single transaction
is enough to write the full timing parameter in SET_FEATURE cmd.
Matches Linux Cadence NAND implementation to ensure reliable and efficient
feature setting.

Signed-off-by: Dinesh Maniyam <dinesh.maniyam at altera.com>
---
 drivers/mtd/nand/raw/cadence_nand.c | 55 +++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/drivers/mtd/nand/raw/cadence_nand.c b/drivers/mtd/nand/raw/cadence_nand.c
index 27aa7f97a45..7093343b7e3 100644
--- a/drivers/mtd/nand/raw/cadence_nand.c
+++ b/drivers/mtd/nand/raw/cadence_nand.c
@@ -2140,6 +2140,59 @@ static void cadence_nand_write_byte(struct mtd_info *mtd, u8 byte)
 	cadence_nand_write_buf(mtd, &byte, 1);
 }
 
+static int cadence_set_features_op(struct nand_chip *chip, u8 feature,
+				   const void *data)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	const u8 *params = data;
+	int status;
+
+	cadence_nand_cmdfunc(mtd, NAND_CMD_SET_FEATURES, feature, -1);
+	cadence_nand_write_buf(mtd, params, ONFI_SUBFEATURE_PARAM_LEN);
+
+	status = cadence_nand_waitfunc(mtd, chip);
+	if (status & NAND_STATUS_FAIL)
+		return -EIO;
+
+	return 0;
+}
+
+static int cadence_get_features_op(struct nand_chip *chip, u8 feature,
+				   void *data)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	u8 *params = data;
+
+	cadence_nand_cmdfunc(mtd, NAND_CMD_GET_FEATURES, feature, -1);
+	cadence_nand_read_buf(mtd, params, ONFI_SUBFEATURE_PARAM_LEN);
+
+	return 0;
+}
+
+static int cadence_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
+				     int addr, uint8_t *subfeature_param)
+{
+	if (IS_ENABLED(CONFIG_SYS_NAND_ONFI_DETECTION))
+		if (!chip->onfi_version ||
+		    !(le16_to_cpu(chip->onfi_params.opt_cmd)
+		    & ONFI_OPT_CMD_SET_GET_FEATURES))
+			return -EOPNOTSUPP;
+
+	return cadence_set_features_op(chip, addr, subfeature_param);
+}
+
+static int cadence_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
+				     int addr, uint8_t *subfeature_param)
+{
+	if (IS_ENABLED(CONFIG_SYS_NAND_ONFI_DETECTION))
+		if (!chip->onfi_version ||
+		    !(le16_to_cpu(chip->onfi_params.opt_cmd)
+		    & ONFI_OPT_CMD_SET_GET_FEATURES))
+			return -EOPNOTSUPP;
+
+	return cadence_get_features_op(chip, addr, subfeature_param);
+}
+
 static int cadence_nand_chip_init(struct cadence_nand_info *cadence, ofnode node)
 {
 	struct cdns_nand_chip *cdns_chip;
@@ -2208,6 +2261,8 @@ static int cadence_nand_chip_init(struct cadence_nand_info *cadence, ofnode node
 	chip->read_buf = cadence_nand_read_buf;
 	chip->write_buf = cadence_nand_write_buf;
 	chip->setup_data_interface = cadence_setup_data_interface;
+	chip->onfi_set_features = cadence_onfi_set_features;
+	chip->onfi_get_features = cadence_onfi_get_features;
 
 	ret = nand_scan_ident(mtd, 1, NULL);
 	if (ret) {
-- 
2.35.3



More information about the U-Boot mailing list