spi: spi-mem: allow specifying a command's extension

In xSPI mode, flashes expect 2-byte opcodes. The second byte is called
the "command extension". There can be 3 types of extensions in xSPI:
repeat, invert, and hex. When the extension type is "repeat", the same
opcode is sent twice. When it is "invert", the second byte is the
inverse of the opcode. When it is "hex" an additional opcode byte based
is sent with the command whose value can be anything.

So, make opcode a 16-bit value and add a 'nbytes', similar to how
multiple address widths are handled.

All usages of sizeof(op->cmd.opcode) also need to be changed to be
op->cmd.nbytes because that is the actual indicator of opcode size.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
Reviewed-by: Jagan Teki <jagan@amarulasolutions.com>
This commit is contained in:
Pratyush Yadav 2021-06-26 00:47:04 +05:30 committed by Jagan Teki
parent a1eb40b70b
commit d15de62301
4 changed files with 15 additions and 11 deletions

View file

@ -64,8 +64,7 @@ static int mtk_snfi_adjust_op_size(struct spi_slave *slave,
* or the output+input data must not exceed the GPRAM size. * or the output+input data must not exceed the GPRAM size.
*/ */
nbytes = sizeof(op->cmd.opcode) + op->addr.nbytes + nbytes = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
op->dummy.nbytes;
if (nbytes + op->data.nbytes <= SNFI_GPRAM_SIZE) if (nbytes + op->data.nbytes <= SNFI_GPRAM_SIZE)
return 0; return 0;

View file

@ -27,7 +27,7 @@ int spi_mem_exec_op(struct spi_slave *slave,
tx_buf = op->data.buf.out; tx_buf = op->data.buf.out;
} }
op_len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; op_len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
op_buf = calloc(1, op_len); op_buf = calloc(1, op_len);
ret = spi_claim_bus(slave); ret = spi_claim_bus(slave);
@ -89,7 +89,7 @@ int spi_mem_adjust_op_size(struct spi_slave *slave,
{ {
unsigned int len; unsigned int len;
len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
if (slave->max_write_size && len > slave->max_write_size) if (slave->max_write_size && len > slave->max_write_size)
return -EINVAL; return -EINVAL;

View file

@ -167,6 +167,9 @@ bool spi_mem_default_supports_op(struct spi_slave *slave,
if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr) if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
return false; return false;
if (op->cmd.nbytes != 1)
return false;
return true; return true;
} }
EXPORT_SYMBOL_GPL(spi_mem_default_supports_op); EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
@ -273,8 +276,7 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
} }
#ifndef __UBOOT__ #ifndef __UBOOT__
tmpbufsize = sizeof(op->cmd.opcode) + op->addr.nbytes + tmpbufsize = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
op->dummy.nbytes;
/* /*
* Allocate a buffer to transmit the CMD, ADDR cycles with kmalloc() so * Allocate a buffer to transmit the CMD, ADDR cycles with kmalloc() so
@ -289,7 +291,7 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
tmpbuf[0] = op->cmd.opcode; tmpbuf[0] = op->cmd.opcode;
xfers[xferpos].tx_buf = tmpbuf; xfers[xferpos].tx_buf = tmpbuf;
xfers[xferpos].len = sizeof(op->cmd.opcode); xfers[xferpos].len = op->cmd.nbytes;
xfers[xferpos].tx_nbits = op->cmd.buswidth; xfers[xferpos].tx_nbits = op->cmd.buswidth;
spi_message_add_tail(&xfers[xferpos], &msg); spi_message_add_tail(&xfers[xferpos], &msg);
xferpos++; xferpos++;
@ -353,7 +355,7 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
tx_buf = op->data.buf.out; tx_buf = op->data.buf.out;
} }
op_len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; op_len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
/* /*
* Avoid using malloc() here so that we can use this code in SPL where * Avoid using malloc() here so that we can use this code in SPL where
@ -442,8 +444,7 @@ int spi_mem_adjust_op_size(struct spi_slave *slave, struct spi_mem_op *op)
if (!ops->mem_ops || !ops->mem_ops->exec_op) { if (!ops->mem_ops || !ops->mem_ops->exec_op) {
unsigned int len; unsigned int len;
len = sizeof(op->cmd.opcode) + op->addr.nbytes + len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
op->dummy.nbytes;
if (slave->max_write_size && len > slave->max_write_size) if (slave->max_write_size && len > slave->max_write_size)
return -EINVAL; return -EINVAL;

View file

@ -17,6 +17,7 @@ struct udevice;
{ \ { \
.buswidth = __buswidth, \ .buswidth = __buswidth, \
.opcode = __opcode, \ .opcode = __opcode, \
.nbytes = 1, \
} }
#define SPI_MEM_OP_ADDR(__nbytes, __val, __buswidth) \ #define SPI_MEM_OP_ADDR(__nbytes, __val, __buswidth) \
@ -69,6 +70,8 @@ enum spi_mem_data_dir {
/** /**
* struct spi_mem_op - describes a SPI memory operation * struct spi_mem_op - describes a SPI memory operation
* @cmd.nbytes: number of opcode bytes (only 1 or 2 are valid). The opcode is
* sent MSB-first.
* @cmd.buswidth: number of IO lines used to transmit the command * @cmd.buswidth: number of IO lines used to transmit the command
* @cmd.opcode: operation opcode * @cmd.opcode: operation opcode
* @cmd.dtr: whether the command opcode should be sent in DTR mode or not * @cmd.dtr: whether the command opcode should be sent in DTR mode or not
@ -92,9 +95,10 @@ enum spi_mem_data_dir {
*/ */
struct spi_mem_op { struct spi_mem_op {
struct { struct {
u8 nbytes;
u8 buswidth; u8 buswidth;
u8 opcode;
u8 dtr : 1; u8 dtr : 1;
u16 opcode;
} cmd; } cmd;
struct { struct {