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