diff options
| author | Noah.Shen <[email protected]> | 2026-04-06 15:13:28 -0500 |
|---|---|---|
| committer | David Lechner <[email protected]> | 2026-04-28 13:11:19 -0500 |
| commit | 4eac47d4eb661c019b84723628bab2f0c826403f (patch) | |
| tree | 9ea2ca48ee7b0e473d7e71b225462d05f2965107 | |
| parent | 4f9842e4799c6c3c98cc27c723ba223b42d739d8 (diff) | |
spi: mtk_snor: avoid alloc in mtk_snor_cmd_program()
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 <[email protected]>
Reviewed-by: Julien Stephan <[email protected]>
Link: https://patch.msgid.link/[email protected]
Signed-off-by: David Lechner <[email protected]>
| -rw-r--r-- | drivers/spi/mtk_snor.c | 77 |
1 files 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; |
