OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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 | --- a/drivers/spi/spi-img-spfi.c |
||
26 | +++ b/drivers/spi/spi-img-spfi.c |
||
27 | @@ -83,6 +83,14 @@ |
||
28 | #define SPFI_INTERRUPT_SDE BIT(1) |
||
29 | #define SPFI_INTERRUPT_SDTRIG BIT(0) |
||
30 | |||
31 | +#define SPFI_INTERRUPT_DATA_BITS (SPFI_INTERRUPT_SDHF |\ |
||
32 | + SPFI_INTERRUPT_SDFUL |\ |
||
33 | + SPFI_INTERRUPT_GDEX32BIT |\ |
||
34 | + SPFI_INTERRUPT_GDHF |\ |
||
35 | + SPFI_INTERRUPT_GDFUL |\ |
||
36 | + SPFI_INTERRUPT_ALLDONETRIG |\ |
||
37 | + SPFI_INTERRUPT_GDEX8BIT) |
||
38 | + |
||
39 | /* |
||
40 | * There are four parallel FIFOs of 16 bytes each. The word buffer |
||
41 | * (*_32BIT_VALID_DATA) accesses all four FIFOs at once, resulting in an |
||
42 | @@ -144,6 +152,23 @@ static inline void spfi_reset(struct img |
||
43 | spfi_writel(spfi, 0, SPFI_CONTROL); |
||
44 | } |
||
45 | |||
46 | +static inline void spfi_finish(struct img_spfi *spfi) |
||
47 | +{ |
||
48 | + if (!(spfi->complete)) |
||
49 | + return; |
||
50 | + |
||
51 | + /* Clear data bits as all transfers(TX and RX) have finished */ |
||
52 | + spfi_writel(spfi, SPFI_INTERRUPT_DATA_BITS, SPFI_INTERRUPT_CLEAR); |
||
53 | + if (spfi_readl(spfi, SPFI_INTERRUPT_STATUS) & SPFI_INTERRUPT_DATA_BITS) { |
||
54 | + dev_err(spfi->dev, "SPFI did not finish transfer cleanly.\n"); |
||
55 | + spfi_reset(spfi); |
||
56 | + } |
||
57 | + /* Disable SPFI for it not to interfere with pending transactions */ |
||
58 | + spfi_writel(spfi, |
||
59 | + spfi_readl(spfi, SPFI_CONTROL) & ~SPFI_CONTROL_SPFI_EN, |
||
60 | + SPFI_CONTROL); |
||
61 | +} |
||
62 | + |
||
63 | static int spfi_wait_all_done(struct img_spfi *spfi) |
||
64 | { |
||
65 | unsigned long timeout = jiffies + msecs_to_jiffies(50); |
||
66 | @@ -152,19 +177,9 @@ static int spfi_wait_all_done(struct img |
||
67 | return 0; |
||
68 | |||
69 | while (time_before(jiffies, timeout)) { |
||
70 | - u32 status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS); |
||
71 | - |
||
72 | - if (status & SPFI_INTERRUPT_ALLDONETRIG) { |
||
73 | - spfi_writel(spfi, SPFI_INTERRUPT_ALLDONETRIG, |
||
74 | - SPFI_INTERRUPT_CLEAR); |
||
75 | - /* |
||
76 | - * Disable SPFI for it not to interfere with |
||
77 | - * pending transactions |
||
78 | - */ |
||
79 | - spfi_writel(spfi, spfi_readl(spfi, SPFI_CONTROL) |
||
80 | - & ~SPFI_CONTROL_SPFI_EN, SPFI_CONTROL); |
||
81 | + if (spfi_readl(spfi, SPFI_INTERRUPT_STATUS) & |
||
82 | + SPFI_INTERRUPT_ALLDONETRIG) |
||
83 | return 0; |
||
84 | - } |
||
85 | cpu_relax(); |
||
86 | } |
||
87 | |||
88 | @@ -296,6 +311,8 @@ static int img_spfi_start_pio(struct spi |
||
89 | } |
||
90 | |||
91 | ret = spfi_wait_all_done(spfi); |
||
92 | + spfi_finish(spfi); |
||
93 | + |
||
94 | if (ret < 0) |
||
95 | return ret; |
||
96 | |||
97 | @@ -311,8 +328,10 @@ static void img_spfi_dma_rx_cb(void *dat |
||
98 | |||
99 | spin_lock_irqsave(&spfi->lock, flags); |
||
100 | spfi->rx_dma_busy = false; |
||
101 | - if (!spfi->tx_dma_busy) |
||
102 | + if (!spfi->tx_dma_busy) { |
||
103 | + spfi_finish(spfi); |
||
104 | spi_finalize_current_transfer(spfi->master); |
||
105 | + } |
||
106 | spin_unlock_irqrestore(&spfi->lock, flags); |
||
107 | } |
||
108 | |||
109 | @@ -325,8 +344,10 @@ static void img_spfi_dma_tx_cb(void *dat |
||
110 | |||
111 | spin_lock_irqsave(&spfi->lock, flags); |
||
112 | spfi->tx_dma_busy = false; |
||
113 | - if (!spfi->rx_dma_busy) |
||
114 | + if (!spfi->rx_dma_busy) { |
||
115 | + spfi_finish(spfi); |
||
116 | spi_finalize_current_transfer(spfi->master); |
||
117 | + } |
||
118 | spin_unlock_irqrestore(&spfi->lock, flags); |
||
119 | } |
||
120 |