spicc: fix miss bytes/time consume/loopback issue [1/1]
authorSunny Luo <sunny.luo@amlogic.com>
Mon, 15 Oct 2018 08:09:03 +0000 (16:09 +0800)
committerLuan Yuan <luan.yuan@amlogic.com>
Tue, 27 Nov 2018 03:12:09 +0000 (11:12 +0800)
PD#SWPL-215

Problem:
1. additional or missing bytes be sent on mosi sometimes.
2. Customer DSP load firmware through SPICC. the loading time is 12s with
buildroot release 20180907 while 6s with 20180131.
3. rx error when work in loopback mode at high speed.

Solution:
1. change to disable irq at the irq-handle begining;
change to enable irq after all data pulled.
2. pre-setup of every spi transfer spends most of time on clk_set_rate().
this time is not obvious while cpu work at a high frequence such as
1000MHz.
In fact, a slave speed is almost fixed and we needn't set it for every
transfer but set only when speed changed.
3. disable auto io delay when in loopback mode.

Verify:
verified on axg-s400-v03 and tl1-skt

Change-Id: I61bcceccc243b218879b2b0711d0aff7538151f6
Signed-off-by: Sunny Luo <sunny.luo@amlogic.com>
drivers/amlogic/spicc/spicc.c
drivers/spi/spi-meson-spicc.c

index 1fcd997..e72023a 100644 (file)
@@ -401,9 +401,11 @@ static void dma_one_burst(struct spicc *spicc)
                        setb(mem_base, DMA_NUM_WR_BURST, threshold - 1);
                        setb(mem_base, DMA_RX_FIFO_TH, threshold - 1);
                }
-               setb(mem_base, CON_XCH, 1);
                spicc->remain -= bl;
                spicc->burst_len = bl;
+               if (spicc->irq)
+                       enable_irq(spicc->irq);
+               setb(mem_base, CON_XCH, 1);
        }
 }
 
@@ -470,8 +472,10 @@ static void pio_one_burst_send(struct spicc *spicc)
                        spicc_set_txfifo(spicc, dat);
                }
                setb(mem_base, CON_BURST_LEN, spicc->burst_len - 1);
-               setb(mem_base, CON_XCH, 1);
                spicc->remain -= spicc->burst_len;
+               if (spicc->irq)
+                       enable_irq(spicc->irq);
+               setb(mem_base, CON_XCH, 1);
        }
 }
 
@@ -501,6 +505,7 @@ static irqreturn_t spicc_xfer_complete_isr(int irq, void *dev_id)
        unsigned long flags;
 
        spin_lock_irqsave(&spicc->lock, flags);
+       disable_irq_nosync(spicc->irq);
        spicc_wait_complete(spicc, 100);
        spicc_log(spicc, &spicc->remain, 1, XFER_COMP_ISR);
        if (!spicc_get_flag(spicc, FLAG_DMA_EN))
@@ -583,11 +588,9 @@ static int spicc_dma_xfer(struct spicc *spicc, struct spi_transfer *t)
        spicc_log(spicc, &spicc->remain, 1, DMA_BEGIN);
        if (spicc->irq) {
                setb(mem_base, INT_XFER_COM_EN, 1);
-               enable_irq(spicc->irq);
                dma_one_burst(spicc);
                ret = wait_for_completion_interruptible_timeout(
                        &spicc->completion, msecs_to_jiffies(2000));
-               disable_irq_nosync(spicc->irq);
                setb(mem_base, INT_XFER_COM_EN, 0);
        } else {
                while (spicc->remain) {
@@ -624,11 +627,9 @@ static int spicc_hw_xfer(struct spicc *spicc, u8 *txp, u8 *rxp, int len)
        spicc_log(spicc, &spicc->remain, 1, PIO_BEGIN);
        if (spicc->irq) {
                setb(mem_base, INT_XFER_COM_EN, 1);
-               enable_irq(spicc->irq);
                pio_one_burst_send(spicc);
                ret = wait_for_completion_interruptible_timeout(
                        &spicc->completion, msecs_to_jiffies(2000));
-               disable_irq_nosync(spicc->irq);
                setb(mem_base, INT_XFER_COM_EN, 0);
        } else {
                while (spicc->remain) {
index d5d8589..ea35284 100644 (file)
@@ -207,6 +207,7 @@ struct meson_spicc_device {
        u8                              *tx_buf;
        u8                              *rx_buf;
        unsigned int                    bytes_per_word;
+       unsigned int                    speed_hz;
        unsigned long                   tx_remain;
        unsigned long                   txb_remain;
        unsigned long                   rx_remain;
@@ -294,7 +295,9 @@ static void meson_spicc_auto_io_delay(struct meson_spicc_device *spicc)
        cap_delay = SPICC_CAP_AHEAD_2_CYCLE;
        hz = clk_get_rate(spicc->clk);
 
-       if (hz >= 100000000)
+       if (spicc->message->spi->mode & SPI_LOOP)
+               cap_delay = SPICC_CAP_AHEAD_1_CYCLE;
+       else if (hz >= 100000000)
                cap_delay = SPICC_CAP_DELAY_1_CYCLE;
        else if (hz >= 80000000)
                cap_delay = SPICC_CAP_NO_DELAY;
@@ -545,7 +548,10 @@ static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc,
        if (conf != conf_orig)
                writel_relaxed(conf, spicc->base + SPICC_CONREG);
 
-       clk_set_rate(spicc->clk, xfer->speed_hz);
+       if (spicc->speed_hz != xfer->speed_hz) {
+               spicc->speed_hz = xfer->speed_hz;
+               clk_set_rate(spicc->clk, xfer->speed_hz);
+       }
        meson_spicc_auto_io_delay(spicc);
 
        spicc->using_dma = 0;