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