sdio_slv.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /*
  2. * ESPRSSIF MIT License
  3. *
  4. * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
  5. *
  6. * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
  7. * it is free of charge, to any person obtaining a copy of this software and associated
  8. * documentation files (the "Software"), to deal in the Software without restriction, including
  9. * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10. * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
  11. * to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in all copies or
  14. * substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. *
  23. */
  24. #include "driver/slc_register.h"
  25. #include "driver/sdio_slv.h"
  26. #include "ets_sys.h"
  27. #include "osapi.h"
  28. #include "os_type.h"
  29. //#include "gpio.h"
  30. #include "user_interface.h"
  31. #include "mem.h"
  32. #define SDIO_TOKEN_SIZE 0//4
  33. #define RX_BUFFER_SIZE 512
  34. #define RX_BUFFER_NUM 4
  35. #define TX_BUFFER_SIZE 512
  36. #define SLC_INTEREST_EVENT (SLC_TX_EOF_INT_ENA | SLC_RX_EOF_INT_ENA | SLC_RX_UDF_INT_ENA | SLC_TX_DSCR_ERR_INT_ENA)
  37. #define TRIG_TOHOST_INT() SET_PERI_REG_MASK(SLC_INTVEC_TOHOST , BIT0);\
  38. //CLEAR_PERI_REG_MASK(SLC_INTVEC_TOHOST , BIT0)
  39. struct sdio_queue
  40. {
  41. uint32 blocksize:12;
  42. uint32 datalen:12;
  43. uint32 unused:5;
  44. uint32 sub_sof:1;
  45. uint32 eof:1;
  46. uint32 owner:1;
  47. uint32 buf_ptr;
  48. uint32 next_link_ptr;
  49. };
  50. struct sdio_slave_status_element
  51. {
  52. uint32 wr_busy:1;
  53. uint32 rd_empty :1;
  54. uint32 comm_cnt :3;
  55. uint32 intr_no :3;
  56. uint32 rx_length:16;
  57. uint32 res:8;
  58. };
  59. union sdio_slave_status
  60. {
  61. struct sdio_slave_status_element elm_value;
  62. uint32 word_value;
  63. };
  64. //uint8 rx_buffer[RX_BUFFER_NUM][RX_BUFFER_SIZE],tx_buffer[1024];
  65. uint8 tx_buffer[TX_BUFFER_SIZE];
  66. uint32 data_len = 0;
  67. struct sdio_list {
  68. uint8 buffer[RX_BUFFER_SIZE + SDIO_TOKEN_SIZE];
  69. uint8* tail;
  70. struct sdio_list* next;
  71. };
  72. static sdio_recv_data_callback_t sdio_recv_data_callback_ptr = NULL;
  73. struct sdio_list* pHead_ToSend;
  74. struct sdio_list* pTail_ToSend;
  75. struct sdio_list* pHead_Sended;
  76. struct sdio_list* pTail_Sended;
  77. os_event_t * sdioQueue;
  78. struct sdio_queue rx_que,tx_que;
  79. static bool has_read = 0;
  80. static void sdio_slave_isr(void *para);
  81. static void tx_buff_handle_done(void);
  82. static void rx_buff_read_done(void);
  83. static void tx_buff_write_done(void);
  84. static void sdio_try_to_load(void);
  85. static void sdio_read_done_process(void);
  86. void sdio_slave_init(void)
  87. {
  88. uint32 regval = 0;
  89. union sdio_slave_status sdio_sta;
  90. ETS_SDIO_INTR_DISABLE();
  91. ////reset orginal link
  92. SET_PERI_REG_MASK(SLC_CONF0, SLC_RXLINK_RST|SLC_TXLINK_RST);
  93. CLEAR_PERI_REG_MASK(SLC_CONF0, SLC_RXLINK_RST|SLC_TXLINK_RST);
  94. os_printf("RX&TX link reset!\n");
  95. //set sdio mode
  96. SET_PERI_REG_MASK(SLC_RX_DSCR_CONF, SLC_RX_EOF_MODE | SLC_RX_FILL_MODE);
  97. //clear to host interrupt io signal for preventing from random initial signal.
  98. WRITE_PERI_REG(SLC_HOST_INTR_CLR, 0xffffffff);
  99. //enable 2 events to trigger the to host intr io
  100. SET_PERI_REG_MASK(SLC_HOST_INTR_ENA , SLC_HOST_TOHOST_BIT0_INT_ENA);
  101. ////initialize rx queue information
  102. has_read = TRUE;
  103. pHead_ToSend = NULL;
  104. int loop = RX_BUFFER_NUM;
  105. struct sdio_list* p = NULL;
  106. while(loop--) {
  107. if(pHead_Sended == NULL) {
  108. pHead_Sended = (struct sdio_list*)os_malloc(sizeof(struct sdio_list));
  109. p = pHead_Sended;
  110. } else {
  111. p->next = (struct sdio_list*)os_malloc(sizeof(struct sdio_list));
  112. p = p->next;
  113. }
  114. //os_printf("p:0x%08x\r\n",p);
  115. p->tail = p->buffer + SDIO_TOKEN_SIZE;
  116. p->next = NULL;
  117. }
  118. pTail_Sended = p;
  119. rx_que.blocksize = RX_BUFFER_SIZE;
  120. rx_que.datalen=0;
  121. rx_que.eof=1;
  122. rx_que.owner=1;
  123. rx_que.sub_sof=0;
  124. rx_que.unused=0;
  125. rx_que.buf_ptr=(uint32)pHead_Sended->buffer;
  126. rx_que.next_link_ptr=0;
  127. ////initialize tx queue information
  128. tx_que.blocksize=TX_BUFFER_SIZE;
  129. tx_que.datalen=0;
  130. tx_que.eof=0;
  131. tx_que.owner=1;
  132. tx_que.sub_sof=0;
  133. tx_que.unused=0;
  134. tx_que.buf_ptr=(uint32)tx_buffer;
  135. tx_que.next_link_ptr=0;
  136. ///////link tx&rx queue information address to sdio hardware
  137. CLEAR_PERI_REG_MASK(SLC_RX_LINK,SLC_RXLINK_DESCADDR_MASK);
  138. regval= ((uint32)&rx_que);
  139. SET_PERI_REG_MASK(SLC_RX_LINK, regval&SLC_RXLINK_DESCADDR_MASK);
  140. CLEAR_PERI_REG_MASK(SLC_TX_LINK,SLC_TXLINK_DESCADDR_MASK);
  141. regval= ((uint32)&tx_que);
  142. SET_PERI_REG_MASK(SLC_TX_LINK, regval&SLC_TXLINK_DESCADDR_MASK);
  143. #if (SDIO_TOKEN_SIZE == 0)
  144. SET_PERI_REG_MASK(SLC_RX_DSCR_CONF, SLC_TOKEN_NO_REPLACE);
  145. #endif
  146. /////config sdio_status reg
  147. sdio_sta.elm_value.comm_cnt=7;
  148. sdio_sta.elm_value.intr_no=INIT_STAGE;
  149. sdio_sta.elm_value.wr_busy=0;
  150. sdio_sta.elm_value.rd_empty=1;
  151. sdio_sta.elm_value.rx_length=0;
  152. sdio_sta.elm_value.res=0;
  153. SET_PERI_REG_MASK(SLC_TX_LINK, SLC_TXLINK_START);
  154. WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value);
  155. /////attach isr func to sdio interrupt
  156. ETS_SDIO_INTR_ATTACH(sdio_slave_isr, NULL);
  157. /////enable sdio operation intr
  158. WRITE_PERI_REG(SLC_INT_ENA, SLC_INTEREST_EVENT);
  159. /////clear sdio initial random active intr signal
  160. WRITE_PERI_REG(SLC_INT_CLR, 0xffffffff);
  161. /////enable sdio intr in cpu
  162. ETS_SDIO_INTR_ENABLE();
  163. }
  164. static void sdio_slave_isr(void *para)
  165. {
  166. uint32 slc_intr_status,postval;
  167. static uint8 state =0;
  168. uint16 rx_len,i;
  169. uint32* pword;
  170. union sdio_slave_status sdio_sta;
  171. slc_intr_status = READ_PERI_REG(SLC_INT_STATUS);
  172. if (slc_intr_status == 0)
  173. {
  174. /* No interested interrupts pending */
  175. return;
  176. }
  177. //clear all intrs
  178. WRITE_PERI_REG(SLC_INT_CLR, slc_intr_status);
  179. //os_printf("slc_intr_status:0x%08x\r\n",slc_intr_status);
  180. //process every intr
  181. //TO HOST DONE
  182. if (slc_intr_status & SLC_RX_EOF_INT_ENA)
  183. {
  184. //following code must be called after a data pack has been read
  185. rx_buff_read_done();
  186. //TRIG_TOHOST_INT();
  187. //system_os_post(2, 1, 0);
  188. sdio_read_done_process();
  189. }
  190. //FROM HOST DONE
  191. if (slc_intr_status & SLC_TX_EOF_INT_ENA)
  192. {
  193. //call the following function after host cpu data transmission finished
  194. tx_buff_write_done();
  195. //system_os_post(USER_TASK_PRIO_1,SDIO_DATA_ERROR,0);
  196. //os_printf("%d,%s\r\n",tx_que.datalen,tx_que.buf_ptr);
  197. //at_fake_uart_rx((uint8*)tx_que.buf_ptr,tx_que.datalen);
  198. if(sdio_recv_data_callback_ptr) {
  199. sdio_recv_data_callback_ptr((uint8*)tx_que.buf_ptr,tx_que.datalen);
  200. }
  201. tx_buff_handle_done();
  202. TRIG_TOHOST_INT();
  203. //system_os_post(2, 3, 0);
  204. }
  205. //TO HOST underflow
  206. if(slc_intr_status & SLC_RX_UDF_INT_ENA)
  207. {
  208. }
  209. //FROM HOST overflow
  210. if(slc_intr_status & SLC_TX_DSCR_ERR_INT_ENA)
  211. {
  212. }
  213. slc_intr_status = READ_PERI_REG(SLC_INT_STATUS);
  214. if(slc_intr_status)
  215. {
  216. WRITE_PERI_REG(SLC_INT_CLR, slc_intr_status);
  217. os_printf("slc_intr_status:0x%08x\r\n",slc_intr_status);
  218. }
  219. }
  220. static void rx_buff_read_done(void)
  221. {
  222. union sdio_slave_status sdio_sta;
  223. /////modify sdio status reg
  224. sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2);
  225. sdio_sta.elm_value.comm_cnt++;
  226. sdio_sta.elm_value.rd_empty=1;
  227. sdio_sta.elm_value.rx_length=0;
  228. sdio_sta.elm_value.intr_no &= (~RX_AVAILIBLE);
  229. WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value); //update sdio status register
  230. //os_printf("rx_buff_read_done\r\n");
  231. }
  232. static void tx_buff_write_done(void)
  233. {
  234. union sdio_slave_status sdio_sta;
  235. /////modify sdio status reg
  236. sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2);
  237. sdio_sta.elm_value.comm_cnt++;
  238. sdio_sta.elm_value.wr_busy=1;
  239. sdio_sta.elm_value.intr_no &= (~TX_AVAILIBLE);
  240. WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value); //update sdio status register
  241. }
  242. static void tx_buff_handle_done(void)
  243. {
  244. union sdio_slave_status sdio_sta;
  245. /////config tx queue information
  246. tx_que.blocksize=TX_BUFFER_SIZE;
  247. tx_que.datalen=0;
  248. tx_que.eof=0;
  249. tx_que.owner=1;
  250. /////modify sdio status reg
  251. sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2);
  252. sdio_sta.elm_value.wr_busy=0;
  253. sdio_sta.elm_value.intr_no |= TX_AVAILIBLE;
  254. SET_PERI_REG_MASK(SLC_TX_LINK, SLC_TXLINK_START); //tx buffer is ready for being written
  255. WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value); //update sdio status register
  256. //*******************************************************************//
  257. }
  258. static int32 rx_buff_load_done(uint16 rx_len)
  259. {
  260. union sdio_slave_status sdio_sta;
  261. if(rx_len == 0) {
  262. return 0;
  263. }
  264. if(rx_len > rx_que.blocksize)
  265. {
  266. rx_len = rx_que.blocksize;
  267. }
  268. //os_memcpy(rx_que.buf_ptr,data,rx_len);
  269. /////config rx queue information
  270. rx_que.blocksize=RX_BUFFER_SIZE;
  271. rx_que.datalen=rx_len + SDIO_TOKEN_SIZE;
  272. rx_que.eof=1;
  273. rx_que.owner=1;
  274. //ETS_SDIO_INTR_DISABLE();
  275. //available_buffer_amount--;
  276. /////modify sdio status reg
  277. sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2);
  278. sdio_sta.elm_value.rd_empty=0;
  279. sdio_sta.elm_value.intr_no |= RX_AVAILIBLE;
  280. sdio_sta.elm_value.rx_length=rx_len;
  281. SET_PERI_REG_MASK(SLC_RX_LINK, SLC_RXLINK_START); //rx buffer is ready for being read
  282. WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value); //update sdio status register
  283. //ETS_SDIO_INTR_ENABLE();
  284. //os_printf("rx_buff_load_done(%d,0x%08x):%s\r\n",rx_len,rx_que.buf_ptr,rx_que.buf_ptr);
  285. //os_printf("rx_buff_load_done:%d\r\n",rx_len);
  286. return rx_len;
  287. }
  288. int32 ICACHE_FLASH_ATTR sdio_load_data(const uint8* data,uint32 len)
  289. {
  290. int32 data_len = 0;
  291. if (pHead_Sended == NULL) {
  292. os_printf("no buf\r\n");
  293. return 0;
  294. }
  295. int32 left_len = 0;
  296. while(len)
  297. {
  298. left_len = RX_BUFFER_SIZE + SDIO_TOKEN_SIZE - (uint32)(pHead_Sended->tail - pHead_Sended->buffer);
  299. if(len < left_len)
  300. {
  301. os_memcpy(pHead_Sended->tail,data,len);
  302. pHead_Sended->tail += len;
  303. len = 0;
  304. data_len += len;
  305. //os_printf(">555:0x%08x,0x%08x\r\n",pHead_Sended->buffer,pHead_Sended->tail);
  306. }
  307. else
  308. {
  309. os_memcpy(pHead_Sended->tail,data,left_len);
  310. pHead_Sended->tail += left_len;
  311. len -= left_len;
  312. data += left_len;
  313. data_len += left_len;
  314. if(pHead_ToSend == NULL) {
  315. pTail_ToSend = pHead_Sended;
  316. pHead_ToSend = pTail_ToSend;
  317. } else {
  318. pTail_ToSend->next = pHead_Sended;
  319. pTail_ToSend = pTail_ToSend->next;
  320. }
  321. pHead_Sended = pHead_Sended->next;
  322. pTail_ToSend->next = NULL;
  323. if(pHead_Sended == NULL)
  324. {
  325. os_printf("buf full\r\n");
  326. break;
  327. }
  328. //os_printf(">666\r\n");
  329. }
  330. }
  331. //os_printf(">>pHead_ToSend:0x%08x\r\n",pHead_ToSend);
  332. if(pHead_ToSend == NULL) {
  333. pTail_ToSend = pHead_Sended;
  334. pHead_ToSend = pTail_ToSend;
  335. pHead_Sended = pHead_Sended->next;
  336. pTail_ToSend->next = NULL;
  337. //system_os_post(2, 2, 0);
  338. sdio_try_to_load();
  339. }
  340. return data_len;
  341. }
  342. static void sdio_try_to_load(void)
  343. {
  344. if((has_read == TRUE) && (pHead_ToSend != NULL))
  345. {
  346. rx_que.buf_ptr = (uint32)pHead_ToSend->buffer;
  347. rx_buff_load_done(pHead_ToSend->tail- pHead_ToSend->buffer - SDIO_TOKEN_SIZE);
  348. //pHead_ToSend = pHead_ToSend->next;
  349. has_read = FALSE;
  350. //os_printf("SLC_INT_STATUS:0x%08x\r\n",READ_PERI_REG(SLC_INT_STATUS));
  351. TRIG_TOHOST_INT();
  352. }
  353. }
  354. static void sdio_read_done_process(void)
  355. {
  356. has_read = TRUE;
  357. pHead_ToSend->tail = pHead_ToSend->buffer + SDIO_TOKEN_SIZE;
  358. if(pHead_Sended) {
  359. pTail_Sended->next = pHead_ToSend;
  360. pTail_Sended = pTail_Sended->next;
  361. }else {
  362. pTail_Sended = pHead_ToSend;
  363. pHead_Sended = pTail_Sended;
  364. }
  365. pHead_ToSend = pHead_ToSend->next;
  366. pTail_Sended->next = NULL;
  367. //os_printf(">>pHead_ToSend:0x%08x,pHead_Sended:0x%08x,0x%08x,0x%08x\r\n",pHead_ToSend,pHead_Sended,pHead_Sended->buffer,pHead_Sended->tail);
  368. if(pHead_ToSend) {
  369. rx_que.buf_ptr = (uint32)pHead_ToSend->buffer;
  370. rx_buff_load_done(pHead_ToSend->tail - pHead_ToSend->buffer - SDIO_TOKEN_SIZE);
  371. has_read = FALSE;
  372. //os_printf("intr trig\r\n");
  373. //TRIG_TOHOST_INT();
  374. } else if ((pHead_Sended != NULL) && (pHead_Sended->buffer != (pHead_Sended->tail- SDIO_TOKEN_SIZE))) {
  375. pHead_ToSend = pHead_Sended;
  376. pTail_ToSend = pHead_ToSend;
  377. pHead_Sended = pHead_Sended->next;
  378. pTail_ToSend->next = NULL;
  379. rx_que.buf_ptr = (uint32)pHead_ToSend->buffer;
  380. rx_buff_load_done(pHead_ToSend->tail- pHead_ToSend->buffer - SDIO_TOKEN_SIZE);
  381. has_read = FALSE;
  382. //os_printf("intr trig\r\n");
  383. //TRIG_TOHOST_INT();
  384. }
  385. TRIG_TOHOST_INT();
  386. }
  387. bool sdio_register_recv_cb(sdio_recv_data_callback_t cb)
  388. {
  389. sdio_recv_data_callback_ptr = cb;
  390. return TRUE;
  391. }