1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2017-10-10 Tanek first version
9 */
10
11 #include <rtthread.h>
12 #include <rthw.h>
13 #include <drivers/dev_mmcsd_core.h>
14
15 #include <board.h>
16 #include <fsl_usdhc.h>
17 #include <fsl_gpio.h>
18 #include <fsl_iomuxc.h>
19
20 #include <finsh.h>
21
22 #define RT_USING_SDIO1
23 #define RT_USING_SDIO2
24
25 //#define DEBUG
26
27 #ifdef DEBUG
28 static int enable_log = 1;
29
30 #define MMCSD_DGB(fmt, ...) \
31 do \
32 { \
33 if (enable_log) \
34 { \
35 rt_kprintf(fmt, ##__VA_ARGS__); \
36 } \
37 } while (0)
38 #else
39 #define MMCSD_DGB(fmt, ...)
40 #endif
41
42 #define CACHE_LINESIZE (32)
43
44
45 #define IMXRT_MAX_FREQ (25UL * 1000UL * 1000UL)
46
47 #define USDHC_READ_BURST_LEN (8U) /*!< number of words USDHC read in a single burst */
48 #define USDHC_WRITE_BURST_LEN (8U) /*!< number of words USDHC write in a single burst */
49 #define USDHC_DATA_TIMEOUT (0xFU) /*!< data timeout counter value */
50 #define SDMMCHOST_SUPPORT_MAX_BLOCK_LENGTH (4096U)
51 #define SDMMCHOST_SUPPORT_MAX_BLOCK_COUNT (USDHC_MAX_BLOCK_COUNT)
52
53 /* Read/write watermark level. The bigger value indicates DMA has higher read/write performance. */
54 #define USDHC_READ_WATERMARK_LEVEL (0x80U)
55 #define USDHC_WRITE_WATERMARK_LEVEL (0x80U)
56
57 /* DMA mode */
58 #define USDHC_DMA_MODE kUSDHC_DmaModeAdma2
59
60 /* Endian mode. */
61 #define USDHC_ENDIAN_MODE kUSDHC_EndianModeLittle
62
63 //#ifdef SOC_IMXRT1170_SERIES
64 #define USDHC_ADMA_TABLE_WORDS (32U) /* define the ADMA descriptor table length */
65 #define USDHC_ADMA2_ADDR_ALIGN (4U) /* define the ADMA2 descriptor table addr align size */
66 //#else
67 //#define USDHC_ADMA_TABLE_WORDS (8U) /* define the ADMA descriptor table length */
68 //#define USDHC_ADMA2_ADDR_ALIGN (4U) /* define the ADMA2 descriptor table addr align size */
69 //#endif
70
71 //rt_align(USDHC_ADMA2_ADDR_ALIGN) uint32_t g_usdhcAdma2Table[USDHC_ADMA_TABLE_WORDS] SECTION("NonCacheable");
72 AT_NONCACHEABLE_SECTION_ALIGN(uint32_t g_usdhcAdma2Table[USDHC_ADMA_TABLE_WORDS], USDHC_ADMA2_ADDR_ALIGN);
73 struct imxrt_mmcsd
74 {
75 struct rt_mmcsd_host *host;
76 struct rt_mmcsd_req *req;
77 struct rt_mmcsd_cmd *cmd;
78
79 struct rt_timer timer;
80
81 rt_uint32_t *buf;
82
83 //USDHC_Type *base;
84 usdhc_host_t usdhc_host;
85 #ifndef SOC_IMXRT1170_SERIES
86 clock_div_t usdhc_div;
87 #endif
88 clock_ip_name_t ip_clock;
89
90 uint32_t *usdhc_adma2_table;
91 };
92
93 #ifndef CODE_STORED_ON_SDCARD
_mmcsd_gpio_init(struct imxrt_mmcsd * mmcsd)94 static void _mmcsd_gpio_init(struct imxrt_mmcsd *mmcsd)
95 {
96
97 // CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */
98 }
99 #endif
100
SDMMCHOST_ErrorRecovery(USDHC_Type * base)101 static void SDMMCHOST_ErrorRecovery(USDHC_Type *base)
102 {
103 uint32_t status = 0U;
104 /* get host present status */
105 status = USDHC_GetPresentStatusFlags(base);
106 /* check command inhibit status flag */
107 if ((status & kUSDHC_CommandInhibitFlag) != 0U)
108 {
109 /* reset command line */
110 USDHC_Reset(base, kUSDHC_ResetCommand, 1000U);
111 }
112 /* check data inhibit status flag */
113 if ((status & kUSDHC_DataInhibitFlag) != 0U)
114 {
115 /* reset data line */
116 USDHC_Reset(base, kUSDHC_ResetData, 1000U);
117 }
118 }
119
120 #ifndef CODE_STORED_ON_SDCARD
_mmcsd_host_init(struct imxrt_mmcsd * mmcsd)121 static void _mmcsd_host_init(struct imxrt_mmcsd *mmcsd)
122 {
123 usdhc_host_t *usdhc_host = &mmcsd->usdhc_host;
124
125 /* Initializes SDHC. */
126 usdhc_host->config.dataTimeout = USDHC_DATA_TIMEOUT;
127 usdhc_host->config.endianMode = USDHC_ENDIAN_MODE;
128 usdhc_host->config.readWatermarkLevel = USDHC_READ_WATERMARK_LEVEL;
129 usdhc_host->config.writeWatermarkLevel = USDHC_WRITE_WATERMARK_LEVEL;
130 #if !(defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN)
131 usdhc_host->config.readBurstLen = USDHC_READ_BURST_LEN;
132 usdhc_host->config.writeBurstLen = USDHC_WRITE_BURST_LEN;
133 #endif
134 USDHC_Init(usdhc_host->base, &(usdhc_host->config));
135 }
136
_mmcsd_clk_init(struct imxrt_mmcsd * mmcsd)137 static void _mmcsd_clk_init(struct imxrt_mmcsd *mmcsd)
138 {
139 CLOCK_EnableClock(mmcsd->ip_clock);
140 #if !defined(SOC_IMXRT1170_SERIES) && !defined(SOC_MIMXRT1062DVL6A)
141 CLOCK_SetDiv(mmcsd->usdhc_div, 5U);
142 #endif
143 }
144
_mmcsd_isr_init(struct imxrt_mmcsd * mmcsd)145 static void _mmcsd_isr_init(struct imxrt_mmcsd *mmcsd)
146 {
147 //NVIC_SetPriority(USDHC1_IRQn, 5U);
148 }
149 #endif
150
_mmc_request(struct rt_mmcsd_host * host,struct rt_mmcsd_req * req)151 static void _mmc_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
152 {
153 struct imxrt_mmcsd *mmcsd;
154 struct rt_mmcsd_cmd *cmd;
155 struct rt_mmcsd_data *data;
156 status_t error;
157 usdhc_adma_config_t dmaConfig;
158 usdhc_transfer_t fsl_content = {0};
159 usdhc_command_t fsl_command = {0};
160 usdhc_data_t fsl_data = {0};
161 rt_uint32_t *buf = NULL;
162
163 RT_ASSERT(host != RT_NULL);
164 RT_ASSERT(req != RT_NULL);
165
166 mmcsd = (struct imxrt_mmcsd *)host->private_data;
167 RT_ASSERT(mmcsd != RT_NULL);
168
169 cmd = req->cmd;
170 RT_ASSERT(cmd != RT_NULL);
171
172 MMCSD_DGB("\tcmd->cmd_code: %02d, cmd->arg: %08x, cmd->flags: %08x --> ", cmd->cmd_code, cmd->arg, cmd->flags);
173
174 data = cmd->data;
175
176 rt_memset(&dmaConfig, 0, sizeof(usdhc_adma_config_t));
177 /* config adma */
178 dmaConfig.dmaMode = USDHC_DMA_MODE;
179 #if !(defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN)
180 dmaConfig.burstLen = kUSDHC_EnBurstLenForINCR;
181 #endif
182 dmaConfig.admaTable = mmcsd->usdhc_adma2_table;
183 dmaConfig.admaTableWords = USDHC_ADMA_TABLE_WORDS;
184
185 fsl_command.index = cmd->cmd_code;
186 fsl_command.argument = cmd->arg;
187
188 if (cmd->cmd_code == STOP_TRANSMISSION)
189 fsl_command.type = kCARD_CommandTypeAbort;
190 else
191 fsl_command.type = kCARD_CommandTypeNormal;
192
193 switch (cmd->flags & RESP_MASK)
194 {
195 case RESP_NONE:
196 fsl_command.responseType = kCARD_ResponseTypeNone;
197 break;
198 case RESP_R1:
199 fsl_command.responseType = kCARD_ResponseTypeR1;
200 break;
201 case RESP_R1B:
202 fsl_command.responseType = kCARD_ResponseTypeR1b;
203 break;
204 case RESP_R2:
205 fsl_command.responseType = kCARD_ResponseTypeR2;
206 break;
207 case RESP_R3:
208 fsl_command.responseType = kCARD_ResponseTypeR3;
209 break;
210 case RESP_R4:
211 fsl_command.responseType = kCARD_ResponseTypeR4;
212 break;
213 case RESP_R6:
214 fsl_command.responseType = kCARD_ResponseTypeR6;
215 break;
216 case RESP_R7:
217 fsl_command.responseType = kCARD_ResponseTypeR7;
218 break;
219 case RESP_R5:
220 fsl_command.responseType = kCARD_ResponseTypeR5;
221 break;
222 default:
223 RT_ASSERT(NULL);
224 }
225
226 fsl_command.flags = 0;
227 fsl_content.command = &fsl_command;
228
229 if (data)
230 {
231 if (req->stop != NULL)
232 fsl_data.enableAutoCommand12 = true;
233 else
234 fsl_data.enableAutoCommand12 = false;
235
236 fsl_data.enableAutoCommand23 = false;
237
238 fsl_data.enableIgnoreError = false;
239 fsl_data.dataType = kUSDHC_TransferDataNormal; //todo : update data type
240 fsl_data.blockSize = data->blksize;
241 fsl_data.blockCount = data->blks;
242
243 MMCSD_DGB(" blksize:%d, blks:%d ", fsl_data.blockSize, fsl_data.blockCount);
244
245 if (((rt_uint32_t)data->buf & (CACHE_LINESIZE - 1)) || // align cache(32byte)
246 ((rt_uint32_t)data->buf > 0x00000000 && (rt_uint32_t)data->buf < 0x00080000) /*|| // ITCM
247 ((rt_uint32_t)data->buf >= 0x20000000 && (rt_uint32_t)data->buf < 0x20080000)*/) // DTCM
248 {
249
250 buf = rt_malloc_align(fsl_data.blockSize * fsl_data.blockCount, CACHE_LINESIZE);
251 RT_ASSERT(buf != RT_NULL);
252
253 MMCSD_DGB(" malloc buf: %p, data->buf:%p, %d ", buf, data->buf, fsl_data.blockSize * fsl_data.blockCount);
254 }
255
256
257 if ((cmd->cmd_code == WRITE_BLOCK) || (cmd->cmd_code == WRITE_MULTIPLE_BLOCK))
258 {
259 if (buf)
260 {
261 MMCSD_DGB(" write(data->buf to buf) ");
262 rt_memcpy(buf, data->buf, fsl_data.blockSize * fsl_data.blockCount);
263 fsl_data.txData = (uint32_t const *)buf;
264 }
265 else
266 {
267 fsl_data.txData = (uint32_t const *)data->buf;
268 }
269
270 fsl_data.rxData = NULL;
271 }
272 else
273 {
274 if (buf)
275 {
276 fsl_data.rxData = (uint32_t *)buf;
277 }
278 else
279 {
280 fsl_data.rxData = (uint32_t *)data->buf;
281 }
282
283 fsl_data.txData = NULL;
284 }
285
286 fsl_content.data = &fsl_data;
287 }
288 else
289 {
290 fsl_content.data = NULL;
291 }
292
293 error = USDHC_TransferBlocking(mmcsd->usdhc_host.base, &dmaConfig, &fsl_content);
294 if (error != kStatus_Success)
295 {
296 SDMMCHOST_ErrorRecovery(mmcsd->usdhc_host.base);
297 MMCSD_DGB(" ***USDHC_TransferBlocking error: %d*** --> \n", error);
298 cmd->err = -RT_ERROR;
299 }
300
301 if (buf)
302 {
303 if (fsl_data.rxData)
304 {
305 MMCSD_DGB("read copy buf to data->buf ");
306 rt_memcpy(data->buf, buf, fsl_data.blockSize * fsl_data.blockCount);
307 }
308
309 rt_free_align(buf);
310 }
311
312 if ((cmd->flags & RESP_MASK) == RESP_R2)
313 {
314 cmd->resp[3] = fsl_command.response[0];
315 cmd->resp[2] = fsl_command.response[1];
316 cmd->resp[1] = fsl_command.response[2];
317 cmd->resp[0] = fsl_command.response[3];
318 MMCSD_DGB(" resp 0x%08X 0x%08X 0x%08X 0x%08X\n",
319 cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
320 }
321 else
322 {
323 cmd->resp[0] = fsl_command.response[0];
324 MMCSD_DGB(" resp 0x%08X\n", cmd->resp[0]);
325 }
326
327 mmcsd_req_complete(host);
328
329 return;
330 }
331
_mmc_set_iocfg(struct rt_mmcsd_host * host,struct rt_mmcsd_io_cfg * io_cfg)332 static void _mmc_set_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
333 {
334
335 struct imxrt_mmcsd *mmcsd;
336 unsigned int usdhc_clk;
337 unsigned int bus_width;
338 uint32_t src_clk;
339
340 RT_ASSERT(host != RT_NULL);
341 RT_ASSERT(host->private_data != RT_NULL);
342 RT_ASSERT(io_cfg != RT_NULL);
343
344 mmcsd = (struct imxrt_mmcsd *)host->private_data;
345 usdhc_clk = io_cfg->clock;
346 bus_width = io_cfg->bus_width;
347
348 if (usdhc_clk > IMXRT_MAX_FREQ)
349 usdhc_clk = IMXRT_MAX_FREQ;
350 #ifdef SOC_IMXRT1170_SERIES
351 clock_root_config_t rootCfg = {0};
352 /* SYS PLL2 528MHz. */
353 const clock_sys_pll2_config_t sysPll2Config = {
354 .ssEnable = false,
355 };
356
357 CLOCK_InitSysPll2(&sysPll2Config);
358 CLOCK_InitPfd(kCLOCK_PllSys2, kCLOCK_Pfd2, 24);
359
360 rootCfg.mux = 4;
361 rootCfg.div = 2;
362 CLOCK_SetRootClock(kCLOCK_Root_Usdhc1, &rootCfg);
363 src_clk = CLOCK_GetRootClockFreq(kCLOCK_Root_Usdhc1);
364 #elif defined(SOC_MIMXRT1062DVL6A)
365 CLOCK_InitSysPll(&sysPllConfig_BOARD_BootClockRUN);
366 /*configure system pll PFD0 fractional divider to 24, output clock is 528MHZ * 18 / 24 = 396 MHZ*/
367 CLOCK_InitSysPfd(kCLOCK_Pfd0, 24U);
368 /* Configure USDHC clock source and divider */
369 CLOCK_SetDiv(kCLOCK_Usdhc1Div, 1U); /* USDHC clock root frequency maximum: 198MHZ */
370 CLOCK_SetMux(kCLOCK_Usdhc1Mux, 1U);
371 src_clk = 396000000U / 2U;
372 #else
373 src_clk = (CLOCK_GetSysPfdFreq(kCLOCK_Pfd2) / (CLOCK_GetDiv(mmcsd->usdhc_div) + 1U));
374 #endif
375 MMCSD_DGB("\tsrc_clk: %d, usdhc_clk: %d, bus_width: %d\n", src_clk, usdhc_clk, bus_width);
376
377 if (usdhc_clk)
378 {
379 USDHC_SetSdClock(mmcsd->usdhc_host.base, src_clk, usdhc_clk);
380
381 /* Change bus width */
382 if (bus_width == MMCSD_BUS_WIDTH_8)
383 USDHC_SetDataBusWidth(mmcsd->usdhc_host.base, kUSDHC_DataBusWidth8Bit);
384 else if (bus_width == MMCSD_BUS_WIDTH_4)
385 USDHC_SetDataBusWidth(mmcsd->usdhc_host.base, kUSDHC_DataBusWidth4Bit);
386 else if (bus_width == MMCSD_BUS_WIDTH_1)
387 USDHC_SetDataBusWidth(mmcsd->usdhc_host.base, kUSDHC_DataBusWidth1Bit);
388 else
389 RT_ASSERT(RT_NULL);
390 }
391 }
392
393 #ifdef DEBUG
log_toggle(int en)394 static void log_toggle(int en)
395 {
396 enable_log = en;
397 }
398 FINSH_FUNCTION_EXPORT(log_toggle, toglle log dumple);
399 #endif
400
401 static const struct rt_mmcsd_host_ops ops =
402 {
403 _mmc_request,
404 _mmc_set_iocfg,
405 RT_NULL,//_mmc_get_card_status,
406 RT_NULL,//_mmc_enable_sdio_irq,
407 };
408
_imxrt_mci_init(void)409 rt_int32_t _imxrt_mci_init(void)
410 {
411 struct rt_mmcsd_host *host;
412 struct imxrt_mmcsd *mmcsd;
413
414 #if (defined(FSL_FEATURE_USDHC_HAS_HS400_MODE) && (FSL_FEATURE_USDHC_HAS_HS400_MODE))
415 uint32_t hs400Capability = 0U;
416 #endif
417
418 host = mmcsd_alloc_host();
419 if (!host)
420 {
421 return -RT_ERROR;
422 }
423
424 mmcsd = rt_malloc(sizeof(struct imxrt_mmcsd));
425 if (!mmcsd)
426 {
427 rt_kprintf("alloc mci failed\n");
428 goto err;
429 }
430
431 rt_memset(mmcsd, 0, sizeof(struct imxrt_mmcsd));
432 mmcsd->usdhc_host.base = USDHC1;
433 //#ifndef SOC_IMXRT1170_SERIES
434 // mmcsd->usdhc_div = kCLOCK_Usdhc1Div;
435 //#endif
436 mmcsd->usdhc_adma2_table = g_usdhcAdma2Table;
437
438 host->ops = &ops;
439 host->freq_min = 375000;
440 host->freq_max = 25000000;
441 host->valid_ocr = VDD_32_33 | VDD_33_34;
442 host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | \
443 MMCSD_SUP_HIGHSPEED | MMCSD_SUP_SDIO_IRQ;
444
445 #if defined(FSL_FEATURE_USDHC_INSTANCE_SUPPORT_HS400_MODEn) && (FSL_FEATURE_USDHC_INSTANCE_SUPPORT_HS400_MODEn)
446 hs400Capability = (uint32_t)FSL_FEATURE_USDHC_INSTANCE_SUPPORT_HS400_MODEn(mmcsd->usdhc_host.base);
447 #endif
448 #if (defined(FSL_FEATURE_USDHC_HAS_HS400_MODE) && (FSL_FEATURE_USDHC_HAS_HS400_MODE))
449 if (hs400Capability != 0U)
450 {
451 host->flags |= (uint32_t)MMCSD_SUP_HIGHSPEED_HS400;
452 }
453
454 #endif
455
456 host->max_seg_size = 65535;
457 host->max_dma_segs = 2;
458 //#ifdef SOC_IMXRT1170_SERIES
459 host->max_blk_size = SDMMCHOST_SUPPORT_MAX_BLOCK_LENGTH;
460 host->max_blk_count = SDMMCHOST_SUPPORT_MAX_BLOCK_COUNT;
461 //#else
462 // host->max_blk_size = 512;
463 // host->max_blk_count = 4096;
464 //#endif
465 mmcsd->host = host;
466
467 #ifndef CODE_STORED_ON_SDCARD
468 _mmcsd_clk_init(mmcsd);
469 _mmcsd_isr_init(mmcsd);
470 _mmcsd_gpio_init(mmcsd);
471 _mmcsd_host_init(mmcsd);
472 #endif
473
474 host->private_data = mmcsd;
475
476 mmcsd_change(host);
477
478 return 0;
479
480 err:
481 mmcsd_free_host(host);
482
483 return -RT_ENOMEM;
484 }
485
imxrt_mci_init(void)486 int imxrt_mci_init(void)
487 {
488 /* initilize sd card */
489 _imxrt_mci_init();
490
491 return 0;
492 }
493 INIT_DEVICE_EXPORT(imxrt_mci_init);
494