Commit 68a24863 authored by Robert Hancock's avatar Robert Hancock Committed by Anas Nashif
Browse files

drivers: spi_xlnx_axi_quadspi: Optimize FIFO handling



Add an optional DT property to specify the size of the RX/TX FIFO
implemented within the SPI core. The property name used is the same one
used by Xilinx's device tree generator.

When the FIFO is known to exist, we can use the RX FIFO occupancy register
to determine how many words can be read from the RX FIFO without checking
the RX FIFO empty flag after every read. Likewise with the TX FIFO, we can
use the FIFO size to avoid checking the FIFO full flag after every write.
This can increase overall throughput.

Signed-off-by: default avatarRobert Hancock <robert.hancock@calian.com>
parent cff38116
Loading
Loading
Loading
Loading
+32 −13
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ struct xlnx_quadspi_config {
	void (*irq_config_func)(const struct device *dev);
	uint8_t num_ss_bits;
	uint8_t num_xfer_bytes;
	uint16_t fifo_size;
#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(xlnx_startup_block)
	bool startup_block;
#endif
@@ -235,6 +236,7 @@ static void xlnx_quadspi_start_tx(const struct device *dev)
	uint32_t spicr = 0U;
	uint32_t spisr;
	uint32_t dtr = 0U;
	uint32_t fifo_avail_words = config->fifo_size ? config->fifo_size : 1;

	if (!spi_context_tx_on(ctx) && !spi_context_rx_on(ctx)) {
		/* All done, de-assert slave select */
@@ -285,10 +287,20 @@ static void xlnx_quadspi_start_tx(const struct device *dev)
		xlnx_quadspi_write32(dev, dtr, SPI_DTR_OFFSET);
		spi_context_update_tx(ctx, config->num_xfer_bytes, 1);

		if (--fifo_avail_words == 0) {
			spisr = xlnx_quadspi_read32(dev, SPISR_OFFSET);
			if (spisr & SPISR_TX_FULL) {
				break;
			}
			if (!config->fifo_size) {
				fifo_avail_words = 1;
			} else if (spisr & SPISR_TX_EMPTY) {
				fifo_avail_words = config->fifo_size;
			} else {
				fifo_avail_words = config->fifo_size -
					 xlnx_quadspi_read32(dev, SPI_TX_FIFO_OCR_OFFSET) - 1;
			}
		}
	}

	spisr = xlnx_quadspi_read32(dev, SPISR_OFFSET);
@@ -396,19 +408,21 @@ static void xlnx_quadspi_isr(const struct device *dev)
	const struct xlnx_quadspi_config *config = dev->config;
	struct xlnx_quadspi_data *data = dev->data;
	struct spi_context *ctx = &data->ctx;
	uint32_t temp;
	uint32_t drr;
	uint32_t ipisr;

	/* Acknowledge interrupt */
	temp = xlnx_quadspi_read32(dev, IPISR_OFFSET);
	xlnx_quadspi_write32(dev, temp, IPISR_OFFSET);
	ipisr = xlnx_quadspi_read32(dev, IPISR_OFFSET);
	xlnx_quadspi_write32(dev, ipisr, IPISR_OFFSET);

	if (temp & IPIXR_DTR_EMPTY) {
		temp = xlnx_quadspi_read32(dev, SPISR_OFFSET);
	if (ipisr & IPIXR_DTR_EMPTY) {
		uint32_t spisr = xlnx_quadspi_read32(dev, SPISR_OFFSET);
		/* RX FIFO occupancy register only exists if FIFO is implemented */
		uint32_t rx_fifo_words = config->fifo_size ?
			xlnx_quadspi_read32(dev, SPI_RX_FIFO_OCR_OFFSET) + 1 : 1;

		/* Read RX data */
		while (!(temp & SPISR_RX_EMPTY)) {
			drr = xlnx_quadspi_read32(dev, SPI_DRR_OFFSET);
		while (!(spisr & SPISR_RX_EMPTY)) {
			uint32_t drr = xlnx_quadspi_read32(dev, SPI_DRR_OFFSET);

			if (spi_context_rx_buf_on(ctx)) {
				switch (config->num_xfer_bytes) {
@@ -432,13 +446,17 @@ static void xlnx_quadspi_isr(const struct device *dev)

			spi_context_update_rx(ctx, config->num_xfer_bytes, 1);

			temp = xlnx_quadspi_read32(dev, SPISR_OFFSET);
			if (--rx_fifo_words == 0) {
				spisr = xlnx_quadspi_read32(dev, SPISR_OFFSET);
				rx_fifo_words = config->fifo_size ?
					xlnx_quadspi_read32(dev, SPI_RX_FIFO_OCR_OFFSET) + 1 : 1;
			}
		}

		/* Start next TX */
		xlnx_quadspi_start_tx(dev);
	} else {
		LOG_WRN("unhandled interrupt, ipisr = 0x%08x", temp);
		LOG_WRN("unhandled interrupt, ipisr = 0x%08x", ipisr);
	}
}

@@ -546,6 +564,7 @@ static const struct spi_driver_api xlnx_quadspi_driver_api = {
		.num_ss_bits = DT_INST_PROP(n, xlnx_num_ss_bits),	\
		.num_xfer_bytes =					\
			DT_INST_PROP(n, xlnx_num_transfer_bits) / 8,	\
		.fifo_size = DT_INST_PROP_OR(n, fifo_size, 0),		\
		STARTUP_BLOCK_INIT(n)					\
	};								\
									\
+8 −0
Original line number Diff line number Diff line
@@ -49,3 +49,11 @@ properties:
      transaction to the SPI flash device to ensure the STARTUP block is
      disengaged and allow the SPI core to control the CCLK line properly.
      The dummy READ_ID transaction will be issued to chip select 0.

  fifo-size:
    type: int
    description: |
      FIFO size configured in SPI core. 0 indicates no FIFO.
      If not specified, 0 is assumed.
      Used to optimize TX/RX read handling. If the FIFO size is 0, the driver
      will check for FIFO full/empty after every word.