aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIcenowy Zheng <icenowy@aosc.xyz>2017-03-06 07:14:43 -0500
committerMark Brown <broonie@kernel.org>2017-03-07 07:10:39 -0500
commit913f536c6c18a2e19e32f06971101c1d0ae3739c (patch)
treef19995a3535e73416a98391c1568149a2ec60c8f
parentc1ae3cfa0e89fa1a7ecc4c99031f5e9ae99d9201 (diff)
spi: sun6i: Allow transfers larger than FIFO size
The spi-sun6i driver have the same problem that spi-sun4i used to have -- SPI transfers are limited to one FIFO depth. This commit fixes this problem in the same way it's fixed in spi-sun4i. See commit 196737912da5 ("spi: sun4i: Allow transfers larger than FIFO size") for more information. The sun6i SPI controllers features changeable interrupt trigger level, but I set it to 3/4 of fifo depth, as same as the the sun4i SPI controllers. Signed-off-by: Icenowy Zheng <icenowy@aosc.xyz> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--drivers/spi/spi-sun6i.c90
1 files changed, 81 insertions, 9 deletions
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index e3114832c485..6e9ca93db9bf 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -46,13 +46,19 @@
46#define SUN6I_TFR_CTL_XCH BIT(31) 46#define SUN6I_TFR_CTL_XCH BIT(31)
47 47
48#define SUN6I_INT_CTL_REG 0x10 48#define SUN6I_INT_CTL_REG 0x10
49#define SUN6I_INT_CTL_RF_RDY BIT(0)
50#define SUN6I_INT_CTL_TF_ERQ BIT(4)
49#define SUN6I_INT_CTL_RF_OVF BIT(8) 51#define SUN6I_INT_CTL_RF_OVF BIT(8)
50#define SUN6I_INT_CTL_TC BIT(12) 52#define SUN6I_INT_CTL_TC BIT(12)
51 53
52#define SUN6I_INT_STA_REG 0x14 54#define SUN6I_INT_STA_REG 0x14
53 55
54#define SUN6I_FIFO_CTL_REG 0x18 56#define SUN6I_FIFO_CTL_REG 0x18
57#define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_MASK 0xff
58#define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS 0
55#define SUN6I_FIFO_CTL_RF_RST BIT(15) 59#define SUN6I_FIFO_CTL_RF_RST BIT(15)
60#define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_MASK 0xff
61#define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS 16
56#define SUN6I_FIFO_CTL_TF_RST BIT(31) 62#define SUN6I_FIFO_CTL_TF_RST BIT(31)
57 63
58#define SUN6I_FIFO_STA_REG 0x1c 64#define SUN6I_FIFO_STA_REG 0x1c
@@ -68,14 +74,16 @@
68#define SUN6I_CLK_CTL_CDR1(div) (((div) & SUN6I_CLK_CTL_CDR1_MASK) << 8) 74#define SUN6I_CLK_CTL_CDR1(div) (((div) & SUN6I_CLK_CTL_CDR1_MASK) << 8)
69#define SUN6I_CLK_CTL_DRS BIT(12) 75#define SUN6I_CLK_CTL_DRS BIT(12)
70 76
77#define SUN6I_MAX_XFER_SIZE 0xffffff
78
71#define SUN6I_BURST_CNT_REG 0x30 79#define SUN6I_BURST_CNT_REG 0x30
72#define SUN6I_BURST_CNT(cnt) ((cnt) & 0xffffff) 80#define SUN6I_BURST_CNT(cnt) ((cnt) & SUN6I_MAX_XFER_SIZE)
73 81
74#define SUN6I_XMIT_CNT_REG 0x34 82#define SUN6I_XMIT_CNT_REG 0x34
75#define SUN6I_XMIT_CNT(cnt) ((cnt) & 0xffffff) 83#define SUN6I_XMIT_CNT(cnt) ((cnt) & SUN6I_MAX_XFER_SIZE)
76 84
77#define SUN6I_BURST_CTL_CNT_REG 0x38 85#define SUN6I_BURST_CTL_CNT_REG 0x38
78#define SUN6I_BURST_CTL_CNT_STC(cnt) ((cnt) & 0xffffff) 86#define SUN6I_BURST_CTL_CNT_STC(cnt) ((cnt) & SUN6I_MAX_XFER_SIZE)
79 87
80#define SUN6I_TXDATA_REG 0x200 88#define SUN6I_TXDATA_REG 0x200
81#define SUN6I_RXDATA_REG 0x300 89#define SUN6I_RXDATA_REG 0x300
@@ -105,6 +113,31 @@ static inline void sun6i_spi_write(struct sun6i_spi *sspi, u32 reg, u32 value)
105 writel(value, sspi->base_addr + reg); 113 writel(value, sspi->base_addr + reg);
106} 114}
107 115
116static inline u32 sun6i_spi_get_tx_fifo_count(struct sun6i_spi *sspi)
117{
118 u32 reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
119
120 reg >>= SUN6I_FIFO_STA_TF_CNT_BITS;
121
122 return reg & SUN6I_FIFO_STA_TF_CNT_MASK;
123}
124
125static inline void sun6i_spi_enable_interrupt(struct sun6i_spi *sspi, u32 mask)
126{
127 u32 reg = sun6i_spi_read(sspi, SUN6I_INT_CTL_REG);
128
129 reg |= mask;
130 sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg);
131}
132
133static inline void sun6i_spi_disable_interrupt(struct sun6i_spi *sspi, u32 mask)
134{
135 u32 reg = sun6i_spi_read(sspi, SUN6I_INT_CTL_REG);
136
137 reg &= ~mask;
138 sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg);
139}
140
108static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len) 141static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len)
109{ 142{
110 u32 reg, cnt; 143 u32 reg, cnt;
@@ -127,10 +160,13 @@ static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len)
127 160
128static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi, int len) 161static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi, int len)
129{ 162{
163 u32 cnt;
130 u8 byte; 164 u8 byte;
131 165
132 if (len > sspi->len) 166 /* See how much data we can fit */
133 len = sspi->len; 167 cnt = sspi->fifo_depth - sun6i_spi_get_tx_fifo_count(sspi);
168
169 len = min3(len, (int)cnt, sspi->len);
134 170
135 while (len--) { 171 while (len--) {
136 byte = sspi->tx_buf ? *sspi->tx_buf++ : 0; 172 byte = sspi->tx_buf ? *sspi->tx_buf++ : 0;
@@ -170,12 +206,12 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
170 struct sun6i_spi *sspi = spi_master_get_devdata(master); 206 struct sun6i_spi *sspi = spi_master_get_devdata(master);
171 unsigned int mclk_rate, div, timeout; 207 unsigned int mclk_rate, div, timeout;
172 unsigned int start, end, tx_time; 208 unsigned int start, end, tx_time;
209 unsigned int trig_level;
173 unsigned int tx_len = 0; 210 unsigned int tx_len = 0;
174 int ret = 0; 211 int ret = 0;
175 u32 reg; 212 u32 reg;
176 213
177 /* We don't support transfer larger than the FIFO */ 214 if (tfr->len > SUN6I_MAX_XFER_SIZE)
178 if (tfr->len > sspi->fifo_depth)
179 return -EINVAL; 215 return -EINVAL;
180 216
181 reinit_completion(&sspi->done); 217 reinit_completion(&sspi->done);
@@ -191,6 +227,17 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
191 SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST); 227 SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST);
192 228
193 /* 229 /*
230 * Setup FIFO interrupt trigger level
231 * Here we choose 3/4 of the full fifo depth, as it's the hardcoded
232 * value used in old generation of Allwinner SPI controller.
233 * (See spi-sun4i.c)
234 */
235 trig_level = sspi->fifo_depth / 4 * 3;
236 sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
237 (trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS) |
238 (trig_level << SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS));
239
240 /*
194 * Setup the transfer control register: Chip Select, 241 * Setup the transfer control register: Chip Select,
195 * polarities, etc. 242 * polarities, etc.
196 */ 243 */
@@ -274,6 +321,10 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
274 321
275 /* Enable the interrupts */ 322 /* Enable the interrupts */
276 sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC); 323 sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
324 sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TC |
325 SUN6I_INT_CTL_RF_RDY);
326 if (tx_len > sspi->fifo_depth)
327 sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TF_ERQ);
277 328
278 /* Start the transfer */ 329 /* Start the transfer */
279 reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG); 330 reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
@@ -293,8 +344,6 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
293 goto out; 344 goto out;
294 } 345 }
295 346
296 sun6i_spi_drain_fifo(sspi, sspi->fifo_depth);
297
298out: 347out:
299 sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0); 348 sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0);
300 349
@@ -309,10 +358,33 @@ static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
309 /* Transfer complete */ 358 /* Transfer complete */
310 if (status & SUN6I_INT_CTL_TC) { 359 if (status & SUN6I_INT_CTL_TC) {
311 sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC); 360 sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC);
361 sun6i_spi_drain_fifo(sspi, sspi->fifo_depth);
312 complete(&sspi->done); 362 complete(&sspi->done);
313 return IRQ_HANDLED; 363 return IRQ_HANDLED;
314 } 364 }
315 365
366 /* Receive FIFO 3/4 full */
367 if (status & SUN6I_INT_CTL_RF_RDY) {
368 sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH);
369 /* Only clear the interrupt _after_ draining the FIFO */
370 sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_RF_RDY);
371 return IRQ_HANDLED;
372 }
373
374 /* Transmit FIFO 3/4 empty */
375 if (status & SUN6I_INT_CTL_TF_ERQ) {
376 sun6i_spi_fill_fifo(sspi, SUN6I_FIFO_DEPTH);
377
378 if (!sspi->len)
379 /* nothing left to transmit */
380 sun6i_spi_disable_interrupt(sspi, SUN6I_INT_CTL_TF_ERQ);
381
382 /* Only clear the interrupt _after_ re-seeding the FIFO */
383 sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TF_ERQ);
384
385 return IRQ_HANDLED;
386 }
387
316 return IRQ_NONE; 388 return IRQ_NONE;
317} 389}
318 390