1 /*
2 * Copyright (C) 2022-2024, Xiaohua Semiconductor Co., Ltd.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2023-02-14 CDT first version
9 */
10
11
12 /*******************************************************************************
13 * Include files
14 ******************************************************************************/
15 #include <rtthread.h>
16 #include <rtdevice.h>
17
18 #if defined(RT_USING_SDIO)
19
20 #if defined(BSP_USING_SDIO1) || defined(BSP_USING_SDIO2)
21
22 #include "drv_sdio.h"
23 #include "board_config.h"
24
25 /*******************************************************************************
26 * Local type definitions ('typedef')
27 ******************************************************************************/
28
29 /* rthw sdio */
30 struct rthw_sdio
31 {
32 struct rt_mmcsd_host *host;
33 struct hc32_sdio_config *config;
34 struct hc32_sdio_des des;
35 struct rt_event event;
36 struct rt_mutex mutex;
37 struct sdio_pkg *pkg;
38 uint8_t *cache_buf;
39 };
40
41 /*******************************************************************************
42 * Local pre-processor symbols/macros ('#define')
43 ******************************************************************************/
44 //#define DRV_DEBUG
45 #define LOG_TAG "drv.sdio"
46 #include <drv_log.h>
47
48 #ifndef SDIO_BUFF_SIZE
49 #define SDIO_BUFF_SIZE (4096)
50 #endif
51
52 #ifndef SDIO_ALIGN_LEN
53 #define SDIO_ALIGN_LEN (4)
54 #endif
55
56 #ifndef SDIO_MAX_FREQ
57 #define SDIO_MAX_FREQ (50*1000*1000)
58 #endif
59
60 #define RTHW_SDIO_LOCK(_sdio) rt_mutex_take(&(_sdio)->mutex, RT_WAITING_FOREVER)
61 #define RTHW_SDIO_UNLOCK(_sdio) rt_mutex_release(&(_sdio)->mutex);
62
63 /*******************************************************************************
64 * Global variable definitions (declared in header file with 'extern')
65 ******************************************************************************/
66 extern rt_err_t rt_hw_board_sdio_init(CM_SDIOC_TypeDef *SDIOCx);
67
68 /*******************************************************************************
69 * Local function prototypes ('static')
70 ******************************************************************************/
71 #ifdef BSP_USING_SDIO1
72 static void _sdio1_handler(void);
73 #endif
74
75 #ifdef BSP_USING_SDIO2
76 static void _sdio2_handler(void);
77 #endif
78
79 /*******************************************************************************
80 * Local variable definitions ('static')
81 ******************************************************************************/
82 enum
83 {
84 #ifdef BSP_USING_SDIO1
85 SDIO1_INDEX,
86 #endif
87 #ifdef BSP_USING_SDIO2
88 SDIO2_INDEX,
89 #endif
90 };
91
92 static struct hc32_sdio_config _sdio_config[] =
93 {
94 #ifdef BSP_USING_SDIO1
95 SDIO1_BUS_CONFIG,
96 #endif /* BSP_USING_SDIO1 */
97 #ifdef BSP_USING_SDIO2
98 SDIO2_BUS_CONFIG,
99 #endif /* BSP_USING_SDIO2 */
100 };
101
102 static const func_ptr_t _sdio_irq_handler[] =
103 {
104 #ifdef BSP_USING_SDIO1
105 _sdio1_handler,
106 #endif /* BSP_USING_SDIO1 */
107 #ifdef BSP_USING_SDIO2
108 _sdio2_handler,
109 #endif /* BSP_USING_SDIO2 */
110 };
111
112 #ifdef BSP_USING_SDIO1
113 rt_align(SDIO_ALIGN_LEN)
114 static rt_uint8_t _sdio1_cache_buf[SDIO_BUFF_SIZE];
115 #endif
116
117 #ifdef BSP_USING_SDIO2
118 rt_align(SDIO_ALIGN_LEN)
119 static rt_uint8_t _sdio2_cache_buf[SDIO_BUFF_SIZE];
120 #endif
121
122 static rt_uint8_t *const _sdio_cache_buf[] =
123 {
124 #ifdef BSP_USING_SDIO1
125 _sdio1_cache_buf,
126 #endif /* BSP_USING_SDIO1 */
127 #ifdef BSP_USING_SDIO2
128 _sdio2_cache_buf,
129 #endif /* BSP_USING_SDIO2 */
130 };
131
132 static struct rt_mmcsd_host *_sdio_host[sizeof(_sdio_config) / sizeof(_sdio_config[0])] = {0};
133
134 /*******************************************************************************
135 * Function implementation - global ('extern') and local ('static')
136 ******************************************************************************/
137
138 /**
139 * @brief Get the response type of hc32 sdioc driver.
140 * @param [in] rt_resp_type SDIO command response type defined in mmcs_core.h
141 * @retval The response type of hc32 sdioc driver
142 */
_sdio_get_cmd_resptype(rt_uint32_t rt_resptype)143 static rt_uint32_t _sdio_get_cmd_resptype(rt_uint32_t rt_resptype)
144 {
145 rt_uint32_t sdioc_resptype;
146
147 switch (rt_resptype)
148 {
149 case RESP_NONE:
150 sdioc_resptype = SDIOC_RESP_TYPE_NO;
151 break;
152 case RESP_R1:
153 sdioc_resptype = SDIOC_RESP_TYPE_R1_R5_R6_R7;
154 break;
155 case RESP_R2:
156 sdioc_resptype = SDIOC_RESP_TYPE_R2;
157 break;
158 case RESP_R3:
159 case RESP_R4:
160 sdioc_resptype = SDIOC_RESP_TYPE_R3_R4;
161 break;
162 case RESP_R5:
163 case RESP_R6:
164 case RESP_R7:
165 sdioc_resptype = SDIOC_RESP_TYPE_R1_R5_R6_R7;
166 break;
167 case RESP_R1B:
168 sdioc_resptype = SDIOC_RESP_TYPE_R1B_R5B;
169 break;
170 default:
171 sdioc_resptype = SDIOC_RESP_TYPE_NO;
172 LOG_E("unknown response type: %d", rt_resptype);
173 break;
174 }
175
176 return sdioc_resptype;
177 }
178
179 /**
180 * @brief This function wait sdio completed.
181 * @param [in] sdio Pointer to a @ref rthw_sdio structure
182 * @retval None
183 */
_sdio_wait_completed(struct rthw_sdio * sdio)184 static void _sdio_wait_completed(struct rthw_sdio *sdio)
185 {
186 rt_uint32_t status;
187 rt_uint32_t response[4];
188 __IO rt_uint32_t to_count;
189 struct rt_mmcsd_cmd *cmd = sdio->pkg->cmd;
190 struct rt_mmcsd_data *data = cmd->data;
191 CM_SDIOC_TypeDef *instance = sdio->config->instance;
192
193 if (rt_event_recv(&sdio->event, 0xFFFFFFFF, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
194 rt_tick_from_millisecond(5000), &status) != RT_EOK)
195 {
196 LOG_E("[%s timeout] sta=0x%08X, cmd %d, arg:0x%08X", __func__, status, cmd->cmd_code, cmd->arg);
197 cmd->err = -RT_ETIMEOUT;
198 return;
199 }
200
201 if (sdio->pkg == RT_NULL)
202 {
203 return;
204 }
205
206 if (resp_type(cmd) == RESP_NONE)
207 {
208 ;
209 }
210 else if (resp_type(cmd) == RESP_R2)
211 {
212 LOG_D("R2");
213 (void)SDIOC_GetResponse(instance, SDIOC_RESP_REG_BIT0_31, &response[0]);
214 (void)SDIOC_GetResponse(instance, SDIOC_RESP_REG_BIT32_63, &response[1]);
215 (void)SDIOC_GetResponse(instance, SDIOC_RESP_REG_BIT64_95, &response[2]);
216 (void)SDIOC_GetResponse(instance, SDIOC_RESP_REG_BIT96_127, &response[3]);
217
218 cmd->resp[0] = (response[3] << 8) + ((response[2] >> 24) & 0xFF);
219 cmd->resp[1] = (response[2] << 8) + ((response[1] >> 24) & 0xFF);
220 cmd->resp[2] = (response[1] << 8) + ((response[0] >> 24) & 0xFF);
221 cmd->resp[3] = (response[0] << 8) + 0x00;
222 }
223 else
224 {
225 (void)SDIOC_GetResponse(instance, SDIOC_RESP_REG_BIT0_31, &response[0]);
226 cmd->resp[0] = response[0];
227 }
228
229 if (status & SDIOC_INT_FLAG_EI)
230 {
231 if (status & (SDIOC_INT_FLAG_CTOE | SDIOC_INT_FLAG_CCE | SDIOC_INT_FLAG_CEBE | SDIOC_INT_FLAG_CIE))
232 {
233 SDIOC_SWReset(instance, SDIOC_SW_RST_CMD_LINE);
234 cmd->err = -RT_ERROR;
235 LOG_D("[%s cmd err] sta=0x%08X, %s%s%s%s cmd %d arg:0x%08X",
236 __func__,
237 status,
238 status & SDIOC_INT_FLAG_CCE ? "Command CRC Error " : "",
239 status & SDIOC_INT_FLAG_CEBE ? "Command End Bit Error" : "",
240 status & SDIOC_INT_FLAG_CTOE ? "Command Timeout Error" : "",
241 status == 0 ? "NULL" : "",
242 cmd->cmd_code,
243 cmd->arg);
244 }
245
246 if (status & (SDIOC_INT_FLAG_DTOE | SDIOC_INT_FLAG_DCE | SDIOC_INT_FLAG_DEBE))
247 {
248 SDIOC_SWReset(instance, SDIOC_SW_RST_DATA_LINE);
249 if (data != NULL)
250 {
251 data->err = -RT_ERROR;
252 LOG_D("[%s dat err] sta=0x%08X, %s%s%s%s cmd %d arg:0x%08X rw:%c len:%d blksize:%d",
253 __func__,
254 status,
255 status & SDIOC_INT_FLAG_DCE ? "Data CRC Error " : "",
256 status & SDIOC_INT_FLAG_DEBE ? "Data End Bit Error" : "",
257 status & SDIOC_INT_FLAG_DTOE ? "Data Timeout Error" : "",
258 status == 0 ? "NULL" : "",
259 cmd->cmd_code,
260 cmd->arg,
261 data ? (data->flags & DATA_DIR_WRITE ? 'w' : 'r') : '-',
262 data ? data->blks * data->blksize : 0,
263 data ? data->blksize : 0);
264 }
265 }
266 }
267 else
268 {
269 cmd->err = RT_EOK;
270 LOG_D("[%s xfer ok] sta=0x%08X, cmd %d, arg:0x%08X, resp[%08X %08X %08X %08X]",
271 __func__,
272 status,
273 cmd->cmd_code,
274 cmd->arg,
275 cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
276 }
277 }
278
279 /**
280 * @brief Transfer data by dma.
281 * @param [in] sdio Pointer to a @ref rthw_sdio structure
282 * @param [in] pkg Pointer to a @ref sdio_pkg structure
283 * @retval None
284 */
_sdio_transfer_by_dma(struct rthw_sdio * sdio,struct sdio_pkg * pkg)285 static void _sdio_transfer_by_dma(struct rthw_sdio *sdio, struct sdio_pkg *pkg)
286 {
287 struct rt_mmcsd_data *data = pkg->cmd->data;
288
289 if ((NULL == sdio) || (NULL == pkg) || (NULL == pkg->buf) || (NULL == pkg->cmd) || (NULL == pkg->cmd->data))
290 {
291 LOG_E("%s function arguments error: %s %s %s %s %s",
292 __func__,
293 (sdio == RT_NULL ? "sdio is NULL" : ""),
294 (pkg == RT_NULL ? "pkg is NULL" : ""),
295 (sdio ? (pkg->buf == RT_NULL ? "pkg->buf is NULL" : "") : ""),
296 (sdio ? (pkg->cmd == RT_NULL ? "pkg->cmd is NULL" : "") : ""),
297 (sdio ? (pkg->cmd->data == RT_NULL ? "pkg->cmd->data is NULL" : "") : "")
298 );
299 return;
300 }
301
302 if (data->flags & DATA_DIR_WRITE)
303 {
304 sdio->des.txconfig(sdio->config->dma_tx.Instance, sdio->config->dma_tx.channel, pkg);
305 DMA_ChCmd(sdio->config->dma_tx.Instance, sdio->config->dma_tx.channel, ENABLE);
306 }
307 else if (data->flags & DATA_DIR_READ)
308 {
309 sdio->des.rxconfig(sdio->config->dma_rx.Instance, sdio->config->dma_rx.channel, pkg);
310 DMA_ChCmd(sdio->config->dma_rx.Instance, sdio->config->dma_rx.channel, ENABLE);
311 }
312 }
313
314 /**
315 * @brief Send command.
316 * @param [in] sdio Pointer to a @ref rthw_sdio structure
317 * @param [in] pkg Pointer to a @ref sdio_pkg structure
318 * @retval None
319 */
_sdio_send_command(struct rthw_sdio * sdio,struct sdio_pkg * pkg)320 static void _sdio_send_command(struct rthw_sdio *sdio, struct sdio_pkg *pkg)
321 {
322 rt_int32_t ret;
323 struct rt_mmcsd_cmd *cmd = pkg->cmd;
324 struct rt_mmcsd_data *data = cmd->data;
325 CM_SDIOC_TypeDef *instance = sdio->config->instance;
326 stc_sdioc_cmd_config_t stcCmdConfig;
327 stc_sdioc_data_config_t stcDataConfig;
328
329 /* save pkg */
330 sdio->pkg = pkg;
331
332 LOG_D("CMD:%d ARG:0x%08x RES:%s%s%s%s%s%s%s%s%s rw:%c len:%d blksize:%d",
333 cmd->cmd_code,
334 cmd->arg,
335 resp_type(cmd) == RESP_NONE ? "NONE" : "",
336 resp_type(cmd) == RESP_R1 ? "R1" : "",
337 resp_type(cmd) == RESP_R1B ? "R1B" : "",
338 resp_type(cmd) == RESP_R2 ? "R2" : "",
339 resp_type(cmd) == RESP_R3 ? "R3" : "",
340 resp_type(cmd) == RESP_R4 ? "R4" : "",
341 resp_type(cmd) == RESP_R5 ? "R5" : "",
342 resp_type(cmd) == RESP_R6 ? "R6" : "",
343 resp_type(cmd) == RESP_R7 ? "R7" : "",
344 data ? (data->flags & DATA_DIR_WRITE ? 'w' : 'r') : '-',
345 data ? data->blks * data->blksize : 0,
346 data ? data->blksize : 0);
347
348 /* config command */
349 stcCmdConfig.u16CmdIndex = cmd->cmd_code;
350
351 /* config command argument */
352 stcCmdConfig.u32Argument = cmd->arg;
353
354 /* config command type */
355 stcCmdConfig.u16CmdType = SDIOC_CMD_TYPE_NORMAL;
356
357 /* config response type */
358 stcCmdConfig.u16ResponseType = _sdio_get_cmd_resptype(resp_type(cmd));
359
360 if (data != RT_NULL)
361 {
362 /* config data */
363 stcDataConfig.u16BlockSize = data->blksize;
364 stcDataConfig.u16BlockCount = data->blks;
365 stcDataConfig.u16TransDir = (data->flags & DATA_DIR_READ) ? SDIOC_TRANS_DIR_TO_HOST : SDIOC_TRANS_DIR_TO_CARD;
366 stcDataConfig.u16AutoCmd12 = SDIOC_AUTO_SEND_CMD12_DISABLE;
367 stcDataConfig.u16DataTimeout = SDIOC_DATA_TIMEOUT_CLK_2E27;
368 stcDataConfig.u16TransMode = (data->blks > 1U) ? SDIOC_TRANS_MD_MULTI : SDIOC_TRANS_MD_SINGLE;
369 ret = SDIOC_ConfigData(instance, &stcDataConfig);
370 if (ret != 0)
371 {
372 LOG_E("configure data error : %d", ret);
373 }
374
375 /* transfer config */
376 _sdio_transfer_by_dma(sdio, pkg);
377
378 stcCmdConfig.u16DataLine = SDIOC_DATA_LINE_ENABLE;;
379 }
380 else
381 {
382 stcCmdConfig.u16DataLine = SDIOC_DATA_LINE_DISABLE;
383 }
384
385 /* send cmd */
386 ret = SDIOC_SendCommand(instance, &stcCmdConfig);
387 if (ret != 0)
388 {
389 LOG_E("send command error : %d", ret);
390 }
391
392 /* wait completed */
393 _sdio_wait_completed(sdio);
394
395 /* clear pkg */
396 sdio->pkg = RT_NULL;
397 }
398
399 /**
400 * @brief Send sdio request.
401 * @param [in] host Pointer to a @ref rt_mmcsd_host structure
402 * @param [in] req Pointer to a @ref rt_mmcsd_req structure
403 * @retval None
404 */
_sdio_request(struct rt_mmcsd_host * host,struct rt_mmcsd_req * req)405 static void _sdio_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
406 {
407 rt_uint32_t mask;
408 struct sdio_pkg pkg;
409 struct rt_mmcsd_data *data;
410 struct rthw_sdio *sdio = host->private_data;
411
412 if ((NULL == host) || (NULL == req) || (NULL == sdio) || (NULL == sdio->config))
413 {
414 LOG_E("%s function arguments error: %s %s %s %s",
415 __func__,
416 (host == RT_NULL ? "host is NULL" : ""),
417 (req == RT_NULL ? "req is NULL" : ""),
418 (sdio == RT_NULL ? "sdio is NULL" : ""),
419 (sdio ? (sdio->config == RT_NULL ? "sdio->config is NULL" : "") : "")
420 );
421 return;
422 }
423
424 RTHW_SDIO_LOCK(sdio);
425
426 if (req->cmd != RT_NULL)
427 {
428 rt_memset(&pkg, 0, sizeof(pkg));
429 data = req->cmd->data;
430 pkg.cmd = req->cmd;
431
432 if (SD_SEND_IF_COND == pkg.cmd->cmd_code)
433 {
434 mask = (CM_SDIOC1 == sdio->config->instance) ? PERIC_SDIOC_SYCTLREG_SELMMC1 : PERIC_SDIOC_SYCTLREG_SELMMC2;
435 if (data == RT_NULL)
436 {
437 CM_PERIC->SDIOC_SYCTLREG &= ~mask;
438 }
439 else
440 {
441 CM_PERIC->SDIOC_SYCTLREG |= mask;
442 }
443 }
444
445 if (data != RT_NULL)
446 {
447 rt_uint32_t size = data->blks * data->blksize;
448
449 RT_ASSERT(size <= SDIO_BUFF_SIZE);
450
451 /* buffer unaligned */
452 if ((rt_uint32_t)data->buf & (SDIO_ALIGN_LEN - 1))
453 {
454 if (data->flags & DATA_DIR_WRITE)
455 {
456 rt_memcpy(sdio->cache_buf, data->buf, size);
457 }
458 pkg.buf = sdio->cache_buf;
459 }
460 else
461 {
462 pkg.buf = data->buf;
463 }
464 }
465
466 _sdio_send_command(sdio, &pkg);
467
468 if ((data != RT_NULL) && (data->flags & DATA_DIR_READ) && ((rt_uint32_t)data->buf & (SDIO_ALIGN_LEN - 1)))
469 {
470 rt_memcpy(data->buf, sdio->cache_buf, data->blksize * data->blks);
471 }
472 }
473
474 if (req->stop != RT_NULL)
475 {
476 rt_memset(&pkg, 0, sizeof(pkg));
477 pkg.cmd = req->stop;
478 _sdio_send_command(sdio, &pkg);
479 }
480
481 RTHW_SDIO_UNLOCK(sdio);
482
483 mmcsd_req_complete(sdio->host);
484 }
485
486 /**
487 * @brief Config sdio.
488 * @param [in] host Pointer to a @ref rt_mmcsd_host structure
489 * @param [in] io_cfg Pointer to a @ref rt_mmcsd_io_cfg structure
490 * @retval None
491 */
_sdio_iocfg(struct rt_mmcsd_host * host,struct rt_mmcsd_io_cfg * io_cfg)492 static void _sdio_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
493 {
494 rt_int32_t ret;
495 rt_uint32_t clk;
496 rt_uint16_t clk_div;
497 rt_uint32_t clk_src;
498 struct rthw_sdio *sdio = host->private_data;
499 CM_SDIOC_TypeDef *instance;
500
501 if ((NULL == host) || (NULL == io_cfg) || (NULL == sdio) || (NULL == sdio->config))
502 {
503 LOG_E("%s function arguments error: %s %s %s %s",
504 __func__,
505 (host == RT_NULL ? "host is NULL" : ""),
506 (io_cfg == RT_NULL ? "io_cfg is NULL" : ""),
507 (sdio == RT_NULL ? "sdio_des is NULL" : ""),
508 (sdio ? (sdio->config == RT_NULL ? "sdio->config is NULL" : "") : "")
509 );
510 return;
511 }
512
513 instance = sdio->config->instance;
514
515 clk_src = sdio->des.clk_get(instance);
516 if (clk_src < 400 * 1000)
517 {
518 LOG_E("clock rate is too low! rate:%d", clk_src);
519 return;
520 }
521
522 clk = io_cfg->clock;
523 if (clk > host->freq_max)
524 {
525 clk = host->freq_max;
526 }
527
528 if (clk > clk_src)
529 {
530 LOG_W("setting rate is greater than clock source rate.");
531 clk = clk_src;
532 }
533
534 LOG_D("clk:%d width:%s%s%s power:%s%s%s",
535 clk,
536 io_cfg->bus_width == MMCSD_BUS_WIDTH_8 ? "8" : "",
537 io_cfg->bus_width == MMCSD_BUS_WIDTH_4 ? "4" : "",
538 io_cfg->bus_width == MMCSD_BUS_WIDTH_1 ? "1" : "",
539 io_cfg->power_mode == MMCSD_POWER_OFF ? "OFF" : "",
540 io_cfg->power_mode == MMCSD_POWER_UP ? "UP" : "",
541 io_cfg->power_mode == MMCSD_POWER_ON ? "ON" : "");
542
543 RTHW_SDIO_LOCK(sdio);
544
545 switch (io_cfg->bus_width)
546 {
547 case MMCSD_BUS_WIDTH_1:
548 SDIOC_SetBusWidth(instance, SDIOC_BUS_WIDTH_1BIT);
549 break;
550 case MMCSD_BUS_WIDTH_4:
551 SDIOC_SetBusWidth(instance, SDIOC_BUS_WIDTH_4BIT);
552 break;
553 case MMCSD_BUS_WIDTH_8:
554 SDIOC_SetBusWidth(instance, SDIOC_BUS_WIDTH_8BIT);
555 break;
556 default:
557 LOG_E("unknown bus width: %d", io_cfg->bus_width);
558 break;
559 }
560
561 switch (io_cfg->power_mode)
562 {
563 case MMCSD_POWER_OFF:
564 SDIOC_PowerCmd(instance, DISABLE);
565 break;
566 case MMCSD_POWER_UP:
567 case MMCSD_POWER_ON:
568 SDIOC_PowerCmd(instance, ENABLE);
569 break;
570 default:
571 LOG_W("unknown power_mode %d", io_cfg->power_mode);
572 break;
573 }
574
575 instance->CLKCON = 0;
576
577 if (clk > 0)
578 {
579 ret = SDIOC_GetOptimumClockDiv(clk, &clk_div);
580 if (ret != LL_OK)
581 {
582 LOG_E("clock division error");
583 }
584 else
585 {
586 SDIOC_SetClockDiv(instance, clk_div);
587
588 if ((clk << 1) <= host->freq_max)
589 {
590 SDIOC_SetSpeedMode(instance, SDIOC_SPEED_MD_NORMAL);
591 }
592 else
593 {
594 SDIOC_SetSpeedMode(instance, SDIOC_SPEED_MD_HIGH);
595 }
596
597 instance->CLKCON = (clk_div | SDIOC_CLKCON_ICE | SDIOC_CLKCON_CE);
598 }
599 }
600
601 RTHW_SDIO_UNLOCK(sdio);
602 }
603
604 /**
605 * @brief Update the sdio interrupt.
606 * @param [in] host Pointer to a @ref rt_mmcsd_host structure
607 * @param [in] enable Enable interrupt when value is non-zero
608 * @retval None
609 */
_sdio_enable_sdio_irq(struct rt_mmcsd_host * host,rt_int32_t enable)610 static void _sdio_enable_sdio_irq(struct rt_mmcsd_host *host, rt_int32_t enable)
611 {
612 struct rthw_sdio *sdio = host->private_data;
613 CM_SDIOC_TypeDef *instance = sdio->config->instance;
614
615 if (enable)
616 {
617 LOG_D("enable sdio interrupt");
618 SDIOC_IntStatusCmd(instance, SDIOC_INT_CINTSEN, ENABLE);
619 SDIOC_IntCmd(instance, SDIOC_INT_CINTSEN, ENABLE);
620 }
621 else
622 {
623 LOG_D("disable sdio interrupt");
624 SDIOC_IntStatusCmd(instance, SDIOC_INT_CINTSEN, DISABLE);
625 SDIOC_IntCmd(instance, SDIOC_INT_CINTSEN, DISABLE);
626 }
627 }
628
629 /**
630 * @brief update all of the using interrupt.
631 * @param [in] host Pointer to a @ref rt_mmcsd_host structure
632 * @param [in] enable Enable interrupt when value is non-zero
633 * @retval None
634 */
_sdio_update_irq(struct rt_mmcsd_host * host,rt_int32_t enable)635 static void _sdio_update_irq(struct rt_mmcsd_host *host, rt_int32_t enable)
636 {
637 struct rthw_sdio *sdio = host->private_data;
638 CM_SDIOC_TypeDef *instance = sdio->config->instance;
639 const rt_uint32_t int_type = (SDIOC_INT_CCSEN | SDIOC_INT_TCSEN | SDIOC_ERR_INT_ALL);
640
641 if (enable)
642 {
643 LOG_D("enable all of the using interrupt");
644 SDIOC_IntStatusCmd(instance, (int_type | SDIOC_INT_BRRSEN | SDIOC_INT_BWRSEN), ENABLE);
645 SDIOC_IntCmd(instance, int_type, ENABLE);
646 }
647 else
648 {
649 LOG_D("disable all of the using interrupt");
650 SDIOC_IntStatusCmd(instance, (int_type | SDIOC_INT_BRRSEN | SDIOC_INT_BWRSEN), DISABLE);
651 SDIOC_IntCmd(instance, int_type, DISABLE);
652 }
653 }
654
655 /**
656 * @brief Get card status.
657 * @param [in] host Pointer to a @ref rt_mmcsd_host structure
658 * @retval rt_int32_t:
659 * - 0: No card
660 * - 1: Card inserted
661 */
_sdio_get_card_status(struct rt_mmcsd_host * host)662 static rt_int32_t _sdio_get_card_status(struct rt_mmcsd_host *host)
663 {
664 struct rthw_sdio *sdio = host->private_data;
665
666 LOG_D("try to detect device");
667 return (rt_int32_t)SDIOC_GetHostStatus(sdio->config->instance, SDIOC_HOST_FLAG_CIN);
668 }
669
670 static const struct rt_mmcsd_host_ops _mmcsd_host_ops =
671 {
672 _sdio_request,
673 _sdio_iocfg,
674 _sdio_get_card_status,
675 _sdio_enable_sdio_irq,
676 };
677
678 /**
679 * @brief Get SDIO clock source frequency.
680 * @param [in] SDIOCx Pointer to SDIOC unit instance
681 * @retval SDIO clock source frequency
682 */
_sdio_clock_get(CM_SDIOC_TypeDef * SDIOCx)683 static rt_uint32_t _sdio_clock_get(CM_SDIOC_TypeDef *SDIOCx)
684 {
685 rt_uint32_t clk;
686
687 (void)SDIOCx;
688 #if defined (HC32F4A0) || defined (HC32F4A8)
689 clk = CLK_GetBusClockFreq(CLK_BUS_PCLK1);
690 #elif defined (HC32F460)
691 clk = CLK_GetBusClockFreq(CLK_BUS_EXCLK);
692 #endif
693
694 return clk;
695 }
696
697 /**
698 * @brief Initialize DMA for SDIO.
699 * @param [in] config Pointer to hc32_sdio_config structure
700 * @retval None
701 */
_sdio_dma_init(struct hc32_sdio_config * config)702 static void _sdio_dma_init(struct hc32_sdio_config *config)
703 {
704 stc_dma_init_t stcDmaInit;
705
706 /* Enable DMA and AOS clock */
707 FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_AOS, ENABLE);
708 FCG_Fcg0PeriphClockCmd(config->dma_rx.clock, ENABLE);
709 FCG_Fcg0PeriphClockCmd(config->dma_tx.clock, ENABLE);
710
711 /* Initialize DMA config structure */
712 (void)DMA_StructInit(&stcDmaInit);
713 stcDmaInit.u32BlockSize = 512UL;
714 stcDmaInit.u32DataWidth = DMA_DATAWIDTH_32BIT;
715
716 /* Configure DMA_RX Transfer */
717 stcDmaInit.u32SrcAddr = (uint32_t)(&config->instance->BUF0);
718 stcDmaInit.u32DestAddr = 0UL;
719 stcDmaInit.u32SrcAddrInc = DMA_SRC_ADDR_FIX;
720 stcDmaInit.u32DestAddrInc = DMA_DEST_ADDR_INC;
721 if (LL_OK != DMA_Init(config->dma_rx.Instance, config->dma_rx.channel, &stcDmaInit))
722 {
723 LOG_E("DMA_RX initialization fail");
724 }
725 AOS_SetTriggerEventSrc(config->dma_rx.trigger_select, config->dma_rx.trigger_event);
726
727 /* Configure DMA_TX Transfer */
728 stcDmaInit.u32SrcAddr = 0UL;
729 stcDmaInit.u32DestAddr = (uint32_t)(&config->instance->BUF0);
730 stcDmaInit.u32SrcAddrInc = DMA_SRC_ADDR_INC;
731 stcDmaInit.u32DestAddrInc = DMA_DEST_ADDR_FIX;
732 if (LL_OK != DMA_Init(config->dma_tx.Instance, config->dma_tx.channel, &stcDmaInit))
733 {
734 LOG_E("DMA_TX initialization fail");
735 }
736 AOS_SetTriggerEventSrc(config->dma_tx.trigger_select, config->dma_tx.trigger_event);
737
738 /* Enable DMA */
739 DMA_Cmd(config->dma_rx.Instance, ENABLE);
740 DMA_Cmd(config->dma_tx.Instance, ENABLE);
741 }
742
743 /**
744 * @brief Configure DMA for SDIO receiving.
745 * @param [in] instance Pointer to DMA instance register base
746 * @param [in] ch DMA channel
747 * @param [in] pkg Pointer to sdio_pkg structure
748 * @retval RT_EOK
749 */
_sdio_dma_rxconfig(CM_DMA_TypeDef * instance,rt_uint8_t ch,struct sdio_pkg * pkg)750 static rt_err_t _sdio_dma_rxconfig(CM_DMA_TypeDef *instance, rt_uint8_t ch, struct sdio_pkg *pkg)
751 {
752 struct rt_mmcsd_cmd *cmd = pkg->cmd;
753 struct rt_mmcsd_data *data = cmd->data;
754
755 DMA_ClearTransCompleteStatus(instance, (DMA_INTSTAT1_BTC_0 | DMA_INTSTAT1_TC_0) << ch);
756 DMA_SetDestAddr(instance, ch, (rt_uint32_t)pkg->buf);
757 DMA_SetBlockSize(instance, ch, (rt_uint16_t)(data->blksize >> 2));
758 DMA_SetTransCount(instance, ch, (rt_uint16_t)data->blks);
759 return RT_EOK;
760 }
761
762 /**
763 * @brief Configure DMA for SDIO transmitting.
764 * @param [in] instance Pointer to DMA instance register base
765 * @param [in] ch DMA channel
766 * @param [in] pkg Pointer to sdio_pkg structure
767 * @retval RT_EOK
768 */
_sdio_dma_txconfig(CM_DMA_TypeDef * instance,rt_uint8_t ch,struct sdio_pkg * pkg)769 static rt_err_t _sdio_dma_txconfig(CM_DMA_TypeDef *instance, rt_uint8_t ch, struct sdio_pkg *pkg)
770 {
771 struct rt_mmcsd_cmd *cmd = pkg->cmd;
772 struct rt_mmcsd_data *data = cmd->data;
773
774 DMA_ClearTransCompleteStatus(instance, (DMA_INTSTAT1_BTC_0 | DMA_INTSTAT1_TC_0) << ch);
775 DMA_SetSrcAddr(instance, ch, (rt_uint32_t)pkg->buf);
776 DMA_SetBlockSize(instance, ch, (rt_uint16_t)(data->blksize >> 2));
777 DMA_SetTransCount(instance, ch, (rt_uint16_t)data->blks);
778 return RT_EOK;
779 }
780
781 /**
782 * @brief This function interrupt process function.
783 * @param [in] host Pointer to rt_mmcsd_host structure
784 * @retval None
785 */
_sdio_irq_process(struct rt_mmcsd_host * host)786 static void _sdio_irq_process(struct rt_mmcsd_host *host)
787 {
788 int complete = 0;
789 struct rthw_sdio *sdio = host->private_data;
790 CM_SDIOC_TypeDef *instance = sdio->config->instance;
791 rt_uint32_t norint_status = (rt_uint32_t)instance->NORINTST;
792 rt_uint32_t errint_status = (rt_uint32_t)instance->ERRINTST;
793 rt_uint32_t status = (errint_status << 16) | norint_status;
794
795 LOG_D("[%s] sta=0x%08X, cmd %d, arg=0x%08X", __func__, status, sdio->pkg->cmd->cmd_code, sdio->pkg->cmd->arg);
796
797 if (norint_status & (SDIOC_INT_FLAG_CRM | SDIOC_INT_FLAG_CIST))
798 {
799 SDIOC_ClearIntStatus(instance, SDIOC_INT_FLAG_CLR_ALL);
800
801 /* ready to change */
802 mmcsd_change(host);
803
804 LOG_D("[%s] card insert or remove", __func__);
805 complete = 1;
806 }
807 else
808 {
809 if (norint_status & SDIOC_INT_FLAG_EI)
810 {
811 SDIOC_ClearIntStatus(instance, SDIOC_INT_FLAG_CLR_ALL);
812 complete = 1;
813
814 LOG_D("[%s] error", __func__);
815 }
816 else
817 {
818 if (norint_status & SDIOC_INT_FLAG_CC)
819 {
820 SDIOC_ClearIntStatus(instance, SDIOC_INT_FLAG_CC);
821 if (sdio->pkg != RT_NULL)
822 {
823 if ((!sdio->pkg->cmd->data) && (resp_type(sdio->pkg->cmd) != RESP_R1B))
824 {
825 complete = 1;
826 }
827 }
828 }
829
830 if (norint_status & SDIOC_INT_FLAG_TC)
831 {
832 SDIOC_ClearIntStatus(instance, SDIOC_INT_FLAG_TC);
833 complete = 1;
834 }
835 }
836 }
837
838 if (norint_status & SDIOC_INT_FLAG_CINT)
839 {
840 SDIOC_ClearIntStatus(instance, SDIOC_INT_FLAG_CINT);
841 sdio_irq_wakeup(host);
842 }
843
844 if (complete)
845 {
846 rt_event_send(&sdio->event, status);
847 LOG_D("[%s] complete", __func__);
848 }
849 }
850
851 #ifdef BSP_USING_SDIO1
852 /**
853 * @brief SDIOC1 irq handler.
854 * @param None
855 * @retval None
856 */
_sdio1_handler(void)857 static void _sdio1_handler(void)
858 {
859 /* enter interrupt */
860 rt_interrupt_enter();
861
862 /* process all SDIO interrupt sources */
863 _sdio_irq_process(_sdio_host[0]);
864
865 /* leave interrupt */
866 rt_interrupt_leave();
867 }
868 #endif
869
870 #ifdef BSP_USING_SDIO2
871 /**
872 * @brief SDIOC2 irq handler.
873 * @param None
874 * @retval None
875 */
_sdio2_handler(void)876 static void _sdio2_handler(void)
877 {
878 /* enter interrupt */
879 rt_interrupt_enter();
880
881 /* process all SDIO interrupt sources */
882 _sdio_irq_process(_sdio_host[1]);
883
884 /* leave interrupt */
885 rt_interrupt_leave();
886 }
887 #endif
888
889 /**
890 * @brief verify bus clock frequency.
891 * @param [in] config Pointer to hc32_sdio_config structure
892 * @retval RT_EOK pass to verify
893 * -RT_ERROR fail to verify
894 */
_sdio_verify_bus_clock_frequency(struct hc32_sdio_config * config)895 static rt_err_t _sdio_verify_bus_clock_frequency(struct hc32_sdio_config *config)
896 {
897 rt_err_t ret = RT_EOK;
898
899 #if defined (HC32F4A0)
900 rt_uint32_t pclk1;
901 rt_uint32_t exlck;
902
903 (void)config;
904 /* ensure bus frequency condition: EXCLK >= PCLK1 */
905 pclk1 = CLK_GetBusClockFreq(CLK_BUS_PCLK1);
906 exlck = CLK_GetBusClockFreq(CLK_BUS_EXCLK);
907 if (exlck < pclk1)
908 {
909 LOG_E("bus frequency error: EXCLK < PCLK1. Please meet the bus frequency condition: EXCLK >= PCLK1");
910 ret = -RT_ERROR;
911 }
912 #endif
913
914 return ret;
915 }
916
917 /**
918 * @brief Enable SDIO clock.
919 * @param [in] config Pointer to hc32_sdio_config structure
920 * @retval RT_EOK pass to enable SDIO clock
921 * -RT_ERROR fail to enable SDIO clock
922 */
_sdio_clock_enable(struct hc32_sdio_config * config)923 static rt_err_t _sdio_clock_enable(struct hc32_sdio_config *config)
924 {
925 /* verify bus clock frequency */
926 if (_sdio_verify_bus_clock_frequency(config) != RT_EOK)
927 {
928 LOG_E("[%s] fail to verify bus clock frequency", __func__);
929 return -RT_ERROR;
930 }
931
932 FCG_Fcg1PeriphClockCmd(config->clock, ENABLE);
933 return RT_EOK;
934 }
935
936 /**
937 * @brief Create mmcsd host.
938 * @param [in] config Pointer to a @ref hc32_sdio_config structure
939 * @param [in] cache_buf Pointer to cache buffer
940 * @param [in] sdio_des Pointer to a @ref hc32_sdio_des structure
941 * @retval rt_mmcsd_host
942 */
_sdio_host_create(struct hc32_sdio_config * config,uint8_t * cache_buf,const struct hc32_sdio_des * sdio_des)943 static struct rt_mmcsd_host *_sdio_host_create(struct hc32_sdio_config *config,
944 uint8_t *cache_buf,
945 const struct hc32_sdio_des *sdio_des)
946 {
947 struct rt_mmcsd_host *host;
948 struct rthw_sdio *sdio = RT_NULL;
949
950 if ((config == RT_NULL) || (cache_buf == RT_NULL) || \
951 (sdio_des == RT_NULL) || (sdio_des->txconfig == RT_NULL) || (sdio_des->rxconfig == RT_NULL))
952 {
953 LOG_E("function arguments error: %s %s %s %s %s",
954 (config == RT_NULL ? "config is NULL" : ""),
955 (cache_buf == RT_NULL ? "cache_buf is NULL" : ""),
956 (sdio_des == RT_NULL ? "sdio_des is NULL" : ""),
957 (sdio_des ? (sdio_des->txconfig ? "txconfig is NULL" : "") : ""),
958 (sdio_des ? (sdio_des->rxconfig ? "rxconfig is NULL" : "") : "")
959 );
960 return RT_NULL;
961 }
962
963 /* malloc rthw_sdio */
964 sdio = rt_malloc(sizeof(struct rthw_sdio));
965 if (sdio == RT_NULL)
966 {
967 LOG_E("malloc rthw_sdio fail");
968 return RT_NULL;
969 }
970 rt_memset(sdio, 0, sizeof(struct rthw_sdio));
971
972 /* malloc mmcsd_alloc_host */
973 host = mmcsd_alloc_host();
974 if (host == RT_NULL)
975 {
976 LOG_E("mmcsd_alloc_host fail");
977 rt_free(sdio);
978 return RT_NULL;
979 }
980
981 rt_memcpy(&sdio->des, sdio_des, sizeof(struct hc32_sdio_des));
982
983 rt_event_init(&sdio->event, "sdio", RT_IPC_FLAG_FIFO);
984 rt_mutex_init(&sdio->mutex, "sdio", RT_IPC_FLAG_FIFO);
985
986 /* set host default attributes */
987 host->ops = &_mmcsd_host_ops;
988 host->freq_min = 400 * 1000;
989 host->freq_max = SDIO_MAX_FREQ;
990 host->valid_ocr = VDD_26_27 | VDD_27_28 | VDD_28_29 | VDD_29_30 | VDD_30_31 | VDD_31_32 | VDD_32_33 | VDD_33_34;/* The voltage range supported is 2.6v-3.4v */
991 host->valid_ocr = VDD_32_33 | VDD_33_34;
992 #ifndef SDIO_USING_1_BIT
993 host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ;
994 #else
995 host->flags = MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ;
996 #endif
997 host->max_seg_size = SDIO_BUFF_SIZE;
998 host->max_dma_segs = 1;
999 host->max_blk_size = 512;
1000 host->max_blk_count = (SDIO_BUFF_SIZE / host->max_blk_size);
1001
1002 /* link up host, config, cache_buf and sdio */
1003 sdio->host = host;
1004 sdio->config = config;
1005 sdio->cache_buf = cache_buf;
1006 host->private_data = sdio;
1007
1008 /* enable interrupt */
1009 _sdio_update_irq(host, 1);
1010
1011 /* ready to change */
1012 mmcsd_change(host);
1013
1014 return host;
1015 }
1016
rt_hw_sdio_init(void)1017 int rt_hw_sdio_init(void)
1018 {
1019 struct rt_mmcsd_host *host;
1020 struct hc32_sdio_config *sdio_config;
1021 rt_size_t obj_num = sizeof(_sdio_config) / sizeof(struct hc32_sdio_config);
1022
1023 const struct hc32_sdio_des sdio_des =
1024 {
1025 .clk_get = _sdio_clock_get,
1026 .rxconfig = _sdio_dma_rxconfig,
1027 .txconfig = _sdio_dma_txconfig,
1028 };
1029
1030 for (rt_size_t i = 0; i < obj_num; i++)
1031 {
1032 sdio_config = &_sdio_config[i];
1033
1034 if (_sdio_clock_enable(sdio_config) != RT_EOK)
1035 {
1036 LOG_E("clock enable fail");
1037 return -1;
1038 }
1039
1040 host = _sdio_host_create(sdio_config, _sdio_cache_buf[i], &sdio_des);
1041 if (host == RT_NULL)
1042 {
1043 LOG_E("host create fail");
1044 return -1;
1045 }
1046 else
1047 {
1048 /* link host */
1049 _sdio_host[i] = host;
1050
1051 /* init board pin */
1052 rt_hw_board_sdio_init(sdio_config->instance);
1053
1054 /* init DMA */
1055 _sdio_dma_init(sdio_config);
1056
1057 /* register the irq handler */
1058 hc32_install_irq_handler(&sdio_config->irq_config, _sdio_irq_handler[i], RT_TRUE);
1059 }
1060 }
1061
1062 return RT_EOK;
1063 }
1064 INIT_DEVICE_EXPORT(rt_hw_sdio_init);
1065
1066 #endif /* BSP_USING_SDIO */
1067 #endif /* RT_USING_SDIO */
1068