[PATCH v3 13/13] mtd: spi-nor: run PHY tuning after init and update dirmap frequency
From: Santhosh Kumar K
Date: Wed May 27 2026 - 13:59:32 EST
Introduce a persistent max_read_op field in struct spi_nor. Populate it
with the correct op layout before creating the read dirmap so
execute_tuning() receives a fully configured op. After both dirmaps are
set up, run spi_mem_execute_tuning() to let the controller validate the
read frequency and write it back into max_read_op.max_freq. Patch the
dirmap's op template with this value so subsequent dirmap reads use
the validated speed.
spi_nor_spimem_get_read_op() is updated to propagate max_read_op.max_freq
into every returned op, so non-dirmap reads via spi_nor_spimem_read_data()
also benefit from the validated frequency automatically.
Signed-off-by: Santhosh Kumar K <s-k6@xxxxxx>
---
drivers/mtd/spi-nor/core.c | 19 +++++++++++++++++++
include/linux/mtd/spi-nor.h | 3 +++
2 files changed, 22 insertions(+)
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 2c9859fb0794..207e0679549e 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -216,6 +216,9 @@ static struct spi_mem_op spi_nor_spimem_get_read_op(struct spi_nor *nor)
if (spi_nor_protocol_is_dtr(nor->read_proto))
op.dummy.nbytes *= 2;
+ /* Propagate the validated frequency; zero before tuning. */
+ op.max_freq = nor->max_read_op.max_freq;
+
return op;
}
@@ -3773,6 +3776,9 @@ static int spi_nor_probe(struct spi_mem *spimem)
return -ENOMEM;
}
+ /* Populate the persistent template with the correct op layout for tuning. */
+ nor->max_read_op = spi_nor_spimem_get_read_op(nor);
+
ret = spi_nor_create_read_dirmap(nor);
if (ret)
return ret;
@@ -3781,6 +3787,19 @@ static int spi_nor_probe(struct spi_mem *spimem)
if (ret)
return ret;
+ /* Tuning failure is non-fatal; the device operates at base speed. */
+ ret = spi_mem_execute_tuning(spimem, &nor->max_read_op, NULL);
+ if (ret && ret != -EOPNOTSUPP)
+ dev_warn(dev, "Failed to execute PHY tuning: %d\n", ret);
+
+ /*
+ * The dirmap was created before tuning ran; update its op template
+ * to use the validated frequency.
+ */
+ if (!ret && nor->dirmap.rdesc)
+ nor->dirmap.rdesc->info.primary_op_tmpl.max_freq =
+ nor->max_read_op.max_freq;
+
return mtd_device_register(&nor->mtd, data ? data->parts : NULL,
data ? data->nr_parts : 0);
}
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index cdcfe0fd2e7d..6a11625f7b2d 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -419,6 +419,9 @@ struct spi_nor {
struct spi_mem_dirmap_desc *wdesc;
} dirmap;
+ /* Persistent op template updated by execute_tuning with validated speed. */
+ struct spi_mem_op max_read_op;
+
void *priv;
};
--
2.34.1