1 /*
2 * Copyright (C) Cvitek Co., Ltd. 2019-2020. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <errno.h>
17 #include <rtthread.h>
18 #include <string.h>
19 #include <stdio.h>
20
21 #include "mmio.h"
22 #include "dw_spi.h"
23
24 #include <rthw.h>
25
26 #ifdef SPI_DEBUG
27 #define SP_DEBUG_LOG(fmt, ...) \
28 do { \
29 rt_kprintf(fmt, ##__VA_ARGS__); \
30 } while(0)
31 #else
32 #define SP_DEBUG_LOG(fmt, ...)
33 #endif
34
35 /* Restart the controller, disable all interrupts, clean rx fifo */
spi_hw_init(struct dw_spi * dws)36 void spi_hw_init(struct dw_spi *dws)
37 {
38 /*
39 * Try to detect the FIFO depth if not set by interface driver,
40 * the depth could be from 2 to 256 from HW spec
41 */
42 if (!dws->fifo_len) {
43 uint32_t fifo;
44
45 for (fifo = 1; fifo < 256; fifo++) {
46 dw_writel(dws, CVI_DW_SPI_TXFTLR, fifo);
47 if (fifo != dw_readl(dws, CVI_DW_SPI_TXFTLR))
48 break;
49 }
50 dw_writel(dws, CVI_DW_SPI_TXFTLR, 0);
51
52 dws->fifo_len = (fifo == 1) ? 0 : fifo;
53
54 SP_DEBUG_LOG("Detected FIFO size: %u bytes\n", dws->fifo_len);
55 }
56 }
57
min3(uint32_t a,uint32_t b,uint32_t c)58 uint32_t min3(uint32_t a, uint32_t b, uint32_t c)
59 {
60 uint32_t tmp;
61
62 tmp = (a < b) ? a : b;
63 return (tmp < c) ? tmp : c;
64 }
65
cpu_relax(void)66 static inline void cpu_relax(void)
67 {
68 //asm volatile("" ::: "memory");
69 }
70
tx_max(struct dw_spi * dws)71 static inline uint32_t tx_max(struct dw_spi *dws)
72 {
73 uint32_t tx_left, tx_room, rxtx_gap, temp;
74 cpu_relax();
75 tx_left = dws->tx_len;
76 tx_room = dws->fifo_len - dw_readl(dws, CVI_DW_SPI_TXFLR);
77
78 /*
79 * Another concern is about the tx/rx mismatch, we
80 * though to use (dws->fifo_len - rxflr - txflr) as
81 * one maximum value for tx, but it doesn't cover the
82 * data which is out of tx/rx fifo and inside the
83 * shift registers. So a control from sw point of
84 * view is taken.
85 */
86
87 SP_DEBUG_LOG("tx left: %#x, tx room: %#x\n", tx_left, tx_room);
88 if (dws->rx != NULL && dws->tx != NULL) {
89 cpu_relax();
90 rxtx_gap = dws->fifo_len - (dws->rx_len - dws->tx_len);
91 temp = min3(tx_left, tx_room, (uint32_t)(rxtx_gap));
92 } else {
93 temp = tx_left < tx_room ? tx_left : tx_room;
94 }
95
96 SP_DEBUG_LOG("temp: %#x\n", temp);
97 return temp;
98 }
99
dw_writer(struct dw_spi * dws)100 void dw_writer(struct dw_spi *dws)
101 {
102 uint32_t max;
103 uint16_t txw = 0;
104
105 max = tx_max(dws);
106 SP_DEBUG_LOG("max: %#x \n", max);
107 while (max--) {
108 if (dws->tx) {
109 if (dws->n_bytes == 1)
110 txw = *(uint8_t *)(dws->tx);
111 else
112 txw = *(uint16_t *)(dws->tx);
113 }
114 dw_writel(dws, CVI_DW_SPI_DR, txw);
115 dws->tx += dws->n_bytes;
116 --dws->tx_len;
117 }
118 }
119
rx_max(struct dw_spi * dws)120 static inline uint32_t rx_max(struct dw_spi *dws)
121 {
122 uint32_t temp;
123 uint32_t rx_left = dws->rx_len;
124 uint32_t data_in_fifo = dw_readl(dws, CVI_DW_SPI_RXFLR);
125
126 temp = (rx_left < data_in_fifo ? rx_left : data_in_fifo);
127 SP_DEBUG_LOG("data_in_fifo:%u temp: %u\n", data_in_fifo, temp);
128 return temp;
129 }
130
dw_spi_check_status(struct dw_spi * dws,bool raw)131 int dw_spi_check_status(struct dw_spi *dws, bool raw)
132 {
133 uint32_t irq_status;
134 int ret = 0;
135
136 if (raw)
137 irq_status = dw_readl(dws, CVI_DW_SPI_RISR);
138 else
139 irq_status = dw_readl(dws, CVI_DW_SPI_ISR);
140
141 if (irq_status & CVI_SPI_INT_RXOI) {
142 SP_DEBUG_LOG("RX FIFO overflow detected\n");
143 ret = -1;
144 }
145
146 if (irq_status & CVI_SPI_INT_RXUI) {
147 SP_DEBUG_LOG("RX FIFO underflow detected\n");
148 ret = -1;
149 }
150
151 if (irq_status & CVI_SPI_INT_TXOI) {
152 SP_DEBUG_LOG("TX FIFO overflow detected\n");
153 ret = -1;
154 }
155
156 if (ret)
157 spi_reset_chip(dws);
158
159 return ret;
160 }
161
dw_reader(struct dw_spi * dws)162 void dw_reader(struct dw_spi *dws)
163 {
164 uint32_t max;
165 uint16_t rxw;
166
167 max = rx_max(dws);
168 SP_DEBUG_LOG("max: %#x \n", max);
169 while (max--) {
170 rxw = dw_readl(dws, CVI_DW_SPI_DR);
171 if (dws->rx) {
172 if (dws->n_bytes == 1)
173 *(uint8_t *)(dws->rx) = rxw;
174 else
175 *(uint16_t *)(dws->rx) = rxw;
176 dws->rx += dws->n_bytes;
177 }
178 --dws->rx_len;
179 }
180 }
181
spi_delay_to_ns(struct spi_delay * _delay,struct dw_spi * dws)182 int spi_delay_to_ns(struct spi_delay *_delay, struct dw_spi *dws)
183 {
184 uint32_t delay = _delay->value;
185 uint32_t unit = _delay->unit;
186 uint32_t hz;
187
188 if (!delay)
189 return 0;
190
191 switch (unit) {
192 case SPI_DELAY_UNIT_USECS:
193 delay *= 1000;
194 break;
195 case SPI_DELAY_UNIT_NSECS: /* nothing to do here */
196 break;
197 case SPI_DELAY_UNIT_SCK:
198 /* clock cycles need to be obtained from spi_transfer */
199 if (!dws)
200 return -1;
201 /* if there is no effective speed know, then approximate
202 * by underestimating with half the requested hz
203 */
204 hz = dws->speed_hz / 2;
205 if (!hz)
206 return -1;
207 delay *= DIV_ROUND_UP(1000000000, hz);
208 break;
209 default:
210 return -EINVAL;
211 }
212
213 return delay;
214 }
215
_spi_transfer_delay_ns(uint32_t ns)216 static void _spi_transfer_delay_ns(uint32_t ns)
217 {
218 if (!ns)
219 return;
220 if (ns <= 1000) {
221 rt_hw_us_delay(1);
222 } else {
223 uint32_t us = DIV_ROUND_UP(ns, 1000);
224 rt_hw_us_delay(us);
225 }
226 }
227
spi_delay_exec(struct spi_delay * _delay,struct dw_spi * dws)228 int spi_delay_exec(struct spi_delay *_delay, struct dw_spi *dws)
229 {
230 int delay;
231
232 if (!_delay)
233 return -1;
234
235 delay = spi_delay_to_ns(_delay, dws);
236 if (delay < 0)
237 return delay;
238
239 _spi_transfer_delay_ns(delay);
240
241 return 0;
242 }
243
poll_transfer(struct dw_spi * dws)244 int poll_transfer(struct dw_spi *dws)
245 {
246 struct spi_delay delay;
247 uint16_t nbits;
248 delay.unit = SPI_DELAY_UNIT_SCK;
249 nbits = dws->n_bytes * BITS_PER_BYTE;
250 int ret = 0;
251
252 do
253 {
254 dw_writer(dws);
255 cpu_relax();
256
257 delay.value = nbits * (dws->rx_len - dws->tx_len);
258 spi_delay_exec(&delay, dws);
259 dw_reader(dws);
260 cpu_relax();
261 ret = dw_spi_check_status(dws, true);
262 if (ret)
263 return ret;
264 } while (dws->rx_len && dws->tx_len);
265
266 return 0;
267 }
268
set_tran_mode(struct dw_spi * dws)269 void set_tran_mode(struct dw_spi *dws)
270 {
271 uint32_t reg = dw_readl(dws, CVI_DW_SPI_CTRLR0);
272 uint8_t tmode;
273
274 if (dws->rx && dws->tx) {
275 tmode = CVI_SPI_TMOD_TR;
276 } else if (dws->rx) {
277 tmode = CVI_SPI_TMOD_RO;
278 } else {
279 tmode = CVI_SPI_TMOD_TO;
280 }
281 reg &= ~CVI_SPI_TMOD_MASK;
282 reg |= (tmode << CVI_SPI_TMOD_OFFSET);
283
284 dw_writel(dws, CVI_DW_SPI_CTRLR0, reg);
285 }
286
dw_spi_set_controller_mode(struct dw_spi * dws,uint8_t enable_master)287 void dw_spi_set_controller_mode(struct dw_spi *dws, uint8_t enable_master)
288 {
289 /* do not support to switch controller mode, it is default master mode */
290 }
291
dw_spi_set_cs(struct dw_spi * dws,bool enable,uint32_t index)292 void dw_spi_set_cs(struct dw_spi *dws, bool enable, uint32_t index)
293 {
294 uint32_t reg = dw_readl(dws, CVI_DW_SPI_SER);
295
296 if (enable)
297 dw_writel(dws, CVI_DW_SPI_SER, reg | BIT(index));
298 else
299 dw_writel(dws, CVI_DW_SPI_SER, reg & ~BIT(index));
300 }
301
dw_spi_set_polarity_and_phase(struct dw_spi * dws,uint8_t format)302 void dw_spi_set_polarity_and_phase(struct dw_spi *dws, uint8_t format)
303 {
304 uint32_t reg = dw_readl(dws, CVI_DW_SPI_CTRLR0);
305 reg &= ~(0x3 << 6);
306
307 switch (format) {
308 case SPI_FORMAT_CPOL0_CPHA0:
309 reg |= (SPI_MODE_0 << 6);
310 break;
311
312 case SPI_FORMAT_CPOL0_CPHA1:
313 reg |= (SPI_MODE_1 << 6);
314 break;
315
316 case SPI_FORMAT_CPOL1_CPHA0:
317 reg |= (SPI_MODE_2 << 6);
318 break;
319
320 case SPI_FORMAT_CPOL1_CPHA1:
321 reg |= (SPI_MODE_3 << 6);
322 break;
323
324 default:
325 reg = dw_readl(dws, CVI_DW_SPI_CTRLR0);
326 break;
327 }
328 SP_DEBUG_LOG("set phase and polarity: %#x\n", reg);
329 dw_writel(dws, CVI_DW_SPI_CTRLR0, reg);
330 }
331
dw_spi_set_clock(struct dw_spi * dws,uint32_t clock_in,uint32_t clock_out)332 uint32_t dw_spi_set_clock(struct dw_spi *dws, uint32_t clock_in, uint32_t clock_out)
333 {
334 uint16_t div;
335
336 div = (DIV_ROUND_UP(clock_in, clock_out) + 1) & 0xfffe;
337 dws->speed_hz = clock_in / div;
338 SP_DEBUG_LOG("clk div value is: %u, hz:%u\n", div, dws->speed_hz);
339 spi_set_clk(dws, div);
340 return dws->speed_hz;
341 }
342
dw_spi_set_data_frame_len(struct dw_spi * dws,uint32_t size)343 int dw_spi_set_data_frame_len(struct dw_spi *dws, uint32_t size)
344 {
345 uint32_t temp = dw_readl(dws, CVI_DW_SPI_CTRLR0);
346 temp &= ~0xf;
347
348 if (size == 8) {
349 dws->n_bytes = 1;
350 } else if (size == 16) {
351 dws->n_bytes = 2;
352 } else {
353 SP_DEBUG_LOG("do not support %u bit data!\n", size);
354 return -1;
355 }
356 temp |= (size - 1);
357 dw_writel(dws, CVI_DW_SPI_CTRLR0, temp);
358 SP_DEBUG_LOG("set data frame len: %#x\n", temp);
359 return 0;
360 }
361
dw_spi_show_regs(struct dw_spi * dws)362 void dw_spi_show_regs(struct dw_spi *dws)
363 {
364 SP_DEBUG_LOG("CTRLR0: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_CTRLR0));
365 SP_DEBUG_LOG("CTRLR1: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_CTRLR1));
366 SP_DEBUG_LOG("SSIENR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_SSIENR));
367 SP_DEBUG_LOG("SER: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_SER));
368 SP_DEBUG_LOG("BAUDR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_BAUDR));
369 SP_DEBUG_LOG("TXFTLR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_TXFTLR));
370 SP_DEBUG_LOG("RXFTLR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_RXFTLR));
371 SP_DEBUG_LOG("TXFLR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_TXFLR));
372 SP_DEBUG_LOG("RXFLR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_RXFLR));
373 SP_DEBUG_LOG("SR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_SR));
374 SP_DEBUG_LOG("IMR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_IMR));
375 SP_DEBUG_LOG("ISR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_ISR));
376 SP_DEBUG_LOG("DMACR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_DMACR));
377 SP_DEBUG_LOG("DMATDLR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_DMATDLR));
378 SP_DEBUG_LOG("DMARDLR: \t0x%08x\n", dw_readl(dws, CVI_DW_SPI_DMARDLR));
379 }
380