dw_spi.c 9.7 KB

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