fpgasvc.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  1. #include "common.h"
  2. #include "config.h"
  3. #include "fpga.h"
  4. #include "esplink.h"
  5. #include "xmalloc.h"
  6. #include <driver/gpio.h>
  7. #include <driver/spi_common.h>
  8. #include <driver/spi_master.h>
  9. #define PIN_FPGA_INT 9
  10. #define PIN_FPGA_CS 10
  11. #define PIN_FPGA_IO0 11
  12. #define PIN_FPGA_CLK 12
  13. #define PIN_FPGA_IO1 13
  14. #define FPGA_SPI_HOST FSPI /* SPI2 */
  15. #define FPGA_PRIORITY 10
  16. #define FPGA_SVC_STACK 4096
  17. static spi_bus_config_t spi_bus_config = {
  18. .data0_io_num = PIN_FPGA_IO0,
  19. .data1_io_num = PIN_FPGA_IO1,
  20. .sclk_io_num = PIN_FPGA_CLK,
  21. .data2_io_num = -1,
  22. .data3_io_num = -1,
  23. .data4_io_num = -1,
  24. .data5_io_num = -1,
  25. .data6_io_num = -1,
  26. .data7_io_num = -1,
  27. .max_transfer_sz = 4096,
  28. .flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_DUAL
  29. };
  30. #define FPGA_IOV_MAX 4
  31. static void ARDUINO_ISR_ATTR spi_callback(spi_transaction_t *);
  32. static const spi_device_interface_config_t spi_device_interface_config = {
  33. .command_bits = 8,
  34. .address_bits = 32,
  35. .dummy_bits = 0,
  36. .mode = 0,
  37. .cs_ena_pretrans = 0,
  38. .cs_ena_posttrans = 0,
  39. .clock_speed_hz = SPI_MASTER_FREQ_40M,
  40. .spics_io_num = PIN_FPGA_CS,
  41. .flags = SPI_DEVICE_HALFDUPLEX,
  42. .queue_size = FPGA_IOV_MAX,
  43. .post_cb = spi_callback
  44. };
  45. static spi_device_handle_t spi_handle;
  46. static TaskHandle_t fpga_task;
  47. static TimerHandle_t fpga_timesync_timer;
  48. static SemaphoreHandle_t spi_mutex;
  49. static EventGroupHandle_t spi_done_evgroup;
  50. static volatile bool spi_abort_all;
  51. static const volatile struct esplink_timesync *tsync_addr;
  52. #define NOTIFY_INDEX 0
  53. #define NOTIFY_FPGA (1 << 0)
  54. #define NOTIFY_ENABLE (1 << 1)
  55. #define NOTIFY_DISABLE (1 << 2)
  56. #define NOTIFY_TIMESYNC (1 << 3)
  57. #if 0
  58. #define NOTIFY_SPI (1 << 3)
  59. #define NOTIFY_RINGBUF (1 << 4)
  60. #endif
  61. static uint32_t notify_poll_for(uint32_t flags)
  62. {
  63. return ulTaskNotifyValueClearIndexed(NULL, NOTIFY_INDEX, flags);
  64. }
  65. /* This supports multiple flags set */
  66. static uint32_t notify_wait_for(uint32_t flags)
  67. {
  68. uint32_t notify_value;
  69. /* Already received? Might already have been waited for... */
  70. notify_value = notify_poll_for(flags);
  71. while (!(notify_value & flags)) {
  72. xTaskNotifyWaitIndexed(NOTIFY_INDEX, 0, flags,
  73. &notify_value, portMAX_DELAY);
  74. }
  75. return notify_value;
  76. }
  77. static void ARDUINO_ISR_ATTR fpga_notify_from_isr(uint32_t flags)
  78. {
  79. BaseType_t wakeup = pdFALSE;
  80. if (xTaskNotifyIndexedFromISR(fpga_task, NOTIFY_INDEX, flags, eSetBits,
  81. &wakeup) != pdFAIL)
  82. portYIELD_FROM_ISR(wakeup);
  83. }
  84. static void fpga_notify_from_task(uint32_t flags)
  85. {
  86. xTaskNotifyIndexed(fpga_task, NOTIFY_INDEX, flags, eSetBits);
  87. }
  88. static void ARDUINO_ISR_ATTR fpga_interrupt(void)
  89. {
  90. fpga_notify_from_isr(NOTIFY_FPGA);
  91. }
  92. static void fpga_timesync_trigger(TimerHandle_t t)
  93. {
  94. (void)t;
  95. fpga_notify_from_task(NOTIFY_TIMESYNC);
  96. }
  97. static void ARDUINO_ISR_ATTR spi_callback(spi_transaction_t *t)
  98. {
  99. size_t flags = (size_t)t->user;
  100. if (!flags)
  101. return;
  102. BaseType_t wakeup = pdFALSE;
  103. if (xEventGroupSetBitsFromISR(spi_done_evgroup, (size_t)t->user,
  104. &wakeup) != pdFAIL)
  105. portYIELD_FROM_ISR(wakeup);
  106. }
  107. static void fpga_service_task(void *);
  108. static EventGroupHandle_t fpga_service_evgroup;
  109. void fpga_service_enable(bool on)
  110. {
  111. uint32_t flag = on ? NOTIFY_ENABLE : NOTIFY_DISABLE;
  112. fpga_notify_from_task(flag);
  113. xEventGroupWaitBits(fpga_service_evgroup, flag, 0, pdTRUE, portMAX_DELAY);
  114. }
  115. esp_err_t fpga_service_init(void)
  116. {
  117. esp_err_t err;
  118. pinMode(PIN_FPGA_INT, INPUT);
  119. setenv_bool("status.max80.fpga", false);
  120. fpga_service_evgroup = null_check(xEventGroupCreate());
  121. spi_mutex = null_check(xSemaphoreCreateRecursiveMutex());
  122. spi_done_evgroup = null_check(xEventGroupCreate());
  123. /* The ordering here attempts to avoid race conditions... */
  124. if (xTaskCreate(fpga_service_task, "fpga_svc", FPGA_SVC_STACK, NULL,
  125. FPGA_PRIORITY, &fpga_task) != pdPASS)
  126. return ESP_FAIL;
  127. fpga_timesync_timer =
  128. null_check(xTimerCreate("rtc_sync", 17*configTICK_RATE_HZ,
  129. pdTRUE, NULL, fpga_timesync_trigger));
  130. esplink_init();
  131. xEventGroupSetBits(fpga_service_evgroup, NOTIFY_DISABLE);
  132. return ESP_OK;
  133. }
  134. static bool fpga_link_enable(void)
  135. {
  136. esp_err_t err;
  137. if (spi_handle)
  138. return true; /* Already started */
  139. xEventGroupClearBits(fpga_service_evgroup, NOTIFY_DISABLE);
  140. err = spi_bus_initialize(FPGA_SPI_HOST, &spi_bus_config, SPI_DMA_CH_AUTO);
  141. if (err)
  142. goto init_fail;
  143. err = spi_bus_add_device(FPGA_SPI_HOST, &spi_device_interface_config,
  144. &spi_handle);
  145. if (err)
  146. goto free_bus_fail;
  147. /* Only device on this bus, so acquire it permanently */
  148. err = spi_device_acquire_bus(spi_handle, portMAX_DELAY);
  149. if (err)
  150. goto release_bus_fail;
  151. xEventGroupClearBits(spi_done_evgroup, EVENT_ALL_BITS);
  152. pinMode(PIN_FPGA_INT, INPUT);
  153. attachInterrupt(PIN_FPGA_INT, fpga_interrupt, FALLING);
  154. xEventGroupSetBits(fpga_service_evgroup, NOTIFY_ENABLE);
  155. xSemaphoreGiveRecursive(spi_mutex);
  156. fpga_notify_from_task(NOTIFY_FPGA); /* In case FPGA_INT was already low */
  157. goto done;
  158. release_bus_fail:
  159. spi_bus_remove_device(spi_handle);
  160. spi_handle = NULL;
  161. free_bus_fail:
  162. spi_bus_free(FPGA_SPI_HOST);
  163. init_fail:
  164. xEventGroupSetBits(fpga_service_evgroup, NOTIFY_DISABLE);
  165. done:
  166. return !err;
  167. }
  168. static void fpga_link_disable(void)
  169. {
  170. if (!spi_handle)
  171. return; /* Already stopped */
  172. xEventGroupClearBits(fpga_service_evgroup, NOTIFY_ENABLE);
  173. xSemaphoreTakeRecursive(spi_mutex, portMAX_DELAY);
  174. detachInterrupt(PIN_FPGA_INT);
  175. spi_device_release_bus(spi_handle);
  176. spi_bus_remove_device(spi_handle);
  177. spi_bus_free(FPGA_SPI_HOST);
  178. spi_handle = NULL;
  179. xEventGroupSetBits(fpga_service_evgroup, NOTIFY_DISABLE);
  180. }
  181. static void fpga_poll_set_time(void);
  182. static bool fpga_online(void)
  183. {
  184. struct esplink_head head;
  185. fpga_io_read(FPGA_CMD_ACK(EL_UIRQ_READY), ESPLINK_HDR_ADDR,
  186. &head, sizeof head);
  187. if (head.magic != ESPLINK_HEAD_MAGIC || head.hlen <= 8) {
  188. printf("[FPGA] Bad header received, magic = 0x%08x len = %u\n",
  189. head.magic, head.hlen);
  190. return false;
  191. }
  192. if (unlikely(head.hlen < sizeof head)) {
  193. /* Clear any fields not provided */
  194. memset((char *)&head + head.hlen, 0, sizeof head - head.hlen);
  195. }
  196. printf("[FPGA] Ready, board = %u.%u fixes %02x fpga %u\n",
  197. head.board.major, head.board.minor,
  198. head.board.fixes, head.board.fpga);
  199. tsync_addr = head.tsync;
  200. printf("[FPGA] online, signature \"%.*s\"\n",
  201. (int)(sizeof head.signature - 1), head.signature);
  202. esplink_start(&head);
  203. setenv_bool("status.max80.fpga", true);
  204. xSemaphoreGiveRecursive(spi_mutex);
  205. xTimerStart(fpga_timesync_timer, portMAX_DELAY);
  206. fpga_poll_set_time();
  207. return true;
  208. }
  209. static void fpga_offline(void)
  210. {
  211. tsync_addr = NULL;
  212. xSemaphoreTakeRecursive(spi_mutex, portMAX_DELAY);
  213. xTimerStop(fpga_timesync_timer, portMAX_DELAY);
  214. setenv_bool("status.max80.fpga", false);
  215. esplink_start(NULL); /* Stop esplink */
  216. }
  217. esp_err_t fpga_iov(const struct fpga_iov *iov, size_t niov)
  218. {
  219. spi_transaction_ext_t trans[FPGA_IOV_MAX];
  220. size_t ntrans = 0;
  221. if (niov > FPGA_IOV_MAX)
  222. return ESP_ERR_INVALID_ARG;
  223. for (size_t i = 0; i < niov; i++) {
  224. const struct fpga_iov *iv = &iov[i];
  225. if (!iv->len && !(iv->cmd & FPGA_CMD_NULL))
  226. continue;
  227. spi_transaction_ext_t *t = &trans[ntrans];
  228. memset(t, 0, sizeof *t);
  229. t->base.flags =
  230. SPI_TRANS_MODE_DIO |
  231. SPI_TRANS_VARIABLE_DUMMY |
  232. SPI_TRANS_MULTILINE_CMD |
  233. SPI_TRANS_MULTILINE_ADDR;
  234. t->base.cmd = iv->cmd;
  235. t->base.addr = iv->iaddr;
  236. if (iv->cmd & FPGA_CMD_RD) {
  237. t->base.rxlength = iv->len << 3;
  238. t->base.rx_buffer = iv->rdata;
  239. /* Emulate partial word read by adding dummy bits for offset */
  240. t->dummy_bits = 16 + ((iv->iaddr & 3) << 2);
  241. if (iv->cmd & FPGA_CMD_STATUS) {
  242. /*
  243. * Include the status "dummy" bits
  244. * THIS REQUIRES THE REMOTE ADDRESS TO BE 32-BIT ALIGNED
  245. */
  246. t->base.rxlength += 32;
  247. t->dummy_bits -= 16;
  248. }
  249. } else {
  250. t->base.length = iv->len << 3;
  251. t->base.tx_buffer = iv->wdata;
  252. }
  253. ntrans++;
  254. }
  255. if (!ntrans)
  256. return ESP_OK;
  257. esp_err_t err = ESP_OK;
  258. xSemaphoreTakeRecursive(spi_mutex, portMAX_DELAY);
  259. if (!spi_handle) {
  260. err = ESP_FAIL;
  261. goto fail;
  262. }
  263. xEventGroupClearBits(spi_done_evgroup, EVENT_ALL_BITS);
  264. size_t tbit = 1;
  265. for (size_t i = 0; i < ntrans; i++) {
  266. spi_transaction_ext_t *t = &trans[i];
  267. t->base.user = (void *)tbit;
  268. err = spi_device_queue_trans(spi_handle, &t->base, portMAX_DELAY);
  269. if (err) {
  270. ntrans = i;
  271. break;
  272. }
  273. tbit <<= 1;
  274. }
  275. if (likely(ntrans)) {
  276. xEventGroupWaitBits(spi_done_evgroup, tbit-1, pdTRUE, pdTRUE,
  277. portMAX_DELAY);
  278. while (ntrans--) {
  279. /* This is insanely stupid to have to do when not needed */
  280. spi_transaction_t *tp;
  281. spi_device_get_trans_result(spi_handle, &tp, 0);
  282. }
  283. }
  284. fail:
  285. xSemaphoreGiveRecursive(spi_mutex);
  286. return err;
  287. }
  288. esp_err_t fpga_io_write(unsigned int cmd, const void *addr,
  289. const void *data, size_t len)
  290. {
  291. struct fpga_iov iov;
  292. iov.cmd = cmd | ~FPGA_CMD_RD;
  293. iov.addr = addr;
  294. iov.wdata = data;
  295. iov.len = len;
  296. return fpga_iov(&iov, 1);
  297. }
  298. esp_err_t fpga_io_read(unsigned int cmd, const void *addr,
  299. void *data, size_t len)
  300. {
  301. struct fpga_iov iov;
  302. iov.cmd = cmd | FPGA_CMD_RD;
  303. iov.addr = addr;
  304. iov.rdata = data;
  305. iov.len = len;
  306. return fpga_iov(&iov, 1);
  307. }
  308. /*
  309. * This should be executed after getting an EL_UIRQ_TIME notification;
  310. * do this in polling mode for best latency.
  311. */
  312. static void fpga_get_time(void)
  313. {
  314. esp_err_t err;
  315. struct tm tm;
  316. struct timeval tv;
  317. struct tsbuf {
  318. /* These two words are the status word normally considered "dummy" */
  319. uint16_t status;
  320. uint16_t tick;
  321. struct esplink_timesync_buf get;
  322. } tsbuf;
  323. if (!tsync_addr) {
  324. fpga_io_status(FPGA_CMD_ACK(EL_UIRQ_TIME));
  325. return;
  326. }
  327. spi_transaction_ext_t trans;
  328. memset(&trans, 0, sizeof trans);
  329. trans.base.flags =
  330. SPI_TRANS_MODE_DIO |
  331. SPI_TRANS_VARIABLE_DUMMY |
  332. SPI_TRANS_MULTILINE_CMD |
  333. SPI_TRANS_MULTILINE_ADDR;
  334. trans.base.rxlength = sizeof tsbuf << 3;
  335. trans.base.rx_buffer = &tsbuf;
  336. trans.base.addr = (size_t)&tsync_addr->get;
  337. trans.base.cmd = FPGA_CMD_RD | FPGA_CMD_ACK(EL_UIRQ_TIME);
  338. xSemaphoreTakeRecursive(spi_mutex, portMAX_DELAY);
  339. err = spi_device_polling_transmit(spi_handle, &trans.base);
  340. xSemaphoreGiveRecursive(spi_mutex);
  341. if (err)
  342. return;
  343. if (time_net_sync_status)
  344. return; /* Ignore time from RTC if SNTP active now */
  345. tm.tm_sec = tsbuf.get.tm.sec2 << 1;
  346. tm.tm_min = tsbuf.get.tm.min;
  347. tm.tm_hour = tsbuf.get.tm.hour;
  348. tm.tm_mday = tsbuf.get.tm.mday;
  349. tm.tm_mon = tsbuf.get.tm.mon - 1;
  350. tm.tm_year = tsbuf.get.tm.year + 80;
  351. tm.tm_isdst = -1; /* Unknown */
  352. /* The third term handles wraparounds due to delay in transit */
  353. tv.tv_sec = mktime(&tm) + (tsbuf.tick >> 15) +
  354. ((tsbuf.get.tick >= tsbuf.tick) << 1);
  355. tv.tv_usec = (((uint32_t)tsbuf.tick << 17) * UINT64_C(1000000)) >> 32;
  356. settimeofday(&tv, NULL);
  357. print_time("[FPGA] Time set from RTC: ", &tv);
  358. }
  359. static void fpga_poll_set_time(void)
  360. {
  361. if (!tsync_addr)
  362. return;
  363. if (!time_net_sync_status) {
  364. /* Poll for current time; will call fpga_get_time() later */
  365. fpga_io_status(FPGA_CMD_IRQ(EL_DIRQ_TIME));
  366. return;
  367. }
  368. /* Otherwise transmit time to set the RTC */
  369. esp_err_t err;
  370. struct timeval tv;
  371. struct esplink_timesync_buf tset;
  372. spi_transaction_t trans;
  373. memset(&trans, 0, sizeof trans);
  374. tset.update = 1;
  375. xSemaphoreTakeRecursive(spi_mutex, portMAX_DELAY);
  376. gettimeofday(&tv, NULL);
  377. const struct tm *tm = localtime(&tv.tv_sec);
  378. tset.tick = ((tv.tv_usec * ((1ULL << (32+15))/1000000+1)) >> 32)
  379. + ((tv.tv_sec & 1) << 15);
  380. tset.tm.sec2 = tm->tm_sec >> 1;
  381. tset.tm.min = tm->tm_min;
  382. tset.tm.hour = tm->tm_hour;
  383. tset.tm.mday = tm->tm_mday;
  384. tset.tm.mon = tm->tm_mon + 1;
  385. tset.tm.year = tm->tm_year - 80;
  386. trans.flags =
  387. SPI_TRANS_MODE_DIO |
  388. SPI_TRANS_MULTILINE_CMD |
  389. SPI_TRANS_MULTILINE_ADDR;
  390. trans.length = sizeof tset << 3;
  391. trans.tx_buffer = &tset;
  392. trans.addr = (size_t)&tsync_addr->set;
  393. trans.cmd = FPGA_CMD_WR | FPGA_CMD_IRQ(EL_DIRQ_TIME) |
  394. FPGA_CMD_ACK(EL_UIRQ_TIME);
  395. err = spi_device_polling_transmit(spi_handle, &trans);
  396. xSemaphoreGiveRecursive(spi_mutex);
  397. if (err)
  398. return;
  399. print_time("[FPGA] RTC update: ", &tv);
  400. }
  401. /*
  402. * Get status in polling mode (small transaction, < 256 CPU cycles).
  403. * cmd typically would be IRQ/ACK bits.
  404. */
  405. uint32_t fpga_io_status(unsigned int cmd)
  406. {
  407. spi_transaction_t trans;
  408. memset(&trans, 0, sizeof trans);
  409. trans.flags =
  410. SPI_TRANS_MODE_DIO |
  411. SPI_TRANS_MULTILINE_CMD |
  412. SPI_TRANS_MULTILINE_ADDR |
  413. SPI_TRANS_USE_RXDATA;
  414. trans.cmd = cmd | FPGA_CMD_RD;
  415. trans.addr = 0;
  416. trans.rxlength = 32;
  417. esp_err_t err = ESP_OK;
  418. xSemaphoreTakeRecursive(spi_mutex, portMAX_DELAY);
  419. err = spi_device_polling_transmit(spi_handle, &trans);
  420. xSemaphoreGiveRecursive(spi_mutex);
  421. return err ? 0 : *(const uint32_t *)trans.rx_data;
  422. }
  423. static void fpga_service_task(void *dummy)
  424. {
  425. (void)dummy;
  426. uint32_t status;
  427. bool fpga_initialized = false;
  428. enum fpga_state {
  429. FPGA_DISABLED, /* FPGA services disabled */
  430. FPGA_OFFLINE, /* FPGA services enabled, waiting for FPGA */
  431. FPGA_ONLINE /* FPGA services active */
  432. } fpga_state = FPGA_DISABLED;
  433. fputs("[FPGA] Starting FPGA services task\n", stdout);
  434. while (1) {
  435. uint32_t notifiers, status;
  436. switch (fpga_state) {
  437. case FPGA_DISABLED:
  438. notifiers = notify_wait_for(NOTIFY_ENABLE);
  439. if ((notifiers & NOTIFY_ENABLE) && fpga_link_enable()) {
  440. fputs("[FPGA] Enabling FPGA services\n", stdout);
  441. fpga_state = FPGA_OFFLINE;
  442. }
  443. break;
  444. case FPGA_OFFLINE:
  445. status = fpga_io_status(FPGA_CMD_ACK(EL_UIRQ_READY)|
  446. FPGA_CMD_IRQ(EL_DIRQ_HELLO));
  447. printf("[FPGA] FPGA status flags = 0x%08x\n", status);
  448. if (!digitalRead(PIN_FPGA_INT)) {
  449. if (status & 0x40)
  450. fpga_io_status(FPGA_CMD_ACK(2));
  451. if (status & 0x80)
  452. fpga_io_status(FPGA_CMD_ACK(3));
  453. if ((status & 0xf031) == 0x9030) {
  454. if (fpga_online())
  455. fpga_state = FPGA_ONLINE;
  456. }
  457. } else {
  458. notifiers = notify_wait_for(NOTIFY_FPGA|NOTIFY_DISABLE);
  459. }
  460. break;
  461. case FPGA_ONLINE:
  462. notifiers = notify_wait_for(NOTIFY_FPGA|NOTIFY_DISABLE|
  463. NOTIFY_TIMESYNC);
  464. if (notifiers & NOTIFY_DISABLE) {
  465. fpga_offline();
  466. break;
  467. }
  468. while (!digitalRead(PIN_FPGA_INT)) {
  469. status = fpga_io_status(0);
  470. if ((status & 0xf031) != 0x9010) {
  471. fpga_offline();
  472. printf("[FPGA] FPGA offline, status = 0x%08x\n", status);
  473. fpga_state = FPGA_OFFLINE;
  474. notifiers = 0;
  475. break;
  476. }
  477. if (status & 0x80)
  478. fpga_get_time();
  479. if (status & 0x40)
  480. esplink_poll();
  481. }
  482. if (notifiers & NOTIFY_TIMESYNC)
  483. fpga_poll_set_time();
  484. break;
  485. }
  486. if (notifiers & NOTIFY_DISABLE) {
  487. fputs("[FPGA] Disabling FPGA services\n", stdout);
  488. fpga_link_disable();
  489. fpga_state = FPGA_DISABLED;
  490. }
  491. }
  492. }