All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] mtd: rawnand: qcom: Implement exec_op()
@ 2022-06-03 16:24 ` Md Sadre Alam
  0 siblings, 0 replies; 14+ messages in thread
From: Md Sadre Alam @ 2022-06-03 16:24 UTC (permalink / raw)
  To: mani, miquel.raynal, richard, vigneshr, linux-mtd, linux-arm-msm,
	linux-kernel
  Cc: quic_srichara, quic_mdalam

Implement exec_op() so we can later get rid of the legacy interface
implementation.

Co-developed-by: Sricharan R <quic_srichara@quicinc.com>
Signed-off-by: Sricharan R <quic_srichara@quicinc.com>
Signed-off-by: Md Sadre Alam <quic_mdalam@quicinc.com>
---
 drivers/mtd/nand/raw/qcom_nandc.c | 368 +++++++++++++++++++++-----------------
 1 file changed, 204 insertions(+), 164 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
index 048b255..507921b 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -14,6 +14,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/delay.h>
+#include <linux/iopoll.h>
 #include <linux/dma/qcom_bam_dma.h>
 
 /* NANDc reg offsets */
@@ -1305,15 +1306,13 @@ static int nandc_param(struct qcom_nand_host *host)
 }
 
 /* sets up descriptors for NAND_CMD_ERASE1 */
-static int erase_block(struct qcom_nand_host *host, int page_addr)
+static int erase_block(struct qcom_nand_host *host)
 {
 	struct nand_chip *chip = &host->chip;
 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
 
 	nandc_set_reg(chip, NAND_FLASH_CMD,
 		      OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE);
-	nandc_set_reg(chip, NAND_ADDR0, page_addr);
-	nandc_set_reg(chip, NAND_ADDR1, 0);
 	nandc_set_reg(chip, NAND_DEV0_CFG0,
 		      host->cfg0_raw & ~(7 << CW_PER_PAGE));
 	nandc_set_reg(chip, NAND_DEV0_CFG1, host->cfg1_raw);
@@ -1321,14 +1320,8 @@ static int erase_block(struct qcom_nand_host *host, int page_addr)
 	nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus);
 	nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus);
 
-	write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
+	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
 	write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
-	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
-	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-
-	write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
-	write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
 
 	return 0;
 }
@@ -1343,16 +1336,12 @@ static int read_id(struct qcom_nand_host *host, int column)
 		return 0;
 
 	nandc_set_reg(chip, NAND_FLASH_CMD, OP_FETCH_ID);
-	nandc_set_reg(chip, NAND_ADDR0, column);
-	nandc_set_reg(chip, NAND_ADDR1, 0);
 	nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT,
 		      nandc->props->is_bam ? 0 : DM_EN);
 	nandc_set_reg(chip, NAND_EXEC_CMD, 1);
 
-	write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
-	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
-	read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
+	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
+	write_reg_dma(nandc, NAND_FLASH_CHIP_SELECT, 1, NAND_BAM_NEXT_SGL);
 
 	return 0;
 }
@@ -1491,7 +1480,6 @@ static void parse_erase_write_errors(struct qcom_nand_host *host, int command)
 
 	for (i = 0; i < num_cw; i++) {
 		u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
-
 		if (flash_status & FS_MPU_ERR)
 			host->status &= ~NAND_STATUS_WP;
 
@@ -1523,86 +1511,6 @@ static void post_command(struct qcom_nand_host *host, int command)
 }
 
 /*
- * Implements chip->legacy.cmdfunc. It's  only used for a limited set of
- * commands. The rest of the commands wouldn't be called by upper layers.
- * For example, NAND_CMD_READOOB would never be called because we have our own
- * versions of read_oob ops for nand_ecc_ctrl.
- */
-static void qcom_nandc_command(struct nand_chip *chip, unsigned int command,
-			       int column, int page_addr)
-{
-	struct qcom_nand_host *host = to_qcom_nand_host(chip);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	bool wait = false;
-	int ret = 0;
-
-	pre_command(host, command);
-
-	switch (command) {
-	case NAND_CMD_RESET:
-		ret = reset(host);
-		wait = true;
-		break;
-
-	case NAND_CMD_READID:
-		nandc->buf_count = 4;
-		ret = read_id(host, column);
-		wait = true;
-		break;
-
-	case NAND_CMD_PARAM:
-		ret = nandc_param(host);
-		wait = true;
-		break;
-
-	case NAND_CMD_ERASE1:
-		ret = erase_block(host, page_addr);
-		wait = true;
-		break;
-
-	case NAND_CMD_READ0:
-		/* we read the entire page for now */
-		WARN_ON(column != 0);
-
-		host->use_ecc = true;
-		set_address(host, 0, page_addr);
-		update_rw_regs(host, ecc->steps, true, 0);
-		break;
-
-	case NAND_CMD_SEQIN:
-		WARN_ON(column != 0);
-		set_address(host, 0, page_addr);
-		break;
-
-	case NAND_CMD_PAGEPROG:
-	case NAND_CMD_STATUS:
-	case NAND_CMD_NONE:
-	default:
-		break;
-	}
-
-	if (ret) {
-		dev_err(nandc->dev, "failure executing command %d\n",
-			command);
-		free_descs(nandc);
-		return;
-	}
-
-	if (wait) {
-		ret = submit_descs(nandc);
-		if (ret)
-			dev_err(nandc->dev,
-				"failure submitting descs for command %d\n",
-				command);
-	}
-
-	free_descs(nandc);
-
-	post_command(host, command);
-}
-
-/*
  * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
  * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
  *
@@ -2044,7 +1952,6 @@ static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf,
 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
 	u8 *data_buf, *oob_buf = NULL;
-
 	nand_read_page_op(chip, page, 0, NULL, 0);
 	data_buf = buf;
 	oob_buf = oob_required ? chip->oob_poi : NULL;
@@ -2366,64 +2273,6 @@ static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs)
 }
 
 /*
- * the three functions below implement chip->legacy.read_byte(),
- * chip->legacy.read_buf() and chip->legacy.write_buf() respectively. these
- * aren't used for reading/writing page data, they are used for smaller data
- * like reading	id, status etc
- */
-static uint8_t qcom_nandc_read_byte(struct nand_chip *chip)
-{
-	struct qcom_nand_host *host = to_qcom_nand_host(chip);
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	u8 *buf = nandc->data_buffer;
-	u8 ret = 0x0;
-
-	if (host->last_command == NAND_CMD_STATUS) {
-		ret = host->status;
-
-		host->status = NAND_STATUS_READY | NAND_STATUS_WP;
-
-		return ret;
-	}
-
-	if (nandc->buf_start < nandc->buf_count)
-		ret = buf[nandc->buf_start++];
-
-	return ret;
-}
-
-static void qcom_nandc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
-{
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
-
-	memcpy(buf, nandc->data_buffer + nandc->buf_start, real_len);
-	nandc->buf_start += real_len;
-}
-
-static void qcom_nandc_write_buf(struct nand_chip *chip, const uint8_t *buf,
-				 int len)
-{
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
-
-	memcpy(nandc->data_buffer + nandc->buf_start, buf, real_len);
-
-	nandc->buf_start += real_len;
-}
-
-/* we support only one external chip for now */
-static void qcom_nandc_select_chip(struct nand_chip *chip, int chipnr)
-{
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-	if (chipnr <= 0)
-		return;
-
-	dev_warn(nandc->dev, "invalid chip select\n");
-}
-
-/*
  * NAND controller page layout info
  *
  * Layout with ECC enabled:
@@ -2738,8 +2587,207 @@ static int qcom_nand_attach_chip(struct nand_chip *chip)
 	return 0;
 }
 
+static int nandc_status(struct nand_chip *chip)
+{
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+
+	memcpy(nandc->data_buffer, &host->status, 1);
+
+	return 0;
+}
+
+static int qcom_nand_send_command(struct nand_chip *chip, u8 command)
+{
+	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+	int ret = 0;
+
+	pre_command(host, command);
+
+	switch (command) {
+	case NAND_CMD_RESET:
+		ret = reset(host);
+		break;
+	case NAND_CMD_READID:
+		nandc->buf_count = 4;
+		ret = read_id(host, 0);
+		break;
+	case NAND_CMD_PARAM:
+		ret = nandc_param(host);
+		break;
+	case NAND_CMD_ERASE1:
+		ret = erase_block(host);
+		break;
+	case NAND_CMD_STATUS:
+		ret = nandc_status(chip);
+		break;
+	case NAND_CMD_READ0:
+		host->use_ecc = true;
+		update_rw_regs(host, ecc->steps, true, 0);
+		break;
+	case NAND_CMD_ERASE2:
+		break;
+	case NAND_CMD_SEQIN:
+		break;
+	case NAND_CMD_PAGEPROG:
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static int qcom_nand_send_address(struct nand_chip *chip,
+				  const struct nand_op_instr *instr, int cmd)
+{
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	u32 page_addr = 0x0, page_mask = 0x0;
+
+	page_addr = instr->ctx.addr.addrs[0];
+
+	/*
+	 *Form page address for erase, read, write to using existing api
+	 */
+
+	switch (cmd) {
+	case NAND_CMD_ERASE1:
+		page_addr = instr->ctx.addr.addrs[0];
+		page_mask = instr->ctx.addr.addrs[1];
+		page_mask <<= 8;
+		page_addr = (page_addr | page_mask);
+		page_mask = instr->ctx.addr.addrs[2];
+		page_mask <<= 16;
+		page_addr = (page_addr | page_mask);
+		page_mask = instr->ctx.addr.addrs[3];
+		page_mask <<= 24;
+		page_addr = (page_addr | page_mask);
+		break;
+	case NAND_CMD_READ0:
+	case NAND_CMD_SEQIN:
+		page_addr = instr->ctx.addr.addrs[3];
+		page_addr <<= 24;
+		page_mask = instr->ctx.addr.addrs[2];
+		page_mask <<= 16;
+		page_addr |= page_mask;
+		page_mask = instr->ctx.addr.addrs[1];
+		page_mask <<= 8;
+		page_addr |= page_mask;
+		page_mask = instr->ctx.addr.addrs[0];
+		page_addr |= page_mask;
+		break;
+	default:
+		break;
+	}
+
+	if (cmd == NAND_CMD_PARAM)
+		return 0;
+
+	nandc_set_reg(chip, NAND_ADDR0, page_addr);
+	nandc_set_reg(chip, NAND_ADDR1, 0);
+
+	if (cmd != NAND_CMD_SEQIN)
+		write_reg_dma(nandc, NAND_ADDR0, 2, 0);
+
+	return 0;
+}
+
+static void qcom_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
+{
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+	memcpy(buf, nandc->data_buffer, len);
+}
+
+static int qcom_nand_exec_instr(struct nand_chip *chip,
+				const struct nand_op_instr *instr)
+{
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+	u32 status;
+	int ret = 0;
+	bool wait = false;
+	static int opcode;
+
+	switch (instr->type) {
+	case NAND_OP_CMD_INSTR:
+		ret = qcom_nand_send_command(chip, instr->ctx.cmd.opcode);
+		if (instr->ctx.cmd.opcode == NAND_CMD_RESET)
+			wait = true;
+		opcode = instr->ctx.cmd.opcode;
+		break;
+	case NAND_OP_ADDR_INSTR:
+		qcom_nand_send_address(chip, instr, opcode);
+		if (opcode != NAND_CMD_READ0 && opcode != NAND_CMD_READSTART &&
+		    opcode != NAND_CMD_PARAM && opcode != NAND_CMD_SEQIN)
+			wait = true;
+		break;
+	case NAND_OP_DATA_IN_INSTR:
+		qcom_nand_read_buf(chip, instr->ctx.data.buf.in, instr->ctx.data.len);
+		break;
+	case NAND_OP_DATA_OUT_INSTR:
+		wait = false;
+		break;
+	case NAND_OP_WAITRDY_INSTR:
+		ret = readl_poll_timeout(nandc->base + NAND_FLASH_STATUS, status,
+					 (status & FS_READY_BSY_N), 20,
+					 instr->ctx.waitrdy.timeout_ms * 1000);
+		if (opcode == NAND_CMD_PARAM)
+			wait = true;
+	default:
+		break;
+	}
+
+	if (wait) {
+		if (opcode != NAND_CMD_PARAM)
+			write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+
+		if (opcode == NAND_CMD_READID)
+			read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
+
+		if (opcode == NAND_CMD_ERASE1) {
+			read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
+			write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
+			write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
+		}
+
+		ret = submit_descs(nandc);
+		if (ret)
+			dev_err(nandc->dev, "failure submitting descs for command 0x%02x\n",
+				opcode);
+
+		free_descs(nandc);
+		post_command(host, opcode);
+	}
+
+	return ret;
+}
+
+static int qcom_nand_exec_op(struct nand_chip *chip,
+			     const struct nand_operation *op,
+				bool check_only)
+{
+	unsigned int i;
+	int ret = 0;
+
+	if (check_only)
+		return 0;
+
+	for (i = 0; i < op->ninstrs; i++) {
+		ret = qcom_nand_exec_instr(chip, &op->instrs[i]);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
 static const struct nand_controller_ops qcom_nandc_ops = {
 	.attach_chip = qcom_nand_attach_chip,
+	.exec_op = qcom_nand_exec_op,
 };
 
 static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
@@ -2938,14 +2986,6 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
 	mtd->owner = THIS_MODULE;
 	mtd->dev.parent = dev;
 
-	chip->legacy.cmdfunc	= qcom_nandc_command;
-	chip->legacy.select_chip	= qcom_nandc_select_chip;
-	chip->legacy.read_byte	= qcom_nandc_read_byte;
-	chip->legacy.read_buf	= qcom_nandc_read_buf;
-	chip->legacy.write_buf	= qcom_nandc_write_buf;
-	chip->legacy.set_features	= nand_get_set_features_notsupp;
-	chip->legacy.get_features	= nand_get_set_features_notsupp;
-
 	/*
 	 * the bad block marker is readable only when we read the last codeword
 	 * of a page with ECC disabled. currently, the nand_base and nand_bbt
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH] mtd: rawnand: qcom: Implement exec_op()
@ 2022-06-03 16:24 ` Md Sadre Alam
  0 siblings, 0 replies; 14+ messages in thread
From: Md Sadre Alam @ 2022-06-03 16:24 UTC (permalink / raw)
  To: mani, miquel.raynal, richard, vigneshr, linux-mtd, linux-arm-msm,
	linux-kernel
  Cc: quic_srichara, quic_mdalam

Implement exec_op() so we can later get rid of the legacy interface
implementation.

Co-developed-by: Sricharan R <quic_srichara@quicinc.com>
Signed-off-by: Sricharan R <quic_srichara@quicinc.com>
Signed-off-by: Md Sadre Alam <quic_mdalam@quicinc.com>
---
 drivers/mtd/nand/raw/qcom_nandc.c | 368 +++++++++++++++++++++-----------------
 1 file changed, 204 insertions(+), 164 deletions(-)

diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
index 048b255..507921b 100644
--- a/drivers/mtd/nand/raw/qcom_nandc.c
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
@@ -14,6 +14,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/delay.h>
+#include <linux/iopoll.h>
 #include <linux/dma/qcom_bam_dma.h>
 
 /* NANDc reg offsets */
@@ -1305,15 +1306,13 @@ static int nandc_param(struct qcom_nand_host *host)
 }
 
 /* sets up descriptors for NAND_CMD_ERASE1 */
-static int erase_block(struct qcom_nand_host *host, int page_addr)
+static int erase_block(struct qcom_nand_host *host)
 {
 	struct nand_chip *chip = &host->chip;
 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
 
 	nandc_set_reg(chip, NAND_FLASH_CMD,
 		      OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE);
-	nandc_set_reg(chip, NAND_ADDR0, page_addr);
-	nandc_set_reg(chip, NAND_ADDR1, 0);
 	nandc_set_reg(chip, NAND_DEV0_CFG0,
 		      host->cfg0_raw & ~(7 << CW_PER_PAGE));
 	nandc_set_reg(chip, NAND_DEV0_CFG1, host->cfg1_raw);
@@ -1321,14 +1320,8 @@ static int erase_block(struct qcom_nand_host *host, int page_addr)
 	nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus);
 	nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus);
 
-	write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
+	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
 	write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
-	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
-	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
-
-	write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
-	write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
 
 	return 0;
 }
@@ -1343,16 +1336,12 @@ static int read_id(struct qcom_nand_host *host, int column)
 		return 0;
 
 	nandc_set_reg(chip, NAND_FLASH_CMD, OP_FETCH_ID);
-	nandc_set_reg(chip, NAND_ADDR0, column);
-	nandc_set_reg(chip, NAND_ADDR1, 0);
 	nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT,
 		      nandc->props->is_bam ? 0 : DM_EN);
 	nandc_set_reg(chip, NAND_EXEC_CMD, 1);
 
-	write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
-	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
-
-	read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
+	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
+	write_reg_dma(nandc, NAND_FLASH_CHIP_SELECT, 1, NAND_BAM_NEXT_SGL);
 
 	return 0;
 }
