1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2023-03-14     luobeihai    first version
9  * 2023-03-27     luobeihai    add APM32E1 series MCU support
10  */
11 
12 #include "board.h"
13 #include "drv_sdio.h"
14 
15 #ifdef BSP_USING_SDIO
16 
17 //#define DRV_DEBUG
18 #define LOG_TAG             "drv.sdio"
19 #include <drv_log.h>
20 
21 static struct apm32_sdio_config sdio_config = SDIO_BUS_CONFIG;
22 static struct apm32_sdio_class sdio_obj;
23 static struct rt_mmcsd_host *host;
24 
25 #define SDIO_TX_RX_COMPLETE_TIMEOUT_LOOPS    (100000)
26 
27 #define RTHW_SDIO_LOCK(_sdio)   rt_mutex_take(&_sdio->mutex, RT_WAITING_FOREVER)
28 #define RTHW_SDIO_UNLOCK(_sdio) rt_mutex_release(&_sdio->mutex);
29 
30 struct sdio_pkg
31 {
32     struct rt_mmcsd_cmd *cmd;
33     void *buff;
34     rt_uint32_t flag;
35 };
36 
37 struct rthw_sdio
38 {
39     struct rt_mmcsd_host *host;
40     struct apm32_sdio_des sdio_des;
41     struct rt_event event;
42     struct rt_mutex mutex;
43     struct sdio_pkg *pkg;
44 };
45 
rt_align(SDIO_ALIGN_LEN)46 rt_align(SDIO_ALIGN_LEN)
47 static rt_uint8_t cache_buf[SDIO_BUFF_SIZE];
48 
49 static rt_uint32_t apm32_sdio_clk_get(struct apm32_sdio *hw_sdio)
50 {
51     return SDIO_CLOCK_FREQ;
52 }
53 
54 /**
55   * @brief  This function get order from sdio.
56   * @param  data
57   * @retval sdio  order
58   */
get_order(rt_uint32_t data)59 static int get_order(rt_uint32_t data)
60 {
61     int order = 0;
62 
63     switch (data)
64     {
65     case 1:
66         order = 0;
67         break;
68     case 2:
69         order = 1;
70         break;
71     case 4:
72         order = 2;
73         break;
74     case 8:
75         order = 3;
76         break;
77     case 16:
78         order = 4;
79         break;
80     case 32:
81         order = 5;
82         break;
83     case 64:
84         order = 6;
85         break;
86     case 128:
87         order = 7;
88         break;
89     case 256:
90         order = 8;
91         break;
92     case 512:
93         order = 9;
94         break;
95     case 1024:
96         order = 10;
97         break;
98     case 2048:
99         order = 11;
100         break;
101     case 4096:
102         order = 12;
103         break;
104     case 8192:
105         order = 13;
106         break;
107     case 16384:
108         order = 14;
109         break;
110     default :
111         order = 0;
112         break;
113     }
114 
115     return order;
116 }
117 
118 /**
119   * @brief  This function wait sdio completed.
120   * @param  sdio  rthw_sdio
121   * @retval None
122   */
rthw_sdio_wait_completed(struct rthw_sdio * sdio)123 static void rthw_sdio_wait_completed(struct rthw_sdio *sdio)
124 {
125     rt_uint32_t status;
126     struct rt_mmcsd_cmd *cmd = sdio->pkg->cmd;
127     struct rt_mmcsd_data *data = cmd->data;
128     struct apm32_sdio *hw_sdio = sdio->sdio_des.hw_sdio;
129 
130     if (rt_event_recv(&sdio->event, 0xffffffff, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
131                       rt_tick_from_millisecond(5000), &status) != RT_EOK)
132     {
133         LOG_E("wait completed timeout");
134         cmd->err = -RT_ETIMEOUT;
135         return;
136     }
137 
138     if (sdio->pkg == RT_NULL)
139     {
140         return;
141     }
142 
143     cmd->resp[0] = hw_sdio->resp1;
144     cmd->resp[1] = hw_sdio->resp2;
145     cmd->resp[2] = hw_sdio->resp3;
146     cmd->resp[3] = hw_sdio->resp4;
147 
148     if (status & HW_SDIO_ERRORS)
149     {
150         if ((status & HW_SDIO_IT_CCRCFAIL) && (resp_type(cmd) & (RESP_R3 | RESP_R4)))
151         {
152             cmd->err = RT_EOK;
153         }
154         else
155         {
156             cmd->err = -RT_ERROR;
157         }
158 
159         if (status & HW_SDIO_IT_CTIMEOUT)
160         {
161             cmd->err = -RT_ETIMEOUT;
162         }
163 
164         if (status & HW_SDIO_IT_DCRCFAIL)
165         {
166             data->err = -RT_ERROR;
167         }
168 
169         if (status & HW_SDIO_IT_DTIMEOUT)
170         {
171             data->err = -RT_ETIMEOUT;
172         }
173 
174         if (cmd->err == RT_EOK)
175         {
176             LOG_D("sta:0x%08X [%08X %08X %08X %08X]", status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
177         }
178         else
179         {
180             LOG_D("err:0x%08x, %s%s%s%s%s%s%s cmd:%d arg:0x%08x rw:%c len:%d blksize:%d",
181                   status,
182                   status & HW_SDIO_IT_CCRCFAIL  ? "CCRCFAIL "    : "",
183                   status & HW_SDIO_IT_DCRCFAIL  ? "DCRCFAIL "    : "",
184                   status & HW_SDIO_IT_CTIMEOUT  ? "CTIMEOUT "    : "",
185                   status & HW_SDIO_IT_DTIMEOUT  ? "DTIMEOUT "    : "",
186                   status & HW_SDIO_IT_TXUNDERR  ? "TXUNDERR "    : "",
187                   status & HW_SDIO_IT_RXOVERR   ? "RXOVERR "     : "",
188                   status == 0                   ? "NULL"         : "",
189                   cmd->cmd_code,
190                   cmd->arg,
191                   data ? (data->flags & DATA_DIR_WRITE ?  'w' : 'r') : '-',
192                   data ? data->blks * data->blksize : 0,
193                   data ? data->blksize : 0
194                  );
195         }
196     }
197     else
198     {
199         cmd->err = RT_EOK;
200         LOG_D("sta:0x%08X [%08X %08X %08X %08X]", status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
201     }
202 }
203 
204 /**
205   * @brief  This function transfer data by dma.
206   * @param  sdio  rthw_sdio
207   * @param  pkg   sdio package
208   * @retval None
209   */
rthw_sdio_transfer_by_dma(struct rthw_sdio * sdio,struct sdio_pkg * pkg)210 static void rthw_sdio_transfer_by_dma(struct rthw_sdio *sdio, struct sdio_pkg *pkg)
211 {
212     struct rt_mmcsd_data *data;
213     int size;
214     void *buff;
215     struct apm32_sdio *hw_sdio;
216 
217     if ((RT_NULL == pkg) || (RT_NULL == sdio))
218     {
219         LOG_E("rthw_sdio_transfer_by_dma invalid args");
220         return;
221     }
222 
223     data = pkg->cmd->data;
224     if (RT_NULL == data)
225     {
226         LOG_E("rthw_sdio_transfer_by_dma invalid args");
227         return;
228     }
229 
230     buff = pkg->buff;
231     if (RT_NULL == buff)
232     {
233         LOG_E("rthw_sdio_transfer_by_dma invalid args");
234         return;
235     }
236     hw_sdio = sdio->sdio_des.hw_sdio;
237     size = data->blks * data->blksize;
238 
239     if (data->flags & DATA_DIR_WRITE)
240     {
241         sdio->sdio_des.txconfig((rt_uint32_t *)buff, (rt_uint32_t *)&hw_sdio->fifo, size);
242         hw_sdio->dctrl |= HW_SDIO_DMA_ENABLE;
243     }
244     else if (data->flags & DATA_DIR_READ)
245     {
246         sdio->sdio_des.rxconfig((rt_uint32_t *)&hw_sdio->fifo, (rt_uint32_t *)buff, size);
247         hw_sdio->dctrl |= HW_SDIO_DMA_ENABLE | HW_SDIO_DPSM_ENABLE;
248     }
249 }
250 
251 /**
252   * @brief  This function send command.
253   * @param  sdio  rthw_sdio
254   * @param  pkg   sdio package
255   * @retval None
256   */
rthw_sdio_send_command(struct rthw_sdio * sdio,struct sdio_pkg * pkg)257 static void rthw_sdio_send_command(struct rthw_sdio *sdio, struct sdio_pkg *pkg)
258 {
259     struct rt_mmcsd_cmd *cmd = pkg->cmd;
260     struct rt_mmcsd_data *data = cmd->data;
261     struct apm32_sdio *hw_sdio = sdio->sdio_des.hw_sdio;
262     rt_uint32_t reg_cmd;
263 
264     /* save pkg */
265     sdio->pkg = pkg;
266 
267     LOG_D("CMD:%d ARG:0x%08x RES:%s%s%s%s%s%s%s%s%s rw:%c len:%d blksize:%d",
268           cmd->cmd_code,
269           cmd->arg,
270           resp_type(cmd) == RESP_NONE ? "NONE"  : "",
271           resp_type(cmd) == RESP_R1  ? "R1"  : "",
272           resp_type(cmd) == RESP_R1B ? "R1B"  : "",
273           resp_type(cmd) == RESP_R2  ? "R2"  : "",
274           resp_type(cmd) == RESP_R3  ? "R3"  : "",
275           resp_type(cmd) == RESP_R4  ? "R4"  : "",
276           resp_type(cmd) == RESP_R5  ? "R5"  : "",
277           resp_type(cmd) == RESP_R6  ? "R6"  : "",
278           resp_type(cmd) == RESP_R7  ? "R7"  : "",
279           data ? (data->flags & DATA_DIR_WRITE ?  'w' : 'r') : '-',
280           data ? data->blks * data->blksize : 0,
281           data ? data->blksize : 0
282          );
283 
284     /* config cmd reg */
285     reg_cmd = cmd->cmd_code | HW_SDIO_CPSM_ENABLE;
286     if (resp_type(cmd) == RESP_NONE)
287         reg_cmd |= HW_SDIO_RESPONSE_NO;
288     else if (resp_type(cmd) == RESP_R2)
289         reg_cmd |= HW_SDIO_RESPONSE_LONG;
290     else
291         reg_cmd |= HW_SDIO_RESPONSE_SHORT;
292 
293     /* config data reg */
294     if (data != RT_NULL)
295     {
296         rt_uint32_t dir = 0;
297         rt_uint32_t size = data->blks * data->blksize;
298         int order;
299 
300         hw_sdio->dctrl = 0;
301         hw_sdio->dtimer = HW_SDIO_DATATIMEOUT;
302         hw_sdio->dlen = size;
303         order = get_order(data->blksize);
304         dir = (data->flags & DATA_DIR_READ) ? HW_SDIO_TO_HOST : 0;
305         hw_sdio->dctrl = HW_SDIO_IO_ENABLE | (order << 4) | dir;
306     }
307 
308     /* transfer config */
309     if (data != RT_NULL)
310     {
311         rthw_sdio_transfer_by_dma(sdio, pkg);
312     }
313 
314     /* open irq */
315     hw_sdio->mask |= HW_SDIO_IT_CMDSENT | HW_SDIO_IT_CMDREND | HW_SDIO_ERRORS;
316     if (data != RT_NULL)
317     {
318         hw_sdio->mask |= HW_SDIO_IT_DATAEND;
319     }
320 
321     /* send cmd */
322     hw_sdio->arg = cmd->arg;
323     hw_sdio->cmd = reg_cmd;
324 
325     /* wait completed */
326     rthw_sdio_wait_completed(sdio);
327 
328     /* Waiting for data to be sent to completion */
329     if (data != RT_NULL)
330     {
331         volatile rt_uint32_t count = SDIO_TX_RX_COMPLETE_TIMEOUT_LOOPS;
332 
333         while (count && (hw_sdio->sta & (HW_SDIO_IT_TXACT | HW_SDIO_IT_RXACT)))
334         {
335             count--;
336         }
337 
338         if ((count == 0) || (hw_sdio->sta & HW_SDIO_ERRORS))
339         {
340             cmd->err = -RT_ERROR;
341         }
342     }
343 
344     /* close irq, keep sdio irq */
345     hw_sdio->mask = hw_sdio->mask & HW_SDIO_IT_SDIOIT ? HW_SDIO_IT_SDIOIT : 0x00;
346 
347     /* clear pkg */
348     sdio->pkg = RT_NULL;
349 }
350 
351 /**
352   * @brief  This function send sdio request.
353   * @param  host  rt_mmcsd_host
354   * @param  req   request
355   * @retval None
356   */
rthw_sdio_request(struct rt_mmcsd_host * host,struct rt_mmcsd_req * req)357 static void rthw_sdio_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
358 {
359     struct sdio_pkg pkg;
360     struct rthw_sdio *sdio = host->private_data;
361     struct rt_mmcsd_data *data;
362 
363     RTHW_SDIO_LOCK(sdio);
364 
365     if (req->cmd != RT_NULL)
366     {
367         rt_memset(&pkg, 0, sizeof(pkg));
368         data = req->cmd->data;
369         pkg.cmd = req->cmd;
370 
371         if (data != RT_NULL)
372         {
373             rt_uint32_t size = data->blks * data->blksize;
374 
375             RT_ASSERT(size <= SDIO_BUFF_SIZE);
376 
377             pkg.buff = data->buf;
378             if ((rt_uint32_t)data->buf & (SDIO_ALIGN_LEN - 1))
379             {
380                 pkg.buff = cache_buf;
381                 if (data->flags & DATA_DIR_WRITE)
382                 {
383                     rt_memcpy(cache_buf, data->buf, size);
384                 }
385             }
386         }
387 
388         rthw_sdio_send_command(sdio, &pkg);
389 
390         if ((data != RT_NULL) && (data->flags & DATA_DIR_READ) && ((rt_uint32_t)data->buf & (SDIO_ALIGN_LEN - 1)))
391         {
392             rt_memcpy(data->buf, cache_buf, data->blksize * data->blks);
393         }
394     }
395 
396     if (req->stop != RT_NULL)
397     {
398         rt_memset(&pkg, 0, sizeof(pkg));
399         pkg.cmd = req->stop;
400         rthw_sdio_send_command(sdio, &pkg);
401     }
402 
403     RTHW_SDIO_UNLOCK(sdio);
404 
405     mmcsd_req_complete(sdio->host);
406 }
407 
408 /**
409   * @brief  This function config sdio.
410   * @param  host    rt_mmcsd_host
411   * @param  io_cfg  rt_mmcsd_io_cfg
412   * @retval None
413   */
rthw_sdio_iocfg(struct rt_mmcsd_host * host,struct rt_mmcsd_io_cfg * io_cfg)414 static void rthw_sdio_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
415 {
416     rt_uint32_t clkcr, div, clk_src;
417     rt_uint32_t clk = io_cfg->clock;
418     struct rthw_sdio *sdio = host->private_data;
419     struct apm32_sdio *hw_sdio = sdio->sdio_des.hw_sdio;
420 
421     clk_src = sdio->sdio_des.clk_get(sdio->sdio_des.hw_sdio);
422     if (clk_src < 400 * 1000)
423     {
424         LOG_E("The clock rate is too low! rata:%d", clk_src);
425         return;
426     }
427 
428     if (clk > host->freq_max) clk = host->freq_max;
429 
430     if (clk > clk_src)
431     {
432         LOG_W("Setting rate is greater than clock source rate.");
433         clk = clk_src;
434     }
435 
436     LOG_D("clk:%d width:%s%s%s power:%s%s%s",
437           clk,
438           io_cfg->bus_width == MMCSD_BUS_WIDTH_8 ? "8" : "",
439           io_cfg->bus_width == MMCSD_BUS_WIDTH_4 ? "4" : "",
440           io_cfg->bus_width == MMCSD_BUS_WIDTH_1 ? "1" : "",
441           io_cfg->power_mode == MMCSD_POWER_OFF ? "OFF" : "",
442           io_cfg->power_mode == MMCSD_POWER_UP ? "UP" : "",
443           io_cfg->power_mode == MMCSD_POWER_ON ? "ON" : ""
444          );
445 
446     RTHW_SDIO_LOCK(sdio);
447 
448     div = clk_src / clk;
449     if ((clk == 0) || (div == 0))
450     {
451         clkcr = 0;
452     }
453     else
454     {
455         if (div < 2)
456         {
457             div = 2;
458         }
459         else if (div > 0xFF)
460         {
461             div = 0xFF;
462         }
463         div -= 2;
464         clkcr = div | HW_SDIO_CLK_ENABLE;
465     }
466 
467     if (io_cfg->bus_width == MMCSD_BUS_WIDTH_8)
468     {
469         clkcr |= HW_SDIO_BUSWIDE_8B;
470     }
471     else if (io_cfg->bus_width == MMCSD_BUS_WIDTH_4)
472     {
473         clkcr |= HW_SDIO_BUSWIDE_4B;
474     }
475     else
476     {
477         clkcr |= HW_SDIO_BUSWIDE_1B;
478     }
479 
480     hw_sdio->clkcr = clkcr;
481 
482     switch (io_cfg->power_mode)
483     {
484     case MMCSD_POWER_OFF:
485         hw_sdio->power = HW_SDIO_POWER_OFF;
486         break;
487     case MMCSD_POWER_UP:
488         hw_sdio->power = HW_SDIO_POWER_UP;
489         break;
490     case MMCSD_POWER_ON:
491         hw_sdio->power = HW_SDIO_POWER_ON;
492         break;
493     default:
494         LOG_W("unknown power_mode %d", io_cfg->power_mode);
495         break;
496     }
497 
498     RTHW_SDIO_UNLOCK(sdio);
499 }
500 
501 /**
502   * @brief  This function update sdio interrupt.
503   * @param  host    rt_mmcsd_host
504   * @param  enable
505   * @retval None
506   */
rthw_sdio_irq_update(struct rt_mmcsd_host * host,rt_int32_t enable)507 void rthw_sdio_irq_update(struct rt_mmcsd_host *host, rt_int32_t enable)
508 {
509     struct rthw_sdio *sdio = host->private_data;
510     struct apm32_sdio *hw_sdio = sdio->sdio_des.hw_sdio;
511 
512     if (enable)
513     {
514         LOG_D("enable sdio irq");
515         hw_sdio->mask |= HW_SDIO_IT_SDIOIT;
516     }
517     else
518     {
519         LOG_D("disable sdio irq");
520         hw_sdio->mask &= ~HW_SDIO_IT_SDIOIT;
521     }
522 }
523 
524 /**
525   * @brief  This function detect sdcard.
526   * @param  host    rt_mmcsd_host
527   * @retval 0x01
528   */
rthw_sd_detect(struct rt_mmcsd_host * host)529 static rt_int32_t rthw_sd_detect(struct rt_mmcsd_host *host)
530 {
531     LOG_D("try to detect device");
532     return 0x01;
533 }
534 
535 /**
536   * @brief  This function interrupt process function.
537   * @param  host  rt_mmcsd_host
538   * @retval None
539   */
rthw_sdio_irq_process(struct rt_mmcsd_host * host)540 void rthw_sdio_irq_process(struct rt_mmcsd_host *host)
541 {
542     int complete = 0;
543     struct rthw_sdio *sdio = host->private_data;
544     struct apm32_sdio *hw_sdio = sdio->sdio_des.hw_sdio;
545     rt_uint32_t intstatus = hw_sdio->sta;
546 
547     if (intstatus & HW_SDIO_ERRORS)
548     {
549         hw_sdio->icr = HW_SDIO_ERRORS;
550         complete = 1;
551     }
552     else
553     {
554         if (intstatus & HW_SDIO_IT_CMDREND)
555         {
556             hw_sdio->icr = HW_SDIO_IT_CMDREND;
557 
558             if (sdio->pkg != RT_NULL)
559             {
560                 if (!sdio->pkg->cmd->data)
561                 {
562                     complete = 1;
563                 }
564                 else if ((sdio->pkg->cmd->data->flags & DATA_DIR_WRITE))
565                 {
566                     hw_sdio->dctrl |= HW_SDIO_DPSM_ENABLE;
567                 }
568             }
569         }
570 
571         if (intstatus & HW_SDIO_IT_CMDSENT)
572         {
573             hw_sdio->icr = HW_SDIO_IT_CMDSENT;
574 
575             if (resp_type(sdio->pkg->cmd) == RESP_NONE)
576             {
577                 complete = 1;
578             }
579         }
580 
581         if (intstatus & HW_SDIO_IT_DATAEND)
582         {
583             hw_sdio->icr = HW_SDIO_IT_DATAEND;
584             complete = 1;
585         }
586     }
587 
588     if ((intstatus & HW_SDIO_IT_SDIOIT) && (hw_sdio->mask & HW_SDIO_IT_SDIOIT))
589     {
590         hw_sdio->icr = HW_SDIO_IT_SDIOIT;
591         sdio_irq_wakeup(host);
592     }
593 
594     if (complete)
595     {
596         hw_sdio->mask &= ~HW_SDIO_ERRORS;
597         rt_event_send(&sdio->event, intstatus);
598     }
599 }
600 
601 static const struct rt_mmcsd_host_ops ops =
602 {
603     rthw_sdio_request,
604     rthw_sdio_iocfg,
605     rthw_sd_detect,
606     rthw_sdio_irq_update,
607 };
608 
609 /**
610   * @brief  This function create mmcsd host.
611   * @param  sdio_des  apm32_sdio_des
612   * @retval rt_mmcsd_host
613   */
sdio_host_create(struct apm32_sdio_des * sdio_des)614 struct rt_mmcsd_host *sdio_host_create(struct apm32_sdio_des *sdio_des)
615 {
616     struct rt_mmcsd_host *host;
617     struct rthw_sdio *sdio = RT_NULL;
618 
619     if ((sdio_des == RT_NULL) || (sdio_des->txconfig == RT_NULL) || (sdio_des->rxconfig == RT_NULL))
620     {
621         LOG_E("L:%d F:%s %s %s %s",
622               (sdio_des == RT_NULL ? "sdio_des is NULL" : ""),
623               (sdio_des ? (sdio_des->txconfig ? "txconfig is NULL" : "") : ""),
624               (sdio_des ? (sdio_des->rxconfig ? "rxconfig is NULL" : "") : "")
625              );
626         return RT_NULL;
627     }
628 
629     sdio = rt_malloc(sizeof(struct rthw_sdio));
630     if (sdio == RT_NULL)
631     {
632         LOG_E("L:%d F:%s malloc rthw_sdio fail");
633         return RT_NULL;
634     }
635     rt_memset(sdio, 0, sizeof(struct rthw_sdio));
636 
637     host = mmcsd_alloc_host();
638     if (host == RT_NULL)
639     {
640         LOG_E("L:%d F:%s mmcsd alloc host fail");
641         rt_free(sdio);
642         return RT_NULL;
643     }
644 
645     rt_memcpy(&sdio->sdio_des, sdio_des, sizeof(struct apm32_sdio_des));
646     sdio->sdio_des.hw_sdio = (sdio_des->hw_sdio == RT_NULL ? (struct apm32_sdio *)SDIO_BASE_ADDRESS : sdio_des->hw_sdio);
647     sdio->sdio_des.clk_get = (sdio_des->clk_get == RT_NULL ? apm32_sdio_clk_get : sdio_des->clk_get);
648 
649     rt_event_init(&sdio->event, "sdio", RT_IPC_FLAG_FIFO);
650     rt_mutex_init(&sdio->mutex, "sdio", RT_IPC_FLAG_PRIO);
651 
652     /* set host defautl attributes */
653     host->ops = &ops;
654     host->freq_min = 400 * 1000;
655     host->freq_max = SDIO_MAX_FREQ;
656     host->valid_ocr = 0X00FFFF80;/* The voltage range supported is 1.65v-3.6v */
657 #ifndef SDIO_USING_1_BIT
658     host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ;
659 #else
660     host->flags = MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ;
661 #endif
662     host->max_seg_size = SDIO_BUFF_SIZE;
663     host->max_dma_segs = 1;
664     host->max_blk_size = 512;
665     host->max_blk_count = 512;
666 
667     /* link up host and sdio */
668     sdio->host = host;
669     host->private_data = sdio;
670 
671     rthw_sdio_irq_update(host, 1);
672 
673     /* ready to change */
674     mmcsd_change(host);
675 
676     return host;
677 }
678 
679 /**
680   * @brief  This function configures the DMATX.
681   * @param  BufferSRC: pointer to the source buffer
682   * @param  BufferSize: buffer size
683   * @retval None
684   */
SD_LowLevel_DMA_TxConfig(uint32_t * src,uint32_t * dst,uint32_t BufferSize)685 void SD_LowLevel_DMA_TxConfig(uint32_t *src, uint32_t *dst, uint32_t BufferSize)
686 {
687     DMA_Config_T DMA_InitStructure;
688     static uint32_t size = 0;
689 
690     size += BufferSize * 4;
691     sdio_obj.cfg = &sdio_config;
692     sdio_obj.dma.handle_tx = sdio_config.dma_tx.Instance;
693 
694 #if defined (SOC_SERIES_APM32F1) || defined (SOC_SERIES_APM32E1)
695     /* clear DMA flag */
696     DMA_ClearStatusFlag(DMA2_FLAG_GINT4 | DMA2_FLAG_TC4 | DMA2_FLAG_HT4 | DMA2_FLAG_TERR4);
697 
698     /* Disable DMA */
699     DMA_Disable(sdio_obj.dma.handle_rx);
700 
701     DMA_InitStructure.dir = DMA_DIR_PERIPHERAL_DST;
702     DMA_InitStructure.bufferSize = BufferSize;
703     DMA_InitStructure.memoryBaseAddr = (uint32_t)src;
704     DMA_InitStructure.memoryDataSize = DMA_MEMORY_DATA_SIZE_WOED;
705     DMA_InitStructure.memoryInc = DMA_MEMORY_INC_ENABLE;
706     DMA_InitStructure.peripheralBaseAddr = (uint32_t)dst;
707     DMA_InitStructure.peripheralDataSize = DMA_PERIPHERAL_DATA_SIZE_WOED;
708     DMA_InitStructure.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;
709     DMA_InitStructure.priority = DMA_PRIORITY_MEDIUM;
710     DMA_InitStructure.loopMode = DMA_MODE_NORMAL;
711     DMA_InitStructure.M2M = DMA_M2MEN_DISABLE;
712 
713     DMA_Config(sdio_obj.dma.handle_tx, &DMA_InitStructure);
714 
715     DMA_Enable(sdio_obj.dma.handle_tx);
716 #elif defined (SOC_SERIES_APM32F4)
717     /* Wait DMA can be setting */
718     while (DMA_ReadCmdStatus(sdio_obj.dma.handle_tx) != DISABLE);
719 
720     /* Clear all DMA intrrupt flag */
721     DMA_Reset(sdio_obj.dma.handle_tx);
722 
723     DMA_InitStructure.channel = sdio_config.dma_tx.channel;
724     DMA_InitStructure.dir = DMA_DIR_MEMORYTOPERIPHERAL;
725     DMA_InitStructure.bufferSize = BufferSize;
726     DMA_InitStructure.memoryBaseAddr = (uint32_t)src;
727     DMA_InitStructure.memoryDataSize = DMA_MEMORY_DATA_SIZE_WORD;
728     DMA_InitStructure.memoryInc = DMA_MEMORY_INC_ENABLE;
729     DMA_InitStructure.memoryBurst = DMA_MEMORYBURST_INC4;
730     DMA_InitStructure.peripheralBaseAddr = (uint32_t)dst;
731     DMA_InitStructure.peripheralDataSize = DMA_PERIPHERAL_DATA_SIZE_WORD;
732     DMA_InitStructure.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;
733     DMA_InitStructure.peripheralBurst = DMA_PERIPHERALBURST_INC4;
734     DMA_InitStructure.loopMode = DMA_MODE_NORMAL;
735     DMA_InitStructure.priority = DMA_PRIORITY_MEDIUM;
736     DMA_InitStructure.fifoMode = DMA_FIFOMODE_ENABLE;
737     DMA_InitStructure.fifoThreshold = DMA_FIFOTHRESHOLD_FULL;
738 
739     DMA_Config(sdio_obj.dma.handle_tx, &DMA_InitStructure);
740     DMA_ConfigFlowController(sdio_obj.dma.handle_tx, DMA_FLOWCTRL_PERIPHERAL);
741     DMA_Enable(sdio_obj.dma.handle_tx);
742 #endif
743 }
744 
745 /**
746   * @brief  This function configures the DMARX.
747   * @param  BufferDST: pointer to the destination buffer
748   * @param  BufferSize: buffer size
749   * @retval None
750   */
SD_LowLevel_DMA_RxConfig(uint32_t * src,uint32_t * dst,uint32_t BufferSize)751 void SD_LowLevel_DMA_RxConfig(uint32_t *src, uint32_t *dst, uint32_t BufferSize)
752 {
753     DMA_Config_T DMA_InitStructure;
754 
755     sdio_obj.cfg = &sdio_config;
756     sdio_obj.dma.handle_rx = sdio_config.dma_rx.Instance;
757 
758 #if defined (SOC_SERIES_APM32F1) || defined (SOC_SERIES_APM32E1)
759     /* clear DMA flag */
760     DMA_ClearStatusFlag(DMA2_FLAG_GINT4 | DMA2_FLAG_TC4 | DMA2_FLAG_HT4 | DMA2_FLAG_TERR4);
761 
762     /* Disable DMA */
763     DMA_Disable(sdio_obj.dma.handle_rx);
764 
765     DMA_InitStructure.dir = DMA_DIR_PERIPHERAL_SRC;
766     DMA_InitStructure.bufferSize = BufferSize;
767     DMA_InitStructure.memoryBaseAddr = (uint32_t)dst;
768     DMA_InitStructure.memoryDataSize = DMA_MEMORY_DATA_SIZE_WOED;
769     DMA_InitStructure.memoryInc = DMA_MEMORY_INC_ENABLE;
770     DMA_InitStructure.peripheralBaseAddr = (uint32_t)src;
771     DMA_InitStructure.peripheralDataSize = DMA_PERIPHERAL_DATA_SIZE_WOED;
772     DMA_InitStructure.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;
773     DMA_InitStructure.priority = DMA_PRIORITY_MEDIUM;
774     DMA_InitStructure.loopMode = DMA_MODE_NORMAL;
775     DMA_InitStructure.M2M = DMA_M2MEN_DISABLE;
776 
777     DMA_Config(sdio_obj.dma.handle_rx, &DMA_InitStructure);
778 
779     DMA_Enable(sdio_obj.dma.handle_rx);
780 #elif defined (SOC_SERIES_APM32F4)
781     /* Wait DMA can be setting */
782     while (DMA_ReadCmdStatus(sdio_obj.dma.handle_rx) != DISABLE);
783 
784     /* Clear all DMA intrrupt flag */
785     DMA_Reset(sdio_obj.dma.handle_rx);
786 
787     DMA_InitStructure.channel = sdio_config.dma_rx.channel;
788     DMA_InitStructure.dir = DMA_DIR_PERIPHERALTOMEMORY;
789     DMA_InitStructure.bufferSize = BufferSize;
790     DMA_InitStructure.memoryBaseAddr = (uint32_t)dst;
791     DMA_InitStructure.memoryDataSize = DMA_MEMORY_DATA_SIZE_WORD;
792     DMA_InitStructure.memoryInc = DMA_MEMORY_INC_ENABLE;
793     DMA_InitStructure.memoryBurst = DMA_MEMORYBURST_INC4;
794     DMA_InitStructure.peripheralBaseAddr = (uint32_t)src;
795     DMA_InitStructure.peripheralDataSize = DMA_PERIPHERAL_DATA_SIZE_WORD;
796     DMA_InitStructure.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;
797     DMA_InitStructure.peripheralBurst = DMA_PERIPHERALBURST_INC4;
798     DMA_InitStructure.loopMode = DMA_MODE_NORMAL;
799     DMA_InitStructure.priority = DMA_PRIORITY_MEDIUM;
800     DMA_InitStructure.fifoMode = DMA_FIFOMODE_ENABLE;
801     DMA_InitStructure.fifoThreshold = DMA_FIFOTHRESHOLD_FULL;
802 
803     DMA_Config(sdio_obj.dma.handle_rx, &DMA_InitStructure);
804     DMA_ConfigFlowController(sdio_obj.dma.handle_rx, DMA_FLOWCTRL_PERIPHERAL);
805     DMA_Enable(sdio_obj.dma.handle_rx);
806 #endif
807 }
808 
809 /**
810   * @brief  This function get apm32 sdio clock.
811   * @param  hw_sdio: apm32_sdio
812   * @retval PCLK2Freq
813   */
apm32_sdio_clock_get(struct apm32_sdio * hw_sdio)814 static rt_uint32_t apm32_sdio_clock_get(struct apm32_sdio *hw_sdio)
815 {
816     return RCM_ReadHCLKFreq();
817 }
818 
DMA_TxConfig(rt_uint32_t * src,rt_uint32_t * dst,int Size)819 static rt_err_t DMA_TxConfig(rt_uint32_t *src, rt_uint32_t *dst, int Size)
820 {
821     SD_LowLevel_DMA_TxConfig((uint32_t *)src, (uint32_t *)dst, Size / 4);
822     return RT_EOK;
823 }
824 
DMA_RxConfig(rt_uint32_t * src,rt_uint32_t * dst,int Size)825 static rt_err_t DMA_RxConfig(rt_uint32_t *src, rt_uint32_t *dst, int Size)
826 {
827     SD_LowLevel_DMA_RxConfig((uint32_t *)src, (uint32_t *)dst, Size / 4);
828     return RT_EOK;
829 }
830 
SDIO_IRQHandler(void)831 void SDIO_IRQHandler(void)
832 {
833     /* enter interrupt */
834     rt_interrupt_enter();
835     /* Process All SDIO Interrupt Sources */
836     rthw_sdio_irq_process(host);
837 
838     /* leave interrupt */
839     rt_interrupt_leave();
840 }
841 
rt_hw_sdio_init(void)842 int rt_hw_sdio_init(void)
843 {
844     struct apm32_sdio_des sdio_des;
845     struct apm32_sdio_config hsd;
846 
847     hsd.Instance = SDCARD_INSTANCE;
848 
849     /* enable DMA clock */
850 #if defined (SOC_SERIES_APM32F1) || defined (SOC_SERIES_APM32E1)
851     SET_BIT(RCM->AHBCLKEN, sdio_config.dma_rx.dma_rcm);
852 #elif defined (SOC_SERIES_APM32F4)
853     SET_BIT(RCM->AHB1CLKEN, sdio_config.dma_rx.dma_rcm);
854 #endif
855 
856     NVIC_EnableIRQRequest(SDIO_IRQn, 2, 0);
857 
858     /* apm32 sdio gpio init and enable clock */
859     extern void apm32_msp_sdio_init(void *Instance);
860     apm32_msp_sdio_init((void *)(hsd.Instance));
861 
862     sdio_des.clk_get = apm32_sdio_clock_get;
863     sdio_des.hw_sdio = (struct apm32_sdio *)SDCARD_INSTANCE;
864     sdio_des.rxconfig = DMA_RxConfig;
865     sdio_des.txconfig = DMA_TxConfig;
866 
867     host = sdio_host_create(&sdio_des);
868     if (host == RT_NULL)
869     {
870         LOG_E("host create fail");
871         return -1;
872     }
873 
874     return 0;
875 }
876 INIT_DEVICE_EXPORT(rt_hw_sdio_init);
877 
apm32_mmcsd_change(void)878 void apm32_mmcsd_change(void)
879 {
880     mmcsd_change(host);
881 }
882 
883 #endif
884