[PATCH 2/8] spi: mtk_snor: avoid alloc in mtk_snor_cmd_program()

David Lechner dlechner at baylibre.com
Mon Apr 6 22:13:28 CEST 2026


From: "Noah.Shen" <noah.shen at mediatek.com>

Rework mtk_snor_cmd_program() to avoid allocating a temporary buffer
for tx data. This improves performance a bit by avoiding the need to
allocate memory and copy data an extra time.

Signed-off-by: Noah.Shen <noah.shen at mediatek.com>
Signed-off-by: David Lechner <dlechner at baylibre.com>
---
 drivers/spi/mtk_snor.c | 77 +++++++++++++++++++++++++++++---------------------
 1 file changed, 45 insertions(+), 32 deletions(-)

diff --git a/drivers/spi/mtk_snor.c b/drivers/spi/mtk_snor.c
index eb36c9dd5e8..0ff4a8b23d5 100644
--- a/drivers/spi/mtk_snor.c
+++ b/drivers/spi/mtk_snor.c
@@ -383,50 +383,63 @@ static int mtk_snor_pp_unbuffered(struct mtk_snor_priv *priv,
 static int mtk_snor_cmd_program(struct mtk_snor_priv *priv,
 				const struct spi_mem_op *op)
 {
-	u32 tx_len = 0;
-	u32 trx_len = 0;
+	int rx_len = 0;
 	int reg_offset = MTK_NOR_REG_PRGDATA_MAX;
+	int tx_len, prg_len;
+	int i;
 	void __iomem *reg;
-	u8 *txbuf;
-	int tx_cnt = 0;
-	u8 *rxbuf = op->data.buf.in;
-	int i = 0;
+	u8 val;
 
-	tx_len = 1 + op->addr.nbytes + op->dummy.nbytes;
-	trx_len = tx_len + op->data.nbytes;
-	if (op->data.dir == SPI_MEM_DATA_OUT)
-		tx_len += op->data.nbytes;
-
-	txbuf = kmalloc_array(tx_len, sizeof(u8), GFP_KERNEL);
-	memset(txbuf, 0x0, tx_len * sizeof(u8));
-
-	/* Join all bytes to be transferred */
-	txbuf[tx_cnt] = op->cmd.opcode;
-	tx_cnt++;
-	for (i = op->addr.nbytes; i > 0; i--, tx_cnt++)
-		txbuf[tx_cnt] = ((u8 *)&op->addr.val)[i - 1];
-	for (i = op->dummy.nbytes; i > 0; i--, tx_cnt++)
-		txbuf[tx_cnt] = 0x0;
+	tx_len = op->cmd.nbytes + op->addr.nbytes;
+
+	/* count dummy bytes only if we need to write data after it */
 	if (op->data.dir == SPI_MEM_DATA_OUT)
-		for (i = op->data.nbytes; i > 0; i--, tx_cnt++)
-			txbuf[tx_cnt] = ((u8 *)op->data.buf.out)[i - 1];
+		tx_len += op->dummy.nbytes + op->data.nbytes;
+	else if (op->data.dir == SPI_MEM_DATA_IN)
+		rx_len = op->data.nbytes;
 
-	for (i = MTK_NOR_REG_PRGDATA_MAX; i >= 0; i--)
-		writeb(0, priv->base + MTK_NOR_REG_PRGDATA(i));
+	prg_len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes +
+		  op->data.nbytes;
 
-	for (i = 0; i < tx_len; i++, reg_offset--)
-		writeb(txbuf[i], priv->base + MTK_NOR_REG_PRGDATA(reg_offset));
+	/* fill tx data */
 
-	kfree(txbuf);
+	for (i = op->cmd.nbytes; i > 0; i--, reg_offset--) {
+		reg = priv->base + MTK_NOR_REG_PRGDATA(reg_offset);
+		val = (op->cmd.opcode >> ((i - 1) * BITS_PER_BYTE)) & 0xff;
+		writeb(val, reg);
+	}
 
-	writel(trx_len * BITS_PER_BYTE, priv->base + MTK_NOR_REG_PRG_CNT);
+	for (i = op->addr.nbytes; i > 0; i--, reg_offset--) {
+		reg = priv->base + MTK_NOR_REG_PRGDATA(reg_offset);
+		val = (op->addr.val >> ((i - 1) * BITS_PER_BYTE)) & 0xff;
+		writeb(val, reg);
+	}
 
-	mtk_snor_cmd_exec(priv, MTK_NOR_CMD_PROGRAM, trx_len * BITS_PER_BYTE);
+	for (i = 0; i < op->dummy.nbytes; i++, reg_offset--) {
+		reg = priv->base + MTK_NOR_REG_PRGDATA(reg_offset);
+		writeb(0, reg);
+	}
 
-	reg_offset = op->data.nbytes - 1;
 	for (i = 0; i < op->data.nbytes; i++, reg_offset--) {
+		reg = priv->base + MTK_NOR_REG_PRGDATA(reg_offset);
+		writeb(((const u8 *)(op->data.buf.out))[i], reg);
+	}
+
+	for (; reg_offset >= 0; reg_offset--) {
+		reg = priv->base + MTK_NOR_REG_PRGDATA(reg_offset);
+		writeb(0, reg);
+	}
+
+	/* trigger op */
+	writel(prg_len * BITS_PER_BYTE, priv->base + MTK_NOR_REG_PRG_CNT);
+
+	mtk_snor_cmd_exec(priv, MTK_NOR_CMD_PROGRAM, prg_len * BITS_PER_BYTE);
+
+	/* fetch read data */
+	reg_offset = 0;
+	for (i = op->data.nbytes - 1; i >= 0; i--, reg_offset++) {
 		reg = priv->base + MTK_NOR_REG_SHIFT(reg_offset);
-		rxbuf[i] = readb(reg);
+		((u8 *)(op->data.buf.in))[i] = readb(reg);
 	}
 
 	return 0;

-- 
2.43.0



More information about the U-Boot mailing list