diff options
author | Martin Sperl <kernel@martin.sperl.org> | 2015-03-23 10:11:53 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-03-23 14:48:58 -0400 |
commit | 4adf312976ef2b72830b83f212fef3f6a36513a6 (patch) | |
tree | c3532ec523a70e1127abb8e3134d58c8e4c1979e | |
parent | 342f948a166c2a17b0e187e3fc2618dc561842f3 (diff) |
spi: bcm2835: fill/drain SPI-fifo as much as possible during interrupt
Implement the recommendation from the BCM2835 data-sheet
with regards to polling drivers to fill/drain the FIFO as much data as possible
also for the interrupt-driven case (which this driver is making use of).
This means that for long transfers (>64bytes) we need one interrupt
every 64 bytes instead of every 12 bytes, as the FIFO is 16 words (not bytes) wide.
Tested with mcp251x (can bus), fb_st7735 (TFT framebuffer device)
and enc28j60 (ethernet) drivers.
Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | drivers/spi/spi-bcm2835.c | 78 |
1 files changed, 17 insertions, 61 deletions
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index 779d3a86c3cb..960dcce607c2 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c | |||
@@ -91,25 +91,23 @@ static inline void bcm2835_wr(struct bcm2835_spi *bs, unsigned reg, u32 val) | |||
91 | writel(val, bs->regs + reg); | 91 | writel(val, bs->regs + reg); |
92 | } | 92 | } |
93 | 93 | ||
94 | static inline void bcm2835_rd_fifo(struct bcm2835_spi *bs, int len) | 94 | static inline void bcm2835_rd_fifo(struct bcm2835_spi *bs) |
95 | { | 95 | { |
96 | u8 byte; | 96 | u8 byte; |
97 | 97 | ||
98 | while (len--) { | 98 | while (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_RXD) { |
99 | byte = bcm2835_rd(bs, BCM2835_SPI_FIFO); | 99 | byte = bcm2835_rd(bs, BCM2835_SPI_FIFO); |
100 | if (bs->rx_buf) | 100 | if (bs->rx_buf) |
101 | *bs->rx_buf++ = byte; | 101 | *bs->rx_buf++ = byte; |
102 | } | 102 | } |
103 | } | 103 | } |
104 | 104 | ||
105 | static inline void bcm2835_wr_fifo(struct bcm2835_spi *bs, int len) | 105 | static inline void bcm2835_wr_fifo(struct bcm2835_spi *bs) |
106 | { | 106 | { |
107 | u8 byte; | 107 | u8 byte; |
108 | 108 | ||
109 | if (len > bs->len) | 109 | while ((bs->len) && |
110 | len = bs->len; | 110 | (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_TXD)) { |
111 | |||
112 | while (len--) { | ||
113 | byte = bs->tx_buf ? *bs->tx_buf++ : 0; | 111 | byte = bs->tx_buf ? *bs->tx_buf++ : 0; |
114 | bcm2835_wr(bs, BCM2835_SPI_FIFO, byte); | 112 | bcm2835_wr(bs, BCM2835_SPI_FIFO, byte); |
115 | bs->len--; | 113 | bs->len--; |
@@ -122,60 +120,24 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id) | |||
122 | struct bcm2835_spi *bs = spi_master_get_devdata(master); | 120 | struct bcm2835_spi *bs = spi_master_get_devdata(master); |
123 | u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); | 121 | u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); |
124 | 122 | ||
125 | /* | 123 | /* Read as many bytes as possible from FIFO */ |
126 | * RXR - RX needs Reading. This means 12 (or more) bytes have been | 124 | bcm2835_rd_fifo(bs); |
127 | * transmitted and hence 12 (or more) bytes have been received. | ||
128 | * | ||
129 | * The FIFO is 16-bytes deep. We check for this interrupt to keep the | ||
130 | * FIFO full; we have a 4-byte-time buffer for IRQ latency. We check | ||
131 | * this before DONE (TX empty) just in case we delayed processing this | ||
132 | * interrupt for some reason. | ||
133 | * | ||
134 | * We only check for this case if we have more bytes to TX; at the end | ||
135 | * of the transfer, we ignore this pipelining optimization, and let | ||
136 | * bcm2835_spi_finish_transfer() drain the RX FIFO. | ||
137 | */ | ||
138 | if (bs->len && (cs & BCM2835_SPI_CS_RXR)) { | ||
139 | /* Read 12 bytes of data */ | ||
140 | bcm2835_rd_fifo(bs, 12); | ||
141 | 125 | ||
142 | /* Write up to 12 bytes */ | 126 | if (bs->len) { /* there is more data to transmit */ |
143 | bcm2835_wr_fifo(bs, 12); | 127 | bcm2835_wr_fifo(bs); |
128 | } else { /* Transfer complete */ | ||
129 | /* Disable SPI interrupts */ | ||
130 | cs &= ~(BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD); | ||
131 | bcm2835_wr(bs, BCM2835_SPI_CS, cs); | ||
144 | 132 | ||
145 | /* | 133 | /* |
146 | * We must have written something to the TX FIFO due to the | 134 | * Wake up bcm2835_spi_transfer_one(), which will call |
147 | * bs->len check above, so cannot be DONE. Hence, return | 135 | * bcm2835_spi_finish_transfer(), to drain the RX FIFO. |
148 | * early. Note that DONE could also be set if we serviced an | ||
149 | * RXR interrupt really late. | ||
150 | */ | 136 | */ |
151 | return IRQ_HANDLED; | 137 | complete(&bs->done); |
152 | } | 138 | } |
153 | 139 | ||
154 | /* | 140 | return IRQ_HANDLED; |
155 | * DONE - TX empty. This occurs when we first enable the transfer | ||
156 | * since we do not pre-fill the TX FIFO. At any other time, given that | ||
157 | * we refill the TX FIFO above based on RXR, and hence ignore DONE if | ||
158 | * RXR is set, DONE really does mean end-of-transfer. | ||
159 | */ | ||
160 | if (cs & BCM2835_SPI_CS_DONE) { | ||
161 | if (bs->len) { /* First interrupt in a transfer */ | ||
162 | bcm2835_wr_fifo(bs, 16); | ||
163 | } else { /* Transfer complete */ | ||
164 | /* Disable SPI interrupts */ | ||
165 | cs &= ~(BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD); | ||
166 | bcm2835_wr(bs, BCM2835_SPI_CS, cs); | ||
167 | |||
168 | /* | ||
169 | * Wake up bcm2835_spi_transfer_one(), which will call | ||
170 | * bcm2835_spi_finish_transfer(), to drain the RX FIFO. | ||
171 | */ | ||
172 | complete(&bs->done); | ||
173 | } | ||
174 | |||
175 | return IRQ_HANDLED; | ||
176 | } | ||
177 | |||
178 | return IRQ_NONE; | ||
179 | } | 141 | } |
180 | 142 | ||
181 | static int bcm2835_spi_start_transfer(struct spi_device *spi, | 143 | static int bcm2835_spi_start_transfer(struct spi_device *spi, |
@@ -238,12 +200,6 @@ static int bcm2835_spi_finish_transfer(struct spi_device *spi, | |||
238 | struct bcm2835_spi *bs = spi_master_get_devdata(spi->master); | 200 | struct bcm2835_spi *bs = spi_master_get_devdata(spi->master); |
239 | u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); | 201 | u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); |
240 | 202 | ||
241 | /* Drain RX FIFO */ | ||
242 | while (cs & BCM2835_SPI_CS_RXD) { | ||
243 | bcm2835_rd_fifo(bs, 1); | ||
244 | cs = bcm2835_rd(bs, BCM2835_SPI_CS); | ||
245 | } | ||
246 | |||
247 | if (tfr->delay_usecs) | 203 | if (tfr->delay_usecs) |
248 | udelay(tfr->delay_usecs); | 204 | udelay(tfr->delay_usecs); |
249 | 205 | ||