1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2020-05-23 liuduanfei first version
9 */
10
11 #include "board.h"
12 #include "drv_sdio.h"
13 #include <dfs_fs.h>
14
15 #ifdef BSP_USING_SDMMC
16
17 #define DBG_TAG "drv.sdio"
18 #ifdef DRV_DEBUG
19 #define DBG_LVL DBG_LOG
20 #else
21 #define DBG_LVL DBG_INFO
22 #endif /* DRV_DEBUG */
23 #include <rtdbg.h>
24
25 static struct rt_mmcsd_host *host;
26 #define SDIO_TX_RX_COMPLETE_TIMEOUT_LOOPS (100000)
27
28 struct sdio_pkg
29 {
30 struct rt_mmcsd_cmd *cmd;
31 void *buff;
32 rt_uint32_t flag;
33 };
34
35 struct rthw_sdio
36 {
37 struct rt_mmcsd_host *host;
38 struct stm32_sdio_des sdio_des;
39 struct rt_event event;
40 struct sdio_pkg *pkg;
41 };
42
rt_align(SDIO_ALIGN_LEN)43 rt_align(SDIO_ALIGN_LEN)
44 static rt_uint8_t cache_buf[SDIO_BUFF_SIZE];
45
46 /**
47 * @brief This function get order from sdio.
48 * @param data
49 * @retval sdio order
50 */
51 static int get_order(rt_uint32_t data)
52 {
53 int order = 0;
54
55 switch (data)
56 {
57 case 1:
58 order = 0;
59 break;
60 case 2:
61 order = 1;
62 break;
63 case 4:
64 order = 2;
65 break;
66 case 8:
67 order = 3;
68 break;
69 case 16:
70 order = 4;
71 break;
72 case 32:
73 order = 5;
74 break;
75 case 64:
76 order = 6;
77 break;
78 case 128:
79 order = 7;
80 break;
81 case 256:
82 order = 8;
83 break;
84 case 512:
85 order = 9;
86 break;
87 case 1024:
88 order = 10;
89 break;
90 case 2048:
91 order = 11;
92 break;
93 case 4096:
94 order = 12;
95 break;
96 case 8192:
97 order = 13;
98 break;
99 case 16384:
100 order = 14;
101 break;
102 default :
103 order = 0;
104 break;
105 }
106 return order;
107 }
108
109 /**
110 * @brief This function wait sdio cmd completed.
111 * @param sdio rthw_sdio
112 * @retval None
113 */
rthw_sdio_wait_completed(struct rthw_sdio * sdio)114 static void rthw_sdio_wait_completed(struct rthw_sdio *sdio)
115 {
116 rt_uint32_t status;
117 struct rt_mmcsd_cmd *cmd = sdio->pkg->cmd;
118 struct stm32_sdio *hw_sdio = sdio->sdio_des.hw_sdio;
119
120 if (rt_event_recv(&sdio->event, 0xffffffff, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
121 rt_tick_from_millisecond(5000), &status) != RT_EOK)
122 {
123 LOG_E("wait cmd completed timeout");
124 cmd->err = -RT_ETIMEOUT;
125 return;
126 }
127
128 cmd->resp[0] = hw_sdio->resp1;
129 if (resp_type(cmd) == RESP_R2)
130 {
131 cmd->resp[1] = hw_sdio->resp2;
132 cmd->resp[2] = hw_sdio->resp3;
133 cmd->resp[3] = hw_sdio->resp4;
134 }
135
136 if (status & SDIO_ERRORS)
137 {
138 if ((status & SDMMC_STA_CCRCFAIL) && (resp_type(cmd) & (RESP_R3 | RESP_R4)))
139 {
140 cmd->err = RT_EOK;
141 }
142 else
143 {
144 cmd->err = -RT_ERROR;
145 }
146 }
147
148 if (cmd->err == RT_EOK)
149 {
150 LOG_D("sta:0x%08X [%08X %08X %08X %08X]", status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
151 }
152 else
153 {
154 LOG_D("send command error = %d", cmd->err);
155 }
156 }
157
158 /**
159 * @brief This function send command.
160 * @param sdio rthw_sdio
161 * @param pkg sdio package
162 * @retval None
163 */
rthw_sdio_send_command(struct rthw_sdio * sdio,struct sdio_pkg * pkg)164 static void rthw_sdio_send_command(struct rthw_sdio *sdio, struct sdio_pkg *pkg)
165 {
166 struct rt_mmcsd_cmd *cmd = pkg->cmd;
167 struct rt_mmcsd_data *data = cmd->data;
168 struct stm32_sdio *hw_sdio = sdio->sdio_des.hw_sdio;
169 rt_uint32_t reg_cmd;
170
171 /* save pkg */
172 sdio->pkg = pkg;
173
174 LOG_D("CMD:%d ARG:0x%08x RES:%s%s%s%s%s%s%s%s%s rw:%c len:%d blksize:%d\n",
175 cmd->cmd_code,
176 cmd->arg,
177 resp_type(cmd) == RESP_NONE ? "NONE" : "",
178 resp_type(cmd) == RESP_R1 ? "R1" : "",
179 resp_type(cmd) == RESP_R1B ? "R1B" : "",
180 resp_type(cmd) == RESP_R2 ? "R2" : "",
181 resp_type(cmd) == RESP_R3 ? "R3" : "",
182 resp_type(cmd) == RESP_R4 ? "R4" : "",
183 resp_type(cmd) == RESP_R5 ? "R5" : "",
184 resp_type(cmd) == RESP_R6 ? "R6" : "",
185 resp_type(cmd) == RESP_R7 ? "R7" : "",
186 data ? (data->flags & DATA_DIR_WRITE ? 'w' : 'r') : '-',
187 data ? data->blks * data->blksize : 0,
188 data ? data->blksize : 0
189 );
190
191 hw_sdio->mask |= SDIO_MASKR_ALL;
192 reg_cmd = cmd->cmd_code | SDMMC_CMD_CPSMEN;
193
194 /* data pre configuration */
195 if (data != RT_NULL)
196 {
197 SCB_CleanInvalidateDCache();
198
199 reg_cmd |= SDMMC_CMD_CMDTRANS;
200 hw_sdio->mask &= ~(SDMMC_MASK_CMDRENDIE | SDMMC_MASK_CMDSENTIE);
201 hw_sdio->dtimer = HW_SDIO_DATATIMEOUT;
202 hw_sdio->dlen = data->blks * data->blksize;
203 hw_sdio->dctrl = (get_order(data->blksize)<<4) | (data->flags & DATA_DIR_READ ? SDMMC_DCTRL_DTDIR : 0);
204 hw_sdio->idmabase0r = (rt_uint32_t)cache_buf;
205 hw_sdio->idmatrlr = SDMMC_IDMA_IDMAEN;
206 }
207
208 if (resp_type(cmd) == RESP_R2)
209 reg_cmd |= SDMMC_CMD_WAITRESP;
210 else if(resp_type(cmd) != RESP_NONE)
211 reg_cmd |= SDMMC_CMD_WAITRESP_0;
212
213 hw_sdio->arg = cmd->arg;
214 hw_sdio->cmd = reg_cmd;
215 /* wait completed */
216 rthw_sdio_wait_completed(sdio);
217
218 /* Waiting for data to be sent to completion */
219 if (data != RT_NULL)
220 {
221 volatile rt_uint32_t count = SDIO_TX_RX_COMPLETE_TIMEOUT_LOOPS;
222
223 while (count && (hw_sdio->sta & SDMMC_STA_DPSMACT))
224 {
225 count--;
226 }
227 if ((count == 0) || (hw_sdio->sta & SDIO_ERRORS))
228 {
229 cmd->err = -RT_ERROR;
230 }
231 }
232
233 /* data post configuration */
234 if (data != RT_NULL)
235 {
236 if (data->flags & DATA_DIR_READ)
237 {
238 rt_memcpy(data->buf, cache_buf, data->blks * data->blksize);
239 SCB_CleanInvalidateDCache();
240 }
241 }
242 }
243
244 /**
245 * @brief This function send sdio request.
246 * @param sdio rthw_sdio
247 * @param req request
248 * @retval None
249 */
rthw_sdio_request(struct rt_mmcsd_host * host,struct rt_mmcsd_req * req)250 static void rthw_sdio_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
251 {
252 struct sdio_pkg pkg;
253 struct rthw_sdio *sdio = host->private_data;
254 struct rt_mmcsd_data *data;
255
256 if (req->cmd != RT_NULL)
257 {
258 rt_memset(&pkg, 0, sizeof(pkg));
259 data = req->cmd->data;
260 pkg.cmd = req->cmd;
261
262 if (data != RT_NULL)
263 {
264 rt_uint32_t size = data->blks * data->blksize;
265
266 RT_ASSERT(size <= SDIO_BUFF_SIZE);
267
268 if (data->flags & DATA_DIR_WRITE)
269 {
270 rt_memcpy(cache_buf, data->buf, size);
271 }
272 }
273
274 rthw_sdio_send_command(sdio, &pkg);
275 }
276
277 if (req->stop != RT_NULL)
278 {
279 rt_memset(&pkg, 0, sizeof(pkg));
280 pkg.cmd = req->stop;
281 rthw_sdio_send_command(sdio, &pkg);
282 }
283
284 mmcsd_req_complete(sdio->host);
285 }
286
287
288 /**
289 * @brief This function interrupt process function.
290 * @param host rt_mmcsd_host
291 * @retval None
292 */
rthw_sdio_irq_process(struct rt_mmcsd_host * host)293 void rthw_sdio_irq_process(struct rt_mmcsd_host *host)
294 {
295 struct rthw_sdio *sdio = host->private_data;
296 struct stm32_sdio *hw_sdio = sdio->sdio_des.hw_sdio;
297 rt_uint32_t intstatus = hw_sdio->sta;
298
299 /* clear irq flag*/
300 hw_sdio->icr = intstatus;
301
302 rt_event_send(&sdio->event, intstatus);
303 }
304
305 /**
306 * @brief This function config sdio.
307 * @param host rt_mmcsd_host
308 * @param io_cfg rt_mmcsd_io_cfg
309 * @retval None
310 */
rthw_sdio_iocfg(struct rt_mmcsd_host * host,struct rt_mmcsd_io_cfg * io_cfg)311 static void rthw_sdio_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
312 {
313 rt_uint32_t temp, clk_src;
314 rt_uint32_t clk = io_cfg->clock;
315 struct rthw_sdio *sdio = host->private_data;
316 struct stm32_sdio *hw_sdio = sdio->sdio_des.hw_sdio;
317
318 LOG_D("clk:%dK width:%s%s%s power:%s%s%s",
319 clk/1000,
320 io_cfg->bus_width == MMCSD_BUS_WIDTH_8 ? "8" : "",
321 io_cfg->bus_width == MMCSD_BUS_WIDTH_4 ? "4" : "",
322 io_cfg->bus_width == MMCSD_BUS_WIDTH_1 ? "1" : "",
323 io_cfg->power_mode == MMCSD_POWER_OFF ? "OFF" : "",
324 io_cfg->power_mode == MMCSD_POWER_UP ? "UP" : "",
325 io_cfg->power_mode == MMCSD_POWER_ON ? "ON" : ""
326 );
327
328 clk_src = SDIO_CLOCK_FREQ;
329
330 if (clk > 0)
331 {
332 if (clk > host->freq_max)
333 clk = host->freq_max;
334 temp = DIV_ROUND_UP(clk_src, 2 * clk);
335 if (temp > 0x3FF)
336 temp = 0x3FF;
337 }
338
339 if (io_cfg->bus_width == MMCSD_BUS_WIDTH_4)
340 temp |= SDMMC_CLKCR_WIDBUS_0;
341 else if (io_cfg->bus_width == MMCSD_BUS_WIDTH_8)
342 temp |= SDMMC_CLKCR_WIDBUS_1;
343
344 hw_sdio->clkcr = temp;
345
346 if (io_cfg->power_mode == MMCSD_POWER_ON)
347 hw_sdio->power |= SDMMC_POWER_PWRCTRL;
348 }
349
350 static const struct rt_mmcsd_host_ops ops =
351 {
352 rthw_sdio_request,
353 rthw_sdio_iocfg,
354 RT_NULL,
355 RT_NULL,
356 };
357
358 /**
359 * @brief This function create mmcsd host.
360 * @param sdio_des stm32_sdio_des
361 * @retval rt_mmcsd_host
362 */
sdio_host_create(struct stm32_sdio_des * sdio_des)363 struct rt_mmcsd_host *sdio_host_create(struct stm32_sdio_des *sdio_des)
364 {
365 struct rt_mmcsd_host *host;
366 struct rthw_sdio *sdio = RT_NULL;
367
368 if (sdio_des == RT_NULL)
369 {
370 return RT_NULL;
371 }
372
373 sdio = rt_malloc(sizeof(struct rthw_sdio));
374 if (sdio == RT_NULL)
375 {
376 LOG_E("malloc rthw_sdio fail");
377 return RT_NULL;
378 }
379 rt_memset(sdio, 0, sizeof(struct rthw_sdio));
380
381 host = mmcsd_alloc_host();
382 if (host == RT_NULL)
383 {
384 LOG_E("alloc host fail");
385 goto err;
386 }
387
388 rt_memcpy(&sdio->sdio_des, sdio_des, sizeof(struct stm32_sdio_des));
389
390 sdio->sdio_des.hw_sdio = (struct stm32_sdio *)SDIO_BASE_ADDRESS;
391
392 rt_event_init(&sdio->event, "sdio", RT_IPC_FLAG_FIFO);
393
394 /* set host default attributes */
395 host->ops = &ops;
396 host->freq_min = 400 * 1000;
397 host->freq_max = SDIO_MAX_FREQ;
398 host->valid_ocr = VDD_32_33 | VDD_33_34;/* The voltage range supported is 3.2v-3.4v */
399 #ifndef SDIO_USING_1_BIT
400 host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_HIGHSPEED;
401 #else
402 host->flags = MMCSD_MUTBLKWRITE | MMCSD_SUP_HIGHSPEED;
403 #endif
404
405 host->max_seg_size = SDIO_BUFF_SIZE;
406 host->max_dma_segs = 1;
407 host->max_blk_size = 512;
408 host->max_blk_count = 512;
409
410 /* link up host and sdio */
411 sdio->host = host;
412 host->private_data = sdio;
413
414 /* ready to change */
415 mmcsd_change(host);
416
417 return host;
418
419 err:
420 if (sdio) rt_free(sdio);
421
422 return RT_NULL;
423 }
424
SDMMC1_IRQHandler(void)425 void SDMMC1_IRQHandler(void)
426 {
427 /* enter interrupt */
428 rt_interrupt_enter();
429 /* Process All SDIO Interrupt Sources */
430 rthw_sdio_irq_process(host);
431 /* leave interrupt */
432 rt_interrupt_leave();
433 }
434
rt_hw_sdio_init(void)435 int rt_hw_sdio_init(void)
436 {
437 struct stm32_sdio_des sdio_des;
438 SD_HandleTypeDef hsd;
439 hsd.Instance = SDMMC1;
440 HAL_SD_MspInit(&hsd);
441
442 host = sdio_host_create(&sdio_des);
443 if (host == RT_NULL)
444 {
445 LOG_E("host create fail");
446 return RT_NULL;
447 }
448 return 0;
449 }
450 INIT_DEVICE_EXPORT(rt_hw_sdio_init);
451
mnt_init(void)452 int mnt_init(void)
453 {
454 rt_thread_delay(RT_TICK_PER_SECOND);
455
456 if (dfs_mount("sd0", "/", "elm", 0, 0) != 0)
457 {
458 rt_kprintf("file system mount failed!\n");
459 }
460 else
461 {
462 rt_kprintf("file system mount success!\n");
463 }
464
465 return 0;
466 }
467 INIT_ENV_EXPORT(mnt_init);
468
469 #endif /* BSP_USING_SDMMC */
470