Commit 4743a0f88c4000dfa3c422ecc4d750d3a3410550

Authored by Roman Tereshonkov
Committed by Grant Likely
1 parent 8b66c13474

spi/omap2_mcspi: add turbo mode support

Turbo mode allows to read data to shift register when rx-buffer
is full thus improving the perfomance. This feature is available
for RX-only mode.

In PIO turbo mode when the penultimate word is available
in RX-buffer the controller should be disabled before reading data
to prevent the next transaction triggering. The controller itself
handles the last word to be correctly loaded to shift-register and
then transferred to RX-buffer.

The turbo mode is enabled by setting turbo_mode parameter to 1.
This parameter is a part of omap2_mcspi_device_config structure
which is passed through the spi_device controller_data pointer.

Signed-off-by: Roman Tereshonkov <roman.tereshonkov@nokia.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>

Showing 1 changed file with 111 additions and 21 deletions Side-by-side Diff

drivers/spi/omap2_mcspi.c
... ... @@ -38,8 +38,8 @@
38 38  
39 39 #include <plat/dma.h>
40 40 #include <plat/clock.h>
  41 +#include <plat/mcspi.h>
41 42  
42   -
43 43 #define OMAP2_MCSPI_MAX_FREQ 48000000
44 44  
45 45 /* OMAP2 has 3 SPI controllers, while OMAP3 has 4 */
... ... @@ -229,6 +229,8 @@
229 229  
230 230 l = enable ? OMAP2_MCSPI_CHCTRL_EN : 0;
231 231 mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l);
  232 + /* Flash post-writes */
  233 + mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0);
232 234 }
233 235  
234 236 static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active)
235 237  
... ... @@ -303,11 +305,14 @@
303 305 unsigned int count, c;
304 306 unsigned long base, tx_reg, rx_reg;
305 307 int word_len, data_type, element_count;
  308 + int elements;
  309 + u32 l;
306 310 u8 * rx;
307 311 const u8 * tx;
308 312  
309 313 mcspi = spi_master_get_devdata(spi->master);
310 314 mcspi_dma = &mcspi->dma_channels[spi->chip_select];
  315 + l = mcspi_cached_chconf0(spi);
311 316  
312 317 count = xfer->len;
313 318 c = count;
314 319  
... ... @@ -346,8 +351,12 @@
346 351 }
347 352  
348 353 if (rx != NULL) {
  354 + elements = element_count - 1;
  355 + if (l & OMAP2_MCSPI_CHCONF_TURBO)
  356 + elements--;
  357 +
349 358 omap_set_dma_transfer_params(mcspi_dma->dma_rx_channel,
350   - data_type, element_count - 1, 1,
  359 + data_type, elements, 1,
351 360 OMAP_DMA_SYNC_ELEMENT,
352 361 mcspi_dma->dma_rx_sync_dev, 1);
353 362  
354 363  
355 364  
356 365  
... ... @@ -379,17 +388,42 @@
379 388 wait_for_completion(&mcspi_dma->dma_rx_completion);
380 389 dma_unmap_single(NULL, xfer->rx_dma, count, DMA_FROM_DEVICE);
381 390 omap2_mcspi_set_enable(spi, 0);
  391 +
  392 + if (l & OMAP2_MCSPI_CHCONF_TURBO) {
  393 +
  394 + if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
  395 + & OMAP2_MCSPI_CHSTAT_RXS)) {
  396 + u32 w;
  397 +
  398 + w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
  399 + if (word_len <= 8)
  400 + ((u8 *)xfer->rx_buf)[elements++] = w;
  401 + else if (word_len <= 16)
  402 + ((u16 *)xfer->rx_buf)[elements++] = w;
  403 + else /* word_len <= 32 */
  404 + ((u32 *)xfer->rx_buf)[elements++] = w;
  405 + } else {
  406 + dev_err(&spi->dev,
  407 + "DMA RX penultimate word empty");
  408 + count -= (word_len <= 8) ? 2 :
  409 + (word_len <= 16) ? 4 :
  410 + /* word_len <= 32 */ 8;
  411 + omap2_mcspi_set_enable(spi, 1);
  412 + return count;
  413 + }
  414 + }
  415 +
382 416 if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
383 417 & OMAP2_MCSPI_CHSTAT_RXS)) {
384 418 u32 w;
385 419  
386 420 w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
387 421 if (word_len <= 8)
388   - ((u8 *)xfer->rx_buf)[element_count - 1] = w;
  422 + ((u8 *)xfer->rx_buf)[elements] = w;
389 423 else if (word_len <= 16)
390   - ((u16 *)xfer->rx_buf)[element_count - 1] = w;
  424 + ((u16 *)xfer->rx_buf)[elements] = w;
391 425 else /* word_len <= 32 */
392   - ((u32 *)xfer->rx_buf)[element_count - 1] = w;
  426 + ((u32 *)xfer->rx_buf)[elements] = w;
393 427 } else {
394 428 dev_err(&spi->dev, "DMA RX last word empty");
395 429 count -= (word_len <= 8) ? 1 :
... ... @@ -433,7 +467,6 @@
433 467 word_len = cs->word_len;
434 468  
435 469 l = mcspi_cached_chconf0(spi);
436   - l &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
437 470  
438 471 /* We store the pre-calculated register addresses on stack to speed
439 472 * up the transfer loop. */
... ... @@ -468,11 +501,26 @@
468 501 dev_err(&spi->dev, "RXS timed out\n");
469 502 goto out;
470 503 }
471   - /* prevent last RX_ONLY read from triggering
472   - * more word i/o: switch to rx+tx
473   - */
474   - if (c == 0 && tx == NULL)
475   - mcspi_write_chconf0(spi, l);
  504 +
  505 + if (c == 1 && tx == NULL &&
  506 + (l & OMAP2_MCSPI_CHCONF_TURBO)) {
  507 + omap2_mcspi_set_enable(spi, 0);
  508 + *rx++ = __raw_readl(rx_reg);
  509 +#ifdef VERBOSE
  510 + dev_dbg(&spi->dev, "read-%d %02x\n",
  511 + word_len, *(rx - 1));
  512 +#endif
  513 + if (mcspi_wait_for_reg_bit(chstat_reg,
  514 + OMAP2_MCSPI_CHSTAT_RXS) < 0) {
  515 + dev_err(&spi->dev,
  516 + "RXS timed out\n");
  517 + goto out;
  518 + }
  519 + c = 0;
  520 + } else if (c == 0 && tx == NULL) {
  521 + omap2_mcspi_set_enable(spi, 0);
  522 + }
  523 +
