Hi Md, quic_mdalam@xxxxxxxxxxx wrote on Thu, 11 May 2023 19:00:14 +0530: > This change will add exec_ops support for RESET , READ_ID, STATUS > command. > > Co-developed-by: Sricharan Ramabadhran <quic_srichara@xxxxxxxxxxx> > Signed-off-by: Sricharan Ramabadhran <quic_srichara@xxxxxxxxxxx> > Signed-off-by: Md Sadre Alam <quic_mdalam@xxxxxxxxxxx> > --- > Change in [v2] > > * Missed to post Cover-letter, so posting v2 patch with cover-letter > > drivers/mtd/nand/raw/qcom_nandc.c | 166 +++++++++++++++++++++++++++++- > 1 file changed, 163 insertions(+), 3 deletions(-) > > diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c > index dae460e2aa0b..d2f2a8971907 100644 > --- a/drivers/mtd/nand/raw/qcom_nandc.c > +++ b/drivers/mtd/nand/raw/qcom_nandc.c > @@ -384,6 +384,9 @@ struct nandc_regs { > * @reg_read_pos: marker for data read in reg_read_buf > * > * @cmd1/vld: some fixed controller register values > + * > + * @exec_opwrite: flag to select correct number of code word > + * while reading status > */ > struct qcom_nand_controller { > struct device *dev; > @@ -434,6 +437,7 @@ struct qcom_nand_controller { > int reg_read_pos; > > u32 cmd1, vld; > + bool exec_opwrite; > }; > > /* > @@ -2920,6 +2924,8 @@ static int qcom_op_cmd_mapping(struct qcom_nand_controller *nandc, u8 cmd, > break; > case NAND_CMD_PAGEPROG: > ret = OP_PROGRAM_PAGE; > + q_op->flag = NAND_CMD_PAGEPROG; Just use the instruction value? > + nandc->exec_opwrite = true; > break; > default: > break; > @@ -2982,10 +2988,95 @@ static void qcom_parse_instructions(struct nand_chip *chip, > } > } > > +static void qcom_delay_ns(unsigned int ns) > +{ > + if (!ns) > + return; > + > + if (ns < 10000) > + ndelay(ns); > + else > + udelay(DIV_ROUND_UP(ns, 1000)); > +} > + > +static int qcom_wait_rdy_poll(struct nand_chip *chip, unsigned int time_ms) > +{ > + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); > + unsigned long start = jiffies + msecs_to_jiffies(time_ms); > + u32 flash; > + > + nandc_read_buffer_sync(nandc, true); > + > + do { > + flash = le32_to_cpu(nandc->reg_read_buf[0]); > + if (flash & FS_READY_BSY_N) > + return 0; > + cpu_relax(); > + } while (time_after(start, jiffies)); > + > + dev_err(nandc->dev, "Timeout waiting for device to be ready:0x%08x\n", flash); > + > + return -ETIMEDOUT; > +} > + > static int qcom_read_status_exec(struct nand_chip *chip, > const struct nand_subop *subop) > { > - return 0; > + 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; > + struct qcom_op q_op; > + const struct nand_op_instr *instr = NULL; > + unsigned int op_id = 0; > + unsigned int len = 0; > + int ret = 0, num_cw = 1, i; > + u32 flash_status; > + > + host->status = NAND_STATUS_READY | NAND_STATUS_WP; > + > + qcom_parse_instructions(chip, subop, &q_op); > + > + if (nandc->exec_opwrite) { I definitely don't understand this flag at all. > + num_cw = ecc->steps; > + nandc->exec_opwrite = false; > + } > + > + pre_command(host, NAND_CMD_STATUS); > + > + nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg); > + nandc_set_reg(chip, NAND_EXEC_CMD, 1); > + > + write_reg_dma(nandc, NAND_FLASH_CMD, 1, 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); > + > + ret = submit_descs(nandc); > + if (ret) > + dev_err(nandc->dev, "failure in sbumitting status descriptor\n"); > + > + free_descs(nandc); > + > + nandc_read_buffer_sync(nandc, true); > + for (i = 0; i < num_cw; i++) { > + flash_status = le32_to_cpu(nandc->reg_read_buf[i]); > + > + if (flash_status & FS_MPU_ERR) > + host->status &= ~NAND_STATUS_WP; > + > + if (flash_status & FS_OP_ERR || (i == (num_cw - 1) && > + (flash_status & FS_DEVICE_STS_ERR))) > + host->status |= NAND_STATUS_FAIL; If there is a failure detected, error out (everywhere). > + } > + > + flash_status = host->status; > + > + instr = q_op.data_instr; > + op_id = q_op.data_instr_idx; > + len = nand_subop_get_data_len(subop, op_id); > + memcpy(instr->ctx.data.buf.in, &flash_status, len); > + > + return ret; > } > > static int qcom_erase_cmd_type_exec(struct nand_chip *chip, const struct nand_subop *subop) > @@ -3000,12 +3091,81 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_ > > static int qcom_read_id_type_exec(struct nand_chip *chip, const struct nand_subop *subop) > { > - return 0; > + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); > + struct qcom_nand_host *host = to_qcom_nand_host(chip); > + struct qcom_op q_op; > + const struct nand_op_instr *instr = NULL; > + unsigned int op_id = 0; > + unsigned int len = 0; > + int ret = 0; > + > + qcom_parse_instructions(chip, subop, &q_op); > + > + pre_command(host, NAND_CMD_READID); > + > + nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg); > + nandc_set_reg(chip, NAND_ADDR0, q_op.addr1_reg); > + nandc_set_reg(chip, NAND_ADDR1, q_op.addr2_reg); > + 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); > + > + ret = submit_descs(nandc); > + if (ret) > + dev_err(nandc->dev, "failure in sbumitting read id descriptor\n"); > + > + free_descs(nandc); > + > + instr = q_op.data_instr; > + op_id = q_op.data_instr_idx; > + len = nand_subop_get_data_len(subop, op_id); > + > + nandc_read_buffer_sync(nandc, true); > + memcpy(instr->ctx.data.buf.in, nandc->reg_read_buf, len); > + > + return ret; > } > > static int qcom_misc_cmd_type_exec(struct nand_chip *chip, const struct nand_subop *subop) > { > - return 0; > + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); > + struct qcom_nand_host *host = to_qcom_nand_host(chip); > + struct qcom_op q_op; > + int ret = 0; > + > + qcom_parse_instructions(chip, subop, &q_op); > + > + if (q_op.flag == NAND_CMD_PAGEPROG) > + goto wait_rdy; > + > + pre_command(host, NAND_CMD_RESET); ??? > + > + nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg); > + nandc_set_reg(chip, NAND_EXEC_CMD, 1); > + > + write_reg_dma(nandc, NAND_FLASH_CMD, 1, 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); > + > + ret = submit_descs(nandc); > + if (ret) > + dev_err(nandc->dev, "failure in sbumitting misc descriptor\n"); Typo ^ Same above. You should error out immediately when something wrong happens. > + > + free_descs(nandc); > + > +wait_rdy: > + qcom_delay_ns(q_op.rdy_delay_ns); > + > + ret = qcom_wait_rdy_poll(chip, q_op.rdy_timeout_ms); > + > + return ret; > } > > static int qcom_data_read_type_exec(struct nand_chip *chip, const struct nand_subop *subop) Thanks, Miquèl