diff options
author | Qipan Li <Qipan.Li@csr.com> | 2014-05-04 02:32:36 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2014-05-20 18:24:20 -0400 |
commit | 41148c3a728222a885bc2f3ba3ce66831de0b244 (patch) | |
tree | e98c1efb42481caa47f2c256b73aef131812e079 /drivers/spi | |
parent | c908ef345d2c314ec25cfac113a8f9bb2b6b3a25 (diff) |
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: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-sirf.c | 101 |
1 files changed, 54 insertions, 47 deletions
diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 2d238990115c..95ac276eaafe 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c | |||
@@ -86,6 +86,7 @@ | |||
86 | #define SIRFSOC_SPI_TX_DONE BIT(1) | 86 | #define SIRFSOC_SPI_TX_DONE BIT(1) |
87 | #define SIRFSOC_SPI_RX_OFLOW BIT(2) | 87 | #define SIRFSOC_SPI_RX_OFLOW BIT(2) |
88 | #define SIRFSOC_SPI_TX_UFLOW BIT(3) | 88 | #define SIRFSOC_SPI_TX_UFLOW BIT(3) |
89 | #define SIRFSOC_SPI_RX_IO_DMA BIT(4) | ||
89 | #define SIRFSOC_SPI_RX_FIFO_FULL BIT(6) | 90 | #define SIRFSOC_SPI_RX_FIFO_FULL BIT(6) |
90 | #define SIRFSOC_SPI_TXFIFO_EMPTY BIT(7) | 91 | #define SIRFSOC_SPI_TXFIFO_EMPTY BIT(7) |
91 | #define SIRFSOC_SPI_RXFIFO_THD_REACH BIT(8) | 92 | #define SIRFSOC_SPI_RXFIFO_THD_REACH BIT(8) |
@@ -265,41 +266,34 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id) | |||
265 | { | 266 | { |
266 | struct sirfsoc_spi *sspi = dev_id; | 267 | struct sirfsoc_spi *sspi = dev_id; |
267 | u32 spi_stat = readl(sspi->base + SIRFSOC_SPI_INT_STATUS); | 268 | u32 spi_stat = readl(sspi->base + SIRFSOC_SPI_INT_STATUS); |
268 | |||
269 | writel(spi_stat, sspi->base + SIRFSOC_SPI_INT_STATUS); | ||
270 | |||
271 | if (sspi->tx_by_cmd && (spi_stat & SIRFSOC_SPI_FRM_END)) { | 269 | if (sspi->tx_by_cmd && (spi_stat & SIRFSOC_SPI_FRM_END)) { |
272 | complete(&sspi->tx_done); | 270 | complete(&sspi->tx_done); |
273 | writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN); | 271 | writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN); |
272 | writel(SIRFSOC_SPI_INT_MASK_ALL, | ||
273 | sspi->base + SIRFSOC_SPI_INT_STATUS); | ||
274 | return IRQ_HANDLED; | 274 | return IRQ_HANDLED; |
275 | } | 275 | } |
276 | 276 | ||
277 | /* Error Conditions */ | 277 | /* Error Conditions */ |
278 | if (spi_stat & SIRFSOC_SPI_RX_OFLOW || | 278 | if (spi_stat & SIRFSOC_SPI_RX_OFLOW || |
279 | spi_stat & SIRFSOC_SPI_TX_UFLOW) { | 279 | spi_stat & SIRFSOC_SPI_TX_UFLOW) { |
280 | complete(&sspi->tx_done); | ||
280 | complete(&sspi->rx_done); | 281 | complete(&sspi->rx_done); |
281 | writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN); | 282 | writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN); |
283 | writel(SIRFSOC_SPI_INT_MASK_ALL, | ||
284 | sspi->base + SIRFSOC_SPI_INT_STATUS); | ||
285 | return IRQ_HANDLED; | ||
282 | } | 286 | } |
287 | if (spi_stat & SIRFSOC_SPI_TXFIFO_EMPTY) | ||
288 | complete(&sspi->tx_done); | ||
289 | while (!(readl(sspi->base + SIRFSOC_SPI_INT_STATUS) & | ||
290 | SIRFSOC_SPI_RX_IO_DMA)) | ||
291 | cpu_relax(); | ||
292 | complete(&sspi->rx_done); | ||
293 | writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN); | ||
294 | writel(SIRFSOC_SPI_INT_MASK_ALL, | ||
295 | sspi->base + SIRFSOC_SPI_INT_STATUS); | ||
283 | 296 | ||
284 | if (spi_stat & (SIRFSOC_SPI_FRM_END | ||
285 | | SIRFSOC_SPI_RXFIFO_THD_REACH)) | ||
286 | while (!((readl(sspi->base + SIRFSOC_SPI_RXFIFO_STATUS) | ||
287 | & SIRFSOC_SPI_FIFO_EMPTY)) && | ||
288 | sspi->left_rx_word) | ||
289 | sspi->rx_word(sspi); | ||
290 | |||
291 | if (spi_stat & (SIRFSOC_SPI_TXFIFO_EMPTY | | ||
292 | SIRFSOC_SPI_TXFIFO_THD_REACH)) | ||
293 | while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS) | ||
294 | & SIRFSOC_SPI_FIFO_FULL)) && | ||
295 | sspi->left_tx_word) | ||
296 | sspi->tx_word(sspi); | ||
297 | |||
298 | /* Received all words */ | ||
299 | if ((sspi->left_rx_word == 0) && (sspi->left_tx_word == 0)) { | ||
300 | complete(&sspi->rx_done); | ||
301 | writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN); | ||
302 | } | ||
303 | return IRQ_HANDLED; | 297 | return IRQ_HANDLED; |
304 | } | 298 | } |
305 | 299 | ||
@@ -420,32 +414,45 @@ static void spi_sirfsoc_pio_transfer(struct spi_device *spi, | |||
420 | int timeout = t->len * 10; | 414 | int timeout = t->len * 10; |
421 | 415 | ||
422 | sspi = spi_master_get_devdata(spi->master); | 416 | sspi = spi_master_get_devdata(spi->master); |
423 | writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP); | 417 | do { |
424 | writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP); | 418 | writel(SIRFSOC_SPI_FIFO_RESET, |
425 | writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP); | 419 | sspi->base + SIRFSOC_SPI_RXFIFO_OP); |
426 | writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP); | 420 | writel(SIRFSOC_SPI_FIFO_RESET, |
427 | writel(0, sspi->base + SIRFSOC_SPI_INT_EN); | 421 | sspi->base + SIRFSOC_SPI_TXFIFO_OP); |
428 | writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS); | 422 | writel(SIRFSOC_SPI_FIFO_START, |
429 | writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | SIRFSOC_SPI_MUL_DAT_MODE | | 423 | sspi->base + SIRFSOC_SPI_RXFIFO_OP); |
430 | SIRFSOC_SPI_ENA_AUTO_CLR, sspi->base + SIRFSOC_SPI_CTRL); | 424 | writel(SIRFSOC_SPI_FIFO_START, |
431 | writel(sspi->left_tx_word - 1, | 425 | sspi->base + SIRFSOC_SPI_TXFIFO_OP); |
432 | sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN); | 426 | writel(0, sspi->base + SIRFSOC_SPI_INT_EN); |
433 | writel(sspi->left_rx_word - 1, | 427 | writel(SIRFSOC_SPI_INT_MASK_ALL, |
434 | sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN); | 428 | sspi->base + SIRFSOC_SPI_INT_STATUS); |
435 | sspi->tx_word(sspi); | 429 | writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | |
436 | writel(SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN | SIRFSOC_SPI_TX_UFLOW_INT_EN | | 430 | SIRFSOC_SPI_MUL_DAT_MODE | SIRFSOC_SPI_ENA_AUTO_CLR, |
437 | SIRFSOC_SPI_RX_OFLOW_INT_EN | SIRFSOC_SPI_RXFIFO_THD_INT_EN | | 431 | sspi->base + SIRFSOC_SPI_CTRL); |
438 | SIRFSOC_SPI_TXFIFO_THD_INT_EN | SIRFSOC_SPI_FRM_END_INT_EN| | 432 | writel(min(sspi->left_tx_word, (u32)(256 / sspi->word_width)) |
439 | SIRFSOC_SPI_RXFIFO_FULL_INT_EN, | 433 | - 1, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN); |
440 | sspi->base + SIRFSOC_SPI_INT_EN); | 434 | writel(min(sspi->left_rx_word, (u32)(256 / sspi->word_width)) |
441 | writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN, | 435 | - 1, sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN); |
436 | while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS) | ||
437 | & SIRFSOC_SPI_FIFO_FULL)) && sspi->left_tx_word) | ||
438 | sspi->tx_word(sspi); | ||
439 | writel(SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN | | ||
440 | SIRFSOC_SPI_TX_UFLOW_INT_EN | | ||
441 | SIRFSOC_SPI_RX_OFLOW_INT_EN, | ||
442 | sspi->base + SIRFSOC_SPI_INT_EN); | ||
443 | writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN, | ||
442 | sspi->base + SIRFSOC_SPI_TX_RX_EN); | 444 | sspi->base + SIRFSOC_SPI_TX_RX_EN); |
443 | if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0) | 445 | if (!wait_for_completion_timeout(&sspi->tx_done, timeout) || |
444 | dev_err(&spi->dev, "transfer timeout\n"); | 446 | !wait_for_completion_timeout(&sspi->rx_done, timeout)) { |
445 | writel(0, sspi->base + SIRFSOC_SPI_RXFIFO_OP); | 447 | dev_err(&spi->dev, "transfer timeout\n"); |
446 | writel(0, sspi->base + SIRFSOC_SPI_TXFIFO_OP); | 448 | break; |
447 | writel(0, sspi->base + SIRFSOC_SPI_TX_RX_EN); | 449 | } |
448 | writel(0, sspi->base + SIRFSOC_SPI_INT_EN); | 450 | while (!((readl(sspi->base + SIRFSOC_SPI_RXFIFO_STATUS) |
451 | & SIRFSOC_SPI_FIFO_EMPTY)) && sspi->left_rx_word) | ||
452 | sspi->rx_word(sspi); | ||
453 | writel(0, sspi->base + SIRFSOC_SPI_RXFIFO_OP); | ||
454 | writel(0, sspi->base + SIRFSOC_SPI_TXFIFO_OP); | ||
455 | } while (sspi->left_tx_word != 0 || sspi->left_rx_word != 0); | ||
449 | } | 456 | } |
450 | 457 | ||
451 | static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) | 458 | static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) |