drv_qspi.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. /**************************************************************************//**
  2. *
  3. * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. *
  7. * Change Logs:
  8. * Date Author Notes
  9. * 2020-11-11 Wayne First version
  10. *
  11. ******************************************************************************/
  12. #include <rtconfig.h>
  13. #if defined(BSP_USING_QSPI)
  14. #define LOG_TAG "drv.qspi"
  15. #define DBG_ENABLE
  16. #define DBG_SECTION_NAME LOG_TAG
  17. #define DBG_LEVEL DBG_INFO
  18. #define DBG_COLOR
  19. #include <rtdbg.h>
  20. #include <rthw.h>
  21. #include <rtdef.h>
  22. #include <drv_spi.h>
  23. /* Private define ---------------------------------------------------------------*/
  24. enum
  25. {
  26. QSPI_START = -1,
  27. #if defined(BSP_USING_QSPI0)
  28. QSPI0_IDX,
  29. #endif
  30. QSPI_CNT
  31. };
  32. /* Private typedef --------------------------------------------------------------*/
  33. /* Private functions ------------------------------------------------------------*/
  34. static rt_err_t nu_qspi_bus_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration);
  35. static rt_uint32_t nu_qspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message);
  36. static int nu_qspi_register_bus(struct nu_spi *qspi_bus, const char *name);
  37. /* Public functions -------------------------------------------------------------*/
  38. /* Private variables ------------------------------------------------------------*/
  39. static struct rt_spi_ops nu_qspi_poll_ops =
  40. {
  41. .configure = nu_qspi_bus_configure,
  42. .xfer = nu_qspi_bus_xfer,
  43. };
  44. static struct nu_spi nu_qspi_arr [] =
  45. {
  46. #if defined(BSP_USING_QSPI0)
  47. {
  48. .name = "qspi0",
  49. .spi_base = (SPI_T *)QSPI0,
  50. .rstidx = QSPI0RST,
  51. .clkidx = QSPI0CKEN,
  52. #if defined(BSP_USING_SPI_PDMA)
  53. #if defined(BSP_USING_QSPI0_PDMA)
  54. .pdma_perp_tx = PDMA_QSPI0_TX,
  55. .pdma_perp_rx = PDMA_QSPI0_RX,
  56. #else
  57. .pdma_perp_tx = NU_PDMA_UNUSED,
  58. .pdma_perp_rx = NU_PDMA_UNUSED,
  59. #endif
  60. #endif
  61. },
  62. #endif
  63. }; /* qspi nu_qspi */
  64. static rt_err_t nu_qspi_bus_configure(struct rt_spi_device *device,
  65. struct rt_spi_configuration *configuration)
  66. {
  67. struct nu_spi *spi_bus;
  68. rt_uint32_t u32SPIMode;
  69. rt_err_t ret = RT_EOK;
  70. RT_ASSERT(device != RT_NULL);
  71. RT_ASSERT(configuration != RT_NULL);
  72. spi_bus = (struct nu_spi *) device->bus;
  73. /* Check mode */
  74. switch (configuration->mode & RT_SPI_MODE_3)
  75. {
  76. case RT_SPI_MODE_0:
  77. u32SPIMode = SPI_MODE_0;
  78. break;
  79. case RT_SPI_MODE_1:
  80. u32SPIMode = SPI_MODE_1;
  81. break;
  82. case RT_SPI_MODE_2:
  83. u32SPIMode = SPI_MODE_2;
  84. break;
  85. case RT_SPI_MODE_3:
  86. u32SPIMode = SPI_MODE_3;
  87. break;
  88. default:
  89. ret = RT_EIO;
  90. goto exit_nu_qspi_bus_configure;
  91. }
  92. /* Check data width */
  93. if (!(configuration->data_width == 8 ||
  94. configuration->data_width == 16 ||
  95. configuration->data_width == 24 ||
  96. configuration->data_width == 32))
  97. {
  98. ret = RT_EINVAL;
  99. goto exit_nu_qspi_bus_configure;
  100. }
  101. /* Need to initialize new configuration? */
  102. if (rt_memcmp(configuration, &spi_bus->configuration, sizeof(struct rt_spi_configuration)) != 0)
  103. {
  104. rt_memcpy(&spi_bus->configuration, configuration, sizeof(struct rt_spi_configuration));
  105. QSPI_Open((QSPI_T *)spi_bus->spi_base, SPI_MASTER, u32SPIMode, configuration->data_width, configuration->max_hz);
  106. if (configuration->mode & RT_SPI_CS_HIGH)
  107. {
  108. /* Set CS pin to LOW */
  109. SPI_SET_SS_LOW(spi_bus->spi_base);
  110. }
  111. else
  112. {
  113. /* Set CS pin to HIGH */
  114. SPI_SET_SS_HIGH(spi_bus->spi_base);
  115. }
  116. if (configuration->mode & RT_SPI_MSB)
  117. {
  118. /* Set sequence to MSB first */
  119. SPI_SET_MSB_FIRST(spi_bus->spi_base);
  120. }
  121. else
  122. {
  123. /* Set sequence to LSB first */
  124. SPI_SET_LSB_FIRST(spi_bus->spi_base);
  125. }
  126. }
  127. /* Clear SPI RX FIFO */
  128. nu_spi_drain_rxfifo(spi_bus->spi_base);
  129. exit_nu_qspi_bus_configure:
  130. return -(ret);
  131. }
  132. static int nu_qspi_mode_config(struct nu_spi *qspi_bus, rt_uint8_t *tx, rt_uint8_t *rx, int qspi_lines)
  133. {
  134. QSPI_T *qspi_base = (QSPI_T *)qspi_bus->spi_base;
  135. if (qspi_lines > 1)
  136. {
  137. if (tx)
  138. {
  139. switch (qspi_lines)
  140. {
  141. case 2:
  142. QSPI_ENABLE_DUAL_OUTPUT_MODE(qspi_base);
  143. break;
  144. case 4:
  145. QSPI_ENABLE_QUAD_OUTPUT_MODE(qspi_base);
  146. break;
  147. default:
  148. LOG_E("Data line is not supported.\n");
  149. break;
  150. }
  151. }
  152. else
  153. {
  154. switch (qspi_lines)
  155. {
  156. case 2:
  157. QSPI_ENABLE_DUAL_INPUT_MODE(qspi_base);
  158. break;
  159. case 4:
  160. QSPI_ENABLE_QUAD_INPUT_MODE(qspi_base);
  161. break;
  162. default:
  163. LOG_E("Data line is not supported.\n");
  164. break;
  165. }
  166. }
  167. }
  168. else
  169. {
  170. QSPI_DISABLE_DUAL_MODE(qspi_base);
  171. QSPI_DISABLE_QUAD_MODE(qspi_base);
  172. }
  173. return qspi_lines;
  174. }
  175. static rt_uint32_t nu_qspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
  176. {
  177. struct nu_spi *qspi_bus;
  178. struct rt_qspi_configuration *qspi_configuration;
  179. struct rt_qspi_message *qspi_message;
  180. rt_uint8_t u8last = 1;
  181. rt_uint8_t bytes_per_word;
  182. QSPI_T *qspi_base;
  183. rt_uint32_t u32len = 0;
  184. RT_ASSERT(device != RT_NULL);
  185. RT_ASSERT(message != RT_NULL);
  186. qspi_bus = (struct nu_spi *) device->bus;
  187. qspi_base = (QSPI_T *)qspi_bus->spi_base;
  188. qspi_configuration = &qspi_bus->configuration;
  189. bytes_per_word = qspi_configuration->parent.data_width / 8;
  190. if (message->cs_take && !(qspi_configuration->parent.mode & RT_SPI_NO_CS))
  191. {
  192. if (qspi_configuration->parent.mode & RT_SPI_CS_HIGH)
  193. {
  194. QSPI_SET_SS_HIGH(qspi_base);
  195. }
  196. else
  197. {
  198. QSPI_SET_SS_LOW(qspi_base);
  199. }
  200. }
  201. qspi_message = (struct rt_qspi_message *)message;
  202. /* Command + Address + Dummy + Data */
  203. /* Command stage */
  204. if (qspi_message->instruction.content != 0)
  205. {
  206. u8last = nu_qspi_mode_config(qspi_bus, (rt_uint8_t *) &qspi_message->instruction.content, RT_NULL, qspi_message->instruction.qspi_lines);
  207. nu_spi_transfer((struct nu_spi *)qspi_bus,
  208. (rt_uint8_t *) &qspi_message->instruction.content,
  209. RT_NULL,
  210. 1,
  211. 1);
  212. }
  213. /* Address stage */
  214. if (qspi_message->address.size > 0)
  215. {
  216. rt_uint32_t u32ReversedAddr = 0;
  217. rt_uint32_t u32AddrNumOfByte = qspi_message->address.size / 8;
  218. switch (u32AddrNumOfByte)
  219. {
  220. case 1:
  221. u32ReversedAddr = (qspi_message->address.content & 0xff);
  222. break;
  223. case 2:
  224. nu_set16_be((rt_uint8_t *)&u32ReversedAddr, qspi_message->address.content);
  225. break;
  226. case 3:
  227. nu_set24_be((rt_uint8_t *)&u32ReversedAddr, qspi_message->address.content);
  228. break;
  229. case 4:
  230. nu_set32_be((rt_uint8_t *)&u32ReversedAddr, qspi_message->address.content);
  231. break;
  232. default:
  233. RT_ASSERT(0);
  234. break;
  235. }
  236. u8last = nu_qspi_mode_config(qspi_bus, (rt_uint8_t *)&u32ReversedAddr, RT_NULL, qspi_message->address.qspi_lines);
  237. nu_spi_transfer((struct nu_spi *)qspi_bus,
  238. (rt_uint8_t *) &u32ReversedAddr,
  239. RT_NULL,
  240. u32AddrNumOfByte,
  241. 1);
  242. }
  243. /* alternate_bytes stage */
  244. if ((qspi_message->alternate_bytes.size > 0) && (qspi_message->alternate_bytes.size <= 4))
  245. {
  246. rt_uint32_t u32AlternateByte = 0;
  247. rt_uint32_t u32NumOfByte = qspi_message->alternate_bytes.size / 8;
  248. switch (u32NumOfByte)
  249. {
  250. case 1:
  251. u32AlternateByte = (qspi_message->alternate_bytes.content & 0xff);
  252. break;
  253. case 2:
  254. nu_set16_be((rt_uint8_t *)&u32AlternateByte, qspi_message->alternate_bytes.content);
  255. break;
  256. case 3:
  257. nu_set24_be((rt_uint8_t *)&u32AlternateByte, qspi_message->alternate_bytes.content);
  258. break;
  259. case 4:
  260. nu_set32_be((rt_uint8_t *)&u32AlternateByte, qspi_message->alternate_bytes.content);
  261. break;
  262. default:
  263. RT_ASSERT(0);
  264. break;
  265. }
  266. u8last = nu_qspi_mode_config(qspi_bus, (rt_uint8_t *)&u32AlternateByte, RT_NULL, qspi_message->alternate_bytes.qspi_lines);
  267. nu_spi_transfer((struct nu_spi *)qspi_bus,
  268. (rt_uint8_t *) &u32AlternateByte,
  269. RT_NULL,
  270. u32NumOfByte,
  271. 1);
  272. }
  273. /* Dummy_cycles stage */
  274. if (qspi_message->dummy_cycles > 0)
  275. {
  276. qspi_bus->dummy = 0x00;
  277. u8last = nu_qspi_mode_config(qspi_bus, (rt_uint8_t *) &qspi_bus->dummy, RT_NULL, u8last);
  278. nu_spi_transfer((struct nu_spi *)qspi_bus,
  279. (rt_uint8_t *) &qspi_bus->dummy,
  280. RT_NULL,
  281. qspi_message->dummy_cycles / (8 / u8last),
  282. 1);
  283. }
  284. if (message->length > 0)
  285. {
  286. /* Data stage */
  287. nu_qspi_mode_config(qspi_bus, (rt_uint8_t *) message->send_buf, (rt_uint8_t *) message->recv_buf, qspi_message->qspi_data_lines);
  288. nu_spi_transfer((struct nu_spi *)qspi_bus,
  289. (rt_uint8_t *) message->send_buf,
  290. (rt_uint8_t *) message->recv_buf,
  291. message->length,
  292. bytes_per_word);
  293. u32len = message->length;
  294. }
  295. else
  296. {
  297. u32len = 1;
  298. }
  299. if (message->cs_release && !(qspi_configuration->parent.mode & RT_SPI_NO_CS))
  300. {
  301. if (qspi_configuration->parent.mode & RT_SPI_CS_HIGH)
  302. {
  303. QSPI_SET_SS_LOW(qspi_base);
  304. }
  305. else
  306. {
  307. QSPI_SET_SS_HIGH(qspi_base);
  308. }
  309. }
  310. return u32len;
  311. }
  312. static int nu_qspi_register_bus(struct nu_spi *qspi_bus, const char *name)
  313. {
  314. return rt_qspi_bus_register(&qspi_bus->dev, name, &nu_qspi_poll_ops);
  315. }
  316. /**
  317. * Hardware SPI Initial
  318. */
  319. static int rt_hw_qspi_init(void)
  320. {
  321. rt_uint8_t i;
  322. for (i = (QSPI_START + 1); i < QSPI_CNT; i++)
  323. {
  324. nu_sys_ipclk_enable(nu_qspi_arr[i].clkidx);
  325. nu_sys_ip_reset(nu_qspi_arr[i].rstidx);
  326. nu_qspi_register_bus(&nu_qspi_arr[i], nu_qspi_arr[i].name);
  327. #if defined(BSP_USING_SPI_PDMA)
  328. nu_qspi_arr[i].pdma_chanid_tx = -1;
  329. nu_qspi_arr[i].pdma_chanid_rx = -1;
  330. #endif
  331. #if defined(BSP_USING_QSPI_PDMA)
  332. if ((nu_qspi_arr[i].pdma_perp_tx != NU_PDMA_UNUSED) && (nu_qspi_arr[i].pdma_perp_rx != NU_PDMA_UNUSED))
  333. {
  334. if (nu_hw_spi_pdma_allocate(&nu_qspi_arr[i]) != RT_EOK)
  335. {
  336. LOG_E("Failed to allocate DMA channels for %s. We will use poll-mode for this bus.\n", nu_qspi_arr[i].name);
  337. }
  338. }
  339. #endif
  340. }
  341. return 0;
  342. }
  343. INIT_DEVICE_EXPORT(rt_hw_qspi_init);
  344. rt_err_t nu_qspi_bus_attach_device(const char *bus_name, const char *device_name, rt_uint8_t data_line_width, void (*enter_qspi_mode)(), void (*exit_qspi_mode)())
  345. {
  346. struct rt_qspi_device *qspi_device = RT_NULL;
  347. rt_err_t result = RT_EOK;
  348. RT_ASSERT(bus_name != RT_NULL);
  349. RT_ASSERT(device_name != RT_NULL);
  350. RT_ASSERT(data_line_width == 1 || data_line_width == 2 || data_line_width == 4);
  351. qspi_device = (struct rt_qspi_device *)rt_malloc(sizeof(struct rt_qspi_device));
  352. if (qspi_device == RT_NULL)
  353. {
  354. LOG_E("no memory, qspi bus attach device failed!\n");
  355. result = -RT_ENOMEM;
  356. goto __exit;
  357. }
  358. qspi_device->enter_qspi_mode = enter_qspi_mode;
  359. qspi_device->exit_qspi_mode = exit_qspi_mode;
  360. qspi_device->config.qspi_dl_width = data_line_width;
  361. result = rt_spi_bus_attach_device(&qspi_device->parent, device_name, bus_name, RT_NULL);
  362. __exit:
  363. if (result != RT_EOK)
  364. {
  365. if (qspi_device)
  366. {
  367. rt_free(qspi_device);
  368. }
  369. }
  370. return result;
  371. }
  372. #endif //#if defined(BSP_USING_QSPI)