STM32:
[esp-hosted.git] / esp_hosted_fg / host / stm32 / driver / sdio / sdio_host.c
1 // Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 /** Includes **/
16 #include <stdio.h>
17 #include <stdint.h>
18 #include <string.h>
19 #include "sdio_reg.h"
20 #include "sdio_api.h"
21 #include "sdio_host.h"
22 #include "sdio_ll.h"
23 #include "FreeRTOS.h"
24 #include "task.h"
25 #include "trace.h"
26
27 /** Macros/Constants **/
28 #define CHECK_SDIO_ERR(ErR) {\
29         if (ErR) { \
30                 printf("%s: %u err %u\r\n",__func__,__LINE__,ErR); \
31                 return ErR; \
32         } \
33 }
34
35 /** Global Variable **/
36 /* Counter to hold the amount of buffers already sent to sdio slave */
37 static uint32_t tx_sent_buffers = 0;
38
39 /* Counter to hold the amount of bytes already received from sdio slave */
40 static uint32_t rx_got_bytes   = 0;
41
42 /** Functions Declaration **/
43
44 /** SDIO slave initialization  **/
45 static stm_ret_t esp_slave_init_io(void);
46 static uint32_t esp_sdio_host_get_buffer_size(void);
47 static stm_ret_t esp_sdio_slave_get_rx_data_size(uint32_t* rx_size);
48
49 /** Functions Defination **/
50
51 /**
52  * @brief  SDIO slave initialization
53  * @param  None
54  * @retval STM_OK for success or failure from enum stm_ret_t
55  */
56 static stm_ret_t esp_slave_init_io(void)
57 {
58         uint8_t ioe = 0, ior = 0, ie = 0;
59         uint8_t bsl = 0, bsh = 0;
60         uint8_t func1_bsl = 0, func1_bsh = 0;
61         uint8_t func2_bsl = 0, func2_bsh = 0;
62
63         CHECK_SDIO_ERR(sdio_driver_read_byte(SDIO_FUNC_0, SD_IO_CCCR_FN_ENABLE, &ioe));
64 #if DEBUG_TRANSPORT
65         //printf("%s %u IOE: 0x%02x\n\r", __func__, __LINE__,ioe);
66 #endif
67
68         CHECK_SDIO_ERR(sdio_driver_read_byte(SDIO_FUNC_0, SD_IO_CCCR_FN_READY, &ior));
69 #if DEBUG_TRANSPORT
70         //printf("%s %u IOR: 0x%02x\n\r", __func__, __LINE__, ior);
71 #endif
72
73         // enable function 1
74         ioe = 6;
75         CHECK_SDIO_ERR(sdio_driver_write_byte(SDIO_FUNC_0, SD_IO_CCCR_FN_ENABLE, ioe, &ioe));
76 #if DEBUG_TRANSPORT
77         //printf("%s %u IOE: 0x%02x\n\r", __func__,__LINE__,ioe);
78 #endif
79
80         ior = 6;
81         CHECK_SDIO_ERR(sdio_driver_write_byte(SDIO_FUNC_0, SD_IO_CCCR_FN_READY, ioe, &ior));
82 #if DEBUG_TRANSPORT
83 //      printf("%s %u IOE: 0x%02x\n\r", __func__,__LINE__,ior);
84 #endif
85
86         // get interrupt status
87         CHECK_SDIO_ERR(sdio_driver_read_byte(SDIO_FUNC_0, SD_IO_CCCR_INT_ENABLE, &ie));
88 #if DEBUG_TRANSPORT
89 //      printf("IE: 0x%02x\n\r", ie);
90 #endif
91
92         // enable interrupts for function 1&2 and master enable
93         ie = 7;
94         CHECK_SDIO_ERR(sdio_driver_write_byte(SDIO_FUNC_0, SD_IO_CCCR_INT_ENABLE, ie, &ie));
95 #if DEBUG_TRANSPORT
96 //      printf("%s: %u IE: 0x%02x\n\r", __func__,__LINE__,ie);
97 #endif
98
99         CHECK_SDIO_ERR(sdio_driver_write_byte(SDIO_FUNC_0, SD_IO_CCCR_BLKSIZEL, bsl, &bsl));
100 #if DEBUG_TRANSPORT
101 //      printf("%s:%u Function 0 BSL: 0x%02x\n\r", __func__,__LINE__,bsl);
102 #endif
103
104         bsh = 2;
105         CHECK_SDIO_ERR(sdio_driver_write_byte(SDIO_FUNC_0, SD_IO_CCCR_BLKSIZEH, bsh, &bsh));
106 #if DEBUG_TRANSPORT
107 //      printf("%s %u Function 0 BSH: 0x%02x\n\r", __func__,__LINE__,bsh);
108 #endif
109
110         CHECK_SDIO_ERR(sdio_driver_write_byte(SDIO_FUNC_0, 0x110, func1_bsl, &func1_bsl));
111 #if DEBUG_TRANSPORT
112 //      printf("%s %u Function 1 BSL: 0x%02x\n\r",  __func__,__LINE__,func1_bsl);
113 #endif
114
115         func1_bsh = 2;         // Set block size 512 (0x200)
116         CHECK_SDIO_ERR(sdio_driver_write_byte(SDIO_FUNC_0, 0x111, func1_bsh, &func1_bsh));
117 #if DEBUG_TRANSPORT
118 //      printf("%s %u Function 1 BSH: 0x%02x\n\r", __func__,__LINE__, func1_bsh);
119 #endif
120
121         CHECK_SDIO_ERR(sdio_driver_write_byte(SDIO_FUNC_0, 0x210, func2_bsl, &func2_bsl));
122 #if DEBUG_TRANSPORT
123 //      printf("%s %u Function 2 BSL: 0x%02x\n\r", __func__,__LINE__, func2_bsl);
124 #endif
125
126         func2_bsh = 2;
127         CHECK_SDIO_ERR(sdio_driver_write_byte(SDIO_FUNC_0, 0x210, func2_bsh, &func2_bsh));
128 #if DEBUG_TRANSPORT
129 //      printf("%s %u Function 2 BSH: 0x%02x\n\r", __func__,__LINE__,func2_bsh);
130         printf("Slave Initialization completed\n\r");
131 #endif
132         return STM_OK;
133 }
134
135 /**
136  * @brief  host use this to initialize the slave as well as SDIO register
137  * @param  None
138  * @retval STM_OK for success or failure from enum stm_ret_t
139  */
140 stm_ret_t sdio_host_init(void)
141 {
142         CHECK_SDIO_ERR(sdio_driver_init());
143
144         CHECK_SDIO_ERR(esp_slave_init_io());
145
146         return STM_OK;
147 }
148
149 /** receive functions **/
150 /**
151  * @brief  HOST receive data
152  * @param  rx_size - read data size
153  * @retval STM_OK for success or failure from enum stm_ret_t
154  */
155 static stm_ret_t esp_sdio_slave_get_rx_data_size(uint32_t* rx_size)
156 {
157         uint32_t len = 0, temp = 0;
158         stm_ret_t err = sdio_driver_read_bytes(SDIO_FUNC_1,
159                         SDIO_REG(ESP_SLAVE_PACKET_LEN_REG), &len, 4, 0);
160         if (err) {
161                 return err;
162         }
163         len &= ESP_SLAVE_LEN_MASK;
164         //len = (len + ESP_SLAVE_LEN_MASK - rx_got_bytes)%ESP_SLAVE_LEN_MASK;
165         if(len >= rx_got_bytes) {
166                 len = (len + ESP_RX_BYTE_MAX - rx_got_bytes)%ESP_RX_BYTE_MAX;
167         } else {
168                 temp = ESP_RX_BYTE_MAX - rx_got_bytes;
169                 len = temp + len;
170
171         }
172
173 #if 0
174         //TODO: unsure ym2
175         /* length is expected to be in multiple of ESP_BLOCK_SIZE */
176         if(len&(ESP_BLOCK_SIZE-1))
177                 return STM_FAIL;
178 #endif
179
180         if (len > MAX_SDIO_BUFFER_SIZE) {
181                 printf("%s: Len from slave[%lu] exceeds max [%d]\n",
182                                 __func__, len, MAX_SDIO_BUFFER_SIZE);
183         }
184
185         *rx_size = len;
186         return STM_OK;
187 }
188
189 /**
190  * @brief  Get a packet from SDIO slave
191  * @param  [out] out_data - Data output address
192  *         size - The size of the output buffer,
193  *                if the buffer is smaller than
194  *                the size of data to receive from slave,
195  *                the driver returns ESP_ERR_NOT_FINISHED
196  *         [out] out_length - Output of length the data received from slave
197  *         wait_ms - Time to wait before timeout, in ms
198  * @retval STM_OK for success or failure from enum stm_ret_t
199  */
200 stm_ret_t sdio_host_get_packet(void* out_data, size_t size,
201                 size_t* out_length, uint32_t wait_ms)
202 {
203         stm_ret_t err = STM_OK;
204         uint32_t len = 0, wait_time = 0, len_remain = 0;
205         uint8_t* start_ptr = NULL;
206         int len_to_send = 0, block_n = 0;
207
208         if (size <= 0) {
209                 printf("Invalid size:%d\n\r", size);
210                 return STM_FAIL_INVALID_ARG;
211         }
212
213         for (;;) {
214                 err = esp_sdio_slave_get_rx_data_size(&len);
215
216                 if (err == STM_OK && len > 0) {
217 #if DEBUG_TRANSPORT
218                         printf("Expected length to be read %lu\n\n",len);
219 #endif
220                         break;
221                 }
222
223                 /* If no error and no data, retry */
224                 wait_time++;
225
226                 if (wait_time >= wait_ms) {
227                         return STM_FAIL_TIMEOUT;
228                 }
229
230                 //vTaskDelay(1);
231                 hard_delay(1);
232         }
233
234         if (len > size) {
235                 printf("Pkt size to be read[%lu] > max sdio size supported[%u]\n\r",len, size);
236                 return STM_OK;
237         }
238
239         len_remain = len;
240         start_ptr = (uint8_t*)out_data;
241
242         do {
243                 /* currently driver supports only block size of 512 */
244
245                 block_n = len_remain / ESP_BLOCK_SIZE;
246
247                 if (block_n != 0) {
248                         len_to_send = ESP_BLOCK_SIZE;
249 #if DEBUG_TRANSPORT
250                         printf("block_n %u, len-to_send %lu\n\r",block_n,len_to_send);
251 #endif
252
253                         err = sdio_driver_read_blocks(SDIO_FUNC_1,
254                                         ESP_SLAVE_CMD53_END_ADDR - len_remain,
255                                         start_ptr, len_to_send, block_n);
256                 } else {
257                         len_to_send = len_remain;
258                         /* though the driver supports to split packet of unaligned size into length
259                          * of 4x and 1~3, we still get aligned size of data to get higher
260                          * efficiency. The length is determined by the SDIO address, and the
261                          * remaining will be ignored by the slave hardware
262                          */
263                         err = sdio_driver_read_bytes(SDIO_FUNC_1,
264                                         ESP_SLAVE_CMD53_END_ADDR - len_remain, start_ptr,
265                                         (len_to_send + 3) & (~3), block_n);
266                 }
267
268                 if (err) {
269 #if DEBUG_TRANSPORT
270                         printf("Err from read bytes %x\n\r",err);
271 #endif
272                         return err;
273                 }
274
275                 start_ptr += len_to_send;
276                 len_remain -= len_to_send;
277         } while (len_remain != 0);
278
279         *out_length = len;
280         rx_got_bytes += len;
281         if (rx_got_bytes >= ESP_RX_BYTE_MAX) {
282                 rx_got_bytes -= ESP_RX_BYTE_MAX;
283         }
284
285         return STM_OK;
286 }
287
288 /**
289  * @brief  Clear interrupt bits of SDIO slave
290  * @param  intr_mask - Mask of interrupt bits to clear
291  * @retval STM_OK for success or failure from enum stm_ret_t
292  */
293 stm_ret_t sdio_host_clear_intr(uint32_t intr_mask)
294 {
295         return sdio_driver_write_bytes(SDIO_FUNC_1,
296                         SDIO_REG(ESP_SLAVE_INT_CLR_REG), (uint8_t*)&intr_mask, 4);
297 }
298
299 /**
300  * @brief  Get interrupt bits of SDIO slave
301  *
302  * @param  intr_st - Output of the masked interrupt bits
303  *                   set to NULL if only raw bits are read
304  *
305  * @retval STM_OK for success or failure from enum stm_ret_t
306  */
307 stm_ret_t sdio_host_get_intr(uint32_t* intr_st)
308 {
309         stm_ret_t ret = STM_OK;
310
311         if (intr_st == NULL) {
312                 return STM_FAIL_INVALID_ARG;
313         }
314
315         if (intr_st != NULL) {
316                 ret = sdio_driver_read_bytes(SDIO_FUNC_1,
317                                 SDIO_REG(ESP_SLAVE_INT_ST_REG), (uint8_t*)intr_st, 4, 0);
318                 if (ret) {
319                         return ret;
320                 }
321         }
322
323         return STM_OK;
324 }
325
326 /** send functions **/
327
328 /**
329  * @brief  Get available buffer to write to slave before transmit
330  * @param  None
331  * @retval
332  *         Number of buffers available at slave
333  */
334 static uint32_t esp_sdio_host_get_buffer_size(void)
335 {
336         stm_ret_t ret = STM_OK;
337         uint32_t len = 0, len1 = 0;
338
339         ret = sdio_driver_read_bytes(SDIO_FUNC_1,
340                         SDIO_REG(ESP_SLAVE_TOKEN_RDATA), &len, 4, 0);
341         if (ret) {
342                 printf("Read length error, ret=%d\n\r", ret);
343                 return 0;
344         }
345
346         //printf("%s len %lu \n\r", __func__, len);
347         len1 = len;
348         len = (len >> ESP_SDIO_SEND_OFFSET) & ESP_TX_BUFFER_MASK;
349         len = (len + ESP_TX_BUFFER_MAX - tx_sent_buffers) % ESP_TX_BUFFER_MAX;
350 #if DEBUG_TRANSPORT
351         //printf("Read ESP32 len: %lu len1 : %lu \n\r", len, len1);
352 #endif
353         return len;
354 }
355
356 /**
357  * @brief  Send a interrupt signal to the SDIO slave
358  * @param  intr_no - interrupt number, now only support 0
359  * @retval STM_OK for success or failure from enum stm_ret_t
360  */
361 stm_ret_t sdio_host_send_intr(uint8_t intr_no)
362 {
363         uint32_t intr_mask = 0;
364         if (intr_no >= 8) {
365                 printf(" Error interrupt number\n\r");
366                 return STM_FAIL_INVALID_ARG;
367         }
368
369         intr_mask = 0x1 << (intr_no + ESP_SDIO_CONF_OFFSET);
370         return STM32WriteReg(SDIO_FUNC_1, SDIO_REG(ESP_SLAVE_SCRATCH_REG_7), intr_mask);
371 }
372
373 /**
374  * @brief Send a packet to the SDIO slave
375  * @param start - Start address of the packet to send
376  *        length - Length of data to send, if the packet is over-size,
377  *                 the it will be divided into blocks and hold into different
378  *                 buffers automatically
379  * @retval STM_OK for success or failure from enum stm_ret_t
380  */
381 stm_ret_t sdio_host_send_packet(const void* start, uint32_t length)
382 {
383         stm_ret_t err;
384         uint8_t* start_ptr = (uint8_t*)start;
385         uint32_t len_remain = length, num = 0, cnt = 300;
386 //      printf("length received %d %lu \n\r", length, len_remain);
387
388         int buffer_used, block_n = 0,len_to_send = 0;
389
390         buffer_used = (length + ESP_BLOCK_SIZE - 1) / ESP_BLOCK_SIZE;
391
392 #if 1
393         while (1) {
394                 num = esp_sdio_host_get_buffer_size();
395 #if DEBUG_TRANSPORT
396                 //printf("Buffer size %lu can be send, input len: %u, len_remain: %lu\n\r", num, length, len_remain);
397 #endif
398
399                 if (num * ESP_BLOCK_SIZE < length) {
400                         if (!--cnt) {
401                                 printf("buff not enough: curr[%lu], exp[%d]\n\r", num, buffer_used);
402                                 return STM_FAIL_TIMEOUT;
403                         } else {
404                                 printf("buff not enough: curr[%lu], exp[%d], retry..\n\r", num, buffer_used);
405                         }
406
407                         //vTaskDelay(1);
408                         hard_delay(1);
409                 }  else {
410                         break;
411                 }
412         }
413 #endif
414         do {
415                 /* Though the driver supports to split packet of unaligned size into
416                  * length of 4x and 1~3, we still send aligned size of data to get
417                  * higher effeciency. The length is determined by the SDIO address, and
418                  * the remainning will be discard by the slave hardware
419                  */
420                 block_n = len_remain / ESP_BLOCK_SIZE;
421
422                 if (block_n) {
423                         len_to_send = block_n * ESP_BLOCK_SIZE;
424                         err = sdio_driver_write_blocks(SDIO_FUNC_1,
425                                         ESP_SLAVE_CMD53_END_ADDR - len_remain,
426                                         start_ptr, len_to_send);
427                 } else {
428                         len_to_send = len_remain;
429                         err = sdio_driver_write_bytes(SDIO_FUNC_1,
430                                         ESP_SLAVE_CMD53_END_ADDR - len_remain,
431                                         start_ptr, (len_to_send + 3) & (~3));
432                 }
433
434                 if (err) {
435                         return err;
436                 }
437
438                 start_ptr += len_to_send;
439                 len_remain -= len_to_send;
440         } while (len_remain);
441
442         if (tx_sent_buffers >= ESP_TX_BUFFER_MAX) {
443                 tx_sent_buffers -= ESP_TX_BUFFER_MAX;
444         }
445
446         tx_sent_buffers += buffer_used;
447         return STM_OK;
448 }
This page took 0.049366 seconds and 4 git commands to generate.