[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