Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 41148c3a authored by Qipan Li's avatar Qipan Li Committed by Mark Brown
Browse files

spi: sirf: decrease the interrupt count and latency of PIO mode



current PIO tranfer method be described as follows:
1. fill as much as bytes but no more than 256 bytes(fifo size)
2. enable oflow/uflow/txfifo_empty interrupt
3. isr process 3 interrupt signal, do complete works.
4. after isr done, if there are left bytes go into 1 else go into 5
5. transfer end

by current PIO transfer method:
1. reduce interrupt counts in spi interrupt line.
2. reduce interrupt latency because no do data fill/fetch in isr.

Signed-off-by: default avatarQipan Li <Qipan.Li@csr.com>
Signed-off-by: default avatarBarry Song <Baohua.Song@csr.com>
Signed-off-by: default avatarMark Brown <broonie@linaro.org>
parent c908ef34
Loading
Loading
Loading
Loading
+54 −47
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@
#define SIRFSOC_SPI_TX_DONE		BIT(1)
#define SIRFSOC_SPI_RX_OFLOW		BIT(2)
#define SIRFSOC_SPI_TX_UFLOW		BIT(3)
#define SIRFSOC_SPI_RX_IO_DMA		BIT(4)
#define SIRFSOC_SPI_RX_FIFO_FULL	BIT(6)
#define SIRFSOC_SPI_TXFIFO_EMPTY	BIT(7)
#define SIRFSOC_SPI_RXFIFO_THD_REACH	BIT(8)
@@ -265,41 +266,34 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
{
	struct sirfsoc_spi *sspi = dev_id;
	u32 spi_stat = readl(sspi->base + SIRFSOC_SPI_INT_STATUS);

	writel(spi_stat, sspi->base + SIRFSOC_SPI_INT_STATUS);

	if (sspi->tx_by_cmd && (spi_stat & SIRFSOC_SPI_FRM_END)) {
		complete(&sspi->tx_done);
		writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
		writel(SIRFSOC_SPI_INT_MASK_ALL,
				sspi->base + SIRFSOC_SPI_INT_STATUS);
		return IRQ_HANDLED;
	}

	/* Error Conditions */
	if (spi_stat & SIRFSOC_SPI_RX_OFLOW ||
			spi_stat & SIRFSOC_SPI_TX_UFLOW) {
		complete(&sspi->tx_done);
		complete(&sspi->rx_done);
		writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
		writel(SIRFSOC_SPI_INT_MASK_ALL,
				sspi->base + SIRFSOC_SPI_INT_STATUS);
		return IRQ_HANDLED;
	}

	if (spi_stat & (SIRFSOC_SPI_FRM_END
			| SIRFSOC_SPI_RXFIFO_THD_REACH))
		while (!((readl(sspi->base + SIRFSOC_SPI_RXFIFO_STATUS)
				& SIRFSOC_SPI_FIFO_EMPTY)) &&
				sspi->left_rx_word)
			sspi->rx_word(sspi);

	if (spi_stat & (SIRFSOC_SPI_TXFIFO_EMPTY |
			SIRFSOC_SPI_TXFIFO_THD_REACH))
		while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS)
				& SIRFSOC_SPI_FIFO_FULL)) &&
				sspi->left_tx_word)
			sspi->tx_word(sspi);

	/* Received all words */
	if ((sspi->left_rx_word == 0) && (sspi->left_tx_word == 0)) {
	if (spi_stat & SIRFSOC_SPI_TXFIFO_EMPTY)
		complete(&sspi->tx_done);
	while (!(readl(sspi->base + SIRFSOC_SPI_INT_STATUS) &
		SIRFSOC_SPI_RX_IO_DMA))
		cpu_relax();
	complete(&sspi->rx_done);
	writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
	}
	writel(SIRFSOC_SPI_INT_MASK_ALL,
			sspi->base + SIRFSOC_SPI_INT_STATUS);

	return IRQ_HANDLED;
}

@@ -420,32 +414,45 @@ static void spi_sirfsoc_pio_transfer(struct spi_device *spi,
	int timeout = t->len * 10;

	sspi = spi_master_get_devdata(spi->master);
	writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
	writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
	writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
	writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
	do {
		writel(SIRFSOC_SPI_FIFO_RESET,
			sspi->base + SIRFSOC_SPI_RXFIFO_OP);
		writel(SIRFSOC_SPI_FIFO_RESET,
			sspi->base + SIRFSOC_SPI_TXFIFO_OP);
		writel(SIRFSOC_SPI_FIFO_START,
			sspi->base + SIRFSOC_SPI_RXFIFO_OP);
		writel(SIRFSOC_SPI_FIFO_START,
			sspi->base + SIRFSOC_SPI_TXFIFO_OP);
		writel(0, sspi->base + SIRFSOC_SPI_INT_EN);
	writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS);
	writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | SIRFSOC_SPI_MUL_DAT_MODE |
		SIRFSOC_SPI_ENA_AUTO_CLR, sspi->base + SIRFSOC_SPI_CTRL);
	writel(sspi->left_tx_word - 1,
			sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN);
	writel(sspi->left_rx_word - 1,
			sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN);
		writel(SIRFSOC_SPI_INT_MASK_ALL,
			sspi->base + SIRFSOC_SPI_INT_STATUS);
		writel(readl(sspi->base + SIRFSOC_SPI_CTRL) |
			SIRFSOC_SPI_MUL_DAT_MODE | SIRFSOC_SPI_ENA_AUTO_CLR,
			sspi->base + SIRFSOC_SPI_CTRL);
		writel(min(sspi->left_tx_word, (u32)(256 / sspi->word_width))
				- 1, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN);
		writel(min(sspi->left_rx_word, (u32)(256 / sspi->word_width))
				- 1, sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN);
		while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS)
			& SIRFSOC_SPI_FIFO_FULL)) && sspi->left_tx_word)
			sspi->tx_word(sspi);
	writel(SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN | SIRFSOC_SPI_TX_UFLOW_INT_EN |
		SIRFSOC_SPI_RX_OFLOW_INT_EN | SIRFSOC_SPI_RXFIFO_THD_INT_EN |
		SIRFSOC_SPI_TXFIFO_THD_INT_EN | SIRFSOC_SPI_FRM_END_INT_EN|
		SIRFSOC_SPI_RXFIFO_FULL_INT_EN,
		writel(SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN |
			SIRFSOC_SPI_TX_UFLOW_INT_EN |
			SIRFSOC_SPI_RX_OFLOW_INT_EN,
			sspi->base + SIRFSOC_SPI_INT_EN);
		writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN,
			sspi->base + SIRFSOC_SPI_TX_RX_EN);
	if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0)
		if (!wait_for_completion_timeout(&sspi->tx_done, timeout) ||
			!wait_for_completion_timeout(&sspi->rx_done, timeout)) {
			dev_err(&spi->dev, "transfer timeout\n");
			break;
		}
		while (!((readl(sspi->base + SIRFSOC_SPI_RXFIFO_STATUS)
			& SIRFSOC_SPI_FIFO_EMPTY)) && sspi->left_rx_word)
			sspi->rx_word(sspi);
		writel(0, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
		writel(0, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
	writel(0, sspi->base + SIRFSOC_SPI_TX_RX_EN);
	writel(0, sspi->base + SIRFSOC_SPI_INT_EN);
	} while (sspi->left_tx_word != 0 || sspi->left_rx_word != 0);
}

static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t)