1 /*
2  * Copyright (c) 2006-2022, Synwit Technology Co.,Ltd.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2021-07-01     lik          first version
9  */
10 
11 #include "drv_sdio.h"
12 
13 #ifdef RT_USING_SDIO
14 #ifdef BSP_USING_SDIO
15 
16 //#define DRV_DEBUG
17 #define LOG_TAG "drv.sdio"
18 #include <drv_log.h>
19 
20 #define SDIO_BUFF_SIZE 4096
21 #define SDIO_ALIGN_LEN 4
22 
23 #ifndef SDIO_MAX_FREQ
24 #define SDIO_MAX_FREQ (37500000)
25 #endif
26 
27 struct swm_sdio_pkg
28 {
29     struct rt_mmcsd_cmd *cmd;
30     void *buff;
31     rt_uint32_t flag;
32 };
33 
34 typedef rt_err_t (*sdio_txconfig)(struct swm_sdio_pkg *pkg, rt_uint32_t *buff, int size);
35 typedef rt_err_t (*sdio_rxconfig)(struct swm_sdio_pkg *pkg, rt_uint32_t *buff, int size);
36 typedef rt_uint32_t (*sdio_clk_get)(SDIO_TypeDef *swm_sdio);
37 
38 struct swm_sdio_des
39 {
40     SDIO_TypeDef *swm_sdio;
41     sdio_txconfig txconfig;
42     sdio_rxconfig rxconfig;
43     sdio_clk_get clk_get;
44 };
45 
46 static struct rt_mmcsd_host *host;
47 
48 #define RTHW_SDIO_LOCK(_sdio) rt_mutex_take(&_sdio->mutex, RT_WAITING_FOREVER)
49 #define RTHW_SDIO_UNLOCK(_sdio) rt_mutex_release(&_sdio->mutex);
50 
51 struct swm_sdio_device
52 {
53     struct rt_mmcsd_host *host;
54     struct swm_sdio_des sdio_des;
55     struct rt_event event;
56     struct rt_mutex mutex;
57     struct swm_sdio_pkg *pkg;
58 };
59 
rt_align(SDIO_ALIGN_LEN)60 rt_align(SDIO_ALIGN_LEN)
61 static rt_uint8_t cache_buf[SDIO_BUFF_SIZE];
62 
63 /**
64   * @brief  This function wait sdio completed.
65   * @param  sdio  swm_sdio_device
66   * @retval None
67   */
68 static void swm_sdio_wait_completed(struct swm_sdio_device *sdio)
69 {
70     rt_uint32_t status;
71     struct rt_mmcsd_cmd *cmd = sdio->pkg->cmd;
72     struct rt_mmcsd_data *data = cmd->data;
73     SDIO_TypeDef *swm_sdio = sdio->sdio_des.swm_sdio;
74 
75     if (rt_event_recv(&sdio->event, 0xffffffff, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
76                       rt_tick_from_millisecond(2000), &status) != RT_EOK)
77     {
78         LOG_E("wait completed timeout");
79         cmd->err = -RT_ETIMEOUT;
80         return;
81     }
82 
83     if (sdio->pkg == RT_NULL)
84     {
85         return;
86     }
87 
88     if (resp_type(cmd) == RESP_NONE)
89     {
90         ;
91     }
92     else if (resp_type(cmd) == RESP_R2)
93     {
94         LOG_D("R2");
95         cmd->resp[0] = (swm_sdio->RESP[3] << 8) + ((swm_sdio->RESP[2] >> 24) & 0xFF);
96         cmd->resp[1] = (swm_sdio->RESP[2] << 8) + ((swm_sdio->RESP[1] >> 24) & 0xFF);
97         cmd->resp[2] = (swm_sdio->RESP[1] << 8) + ((swm_sdio->RESP[0] >> 24) & 0xFF);
98         cmd->resp[3] = (swm_sdio->RESP[0] << 8) + 0x00;
99     }
100     else
101     {
102         cmd->resp[0] = swm_sdio->RESP[0];
103     }
104 
105     if (status & SDIO_IF_ERROR_Msk)
106     {
107         if ((status & SDIO_IF_CMDCRCERR_Msk) && (resp_type(cmd) & (RESP_R3 | RESP_R4)))
108         {
109             cmd->err = RT_EOK;
110         }
111         else
112         {
113             cmd->err = -RT_ERROR;
114         }
115 
116         if (status & SDIO_IF_CMDCRCERR_Msk)
117         {
118             SDIO->CR2 |= (1 << SDIO_CR2_RSTCMD_Pos);
119             data->err = -RT_ERROR;
120         }
121 
122         if (status & SDIO_IF_CMDTIMEOUT_Msk)
123         {
124             SDIO->CR2 |= (1 << SDIO_CR2_RSTCMD_Pos);
125             cmd->err = -RT_ETIMEOUT;
126         }
127 
128         if (status & SDIO_IF_DATCRCERR_Msk)
129         {
130             SDIO->CR2 |= (1 << SDIO_CR2_RSTDAT_Pos);
131             data->err = -RT_ERROR;
132         }
133 
134         if (status & SDIO_IF_DATTIMEOUT_Msk)
135         {
136             SDIO->CR2 |= (1 << SDIO_CR2_RSTDAT_Pos);
137             data->err = -RT_ETIMEOUT;
138         }
139 
140         if (cmd->err == RT_EOK)
141         {
142             LOG_D("sta:0x%08X [%08X %08X %08X %08X]", status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
143         }
144         else
145         {
146             LOG_D("err:0x%08x, %s%s%s%s%s cmd:%d arg:0x%08x rw:%c len:%d blksize:%d",
147                   status,
148                   status & SDIO_IF_CMDCRCERR_Msk  ? "CCRCFAIL "    : "",
149                   status & SDIO_IF_DATCRCERR_Msk  ? "DCRCFAIL "    : "",
150                   status & SDIO_IF_CMDTIMEOUT_Msk ? "CTIMEOUT "    : "",
151                   status & SDIO_IF_DATTIMEOUT_Msk ? "DTIMEOUT "    : "",
152                   status == 0 ? "NULL" : "",
153                   cmd->cmd_code,
154                   cmd->arg,
155                   data ? (data->flags & DATA_DIR_WRITE ? 'w' : 'r') : '-',
156                   data ? data->blks * data->blksize : 0,
157                   data ? data->blksize : 0);
158         }
159     }
160     else
161     {
162         cmd->err = RT_EOK;
163         LOG_D("sta:0x%08X [%08X %08X %08X %08X]", status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
164     }
165 }
166 
167 /**
168   * @brief  This function transfer data by dma.
169   * @param  sdio  swm_sdio_device
170   * @param  pkg   sdio package
171   * @retval None
172   */
swm_sdio_transfer(struct swm_sdio_device * sdio,struct swm_sdio_pkg * pkg)173 static void swm_sdio_transfer(struct swm_sdio_device *sdio, struct swm_sdio_pkg *pkg)
174 {
175     struct rt_mmcsd_data *data;
176     int size;
177     void *buff;
178 
179     if ((RT_NULL == pkg) || (RT_NULL == sdio))
180     {
181         LOG_E("swm_sdio_transfer invalid args");
182         return;
183     }
184 
185     data = pkg->cmd->data;
186     if (RT_NULL == data)
187     {
188         LOG_E("swm_sdio_transfer invalid args");
189         return;
190     }
191 
192     buff = pkg->buff;
193     if (RT_NULL == buff)
194     {
195         LOG_E("swm_sdio_transfer invalid args");
196         return;
197     }
198 
199     size = data->blks * data->blksize;
200 
201     if (data->flags & DATA_DIR_WRITE)
202     {
203         sdio->sdio_des.txconfig(pkg, (rt_uint32_t *)buff, size);
204     }
205     else if (data->flags & DATA_DIR_READ)
206     {
207         sdio->sdio_des.rxconfig(pkg, (rt_uint32_t *)buff, size);
208     }
209 }
210 
211 /**
212   * @brief  This function send command.
213   * @param  sdio  swm_sdio_device
214   * @param  pkg   sdio package
215   * @retval None
216   */
swm_sdio_send_command(struct swm_sdio_device * sdio,struct swm_sdio_pkg * pkg)217 static void swm_sdio_send_command(struct swm_sdio_device *sdio, struct swm_sdio_pkg *pkg)
218 {
219     struct rt_mmcsd_cmd *cmd = pkg->cmd;
220     struct rt_mmcsd_data *data = cmd->data;
221     SDIO_TypeDef *swm_sdio = sdio->sdio_des.swm_sdio;
222     rt_uint32_t reg_cmd;
223 
224     /* save pkg */
225     sdio->pkg = pkg;
226 
227     LOG_D("CMD:%d ARG:0x%08x RES:%s%s%s%s%s%s%s%s%s rw:%c len:%d blksize:%d",
228           cmd->cmd_code,
229           cmd->arg,
230           resp_type(cmd) == RESP_NONE ? "NONE" : "",
231           resp_type(cmd) == RESP_R1 ? "R1" : "",
232           resp_type(cmd) == RESP_R1B ? "R1B" : "",
233           resp_type(cmd) == RESP_R2 ? "R2" : "",
234           resp_type(cmd) == RESP_R3 ? "R3" : "",
235           resp_type(cmd) == RESP_R4 ? "R4" : "",
236           resp_type(cmd) == RESP_R5 ? "R5" : "",
237           resp_type(cmd) == RESP_R6 ? "R6" : "",
238           resp_type(cmd) == RESP_R7 ? "R7" : "",
239           data ? (data->flags & DATA_DIR_WRITE ? 'w' : 'r') : '-',
240           data ? data->blks * data->blksize : 0,
241           data ? data->blksize : 0);
242 
243     /* config cmd reg */
244     reg_cmd = (cmd->cmd_code << SDIO_CMD_CMDINDX_Pos) |
245               (0 << SDIO_CMD_CMDTYPE_Pos) |
246               (0 << SDIO_CMD_IDXCHECK_Pos) |
247               (0 << SDIO_CMD_CRCCHECK_Pos) |
248               (0 << SDIO_CMD_DMAEN_Pos);
249     if (resp_type(cmd) == RESP_NONE)
250         reg_cmd |= SD_RESP_NO << SDIO_CMD_RESPTYPE_Pos;
251     else if (resp_type(cmd) == RESP_R2)
252         reg_cmd |= SD_RESP_128b << SDIO_CMD_RESPTYPE_Pos;
253     else
254         reg_cmd |= SD_RESP_32b << SDIO_CMD_RESPTYPE_Pos;
255 
256     /* config data reg */
257     if (data != RT_NULL)
258     {
259         rt_uint32_t dir = 0;
260         dir = (data->flags & DATA_DIR_READ) ? 1 : 0;
261 
262         swm_sdio->BLK = (data->blks << SDIO_BLK_COUNT_Pos) | (data->blksize << SDIO_BLK_SIZE_Pos);
263 
264         reg_cmd |= (1 << SDIO_CMD_HAVEDATA_Pos) |
265                    (dir << SDIO_CMD_DIRREAD_Pos) |
266                    ((data->blks > 1) << SDIO_CMD_MULTBLK_Pos) |
267                    ((data->blks > 1) << SDIO_CMD_BLKCNTEN_Pos) |
268                    (0 << SDIO_CMD_AUTOCMD12_Pos);
269     }
270     else
271     {
272         reg_cmd |= (0 << SDIO_CMD_HAVEDATA_Pos);
273     }
274 
275     /* send cmd */
276     swm_sdio->ARG = cmd->arg;
277     swm_sdio->CMD = reg_cmd;
278 
279     /* transfer config */
280     if (data != RT_NULL)
281     {
282         swm_sdio_transfer(sdio, pkg);
283     }
284 
285     /* wait completed */
286     swm_sdio_wait_completed(sdio);
287 
288     /* clear pkg */
289     sdio->pkg = RT_NULL;
290 }
291 
292 /**
293   * @brief  This function send sdio request.
294   * @param  sdio  swm_sdio_device
295   * @param  req   request
296   * @retval None
297   */
swm_sdio_request(struct rt_mmcsd_host * host,struct rt_mmcsd_req * req)298 static void swm_sdio_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
299 {
300     struct swm_sdio_pkg pkg;
301     struct swm_sdio_device *sdio = host->private_data;
302     struct rt_mmcsd_data *data;
303 
304     RTHW_SDIO_LOCK(sdio);
305 
306     if (req->cmd != RT_NULL)
307     {
308         rt_memset(&pkg, 0, sizeof(pkg));
309         data = req->cmd->data;
310         pkg.cmd = req->cmd;
311 
312         if (data != RT_NULL)
313         {
314             rt_uint32_t size = data->blks * data->blksize;
315 
316             RT_ASSERT(size <= SDIO_BUFF_SIZE);
317 
318             pkg.buff = data->buf;
319             if ((rt_uint32_t)data->buf & (SDIO_ALIGN_LEN - 1))
320             {
321                 pkg.buff = cache_buf;
322                 if (data->flags & DATA_DIR_WRITE)
323                 {
324                     rt_memcpy(cache_buf, data->buf, size);
325                 }
326             }
327         }
328 
329         swm_sdio_send_command(sdio, &pkg);
330 
331         if ((data != RT_NULL) && (data->flags & DATA_DIR_READ) && ((rt_uint32_t)data->buf & (SDIO_ALIGN_LEN - 1)))
332         {
333             rt_memcpy(data->buf, cache_buf, data->blksize * data->blks);
334         }
335     }
336 
337     if (req->stop != RT_NULL)
338     {
339         rt_memset(&pkg, 0, sizeof(pkg));
340         pkg.cmd = req->stop;
341         swm_sdio_send_command(sdio, &pkg);
342     }
343 
344     RTHW_SDIO_UNLOCK(sdio);
345 
346     mmcsd_req_complete(sdio->host);
347 }
348 
349 /**
350   * @brief  This function config sdio.
351   * @param  host    rt_mmcsd_host
352   * @param  io_cfg  rt_mmcsd_io_cfg
353   * @retval None
354   */
swm_sdio_set_iocfg(struct rt_mmcsd_host * host,struct rt_mmcsd_io_cfg * io_cfg)355 static void swm_sdio_set_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
356 {
357     rt_uint32_t clkcr, div, clk_src;
358     rt_uint32_t clk = io_cfg->clock;
359     struct swm_sdio_device *sdio = host->private_data;
360     SDIO_TypeDef *swm_sdio = sdio->sdio_des.swm_sdio;
361 
362     clk_src = sdio->sdio_des.clk_get(sdio->sdio_des.swm_sdio);
363     if (clk_src < 400 * 1000)
364     {
365         LOG_E("The clock rate is too low! rata:%d", clk_src);
366         return;
367     }
368 
369     if (clk > host->freq_max)
370         clk = host->freq_max;
371 
372     if (clk > clk_src)
373     {
374         LOG_W("Setting rate is greater than clock source rate.");
375         clk = clk_src;
376     }
377 
378     LOG_D("clk:%d width:%s%s%s power:%s%s%s",
379           clk,
380           io_cfg->bus_width == MMCSD_BUS_WIDTH_8 ? "8" : "",
381           io_cfg->bus_width == MMCSD_BUS_WIDTH_4 ? "4" : "",
382           io_cfg->bus_width == MMCSD_BUS_WIDTH_1 ? "1" : "",
383           io_cfg->power_mode == MMCSD_POWER_OFF ? "OFF" : "",
384           io_cfg->power_mode == MMCSD_POWER_UP ? "UP" : "",
385           io_cfg->power_mode == MMCSD_POWER_ON ? "ON" : "");
386 
387     RTHW_SDIO_LOCK(sdio);
388 
389     swm_sdio->CR1 = (1 << SDIO_CR1_CDSRC_Pos) | (7 << SDIO_CR1_VOLT_Pos);
390     if (io_cfg->bus_width == MMCSD_BUS_WIDTH_8)
391     {
392         swm_sdio->CR1 |= (1 << SDIO_CR1_8BIT_Pos);
393     }
394     else
395     {
396         swm_sdio->CR1 &= ~SDIO_CR1_8BIT_Msk;
397         if (io_cfg->bus_width == MMCSD_BUS_WIDTH_4)
398         {
399             swm_sdio->CR1 |= (1 << SDIO_CR1_4BIT_Pos);
400         }
401         else
402         {
403             swm_sdio->CR1 &= ~SDIO_CR1_4BIT_Msk;
404         }
405     }
406     switch (io_cfg->power_mode)
407     {
408     case MMCSD_POWER_OFF:
409         swm_sdio->CR1 &= ~SDIO_CR1_PWRON_Msk;
410         break;
411     case MMCSD_POWER_UP:
412     case MMCSD_POWER_ON:
413         swm_sdio->CR1 |= (1 << SDIO_CR1_PWRON_Pos);
414         break;
415     default:
416         LOG_W("unknown power_mode %d", io_cfg->power_mode);
417         break;
418     }
419 
420     div = clk_src / clk;
421     if ((clk == 0) || (div == 0))
422     {
423         clkcr = 0;
424     }
425     else
426     {
427         if (div > 128)
428             clkcr = 0x80;
429         else if (div > 64)
430             clkcr = 0x40;
431         else if (div > 32)
432             clkcr = 0x20;
433         else if (div > 16)
434             clkcr = 0x10;
435         else if (div > 8)
436             clkcr = 0x08;
437         else if (div > 4)
438             clkcr = 0x04;
439         else if (div > 2)
440             clkcr = 0x02;
441         else if (div > 1)
442             clkcr = 0x01;
443         else
444             clkcr = 0x00;
445     }
446 
447     SDIO->CR2 = (1 << SDIO_CR2_CLKEN_Pos) |
448                 (1 << SDIO_CR2_SDCLKEN_Pos) |
449                 (clkcr << SDIO_CR2_SDCLKDIV_Pos) |
450                 (0xC << SDIO_CR2_TIMEOUT_Pos); // 2**25 SDIO_CLK
451 
452     while ((SDIO->CR2 & SDIO_CR2_CLKRDY_Msk) == 0)
453         ;
454 
455     RTHW_SDIO_UNLOCK(sdio);
456 }
457 
458 /**
459   * @brief  This function delect sdcard.
460   * @param  host    rt_mmcsd_host
461   * @retval 0x01
462   */
swm_sdio_get_card_status(struct rt_mmcsd_host * host)463 static rt_int32_t swm_sdio_get_card_status(struct rt_mmcsd_host *host)
464 {
465     LOG_D("try to detect device");
466     return 0x01;
467 }
468 
469 /**
470   * @brief  This function update sdio interrupt.
471   * @param  host    rt_mmcsd_host
472   * @param  enable
473   * @retval None
474   */
swm_sdio_enable_irq(struct rt_mmcsd_host * host,rt_int32_t enable)475 void swm_sdio_enable_irq(struct rt_mmcsd_host *host, rt_int32_t enable)
476 {
477     struct swm_sdio_device *sdio = host->private_data;
478     SDIO_TypeDef *swm_sdio = sdio->sdio_des.swm_sdio;
479 
480     if (enable)
481     {
482         LOG_D("enable sdio irq");
483         swm_sdio->IM = 0xFFFFFFFF;
484         swm_sdio->IE = 0xFFFF000F;
485     }
486     else
487     {
488         LOG_D("disable sdio irq");
489         swm_sdio->IM &= ~0xFFFFFFFF;
490         swm_sdio->IE &= ~0xFFFFFFFF;
491     }
492 }
493 
494 static const struct rt_mmcsd_host_ops swm_sdio_ops =
495     {
496         .request = swm_sdio_request,
497         .set_iocfg = swm_sdio_set_iocfg,
498         .get_card_status = swm_sdio_get_card_status,
499         .enable_sdio_irq = swm_sdio_enable_irq,
500 };
501 
swm_sdio_host_create(struct swm_sdio_des * sdio_des)502 struct rt_mmcsd_host *swm_sdio_host_create(struct swm_sdio_des *sdio_des)
503 {
504     struct rt_mmcsd_host *host;
505     struct swm_sdio_device *sdio = RT_NULL;
506 
507     if ((sdio_des == RT_NULL) || (sdio_des->txconfig == RT_NULL) || (sdio_des->rxconfig == RT_NULL))
508     {
509         LOG_E("L:%d F:%s %s %s %s",
510               (sdio_des == RT_NULL ? "sdio_des is NULL" : ""),
511               (sdio_des ? (sdio_des->txconfig ? "txconfig is NULL" : "") : ""),
512               (sdio_des ? (sdio_des->rxconfig ? "rxconfig is NULL" : "") : ""));
513         return RT_NULL;
514     }
515 
516     sdio = rt_malloc(sizeof(struct swm_sdio_device));
517     if (sdio == RT_NULL)
518     {
519         LOG_E("L:%d F:%s malloc swm_sdio_device fail");
520         return RT_NULL;
521     }
522     rt_memset(sdio, 0, sizeof(struct swm_sdio_device));
523 
524     host = mmcsd_alloc_host();
525     if (host == RT_NULL)
526     {
527         LOG_E("L:%d F:%s mmcsd alloc host fail");
528         rt_free(sdio);
529         return RT_NULL;
530     }
531 
532     rt_memcpy(&sdio->sdio_des, sdio_des, sizeof(struct swm_sdio_des));
533 
534     rt_event_init(&sdio->event, "sdio", RT_IPC_FLAG_FIFO);
535     rt_mutex_init(&sdio->mutex, "sdio", RT_IPC_FLAG_FIFO);
536 
537     /* set host defautl attributes */
538     host->ops = &swm_sdio_ops;
539     host->freq_min = 400 * 1000;
540     host->freq_max = SDIO_MAX_FREQ;
541     host->valid_ocr = 0X00FFFF80; /* The voltage range supported is 1.65v-3.6v */
542 #ifndef SDIO_USING_1_BIT
543     host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ;
544 #else
545     host->flags = MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ;
546 #endif
547     host->max_seg_size = SDIO_BUFF_SIZE;
548     host->max_dma_segs = 1;
549     host->max_blk_size = 512;
550     host->max_blk_count = 512;
551 
552     /* link up host and sdio */
553     sdio->host = host;
554     host->private_data = sdio;
555 
556     swm_sdio_enable_irq(host, 1);
557 
558     /* ready to change */
559     mmcsd_change(host);
560 
561     return host;
562 }
563 
swm_sdio_clock_get(SDIO_TypeDef * swm_sdio)564 static rt_uint32_t swm_sdio_clock_get(SDIO_TypeDef *swm_sdio)
565 {
566     uint32_t prediv;
567     switch((SYS->CLKSEL & SYS_CLKSEL_SDIO_Msk) >> SYS_CLKSEL_SDIO_Pos)
568     {
569         case 0: prediv = 1; break;
570         case 1: prediv = 3; break;
571         case 2: prediv = 2; break;
572         case 3: prediv = 0; break;
573     }
574     return (SystemCoreClock / (1 << prediv));
575 }
576 
swm_sdio_rxconfig(struct swm_sdio_pkg * pkg,rt_uint32_t * buff,int size)577 static rt_err_t swm_sdio_rxconfig(struct swm_sdio_pkg *pkg, rt_uint32_t *buff, int size)
578 {
579     struct rt_mmcsd_cmd *cmd = pkg->cmd;
580     struct rt_mmcsd_data *data = cmd->data;
581     int offset = 0;
582     for (uint32_t i = 0; i < data->blks; i++)
583     {
584         offset = i* data->blksize / 4;
585         while ((SDIO->IF & SDIO_IF_BUFRDRDY_Msk) == 0)
586             __NOP();
587         SDIO->IF = SDIO_IF_BUFRDRDY_Msk;
588         for (uint32_t j = 0; j < data->blksize / 4; j++)
589         {
590             buff[offset + j] = SDIO->DATA;
591         }
592     }
593     return RT_EOK;
594 }
595 
swm_sdio_txconfig(struct swm_sdio_pkg * pkg,rt_uint32_t * buff,int size)596 static rt_err_t swm_sdio_txconfig(struct swm_sdio_pkg *pkg, rt_uint32_t *buff, int size)
597 {
598     struct rt_mmcsd_cmd *cmd = pkg->cmd;
599     struct rt_mmcsd_data *data = cmd->data;
600     int offset = 0;
601     for (uint32_t i = 0; i < data->blks; i++)
602     {
603         offset = i* data->blksize / 4;
604         while ((SDIO->IF & SDIO_IF_BUFWRRDY_Msk) == 0)
605             __NOP();
606         SDIO->IF = SDIO_IF_BUFWRRDY_Msk;
607         for (uint32_t j = 0; j < data->blksize / 4; j++)
608         {
609             SDIO->DATA = buff[offset + j];
610         }
611     }
612     return RT_EOK;
613 }
614 
615 /**
616   * @brief  This function interrupt process function.
617   * @param  host  rt_mmcsd_host
618   * @retval None
619   */
swm_sdio_irq_process(struct rt_mmcsd_host * host)620 static void swm_sdio_irq_process(struct rt_mmcsd_host *host)
621 {
622     int complete = 0;
623     struct swm_sdio_device *sdio = host->private_data;
624     SDIO_TypeDef *swm_sdio = sdio->sdio_des.swm_sdio;
625     rt_uint32_t intstatus = swm_sdio->IF;
626 
627     if (intstatus & SDIO_IF_ERROR_Msk)
628     {
629         swm_sdio->IF = 0xFFFFFFFF;
630         complete = 1;
631     }
632     else
633     {
634         if (intstatus & SDIO_IF_CMDDONE_Msk)
635         {
636             swm_sdio->IF = SDIO_IF_CMDDONE_Msk;
637             if (sdio->pkg != RT_NULL)
638             {
639                 if (!sdio->pkg->cmd->data)
640                 {
641                     complete = 1;
642                 }
643             }
644         }
645 
646         if (intstatus & SDIO_IF_TRXDONE_Msk)
647         {
648             swm_sdio->IF = SDIO_IF_TRXDONE_Msk;
649             complete = 1;
650         }
651     }
652 
653     if (complete)
654     {
655         rt_event_send(&sdio->event, intstatus);
656     }
657 }
658 
SDIO_Handler(void)659 void SDIO_Handler(void)
660 {
661     /* enter interrupt */
662     rt_interrupt_enter();
663     /* Process All SDIO Interrupt Sources */
664     swm_sdio_irq_process(host);
665     /* leave interrupt */
666     rt_interrupt_leave();
667 }
668 
swm_sdio_init(void)669 int swm_sdio_init(void)
670 {
671     int result = RT_EOK;
672 
673     struct swm_sdio_des sdio_des;
674 
675     PORT_Init(PORTM, PIN2, PORTM_PIN2_SD_CLK, 0);
676     PORT_Init(PORTM, PIN4, PORTM_PIN4_SD_CMD, 1);
677     PORT_Init(PORTM, PIN5, PORTM_PIN5_SD_D0, 1);
678     PORT_Init(PORTM, PIN6, PORTM_PIN6_SD_D1, 1);
679     PORT_Init(PORTN, PIN0, PORTN_PIN0_SD_D2, 1);
680     PORT_Init(PORTN, PIN1, PORTN_PIN1_SD_D3, 1);
681 
682     NVIC_EnableIRQ(SDIO_IRQn);
683     SYS->CLKSEL &= ~SYS_CLKSEL_SDIO_Msk;
684     if (SystemCoreClock > 80000000)                //SDIO时钟需要小于52MHz
685         SYS->CLKSEL |= (2 << SYS_CLKSEL_SDIO_Pos); //SDCLK = SYSCLK / 4
686     else
687         SYS->CLKSEL |= (0 << SYS_CLKSEL_SDIO_Pos); //SDCLK = SYSCLK / 2
688 
689     SYS->CLKEN0 |= (0x01 << SYS_CLKEN0_SDIO_Pos);
690 
691     SDIO->CR2 = (1 << SDIO_CR2_RSTALL_Pos);
692 
693     NVIC_EnableIRQ(SDIO_IRQn);
694     sdio_des.clk_get = swm_sdio_clock_get;
695     sdio_des.swm_sdio = SDIO;
696     sdio_des.rxconfig = swm_sdio_rxconfig;
697     sdio_des.txconfig = swm_sdio_txconfig;
698 
699     host = swm_sdio_host_create(&sdio_des);
700     if (host == RT_NULL)
701     {
702         LOG_E("host create fail.");
703         result = -1;
704     }
705     else
706     {
707         LOG_D("host create success.");
708         result = 0;
709     }
710     return result;
711 }
712 INIT_DEVICE_EXPORT(swm_sdio_init);
713 
714 #endif /* BSP_USING_SDIO */
715 #endif /* RT_USING_SDIO */
716