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