dw_spi.c 9.8 KB

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