Message ID | 20220802175755.6530-9-sudip.mukherjee@sifive.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add support for enhanced SPI for Designware SPI controllers | expand |
On Tue, Aug 02, 2022 at 06:57:52PM +0100, Sudip Mukherjee wrote: > In enhanced spi mode we will be writing the address to a single FIFO > location instead of writing to multiple FIFOs in the standard SPI mode. > Save the cmd and address bytes in the buffer accordingly. > > Signed-off-by: Sudip Mukherjee <sudip.mukherjee@sifive.com> > --- > drivers/spi/spi-dw-core.c | 55 ++++++++++++++++++++++++++++++++++----- > 1 file changed, 48 insertions(+), 7 deletions(-) > > diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c > index 8cb30540ad5b..2564a2276572 100644 > --- a/drivers/spi/spi-dw-core.c > +++ b/drivers/spi/spi-dw-core.c > @@ -520,7 +520,8 @@ static bool dw_spi_supports_mem_op(struct spi_mem *mem, > return spi_mem_default_supports_op(mem, op); > } > > -static int dw_spi_init_mem_buf(struct dw_spi *dws, const struct spi_mem_op *op) > +static int dw_spi_init_mem_buf(struct dw_spi *dws, const struct spi_mem_op *op, > + bool enhanced_spi) There is no point in modifying this method. Since clock stretching is available you won't need to collect all the data in a single buffer. So just create a new method dw_spi_init_enh_mem_buf() which would set dws->tx/rx pointers and tx_len/rx_len fields with the spi_mem_op.data.buf.{in,out} and the corresponding lengths. The command and address data shall be written to the Tx FIFO to initiate the SPI MEM transfers, since in accordance with the HW manual the SPI-bus transfers won't start before it is done. -Sergey > { > unsigned int i, j, len; > u8 *out; > @@ -548,17 +549,57 @@ static int dw_spi_init_mem_buf(struct dw_spi *dws, const struct spi_mem_op *op) > */ > for (i = 0; i < op->cmd.nbytes; ++i) > out[i] = DW_SPI_GET_BYTE(op->cmd.opcode, op->cmd.nbytes - i - 1); > - for (j = 0; j < op->addr.nbytes; ++i, ++j) > - out[i] = DW_SPI_GET_BYTE(op->addr.val, op->addr.nbytes - j - 1); > - for (j = 0; j < op->dummy.nbytes; ++i, ++j) > - out[i] = 0x0; > + > + if (enhanced_spi) { > + /* > + * Fill the remaining spaces of dws->reg_io_width bytes > + * size register with zero for cmd. > + */ > + for (; i < dws->reg_io_width; ++i) > + out[i] = 0; > + /* > + * Copy the address bytes in dws->reg_io_width bytes size > + * register and fill remaining spaces with zero. > + */ > + for (j = op->addr.nbytes; j > 0; ++i, --j) > + out[i] = DW_SPI_GET_BYTE(op->addr.val, op->addr.nbytes - j); > + for (j = op->addr.nbytes; j < dws->reg_io_width; ++i, ++j) > + out[i] = 0; > + } else { > + for (j = 0; j < op->addr.nbytes; ++i, ++j) > + out[i] = DW_SPI_GET_BYTE(op->addr.val, op->addr.nbytes - j - 1); > + } > + > + if (!enhanced_spi) { > + /* > + * dummy bytes are not needed in enhanced mode as > + * wait_cycles specified as number of SPI clock cycles > + * between control frames transmit and data reception > + * will be mentioned in enhanced spi mode. > + */ > + for (j = 0; j < op->dummy.nbytes; ++i, ++j) > + out[i] = 0x0; > + } > > if (op->data.dir == SPI_MEM_DATA_OUT) > memcpy(&out[i], op->data.buf.out, op->data.nbytes); > > dws->n_bytes = 1; > dws->tx = out; > - dws->tx_len = len; > + > + if (enhanced_spi) { > + /* > + * In enhanced mode cmd will be one FIFO and address > + * will be one more FIFO. > + */ > + dws->tx_len = 1; > + if (op->addr.nbytes) > + dws->tx_len += 1; > + if (op->data.dir == SPI_MEM_DATA_OUT) > + dws->tx_len += op->data.nbytes; > + } else { > + dws->tx_len = len; > + } > if (op->data.dir == SPI_MEM_DATA_IN) { > dws->rx = op->data.buf.in; > dws->rx_len = op->data.nbytes; > @@ -744,7 +785,7 @@ static int dw_spi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) > * Collect the outbound data into a single buffer to speed the > * transmission up at least on the initial stage. > */ > - ret = dw_spi_init_mem_buf(dws, op); > + ret = dw_spi_init_mem_buf(dws, op, enhanced_spi); > if (ret) > return ret; > > -- > 2.30.2 >
diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index 8cb30540ad5b..2564a2276572 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -520,7 +520,8 @@ static bool dw_spi_supports_mem_op(struct spi_mem *mem, return spi_mem_default_supports_op(mem, op); } -static int dw_spi_init_mem_buf(struct dw_spi *dws, const struct spi_mem_op *op) +static int dw_spi_init_mem_buf(struct dw_spi *dws, const struct spi_mem_op *op, + bool enhanced_spi) { unsigned int i, j, len; u8 *out; @@ -548,17 +549,57 @@ static int dw_spi_init_mem_buf(struct dw_spi *dws, const struct spi_mem_op *op) */ for (i = 0; i < op->cmd.nbytes; ++i) out[i] = DW_SPI_GET_BYTE(op->cmd.opcode, op->cmd.nbytes - i - 1); - for (j = 0; j < op->addr.nbytes; ++i, ++j) - out[i] = DW_SPI_GET_BYTE(op->addr.val, op->addr.nbytes - j - 1); - for (j = 0; j < op->dummy.nbytes; ++i, ++j) - out[i] = 0x0; + + if (enhanced_spi) { + /* + * Fill the remaining spaces of dws->reg_io_width bytes + * size register with zero for cmd. + */ + for (; i < dws->reg_io_width; ++i) + out[i] = 0; + /* + * Copy the address bytes in dws->reg_io_width bytes size + * register and fill remaining spaces with zero. + */ + for (j = op->addr.nbytes; j > 0; ++i, --j) + out[i] = DW_SPI_GET_BYTE(op->addr.val, op->addr.nbytes - j); + for (j = op->addr.nbytes; j < dws->reg_io_width; ++i, ++j) + out[i] = 0; + } else { + for (j = 0; j < op->addr.nbytes; ++i, ++j) + out[i] = DW_SPI_GET_BYTE(op->addr.val, op->addr.nbytes - j - 1); + } + + if (!enhanced_spi) { + /* + * dummy bytes are not needed in enhanced mode as + * wait_cycles specified as number of SPI clock cycles + * between control frames transmit and data reception + * will be mentioned in enhanced spi mode. + */ + for (j = 0; j < op->dummy.nbytes; ++i, ++j) + out[i] = 0x0; + } if (op->data.dir == SPI_MEM_DATA_OUT) memcpy(&out[i], op->data.buf.out, op->data.nbytes); dws->n_bytes = 1; dws->tx = out; - dws->tx_len = len; + + if (enhanced_spi) { + /* + * In enhanced mode cmd will be one FIFO and address + * will be one more FIFO. + */ + dws->tx_len = 1; + if (op->addr.nbytes) + dws->tx_len += 1; + if (op->data.dir == SPI_MEM_DATA_OUT) + dws->tx_len += op->data.nbytes; + } else { + dws->tx_len = len; + } if (op->data.dir == SPI_MEM_DATA_IN) { dws->rx = op->data.buf.in; dws->rx_len = op->data.nbytes; @@ -744,7 +785,7 @@ static int dw_spi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) * Collect the outbound data into a single buffer to speed the * transmission up at least on the initial stage. */ - ret = dw_spi_init_mem_buf(dws, op); + ret = dw_spi_init_mem_buf(dws, op, enhanced_spi); if (ret) return ret;
In enhanced spi mode we will be writing the address to a single FIFO location instead of writing to multiple FIFOs in the standard SPI mode. Save the cmd and address bytes in the buffer accordingly. Signed-off-by: Sudip Mukherjee <sudip.mukherjee@sifive.com> --- drivers/spi/spi-dw-core.c | 55 ++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 7 deletions(-)