@@ -1491,7 +1480,6 @@ static void parse_erase_write_errors(struct qcom_nand_host *host, int command)
 
 	for (i = 0; i < num_cw; i++) {
 		u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
-
 		if (flash_status & FS_MPU_ERR)
 			host->status &= ~NAND_STATUS_WP;
 
@@ -1523,86 +1511,6 @@ static void post_command(struct qcom_nand_host *host, int command)
 }
 
 /*
- * Implements chip->legacy.cmdfunc. It's  only used for a limited set of
- * commands. The rest of the commands wouldn't be called by upper layers.
- * For example, NAND_CMD_READOOB would never be called because we have our own
- * versions of read_oob ops for nand_ecc_ctrl.
- */
-static void qcom_nandc_command(struct nand_chip *chip, unsigned int command,
-			       int column, int page_addr)
-{
-	struct qcom_nand_host *host = to_qcom_nand_host(chip);
-	struct nand_ecc_ctrl *ecc = &chip->ecc;
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	bool wait = false;
-	int ret = 0;
-
-	pre_command(host, command);
-
-	switch (command) {
-	case NAND_CMD_RESET:
-		ret = reset(host);
-		wait = true;
-		break;
-
-	case NAND_CMD_READID:
-		nandc->buf_count = 4;
-		ret = read_id(host, column);
-		wait = true;
-		break;
-
-	case NAND_CMD_PARAM:
-		ret = nandc_param(host);
-		wait = true;
-		break;
-
-	case NAND_CMD_ERASE1:
-		ret = erase_block(host, page_addr);
-		wait = true;
-		break;
-
-	case NAND_CMD_READ0:
-		/* we read the entire page for now */
-		WARN_ON(column != 0);
-
-		host->use_ecc = true;
-		set_address(host, 0, page_addr);
-		update_rw_regs(host, ecc->steps, true, 0);
-		break;
-
-	case NAND_CMD_SEQIN:
-		WARN_ON(column != 0);
-		set_address(host, 0, page_addr);
-		break;
-
-	case NAND_CMD_PAGEPROG:
-	case NAND_CMD_STATUS:
-	case NAND_CMD_NONE:
-	default:
-		break;
-	}
-
-	if (ret) {
-		dev_err(nandc->dev, "failure executing command %d\n",
-			command);
-		free_descs(nandc);
-		return;
-	}
-
-	if (wait) {
-		ret = submit_descs(nandc);
-		if (ret)
-			dev_err(nandc->dev,
-				"failure submitting descs for command %d\n",
-				command);
-	}
-
-	free_descs(nandc);
-
-	post_command(host, command);
-}
-
-/*
  * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
  * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
  *
@@ -2044,7 +1952,6 @@ static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf,
 	struct qcom_nand_host *host = to_qcom_nand_host(chip);
 	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
 	u8 *data_buf, *oob_buf = NULL;
-
 	nand_read_page_op(chip, page, 0, NULL, 0);
 	data_buf = buf;
 	oob_buf = oob_required ? chip->oob_poi : NULL;
@@ -2366,64 +2273,6 @@ static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs)
 }
 
 /*
- * the three functions below implement chip->legacy.read_byte(),
- * chip->legacy.read_buf() and chip->legacy.write_buf() respectively. these
- * aren't used for reading/writing page data, they are used for smaller data
- * like reading	id, status etc
- */
-static uint8_t qcom_nandc_read_byte(struct nand_chip *chip)
-{
-	struct qcom_nand_host *host = to_qcom_nand_host(chip);
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	u8 *buf = nandc->data_buffer;
-	u8 ret = 0x0;
-
-	if (host->last_command == NAND_CMD_STATUS) {
-		ret = host->status;
-
-		host->status = NAND_STATUS_READY | NAND_STATUS_WP;
-
-		return ret;
-	}
-
-	if (nandc->buf_start < nandc->buf_count)
-		ret = buf[nandc->buf_start++];
-
-	return ret;
-}
-
-static void qcom_nandc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
-{
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
-
-	memcpy(buf, nandc->data_buffer + nandc->buf_start, real_len);
-	nandc->buf_start += real_len;
-}
-
-static void qcom_nandc_write_buf(struct nand_chip *chip, const uint8_t *buf,
-				 int len)
-{
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
-
-	memcpy(nandc->data_buffer + nandc->buf_start, buf, real_len);
-
-	nandc->buf_start += real_len;
-}
-
-/* we support only one external chip for now */
-static void qcom_nandc_select_chip(struct nand_chip *chip, int chipnr)
-{
-	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
-
-	if (chipnr <= 0)
-		return;
-
-	dev_warn(nandc->dev, "invalid chip select\n");
-}
-
-/*
  * NAND controller page layout info
  *
  * Layout with ECC enabled:
@@ -2738,8 +2587,207 @@ static int qcom_nand_attach_chip(struct nand_chip *chip)
 	return 0;
 }
 
+static int nandc_status(struct nand_chip *chip)
+{
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+
+	memcpy(nandc->data_buffer, &host->status, 1);
+
+	return 0;
+}
+
+static int qcom_nand_send_command(struct nand_chip *chip, u8 command)
+{
+	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct nand_ecc_ctrl *ecc = &chip->ecc;
+
+	int ret = 0;
+
+	pre_command(host, command);
+
+	switch (command) {
+	case NAND_CMD_RESET:
+		ret = reset(host);
+		break;
+	case NAND_CMD_READID:
+		nandc->buf_count = 4;
+		ret = read_id(host, 0);
+		break;
+	case NAND_CMD_PARAM:
+		ret = nandc_param(host);
+		break;
+	case NAND_CMD_ERASE1:
+		ret = erase_block(host);
+		break;
+	case NAND_CMD_STATUS:
+		ret = nandc_status(chip);
+		break;
+	case NAND_CMD_READ0:
+		host->use_ecc = true;
+		update_rw_regs(host, ecc->steps, true, 0);
+		break;
+	case NAND_CMD_ERASE2:
+		break;
+	case NAND_CMD_SEQIN:
+		break;
+	case NAND_CMD_PAGEPROG:
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static int qcom_nand_send_address(struct nand_chip *chip,
+				  const struct nand_op_instr *instr, int cmd)
+{
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	u32 page_addr = 0x0, page_mask = 0x0;
+
+	page_addr = instr->ctx.addr.addrs[0];
+
+	/*
+	 *Form page address for erase, read, write to using existing api
+	 */
+
+	switch (cmd) {
+	case NAND_CMD_ERASE1:
+		page_addr = instr->ctx.addr.addrs[0];
+		page_mask = instr->ctx.addr.addrs[1];
+		page_mask <<= 8;
+		page_addr = (page_addr | page_mask);
+		page_mask = instr->ctx.addr.addrs[2];
+		page_mask <<= 16;
+		page_addr = (page_addr | page_mask);
+		page_mask = instr->ctx.addr.addrs[3];
+		page_mask <<= 24;
+		page_addr = (page_addr | page_mask);
+		break;
+	case NAND_CMD_READ0:
+	case NAND_CMD_SEQIN:
+		page_addr = instr->ctx.addr.addrs[3];
+		page_addr <<= 24;
+		page_mask = instr->ctx.addr.addrs[2];
+		page_mask <<= 16;
+		page_addr |= page_mask;
+		page_mask = instr->ctx.addr.addrs[1];
+		page_mask <<= 8;
+		page_addr |= page_mask;
+		page_mask = instr->ctx.addr.addrs[0];
+		page_addr |= page_mask;
+		break;
+	default:
+		break;
+	}
+
+	if (cmd == NAND_CMD_PARAM)
+		return 0;
+
+	nandc_set_reg(chip, NAND_ADDR0, page_addr);
+	nandc_set_reg(chip, NAND_ADDR1, 0);
+
+	if (cmd != NAND_CMD_SEQIN)
+		write_reg_dma(nandc, NAND_ADDR0, 2, 0);
+
+	return 0;
+}
+
+static void qcom_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
+{
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+
+	memcpy(buf, nandc->data_buffer, len);
+}
+
+static int qcom_nand_exec_instr(struct nand_chip *chip,
+				const struct nand_op_instr *instr)
+{
+	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
+	struct qcom_nand_host *host = to_qcom_nand_host(chip);
+	u32 status;
+	int ret = 0;
+	bool wait = false;
+	static int opcode;
+
+	switch (instr->type) {
+	case NAND_OP_CMD_INSTR:
+		ret = qcom_nand_send_command(chip, instr->ctx.cmd.opcode);
+		if (instr->ctx.cmd.opcode == NAND_CMD_RESET)
+			wait = true;
+		opcode = instr->ctx.cmd.opcode;
+		break;
+	case NAND_OP_ADDR_INSTR:
+		qcom_nand_send_address(chip, instr, opcode);
+		if (opcode != NAND_CMD_READ0 && opcode != NAND_CMD_READSTART &&
+		    opcode != NAND_CMD_PARAM && opcode != NAND_CMD_SEQIN)
+			wait = true;
+		break;
+	case NAND_OP_DATA_IN_INSTR:
+		qcom_nand_read_buf(chip, instr->ctx.data.buf.in, instr->ctx.data.len);
+		break;
+	case NAND_OP_DATA_OUT_INSTR:
+		wait = false;
+		break;
+	case NAND_OP_WAITRDY_INSTR:
+		ret = readl_poll_timeout(nandc->base + NAND_FLASH_STATUS, status,
+					 (status & FS_READY_BSY_N), 20,
+					 instr->ctx.waitrdy.timeout_ms * 1000);
+		if (opcode == NAND_CMD_PARAM)
+			wait = true;
+	default:
+		break;
+	}
+
+	if (wait) {
+		if (opcode != NAND_CMD_PARAM)
+			write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+
+		if (opcode == NAND_CMD_READID)
+			read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
+
+		if (opcode == NAND_CMD_ERASE1) {
+			read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
+			write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
+			write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
+		}
+
+		ret = submit_descs(nandc);
+		if (ret)
+			dev_err(nandc->dev, "failure submitting descs for command 0x%02x\n",
+				opcode);
+
+		free_descs(nandc);
+		post_command(host, opcode);
+	}
+
+	return ret;
+}
+
+static int qcom_nand_exec_op(struct nand_chip *chip,
+			     const struct nand_operation *op,
+				bool check_only)
+{
+	unsigned int i;
+	int ret = 0;
+
+	if (check_only)
+		return 0;
+
+	for (i = 0; i < op->ninstrs; i++) {
+		ret = qcom_nand_exec_instr(chip, &op->instrs[i]);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
 static const struct nand_controller_ops qcom_nandc_ops = {
 	.attach_chip = qcom_nand_attach_chip,
+	.exec_op = qcom_nand_exec_op,
 };
 
 static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
@@ -2938,14 +2986,6 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
 	mtd->owner = THIS_MODULE;
 	mtd->dev.parent = dev;
 
-	chip->legacy.cmdfunc	= qcom_nandc_command;
-	chip->legacy.select_chip	= qcom_nandc_select_chip;
-	chip->legacy.read_byte	= qcom_nandc_read_byte;
-	chip->legacy.read_buf	= qcom_nandc_read_buf;
-	chip->legacy.write_buf	= qcom_nandc_write_buf;
-	chip->legacy.set_features	= nand_get_set_features_notsupp;
-	chip->legacy.get_features	= nand_get_set_features_notsupp;
-
 	/*
 	 * the bad block marker is readable only when we read the last codeword
 	 * of a page with ECC disabled. currently, the nand_base and nand_bbt
-- 
2.7.4


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

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH] mtd: rawnand: qcom: Implement exec_op()
  2022-06-03 16:24 ` Md Sadre Alam
@ 2022-06-03 16:57   ` Miquel Raynal
  -1 siblings, 0 replies; 14+ messages in thread
From: Miquel Raynal @ 2022-06-03 16:57 UTC (permalink / raw)
  To: Md Sadre Alam
  Cc: mani, richard, vigneshr, linux-mtd, linux-arm-msm, linux-kernel,
	quic_srichara

Hello,

quic_mdalam@quicinc.com wrote on Fri,  3 Jun 2022 21:54:58 +0530:

> Implement exec_op() so we can later get rid of the legacy interface
> implementation.

Thanks for doing this conversion!

> 
> Co-developed-by: Sricharan R <quic_srichara@quicinc.com>
> Signed-off-by: Sricharan R <quic_srichara@quicinc.com>
> Signed-off-by: Md Sadre Alam <quic_mdalam@quicinc.com>
> ---
>  drivers/mtd/nand/raw/qcom_nandc.c | 368 +++++++++++++++++++++-----------------
>  1 file changed, 204 insertions(+), 164 deletions(-)
> 
> diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
> index 048b255..507921b 100644
> --- a/drivers/mtd/nand/raw/qcom_nandc.c
> +++ b/drivers/mtd/nand/raw/qcom_nandc.c
> @@ -14,6 +14,7 @@
>  #include <linux/of.h>
>  #include <linux/of_device.h>
>  #include <linux/delay.h>
> +#include <linux/iopoll.h>
>  #include <linux/dma/qcom_bam_dma.h>
>  
>  /* NANDc reg offsets */
> @@ -1305,15 +1306,13 @@ static int nandc_param(struct qcom_nand_host *host)
>  }
>  
>  /* sets up descriptors for NAND_CMD_ERASE1 */
> -static int erase_block(struct qcom_nand_host *host, int page_addr)
> +static int erase_block(struct qcom_nand_host *host)
>  {
>  	struct nand_chip *chip = &host->chip;
>  	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>  
>  	nandc_set_reg(chip, NAND_FLASH_CMD,
>  		      OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE);
> -	nandc_set_reg(chip, NAND_ADDR0, page_addr);
> -	nandc_set_reg(chip, NAND_ADDR1, 0);
>  	nandc_set_reg(chip, NAND_DEV0_CFG0,
>  		      host->cfg0_raw & ~(7 << CW_PER_PAGE));
>  	nandc_set_reg(chip, NAND_DEV0_CFG1, host->cfg1_raw);
> @@ -1321,14 +1320,8 @@ static int erase_block(struct qcom_nand_host *host, int page_addr)
>  	nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus);
>  	nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus);
>  
> -	write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
> +	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
>  	write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
> -	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
> -
> -	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
> -
> -	write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
> -	write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
>  
>  	return 0;
>  }
> @@ -1343,16 +1336,12 @@ static int read_id(struct qcom_nand_host *host, int column)
>  		return 0;
>  
>  	nandc_set_reg(chip, NAND_FLASH_CMD, OP_FETCH_ID);
> -	nandc_set_reg(chip, NAND_ADDR0, column);
> -	nandc_set_reg(chip, NAND_ADDR1, 0);
>  	nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT,
>  		      nandc->props->is_bam ? 0 : DM_EN);
>  	nandc_set_reg(chip, NAND_EXEC_CMD, 1);
>  
> -	write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
> -	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
> -
> -	read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
> +	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
> +	write_reg_dma(nandc, NAND_FLASH_CHIP_SELECT, 1, NAND_BAM_NEXT_SGL);
>  
>  	return 0;
>  }
> @@ -1491,7 +1480,6 @@ static void parse_erase_write_errors(struct qcom_nand_host *host, int command)
>  
>  	for (i = 0; i < num_cw; i++) {
>  		u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
> -
>  		if (flash_status & FS_MPU_ERR)
>  			host->status &= ~NAND_STATUS_WP;
>  
> @@ -1523,86 +1511,6 @@ static void post_command(struct qcom_nand_host *host, int command)
>  }
>  
>  /*
> - * Implements chip->legacy.cmdfunc. It's  only used for a limited set of
> - * commands. The rest of the commands wouldn't be called by upper layers.
> - * For example, NAND_CMD_READOOB would never be called because we have our own
> - * versions of read_oob ops for nand_ecc_ctrl.
> - */
> -static void qcom_nandc_command(struct nand_chip *chip, unsigned int command,
> -			       int column, int page_addr)
> -{
> -	struct qcom_nand_host *host = to_qcom_nand_host(chip);
> -	struct nand_ecc_ctrl *ecc = &chip->ecc;
> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> -	bool wait = false;
> -	int ret = 0;
> -
> -	pre_command(host, command);
> -
> -	switch (command) {
> -	case NAND_CMD_RESET:
> -		ret = reset(host);
> -		wait = true;
> -		break;
> -
> -	case NAND_CMD_READID:
> -		nandc->buf_count = 4;
> -		ret = read_id(host, column);
> -		wait = true;
> -		break;
> -
> -	case NAND_CMD_PARAM:
> -		ret = nandc_param(host);
> -		wait = true;
> -		break;
> -
> -	case NAND_CMD_ERASE1:
> -		ret = erase_block(host, page_addr);
> -		wait = true;
> -		break;
> -
> -	case NAND_CMD_READ0:
> -		/* we read the entire page for now */
> -		WARN_ON(column != 0);
> -
> -		host->use_ecc = true;
> -		set_address(host, 0, page_addr);
> -		update_rw_regs(host, ecc->steps, true, 0);
> -		break;
> -
> -	case NAND_CMD_SEQIN:
> -		WARN_ON(column != 0);
> -		set_address(host, 0, page_addr);
> -		break;
> -
> -	case NAND_CMD_PAGEPROG:
> -	case NAND_CMD_STATUS:
> -	case NAND_CMD_NONE:
> -	default:
> -		break;
> -	}
> -
> -	if (ret) {
> -		dev_err(nandc->dev, "failure executing command %d\n",
> -			command);
> -		free_descs(nandc);
> -		return;
> -	}
> -
> -	if (wait) {
> -		ret = submit_descs(nandc);
> -		if (ret)
> -			dev_err(nandc->dev,
> -				"failure submitting descs for command %d\n",
> -				command);
> -	}
> -
> -	free_descs(nandc);
> -
> -	post_command(host, command);
> -}
> -
> -/*
>   * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
>   * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
>   *
> @@ -2044,7 +1952,6 @@ static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf,
>  	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>  	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>  	u8 *data_buf, *oob_buf = NULL;
> -
>  	nand_read_page_op(chip, page, 0, NULL, 0);
>  	data_buf = buf;
>  	oob_buf = oob_required ? chip->oob_poi : NULL;
> @@ -2366,64 +2273,6 @@ static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs)
>  }
>  
>  /*
> - * the three functions below implement chip->legacy.read_byte(),
> - * chip->legacy.read_buf() and chip->legacy.write_buf() respectively. these
> - * aren't used for reading/writing page data, they are used for smaller data
> - * like reading	id, status etc
> - */
> -static uint8_t qcom_nandc_read_byte(struct nand_chip *chip)
> -{
> -	struct qcom_nand_host *host = to_qcom_nand_host(chip);
> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> -	u8 *buf = nandc->data_buffer;
> -	u8 ret = 0x0;
> -
> -	if (host->last_command == NAND_CMD_STATUS) {
> -		ret = host->status;
> -
> -		host->status = NAND_STATUS_READY | NAND_STATUS_WP;
> -
> -		return ret;
> -	}
> -
> -	if (nandc->buf_start < nandc->buf_count)
> -		ret = buf[nandc->buf_start++];
> -
> -	return ret;
> -}
> -
> -static void qcom_nandc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
> -{
> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> -	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
> -
> -	memcpy(buf, nandc->data_buffer + nandc->buf_start, real_len);
> -	nandc->buf_start += real_len;
> -}
> -
> -static void qcom_nandc_write_buf(struct nand_chip *chip, const uint8_t *buf,
> -				 int len)
> -{
> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> -	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
> -
> -	memcpy(nandc->data_buffer + nandc->buf_start, buf, real_len);
> -
> -	nandc->buf_start += real_len;
> -}
> -
> -/* we support only one external chip for now */
> -static void qcom_nandc_select_chip(struct nand_chip *chip, int chipnr)
> -{
> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> -
> -	if (chipnr <= 0)
> -		return;
> -
> -	dev_warn(nandc->dev, "invalid chip select\n");
> -}
> -
> -/*
>   * NAND controller page layout info
>   *
>   * Layout with ECC enabled:
> @@ -2738,8 +2587,207 @@ static int qcom_nand_attach_chip(struct nand_chip *chip)
>  	return 0;
>  }
>  
> +static int nandc_status(struct nand_chip *chip)
> +{
> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
> +
> +	memcpy(nandc->data_buffer, &host->status, 1);
> +
> +	return 0;
> +}
> +
> +static int qcom_nand_send_command(struct nand_chip *chip, u8 command)
> +{
> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> +	struct nand_ecc_ctrl *ecc = &chip->ecc;
> +
> +	int ret = 0;
> +
> +	pre_command(host, command);
> +
> +	switch (command) {
> +	case NAND_CMD_RESET:
> +		ret = reset(host);
> +		break;
> +	case NAND_CMD_READID:
> +		nandc->buf_count = 4;
> +		ret = read_id(host, 0);
> +		break;
> +	case NAND_CMD_PARAM:
> +		ret = nandc_param(host);
> +		break;
> +	case NAND_CMD_ERASE1:
> +		ret = erase_block(host);
> +		break;
> +	case NAND_CMD_STATUS:
> +		ret = nandc_status(chip);
> +		break;
> +	case NAND_CMD_READ0:
> +		host->use_ecc = true;

->exec_op() and ECC are orthogonal

> +		update_rw_regs(host, ecc->steps, true, 0);
> +		break;
> +	case NAND_CMD_ERASE2:
> +		break;
> +	case NAND_CMD_SEQIN:
> +		break;
> +	case NAND_CMD_PAGEPROG:
> +		break;

I am sorry but this is not following ->exec_op() main idea. The
controller is just here to forward requests to the device it must
respect a number of cycles but that's pretty much all. Here you are
actually re-writing ->cmdfunc() which is not what we expect.


> +	default:
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static int qcom_nand_send_address(struct nand_chip *chip,
> +				  const struct nand_op_instr *instr, int cmd)
> +{
> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> +	u32 page_addr = 0x0, page_mask = 0x0;
> +
> +	page_addr = instr->ctx.addr.addrs[0];
> +
> +	/*
> +	 *Form page address for erase, read, write to using existing api
> +	 */
> +
> +	switch (cmd) {
> +	case NAND_CMD_ERASE1:
> +		page_addr = instr->ctx.addr.addrs[0];
> +		page_mask = instr->ctx.addr.addrs[1];
> +		page_mask <<= 8;
> +		page_addr = (page_addr | page_mask);
> +		page_mask = instr->ctx.addr.addrs[2];
> +		page_mask <<= 16;
> +		page_addr = (page_addr | page_mask);
> +		page_mask = instr->ctx.addr.addrs[3];
> +		page_mask <<= 24;
> +		page_addr = (page_addr | page_mask);
> +		break;
> +	case NAND_CMD_READ0:
> +	case NAND_CMD_SEQIN:
> +		page_addr = instr->ctx.addr.addrs[3];
> +		page_addr <<= 24;
> +		page_mask = instr->ctx.addr.addrs[2];
> +		page_mask <<= 16;
> +		page_addr |= page_mask;
> +		page_mask = instr->ctx.addr.addrs[1];
> +		page_mask <<= 8;
> +		page_addr |= page_mask;
> +		page_mask = instr->ctx.addr.addrs[0];
> +		page_addr |= page_mask;

Same here, just write the number of address cycles that were requested
by the core.

> +		break;
> +	default:
> +		break;
> +	}
> +
> +	if (cmd == NAND_CMD_PARAM)
> +		return 0;
> +
> +	nandc_set_reg(chip, NAND_ADDR0, page_addr);
> +	nandc_set_reg(chip, NAND_ADDR1, 0);
> +
> +	if (cmd != NAND_CMD_SEQIN)
> +		write_reg_dma(nandc, NAND_ADDR0, 2, 0);
> +
> +	return 0;
> +}
> +
> +static void qcom_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
> +{
> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> +
> +	memcpy(buf, nandc->data_buffer, len);

Is this bounce buffer needed?

> +}
> +
> +static int qcom_nand_exec_instr(struct nand_chip *chip,
> +				const struct nand_op_instr *instr)
> +{
> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
> +	u32 status;
> +	int ret = 0;
> +	bool wait = false;
> +	static int opcode;
> +
> +	switch (instr->type) {
> +	case NAND_OP_CMD_INSTR:
> +		ret = qcom_nand_send_command(chip, instr->ctx.cmd.opcode);
> +		if (instr->ctx.cmd.opcode == NAND_CMD_RESET)
> +			wait = true;
> +		opcode = instr->ctx.cmd.opcode;
> +		break;
> +	case NAND_OP_ADDR_INSTR:
> +		qcom_nand_send_address(chip, instr, opcode);
> +		if (opcode != NAND_CMD_READ0 && opcode != NAND_CMD_READSTART &&
> +		    opcode != NAND_CMD_PARAM && opcode != NAND_CMD_SEQIN)
> +			wait = true;
> +		break;
> +	case NAND_OP_DATA_IN_INSTR:
> +		qcom_nand_read_buf(chip, instr->ctx.data.buf.in, instr->ctx.data.len);
> +		break;
> +	case NAND_OP_DATA_OUT_INSTR:
> +		wait = false;
> +		break;
> +	case NAND_OP_WAITRDY_INSTR:
> +		ret = readl_poll_timeout(nandc->base + NAND_FLASH_STATUS, status,
> +					 (status & FS_READY_BSY_N), 20,
> +					 instr->ctx.waitrdy.timeout_ms * 1000);
> +		if (opcode == NAND_CMD_PARAM)
> +			wait = true;
> +	default:
> +		break;
> +	}
> +
> +	if (wait) {
> +		if (opcode != NAND_CMD_PARAM)
> +			write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
> +
> +		if (opcode == NAND_CMD_READID)
> +			read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
> +
> +		if (opcode == NAND_CMD_ERASE1) {
> +			read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
> +			write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
> +			write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
> +		}
> +
> +		ret = submit_descs(nandc);
> +		if (ret)
> +			dev_err(nandc->dev, "failure submitting descs for command 0x%02x\n",
> +				opcode);
> +
> +		free_descs(nandc);
> +		post_command(host, opcode);
> +	}
> +
> +	return ret;
> +}
> +
> +static int qcom_nand_exec_op(struct nand_chip *chip,
> +			     const struct nand_operation *op,
> +				bool check_only)
> +{
> +	unsigned int i;
> +	int ret = 0;
> +
> +	if (check_only)
> +		return 0;
> +
> +	for (i = 0; i < op->ninstrs; i++) {
> +		ret = qcom_nand_exec_instr(chip, &op->instrs[i]);
> +		if (ret)
> +			break;
> +	}
> +
> +	return ret;
> +}
> +
>  static const struct nand_controller_ops qcom_nandc_ops = {
>  	.attach_chip = qcom_nand_attach_chip,
> +	.exec_op = qcom_nand_exec_op,
>  };
>  
>  static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
> @@ -2938,14 +2986,6 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
>  	mtd->owner = THIS_MODULE;
>  	mtd->dev.parent = dev;
>  
> -	chip->legacy.cmdfunc	= qcom_nandc_command;
> -	chip->legacy.select_chip	= qcom_nandc_select_chip;
> -	chip->legacy.read_byte	= qcom_nandc_read_byte;
> -	chip->legacy.read_buf	= qcom_nandc_read_buf;
> -	chip->legacy.write_buf	= qcom_nandc_write_buf;
> -	chip->legacy.set_features	= nand_get_set_features_notsupp;
> -	chip->legacy.get_features	= nand_get_set_features_notsupp;
> -
>  	/*
>  	 * the bad block marker is readable only when we read the last codeword
>  	 * of a page with ECC disabled. currently, the nand_base and nand_bbt


Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] mtd: rawnand: qcom: Implement exec_op()
@ 2022-06-03 16:57   ` Miquel Raynal
  0 siblings, 0 replies; 14+ messages in thread
From: Miquel Raynal @ 2022-06-03 16:57 UTC (permalink / raw)
  To: Md Sadre Alam
  Cc: mani, richard, vigneshr, linux-mtd, linux-arm-msm, linux-kernel,
	quic_srichara

Hello,

quic_mdalam@quicinc.com wrote on Fri,  3 Jun 2022 21:54:58 +0530:

> Implement exec_op() so we can later get rid of the legacy interface
> implementation.

Thanks for doing this conversion!

> 
> Co-developed-by: Sricharan R <quic_srichara@quicinc.com>
> Signed-off-by: Sricharan R <quic_srichara@quicinc.com>
> Signed-off-by: Md Sadre Alam <quic_mdalam@quicinc.com>
> ---
>  drivers/mtd/nand/raw/qcom_nandc.c | 368 +++++++++++++++++++++-----------------
>  1 file changed, 204 insertions(+), 164 deletions(-)
> 
> diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
> index 048b255..507921b 100644
> --- a/drivers/mtd/nand/raw/qcom_nandc.c
> +++ b/drivers/mtd/nand/raw/qcom_nandc.c
> @@ -14,6 +14,7 @@
>  #include <linux/of.h>
>  #include <linux/of_device.h>
>  #include <linux/delay.h>
> +#include <linux/iopoll.h>
>  #include <linux/dma/qcom_bam_dma.h>
>  
>  /* NANDc reg offsets */
> @@ -1305,15 +1306,13 @@ static int nandc_param(struct qcom_nand_host *host)
>  }
>  
>  /* sets up descriptors for NAND_CMD_ERASE1 */
> -static int erase_block(struct qcom_nand_host *host, int page_addr)
> +static int erase_block(struct qcom_nand_host *host)
>  {
>  	struct nand_chip *chip = &host->chip;
>  	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>  
>  	nandc_set_reg(chip, NAND_FLASH_CMD,
>  		      OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE);
> -	nandc_set_reg(chip, NAND_ADDR0, page_addr);
> -	nandc_set_reg(chip, NAND_ADDR1, 0);
>  	nandc_set_reg(chip, NAND_DEV0_CFG0,
>  		      host->cfg0_raw & ~(7 << CW_PER_PAGE));
>  	nandc_set_reg(chip, NAND_DEV0_CFG1, host->cfg1_raw);
> @@ -1321,14 +1320,8 @@ static int erase_block(struct qcom_nand_host *host, int page_addr)
>  	nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus);
>  	nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus);
>  
> -	write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
> +	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
>  	write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
> -	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
> -
> -	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
> -
> -	write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
> -	write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
>  
>  	return 0;
>  }
> @@ -1343,16 +1336,12 @@ static int read_id(struct qcom_nand_host *host, int column)
>  		return 0;
>  
>  	nandc_set_reg(chip, NAND_FLASH_CMD, OP_FETCH_ID);
> -	nandc_set_reg(chip, NAND_ADDR0, column);
> -	nandc_set_reg(chip, NAND_ADDR1, 0);
>  	nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT,
>  		      nandc->props->is_bam ? 0 : DM_EN);
>  	nandc_set_reg(chip, NAND_EXEC_CMD, 1);
>  
> -	write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
> -	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
> -
> -	read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
> +	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
> +	write_reg_dma(nandc, NAND_FLASH_CHIP_SELECT, 1, NAND_BAM_NEXT_SGL);
>  
>  	return 0;
>  }
> @@ -1491,7 +1480,6 @@ static void parse_erase_write_errors(struct qcom_nand_host *host, int command)
>  
>  	for (i = 0; i < num_cw; i++) {
>  		u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
> -
>  		if (flash_status & FS_MPU_ERR)
>  			host->status &= ~NAND_STATUS_WP;
>  
> @@ -1523,86 +1511,6 @@ static void post_command(struct qcom_nand_host *host, int command)
>  }
>  
>  /*
> - * Implements chip->legacy.cmdfunc. It's  only used for a limited set of
> - * commands. The rest of the commands wouldn't be called by upper layers.
> - * For example, NAND_CMD_READOOB would never be called because we have our own
> - * versions of read_oob ops for nand_ecc_ctrl.
> - */
> -static void qcom_nandc_command(struct nand_chip *chip, unsigned int command,
> -			       int column, int page_addr)
> -{
> -	struct qcom_nand_host *host = to_qcom_nand_host(chip);
> -	struct nand_ecc_ctrl *ecc = &chip->ecc;
> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> -	bool wait = false;
> -	int ret = 0;
> -
> -	pre_command(host, command);
> -
> -	switch (command) {
> -	case NAND_CMD_RESET:
> -		ret = reset(host);
> -		wait = true;
> -		break;
> -
> -	case NAND_CMD_READID:
> -		nandc->buf_count = 4;
> -		ret = read_id(host, column);
> -		wait = true;
> -		break;
> -
> -	case NAND_CMD_PARAM:
> -		ret = nandc_param(host);
> -		wait = true;
> -		break;
> -
> -	case NAND_CMD_ERASE1:
> -		ret = erase_block(host, page_addr);
> -		wait = true;
> -		break;
> -
> -	case NAND_CMD_READ0:
> -		/* we read the entire page for now */
> -		WARN_ON(column != 0);
> -
> -		host->use_ecc = true;
> -		set_address(host, 0, page_addr);
> -		update_rw_regs(host, ecc->steps, true, 0);
> -		break;
> -
> -	case NAND_CMD_SEQIN:
> -		WARN_ON(column != 0);
> -		set_address(host, 0, page_addr);
> -		break;
> -
> -	case NAND_CMD_PAGEPROG:
> -	case NAND_CMD_STATUS:
> -	case NAND_CMD_NONE:
> -	default:
> -		break;
> -	}
> -
> -	if (ret) {
> -		dev_err(nandc->dev, "failure executing command %d\n",
> -			command);
> -		free_descs(nandc);
> -		return;
> -	}
> -
> -	if (wait) {
> -		ret = submit_descs(nandc);
> -		if (ret)
> -			dev_err(nandc->dev,
> -				"failure submitting descs for command %d\n",
> -				command);
> -	}
> -
> -	free_descs(nandc);
> -
> -	post_command(host, command);
> -}
> -
> -/*
>   * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
>   * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
>   *
> @@ -2044,7 +1952,6 @@ static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf,
>  	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>  	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>  	u8 *data_buf, *oob_buf = NULL;
> -
>  	nand_read_page_op(chip, page, 0, NULL, 0);
>  	data_buf = buf;
>  	oob_buf = oob_required ? chip->oob_poi : NULL;
> @@ -2366,64 +2273,6 @@ static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs)
>  }
>  
>  /*
> - * the three functions below implement chip->legacy.read_byte(),
> - * chip->legacy.read_buf() and chip->legacy.write_buf() respectively. these
> - * aren't used for reading/writing page data, they are used for smaller data
> - * like reading	id, status etc
> - */
> -static uint8_t qcom_nandc_read_byte(struct nand_chip *chip)
> -{
> -	struct qcom_nand_host *host = to_qcom_nand_host(chip);
> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> -	u8 *buf = nandc->data_buffer;
> -	u8 ret = 0x0;
> -
> -	if (host->last_command == NAND_CMD_STATUS) {
> -		ret = host->status;
> -
> -		host->status = NAND_STATUS_READY | NAND_STATUS_WP;
> -
> -		return ret;
> -	}
> -
> -	if (nandc->buf_start < nandc->buf_count)
> -		ret = buf[nandc->buf_start++];
> -
> -	return ret;
> -}
> -
> -static void qcom_nandc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
> -{
> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> -	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
> -
> -	memcpy(buf, nandc->data_buffer + nandc->buf_start, real_len);
> -	nandc->buf_start += real_len;
> -}
> -
> -static void qcom_nandc_write_buf(struct nand_chip *chip, const uint8_t *buf,
> -				 int len)
> -{
> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> -	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
> -
> -	memcpy(nandc->data_buffer + nandc->buf_start, buf, real_len);
> -
> -	nandc->buf_start += real_len;
> -}
> -
> -/* we support only one external chip for now */
> -static void qcom_nandc_select_chip(struct nand_chip *chip, int chipnr)
> -{
> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> -
> -	if (chipnr <= 0)
> -		return;
> -
> -	dev_warn(nandc->dev, "invalid chip select\n");
> -}
> -
> -/*
>   * NAND controller page layout info
>   *
>   * Layout with ECC enabled:
> @@ -2738,8 +2587,207 @@ static int qcom_nand_attach_chip(struct nand_chip *chip)
>  	return 0;
>  }
>  
> +static int nandc_status(struct nand_chip *chip)
> +{
> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
> +
> +	memcpy(nandc->data_buffer, &host->status, 1);
> +
> +	return 0;
> +}
> +
> +static int qcom_nand_send_command(struct nand_chip *chip, u8 command)
> +{
> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> +	struct nand_ecc_ctrl *ecc = &chip->ecc;
> +
> +	int ret = 0;
> +
> +	pre_command(host, command);
> +
> +	switch (command) {
> +	case NAND_CMD_RESET:
> +		ret = reset(host);
> +		break;
> +	case NAND_CMD_READID:
> +		nandc->buf_count = 4;
> +		ret = read_id(host, 0);
> +		break;
> +	case NAND_CMD_PARAM:
> +		ret = nandc_param(host);
> +		break;
> +	case NAND_CMD_ERASE1:
> +		ret = erase_block(host);
> +		break;
> +	case NAND_CMD_STATUS:
> +		ret = nandc_status(chip);
> +		break;
> +	case NAND_CMD_READ0:
> +		host->use_ecc = true;

->exec_op() and ECC are orthogonal

> +		update_rw_regs(host, ecc->steps, true, 0);
> +		break;
> +	case NAND_CMD_ERASE2:
> +		break;
> +	case NAND_CMD_SEQIN:
> +		break;
> +	case NAND_CMD_PAGEPROG:
> +		break;

I am sorry but this is not following ->exec_op() main idea. The
controller is just here to forward requests to the device it must
respect a number of cycles but that's pretty much all. Here you are
actually re-writing ->cmdfunc() which is not what we expect.


> +	default:
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static int qcom_nand_send_address(struct nand_chip *chip,
> +				  const struct nand_op_instr *instr, int cmd)
> +{
> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> +	u32 page_addr = 0x0, page_mask = 0x0;
> +
> +	page_addr = instr->ctx.addr.addrs[0];
> +
> +	/*
> +	 *Form page address for erase, read, write to using existing api
> +	 */
> +
> +	switch (cmd) {
> +	case NAND_CMD_ERASE1:
> +		page_addr = instr->ctx.addr.addrs[0];
> +		page_mask = instr->ctx.addr.addrs[1];
> +		page_mask <<= 8;
> +		page_addr = (page_addr | page_mask);
> +		page_mask = instr->ctx.addr.addrs[2];
> +		page_mask <<= 16;
> +		page_addr = (page_addr | page_mask);
> +		page_mask = instr->ctx.addr.addrs[3];
> +		page_mask <<= 24;
> +		page_addr = (page_addr | page_mask);
> +		break;
> +	case NAND_CMD_READ0:
> +	case NAND_CMD_SEQIN:
> +		page_addr = instr->ctx.addr.addrs[3];
> +		page_addr <<= 24;
> +		page_mask = instr->ctx.addr.addrs[2];
> +		page_mask <<= 16;
> +		page_addr |= page_mask;
> +		page_mask = instr->ctx.addr.addrs[1];
> +		page_mask <<= 8;
> +		page_addr |= page_mask;
> +		page_mask = instr->ctx.addr.addrs[0];
> +		page_addr |= page_mask;

Same here, just write the number of address cycles that were requested
by the core.

> +		break;
> +	default:
> +		break;
> +	}
> +
> +	if (cmd == NAND_CMD_PARAM)
> +		return 0;
> +
> +	nandc_set_reg(chip, NAND_ADDR0, page_addr);
> +	nandc_set_reg(chip, NAND_ADDR1, 0);
> +
> +	if (cmd != NAND_CMD_SEQIN)
> +		write_reg_dma(nandc, NAND_ADDR0, 2, 0);
> +
> +	return 0;
> +}
> +
> +static void qcom_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
> +{
> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> +
> +	memcpy(buf, nandc->data_buffer, len);

Is this bounce buffer needed?

> +}
> +
> +static int qcom_nand_exec_instr(struct nand_chip *chip,
> +				const struct nand_op_instr *instr)
> +{
> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
> +	u32 status;
> +	int ret = 0;
> +	bool wait = false;
> +	static int opcode;
> +
> +	switch (instr->type) {
> +	case NAND_OP_CMD_INSTR:
> +		ret = qcom_nand_send_command(chip, instr->ctx.cmd.opcode);
> +		if (instr->ctx.cmd.opcode == NAND_CMD_RESET)
> +			wait = true;
> +		opcode = instr->ctx.cmd.opcode;
> +		break;
> +	case NAND_OP_ADDR_INSTR:
> +		qcom_nand_send_address(chip, instr, opcode);
> +		if (opcode != NAND_CMD_READ0 && opcode != NAND_CMD_READSTART &&
> +		    opcode != NAND_CMD_PARAM && opcode != NAND_CMD_SEQIN)
> +			wait = true;
> +		break;
> +	case NAND_OP_DATA_IN_INSTR:
> +		qcom_nand_read_buf(chip, instr->ctx.data.buf.in, instr->ctx.data.len);
> +		break;
> +	case NAND_OP_DATA_OUT_INSTR:
> +		wait = false;
> +		break;
> +	case NAND_OP_WAITRDY_INSTR:
> +		ret = readl_poll_timeout(nandc->base + NAND_FLASH_STATUS, status,
> +					 (status & FS_READY_BSY_N), 20,
> +					 instr->ctx.waitrdy.timeout_ms * 1000);
> +		if (opcode == NAND_CMD_PARAM)
> +			wait = true;
> +	default:
> +		break;
> +	}
> +
> +	if (wait) {
> +		if (opcode != NAND_CMD_PARAM)
> +			write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
> +
> +		if (opcode == NAND_CMD_READID)
> +			read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
> +
> +		if (opcode == NAND_CMD_ERASE1) {
> +			read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
> +			write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
> +			write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
> +		}
> +
> +		ret = submit_descs(nandc);
> +		if (ret)
> +			dev_err(nandc->dev, "failure submitting descs for command 0x%02x\n",
> +				opcode);
> +
> +		free_descs(nandc);
> +		post_command(host, opcode);
> +	}
> +
> +	return ret;
> +}
> +
> +static int qcom_nand_exec_op(struct nand_chip *chip,
> +			     const struct nand_operation *op,
> +				bool check_only)
> +{
> +	unsigned int i;
> +	int ret = 0;
> +
> +	if (check_only)
> +		return 0;
> +
> +	for (i = 0; i < op->ninstrs; i++) {
> +		ret = qcom_nand_exec_instr(chip, &op->instrs[i]);
> +		if (ret)
> +			break;
> +	}
> +
> +	return ret;
> +}
> +
>  static const struct nand_controller_ops qcom_nandc_ops = {
>  	.attach_chip = qcom_nand_attach_chip,
> +	.exec_op = qcom_nand_exec_op,
>  };
>  
>  static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
> @@ -2938,14 +2986,6 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
>  	mtd->owner = THIS_MODULE;
>  	mtd->dev.parent = dev;
>  
> -	chip->legacy.cmdfunc	= qcom_nandc_command;
> -	chip->legacy.select_chip	= qcom_nandc_select_chip;
> -	chip->legacy.read_byte	= qcom_nandc_read_byte;
> -	chip->legacy.read_buf	= qcom_nandc_read_buf;
> -	chip->legacy.write_buf	= qcom_nandc_write_buf;
> -	chip->legacy.set_features	= nand_get_set_features_notsupp;
> -	chip->legacy.get_features	= nand_get_set_features_notsupp;
> -
>  	/*
>  	 * the bad block marker is readable only when we read the last codeword
>  	 * of a page with ECC disabled. currently, the nand_base and nand_bbt


Thanks,
Miquèl

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

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] mtd: rawnand: qcom: Implement exec_op()
  2022-06-03 16:24 ` Md Sadre Alam
@ 2022-06-05 23:45   ` kernel test robot
  -1 siblings, 0 replies; 14+ messages in thread
From: kernel test robot @ 2022-06-05 23:45 UTC (permalink / raw)
  To: Md Sadre Alam, mani, miquel.raynal, richard, vigneshr, linux-mtd,
	linux-arm-msm, linux-kernel
  Cc: llvm, kbuild-all, quic_srichara, quic_mdalam

Hi Md,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on mtd/nand/next]
[also build test WARNING on v5.18 next-20220603]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/intel-lab-lkp/linux/commits/Md-Sadre-Alam/mtd-rawnand-qcom-Implement-exec_op/20220605-235824
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git nand/next
config: arm64-randconfig-r021-20220605 (https://download.01.org/0day-ci/archive/20220606/202206060716.xdJ89V2D-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 416a5080d89066029f9889dc23f94de47c2fa895)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install arm64 cross compiling tool for clang build
        # apt-get install binutils-aarch64-linux-gnu
        # https://github.com/intel-lab-lkp/linux/commit/5ab4409034966f5503f62ef2df59408762a9e872
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Md-Sadre-Alam/mtd-rawnand-qcom-Implement-exec_op/20220605-235824
        git checkout 5ab4409034966f5503f62ef2df59408762a9e872
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm64 SHELL=/bin/bash drivers/mtd/nand/raw/ drivers/nfc/nfcmrvl/

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/mtd/nand/raw/qcom_nandc.c:2727:2: warning: unannotated fall-through between switch labels [-Wimplicit-fallthrough]
           default:
           ^
   drivers/mtd/nand/raw/qcom_nandc.c:2727:2: note: insert 'break;' to avoid fall-through
           default:
           ^
           break; 
   1 warning generated.


vim +2727 drivers/mtd/nand/raw/qcom_nandc.c

  2691	
  2692	static int qcom_nand_exec_instr(struct nand_chip *chip,
  2693					const struct nand_op_instr *instr)
  2694	{
  2695		struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
  2696		struct qcom_nand_host *host = to_qcom_nand_host(chip);
  2697		u32 status;
  2698		int ret = 0;
  2699		bool wait = false;
  2700		static int opcode;
  2701	
  2702		switch (instr->type) {
  2703		case NAND_OP_CMD_INSTR:
  2704			ret = qcom_nand_send_command(chip, instr->ctx.cmd.opcode);
  2705			if (instr->ctx.cmd.opcode == NAND_CMD_RESET)
  2706				wait = true;
  2707			opcode = instr->ctx.cmd.opcode;
  2708			break;
  2709		case NAND_OP_ADDR_INSTR:
  2710			qcom_nand_send_address(chip, instr, opcode);
  2711			if (opcode != NAND_CMD_READ0 && opcode != NAND_CMD_READSTART &&
  2712			    opcode != NAND_CMD_PARAM && opcode != NAND_CMD_SEQIN)
  2713				wait = true;
  2714			break;
  2715		case NAND_OP_DATA_IN_INSTR:
  2716			qcom_nand_read_buf(chip, instr->ctx.data.buf.in, instr->ctx.data.len);
  2717			break;
  2718		case NAND_OP_DATA_OUT_INSTR:
  2719			wait = false;
  2720			break;
  2721		case NAND_OP_WAITRDY_INSTR:
  2722			ret = readl_poll_timeout(nandc->base + NAND_FLASH_STATUS, status,
  2723						 (status & FS_READY_BSY_N), 20,
  2724						 instr->ctx.waitrdy.timeout_ms * 1000);
  2725			if (opcode == NAND_CMD_PARAM)
  2726				wait = true;
> 2727		default:
  2728			break;
  2729		}
  2730	
  2731		if (wait) {
  2732			if (opcode != NAND_CMD_PARAM)
  2733				write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
  2734	
  2735			if (opcode == NAND_CMD_READID)
  2736				read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
  2737	
  2738			if (opcode == NAND_CMD_ERASE1) {
  2739				read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
  2740				write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
  2741				write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
  2742			}
  2743	
  2744			ret = submit_descs(nandc);
  2745			if (ret)
  2746				dev_err(nandc->dev, "failure submitting descs for command 0x%02x\n",
  2747					opcode);
  2748	
  2749			free_descs(nandc);
  2750			post_command(host, opcode);
  2751		}
  2752	
  2753		return ret;
  2754	}
  2755	

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] mtd: rawnand: qcom: Implement exec_op()
@ 2022-06-05 23:45   ` kernel test robot
  0 siblings, 0 replies; 14+ messages in thread
From: kernel test robot @ 2022-06-05 23:45 UTC (permalink / raw)
  To: Md Sadre Alam, mani, miquel.raynal, richard, vigneshr, linux-mtd,
	linux-arm-msm, linux-kernel
  Cc: llvm, kbuild-all, quic_srichara, quic_mdalam

Hi Md,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on mtd/nand/next]
[also build test WARNING on v5.18 next-20220603]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/intel-lab-lkp/linux/commits/Md-Sadre-Alam/mtd-rawnand-qcom-Implement-exec_op/20220605-235824
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git nand/next
config: arm64-randconfig-r021-20220605 (https://download.01.org/0day-ci/archive/20220606/202206060716.xdJ89V2D-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 416a5080d89066029f9889dc23f94de47c2fa895)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install arm64 cross compiling tool for clang build
        # apt-get install binutils-aarch64-linux-gnu
        # https://github.com/intel-lab-lkp/linux/commit/5ab4409034966f5503f62ef2df59408762a9e872
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Md-Sadre-Alam/mtd-rawnand-qcom-Implement-exec_op/20220605-235824
        git checkout 5ab4409034966f5503f62ef2df59408762a9e872
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm64 SHELL=/bin/bash drivers/mtd/nand/raw/ drivers/nfc/nfcmrvl/

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/mtd/nand/raw/qcom_nandc.c:2727:2: warning: unannotated fall-through between switch labels [-Wimplicit-fallthrough]
           default:
           ^
   drivers/mtd/nand/raw/qcom_nandc.c:2727:2: note: insert 'break;' to avoid fall-through
           default:
           ^
           break; 
   1 warning generated.


vim +2727 drivers/mtd/nand/raw/qcom_nandc.c

  2691	
  2692	static int qcom_nand_exec_instr(struct nand_chip *chip,
  2693					const struct nand_op_instr *instr)
  2694	{
  2695		struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
  2696		struct qcom_nand_host *host = to_qcom_nand_host(chip);
  2697		u32 status;
  2698		int ret = 0;
  2699		bool wait = false;
  2700		static int opcode;
  2701	
  2702		switch (instr->type) {
  2703		case NAND_OP_CMD_INSTR:
  2704			ret = qcom_nand_send_command(chip, instr->ctx.cmd.opcode);
  2705			if (instr->ctx.cmd.opcode == NAND_CMD_RESET)
  2706				wait = true;
  2707			opcode = instr->ctx.cmd.opcode;
  2708			break;
  2709		case NAND_OP_ADDR_INSTR:
  2710			qcom_nand_send_address(chip, instr, opcode);
  2711			if (opcode != NAND_CMD_READ0 && opcode != NAND_CMD_READSTART &&
  2712			    opcode != NAND_CMD_PARAM && opcode != NAND_CMD_SEQIN)
  2713				wait = true;
  2714			break;
  2715		case NAND_OP_DATA_IN_INSTR:
  2716			qcom_nand_read_buf(chip, instr->ctx.data.buf.in, instr->ctx.data.len);
  2717			break;
  2718		case NAND_OP_DATA_OUT_INSTR:
  2719			wait = false;
  2720			break;
  2721		case NAND_OP_WAITRDY_INSTR:
  2722			ret = readl_poll_timeout(nandc->base + NAND_FLASH_STATUS, status,
  2723						 (status & FS_READY_BSY_N), 20,
  2724						 instr->ctx.waitrdy.timeout_ms * 1000);
  2725			if (opcode == NAND_CMD_PARAM)
  2726				wait = true;
> 2727		default:
  2728			break;
  2729		}
  2730	
  2731		if (wait) {
  2732			if (opcode != NAND_CMD_PARAM)
  2733				write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
  2734	
  2735			if (opcode == NAND_CMD_READID)
  2736				read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
  2737	
  2738			if (opcode == NAND_CMD_ERASE1) {
  2739				read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
  2740				write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
  2741				write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
  2742			}
  2743	
  2744			ret = submit_descs(nandc);
  2745			if (ret)
  2746				dev_err(nandc->dev, "failure submitting descs for command 0x%02x\n",
  2747					opcode);
  2748	
  2749			free_descs(nandc);
  2750			post_command(host, opcode);
  2751		}
  2752	
  2753		return ret;
  2754	}
  2755	

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

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

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] mtd: rawnand: qcom: Implement exec_op()
  2022-06-03 16:57   ` Miquel Raynal
@ 2022-06-06  4:48     ` Md Sadre Alam
  -1 siblings, 0 replies; 14+ messages in thread
From: Md Sadre Alam @ 2022-06-06  4:48 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: mani, richard, vigneshr, linux-mtd, linux-arm-msm, linux-kernel,
	quic_srichara


On 6/3/2022 10:27 PM, Miquel Raynal wrote:
> Hello,
>
> quic_mdalam@quicinc.com wrote on Fri,  3 Jun 2022 21:54:58 +0530:
>
>> Implement exec_op() so we can later get rid of the legacy interface
>> implementation.
> Thanks for doing this conversion!
>
>> Co-developed-by: Sricharan R <quic_srichara@quicinc.com>
>> Signed-off-by: Sricharan R <quic_srichara@quicinc.com>
>> Signed-off-by: Md Sadre Alam <quic_mdalam@quicinc.com>
>> ---
>>   drivers/mtd/nand/raw/qcom_nandc.c | 368 +++++++++++++++++++++-----------------
>>   1 file changed, 204 insertions(+), 164 deletions(-)
>>
>> diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
>> index 048b255..507921b 100644
>> --- a/drivers/mtd/nand/raw/qcom_nandc.c
>> +++ b/drivers/mtd/nand/raw/qcom_nandc.c
>> @@ -14,6 +14,7 @@
>>   #include <linux/of.h>
>>   #include <linux/of_device.h>
>>   #include <linux/delay.h>
>> +#include <linux/iopoll.h>
>>   #include <linux/dma/qcom_bam_dma.h>
>>   
>>   /* NANDc reg offsets */
>> @@ -1305,15 +1306,13 @@ static int nandc_param(struct qcom_nand_host *host)
>>   }
>>   
>>   /* sets up descriptors for NAND_CMD_ERASE1 */
>> -static int erase_block(struct qcom_nand_host *host, int page_addr)
>> +static int erase_block(struct qcom_nand_host *host)
>>   {
>>   	struct nand_chip *chip = &host->chip;
>>   	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>>   
>>   	nandc_set_reg(chip, NAND_FLASH_CMD,
>>   		      OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE);
>> -	nandc_set_reg(chip, NAND_ADDR0, page_addr);
>> -	nandc_set_reg(chip, NAND_ADDR1, 0);
>>   	nandc_set_reg(chip, NAND_DEV0_CFG0,
>>   		      host->cfg0_raw & ~(7 << CW_PER_PAGE));
>>   	nandc_set_reg(chip, NAND_DEV0_CFG1, host->cfg1_raw);
>> @@ -1321,14 +1320,8 @@ static int erase_block(struct qcom_nand_host *host, int page_addr)
>>   	nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus);
>>   	nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus);
>>   
>> -	write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
>> +	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
>>   	write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
>> -	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>> -
>> -	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
>> -
>> -	write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
>> -	write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
>>   
>>   	return 0;
>>   }
>> @@ -1343,16 +1336,12 @@ static int read_id(struct qcom_nand_host *host, int column)
>>   		return 0;
>>   
>>   	nandc_set_reg(chip, NAND_FLASH_CMD, OP_FETCH_ID);
>> -	nandc_set_reg(chip, NAND_ADDR0, column);
>> -	nandc_set_reg(chip, NAND_ADDR1, 0);
>>   	nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT,
>>   		      nandc->props->is_bam ? 0 : DM_EN);
>>   	nandc_set_reg(chip, NAND_EXEC_CMD, 1);
>>   
>> -	write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
>> -	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>> -
>> -	read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
>> +	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
>> +	write_reg_dma(nandc, NAND_FLASH_CHIP_SELECT, 1, NAND_BAM_NEXT_SGL);
>>   
>>   	return 0;
>>   }
>> @@ -1491,7 +1480,6 @@ static void parse_erase_write_errors(struct qcom_nand_host *host, int command)
>>   
>>   	for (i = 0; i < num_cw; i++) {
>>   		u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
>> -
>>   		if (flash_status & FS_MPU_ERR)
>>   			host->status &= ~NAND_STATUS_WP;
>>   
>> @@ -1523,86 +1511,6 @@ static void post_command(struct qcom_nand_host *host, int command)
>>   }
>>   
>>   /*
>> - * Implements chip->legacy.cmdfunc. It's  only used for a limited set of
>> - * commands. The rest of the commands wouldn't be called by upper layers.
>> - * For example, NAND_CMD_READOOB would never be called because we have our own
>> - * versions of read_oob ops for nand_ecc_ctrl.
>> - */
>> -static void qcom_nandc_command(struct nand_chip *chip, unsigned int command,
>> -			       int column, int page_addr)
>> -{
>> -	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>> -	struct nand_ecc_ctrl *ecc = &chip->ecc;
>> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> -	bool wait = false;
>> -	int ret = 0;
>> -
>> -	pre_command(host, command);
>> -
>> -	switch (command) {
>> -	case NAND_CMD_RESET:
>> -		ret = reset(host);
>> -		wait = true;
>> -		break;
>> -
>> -	case NAND_CMD_READID:
>> -		nandc->buf_count = 4;
>> -		ret = read_id(host, column);
>> -		wait = true;
>> -		break;
>> -
>> -	case NAND_CMD_PARAM:
>> -		ret = nandc_param(host);
>> -		wait = true;
>> -		break;
>> -
>> -	case NAND_CMD_ERASE1:
>> -		ret = erase_block(host, page_addr);
>> -		wait = true;
>> -		break;
>> -
>> -	case NAND_CMD_READ0:
>> -		/* we read the entire page for now */
>> -		WARN_ON(column != 0);
>> -
>> -		host->use_ecc = true;
>> -		set_address(host, 0, page_addr);
>> -		update_rw_regs(host, ecc->steps, true, 0);
>> -		break;
>> -
>> -	case NAND_CMD_SEQIN:
>> -		WARN_ON(column != 0);
>> -		set_address(host, 0, page_addr);
>> -		break;
>> -
>> -	case NAND_CMD_PAGEPROG:
>> -	case NAND_CMD_STATUS:
>> -	case NAND_CMD_NONE:
>> -	default:
>> -		break;
>> -	}
>> -
>> -	if (ret) {
>> -		dev_err(nandc->dev, "failure executing command %d\n",
>> -			command);
>> -		free_descs(nandc);
>> -		return;
>> -	}
>> -
>> -	if (wait) {
>> -		ret = submit_descs(nandc);
>> -		if (ret)
>> -			dev_err(nandc->dev,
>> -				"failure submitting descs for command %d\n",
>> -				command);
>> -	}
>> -
>> -	free_descs(nandc);
>> -
>> -	post_command(host, command);
>> -}
>> -
>> -/*
>>    * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
>>    * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
>>    *
>> @@ -2044,7 +1952,6 @@ static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf,
>>   	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>>   	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>>   	u8 *data_buf, *oob_buf = NULL;
>> -
>>   	nand_read_page_op(chip, page, 0, NULL, 0);
>>   	data_buf = buf;
>>   	oob_buf = oob_required ? chip->oob_poi : NULL;
>> @@ -2366,64 +2273,6 @@ static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs)
>>   }
>>   
>>   /*
>> - * the three functions below implement chip->legacy.read_byte(),
>> - * chip->legacy.read_buf() and chip->legacy.write_buf() respectively. these
>> - * aren't used for reading/writing page data, they are used for smaller data
>> - * like reading	id, status etc
>> - */
>> -static uint8_t qcom_nandc_read_byte(struct nand_chip *chip)
>> -{
>> -	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> -	u8 *buf = nandc->data_buffer;
>> -	u8 ret = 0x0;
>> -
>> -	if (host->last_command == NAND_CMD_STATUS) {
>> -		ret = host->status;
>> -
>> -		host->status = NAND_STATUS_READY | NAND_STATUS_WP;
>> -
>> -		return ret;
>> -	}
>> -
>> -	if (nandc->buf_start < nandc->buf_count)
>> -		ret = buf[nandc->buf_start++];
>> -
>> -	return ret;
>> -}
>> -
>> -static void qcom_nandc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
>> -{
>> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> -	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
>> -
>> -	memcpy(buf, nandc->data_buffer + nandc->buf_start, real_len);
>> -	nandc->buf_start += real_len;
>> -}
>> -
>> -static void qcom_nandc_write_buf(struct nand_chip *chip, const uint8_t *buf,
>> -				 int len)
>> -{
>> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> -	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
>> -
>> -	memcpy(nandc->data_buffer + nandc->buf_start, buf, real_len);
>> -
>> -	nandc->buf_start += real_len;
>> -}
>> -
>> -/* we support only one external chip for now */
>> -static void qcom_nandc_select_chip(struct nand_chip *chip, int chipnr)
>> -{
>> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> -
>> -	if (chipnr <= 0)
>> -		return;
>> -
>> -	dev_warn(nandc->dev, "invalid chip select\n");
>> -}
>> -
>> -/*
>>    * NAND controller page layout info
>>    *
>>    * Layout with ECC enabled:
>> @@ -2738,8 +2587,207 @@ static int qcom_nand_attach_chip(struct nand_chip *chip)
>>   	return 0;
>>   }
>>   
>> +static int nandc_status(struct nand_chip *chip)
>> +{
>> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>> +
>> +	memcpy(nandc->data_buffer, &host->status, 1);
>> +
>> +	return 0;
>> +}
>> +
>> +static int qcom_nand_send_command(struct nand_chip *chip, u8 command)
>> +{
>> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> +	struct nand_ecc_ctrl *ecc = &chip->ecc;
>> +
>> +	int ret = 0;
>> +
>> +	pre_command(host, command);
>> +
>> +	switch (command) {
>> +	case NAND_CMD_RESET:
>> +		ret = reset(host);
>> +		break;
>> +	case NAND_CMD_READID:
>> +		nandc->buf_count = 4;
>> +		ret = read_id(host, 0);
>> +		break;
>> +	case NAND_CMD_PARAM:
>> +		ret = nandc_param(host);
>> +		break;
>> +	case NAND_CMD_ERASE1:
>> +		ret = erase_block(host);
>> +		break;
>> +	case NAND_CMD_STATUS:
>> +		ret = nandc_status(chip);
>> +		break;
>> +	case NAND_CMD_READ0:
>> +		host->use_ecc = true;
> ->exec_op() and ECC are orthogonal
>
>> +		update_rw_regs(host, ecc->steps, true, 0);
>> +		break;
>> +	case NAND_CMD_ERASE2:
>> +		break;
>> +	case NAND_CMD_SEQIN:
>> +		break;
>> +	case NAND_CMD_PAGEPROG:
>> +		break;
> I am sorry but this is not following ->exec_op() main idea. The
> controller is just here to forward requests to the device it must
> respect a number of cycles but that's pretty much all. Here you are
> actually re-writing ->cmdfunc() which is not what we expect.


  Thanks for reviewing this. I will address this all comments in next patch.

>
>
>> +	default:
>> +		break;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static int qcom_nand_send_address(struct nand_chip *chip,
>> +				  const struct nand_op_instr *instr, int cmd)
>> +{
>> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> +	u32 page_addr = 0x0, page_mask = 0x0;
>> +
>> +	page_addr = instr->ctx.addr.addrs[0];
>> +
>> +	/*
>> +	 *Form page address for erase, read, write to using existing api
>> +	 */
>> +
>> +	switch (cmd) {
>> +	case NAND_CMD_ERASE1:
>> +		page_addr = instr->ctx.addr.addrs[0];
>> +		page_mask = instr->ctx.addr.addrs[1];
>> +		page_mask <<= 8;
>> +		page_addr = (page_addr | page_mask);
>> +		page_mask = instr->ctx.addr.addrs[2];
>> +		page_mask <<= 16;
>> +		page_addr = (page_addr | page_mask);
>> +		page_mask = instr->ctx.addr.addrs[3];
>> +		page_mask <<= 24;
>> +		page_addr = (page_addr | page_mask);
>> +		break;
>> +	case NAND_CMD_READ0:
>> +	case NAND_CMD_SEQIN:
>> +		page_addr = instr->ctx.addr.addrs[3];
>> +		page_addr <<= 24;
>> +		page_mask = instr->ctx.addr.addrs[2];
>> +		page_mask <<= 16;
>> +		page_addr |= page_mask;
>> +		page_mask = instr->ctx.addr.addrs[1];
>> +		page_mask <<= 8;
>> +		page_addr |= page_mask;
>> +		page_mask = instr->ctx.addr.addrs[0];
>> +		page_addr |= page_mask;
> Same here, just write the number of address cycles that were requested
> by the core.


  Sure, I will modify this in next patch.

>
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	if (cmd == NAND_CMD_PARAM)
>> +		return 0;
>> +
>> +	nandc_set_reg(chip, NAND_ADDR0, page_addr);
>> +	nandc_set_reg(chip, NAND_ADDR1, 0);
>> +
>> +	if (cmd != NAND_CMD_SEQIN)
>> +		write_reg_dma(nandc, NAND_ADDR0, 2, 0);
>> +
>> +	return 0;
>> +}
>> +
>> +static void qcom_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
>> +{
>> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> +
>> +	memcpy(buf, nandc->data_buffer, len);
> Is this bounce buffer needed?
  Yes , for read id data we need this bounce buffer.
>
>> +}
>> +
>> +static int qcom_nand_exec_instr(struct nand_chip *chip,
>> +				const struct nand_op_instr *instr)
>> +{
>> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>> +	u32 status;
>> +	int ret = 0;
>> +	bool wait = false;
>> +	static int opcode;
>> +
>> +	switch (instr->type) {
>> +	case NAND_OP_CMD_INSTR:
>> +		ret = qcom_nand_send_command(chip, instr->ctx.cmd.opcode);
>> +		if (instr->ctx.cmd.opcode == NAND_CMD_RESET)
>> +			wait = true;
>> +		opcode = instr->ctx.cmd.opcode;
>> +		break;
>> +	case NAND_OP_ADDR_INSTR:
>> +		qcom_nand_send_address(chip, instr, opcode);
>> +		if (opcode != NAND_CMD_READ0 && opcode != NAND_CMD_READSTART &&
>> +		    opcode != NAND_CMD_PARAM && opcode != NAND_CMD_SEQIN)
>> +			wait = true;
>> +		break;
>> +	case NAND_OP_DATA_IN_INSTR:
>> +		qcom_nand_read_buf(chip, instr->ctx.data.buf.in, instr->ctx.data.len);
>> +		break;
>> +	case NAND_OP_DATA_OUT_INSTR:
>> +		wait = false;
>> +		break;
>> +	case NAND_OP_WAITRDY_INSTR:
>> +		ret = readl_poll_timeout(nandc->base + NAND_FLASH_STATUS, status,
>> +					 (status & FS_READY_BSY_N), 20,
>> +					 instr->ctx.waitrdy.timeout_ms * 1000);
>> +		if (opcode == NAND_CMD_PARAM)
>> +			wait = true;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	if (wait) {
>> +		if (opcode != NAND_CMD_PARAM)
>> +			write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>> +
>> +		if (opcode == NAND_CMD_READID)
>> +			read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
>> +
>> +		if (opcode == NAND_CMD_ERASE1) {
>> +			read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
>> +			write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
>> +			write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
>> +		}
>> +
>> +		ret = submit_descs(nandc);
>> +		if (ret)
>> +			dev_err(nandc->dev, "failure submitting descs for command 0x%02x\n",
>> +				opcode);
>> +
>> +		free_descs(nandc);
>> +		post_command(host, opcode);
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static int qcom_nand_exec_op(struct nand_chip *chip,
>> +			     const struct nand_operation *op,
>> +				bool check_only)
>> +{
>> +	unsigned int i;
>> +	int ret = 0;
>> +
>> +	if (check_only)
>> +		return 0;
>> +
>> +	for (i = 0; i < op->ninstrs; i++) {
>> +		ret = qcom_nand_exec_instr(chip, &op->instrs[i]);
>> +		if (ret)
>> +			break;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>>   static const struct nand_controller_ops qcom_nandc_ops = {
>>   	.attach_chip = qcom_nand_attach_chip,
>> +	.exec_op = qcom_nand_exec_op,
>>   };
>>   
>>   static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
>> @@ -2938,14 +2986,6 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
>>   	mtd->owner = THIS_MODULE;
>>   	mtd->dev.parent = dev;
>>   
>> -	chip->legacy.cmdfunc	= qcom_nandc_command;
>> -	chip->legacy.select_chip	= qcom_nandc_select_chip;
>> -	chip->legacy.read_byte	= qcom_nandc_read_byte;
>> -	chip->legacy.read_buf	= qcom_nandc_read_buf;
>> -	chip->legacy.write_buf	= qcom_nandc_write_buf;
>> -	chip->legacy.set_features	= nand_get_set_features_notsupp;
>> -	chip->legacy.get_features	= nand_get_set_features_notsupp;
>> -
>>   	/*
>>   	 * the bad block marker is readable only when we read the last codeword
>>   	 * of a page with ECC disabled. currently, the nand_base and nand_bbt
>
> Thanks,
> Miquèl

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

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] mtd: rawnand: qcom: Implement exec_op()
@ 2022-06-06  4:48     ` Md Sadre Alam
  0 siblings, 0 replies; 14+ messages in thread
From: Md Sadre Alam @ 2022-06-06  4:48 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: mani, richard, vigneshr, linux-mtd, linux-arm-msm, linux-kernel,
	quic_srichara


On 6/3/2022 10:27 PM, Miquel Raynal wrote:
> Hello,
>
> quic_mdalam@quicinc.com wrote on Fri,  3 Jun 2022 21:54:58 +0530:
>
>> Implement exec_op() so we can later get rid of the legacy interface
>> implementation.
> Thanks for doing this conversion!
>
>> Co-developed-by: Sricharan R <quic_srichara@quicinc.com>
>> Signed-off-by: Sricharan R <quic_srichara@quicinc.com>
>> Signed-off-by: Md Sadre Alam <quic_mdalam@quicinc.com>
>> ---
>>   drivers/mtd/nand/raw/qcom_nandc.c | 368 +++++++++++++++++++++-----------------
>>   1 file changed, 204 insertions(+), 164 deletions(-)
>>
>> diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
>> index 048b255..507921b 100644
>> --- a/drivers/mtd/nand/raw/qcom_nandc.c
>> +++ b/drivers/mtd/nand/raw/qcom_nandc.c
>> @@ -14,6 +14,7 @@
>>   #include <linux/of.h>
>>   #include <linux/of_device.h>
>>   #include <linux/delay.h>
>> +#include <linux/iopoll.h>
>>   #include <linux/dma/qcom_bam_dma.h>
>>   
>>   /* NANDc reg offsets */
>> @@ -1305,15 +1306,13 @@ static int nandc_param(struct qcom_nand_host *host)
>>   }
>>   
>>   /* sets up descriptors for NAND_CMD_ERASE1 */
>> -static int erase_block(struct qcom_nand_host *host, int page_addr)
>> +static int erase_block(struct qcom_nand_host *host)
>>   {
>>   	struct nand_chip *chip = &host->chip;
>>   	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>>   
>>   	nandc_set_reg(chip, NAND_FLASH_CMD,
>>   		      OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE);
>> -	nandc_set_reg(chip, NAND_ADDR0, page_addr);
>> -	nandc_set_reg(chip, NAND_ADDR1, 0);
>>   	nandc_set_reg(chip, NAND_DEV0_CFG0,
>>   		      host->cfg0_raw & ~(7 << CW_PER_PAGE));
>>   	nandc_set_reg(chip, NAND_DEV0_CFG1, host->cfg1_raw);
>> @@ -1321,14 +1320,8 @@ static int erase_block(struct qcom_nand_host *host, int page_addr)
>>   	nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus);
>>   	nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus);
>>   
>> -	write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
>> +	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
>>   	write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
>> -	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>> -
>> -	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
>> -
>> -	write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
>> -	write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
>>   
>>   	return 0;
>>   }
>> @@ -1343,16 +1336,12 @@ static int read_id(struct qcom_nand_host *host, int column)
>>   		return 0;
>>   
>>   	nandc_set_reg(chip, NAND_FLASH_CMD, OP_FETCH_ID);
>> -	nandc_set_reg(chip, NAND_ADDR0, column);
>> -	nandc_set_reg(chip, NAND_ADDR1, 0);
>>   	nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT,
>>   		      nandc->props->is_bam ? 0 : DM_EN);
>>   	nandc_set_reg(chip, NAND_EXEC_CMD, 1);
>>   
>> -	write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
>> -	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>> -
>> -	read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
>> +	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
>> +	write_reg_dma(nandc, NAND_FLASH_CHIP_SELECT, 1, NAND_BAM_NEXT_SGL);
>>   
>>   	return 0;
>>   }
>> @@ -1491,7 +1480,6 @@ static void parse_erase_write_errors(struct qcom_nand_host *host, int command)
>>   
>>   	for (i = 0; i < num_cw; i++) {
>>   		u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
>> -
>>   		if (flash_status & FS_MPU_ERR)
>>   			host->status &= ~NAND_STATUS_WP;
>>   
>> @@ -1523,86 +1511,6 @@ static void post_command(struct qcom_nand_host *host, int command)
>>   }
>>   
>>   /*
>> - * Implements chip->legacy.cmdfunc. It's  only used for a limited set of
>> - * commands. The rest of the commands wouldn't be called by upper layers.
>> - * For example, NAND_CMD_READOOB would never be called because we have our own
>> - * versions of read_oob ops for nand_ecc_ctrl.
>> - */
>> -static void qcom_nandc_command(struct nand_chip *chip, unsigned int command,
>> -			       int column, int page_addr)
>> -{
>> -	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>> -	struct nand_ecc_ctrl *ecc = &chip->ecc;
>> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> -	bool wait = false;
>> -	int ret = 0;
>> -
>> -	pre_command(host, command);
>> -
>> -	switch (command) {
>> -	case NAND_CMD_RESET:
>> -		ret = reset(host);
>> -		wait = true;
>> -		break;
>> -
>> -	case NAND_CMD_READID:
>> -		nandc->buf_count = 4;
>> -		ret = read_id(host, column);
>> -		wait = true;
>> -		break;
>> -
>> -	case NAND_CMD_PARAM:
>> -		ret = nandc_param(host);
>> -		wait = true;
>> -		break;
>> -
>> -	case NAND_CMD_ERASE1:
>> -		ret = erase_block(host, page_addr);
>> -		wait = true;
>> -		break;
>> -
>> -	case NAND_CMD_READ0:
>> -		/* we read the entire page for now */
>> -		WARN_ON(column != 0);
>> -
>> -		host->use_ecc = true;
>> -		set_address(host, 0, page_addr);
>> -		update_rw_regs(host, ecc->steps, true, 0);
>> -		break;
>> -
>> -	case NAND_CMD_SEQIN:
>> -		WARN_ON(column != 0);
>> -		set_address(host, 0, page_addr);
>> -		break;
>> -
>> -	case NAND_CMD_PAGEPROG:
>> -	case NAND_CMD_STATUS:
>> -	case NAND_CMD_NONE:
>> -	default:
>> -		break;
>> -	}
>> -
>> -	if (ret) {
>> -		dev_err(nandc->dev, "failure executing command %d\n",
>> -			command);
>> -		free_descs(nandc);
>> -		return;
>> -	}
>> -
>> -	if (wait) {
>> -		ret = submit_descs(nandc);
>> -		if (ret)
>> -			dev_err(nandc->dev,
>> -				"failure submitting descs for command %d\n",
>> -				command);
>> -	}
>> -
>> -	free_descs(nandc);
>> -
>> -	post_command(host, command);
>> -}
>> -
>> -/*
>>    * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
>>    * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
>>    *
>> @@ -2044,7 +1952,6 @@ static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf,
>>   	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>>   	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>>   	u8 *data_buf, *oob_buf = NULL;
>> -
>>   	nand_read_page_op(chip, page, 0, NULL, 0);
>>   	data_buf = buf;
>>   	oob_buf = oob_required ? chip->oob_poi : NULL;
>> @@ -2366,64 +2273,6 @@ static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs)
>>   }
>>   
>>   /*
>> - * the three functions below implement chip->legacy.read_byte(),
>> - * chip->legacy.read_buf() and chip->legacy.write_buf() respectively. these
>> - * aren't used for reading/writing page data, they are used for smaller data
>> - * like reading	id, status etc
>> - */
>> -static uint8_t qcom_nandc_read_byte(struct nand_chip *chip)
>> -{
>> -	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> -	u8 *buf = nandc->data_buffer;
>> -	u8 ret = 0x0;
>> -
>> -	if (host->last_command == NAND_CMD_STATUS) {
>> -		ret = host->status;
>> -
>> -		host->status = NAND_STATUS_READY | NAND_STATUS_WP;
>> -
>> -		return ret;
>> -	}
>> -
>> -	if (nandc->buf_start < nandc->buf_count)
>> -		ret = buf[nandc->buf_start++];
>> -
>> -	return ret;
>> -}
>> -
>> -static void qcom_nandc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
>> -{
>> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> -	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
>> -
>> -	memcpy(buf, nandc->data_buffer + nandc->buf_start, real_len);
>> -	nandc->buf_start += real_len;
>> -}
>> -
>> -static void qcom_nandc_write_buf(struct nand_chip *chip, const uint8_t *buf,
>> -				 int len)
>> -{
>> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> -	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
>> -
>> -	memcpy(nandc->data_buffer + nandc->buf_start, buf, real_len);
>> -
>> -	nandc->buf_start += real_len;
>> -}
>> -
>> -/* we support only one external chip for now */
>> -static void qcom_nandc_select_chip(struct nand_chip *chip, int chipnr)
>> -{
>> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> -
>> -	if (chipnr <= 0)
>> -		return;
>> -
>> -	dev_warn(nandc->dev, "invalid chip select\n");
>> -}
>> -
>> -/*
>>    * NAND controller page layout info
>>    *
>>    * Layout with ECC enabled:
>> @@ -2738,8 +2587,207 @@ static int qcom_nand_attach_chip(struct nand_chip *chip)
>>   	return 0;
>>   }
>>   
>> +static int nandc_status(struct nand_chip *chip)
>> +{
>> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>> +
>> +	memcpy(nandc->data_buffer, &host->status, 1);
>> +
>> +	return 0;
>> +}
>> +
>> +static int qcom_nand_send_command(struct nand_chip *chip, u8 command)
>> +{
>> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> +	struct nand_ecc_ctrl *ecc = &chip->ecc;
>> +
>> +	int ret = 0;
>> +
>> +	pre_command(host, command);
>> +
>> +	switch (command) {
>> +	case NAND_CMD_RESET:
>> +		ret = reset(host);
>> +		break;
>> +	case NAND_CMD_READID:
>> +		nandc->buf_count = 4;
>> +		ret = read_id(host, 0);
>> +		break;
>> +	case NAND_CMD_PARAM:
>> +		ret = nandc_param(host);
>> +		break;
>> +	case NAND_CMD_ERASE1:
>> +		ret = erase_block(host);
>> +		break;
>> +	case NAND_CMD_STATUS:
>> +		ret = nandc_status(chip);
>> +		break;
>> +	case NAND_CMD_READ0:
>> +		host->use_ecc = true;
> ->exec_op() and ECC are orthogonal
>
>> +		update_rw_regs(host, ecc->steps, true, 0);
>> +		break;
>> +	case NAND_CMD_ERASE2:
>> +		break;
>> +	case NAND_CMD_SEQIN:
>> +		break;
>> +	case NAND_CMD_PAGEPROG:
>> +		break;
> I am sorry but this is not following ->exec_op() main idea. The
> controller is just here to forward requests to the device it must
> respect a number of cycles but that's pretty much all. Here you are
> actually re-writing ->cmdfunc() which is not what we expect.


  Thanks for reviewing this. I will address this all comments in next patch.

>
>
>> +	default:
>> +		break;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static int qcom_nand_send_address(struct nand_chip *chip,
>> +				  const struct nand_op_instr *instr, int cmd)
>> +{
>> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> +	u32 page_addr = 0x0, page_mask = 0x0;
>> +
>> +	page_addr = instr->ctx.addr.addrs[0];
>> +
>> +	/*
>> +	 *Form page address for erase, read, write to using existing api
>> +	 */
>> +
>> +	switch (cmd) {
>> +	case NAND_CMD_ERASE1:
>> +		page_addr = instr->ctx.addr.addrs[0];
>> +		page_mask = instr->ctx.addr.addrs[1];
>> +		page_mask <<= 8;
>> +		page_addr = (page_addr | page_mask);
>> +		page_mask = instr->ctx.addr.addrs[2];
>> +		page_mask <<= 16;
>> +		page_addr = (page_addr | page_mask);
>> +		page_mask = instr->ctx.addr.addrs[3];
>> +		page_mask <<= 24;
>> +		page_addr = (page_addr | page_mask);
>> +		break;
>> +	case NAND_CMD_READ0:
>> +	case NAND_CMD_SEQIN:
>> +		page_addr = instr->ctx.addr.addrs[3];
>> +		page_addr <<= 24;
>> +		page_mask = instr->ctx.addr.addrs[2];
>> +		page_mask <<= 16;
>> +		page_addr |= page_mask;
>> +		page_mask = instr->ctx.addr.addrs[1];
>> +		page_mask <<= 8;
>> +		page_addr |= page_mask;
>> +		page_mask = instr->ctx.addr.addrs[0];
>> +		page_addr |= page_mask;
> Same here, just write the number of address cycles that were requested
> by the core.


  Sure, I will modify this in next patch.

>
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	if (cmd == NAND_CMD_PARAM)
>> +		return 0;
>> +
>> +	nandc_set_reg(chip, NAND_ADDR0, page_addr);
>> +	nandc_set_reg(chip, NAND_ADDR1, 0);
>> +
>> +	if (cmd != NAND_CMD_SEQIN)
>> +		write_reg_dma(nandc, NAND_ADDR0, 2, 0);
>> +
>> +	return 0;
>> +}
>> +
>> +static void qcom_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
>> +{
>> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> +
>> +	memcpy(buf, nandc->data_buffer, len);
> Is this bounce buffer needed?
  Yes , for read id data we need this bounce buffer.
>
>> +}
>> +
>> +static int qcom_nand_exec_instr(struct nand_chip *chip,
>> +				const struct nand_op_instr *instr)
>> +{
>> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>> +	u32 status;
>> +	int ret = 0;
>> +	bool wait = false;
>> +	static int opcode;
>> +
>> +	switch (instr->type) {
>> +	case NAND_OP_CMD_INSTR:
>> +		ret = qcom_nand_send_command(chip, instr->ctx.cmd.opcode);
>> +		if (instr->ctx.cmd.opcode == NAND_CMD_RESET)
>> +			wait = true;
>> +		opcode = instr->ctx.cmd.opcode;
>> +		break;
>> +	case NAND_OP_ADDR_INSTR:
>> +		qcom_nand_send_address(chip, instr, opcode);
>> +		if (opcode != NAND_CMD_READ0 && opcode != NAND_CMD_READSTART &&
>> +		    opcode != NAND_CMD_PARAM && opcode != NAND_CMD_SEQIN)
>> +			wait = true;
>> +		break;
>> +	case NAND_OP_DATA_IN_INSTR:
>> +		qcom_nand_read_buf(chip, instr->ctx.data.buf.in, instr->ctx.data.len);
>> +		break;
>> +	case NAND_OP_DATA_OUT_INSTR:
>> +		wait = false;
>> +		break;
>> +	case NAND_OP_WAITRDY_INSTR:
>> +		ret = readl_poll_timeout(nandc->base + NAND_FLASH_STATUS, status,
>> +					 (status & FS_READY_BSY_N), 20,
>> +					 instr->ctx.waitrdy.timeout_ms * 1000);
>> +		if (opcode == NAND_CMD_PARAM)
>> +			wait = true;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	if (wait) {
>> +		if (opcode != NAND_CMD_PARAM)
>> +			write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>> +
>> +		if (opcode == NAND_CMD_READID)
>> +			read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
>> +
>> +		if (opcode == NAND_CMD_ERASE1) {
>> +			read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
>> +			write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
>> +			write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
>> +		}
>> +
>> +		ret = submit_descs(nandc);
>> +		if (ret)
>> +			dev_err(nandc->dev, "failure submitting descs for command 0x%02x\n",
>> +				opcode);
>> +
>> +		free_descs(nandc);
>> +		post_command(host, opcode);
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static int qcom_nand_exec_op(struct nand_chip *chip,
>> +			     const struct nand_operation *op,
>> +				bool check_only)
>> +{
>> +	unsigned int i;
>> +	int ret = 0;
>> +
>> +	if (check_only)
>> +		return 0;
>> +
>> +	for (i = 0; i < op->ninstrs; i++) {
>> +		ret = qcom_nand_exec_instr(chip, &op->instrs[i]);
>> +		if (ret)
>> +			break;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>>   static const struct nand_controller_ops qcom_nandc_ops = {
>>   	.attach_chip = qcom_nand_attach_chip,
>> +	.exec_op = qcom_nand_exec_op,
>>   };
>>   
>>   static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
>> @@ -2938,14 +2986,6 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
>>   	mtd->owner = THIS_MODULE;
>>   	mtd->dev.parent = dev;
>>   
>> -	chip->legacy.cmdfunc	= qcom_nandc_command;
>> -	chip->legacy.select_chip	= qcom_nandc_select_chip;
>> -	chip->legacy.read_byte	= qcom_nandc_read_byte;
>> -	chip->legacy.read_buf	= qcom_nandc_read_buf;
>> -	chip->legacy.write_buf	= qcom_nandc_write_buf;
>> -	chip->legacy.set_features	= nand_get_set_features_notsupp;
>> -	chip->legacy.get_features	= nand_get_set_features_notsupp;
>> -
>>   	/*
>>   	 * the bad block marker is readable only when we read the last codeword
>>   	 * of a page with ECC disabled. currently, the nand_base and nand_bbt
>
> Thanks,
> Miquèl

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] mtd: rawnand: qcom: Implement exec_op()
  2022-06-03 16:24 ` Md Sadre Alam
@ 2022-09-15 13:43   ` Manivannan Sadhasivam
  -1 siblings, 0 replies; 14+ messages in thread
From: Manivannan Sadhasivam @ 2022-09-15 13:43 UTC (permalink / raw)
  To: Md Sadre Alam
  Cc: miquel.raynal, richard, vigneshr, linux-mtd, linux-arm-msm,
	linux-kernel, quic_srichara

On Fri, Jun 03, 2022 at 09:54:58PM +0530, Md Sadre Alam wrote:
> Implement exec_op() so we can later get rid of the legacy interface
> implementation.
> 
> Co-developed-by: Sricharan R <quic_srichara@quicinc.com>
> Signed-off-by: Sricharan R <quic_srichara@quicinc.com>
> Signed-off-by: Md Sadre Alam <quic_mdalam@quicinc.com>

Sadre, Sri, any update on this patch?

Thanks,
Mani

> ---
>  drivers/mtd/nand/raw/qcom_nandc.c | 368 +++++++++++++++++++++-----------------
>  1 file changed, 204 insertions(+), 164 deletions(-)
> 
> diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
> index 048b255..507921b 100644
> --- a/drivers/mtd/nand/raw/qcom_nandc.c
> +++ b/drivers/mtd/nand/raw/qcom_nandc.c
> @@ -14,6 +14,7 @@
>  #include <linux/of.h>
>  #include <linux/of_device.h>
>  #include <linux/delay.h>
> +#include <linux/iopoll.h>
>  #include <linux/dma/qcom_bam_dma.h>
>  
>  /* NANDc reg offsets */
> @@ -1305,15 +1306,13 @@ static int nandc_param(struct qcom_nand_host *host)
>  }
>  
>  /* sets up descriptors for NAND_CMD_ERASE1 */
> -static int erase_block(struct qcom_nand_host *host, int page_addr)
> +static int erase_block(struct qcom_nand_host *host)
>  {
>  	struct nand_chip *chip = &host->chip;
>  	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>  
>  	nandc_set_reg(chip, NAND_FLASH_CMD,
>  		      OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE);
> -	nandc_set_reg(chip, NAND_ADDR0, page_addr);
> -	nandc_set_reg(chip, NAND_ADDR1, 0);
>  	nandc_set_reg(chip, NAND_DEV0_CFG0,
>  		      host->cfg0_raw & ~(7 << CW_PER_PAGE));
>  	nandc_set_reg(chip, NAND_DEV0_CFG1, host->cfg1_raw);
> @@ -1321,14 +1320,8 @@ static int erase_block(struct qcom_nand_host *host, int page_addr)
>  	nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus);
>  	nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus);
>  
> -	write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
> +	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
>  	write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
> -	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
> -
> -	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
> -
> -	write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
> -	write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
>  
>  	return 0;
>  }
> @@ -1343,16 +1336,12 @@ static int read_id(struct qcom_nand_host *host, int column)
>  		return 0;
>  
>  	nandc_set_reg(chip, NAND_FLASH_CMD, OP_FETCH_ID);
> -	nandc_set_reg(chip, NAND_ADDR0, column);
> -	nandc_set_reg(chip, NAND_ADDR1, 0);
>  	nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT,
>  		      nandc->props->is_bam ? 0 : DM_EN);
>  	nandc_set_reg(chip, NAND_EXEC_CMD, 1);
>  
> -	write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
> -	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
> -
> -	read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
> +	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
> +	write_reg_dma(nandc, NAND_FLASH_CHIP_SELECT, 1, NAND_BAM_NEXT_SGL);
>  
>  	return 0;
>  }
> @@ -1491,7 +1480,6 @@ static void parse_erase_write_errors(struct qcom_nand_host *host, int command)
>  
>  	for (i = 0; i < num_cw; i++) {
>  		u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
> -
>  		if (flash_status & FS_MPU_ERR)
>  			host->status &= ~NAND_STATUS_WP;
>  
> @@ -1523,86 +1511,6 @@ static void post_command(struct qcom_nand_host *host, int command)
>  }
>  
>  /*
> - * Implements chip->legacy.cmdfunc. It's  only used for a limited set of
> - * commands. The rest of the commands wouldn't be called by upper layers.
> - * For example, NAND_CMD_READOOB would never be called because we have our own
> - * versions of read_oob ops for nand_ecc_ctrl.
> - */
> -static void qcom_nandc_command(struct nand_chip *chip, unsigned int command,
> -			       int column, int page_addr)
> -{
> -	struct qcom_nand_host *host = to_qcom_nand_host(chip);
> -	struct nand_ecc_ctrl *ecc = &chip->ecc;
> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> -	bool wait = false;
> -	int ret = 0;
> -
> -	pre_command(host, command);
> -
> -	switch (command) {
> -	case NAND_CMD_RESET:
> -		ret = reset(host);
> -		wait = true;
> -		break;
> -
> -	case NAND_CMD_READID:
> -		nandc->buf_count = 4;
> -		ret = read_id(host, column);
> -		wait = true;
> -		break;
> -
> -	case NAND_CMD_PARAM:
> -		ret = nandc_param(host);
> -		wait = true;
> -		break;
> -
> -	case NAND_CMD_ERASE1:
> -		ret = erase_block(host, page_addr);
> -		wait = true;
> -		break;
> -
> -	case NAND_CMD_READ0:
> -		/* we read the entire page for now */
> -		WARN_ON(column != 0);
> -
> -		host->use_ecc = true;
> -		set_address(host, 0, page_addr);
> -		update_rw_regs(host, ecc->steps, true, 0);
> -		break;
> -
> -	case NAND_CMD_SEQIN:
> -		WARN_ON(column != 0);
> -		set_address(host, 0, page_addr);
> -		break;
> -
> -	case NAND_CMD_PAGEPROG:
> -	case NAND_CMD_STATUS:
> -	case NAND_CMD_NONE:
> -	default:
> -		break;
> -	}
> -
> -	if (ret) {
> -		dev_err(nandc->dev, "failure executing command %d\n",
> -			command);
> -		free_descs(nandc);
> -		return;
> -	}
> -
> -	if (wait) {
> -		ret = submit_descs(nandc);
> -		if (ret)
> -			dev_err(nandc->dev,
> -				"failure submitting descs for command %d\n",
> -				command);
> -	}
> -
> -	free_descs(nandc);
> -
> -	post_command(host, command);
> -}
> -
> -/*
>   * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
>   * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
>   *
> @@ -2044,7 +1952,6 @@ static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf,
>  	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>  	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>  	u8 *data_buf, *oob_buf = NULL;
> -
>  	nand_read_page_op(chip, page, 0, NULL, 0);
>  	data_buf = buf;
>  	oob_buf = oob_required ? chip->oob_poi : NULL;
> @@ -2366,64 +2273,6 @@ static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs)
>  }
>  
>  /*
> - * the three functions below implement chip->legacy.read_byte(),
> - * chip->legacy.read_buf() and chip->legacy.write_buf() respectively. these
> - * aren't used for reading/writing page data, they are used for smaller data
> - * like reading	id, status etc
> - */
> -static uint8_t qcom_nandc_read_byte(struct nand_chip *chip)
> -{
> -	struct qcom_nand_host *host = to_qcom_nand_host(chip);
> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> -	u8 *buf = nandc->data_buffer;
> -	u8 ret = 0x0;
> -
> -	if (host->last_command == NAND_CMD_STATUS) {
> -		ret = host->status;
> -
> -		host->status = NAND_STATUS_READY | NAND_STATUS_WP;
> -
> -		return ret;
> -	}
> -
> -	if (nandc->buf_start < nandc->buf_count)
> -		ret = buf[nandc->buf_start++];
> -
> -	return ret;
> -}
> -
> -static void qcom_nandc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
> -{
> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> -	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
> -
> -	memcpy(buf, nandc->data_buffer + nandc->buf_start, real_len);
> -	nandc->buf_start += real_len;
> -}
> -
> -static void qcom_nandc_write_buf(struct nand_chip *chip, const uint8_t *buf,
> -				 int len)
> -{
> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> -	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
> -
> -	memcpy(nandc->data_buffer + nandc->buf_start, buf, real_len);
> -
> -	nandc->buf_start += real_len;
> -}
> -
> -/* we support only one external chip for now */
> -static void qcom_nandc_select_chip(struct nand_chip *chip, int chipnr)
> -{
> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> -
> -	if (chipnr <= 0)
> -		return;
> -
> -	dev_warn(nandc->dev, "invalid chip select\n");
> -}
> -
> -/*
>   * NAND controller page layout info
>   *
>   * Layout with ECC enabled:
> @@ -2738,8 +2587,207 @@ static int qcom_nand_attach_chip(struct nand_chip *chip)
>  	return 0;
>  }
>  
> +static int nandc_status(struct nand_chip *chip)
> +{
> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
> +
> +	memcpy(nandc->data_buffer, &host->status, 1);
> +
> +	return 0;
> +}
> +
> +static int qcom_nand_send_command(struct nand_chip *chip, u8 command)
> +{
> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> +	struct nand_ecc_ctrl *ecc = &chip->ecc;
> +
> +	int ret = 0;
> +
> +	pre_command(host, command);
> +
> +	switch (command) {
> +	case NAND_CMD_RESET:
> +		ret = reset(host);
> +		break;
> +	case NAND_CMD_READID:
> +		nandc->buf_count = 4;
> +		ret = read_id(host, 0);
> +		break;
> +	case NAND_CMD_PARAM:
> +		ret = nandc_param(host);
> +		break;
> +	case NAND_CMD_ERASE1:
> +		ret = erase_block(host);
> +		break;
> +	case NAND_CMD_STATUS:
> +		ret = nandc_status(chip);
> +		break;
> +	case NAND_CMD_READ0:
> +		host->use_ecc = true;
> +		update_rw_regs(host, ecc->steps, true, 0);
> +		break;
> +	case NAND_CMD_ERASE2:
> +		break;
> +	case NAND_CMD_SEQIN:
> +		break;
> +	case NAND_CMD_PAGEPROG:
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static int qcom_nand_send_address(struct nand_chip *chip,
> +				  const struct nand_op_instr *instr, int cmd)
> +{
> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> +	u32 page_addr = 0x0, page_mask = 0x0;
> +
> +	page_addr = instr->ctx.addr.addrs[0];
> +
> +	/*
> +	 *Form page address for erase, read, write to using existing api
> +	 */
> +
> +	switch (cmd) {
> +	case NAND_CMD_ERASE1:
> +		page_addr = instr->ctx.addr.addrs[0];
> +		page_mask = instr->ctx.addr.addrs[1];
> +		page_mask <<= 8;
> +		page_addr = (page_addr | page_mask);
> +		page_mask = instr->ctx.addr.addrs[2];
> +		page_mask <<= 16;
> +		page_addr = (page_addr | page_mask);
> +		page_mask = instr->ctx.addr.addrs[3];
> +		page_mask <<= 24;
> +		page_addr = (page_addr | page_mask);
> +		break;
> +	case NAND_CMD_READ0:
> +	case NAND_CMD_SEQIN:
> +		page_addr = instr->ctx.addr.addrs[3];
> +		page_addr <<= 24;
> +		page_mask = instr->ctx.addr.addrs[2];
> +		page_mask <<= 16;
> +		page_addr |= page_mask;
> +		page_mask = instr->ctx.addr.addrs[1];
> +		page_mask <<= 8;
> +		page_addr |= page_mask;
> +		page_mask = instr->ctx.addr.addrs[0];
> +		page_addr |= page_mask;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	if (cmd == NAND_CMD_PARAM)
> +		return 0;
> +
> +	nandc_set_reg(chip, NAND_ADDR0, page_addr);
> +	nandc_set_reg(chip, NAND_ADDR1, 0);
> +
> +	if (cmd != NAND_CMD_SEQIN)
> +		write_reg_dma(nandc, NAND_ADDR0, 2, 0);
> +
> +	return 0;
> +}
> +
> +static void qcom_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
> +{
> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> +
> +	memcpy(buf, nandc->data_buffer, len);
> +}
> +
> +static int qcom_nand_exec_instr(struct nand_chip *chip,
> +				const struct nand_op_instr *instr)
> +{
> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
> +	u32 status;
> +	int ret = 0;
> +	bool wait = false;
> +	static int opcode;
> +
> +	switch (instr->type) {
> +	case NAND_OP_CMD_INSTR:
> +		ret = qcom_nand_send_command(chip, instr->ctx.cmd.opcode);
> +		if (instr->ctx.cmd.opcode == NAND_CMD_RESET)
> +			wait = true;
> +		opcode = instr->ctx.cmd.opcode;
> +		break;
> +	case NAND_OP_ADDR_INSTR:
> +		qcom_nand_send_address(chip, instr, opcode);
> +		if (opcode != NAND_CMD_READ0 && opcode != NAND_CMD_READSTART &&
> +		    opcode != NAND_CMD_PARAM && opcode != NAND_CMD_SEQIN)
> +			wait = true;
> +		break;
> +	case NAND_OP_DATA_IN_INSTR:
> +		qcom_nand_read_buf(chip, instr->ctx.data.buf.in, instr->ctx.data.len);
> +		break;
> +	case NAND_OP_DATA_OUT_INSTR:
> +		wait = false;
> +		break;
> +	case NAND_OP_WAITRDY_INSTR:
> +		ret = readl_poll_timeout(nandc->base + NAND_FLASH_STATUS, status,
> +					 (status & FS_READY_BSY_N), 20,
> +					 instr->ctx.waitrdy.timeout_ms * 1000);
> +		if (opcode == NAND_CMD_PARAM)
> +			wait = true;
> +	default:
> +		break;
> +	}
> +
> +	if (wait) {
> +		if (opcode != NAND_CMD_PARAM)
> +			write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
> +
> +		if (opcode == NAND_CMD_READID)
> +			read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
> +
> +		if (opcode == NAND_CMD_ERASE1) {
> +			read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
> +			write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
> +			write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
> +		}
> +
> +		ret = submit_descs(nandc);
> +		if (ret)
> +			dev_err(nandc->dev, "failure submitting descs for command 0x%02x\n",
> +				opcode);
> +
> +		free_descs(nandc);
> +		post_command(host, opcode);
> +	}
> +
> +	return ret;
> +}
> +
> +static int qcom_nand_exec_op(struct nand_chip *chip,
> +			     const struct nand_operation *op,
> +				bool check_only)
> +{
> +	unsigned int i;
> +	int ret = 0;
> +
> +	if (check_only)
> +		return 0;
> +
> +	for (i = 0; i < op->ninstrs; i++) {
> +		ret = qcom_nand_exec_instr(chip, &op->instrs[i]);
> +		if (ret)
> +			break;
> +	}
> +
> +	return ret;
> +}
> +
>  static const struct nand_controller_ops qcom_nandc_ops = {
>  	.attach_chip = qcom_nand_attach_chip,
> +	.exec_op = qcom_nand_exec_op,
>  };
>  
>  static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
> @@ -2938,14 +2986,6 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
>  	mtd->owner = THIS_MODULE;
>  	mtd->dev.parent = dev;
>  
> -	chip->legacy.cmdfunc	= qcom_nandc_command;
> -	chip->legacy.select_chip	= qcom_nandc_select_chip;
> -	chip->legacy.read_byte	= qcom_nandc_read_byte;
> -	chip->legacy.read_buf	= qcom_nandc_read_buf;
> -	chip->legacy.write_buf	= qcom_nandc_write_buf;
> -	chip->legacy.set_features	= nand_get_set_features_notsupp;
> -	chip->legacy.get_features	= nand_get_set_features_notsupp;
> -
>  	/*
>  	 * the bad block marker is readable only when we read the last codeword
>  	 * of a page with ECC disabled. currently, the nand_base and nand_bbt
> -- 
> 2.7.4
> 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] mtd: rawnand: qcom: Implement exec_op()
@ 2022-09-15 13:43   ` Manivannan Sadhasivam
  0 siblings, 0 replies; 14+ messages in thread
From: Manivannan Sadhasivam @ 2022-09-15 13:43 UTC (permalink / raw)
  To: Md Sadre Alam
  Cc: miquel.raynal, richard, vigneshr, linux-mtd, linux-arm-msm,
	linux-kernel, quic_srichara

On Fri, Jun 03, 2022 at 09:54:58PM +0530, Md Sadre Alam wrote:
> Implement exec_op() so we can later get rid of the legacy interface
> implementation.
> 
> Co-developed-by: Sricharan R <quic_srichara@quicinc.com>
> Signed-off-by: Sricharan R <quic_srichara@quicinc.com>
> Signed-off-by: Md Sadre Alam <quic_mdalam@quicinc.com>

Sadre, Sri, any update on this patch?

Thanks,
Mani

> ---
>  drivers/mtd/nand/raw/qcom_nandc.c | 368 +++++++++++++++++++++-----------------
>  1 file changed, 204 insertions(+), 164 deletions(-)
> 
> diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
> index 048b255..507921b 100644
> --- a/drivers/mtd/nand/raw/qcom_nandc.c
> +++ b/drivers/mtd/nand/raw/qcom_nandc.c
> @@ -14,6 +14,7 @@
>  #include <linux/of.h>
>  #include <linux/of_device.h>
>  #include <linux/delay.h>
> +#include <linux/iopoll.h>
>  #include <linux/dma/qcom_bam_dma.h>
>  
>  /* NANDc reg offsets */
> @@ -1305,15 +1306,13 @@ static int nandc_param(struct qcom_nand_host *host)
>  }
>  
>  /* sets up descriptors for NAND_CMD_ERASE1 */
> -static int erase_block(struct qcom_nand_host *host, int page_addr)
> +static int erase_block(struct qcom_nand_host *host)
>  {
>  	struct nand_chip *chip = &host->chip;
>  	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>  
>  	nandc_set_reg(chip, NAND_FLASH_CMD,
>  		      OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE);
> -	nandc_set_reg(chip, NAND_ADDR0, page_addr);
> -	nandc_set_reg(chip, NAND_ADDR1, 0);
>  	nandc_set_reg(chip, NAND_DEV0_CFG0,
>  		      host->cfg0_raw & ~(7 << CW_PER_PAGE));
>  	nandc_set_reg(chip, NAND_DEV0_CFG1, host->cfg1_raw);
> @@ -1321,14 +1320,8 @@ static int erase_block(struct qcom_nand_host *host, int page_addr)
>  	nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus);
>  	nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus);
>  
> -	write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
> +	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
>  	write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
> -	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
> -
> -	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
> -
> -	write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
> -	write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
>  
>  	return 0;
>  }
> @@ -1343,16 +1336,12 @@ static int read_id(struct qcom_nand_host *host, int column)
>  		return 0;
>  
>  	nandc_set_reg(chip, NAND_FLASH_CMD, OP_FETCH_ID);
> -	nandc_set_reg(chip, NAND_ADDR0, column);
> -	nandc_set_reg(chip, NAND_ADDR1, 0);
>  	nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT,
>  		      nandc->props->is_bam ? 0 : DM_EN);
>  	nandc_set_reg(chip, NAND_EXEC_CMD, 1);
>  
> -	write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
> -	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
> -
> -	read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
> +	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
> +	write_reg_dma(nandc, NAND_FLASH_CHIP_SELECT, 1, NAND_BAM_NEXT_SGL);
>  
>  	return 0;
>  }
> @@ -1491,7 +1480,6 @@ static void parse_erase_write_errors(struct qcom_nand_host *host, int command)
>  
>  	for (i = 0; i < num_cw; i++) {
>  		u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
> -
>  		if (flash_status & FS_MPU_ERR)
>  			host->status &= ~NAND_STATUS_WP;
>  
> @@ -1523,86 +1511,6 @@ static void post_command(struct qcom_nand_host *host, int command)
>  }
>  
>  /*
> - * Implements chip->legacy.cmdfunc. It's  only used for a limited set of
> - * commands. The rest of the commands wouldn't be called by upper layers.
> - * For example, NAND_CMD_READOOB would never be called because we have our own
> - * versions of read_oob ops for nand_ecc_ctrl.
> - */
> -static void qcom_nandc_command(struct nand_chip *chip, unsigned int command,
> -			       int column, int page_addr)
> -{
> -	struct qcom_nand_host *host = to_qcom_nand_host(chip);
> -	struct nand_ecc_ctrl *ecc = &chip->ecc;
> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> -	bool wait = false;
> -	int ret = 0;
> -
> -	pre_command(host, command);
> -
> -	switch (command) {
> -	case NAND_CMD_RESET:
> -		ret = reset(host);
> -		wait = true;
> -		break;
> -
> -	case NAND_CMD_READID:
> -		nandc->buf_count = 4;
> -		ret = read_id(host, column);
> -		wait = true;
> -		break;
> -
> -	case NAND_CMD_PARAM:
> -		ret = nandc_param(host);
> -		wait = true;
> -		break;
> -
> -	case NAND_CMD_ERASE1:
> -		ret = erase_block(host, page_addr);
> -		wait = true;
> -		break;
> -
> -	case NAND_CMD_READ0:
> -		/* we read the entire page for now */
> -		WARN_ON(column != 0);
> -
> -		host->use_ecc = true;
> -		set_address(host, 0, page_addr);
> -		update_rw_regs(host, ecc->steps, true, 0);
> -		break;
> -
> -	case NAND_CMD_SEQIN:
> -		WARN_ON(column != 0);
> -		set_address(host, 0, page_addr);
> -		break;
> -
> -	case NAND_CMD_PAGEPROG:
> -	case NAND_CMD_STATUS:
> -	case NAND_CMD_NONE:
> -	default:
> -		break;
> -	}
> -
> -	if (ret) {
> -		dev_err(nandc->dev, "failure executing command %d\n",
> -			command);
> -		free_descs(nandc);
> -		return;
> -	}
> -
> -	if (wait) {
> -		ret = submit_descs(nandc);
> -		if (ret)
> -			dev_err(nandc->dev,
> -				"failure submitting descs for command %d\n",
> -				command);
> -	}
> -
> -	free_descs(nandc);
> -
> -	post_command(host, command);
> -}
> -
> -/*
>   * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
>   * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
>   *
> @@ -2044,7 +1952,6 @@ static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf,
>  	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>  	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>  	u8 *data_buf, *oob_buf = NULL;
> -
>  	nand_read_page_op(chip, page, 0, NULL, 0);
>  	data_buf = buf;
>  	oob_buf = oob_required ? chip->oob_poi : NULL;
> @@ -2366,64 +2273,6 @@ static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs)
>  }
>  
>  /*
> - * the three functions below implement chip->legacy.read_byte(),
> - * chip->legacy.read_buf() and chip->legacy.write_buf() respectively. these
> - * aren't used for reading/writing page data, they are used for smaller data
> - * like reading	id, status etc
> - */
> -static uint8_t qcom_nandc_read_byte(struct nand_chip *chip)
> -{
> -	struct qcom_nand_host *host = to_qcom_nand_host(chip);
> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> -	u8 *buf = nandc->data_buffer;
> -	u8 ret = 0x0;
> -
> -	if (host->last_command == NAND_CMD_STATUS) {
> -		ret = host->status;
> -
> -		host->status = NAND_STATUS_READY | NAND_STATUS_WP;
> -
> -		return ret;
> -	}
> -
> -	if (nandc->buf_start < nandc->buf_count)
> -		ret = buf[nandc->buf_start++];
> -
> -	return ret;
> -}
> -
> -static void qcom_nandc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
> -{
> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> -	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
> -
> -	memcpy(buf, nandc->data_buffer + nandc->buf_start, real_len);
> -	nandc->buf_start += real_len;
> -}
> -
> -static void qcom_nandc_write_buf(struct nand_chip *chip, const uint8_t *buf,
> -				 int len)
> -{
> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> -	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
> -
> -	memcpy(nandc->data_buffer + nandc->buf_start, buf, real_len);
> -
> -	nandc->buf_start += real_len;
> -}
> -
> -/* we support only one external chip for now */
> -static void qcom_nandc_select_chip(struct nand_chip *chip, int chipnr)
> -{
> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> -
> -	if (chipnr <= 0)
> -		return;
> -
> -	dev_warn(nandc->dev, "invalid chip select\n");
> -}
> -
> -/*
>   * NAND controller page layout info
>   *
>   * Layout with ECC enabled:
> @@ -2738,8 +2587,207 @@ static int qcom_nand_attach_chip(struct nand_chip *chip)
>  	return 0;
>  }
>  
> +static int nandc_status(struct nand_chip *chip)
> +{
> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
> +
> +	memcpy(nandc->data_buffer, &host->status, 1);
> +
> +	return 0;
> +}
> +
> +static int qcom_nand_send_command(struct nand_chip *chip, u8 command)
> +{
> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> +	struct nand_ecc_ctrl *ecc = &chip->ecc;
> +
> +	int ret = 0;
> +
> +	pre_command(host, command);
> +
> +	switch (command) {
> +	case NAND_CMD_RESET:
> +		ret = reset(host);
> +		break;
> +	case NAND_CMD_READID:
> +		nandc->buf_count = 4;
> +		ret = read_id(host, 0);
> +		break;
> +	case NAND_CMD_PARAM:
> +		ret = nandc_param(host);
> +		break;
> +	case NAND_CMD_ERASE1:
> +		ret = erase_block(host);
> +		break;
> +	case NAND_CMD_STATUS:
> +		ret = nandc_status(chip);
> +		break;
> +	case NAND_CMD_READ0:
> +		host->use_ecc = true;
> +		update_rw_regs(host, ecc->steps, true, 0);
> +		break;
> +	case NAND_CMD_ERASE2:
> +		break;
> +	case NAND_CMD_SEQIN:
> +		break;
> +	case NAND_CMD_PAGEPROG:
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static int qcom_nand_send_address(struct nand_chip *chip,
> +				  const struct nand_op_instr *instr, int cmd)
> +{
> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> +	u32 page_addr = 0x0, page_mask = 0x0;
> +
> +	page_addr = instr->ctx.addr.addrs[0];
> +
> +	/*
> +	 *Form page address for erase, read, write to using existing api
> +	 */
> +
> +	switch (cmd) {
> +	case NAND_CMD_ERASE1:
> +		page_addr = instr->ctx.addr.addrs[0];
> +		page_mask = instr->ctx.addr.addrs[1];
> +		page_mask <<= 8;
> +		page_addr = (page_addr | page_mask);
> +		page_mask = instr->ctx.addr.addrs[2];
> +		page_mask <<= 16;
> +		page_addr = (page_addr | page_mask);
> +		page_mask = instr->ctx.addr.addrs[3];
> +		page_mask <<= 24;
> +		page_addr = (page_addr | page_mask);
> +		break;
> +	case NAND_CMD_READ0:
> +	case NAND_CMD_SEQIN:
> +		page_addr = instr->ctx.addr.addrs[3];
> +		page_addr <<= 24;
> +		page_mask = instr->ctx.addr.addrs[2];
> +		page_mask <<= 16;
> +		page_addr |= page_mask;
> +		page_mask = instr->ctx.addr.addrs[1];
> +		page_mask <<= 8;
> +		page_addr |= page_mask;
> +		page_mask = instr->ctx.addr.addrs[0];
> +		page_addr |= page_mask;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	if (cmd == NAND_CMD_PARAM)
> +		return 0;
> +
> +	nandc_set_reg(chip, NAND_ADDR0, page_addr);
> +	nandc_set_reg(chip, NAND_ADDR1, 0);
> +
> +	if (cmd != NAND_CMD_SEQIN)
> +		write_reg_dma(nandc, NAND_ADDR0, 2, 0);
> +
> +	return 0;
> +}
> +
> +static void qcom_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
> +{
> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> +
> +	memcpy(buf, nandc->data_buffer, len);
> +}
> +
> +static int qcom_nand_exec_instr(struct nand_chip *chip,
> +				const struct nand_op_instr *instr)
> +{
> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
> +	u32 status;
> +	int ret = 0;
> +	bool wait = false;
> +	static int opcode;
> +
> +	switch (instr->type) {
> +	case NAND_OP_CMD_INSTR:
> +		ret = qcom_nand_send_command(chip, instr->ctx.cmd.opcode);
> +		if (instr->ctx.cmd.opcode == NAND_CMD_RESET)
> +			wait = true;
> +		opcode = instr->ctx.cmd.opcode;
> +		break;
> +	case NAND_OP_ADDR_INSTR:
> +		qcom_nand_send_address(chip, instr, opcode);
> +		if (opcode != NAND_CMD_READ0 && opcode != NAND_CMD_READSTART &&
> +		    opcode != NAND_CMD_PARAM && opcode != NAND_CMD_SEQIN)
> +			wait = true;
> +		break;
> +	case NAND_OP_DATA_IN_INSTR:
> +		qcom_nand_read_buf(chip, instr->ctx.data.buf.in, instr->ctx.data.len);
> +		break;
> +	case NAND_OP_DATA_OUT_INSTR:
> +		wait = false;
> +		break;
> +	case NAND_OP_WAITRDY_INSTR:
> +		ret = readl_poll_timeout(nandc->base + NAND_FLASH_STATUS, status,
> +					 (status & FS_READY_BSY_N), 20,
> +					 instr->ctx.waitrdy.timeout_ms * 1000);
> +		if (opcode == NAND_CMD_PARAM)
> +			wait = true;
> +	default:
> +		break;
> +	}
> +
> +	if (wait) {
> +		if (opcode != NAND_CMD_PARAM)
> +			write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
> +
> +		if (opcode == NAND_CMD_READID)
> +			read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
> +
> +		if (opcode == NAND_CMD_ERASE1) {
> +			read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
> +			write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
> +			write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
> +		}
> +
> +		ret = submit_descs(nandc);
> +		if (ret)
> +			dev_err(nandc->dev, "failure submitting descs for command 0x%02x\n",
> +				opcode);
> +
> +		free_descs(nandc);
> +		post_command(host, opcode);
> +	}
> +
> +	return ret;
> +}
> +
> +static int qcom_nand_exec_op(struct nand_chip *chip,
> +			     const struct nand_operation *op,
> +				bool check_only)
> +{
> +	unsigned int i;
> +	int ret = 0;
> +
> +	if (check_only)
> +		return 0;
> +
> +	for (i = 0; i < op->ninstrs; i++) {
> +		ret = qcom_nand_exec_instr(chip, &op->instrs[i]);
> +		if (ret)
> +			break;
> +	}
> +
> +	return ret;
> +}
> +
>  static const struct nand_controller_ops qcom_nandc_ops = {
>  	.attach_chip = qcom_nand_attach_chip,
> +	.exec_op = qcom_nand_exec_op,
>  };
>  
>  static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
> @@ -2938,14 +2986,6 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
>  	mtd->owner = THIS_MODULE;
>  	mtd->dev.parent = dev;
>  
> -	chip->legacy.cmdfunc	= qcom_nandc_command;
> -	chip->legacy.select_chip	= qcom_nandc_select_chip;
> -	chip->legacy.read_byte	= qcom_nandc_read_byte;
> -	chip->legacy.read_buf	= qcom_nandc_read_buf;
> -	chip->legacy.write_buf	= qcom_nandc_write_buf;
> -	chip->legacy.set_features	= nand_get_set_features_notsupp;
> -	chip->legacy.get_features	= nand_get_set_features_notsupp;
> -
>  	/*
>  	 * the bad block marker is readable only when we read the last codeword
>  	 * of a page with ECC disabled. currently, the nand_base and nand_bbt
> -- 
> 2.7.4
> 

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

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] mtd: rawnand: qcom: Implement exec_op()
  2022-09-15 13:43   ` Manivannan Sadhasivam
@ 2022-09-20 10:19     ` Sricharan Ramabadhran
  -1 siblings, 0 replies; 14+ messages in thread
From: Sricharan Ramabadhran @ 2022-09-20 10:19 UTC (permalink / raw)
  To: Manivannan Sadhasivam, Md Sadre Alam
  Cc: miquel.raynal, richard, vigneshr, linux-mtd, linux-arm-msm, linux-kernel

Hi Mani,

On 9/15/2022 7:13 PM, Manivannan Sadhasivam wrote:
> On Fri, Jun 03, 2022 at 09:54:58PM +0530, Md Sadre Alam wrote:
>> Implement exec_op() so we can later get rid of the legacy interface
>> implementation.
>>
>> Co-developed-by: Sricharan R <quic_srichara@quicinc.com>
>> Signed-off-by: Sricharan R <quic_srichara@quicinc.com>
>> Signed-off-by: Md Sadre Alam <quic_mdalam@quicinc.com>
> Sadre, Sri, any update on this patch?

Sorry got stuck with few other activities, we are taking this now up again.
So will post the reworked patches sometime next week.

Regards,
   Sricharan



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] mtd: rawnand: qcom: Implement exec_op()
@ 2022-09-20 10:19     ` Sricharan Ramabadhran
  0 siblings, 0 replies; 14+ messages in thread
From: Sricharan Ramabadhran @ 2022-09-20 10:19 UTC (permalink / raw)
  To: Manivannan Sadhasivam, Md Sadre Alam
  Cc: miquel.raynal, richard, vigneshr, linux-mtd, linux-arm-msm, linux-kernel

Hi Mani,

On 9/15/2022 7:13 PM, Manivannan Sadhasivam wrote:
> On Fri, Jun 03, 2022 at 09:54:58PM +0530, Md Sadre Alam wrote:
>> Implement exec_op() so we can later get rid of the legacy interface
>> implementation.
>>
>> Co-developed-by: Sricharan R <quic_srichara@quicinc.com>
>> Signed-off-by: Sricharan R <quic_srichara@quicinc.com>
>> Signed-off-by: Md Sadre Alam <quic_mdalam@quicinc.com>
> Sadre, Sri, any update on this patch?

Sorry got stuck with few other activities, we are taking this now up again.
So will post the reworked patches sometime next week.

Regards,
   Sricharan



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

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] mtd: rawnand: qcom: Implement exec_op()
  2022-09-15 13:43   ` Manivannan Sadhasivam
@ 2023-04-19  9:41     ` Md Sadre Alam
  -1 siblings, 0 replies; 14+ messages in thread
From: Md Sadre Alam @ 2023-04-19  9:41 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: miquel.raynal, richard, vigneshr, linux-mtd, linux-arm-msm,
	linux-kernel, quic_srichara



On 9/15/2022 7:13 PM, Manivannan Sadhasivam wrote:
> On Fri, Jun 03, 2022 at 09:54:58PM +0530, Md Sadre Alam wrote:
>> Implement exec_op() so we can later get rid of the legacy interface
>> implementation.
>>
>> Co-developed-by: Sricharan R <quic_srichara@quicinc.com>
>> Signed-off-by: Sricharan R <quic_srichara@quicinc.com>
>> Signed-off-by: Md Sadre Alam <quic_mdalam@quicinc.com>
> 
> Sadre, Sri, any update on this patch?
> 
> Thanks,
> Mani
>

Hi Mani,

I have sent V2 patch and address all the comments from patch V1.

https://lore.kernel.org/lkml/20230419093617.27134-1-quic_mdalam@quicinc.com/

Thanks,
Alam.

>> ---
>>   drivers/mtd/nand/raw/qcom_nandc.c | 368 +++++++++++++++++++++-----------------
>>   1 file changed, 204 insertions(+), 164 deletions(-)
>>
>> diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
>> index 048b255..507921b 100644
>> --- a/drivers/mtd/nand/raw/qcom_nandc.c
>> +++ b/drivers/mtd/nand/raw/qcom_nandc.c
>> @@ -14,6 +14,7 @@
>>   #include <linux/of.h>
>>   #include <linux/of_device.h>
>>   #include <linux/delay.h>
>> +#include <linux/iopoll.h>
>>   #include <linux/dma/qcom_bam_dma.h>
>>   
>>   /* NANDc reg offsets */
>> @@ -1305,15 +1306,13 @@ static int nandc_param(struct qcom_nand_host *host)
>>   }
>>   
>>   /* sets up descriptors for NAND_CMD_ERASE1 */
>> -static int erase_block(struct qcom_nand_host *host, int page_addr)
>> +static int erase_block(struct qcom_nand_host *host)
>>   {
>>   	struct nand_chip *chip = &host->chip;
>>   	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>>   
>>   	nandc_set_reg(chip, NAND_FLASH_CMD,
>>   		      OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE);
>> -	nandc_set_reg(chip, NAND_ADDR0, page_addr);
>> -	nandc_set_reg(chip, NAND_ADDR1, 0);
>>   	nandc_set_reg(chip, NAND_DEV0_CFG0,
>>   		      host->cfg0_raw & ~(7 << CW_PER_PAGE));
>>   	nandc_set_reg(chip, NAND_DEV0_CFG1, host->cfg1_raw);
>> @@ -1321,14 +1320,8 @@ static int erase_block(struct qcom_nand_host *host, int page_addr)
>>   	nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus);
>>   	nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus);
>>   
>> -	write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
>> +	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
>>   	write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
>> -	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>> -
>> -	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
>> -
>> -	write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
>> -	write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
>>   
>>   	return 0;
>>   }
>> @@ -1343,16 +1336,12 @@ static int read_id(struct qcom_nand_host *host, int column)
>>   		return 0;
>>   
>>   	nandc_set_reg(chip, NAND_FLASH_CMD, OP_FETCH_ID);
>> -	nandc_set_reg(chip, NAND_ADDR0, column);
>> -	nandc_set_reg(chip, NAND_ADDR1, 0);
>>   	nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT,
>>   		      nandc->props->is_bam ? 0 : DM_EN);
>>   	nandc_set_reg(chip, NAND_EXEC_CMD, 1);
>>   
>> -	write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
>> -	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>> -
>> -	read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
>> +	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
>> +	write_reg_dma(nandc, NAND_FLASH_CHIP_SELECT, 1, NAND_BAM_NEXT_SGL);
>>   
>>   	return 0;
>>   }
>> @@ -1491,7 +1480,6 @@ static void parse_erase_write_errors(struct qcom_nand_host *host, int command)
>>   
>>   	for (i = 0; i < num_cw; i++) {
>>   		u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
>> -
>>   		if (flash_status & FS_MPU_ERR)
>>   			host->status &= ~NAND_STATUS_WP;
>>   
>> @@ -1523,86 +1511,6 @@ static void post_command(struct qcom_nand_host *host, int command)
>>   }
>>   
>>   /*
>> - * Implements chip->legacy.cmdfunc. It's  only used for a limited set of
>> - * commands. The rest of the commands wouldn't be called by upper layers.
>> - * For example, NAND_CMD_READOOB would never be called because we have our own
>> - * versions of read_oob ops for nand_ecc_ctrl.
>> - */
>> -static void qcom_nandc_command(struct nand_chip *chip, unsigned int command,
>> -			       int column, int page_addr)
>> -{
>> -	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>> -	struct nand_ecc_ctrl *ecc = &chip->ecc;
>> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> -	bool wait = false;
>> -	int ret = 0;
>> -
>> -	pre_command(host, command);
>> -
>> -	switch (command) {
>> -	case NAND_CMD_RESET:
>> -		ret = reset(host);
>> -		wait = true;
>> -		break;
>> -
>> -	case NAND_CMD_READID:
>> -		nandc->buf_count = 4;
>> -		ret = read_id(host, column);
>> -		wait = true;
>> -		break;
>> -
>> -	case NAND_CMD_PARAM:
>> -		ret = nandc_param(host);
>> -		wait = true;
>> -		break;
>> -
>> -	case NAND_CMD_ERASE1:
>> -		ret = erase_block(host, page_addr);
>> -		wait = true;
>> -		break;
>> -
>> -	case NAND_CMD_READ0:
>> -		/* we read the entire page for now */
>> -		WARN_ON(column != 0);
>> -
>> -		host->use_ecc = true;
>> -		set_address(host, 0, page_addr);
>> -		update_rw_regs(host, ecc->steps, true, 0);
>> -		break;
>> -
>> -	case NAND_CMD_SEQIN:
>> -		WARN_ON(column != 0);
>> -		set_address(host, 0, page_addr);
>> -		break;
>> -
>> -	case NAND_CMD_PAGEPROG:
>> -	case NAND_CMD_STATUS:
>> -	case NAND_CMD_NONE:
>> -	default:
>> -		break;
>> -	}
>> -
>> -	if (ret) {
>> -		dev_err(nandc->dev, "failure executing command %d\n",
>> -			command);
>> -		free_descs(nandc);
>> -		return;
>> -	}
>> -
>> -	if (wait) {
>> -		ret = submit_descs(nandc);
>> -		if (ret)
>> -			dev_err(nandc->dev,
>> -				"failure submitting descs for command %d\n",
>> -				command);
>> -	}
>> -
>> -	free_descs(nandc);
>> -
>> -	post_command(host, command);
>> -}
>> -
>> -/*
>>    * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
>>    * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
>>    *
>> @@ -2044,7 +1952,6 @@ static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf,
>>   	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>>   	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>>   	u8 *data_buf, *oob_buf = NULL;
>> -
>>   	nand_read_page_op(chip, page, 0, NULL, 0);
>>   	data_buf = buf;
>>   	oob_buf = oob_required ? chip->oob_poi : NULL;
>> @@ -2366,64 +2273,6 @@ static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs)
>>   }
>>   
>>   /*
>> - * the three functions below implement chip->legacy.read_byte(),
>> - * chip->legacy.read_buf() and chip->legacy.write_buf() respectively. these
>> - * aren't used for reading/writing page data, they are used for smaller data
>> - * like reading	id, status etc
>> - */
>> -static uint8_t qcom_nandc_read_byte(struct nand_chip *chip)
>> -{
>> -	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> -	u8 *buf = nandc->data_buffer;
>> -	u8 ret = 0x0;
>> -
>> -	if (host->last_command == NAND_CMD_STATUS) {
>> -		ret = host->status;
>> -
>> -		host->status = NAND_STATUS_READY | NAND_STATUS_WP;
>> -
>> -		return ret;
>> -	}
>> -
>> -	if (nandc->buf_start < nandc->buf_count)
>> -		ret = buf[nandc->buf_start++];
>> -
>> -	return ret;
>> -}
>> -
>> -static void qcom_nandc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
>> -{
>> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> -	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
>> -
>> -	memcpy(buf, nandc->data_buffer + nandc->buf_start, real_len);
>> -	nandc->buf_start += real_len;
>> -}
>> -
>> -static void qcom_nandc_write_buf(struct nand_chip *chip, const uint8_t *buf,
>> -				 int len)
>> -{
>> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> -	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
>> -
>> -	memcpy(nandc->data_buffer + nandc->buf_start, buf, real_len);
>> -
>> -	nandc->buf_start += real_len;
>> -}
>> -
>> -/* we support only one external chip for now */
>> -static void qcom_nandc_select_chip(struct nand_chip *chip, int chipnr)
>> -{
>> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> -
>> -	if (chipnr <= 0)
>> -		return;
>> -
>> -	dev_warn(nandc->dev, "invalid chip select\n");
>> -}
>> -
>> -/*
>>    * NAND controller page layout info
>>    *
>>    * Layout with ECC enabled:
>> @@ -2738,8 +2587,207 @@ static int qcom_nand_attach_chip(struct nand_chip *chip)
>>   	return 0;
>>   }
>>   
>> +static int nandc_status(struct nand_chip *chip)
>> +{
>> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>> +
>> +	memcpy(nandc->data_buffer, &host->status, 1);
>> +
>> +	return 0;
>> +}
>> +
>> +static int qcom_nand_send_command(struct nand_chip *chip, u8 command)
>> +{
>> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> +	struct nand_ecc_ctrl *ecc = &chip->ecc;
>> +
>> +	int ret = 0;
>> +
>> +	pre_command(host, command);
>> +
>> +	switch (command) {
>> +	case NAND_CMD_RESET:
>> +		ret = reset(host);
>> +		break;
>> +	case NAND_CMD_READID:
>> +		nandc->buf_count = 4;
>> +		ret = read_id(host, 0);
>> +		break;
>> +	case NAND_CMD_PARAM:
>> +		ret = nandc_param(host);
>> +		break;
>> +	case NAND_CMD_ERASE1:
>> +		ret = erase_block(host);
>> +		break;
>> +	case NAND_CMD_STATUS:
>> +		ret = nandc_status(chip);
>> +		break;
>> +	case NAND_CMD_READ0:
>> +		host->use_ecc = true;
>> +		update_rw_regs(host, ecc->steps, true, 0);
>> +		break;
>> +	case NAND_CMD_ERASE2:
>> +		break;
>> +	case NAND_CMD_SEQIN:
>> +		break;
>> +	case NAND_CMD_PAGEPROG:
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static int qcom_nand_send_address(struct nand_chip *chip,
>> +				  const struct nand_op_instr *instr, int cmd)
>> +{
>> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> +	u32 page_addr = 0x0, page_mask = 0x0;
>> +
>> +	page_addr = instr->ctx.addr.addrs[0];
>> +
>> +	/*
>> +	 *Form page address for erase, read, write to using existing api
>> +	 */
>> +
>> +	switch (cmd) {
>> +	case NAND_CMD_ERASE1:
>> +		page_addr = instr->ctx.addr.addrs[0];
>> +		page_mask = instr->ctx.addr.addrs[1];
>> +		page_mask <<= 8;
>> +		page_addr = (page_addr | page_mask);
>> +		page_mask = instr->ctx.addr.addrs[2];
>> +		page_mask <<= 16;
>> +		page_addr = (page_addr | page_mask);
>> +		page_mask = instr->ctx.addr.addrs[3];
>> +		page_mask <<= 24;
>> +		page_addr = (page_addr | page_mask);
>> +		break;
>> +	case NAND_CMD_READ0:
>> +	case NAND_CMD_SEQIN:
>> +		page_addr = instr->ctx.addr.addrs[3];
>> +		page_addr <<= 24;
>> +		page_mask = instr->ctx.addr.addrs[2];
>> +		page_mask <<= 16;
>> +		page_addr |= page_mask;
>> +		page_mask = instr->ctx.addr.addrs[1];
>> +		page_mask <<= 8;
>> +		page_addr |= page_mask;
>> +		page_mask = instr->ctx.addr.addrs[0];
>> +		page_addr |= page_mask;
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	if (cmd == NAND_CMD_PARAM)
>> +		return 0;
>> +
>> +	nandc_set_reg(chip, NAND_ADDR0, page_addr);
>> +	nandc_set_reg(chip, NAND_ADDR1, 0);
>> +
>> +	if (cmd != NAND_CMD_SEQIN)
>> +		write_reg_dma(nandc, NAND_ADDR0, 2, 0);
>> +
>> +	return 0;
>> +}
>> +
>> +static void qcom_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
>> +{
>> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> +
>> +	memcpy(buf, nandc->data_buffer, len);
>> +}
>> +
>> +static int qcom_nand_exec_instr(struct nand_chip *chip,
>> +				const struct nand_op_instr *instr)
>> +{
>> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>> +	u32 status;
>> +	int ret = 0;
>> +	bool wait = false;
>> +	static int opcode;
>> +
>> +	switch (instr->type) {
>> +	case NAND_OP_CMD_INSTR:
>> +		ret = qcom_nand_send_command(chip, instr->ctx.cmd.opcode);
>> +		if (instr->ctx.cmd.opcode == NAND_CMD_RESET)
>> +			wait = true;
>> +		opcode = instr->ctx.cmd.opcode;
>> +		break;
>> +	case NAND_OP_ADDR_INSTR:
>> +		qcom_nand_send_address(chip, instr, opcode);
>> +		if (opcode != NAND_CMD_READ0 && opcode != NAND_CMD_READSTART &&
>> +		    opcode != NAND_CMD_PARAM && opcode != NAND_CMD_SEQIN)
>> +			wait = true;
>> +		break;
>> +	case NAND_OP_DATA_IN_INSTR:
>> +		qcom_nand_read_buf(chip, instr->ctx.data.buf.in, instr->ctx.data.len);
>> +		break;
>> +	case NAND_OP_DATA_OUT_INSTR:
>> +		wait = false;
>> +		break;
>> +	case NAND_OP_WAITRDY_INSTR:
>> +		ret = readl_poll_timeout(nandc->base + NAND_FLASH_STATUS, status,
>> +					 (status & FS_READY_BSY_N), 20,
>> +					 instr->ctx.waitrdy.timeout_ms * 1000);
>> +		if (opcode == NAND_CMD_PARAM)
>> +			wait = true;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	if (wait) {
>> +		if (opcode != NAND_CMD_PARAM)
>> +			write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>> +
>> +		if (opcode == NAND_CMD_READID)
>> +			read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
>> +
>> +		if (opcode == NAND_CMD_ERASE1) {
>> +			read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
>> +			write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
>> +			write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
>> +		}
>> +
>> +		ret = submit_descs(nandc);
>> +		if (ret)
>> +			dev_err(nandc->dev, "failure submitting descs for command 0x%02x\n",
>> +				opcode);
>> +
>> +		free_descs(nandc);
>> +		post_command(host, opcode);
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static int qcom_nand_exec_op(struct nand_chip *chip,
>> +			     const struct nand_operation *op,
>> +				bool check_only)
>> +{
>> +	unsigned int i;
>> +	int ret = 0;
>> +
>> +	if (check_only)
>> +		return 0;
>> +
>> +	for (i = 0; i < op->ninstrs; i++) {
>> +		ret = qcom_nand_exec_instr(chip, &op->instrs[i]);
>> +		if (ret)
>> +			break;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>>   static const struct nand_controller_ops qcom_nandc_ops = {
>>   	.attach_chip = qcom_nand_attach_chip,
>> +	.exec_op = qcom_nand_exec_op,
>>   };
>>   
>>   static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
>> @@ -2938,14 +2986,6 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
>>   	mtd->owner = THIS_MODULE;
>>   	mtd->dev.parent = dev;
>>   
>> -	chip->legacy.cmdfunc	= qcom_nandc_command;
>> -	chip->legacy.select_chip	= qcom_nandc_select_chip;
>> -	chip->legacy.read_byte	= qcom_nandc_read_byte;
>> -	chip->legacy.read_buf	= qcom_nandc_read_buf;
>> -	chip->legacy.write_buf	= qcom_nandc_write_buf;
>> -	chip->legacy.set_features	= nand_get_set_features_notsupp;
>> -	chip->legacy.get_features	= nand_get_set_features_notsupp;
>> -
>>   	/*
>>   	 * the bad block marker is readable only when we read the last codeword
>>   	 * of a page with ECC disabled. currently, the nand_base and nand_bbt
>> -- 
>> 2.7.4
>>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] mtd: rawnand: qcom: Implement exec_op()
@ 2023-04-19  9:41     ` Md Sadre Alam
  0 siblings, 0 replies; 14+ messages in thread
From: Md Sadre Alam @ 2023-04-19  9:41 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: miquel.raynal, richard, vigneshr, linux-mtd, linux-arm-msm,
	linux-kernel, quic_srichara



On 9/15/2022 7:13 PM, Manivannan Sadhasivam wrote:
> On Fri, Jun 03, 2022 at 09:54:58PM +0530, Md Sadre Alam wrote:
>> Implement exec_op() so we can later get rid of the legacy interface
>> implementation.
>>
>> Co-developed-by: Sricharan R <quic_srichara@quicinc.com>
>> Signed-off-by: Sricharan R <quic_srichara@quicinc.com>
>> Signed-off-by: Md Sadre Alam <quic_mdalam@quicinc.com>
> 
> Sadre, Sri, any update on this patch?
> 
> Thanks,
> Mani
>

Hi Mani,

I have sent V2 patch and address all the comments from patch V1.

https://lore.kernel.org/lkml/20230419093617.27134-1-quic_mdalam@quicinc.com/

Thanks,
Alam.

>> ---
>>   drivers/mtd/nand/raw/qcom_nandc.c | 368 +++++++++++++++++++++-----------------
>>   1 file changed, 204 insertions(+), 164 deletions(-)
>>
>> diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c
>> index 048b255..507921b 100644
>> --- a/drivers/mtd/nand/raw/qcom_nandc.c
>> +++ b/drivers/mtd/nand/raw/qcom_nandc.c
>> @@ -14,6 +14,7 @@
>>   #include <linux/of.h>
>>   #include <linux/of_device.h>
>>   #include <linux/delay.h>
>> +#include <linux/iopoll.h>
>>   #include <linux/dma/qcom_bam_dma.h>
>>   
>>   /* NANDc reg offsets */
>> @@ -1305,15 +1306,13 @@ static int nandc_param(struct qcom_nand_host *host)
>>   }
>>   
>>   /* sets up descriptors for NAND_CMD_ERASE1 */
>> -static int erase_block(struct qcom_nand_host *host, int page_addr)
>> +static int erase_block(struct qcom_nand_host *host)
>>   {
>>   	struct nand_chip *chip = &host->chip;
>>   	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>>   
>>   	nandc_set_reg(chip, NAND_FLASH_CMD,
>>   		      OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE);
>> -	nandc_set_reg(chip, NAND_ADDR0, page_addr);
>> -	nandc_set_reg(chip, NAND_ADDR1, 0);
>>   	nandc_set_reg(chip, NAND_DEV0_CFG0,
>>   		      host->cfg0_raw & ~(7 << CW_PER_PAGE));
>>   	nandc_set_reg(chip, NAND_DEV0_CFG1, host->cfg1_raw);
>> @@ -1321,14 +1320,8 @@ static int erase_block(struct qcom_nand_host *host, int page_addr)
>>   	nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus);
>>   	nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus);
>>   
>> -	write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
>> +	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
>>   	write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
>> -	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>> -
>> -	read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
>> -
>> -	write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
>> -	write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
>>   
>>   	return 0;
>>   }
>> @@ -1343,16 +1336,12 @@ static int read_id(struct qcom_nand_host *host, int column)
>>   		return 0;
>>   
>>   	nandc_set_reg(chip, NAND_FLASH_CMD, OP_FETCH_ID);
>> -	nandc_set_reg(chip, NAND_ADDR0, column);
>> -	nandc_set_reg(chip, NAND_ADDR1, 0);
>>   	nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT,
>>   		      nandc->props->is_bam ? 0 : DM_EN);
>>   	nandc_set_reg(chip, NAND_EXEC_CMD, 1);
>>   
>> -	write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL);
>> -	write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>> -
>> -	read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
>> +	write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
>> +	write_reg_dma(nandc, NAND_FLASH_CHIP_SELECT, 1, NAND_BAM_NEXT_SGL);
>>   
>>   	return 0;
>>   }
>> @@ -1491,7 +1480,6 @@ static void parse_erase_write_errors(struct qcom_nand_host *host, int command)
>>   
>>   	for (i = 0; i < num_cw; i++) {
>>   		u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]);
>> -
>>   		if (flash_status & FS_MPU_ERR)
>>   			host->status &= ~NAND_STATUS_WP;
>>   
>> @@ -1523,86 +1511,6 @@ static void post_command(struct qcom_nand_host *host, int command)
>>   }
>>   
>>   /*
>> - * Implements chip->legacy.cmdfunc. It's  only used for a limited set of
>> - * commands. The rest of the commands wouldn't be called by upper layers.
>> - * For example, NAND_CMD_READOOB would never be called because we have our own
>> - * versions of read_oob ops for nand_ecc_ctrl.
>> - */
>> -static void qcom_nandc_command(struct nand_chip *chip, unsigned int command,
>> -			       int column, int page_addr)
>> -{
>> -	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>> -	struct nand_ecc_ctrl *ecc = &chip->ecc;
>> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> -	bool wait = false;
>> -	int ret = 0;
>> -
>> -	pre_command(host, command);
>> -
>> -	switch (command) {
>> -	case NAND_CMD_RESET:
>> -		ret = reset(host);
>> -		wait = true;
>> -		break;
>> -
>> -	case NAND_CMD_READID:
>> -		nandc->buf_count = 4;
>> -		ret = read_id(host, column);
>> -		wait = true;
>> -		break;
>> -
>> -	case NAND_CMD_PARAM:
>> -		ret = nandc_param(host);
>> -		wait = true;
>> -		break;
>> -
>> -	case NAND_CMD_ERASE1:
>> -		ret = erase_block(host, page_addr);
>> -		wait = true;
>> -		break;
>> -
>> -	case NAND_CMD_READ0:
>> -		/* we read the entire page for now */
>> -		WARN_ON(column != 0);
>> -
>> -		host->use_ecc = true;
>> -		set_address(host, 0, page_addr);
>> -		update_rw_regs(host, ecc->steps, true, 0);
>> -		break;
>> -
>> -	case NAND_CMD_SEQIN:
>> -		WARN_ON(column != 0);
>> -		set_address(host, 0, page_addr);
>> -		break;
>> -
>> -	case NAND_CMD_PAGEPROG:
>> -	case NAND_CMD_STATUS:
>> -	case NAND_CMD_NONE:
>> -	default:
>> -		break;
>> -	}
>> -
>> -	if (ret) {
>> -		dev_err(nandc->dev, "failure executing command %d\n",
>> -			command);
>> -		free_descs(nandc);
>> -		return;
>> -	}
>> -
>> -	if (wait) {
>> -		ret = submit_descs(nandc);
>> -		if (ret)
>> -			dev_err(nandc->dev,
>> -				"failure submitting descs for command %d\n",
>> -				command);
>> -	}
>> -
>> -	free_descs(nandc);
>> -
>> -	post_command(host, command);
>> -}
>> -
>> -/*
>>    * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read
>>    * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS.
>>    *
>> @@ -2044,7 +1952,6 @@ static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf,
>>   	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>>   	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>>   	u8 *data_buf, *oob_buf = NULL;
>> -
>>   	nand_read_page_op(chip, page, 0, NULL, 0);
>>   	data_buf = buf;
>>   	oob_buf = oob_required ? chip->oob_poi : NULL;
>> @@ -2366,64 +2273,6 @@ static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs)
>>   }
>>   
>>   /*
>> - * the three functions below implement chip->legacy.read_byte(),
>> - * chip->legacy.read_buf() and chip->legacy.write_buf() respectively. these
>> - * aren't used for reading/writing page data, they are used for smaller data
>> - * like reading	id, status etc
>> - */
>> -static uint8_t qcom_nandc_read_byte(struct nand_chip *chip)
>> -{
>> -	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> -	u8 *buf = nandc->data_buffer;
>> -	u8 ret = 0x0;
>> -
>> -	if (host->last_command == NAND_CMD_STATUS) {
>> -		ret = host->status;
>> -
>> -		host->status = NAND_STATUS_READY | NAND_STATUS_WP;
>> -
>> -		return ret;
>> -	}
>> -
>> -	if (nandc->buf_start < nandc->buf_count)
>> -		ret = buf[nandc->buf_start++];
>> -
>> -	return ret;
>> -}
>> -
>> -static void qcom_nandc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
>> -{
>> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> -	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
>> -
>> -	memcpy(buf, nandc->data_buffer + nandc->buf_start, real_len);
>> -	nandc->buf_start += real_len;
>> -}
>> -
>> -static void qcom_nandc_write_buf(struct nand_chip *chip, const uint8_t *buf,
>> -				 int len)
>> -{
>> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> -	int real_len = min_t(size_t, len, nandc->buf_count - nandc->buf_start);
>> -
>> -	memcpy(nandc->data_buffer + nandc->buf_start, buf, real_len);
>> -
>> -	nandc->buf_start += real_len;
>> -}
>> -
>> -/* we support only one external chip for now */
>> -static void qcom_nandc_select_chip(struct nand_chip *chip, int chipnr)
>> -{
>> -	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> -
>> -	if (chipnr <= 0)
>> -		return;
>> -
>> -	dev_warn(nandc->dev, "invalid chip select\n");
>> -}
>> -
>> -/*
>>    * NAND controller page layout info
>>    *
>>    * Layout with ECC enabled:
>> @@ -2738,8 +2587,207 @@ static int qcom_nand_attach_chip(struct nand_chip *chip)
>>   	return 0;
>>   }
>>   
>> +static int nandc_status(struct nand_chip *chip)
>> +{
>> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>> +
>> +	memcpy(nandc->data_buffer, &host->status, 1);
>> +
>> +	return 0;
>> +}
>> +
>> +static int qcom_nand_send_command(struct nand_chip *chip, u8 command)
>> +{
>> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> +	struct nand_ecc_ctrl *ecc = &chip->ecc;
>> +
>> +	int ret = 0;
>> +
>> +	pre_command(host, command);
>> +
>> +	switch (command) {
>> +	case NAND_CMD_RESET:
>> +		ret = reset(host);
>> +		break;
>> +	case NAND_CMD_READID:
>> +		nandc->buf_count = 4;
>> +		ret = read_id(host, 0);
>> +		break;
>> +	case NAND_CMD_PARAM:
>> +		ret = nandc_param(host);
>> +		break;
>> +	case NAND_CMD_ERASE1:
>> +		ret = erase_block(host);
>> +		break;
>> +	case NAND_CMD_STATUS:
>> +		ret = nandc_status(chip);
>> +		break;
>> +	case NAND_CMD_READ0:
>> +		host->use_ecc = true;
>> +		update_rw_regs(host, ecc->steps, true, 0);
>> +		break;
>> +	case NAND_CMD_ERASE2:
>> +		break;
>> +	case NAND_CMD_SEQIN:
>> +		break;
>> +	case NAND_CMD_PAGEPROG:
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static int qcom_nand_send_address(struct nand_chip *chip,
>> +				  const struct nand_op_instr *instr, int cmd)
>> +{
>> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> +	u32 page_addr = 0x0, page_mask = 0x0;
>> +
>> +	page_addr = instr->ctx.addr.addrs[0];
>> +
>> +	/*
>> +	 *Form page address for erase, read, write to using existing api
>> +	 */
>> +
>> +	switch (cmd) {
>> +	case NAND_CMD_ERASE1:
>> +		page_addr = instr->ctx.addr.addrs[0];
>> +		page_mask = instr->ctx.addr.addrs[1];
>> +		page_mask <<= 8;
>> +		page_addr = (page_addr | page_mask);
>> +		page_mask = instr->ctx.addr.addrs[2];
>> +		page_mask <<= 16;
>> +		page_addr = (page_addr | page_mask);
>> +		page_mask = instr->ctx.addr.addrs[3];
>> +		page_mask <<= 24;
>> +		page_addr = (page_addr | page_mask);
>> +		break;
>> +	case NAND_CMD_READ0:
>> +	case NAND_CMD_SEQIN:
>> +		page_addr = instr->ctx.addr.addrs[3];
>> +		page_addr <<= 24;
>> +		page_mask = instr->ctx.addr.addrs[2];
>> +		page_mask <<= 16;
>> +		page_addr |= page_mask;
>> +		page_mask = instr->ctx.addr.addrs[1];
>> +		page_mask <<= 8;
>> +		page_addr |= page_mask;
>> +		page_mask = instr->ctx.addr.addrs[0];
>> +		page_addr |= page_mask;
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	if (cmd == NAND_CMD_PARAM)
>> +		return 0;
>> +
>> +	nandc_set_reg(chip, NAND_ADDR0, page_addr);
>> +	nandc_set_reg(chip, NAND_ADDR1, 0);
>> +
>> +	if (cmd != NAND_CMD_SEQIN)
>> +		write_reg_dma(nandc, NAND_ADDR0, 2, 0);
>> +
>> +	return 0;
>> +}
>> +
>> +static void qcom_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
>> +{
>> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> +
>> +	memcpy(buf, nandc->data_buffer, len);
>> +}
>> +
>> +static int qcom_nand_exec_instr(struct nand_chip *chip,
>> +				const struct nand_op_instr *instr)
>> +{
>> +	struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
>> +	struct qcom_nand_host *host = to_qcom_nand_host(chip);
>> +	u32 status;
>> +	int ret = 0;
>> +	bool wait = false;
>> +	static int opcode;
>> +
>> +	switch (instr->type) {
>> +	case NAND_OP_CMD_INSTR:
>> +		ret = qcom_nand_send_command(chip, instr->ctx.cmd.opcode);
>> +		if (instr->ctx.cmd.opcode == NAND_CMD_RESET)
>> +			wait = true;
>> +		opcode = instr->ctx.cmd.opcode;
>> +		break;
>> +	case NAND_OP_ADDR_INSTR:
>> +		qcom_nand_send_address(chip, instr, opcode);
>> +		if (opcode != NAND_CMD_READ0 && opcode != NAND_CMD_READSTART &&
>> +		    opcode != NAND_CMD_PARAM && opcode != NAND_CMD_SEQIN)
>> +			wait = true;
>> +		break;
>> +	case NAND_OP_DATA_IN_INSTR:
>> +		qcom_nand_read_buf(chip, instr->ctx.data.buf.in, instr->ctx.data.len);
>> +		break;
>> +	case NAND_OP_DATA_OUT_INSTR:
>> +		wait = false;
>> +		break;
>> +	case NAND_OP_WAITRDY_INSTR:
>> +		ret = readl_poll_timeout(nandc->base + NAND_FLASH_STATUS, status,
>> +					 (status & FS_READY_BSY_N), 20,
>> +					 instr->ctx.waitrdy.timeout_ms * 1000);
>> +		if (opcode == NAND_CMD_PARAM)
>> +			wait = true;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	if (wait) {
>> +		if (opcode != NAND_CMD_PARAM)
>> +			write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
>> +
>> +		if (opcode == NAND_CMD_READID)
>> +			read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
>> +
>> +		if (opcode == NAND_CMD_ERASE1) {
>> +			read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
>> +			write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0);
>> +			write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL);
>> +		}
>> +
>> +		ret = submit_descs(nandc);
>> +		if (ret)
>> +			dev_err(nandc->dev, "failure submitting descs for command 0x%02x\n",
>> +				opcode);
>> +
>> +		free_descs(nandc);
>> +		post_command(host, opcode);
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static int qcom_nand_exec_op(struct nand_chip *chip,
>> +			     const struct nand_operation *op,
>> +				bool check_only)
>> +{
>> +	unsigned int i;
>> +	int ret = 0;
>> +
>> +	if (check_only)
>> +		return 0;
>> +
>> +	for (i = 0; i < op->ninstrs; i++) {
>> +		ret = qcom_nand_exec_instr(chip, &op->instrs[i]);
>> +		if (ret)
>> +			break;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>>   static const struct nand_controller_ops qcom_nandc_ops = {
>>   	.attach_chip = qcom_nand_attach_chip,
>> +	.exec_op = qcom_nand_exec_op,
>>   };
>>   
>>   static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
>> @@ -2938,14 +2986,6 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc,
>>   	mtd->owner = THIS_MODULE;
>>   	mtd->dev.parent = dev;
>>   
>> -	chip->legacy.cmdfunc	= qcom_nandc_command;
>> -	chip->legacy.select_chip	= qcom_nandc_select_chip;
>> -	chip->legacy.read_byte	= qcom_nandc_read_byte;
>> -	chip->legacy.read_buf	= qcom_nandc_read_buf;
>> -	chip->legacy.write_buf	= qcom_nandc_write_buf;
>> -	chip->legacy.set_features	= nand_get_set_features_notsupp;
>> -	chip->legacy.get_features	= nand_get_set_features_notsupp;
>> -
>>   	/*
>>   	 * the bad block marker is readable only when we read the last codeword
>>   	 * of a page with ECC disabled. currently, the nand_base and nand_bbt
>> -- 
>> 2.7.4
>>

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

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2023-04-19  9:43 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-03 16:24 [PATCH] mtd: rawnand: qcom: Implement exec_op() Md Sadre Alam
2022-06-03 16:24 ` Md Sadre Alam
2022-06-03 16:57 ` Miquel Raynal
2022-06-03 16:57   ` Miquel Raynal
2022-06-06  4:48   ` Md Sadre Alam
2022-06-06  4:48     ` Md Sadre Alam
2022-06-05 23:45 ` kernel test robot
2022-06-05 23:45   ` kernel test robot
2022-09-15 13:43 ` Manivannan Sadhasivam
2022-09-15 13:43   ` Manivannan Sadhasivam
2022-09-20 10:19   ` Sricharan Ramabadhran
2022-09-20 10:19     ` Sricharan Ramabadhran
2023-04-19  9:41   ` Md Sadre Alam
2023-04-19  9:41     ` Md Sadre Alam

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.