fpgasvc.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. #include "common.h"
  2. #include "config.h"
  3. #include "fpga.h"
  4. #include "esplink.h"
  5. #include <driver/gpio.h>
  6. #include <driver/spi_common.h>
  7. #include <driver/spi_master.h>
  8. #define PIN_FPGA_INT 9
  9. #define PIN_FPGA_CS 10
  10. #define PIN_FPGA_IO0 11
  11. #define PIN_FPGA_CLK 12
  12. #define PIN_FPGA_IO1 13
  13. #define FPGA_SPI_HOST FSPI /* SPI2 */
  14. #define FPGA_PRIORITY 3
  15. static spi_bus_config_t spi_bus_config = {
  16. .data0_io_num = PIN_FPGA_IO0,
  17. .data1_io_num = PIN_FPGA_IO1,
  18. .sclk_io_num = PIN_FPGA_CLK,
  19. .data2_io_num = -1,
  20. .data3_io_num = -1,
  21. .data4_io_num = -1,
  22. .data5_io_num = -1,
  23. .data6_io_num = -1,
  24. .data7_io_num = -1,
  25. .max_transfer_sz = 4096,
  26. .flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_DUAL
  27. };
  28. static const spi_device_interface_config_t spi_device_interface_config = {
  29. .command_bits = 8,
  30. .address_bits = 32,
  31. .dummy_bits = 0,
  32. .mode = 0,
  33. .cs_ena_pretrans = 0,
  34. .cs_ena_posttrans = 0,
  35. .clock_speed_hz = SPI_MASTER_FREQ_40M,
  36. .spics_io_num = PIN_FPGA_CS,
  37. .flags = SPI_DEVICE_HALFDUPLEX,
  38. .queue_size = 4 /* Maybe? */
  39. };
  40. static spi_device_handle_t spi_handle;
  41. static TaskHandle_t fpga_task;
  42. static SemaphoreHandle_t spi_mutex;
  43. #define NOTIFY_INDEX 0
  44. static void ARDUINO_ISR_ATTR fpga_interrupt(void)
  45. {
  46. BaseType_t do_wakeup = pdFALSE;
  47. if (!fpga_task)
  48. return;
  49. xTaskNotifyIndexedFromISR(fpga_task, NOTIFY_INDEX, 1, eIncrement,
  50. &do_wakeup);
  51. if (do_wakeup)
  52. portYIELD_FROM_ISR(do_wakeup);
  53. }
  54. static void fpga_service_task(void *);
  55. int fpga_service_start(void)
  56. {
  57. esp_err_t err;
  58. pinMode(PIN_FPGA_INT, INPUT_PULLUP);
  59. if (!spi_mutex) {
  60. spi_mutex = xSemaphoreCreateMutex();
  61. if (!spi_mutex)
  62. goto failed;
  63. }
  64. xSemaphoreTake(spi_mutex, portMAX_DELAY);
  65. err = spi_bus_initialize(FPGA_SPI_HOST, &spi_bus_config, SPI_DMA_CH_AUTO);
  66. if (err)
  67. goto failed;
  68. err = spi_bus_add_device(FPGA_SPI_HOST, &spi_device_interface_config,
  69. &spi_handle);
  70. if (err)
  71. goto failed;
  72. /* Only device on this bus, so acquire it permanently */
  73. spi_device_acquire_bus(spi_handle, portMAX_DELAY);
  74. xSemaphoreGive(spi_mutex);
  75. if (!fpga_task) {
  76. /* The ordering here attempts to avoid race conditions... */
  77. if (xTaskCreate(fpga_service_task, "fpga_svc", 4096, NULL,
  78. FPGA_PRIORITY, &fpga_task) != pdPASS)
  79. goto failed;
  80. attachInterrupt(PIN_FPGA_INT, fpga_interrupt, FALLING);
  81. xTaskNotifyIndexed(fpga_task, NOTIFY_INDEX, 1, eIncrement);
  82. esp_register_shutdown_handler(fpga_service_stop);
  83. }
  84. /* All good (hopefully?) */
  85. return 0;
  86. failed:
  87. printf("[FPGA] Failed to initialize FPGA SPI bus\n");
  88. if (spi_mutex)
  89. xSemaphoreGive(spi_mutex);
  90. fpga_service_stop();
  91. return -1;
  92. }
  93. void fpga_service_stop(void)
  94. {
  95. if (spi_mutex) {
  96. xSemaphoreTake(spi_mutex, portMAX_DELAY);
  97. if (fpga_task) {
  98. esp_unregister_shutdown_handler(fpga_service_stop);
  99. detachInterrupt(PIN_FPGA_INT);
  100. vTaskDelete(fpga_task);
  101. fpga_task = NULL;
  102. }
  103. if (spi_handle) {
  104. spi_device_release_bus(spi_handle);
  105. spi_bus_remove_device(spi_handle);
  106. spi_bus_free(FPGA_SPI_HOST);
  107. spi_handle = NULL;
  108. }
  109. xSemaphoreGive(spi_mutex);
  110. }
  111. printf("[FPGA] FPGA services stopped\n");
  112. }
  113. #define FPGA_CMD_IRQ(x) ((x) << 0)
  114. #define FPGA_CMD_ACK(x) ((x) << 2)
  115. #define FPGA_CMD_ACK2 (2 << 2)
  116. #define FPGA_CMD_ACK3 (3 << 2)
  117. #define FPGA_CMD_WR (0 << 4)
  118. #define FPGA_CMD_RD (1 << 4)
  119. #define FPGA_CMD_CONTROL_MASK 0x0f
  120. #define FPGA_HDR_ADDR 0x40000000
  121. static esp_err_t fpga_io_write(unsigned int cmd, uint32_t addr,
  122. const void *data, size_t len)
  123. {
  124. spi_transaction_ext_t trans;
  125. esp_err_t err;
  126. if (!len && !(cmd & ~FPGA_CMD_RD))
  127. return ESP_OK;
  128. memset(&trans, 0, sizeof trans);
  129. trans.base.flags =
  130. SPI_TRANS_MODE_DIO |
  131. SPI_TRANS_MULTILINE_CMD |
  132. SPI_TRANS_MULTILINE_ADDR;
  133. trans.base.cmd = cmd | ~FPGA_CMD_RD;
  134. trans.base.addr = addr;
  135. trans.base.tx_buffer = data;
  136. trans.base.length = len << 3;
  137. xSemaphoreTake(spi_mutex, portMAX_DELAY);
  138. err = spi_device_transmit(spi_handle, (spi_transaction_t *)&trans);
  139. xSemaphoreGive(spi_mutex);
  140. return err;
  141. }
  142. static esp_err_t fpga_io_read(unsigned int cmd, uint32_t addr,
  143. void *data, size_t len)
  144. {
  145. spi_transaction_ext_t trans;
  146. esp_err_t err;
  147. if (!len && !(cmd & ~FPGA_CMD_RD))
  148. return ESP_OK;
  149. memset(&trans, 0, sizeof trans);
  150. trans.base.flags =
  151. SPI_TRANS_MODE_DIO |
  152. SPI_TRANS_VARIABLE_DUMMY |
  153. SPI_TRANS_MULTILINE_CMD |
  154. SPI_TRANS_MULTILINE_ADDR;
  155. trans.base.cmd = cmd | FPGA_CMD_RD;
  156. trans.base.addr = addr;
  157. trans.base.rx_buffer = data;
  158. /* Emulate partial word read by adding dummy bits for offset */
  159. trans.dummy_bits = 16 + ((addr & 3) << 2);
  160. trans.base.rxlength = len << 3;
  161. xSemaphoreTake(spi_mutex, portMAX_DELAY);
  162. err = spi_device_transmit(spi_handle, (spi_transaction_t *)&trans);
  163. xSemaphoreGive(spi_mutex);
  164. return err;
  165. }
  166. /* CMD here can be interrupt flags, for example */
  167. static uint32_t fpga_io_status(unsigned int cmd)
  168. {
  169. spi_transaction_ext_t trans;
  170. esp_err_t err;
  171. memset(&trans, 0, sizeof trans);
  172. trans.base.flags =
  173. SPI_TRANS_MODE_DIO |
  174. SPI_TRANS_MULTILINE_CMD |
  175. SPI_TRANS_MULTILINE_ADDR |
  176. SPI_TRANS_USE_RXDATA;
  177. trans.base.cmd = cmd | FPGA_CMD_RD;
  178. trans.base.rxlength = 32;
  179. xSemaphoreTake(spi_mutex, portMAX_DELAY);
  180. err = spi_device_transmit(spi_handle, (spi_transaction_t *)&trans);
  181. xSemaphoreGive(spi_mutex);
  182. return err ? 0 : ntohl(*(const uint32_t *)&trans.base.rx_data);
  183. }
  184. static void fpga_service_task(void *dummy)
  185. {
  186. (void)dummy;
  187. struct dram_io_head head;
  188. uint32_t status;
  189. printf("[FPGA] Starting FPGA services\n");
  190. /* If the FPGA is already up, need to issue our own active handshake */
  191. status = fpga_io_status(FPGA_CMD_IRQ(RV_IRQ_HELLO));
  192. printf("[FPGA] Link status bits = 0x%08x, int = %u\n",
  193. status, digitalRead(PIN_FPGA_INT));
  194. while (1) {
  195. /* Wait until an interrupt is received */
  196. xTaskNotifyWaitIndexed(NOTIFY_INDEX, 0, -1U, NULL, portMAX_DELAY);
  197. while (!digitalRead(PIN_FPGA_INT)) {
  198. bool ok = false;
  199. uint32_t status = fpga_io_status(0);
  200. printf("[FPGA] Link status bits = 0x%08x\n", status);
  201. if ((status & 0x000fc010) == 0x00008000) {
  202. fpga_io_read(FPGA_CMD_ACK(ESP_IRQ_READY), FPGA_HDR_ADDR,
  203. &head, sizeof head);
  204. if (head.magic == DRAM_IO_MAGIC && head.hlen >= sizeof head) {
  205. printf("[FPGA] Ready, board = %u.%u fixes %02x fpga %u\n",
  206. head.board.major, head.board.minor,
  207. head.board.fixes, head.board.fpga);
  208. char signature_string[head.signature_len+1];
  209. fpga_io_read(0, (size_t)head.signature,
  210. signature_string, head.signature_len);
  211. signature_string[head.signature_len] = '\0';
  212. fpga_io_write(0, (size_t)head.signature + 9, "GUBBAR", 6);
  213. printf("[FPGA] \"%s\"\n", signature_string);
  214. ok = true;
  215. }
  216. } else {
  217. printf("[FPGA] None or invalid FPGA response, offline\n");
  218. }
  219. }
  220. }
  221. }