1 /*
2  * Copyright (c) 2006-2024, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2024-11-06     QT-one       first version
9  */
10 
11 #include <rtdbg.h>
12 #include "drv_sdio.h"
13 
14 #ifdef BSP_USING_SDIO
15 #if !defined (BSP_USING_SDIO)
16     #error "Please define at least one SDIOx"
17 #endif
18 
19 #define RT_HW_SDIO_LOCK(_sdio) rt_mutex_take(&_sdio->mutex, RT_WAITING_FOREVER)
20 #define RT_HW_SDIO_UNLOCK(_sdio) rt_mutex_release(&_sdio->mutex);
21 
22 typedef rt_err_t (*dma_txconfig)(rt_uint32_t *src, rt_uint32_t *dst, int size);
23 typedef rt_err_t (*dma_rxconfig)(rt_uint32_t *src, rt_uint32_t *dst, int size);
24 typedef rt_uint32_t (*sdio_clk_get)(HT_SDIO_TypeDef *hw_sdio);
25 
26 struct ht32_sdio_config
27 {
28     SDIO_InitTypeDef sdio_cfg;          /* SDIO Configuration Structure */
29     PDMACH_InitTypeDef dma_tx_cfg;      /* TX DMA Configuration Structure */
30     PDMACH_InitTypeDef dma_rx_cfg;      /* RX DMA Configuration Structure */
31 };
32 
33 struct ht32_sdio_des
34 {
35     HT_SDIO_TypeDef *hw_sdio;           /* Pointer to sdio hardware structure */
36     dma_txconfig txconfig;              /* Pointer to the configuration function for the TX DMA */
37     dma_rxconfig rxconfig;              /* Pointer to the configuration function for the RX DMA */
38     sdio_clk_get clk_get;               /* Pointer to get sdio clock function */
39 };
40 
41 struct sdio_pkg
42 {
43     struct rt_mmcsd_cmd *cmd;           /* RTT-defined mmcsd command structure */
44     void *buff;                         /* Pointer to hold data */
45     SDIO_CmdInitTypeDef sdio_cmd_str;   /* Send Command Configuration */
46     SDIO_DataInitTypeDef sdio_dat_str;  /* Send Data Configuration */
47 };
48 
49 struct rt_hw_sdio
50 {
51     struct rt_mmcsd_host *host;         /* mmcsd host structure */
52     struct ht32_sdio_des sdio_des;      /* Configuration information for sdio */
53     struct rt_event dat_event;          /* data event variable */
54     struct rt_event cmd_event;          /* command event variable */
55     struct rt_mutex mutex;              /* mutually exclusive variable */
56     struct sdio_pkg *pkg;               /* package structure */
57 };
58 
59 rt_align(SDIO_ALIGN_LEN)                        /* Ensure data alignment */
60 static rt_uint8_t cache_buf[SDIO_BUFF_SIZE];    /* Buff caches allocated to SDIOs */
61 
62 static struct rt_mmcsd_host *host;
63 static struct ht32_sdio_config sdio_cfg;
64 
sdio_delay(rt_uint32_t ms)65 static void sdio_delay(rt_uint32_t ms)
66 {
67     while (ms > 0)
68         ms--;
69 }
70 
ht32_sdio_clk_get(HT_SDIO_TypeDef * hw_sdio)71 static rt_uint32_t ht32_sdio_clk_get(HT_SDIO_TypeDef *hw_sdio)
72 {
73     return SDIO_CLOCK_FREQ;
74 }
75 /**
76   * @brief  this function transfer data by dma.
77   * @param  sdio rt_hw_sdio
78   * @param  pkg sdio package
79   * @retval none
80   */
rt_hw_sdio_transfer_by_dma(struct rt_hw_sdio * sdio,struct sdio_pkg * pkg)81 static void rt_hw_sdio_transfer_by_dma(struct rt_hw_sdio *sdio, struct sdio_pkg *pkg)
82 {
83     struct rt_mmcsd_data *data;
84     void *buff;
85     HT_SDIO_TypeDef *hw_sdio;
86     if ((RT_NULL == pkg) || (RT_NULL == sdio))
87     {
88         LOG_E("rt_hw_sdio_transfer_by_dma invalid args");
89         return;
90     }
91 
92     data = pkg->cmd->data;
93     if (RT_NULL == data)
94     {
95         LOG_E("rt_hw_sdio_transfer_by_dma invalid args");
96         return;
97     }
98 
99     buff = pkg->buff;
100     if (RT_NULL == buff)
101     {
102         LOG_E("rt_hw_sdio_transfer_by_dma invalid args");
103         return;
104     }
105 
106     hw_sdio = sdio->sdio_des.hw_sdio;
107     if (data->flags & DATA_DIR_WRITE)
108     {
109         LOG_D("SDIO write!");
110         sdio->sdio_des.txconfig((rt_uint32_t *)buff, (rt_uint32_t *)&hw_sdio->DR, (data->blks * data->blksize));
111     }
112     else if (data->flags & DATA_DIR_READ)
113     {
114         LOG_D("SDIO read!");
115         sdio->sdio_des.rxconfig((rt_uint32_t *)&hw_sdio->DR, (rt_uint32_t *)buff, (data->blks * data->blksize));
116     }
117 }
118 /**
119   * @brief  this function send command.
120   * @param  sdio rt_hw_sdio
121   * @param  pkg sdio package
122   * @retval none
123   */
rt_hw_sdio_send_command(struct rt_hw_sdio * sdio,struct sdio_pkg * pkg)124 static void rt_hw_sdio_send_command(struct rt_hw_sdio *sdio, struct sdio_pkg *pkg)
125 {
126     rt_uint32_t status = 0;
127     struct rt_mmcsd_cmd *cmd = pkg->cmd;
128     struct rt_mmcsd_data *data = cmd->data;
129     HT_SDIO_TypeDef *hw_sdio = sdio->sdio_des.hw_sdio;
130 
131     /* save pkg */
132     sdio->pkg = pkg;
133 
134     LOG_D("CMD:%d ARG:0x%08x RES:%s%s%s%s%s%s%s%s%s rw:%c len:%d blksize:%d",
135           cmd->cmd_code,
136           cmd->arg,
137           resp_type(cmd) == RESP_NONE ? "NONE"  : "",
138           resp_type(cmd) == RESP_R1  ? "R1"  : "",
139           resp_type(cmd) == RESP_R1B ? "R1B"  : "",
140           resp_type(cmd) == RESP_R2  ? "R2"  : "",
141           resp_type(cmd) == RESP_R3  ? "R3"  : "",
142           resp_type(cmd) == RESP_R4  ? "R4"  : "",
143           resp_type(cmd) == RESP_R5  ? "R5"  : "",
144           resp_type(cmd) == RESP_R6  ? "R6"  : "",
145           resp_type(cmd) == RESP_R7  ? "R7"  : "",
146           data ? (data->flags & DATA_DIR_WRITE ?  'w' : 'r') : '-',
147           data ? data->blks * data->blksize : 0,
148           data ? data->blksize : 0
149          );
150 
151     /* config cmd reg */
152     pkg->sdio_cmd_str.SDIO_DatPresent   = SDIO_Data_Present_No;
153 
154     /* config data reg */
155     if (data != RT_NULL)
156     {
157         rt_uint32_t dir = 0;
158         dir = (data->flags & DATA_DIR_READ) ? SDIO_TransferDir_ToSDIO : SDIO_TransferDir_ToCard;
159         if (SDIO_TransferDir_ToSDIO == dir) /* read */
160             SDIO_FlagConfig(SDIO_FLAG_BUF_OVERFLOW | SDIO_FLAG_DATA_CRCERR | SDIO_FLAG_DATA_TIMEOUT | SDIO_FLAG_TRANS_END, ENABLE);
161         else if (SDIO_TransferDir_ToCard == dir) /* write */
162             SDIO_FlagConfig(SDIO_FLAG_BUF_UNDERFLOW | SDIO_FLAG_DATA_CRCERR | SDIO_FLAG_DATA_TIMEOUT | SDIO_FLAG_TRANS_END, ENABLE);
163         if (data->blksize > 2048)
164             LOG_E("Block length out of range!");
165         pkg->sdio_dat_str.SDIO_DataBlockCount   = data->blks;                       /* Specify the number of data blocks to be transferred 1~65535 */
166         pkg->sdio_dat_str.SDIO_DataBlockSize    = data->blksize;                    /* Specify the size of the data block to be transferred 1~2048 */
167         pkg->sdio_dat_str.SDIO_DataTimeOut      = HW_SDIO_DATATIMEOUT;              /* Specify the data timeout period 0x1 ~ 0x00ffffff */
168         pkg->sdio_dat_str.SDIO_TransferDir      = dir;                              /* Specify the direction of data transmission r/w */
169         if (data->blks > 1)
170             pkg->sdio_dat_str.SDIO_TransferMode     = SDIO_MultiBlock_DMA_Transfer;     /* multiblock transfer mode */
171         else
172             pkg->sdio_dat_str.SDIO_TransferMode     = SDIO_SingleBlock_DMA_Transfer;    /* single-block transfer mode */
173         SDIO_DataConfig(&pkg->sdio_dat_str);
174 
175         pkg->sdio_cmd_str.SDIO_DatPresent       = SDIO_Data_Present_Yes;
176 
177         rt_hw_sdio_transfer_by_dma(sdio, pkg);
178     }
179 
180     /* Configuring Response Mode */
181     if (resp_type(cmd) == RESP_NONE)
182         pkg->sdio_cmd_str.SDIO_Response     = SDIO_Response_No;
183     else if (resp_type(cmd) == RESP_R2)
184         pkg->sdio_cmd_str.SDIO_Response     = SDIO_Response_Long;
185     else
186         pkg->sdio_cmd_str.SDIO_Response     = SDIO_Response_Short;
187 
188     if (resp_type(cmd) & (RESP_R1 | RESP_R6))
189         pkg->sdio_cmd_str.SDIO_CmdIdxChk    = SDIO_CmdIdxChk_Yes;
190     else
191         pkg->sdio_cmd_str.SDIO_CmdIdxChk    = SDIO_Data_Present_No;
192 
193     if (resp_type(cmd) & (RESP_R3))
194         pkg->sdio_cmd_str.SDIO_CmdCrcChk    = SDIO_CmdCrcChk_No;
195     else
196         pkg->sdio_cmd_str.SDIO_CmdCrcChk    = SDIO_CmdCrcChk_Yes;
197     /* send cmd */
198     pkg->sdio_cmd_str.SDIO_Argument     = cmd->arg;                 /* sdio Command Parameters */
199     pkg->sdio_cmd_str.SDIO_CmdIndex     = (cmd->cmd_code << 8);     /* Index of sdio commands  0x01 ~ 0x40*/
200     /* open irq */
201     SDIO_FlagConfig(HW_SDIO_CMD_FLAG, ENABLE);
202     SDIO_IntConfig(HW_SDIO_CMD_FLAG, ENABLE);
203     SDIO_SendCommand(&pkg->sdio_cmd_str);
204     /* wait completed */
205     if (rt_event_recv(&sdio->cmd_event, 0xffffffff, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
206                       rt_tick_from_millisecond(5000), &status) != RT_EOK)
207     {
208         LOG_E("wait completed timeout");
209         cmd->err = -RT_ETIMEOUT;
210         return;
211     }
212     SDIO_IntConfig(HW_SDIO_CMD_FLAG, DISABLE);
213     if (cmd->err != RT_EOK)
214         LOG_D("cmd err!");
215 
216     /* waiting for data to be sent to completion */
217     if (data != RT_NULL)
218     {
219         status = 0;
220         SDIO_IntConfig(SDIO_INT_BUF_OVERFLOW | SDIO_INT_DATA_CRCERR | SDIO_INT_DATA_TIMEOUT | SDIO_INT_TRANS_END, ENABLE);
221         if (rt_event_recv(&sdio->dat_event, 0xffffffff, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
222                           rt_tick_from_millisecond(5000), &status) != RT_EOK)
223         {
224             LOG_E("wait completed timeout");
225             data->err = -RT_ETIMEOUT;
226             return;
227         }
228         SDIO_IntConfig(SDIO_INT_BUF_OVERFLOW | SDIO_INT_DATA_CRCERR | SDIO_INT_DATA_TIMEOUT | SDIO_INT_TRANS_END, DISABLE);
229         if (data->err != RT_EOK)
230             LOG_D("data err!");
231     }
232     /* close irq, keep sdio irq */
233     hw_sdio->IER = 0x00;
234     /* clear pkg */
235     sdio->pkg = RT_NULL;
236 }
237 /**
238   * @brief  this function send sdio request.
239   * @param  sdio rt_hw_sdio
240   * @param  req request
241   * @retval none
242   */
rt_hw_sdio_request(struct rt_mmcsd_host * host,struct rt_mmcsd_req * req)243 static void rt_hw_sdio_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
244 {
245     struct sdio_pkg pkg;
246     struct rt_hw_sdio *sdio = host->private_data;
247     struct rt_mmcsd_data *data;
248 
249     RT_HW_SDIO_LOCK(sdio);
250     /* Send commands and data */
251     if (req->cmd != RT_NULL)
252     {
253         memset(&pkg, 0, sizeof(pkg));
254         data = req->cmd->data;
255         pkg.cmd = req->cmd;
256 
257         if (data != RT_NULL)
258         {
259             rt_uint32_t size = data->blks * data->blksize;
260             RT_ASSERT(size <= SDIO_BUFF_SIZE);
261             pkg.buff = data->buf;
262             if ((rt_uint32_t)data->buf & (SDIO_ALIGN_LEN - 1))
263             {
264                 pkg.buff = cache_buf;
265                 if (data->flags & DATA_DIR_WRITE)
266                 {
267                     memcpy(cache_buf, data->buf, size);
268                 }
269             }
270         }
271         rt_hw_sdio_send_command(sdio, &pkg);
272         if ((data != RT_NULL) && (data->flags & DATA_DIR_READ) && ((rt_uint32_t)data->buf & (SDIO_ALIGN_LEN - 1)))
273         {
274             memcpy(data->buf, cache_buf, data->blksize * data->blks);
275         }
276     }
277     /* Send stop command */
278     if (req->stop != RT_NULL)
279     {
280         memset(&pkg, 0, sizeof(pkg));
281         pkg.cmd = req->stop;
282         rt_hw_sdio_send_command(sdio, &pkg);
283     }
284     RT_HW_SDIO_UNLOCK(sdio);
285     mmcsd_req_complete(sdio->host);
286 }
287 /**
288   * @brief  this function config sdio.
289   * @param  host rt_mmcsd_host
290   * @param  io_cfg rt_mmcsd_io_cfg
291   * @retval none
292   */
rt_hw_sdio_iocfg(struct rt_mmcsd_host * host,struct rt_mmcsd_io_cfg * io_cfg)293 static void rt_hw_sdio_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
294 {
295     rt_uint32_t div, clk_src;
296     rt_uint32_t clk = io_cfg->clock;
297     struct rt_hw_sdio *sdio = host->private_data;
298     /* SDIO Clock Acquisition and Limiting */
299     clk_src = sdio->sdio_des.clk_get(sdio->sdio_des.hw_sdio);
300     if (clk_src < 400 * 1000)
301     {
302         LOG_E("Chip clock frequency too low! fre:%d", clk_src);
303         return;
304     }
305     if (clk > host->freq_max) clk = host->freq_max;
306     if (clk > clk_src)
307     {
308         LOG_W("Setting rate is greater than clock source rate.");
309         clk = clk_src;
310     }
311 
312     LOG_D("clk:%d width:%s%s%s power:%s%s%s",
313           clk,
314           io_cfg->bus_width == MMCSD_BUS_WIDTH_8 ? "8" : "",
315           io_cfg->bus_width == MMCSD_BUS_WIDTH_4 ? "4" : "",
316           io_cfg->bus_width == MMCSD_BUS_WIDTH_1 ? "1" : "",
317           io_cfg->power_mode == MMCSD_POWER_OFF ? "OFF" : "",
318           io_cfg->power_mode == MMCSD_POWER_UP ? "UP" : "",
319           io_cfg->power_mode == MMCSD_POWER_ON ? "ON" : ""
320          );
321 
322     RT_HW_SDIO_LOCK(sdio);
323     /* SDIO Clock Division Configuration */
324     div = clk_src / clk;
325     if ((clk == 0) || (div == 0))
326     {
327         div = 1;
328     }
329     else
330     {
331         if (div < 1)
332         {
333             div = 1;
334         }
335         else if (div > 0xff)
336         {
337             div = 0xff;
338         }
339     }
340     sdio_cfg.sdio_cfg.SDIO_ClockDiv         = div;
341     if (div % 2)
342         sdio_cfg.sdio_cfg.SDIO_ClockPeriod = SDIO_Clock_LowPeriod_Longer;
343     else
344         sdio_cfg.sdio_cfg.SDIO_ClockPeriod = SDIO_Clock_LowPeriod_Shorter;
345 
346     /* Data bus mode configuration */
347     if (io_cfg->bus_width == MMCSD_BUS_WIDTH_8)
348     {
349         LOG_E("8-bit data width not supported!");
350         return;
351     }
352     else if (io_cfg->bus_width == MMCSD_BUS_WIDTH_4)
353     {
354         sdio_cfg.sdio_cfg.SDIO_BusWide = SDIO_BusWide_4b;
355         sdio_cfg.sdio_cfg.SDIO_BusMode = SDIO_BusMode_HighSpeed;
356     }
357     else
358     {
359         sdio_cfg.sdio_cfg.SDIO_BusWide = SDIO_BusWide_1b;
360         sdio_cfg.sdio_cfg.SDIO_BusMode = SDIO_BusMode_NormalSpeed;
361     }
362     /* Power Mode Configuration */
363     switch (io_cfg->power_mode)
364     {
365     case MMCSD_POWER_OFF:
366         sdio_cfg.sdio_cfg.SDIO_ClockPowerSave = SDIO_Clock_PowerSave_Disable;
367         break;
368     case MMCSD_POWER_UP:
369         sdio_cfg.sdio_cfg.SDIO_ClockPowerSave = SDIO_Clock_PowerSave_StopHigh;
370         break;
371     case MMCSD_POWER_ON:
372         sdio_cfg.sdio_cfg.SDIO_ClockPowerSave = SDIO_Clock_PowerSave_StopLow;
373         break;
374     default:
375         LOG_W("unknown power_mode %d", io_cfg->power_mode);
376         break;
377     }
378     SDIO_Init(&sdio_cfg.sdio_cfg);
379     RT_HW_SDIO_UNLOCK(sdio);
380 }
381 /**
382   * @brief  this function update sdio interrupt.
383   * @param  host rt_mmcsd_host
384   * @param  enable
385   * @retval none
386   */
rt_hw_sdio_irq_update(struct rt_mmcsd_host * host,rt_int32_t enable)387 void rt_hw_sdio_irq_update(struct rt_mmcsd_host *host, rt_int32_t enable)
388 {
389     if (enable)
390     {
391         LOG_D("enable sdio irq");
392         NVIC_EnableIRQ(SDIO_IRQn);
393     }
394     else
395     {
396         LOG_D("disable sdio irq");
397         NVIC_DisableIRQ(SDIO_IRQn);
398     }
399 }
400 /**
401   * @brief  this function delect sdcard.
402   * @param  host rt_mmcsd_host
403   * @retval 0x01
404   */
rt_hw_sd_delect(struct rt_mmcsd_host * host)405 static rt_int32_t rt_hw_sd_delect(struct rt_mmcsd_host *host)
406 {
407     LOG_D("try to detect device");
408     return 0x01;
409 }
410 /**
411   * @brief  this function interrupt process function.
412   * @param  host rt_mmcsd_host
413   * @retval none
414   */
rt_hw_sdio_irq_process(struct rt_mmcsd_host * host)415 void rt_hw_sdio_irq_process(struct rt_mmcsd_host *host)
416 {
417     rt_uint8_t cmd_flag = 0;
418     rt_uint8_t data_flag = 0;
419     struct rt_hw_sdio *sdio = host->private_data;
420     HT_SDIO_TypeDef *hw_sdio = sdio->sdio_des.hw_sdio;
421     rt_uint32_t intstatus = hw_sdio->SR;
422     struct rt_mmcsd_cmd *cmd = sdio->pkg->cmd;
423     struct rt_mmcsd_data *data = cmd->data;
424     if (sdio->pkg == NULL)
425     {
426         SDIO_FlagConfig(HW_SDIO_CMD_FLAG, DISABLE);
427         SDIO_ClearFlag(HW_SDIO_CMD_FLAG);
428         SDIO_FlagConfig(HW_SDIO_DATA_FLAG, DISABLE);
429         SDIO_ClearFlag(HW_SDIO_DATA_FLAG);
430         return;
431     }
432     /* Command Response Processing */
433     if (cmd != NULL)
434     {
435         if (intstatus != 0x00000001)
436             sdio_delay(10000);
437         cmd->resp[0] = hw_sdio->RESP0;
438         cmd->resp[1] = hw_sdio->RESP1;
439         cmd->resp[2] = hw_sdio->RESP2;
440         cmd->resp[3] = hw_sdio->RESP3;
441         cmd->err = RT_EOK;
442         if (SDIO_GetFlagStatus(SDIO_FLAG_CMD_SEND))
443         {
444             SDIO_FlagConfig(HW_SDIO_CMD_FLAG, DISABLE);
445             SDIO_ClearFlag(SDIO_FLAG_CMD_SEND);
446             cmd_flag = 1;
447         }
448         if (SDIO_GetFlagStatus(SDIO_FLAG_CMD_TIMEOUT))
449         {
450             SDIO_FlagConfig(HW_SDIO_CMD_FLAG, DISABLE);
451             SDIO_ClearFlag(SDIO_FLAG_CMD_TIMEOUT);
452             RESET_CPSM();
453             cmd->err = -RT_ETIMEOUT;
454             cmd_flag = 1;
455         }
456         if ((SDIO_GetFlagStatus(SDIO_FLAG_CMD_CRCERR)) && (resp_type(cmd) & (RESP_R3 | RESP_R4)))
457         {
458             SDIO_FlagConfig(HW_SDIO_CMD_FLAG, DISABLE);
459             SDIO_ClearFlag(SDIO_FLAG_CMD_CRCERR);
460             cmd->err = RT_EOK;
461             cmd_flag = 1;
462         }
463         else if (SDIO_GetFlagStatus(SDIO_FLAG_CMD_CRCERR))
464         {
465             SDIO_FlagConfig(HW_SDIO_CMD_FLAG, DISABLE);
466             SDIO_ClearFlag(SDIO_FLAG_CMD_CRCERR);
467             cmd->err = -RT_ERROR;
468             cmd_flag = 1;
469         }
470         if ((SDIO_GetFlagStatus(SDIO_FLAG_CMD_IDXERR)) && (resp_type(cmd) & (RESP_R1 | RESP_R6)) && (cmd->err == RT_EOK))
471         {
472             SDIO_FlagConfig(HW_SDIO_CMD_FLAG, DISABLE);
473             SDIO_ClearFlag(SDIO_FLAG_CMD_IDXERR);
474             cmd->err = RT_EOK;
475             cmd_flag = 1;
476         }
477         else if (SDIO_GetFlagStatus(SDIO_FLAG_CMD_IDXERR))
478         {
479             SDIO_FlagConfig(HW_SDIO_CMD_FLAG, DISABLE);
480             SDIO_ClearFlag(SDIO_FLAG_CMD_IDXERR);
481             cmd->err = -RT_ERROR;
482             cmd_flag = 1;
483         }
484         if (cmd_flag)
485         {
486             rt_event_send(&sdio->cmd_event, intstatus);
487         }
488     }
489     /* Data response processing */
490     if (data != NULL)
491     {
492         data->err = RT_EOK;
493         if (SDIO_GetFlagStatus(SDIO_FLAG_TRANS_END))
494         {
495             SDIO_FlagConfig(HW_SDIO_DATA_FLAG, DISABLE);
496             SDIO_ClearFlag(SDIO_FLAG_TRANS_END);
497             data_flag = 1;
498         }
499 
500         if (SDIO_GetFlagStatus(SDIO_FLAG_DATA_TIMEOUT))
501         {
502             SDIO_FlagConfig(HW_SDIO_DATA_FLAG, DISABLE);
503             SDIO_ClearFlag(SDIO_FLAG_DATA_TIMEOUT);
504             data->err = -RT_ETIMEOUT;
505             data_flag = 1;
506         }
507         if (SDIO_GetFlagStatus(SDIO_FLAG_DATA_CRCERR))
508         {
509             SDIO_FlagConfig(HW_SDIO_DATA_FLAG, DISABLE);
510             SDIO_ClearFlag(SDIO_FLAG_DATA_CRCERR);
511             data->err = -RT_ERROR;
512             data_flag = 1;
513         }
514         if (SDIO_GetFlagStatus(SDIO_FLAG_BUF_OVERFLOW))
515         {
516             SDIO_FlagConfig(HW_SDIO_DATA_FLAG, DISABLE);
517             SDIO_ClearFlag(SDIO_FLAG_BUF_OVERFLOW);
518             data->err = -RT_ERROR;
519             data_flag = 1;
520         }
521         /* 如果操作完成 */
522         if (data_flag)
523         {
524             rt_event_send(&sdio->dat_event, intstatus);         /* 发送事件,通知操作完成 */
525         }
526     }
527 
528 
529 }
530 static const struct rt_mmcsd_host_ops ops =
531 {
532     .request            = rt_hw_sdio_request,
533     .set_iocfg          = rt_hw_sdio_iocfg,
534     .get_card_status    = rt_hw_sd_delect,
535     .enable_sdio_irq    = rt_hw_sdio_irq_update,
536 };
537 /**
538   * @brief  this function create mmcsd host.
539   * @param  sdio_des at32_sdio_des
540   * @retval rt_mmcsd_host
541   */
sdio_host_create(struct ht32_sdio_des * sdio_des)542 struct rt_mmcsd_host *sdio_host_create(struct ht32_sdio_des *sdio_des)
543 {
544     struct rt_mmcsd_host *host;
545     struct rt_hw_sdio *sdio = RT_NULL;
546     /* effective parameter */
547     if ((sdio_des == RT_NULL) || (sdio_des->txconfig == RT_NULL) || (sdio_des->rxconfig == RT_NULL))
548     {
549         LOG_E("L:%d F:%s %s %s %s",
550               (sdio_des == RT_NULL ? "sdio_des is NULL" : ""),
551               (sdio_des ? (sdio_des->txconfig ? "txconfig is NULL" : "") : ""),
552               (sdio_des ? (sdio_des->rxconfig ? "rxconfig is NULL" : "") : "")
553              );
554         return RT_NULL;
555     }
556 
557     sdio = rt_malloc(sizeof(struct rt_hw_sdio));
558     if (sdio == RT_NULL)
559     {
560         LOG_E("L:%d F:%s malloc rt_hw_sdio fail");
561         return RT_NULL;
562     }
563     rt_memset(sdio, 0, sizeof(struct rt_hw_sdio));
564 
565     host = mmcsd_alloc_host();
566     if (host == RT_NULL)
567     {
568         LOG_E("L:%d F:%s mmcsd alloc host fail");
569         rt_free(sdio);
570         return RT_NULL;
571     }
572 
573     rt_memcpy(&sdio->sdio_des, sdio_des, sizeof(struct ht32_sdio_des));
574     sdio->sdio_des.hw_sdio = (sdio_des->hw_sdio == RT_NULL ? (HT_SDIO_TypeDef *)SDIO_BASE_ADDRESS : sdio_des->hw_sdio);
575     sdio->sdio_des.clk_get = (sdio_des->clk_get == RT_NULL ? ht32_sdio_clk_get : sdio_des->clk_get);
576     /* Initialising events and mutexes */
577     rt_event_init(&sdio->dat_event, "sdio", RT_IPC_FLAG_FIFO);
578     rt_event_init(&sdio->cmd_event, "sdio_cmd", RT_IPC_FLAG_FIFO);
579     rt_mutex_init(&sdio->mutex, "sdio", RT_IPC_FLAG_PRIO);
580 
581     /* set host defautl attributes */
582     host->ops = &ops;
583     host->freq_min = 400 * 1000;
584     host->freq_max = SDIO_MAX_FREQ;
585     host->valid_ocr = 0X00FFFF80;
586 #ifndef SDIO_USING_1_BIT
587     host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ;
588 #else
589     host->flags = MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ;
590 #endif
591     host->max_seg_size = SDIO_BUFF_SIZE;
592     host->max_dma_segs = 1;
593     host->max_blk_size = 512;
594     host->max_blk_count = 512;
595 
596     /* link up host and sdio */
597     sdio->host = host;
598     host->private_data = sdio;
599 
600     rt_hw_sdio_irq_update(host, 1);
601 
602     /* ready to change */
603     mmcsd_change(host);
604 
605     return host;
606 }
607 
608 /**
609   * @brief  this function configures the dmatx.
610   * @param  src: pointer to the source buffer
611   * @param  dst: pointer to the destination buffer
612   * @param  buffer_size: size of tx buffer
613   * @retval none
614   */
sd_lowlevel_dmatx_config(uint32_t * src,uint32_t * dst,uint32_t buffer_size)615 void sd_lowlevel_dmatx_config(uint32_t *src, uint32_t *dst, uint32_t buffer_size)
616 {
617     PDMACH_InitTypeDef PDMACH_InitStruct;
618     /* Configure */
619     PDMACH_InitStruct.PDMACH_SrcAddr = (u32)src;
620     PDMACH_InitStruct.PDMACH_DstAddr = (u32)dst;
621     PDMACH_InitStruct.PDMACH_AdrMod = SRC_ADR_LIN_INC | DST_ADR_FIX;
622     PDMACH_InitStruct.PDMACH_BlkCnt = buffer_size;
623     PDMACH_InitStruct.PDMACH_BlkLen = 1;
624     PDMACH_InitStruct.PDMACH_DataSize = WIDTH_32BIT;
625     PDMACH_InitStruct.PDMACH_Priority = H_PRIO;
626     PDMA_Config(PDMA_SDIO_TX, &PDMACH_InitStruct);
627     PDMA_IntConfig(PDMA_SDIO_TX, (PDMA_INT_GE | PDMA_INT_TC | PDMA_INT_TE), ENABLE);
628     NVIC_EnableIRQ(PDMACH7_IRQn);
629     PDMA_EnaCmd(PDMA_SDIO_TX, ENABLE);
630 }
631 
632 /**
633   * @brief  this function configures the dmarx.
634   * @param  src: pointer to the source buffer
635   * @param  dst: pointer to the destination buffer
636   * @param  buffer_size: size of rx buffer
637   * @retval none
638   */
sd_lowlevel_dmarx_config(uint32_t * src,uint32_t * dst,uint32_t buffer_size)639 void sd_lowlevel_dmarx_config(uint32_t *src, uint32_t *dst, uint32_t buffer_size)
640 {
641     PDMACH_InitTypeDef PDMACH_InitStruct;
642     /* Configure */
643     PDMACH_InitStruct.PDMACH_SrcAddr = (u32)src;
644     PDMACH_InitStruct.PDMACH_DstAddr = (u32)dst;
645     PDMACH_InitStruct.PDMACH_AdrMod = SRC_ADR_FIX | DST_ADR_LIN_INC;
646     PDMACH_InitStruct.PDMACH_BlkCnt = buffer_size;
647     PDMACH_InitStruct.PDMACH_BlkLen = 1;
648     PDMACH_InitStruct.PDMACH_DataSize = WIDTH_32BIT;
649     PDMACH_InitStruct.PDMACH_Priority = H_PRIO;
650     PDMA_Config(PDMA_SDIO_RX, &PDMACH_InitStruct);
651     PDMA_IntConfig(PDMA_SDIO_RX, (PDMA_INT_GE | PDMA_INT_TC | PDMA_INT_TE), ENABLE);
652     NVIC_EnableIRQ(PDMACH6_IRQn);
653     PDMA_EnaCmd(PDMA_SDIO_RX, ENABLE);
654 }
655 
656 
657 /**
658   * @brief  this function get at32 sdio clock.
659   * @param  hw_sdio: at32_sdio
660   * @retval ahb frequency
661   */
ht32_sdio_clock_get(HT_SDIO_TypeDef * hw_sdio)662 static rt_uint32_t ht32_sdio_clock_get(HT_SDIO_TypeDef *hw_sdio)
663 {
664     return SystemCoreClock;
665 }
dma_tx_config(rt_uint32_t * src,rt_uint32_t * dst,int size)666 static rt_err_t dma_tx_config(rt_uint32_t *src, rt_uint32_t *dst, int size)
667 {
668     sd_lowlevel_dmatx_config((uint32_t *)src, (uint32_t *)dst, size / 4);
669     return RT_EOK;
670 }
dma_rx_config(rt_uint32_t * src,rt_uint32_t * dst,int size)671 static rt_err_t dma_rx_config(rt_uint32_t *src, rt_uint32_t *dst, int size)
672 {
673     sd_lowlevel_dmarx_config((uint32_t *)src, (uint32_t *)dst, size / 4);
674     return RT_EOK;
675 }
676 
rt_hw_sdio_init(void)677 int rt_hw_sdio_init(void)
678 {
679     struct ht32_sdio_des sdio_des;
680 
681     ht32_sdio_gpio_init((void *)(HT_SDIO));
682     sdio_des.clk_get = ht32_sdio_clock_get;
683     sdio_des.hw_sdio = (HT_SDIO_TypeDef *)HT_SDIO;
684     sdio_des.rxconfig = dma_rx_config;
685     sdio_des.txconfig = dma_tx_config;
686     host = sdio_host_create(&sdio_des);
687     if (host == RT_NULL)
688     {
689         LOG_E("host create fail");
690         return -1;
691     }
692     return 0;
693 }
694 
695 INIT_DEVICE_EXPORT(rt_hw_sdio_init);
696 
697 /*********************************************************************************************************//**
698  * @brief   This function handles PDMA_CH6 interrupt.
699  * @retval  None
700  ************************************************************************************************************/
PDMA_CH6_IRQHandler(void)701 void PDMA_CH6_IRQHandler(void)
702 {
703     if (HT_PDMA->ISR1 & (PDMA_FLAG_TE << ((PDMA_CH6 - 6) * 5)))
704     {
705         LOG_E(" TE6");
706         while (1);
707     }
708 
709     HT_PDMA->ISCR1 = PDMA_FLAG_TC << ((PDMA_CH6 - 6) * 5);
710     PDMA_EnaCmd(PDMA_SDIO_RX, DISABLE);
711 }
712 
713 /*********************************************************************************************************//**
714  * @brief   This function handles PDMA_CH7 interrupt.
715  * @retval  None
716  ************************************************************************************************************/
PDMA_CH7_IRQHandler(void)717 void PDMA_CH7_IRQHandler(void)
718 {
719     if (HT_PDMA->ISR1 & (PDMA_FLAG_TE << ((PDMA_CH7 - 6) * 5)))
720     {
721         LOG_E(" TE7");
722         while (1);
723     }
724 
725     HT_PDMA->ISCR1 = PDMA_FLAG_TC << ((PDMA_CH7 - 6) * 5);
726     PDMA_EnaCmd(PDMA_SDIO_TX, DISABLE);
727 }
728 
729 /*********************************************************************************************************//**
730  * @brief   This function handles SDIO interrupt.
731  * @retval  None
732  ************************************************************************************************************/
SDIO_IRQHandler(void)733 void SDIO_IRQHandler(void)
734 {
735     /* enter interrupt */
736     rt_interrupt_enter();
737     rt_hw_sdio_irq_process(host);
738     /* leave interrupt */
739     rt_interrupt_leave();
740 }
741 
ht32_mmcsd_change(void)742 void ht32_mmcsd_change(void)
743 {
744     mmcsd_change(host);
745 }
746 
747 #endif /* BSP_USING_SDIO */
748