pistachio: add 4.9 kernel support
[librecmc/librecmc.git] / target / linux / pistachio / patches-4.9 / 106-spi-img-spfi-finish-every-transfer-cleanly.patch
1 From 5fcca3fd4b621d7b5bdeca18d36dfc6ca6cfe383 Mon Sep 17 00:00:00 2001
2 From: Ionela Voinescu <ionela.voinescu@imgtec.com>
3 Date: Wed, 10 Aug 2016 11:42:26 +0100
4 Subject: spi: img-spfi: finish every transfer cleanly
5
6 Before this change, the interrupt status bit that signaled
7 the end of a tranfers was cleared in the wait_all_done
8 function. That functionality triggered issues for DMA
9 duplex transactions where the wait function was called
10 twice, in both the TX and RX callbacks.
11
12 In order to fix the issue, clear all interrupt data bits
13 at the end of a PIO transfer or at the end of both TX and RX
14 duplex transfers, if the transfer is not a pending tranfer
15 (command waiting for data). After that, the status register
16 is checked for new incoming data or new data requests to be
17 signaled. If SPFI finished cleanly, no new interrupt data
18 bits should be set.
19
20 Signed-off-by: Ionela Voinescu <ionela.voinescu@imgtec.com>
21 ---
22  drivers/spi/spi-img-spfi.c | 49 +++++++++++++++++++++++++++++++++-------------
23  1 file changed, 35 insertions(+), 14 deletions(-)
24
25 diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c
26 index 8ad6c75..a124423 100644
27 --- a/drivers/spi/spi-img-spfi.c
28 +++ b/drivers/spi/spi-img-spfi.c
29 @@ -83,6 +83,14 @@
30  #define SPFI_INTERRUPT_SDE                     BIT(1)
31  #define SPFI_INTERRUPT_SDTRIG                  BIT(0)
32  
33 +#define SPFI_INTERRUPT_DATA_BITS               (SPFI_INTERRUPT_SDHF |\
34 +                                               SPFI_INTERRUPT_SDFUL |\
35 +                                               SPFI_INTERRUPT_GDEX32BIT |\
36 +                                               SPFI_INTERRUPT_GDHF |\
37 +                                               SPFI_INTERRUPT_GDFUL |\
38 +                                               SPFI_INTERRUPT_ALLDONETRIG |\
39 +                                               SPFI_INTERRUPT_GDEX8BIT)
40 +
41  /*
42   * There are four parallel FIFOs of 16 bytes each.  The word buffer
43   * (*_32BIT_VALID_DATA) accesses all four FIFOs at once, resulting in an
44 @@ -144,6 +152,23 @@ static inline void spfi_reset(struct img_spfi *spfi)
45         spfi_writel(spfi, 0, SPFI_CONTROL);
46  }
47  
48 +static inline void spfi_finish(struct img_spfi *spfi)
49 +{
50 +       if (!(spfi->complete))
51 +               return;
52 +
53 +       /* Clear data bits as all transfers(TX and RX) have finished */
54 +       spfi_writel(spfi, SPFI_INTERRUPT_DATA_BITS, SPFI_INTERRUPT_CLEAR);
55 +       if (spfi_readl(spfi, SPFI_INTERRUPT_STATUS) & SPFI_INTERRUPT_DATA_BITS) {
56 +               dev_err(spfi->dev, "SPFI did not finish transfer cleanly.\n");
57 +               spfi_reset(spfi);
58 +       }
59 +       /* Disable SPFI for it not to interfere with pending transactions */
60 +       spfi_writel(spfi,
61 +                   spfi_readl(spfi, SPFI_CONTROL) & ~SPFI_CONTROL_SPFI_EN,
62 +                   SPFI_CONTROL);
63 +}
64 +
65  static int spfi_wait_all_done(struct img_spfi *spfi)
66  {
67         unsigned long timeout = jiffies + msecs_to_jiffies(50);
68 @@ -152,19 +177,9 @@ static int spfi_wait_all_done(struct img_spfi *spfi)
69                 return 0;
70  
71         while (time_before(jiffies, timeout)) {
72 -               u32 status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS);
73 -
74 -               if (status & SPFI_INTERRUPT_ALLDONETRIG) {
75 -                       spfi_writel(spfi, SPFI_INTERRUPT_ALLDONETRIG,
76 -                                   SPFI_INTERRUPT_CLEAR);
77 -                       /*
78 -                        * Disable SPFI for it not to interfere with
79 -                        * pending transactions
80 -                        */
81 -                       spfi_writel(spfi, spfi_readl(spfi, SPFI_CONTROL)
82 -                       & ~SPFI_CONTROL_SPFI_EN, SPFI_CONTROL);
83 +               if (spfi_readl(spfi, SPFI_INTERRUPT_STATUS) &
84 +                   SPFI_INTERRUPT_ALLDONETRIG)
85                         return 0;
86 -               }
87                 cpu_relax();
88         }
89  
90 @@ -296,6 +311,8 @@ static int img_spfi_start_pio(struct spi_master *master,
91         }
92  
93         ret = spfi_wait_all_done(spfi);
94 +       spfi_finish(spfi);
95 +
96         if (ret < 0)
97                 return ret;
98  
99 @@ -311,8 +328,10 @@ static void img_spfi_dma_rx_cb(void *data)
100  
101         spin_lock_irqsave(&spfi->lock, flags);
102         spfi->rx_dma_busy = false;
103 -       if (!spfi->tx_dma_busy)
104 +       if (!spfi->tx_dma_busy) {
105 +               spfi_finish(spfi);
106                 spi_finalize_current_transfer(spfi->master);
107 +       }
108         spin_unlock_irqrestore(&spfi->lock, flags);
109  }
110  
111 @@ -325,8 +344,10 @@ static void img_spfi_dma_tx_cb(void *data)
112  
113         spin_lock_irqsave(&spfi->lock, flags);
114         spfi->tx_dma_busy = false;
115 -       if (!spfi->rx_dma_busy)
116 +       if (!spfi->rx_dma_busy) {
117 +               spfi_finish(spfi);
118                 spi_finalize_current_transfer(spfi->master);
119 +       }
120         spin_unlock_irqrestore(&spfi->lock, flags);
121  }
122  
123 -- 
124 2.7.4
125