1 /*
2  * Copyright (c) 2006-2022, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2020-05-23     liuduanfei   first version
9  */
10 #include "board.h"
11 
12 #ifdef RT_USING_SDIO
13 
14 #if !defined(BSP_USING_SDIO1) && !defined(BSP_USING_SDIO2)
15     #error "Please define at least one BSP_USING_SDIOx"
16 #endif
17 
18 #include "drv_sdio.h"
19 
20 #define DBG_TAG              "drv.sdio"
21 #ifdef DRV_DEBUG
22     #define DBG_LVL               DBG_LOG
23 #else
24     #define DBG_LVL               DBG_INFO
25 #endif /* DRV_DEBUG */
26 #include <rtdbg.h>
27 
28 static struct rt_mmcsd_host *host1;
29 static struct rt_mmcsd_host *host2;
30 static rt_mutex_t mmcsd_mutex = RT_NULL;
31 
32 #define SDIO_TX_RX_COMPLETE_TIMEOUT_LOOPS    (1000000)
33 
34 struct sdio_pkg
35 {
36     struct rt_mmcsd_cmd *cmd;
37     void *buff;
38     rt_uint32_t flag;
39 };
40 
41 struct rthw_sdio
42 {
43     struct rt_mmcsd_host *host;
44     struct stm32_sdio_des sdio_des;
45     struct rt_event event;
46     struct sdio_pkg *pkg;
47 };
48 
rt_align(SDIO_ALIGN_LEN)49 rt_align(SDIO_ALIGN_LEN)
50 static rt_uint8_t cache_buf[SDIO_BUFF_SIZE];
51 
52 /**
53   * @brief  This function get order from sdio.
54   * @param  data
55   * @retval sdio order
56   */
57 static int get_order(rt_uint32_t data)
58 {
59     int order = 0;
60 
61     switch (data)
62     {
63         case 1:
64             order = 0;
65             break;
66 
67         case 2:
68             order = 1;
69             break;
70 
71         case 4:
72             order = 2;
73             break;
74 
75         case 8:
76             order = 3;
77             break;
78 
79         case 16:
80             order = 4;
81             break;
82 
83         case 32:
84             order = 5;
85             break;
86 
87         case 64:
88             order = 6;
89             break;
90 
91         case 128:
92             order = 7;
93             break;
94 
95         case 256:
96             order = 8;
97             break;
98 
99         case 512:
100             order = 9;
101             break;
102 
103         case 1024:
104             order = 10;
105             break;
106 
107         case 2048:
108             order = 11;
109             break;
110 
111         case 4096:
112             order = 12;
113             break;
114 
115         case 8192:
116             order = 13;
117             break;
118 
119         case 16384:
120             order = 14;
121             break;
122 
123         default :
124             order = 0;
125             break;
126     }
127 
128     return order;
129 }
130 
131 /**
132   * @brief  This function wait sdio cmd completed.
133   * @param  sdio rthw_sdio
134   * @retval None
135   */
rthw_sdio_wait_completed(struct rthw_sdio * sdio)136 static void rthw_sdio_wait_completed(struct rthw_sdio *sdio)
137 {
138     rt_uint32_t status;
139     struct rt_mmcsd_cmd *cmd = sdio->pkg->cmd;
140     struct stm32_sdio *hw_sdio = sdio->sdio_des.hw_sdio;
141 
142     if (rt_event_recv(&sdio->event, 0xffffffff, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
143                       rt_tick_from_millisecond(5000), &status) != RT_EOK)
144     {
145         LOG_E("wait cmd completed timeout");
146         cmd->err = -RT_ETIMEOUT;
147         return;
148     }
149 
150     cmd->resp[0] = hw_sdio->resp1;
151 
152     if (resp_type(cmd) == RESP_R2)
153     {
154         cmd->resp[1] = hw_sdio->resp2;
155         cmd->resp[2] = hw_sdio->resp3;
156         cmd->resp[3] = hw_sdio->resp4;
157     }
158 
159     if (status & SDIO_ERRORS)
160     {
161         if ((status & SDMMC_STA_CCRCFAIL) && (resp_type(cmd) & (RESP_R3 | RESP_R4)))
162         {
163             cmd->err = RT_EOK;
164         }
165         else
166         {
167             cmd->err = -RT_ERROR;
168         }
169     }
170     else
171     {
172         cmd->err = RT_EOK;
173     }
174 
175 
176     if (cmd->err == RT_EOK)
177     {
178         LOG_D("sta:0x%08X [%08X %08X %08X %08X]", status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
179     }
180     else
181     {
182         LOG_D("send command error = %d", cmd->err);
183     }
184 }
185 
186 /**
187   * @brief  This function send command.
188   * @param  sdio rthw_sdio
189   * @param  pkg  sdio package
190   * @retval None
191   */
rthw_sdio_send_command(struct rthw_sdio * sdio,struct sdio_pkg * pkg)192 static void rthw_sdio_send_command(struct rthw_sdio *sdio, struct sdio_pkg *pkg)
193 {
194     struct rt_mmcsd_cmd *cmd = pkg->cmd;
195     struct rt_mmcsd_data *data = cmd->data;
196     struct stm32_sdio *hw_sdio = sdio->sdio_des.hw_sdio;
197     rt_uint32_t reg_cmd;
198 
199     rt_event_control(&sdio->event, RT_IPC_CMD_RESET, RT_NULL);
200     /* save pkg */
201     sdio->pkg = pkg;
202 
203     LOG_D("CMD:%d ARG:0x%08x RES:%s%s%s%s%s%s%s%s%s rw:%c len:%d blksize:%d\n",
204           cmd->cmd_code,
205           cmd->arg,
206           resp_type(cmd) == RESP_NONE ? "NONE"  : "",
207           resp_type(cmd) == RESP_R1  ? "R1"  : "",
208           resp_type(cmd) == RESP_R1B ? "R1B"  : "",
209           resp_type(cmd) == RESP_R2  ? "R2"  : "",
210           resp_type(cmd) == RESP_R3  ? "R3"  : "",
211           resp_type(cmd) == RESP_R4  ? "R4"  : "",
212           resp_type(cmd) == RESP_R5  ? "R5"  : "",
213           resp_type(cmd) == RESP_R6  ? "R6"  : "",
214           resp_type(cmd) == RESP_R7  ? "R7"  : "",
215           data ? (data->flags & DATA_DIR_WRITE ?  'w' : 'r') : '-',
216           data ? data->blks * data->blksize : 0,
217           data ? data->blksize : 0
218          );
219 
220     hw_sdio->mask |= SDIO_MASKR_ALL;
221     reg_cmd = cmd->cmd_code | SDMMC_CMD_CPSMEN;
222 
223     /* data pre configuration */
224     if (data != RT_NULL)
225     {
226         SCB_CleanInvalidateDCache();
227 
228         reg_cmd |= SDMMC_CMD_CMDTRANS;
229         hw_sdio->mask &= ~(SDMMC_MASK_CMDRENDIE | SDMMC_MASK_CMDSENTIE);
230         hw_sdio->dtimer = HW_SDIO_DATATIMEOUT;
231         hw_sdio->dlen = data->blks * data->blksize;
232         hw_sdio->dctrl = (get_order(data->blksize) << 4) | (data->flags & DATA_DIR_READ ? SDMMC_DCTRL_DTDIR : 0);
233         hw_sdio->idmabase0r = (rt_uint32_t)cache_buf;
234         hw_sdio->idmatrlr = SDMMC_IDMA_IDMAEN;
235     }
236 
237     if (resp_type(cmd) == RESP_R2)
238         reg_cmd |= SDMMC_CMD_WAITRESP;
239     else if(resp_type(cmd) != RESP_NONE)
240         reg_cmd |= SDMMC_CMD_WAITRESP_0;
241 
242     hw_sdio->arg = cmd->arg;
243     hw_sdio->cmd = reg_cmd;
244     /* wait completed */
245     rthw_sdio_wait_completed(sdio);
246 
247     /* Waiting for data to be sent to completion */
248     if (data != RT_NULL)
249     {
250         volatile rt_uint32_t count = SDIO_TX_RX_COMPLETE_TIMEOUT_LOOPS;
251 
252         while (count && (hw_sdio->sta & SDMMC_STA_DPSMACT))
253         {
254             count--;
255         }
256 
257         if ((count == 0) || (hw_sdio->sta & SDIO_ERRORS))
258         {
259             cmd->err = -RT_ERROR;
260         }
261     }
262 
263     /* data post configuration */
264     if (data != RT_NULL)
265     {
266         if (data->flags & DATA_DIR_READ)
267         {
268             rt_memcpy(data->buf, cache_buf, data->blks * data->blksize);
269             SCB_CleanInvalidateDCache();
270         }
271     }
272 }
273 
274 /**
275   * @brief  This function send sdio request.
276   * @param  sdio  rthw_sdio
277   * @param  req   request
278   * @retval None
279   */
rthw_sdio_request(struct rt_mmcsd_host * host,struct rt_mmcsd_req * req)280 static void rthw_sdio_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
281 {
282     struct sdio_pkg pkg;
283     struct rthw_sdio *sdio = host->private_data;
284     struct rt_mmcsd_data *data;
285 
286 
287     rt_mutex_take(mmcsd_mutex, RT_WAITING_FOREVER);
288 
289     if (req->cmd != RT_NULL)
290     {
291         rt_memset(&pkg, 0, sizeof(pkg));
292         data = req->cmd->data;
293         pkg.cmd = req->cmd;
294 
295         if (data != RT_NULL)
296         {
297             rt_uint32_t size = data->blks * data->blksize;
298 
299             RT_ASSERT(size <= SDIO_BUFF_SIZE);
300 
301             if (data->flags & DATA_DIR_WRITE)
302             {
303                 rt_memcpy(cache_buf, data->buf, size);
304             }
305         }
306 
307         rthw_sdio_send_command(sdio, &pkg);
308     }
309 
310     if (req->stop != RT_NULL)
311     {
312         rt_memset(&pkg, 0, sizeof(pkg));
313         pkg.cmd = req->stop;
314         rthw_sdio_send_command(sdio, &pkg);
315     }
316 
317     mmcsd_req_complete(sdio->host);
318 
319     rt_mutex_release(mmcsd_mutex);
320 }
321 
322 
323 /**
324   * @brief  This function interrupt process function.
325   * @param  host  rt_mmcsd_host
326   * @retval None
327   */
rthw_sdio_irq_process(struct rt_mmcsd_host * host)328 void rthw_sdio_irq_process(struct rt_mmcsd_host *host)
329 {
330     struct rthw_sdio *sdio = host->private_data;
331     struct stm32_sdio *hw_sdio = sdio->sdio_des.hw_sdio;
332     rt_uint32_t intstatus = hw_sdio->sta;
333 
334     /* clear irq flag*/
335     hw_sdio->icr = intstatus;
336 
337     rt_event_send(&sdio->event, intstatus);
338 }
339 
340 /**
341   * @brief  This function config sdio.
342   * @param  host    rt_mmcsd_host
343   * @param  io_cfg  rt_mmcsd_io_cfg
344   * @retval None
345   */
rthw_sdio_iocfg(struct rt_mmcsd_host * host,struct rt_mmcsd_io_cfg * io_cfg)346 static void rthw_sdio_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
347 {
348     rt_uint32_t temp, clk_src;
349     rt_uint32_t clk = io_cfg->clock;
350     struct rthw_sdio *sdio = host->private_data;
351     struct stm32_sdio *hw_sdio = sdio->sdio_des.hw_sdio;
352 
353     LOG_D("clk:%dK width:%s%s%s power:%s%s%s",
354           clk / 1000,
355           io_cfg->bus_width == MMCSD_BUS_WIDTH_8 ? "8" : "",
356           io_cfg->bus_width == MMCSD_BUS_WIDTH_4 ? "4" : "",
357           io_cfg->bus_width == MMCSD_BUS_WIDTH_1 ? "1" : "",
358           io_cfg->power_mode == MMCSD_POWER_OFF ? "OFF" : "",
359           io_cfg->power_mode == MMCSD_POWER_UP ? "UP" : "",
360           io_cfg->power_mode == MMCSD_POWER_ON ? "ON" : ""
361          );
362 
363     clk_src = SDIO_CLOCK_FREQ;
364 
365     if (clk > 0)
366     {
367         if (clk > host->freq_max)
368             clk = host->freq_max;
369 
370         temp = DIV_ROUND_UP(clk_src, 2 * clk);
371 
372         if (temp > 0x3FF)
373             temp = 0x3FF;
374     }
375 
376     if (io_cfg->bus_width == MMCSD_BUS_WIDTH_4)
377         temp |= SDMMC_CLKCR_WIDBUS_0;
378     else if (io_cfg->bus_width == MMCSD_BUS_WIDTH_8)
379         temp |= SDMMC_CLKCR_WIDBUS_1;
380 
381     hw_sdio->clkcr = temp;
382 
383     if (io_cfg->power_mode == MMCSD_POWER_ON)
384         hw_sdio->power |= SDMMC_POWER_PWRCTRL;
385 }
386 
387 static const struct rt_mmcsd_host_ops ops =
388 {
389     rthw_sdio_request,
390     rthw_sdio_iocfg,
391     RT_NULL,
392     RT_NULL,
393 };
394 
395 /**
396   * @brief  This function create mmcsd host.
397   * @param  sdio_des stm32_sdio_des
398   * @retval rt_mmcsd_host
399   */
sdio_host_create(struct stm32_sdio_des * sdio_des)400 struct rt_mmcsd_host *sdio_host_create(struct stm32_sdio_des *sdio_des)
401 {
402     struct rt_mmcsd_host *host;
403     struct rthw_sdio *sdio = RT_NULL;
404 
405     if (sdio_des == RT_NULL)
406     {
407         return RT_NULL;
408     }
409 
410     sdio = rt_malloc(sizeof(struct rthw_sdio));
411 
412     if (sdio == RT_NULL)
413     {
414         LOG_E("malloc rthw_sdio fail");
415         return RT_NULL;
416     }
417 
418     rt_memset(sdio, 0, sizeof(struct rthw_sdio));
419 
420     host = mmcsd_alloc_host();
421 
422     if (host == RT_NULL)
423     {
424         LOG_E("alloc host fail");
425         goto err;
426     }
427 
428     rt_memcpy(&sdio->sdio_des, sdio_des, sizeof(struct stm32_sdio_des));
429 
430     if(sdio_des->hsd.Instance == SDMMC1)
431     {
432         sdio->sdio_des.hw_sdio = (struct stm32_sdio *)SDIO1_BASE_ADDRESS;
433         rt_event_init(&sdio->event, "sdio", RT_IPC_FLAG_FIFO);
434     }
435 
436     if(sdio_des->hsd.Instance == SDMMC2)
437     {
438         sdio->sdio_des.hw_sdio = (struct stm32_sdio *)SDIO2_BASE_ADDRESS;
439         rt_event_init(&sdio->event, "sdio2", RT_IPC_FLAG_FIFO);
440     }
441 
442     /* set host default attributes */
443     host->ops = &ops;
444     host->freq_min = 400 * 1000;
445     host->freq_max = SDIO_MAX_FREQ;
446     host->valid_ocr = VDD_32_33 | VDD_33_34;/* The voltage range supported is 3.2v-3.4v */
447     host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_HIGHSPEED;
448     host->max_seg_size = SDIO_BUFF_SIZE;
449     host->max_dma_segs = 1;
450     host->max_blk_size = 512;
451     host->max_blk_count = 512;
452 
453     /* link up host and sdio */
454     sdio->host = host;
455     host->private_data = sdio;
456 
457     return host;
458 
459 err:
460 
461     if (sdio) rt_free(sdio);
462 
463     return RT_NULL;
464 }
465 
SDMMC1_IRQHandler(void)466 void SDMMC1_IRQHandler(void)
467 {
468     /* enter interrupt */
469     rt_interrupt_enter();
470     /* Process All SDIO Interrupt Sources */
471     rthw_sdio_irq_process(host1);
472     /* leave interrupt */
473     rt_interrupt_leave();
474 }
475 
SDMMC2_IRQHandler(void)476 void SDMMC2_IRQHandler(void)
477 {
478     /* enter interrupt */
479     rt_interrupt_enter();
480     /* Process All SDIO Interrupt Sources */
481     rthw_sdio_irq_process(host2);
482     /* leave interrupt */
483     rt_interrupt_leave();
484 }
485 
rt_hw_sdio_init(void)486 int rt_hw_sdio_init(void)
487 {
488     #ifdef BSP_USING_SDIO1
489     struct stm32_sdio_des sdio_des1;
490     sdio_des1.hsd.Instance = SDMMC1;
491     HAL_SD_MspInit(&sdio_des1.hsd);
492 
493     host1 = sdio_host_create(&sdio_des1);
494 
495     if (host1 == RT_NULL)
496     {
497         LOG_E("host create fail");
498         return RT_NULL;
499     }
500 
501     #endif
502 
503     #ifdef BSP_USING_SDIO2
504     //sdmmc2 wifi
505     struct stm32_sdio_des sdio_des2;
506     sdio_des2.hsd.Instance = SDMMC2;
507     HAL_SD_MspInit(&sdio_des2.hsd);
508 
509     host2 = sdio_host_create(&sdio_des2);
510 
511     if (host2 == RT_NULL)
512     {
513         LOG_E("host2 create fail");
514         return RT_NULL;
515     }
516 
517     /* wifi auto change */
518     mmcsd_change(host2);
519     #endif
520     mmcsd_mutex = rt_mutex_create("mmutex", RT_IPC_FLAG_PRIO);
521 
522     if (mmcsd_mutex == RT_NULL)
523     {
524         rt_kprintf("create mmcsd mutex failed.\n");
525         return -1;
526     }
527 
528     return 0;
529 }
530 INIT_DEVICE_EXPORT(rt_hw_sdio_init);
531 
sdcard_change(void)532 void sdcard_change(void)
533 {
534     mmcsd_change(host1);
535 }
536 
537 #endif /* RT_USING_SDIO */
538