From 4729baecba9d7a3843470aeff5e6a8923098d0b9 Mon Sep 17 00:00:00 2001 From: Sunny Luo Date: Mon, 15 Oct 2018 16:09:03 +0800 Subject: [PATCH] spicc: fix miss bytes/time consume/loopback issue [1/1] 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 --- drivers/amlogic/spicc/spicc.c | 13 +++++++------ drivers/spi/spi-meson-spicc.c | 10 ++++++++-- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/amlogic/spicc/spicc.c b/drivers/amlogic/spicc/spicc.c index 1fcd997..e72023a 100644 --- a/drivers/amlogic/spicc/spicc.c +++ b/drivers/amlogic/spicc/spicc.c @@ -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) { diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index d5d8589..ea35284 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -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; -- 2.7.4