476 524 *rx++ = __raw_readl(rx_reg);
477 525 #ifdef VERBOSE
478 526 dev_dbg(&spi->dev, "read-%d %02x\n",
... ... @@ -506,11 +554,26 @@
506 554 dev_err(&spi->dev, "RXS timed out\n");
507 555 goto out;
508 556 }
509   - /* prevent last RX_ONLY read from triggering
510   - * more word i/o: switch to rx+tx
511   - */
512   - if (c == 0 && tx == NULL)
513   - mcspi_write_chconf0(spi, l);
  557 +
  558 + if (c == 2 && tx == NULL &&
  559 + (l & OMAP2_MCSPI_CHCONF_TURBO)) {
  560 + omap2_mcspi_set_enable(spi, 0);
  561 + *rx++ = __raw_readl(rx_reg);
  562 +#ifdef VERBOSE
  563 + dev_dbg(&spi->dev, "read-%d %04x\n",
  564 + word_len, *(rx - 1));
  565 +#endif
  566 + if (mcspi_wait_for_reg_bit(chstat_reg,
  567 + OMAP2_MCSPI_CHSTAT_RXS) < 0) {
  568 + dev_err(&spi->dev,
  569 + "RXS timed out\n");
  570 + goto out;
  571 + }
  572 + c = 0;
  573 + } else if (c == 0 && tx == NULL) {
  574 + omap2_mcspi_set_enable(spi, 0);
  575 + }
  576 +
514 577 *rx++ = __raw_readl(rx_reg);
515 578 #ifdef VERBOSE
516 579 dev_dbg(&spi->dev, "read-%d %04x\n",
... ... @@ -544,11 +607,26 @@
544 607 dev_err(&spi->dev, "RXS timed out\n");
545 608 goto out;
546 609 }
547   - /* prevent last RX_ONLY read from triggering
548   - * more word i/o: switch to rx+tx
549   - */
550   - if (c == 0 && tx == NULL)
551   - mcspi_write_chconf0(spi, l);
  610 +
  611 + if (c == 4 && tx == NULL &&
  612 + (l & OMAP2_MCSPI_CHCONF_TURBO)) {
  613 + omap2_mcspi_set_enable(spi, 0);
  614 + *rx++ = __raw_readl(rx_reg);
  615 +#ifdef VERBOSE
  616 + dev_dbg(&spi->dev, "read-%d %08x\n",
  617 + word_len, *(rx - 1));
  618 +#endif
  619 + if (mcspi_wait_for_reg_bit(chstat_reg,
  620 + OMAP2_MCSPI_CHSTAT_RXS) < 0) {
  621 + dev_err(&spi->dev,
  622 + "RXS timed out\n");
  623 + goto out;
  624 + }
  625 + c = 0;
  626 + } else if (c == 0 && tx == NULL) {
  627 + omap2_mcspi_set_enable(spi, 0);
  628 + }
  629 +
552 630 *rx++ = __raw_readl(rx_reg);
553 631 #ifdef VERBOSE
554 632 dev_dbg(&spi->dev, "read-%d %08x\n",
... ... @@ -568,6 +646,7 @@
568 646 dev_err(&spi->dev, "EOT timed out\n");
569 647 }
570 648 out:
  649 + omap2_mcspi_set_enable(spi, 1);
571 650 return count - c;
572 651 }
573 652  
... ... @@ -797,6 +876,7 @@
797 876 struct spi_transfer *t = NULL;
798 877 int cs_active = 0;
799 878 struct omap2_mcspi_cs *cs;
  879 + struct omap2_mcspi_device_config *cd;
800 880 int par_override = 0;
801 881 int status = 0;
802 882 u32 chconf;
... ... @@ -809,6 +889,7 @@
809 889  
810 890 spi = m->spi;
811 891 cs = spi->controller_state;
  892 + cd = spi->controller_data;
812 893  
813 894 omap2_mcspi_set_enable(spi, 1);
814 895 list_for_each_entry(t, &m->transfers, transfer_list) {
815 896  
... ... @@ -832,10 +913,19 @@
832 913  
833 914 chconf = mcspi_cached_chconf0(spi);
834 915 chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
  916 + chconf &= ~OMAP2_MCSPI_CHCONF_TURBO;
  917 +
835 918 if (t->tx_buf == NULL)
836 919 chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
837 920 else if (t->rx_buf == NULL)
838 921 chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
  922 +
  923 + if (cd && cd->turbo_mode && t->tx_buf == NULL) {
  924 + /* Turbo mode is for more than one word */
  925 + if (t->len > ((cs->word_len + 7) >> 3))
  926 + chconf |= OMAP2_MCSPI_CHCONF_TURBO;
  927 + }
  928 +
839 929 mcspi_write_chconf0(spi, chconf);
840 930  
841 931 if (t->len) {