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 * 2017-08-08 Yang the first version
9 */
10
11 #include <string.h>
12 #include <board.h>
13
14 #include "drv_sd.h"
15
16
17 static struct mci_device *_mci_device;
18 static uint8_t sdio_buffer[1024];
19
rt_mci_init(rt_device_t dev)20 static rt_err_t rt_mci_init(rt_device_t dev)
21 {
22 rt_err_t result = RT_EOK;
23
24 return result;
25 }
26
rt_mci_open(rt_device_t dev,rt_uint16_t oflag)27 static rt_err_t rt_mci_open(rt_device_t dev, rt_uint16_t oflag)
28 {
29 return RT_EOK;
30 }
31
rt_mci_close(rt_device_t dev)32 static rt_err_t rt_mci_close(rt_device_t dev)
33 {
34 return RT_EOK;
35 }
36
rt_mci_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)37 static rt_ssize_t rt_mci_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
38 {
39 rt_uint8_t status = kStatus_Success;
40 struct mci_device *mci = (struct mci_device *)dev;
41
42 rt_mutex_take(&mci->lock, RT_WAITING_FOREVER);
43
44 {
45 /* non-aligned. */
46 uint32_t i;
47 rt_size_t sector_adr;
48 uint8_t* copy_buffer;
49
50 sector_adr = pos;
51 copy_buffer = (uint8_t*)buffer;
52
53 for(i=0; i<size; i++)
54 {
55 status=SD_ReadBlocks(&mci->card, sdio_buffer, sector_adr, 1);
56
57 memcpy(copy_buffer, sdio_buffer, mci->card.blockSize);
58 sector_adr ++;
59 copy_buffer += mci->card.blockSize;
60 }
61 }
62
63 rt_mutex_release(&_mci_device->lock);
64
65 if (status == kStatus_Success) return size;
66
67 return 0;
68 }
69
rt_mci_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)70 static rt_ssize_t rt_mci_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
71 {
72 rt_uint8_t status = kStatus_Success;
73 struct mci_device *mci = (struct mci_device *)dev;
74
75 rt_mutex_take(&mci->lock, RT_WAITING_FOREVER);
76
77 {
78 /* non-aligned. */
79 uint32_t i;
80 rt_size_t sector_adr;
81 uint8_t* copy_buffer;
82
83 sector_adr = pos;
84 copy_buffer = (uint8_t*)buffer;
85
86 for(i = 0; i < size; i++)
87 {
88 memcpy(sdio_buffer, copy_buffer, mci->card.blockSize);
89
90 status = SD_WriteBlocks(&mci->card, sdio_buffer, sector_adr, 1);
91
92 sector_adr ++;
93 copy_buffer += mci->card.blockSize;
94
95 }
96 }
97
98 /* release and exit */
99 rt_mutex_release(&_mci_device->lock);
100
101 if (status == kStatus_Success) return size;
102
103 return 0;
104 }
105
rt_mci_control(rt_device_t dev,int cmd,void * args)106 static rt_err_t rt_mci_control(rt_device_t dev, int cmd, void *args)
107 {
108 struct mci_device *mci = (struct mci_device *)dev;
109
110 RT_ASSERT(dev != RT_NULL);
111
112 if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
113 {
114 struct rt_device_blk_geometry *geometry;
115
116 geometry = (struct rt_device_blk_geometry *)args;
117 if (geometry == RT_NULL) return -RT_ERROR;
118
119 geometry->bytes_per_sector = mci->card.blockSize;
120 geometry->block_size = mci->card.csd.eraseSectorSize;
121 geometry->sector_count = mci->card.blockCount;
122 }
123
124 return RT_EOK;
125 }
126
sdio_init_pins(void)127 void sdio_init_pins(void)
128 {
129 const uint32_t port2_pin10_config = (
130 IOCON_PIO_FUNC2 | /* Pin is configured as SD_CARD_DET_N */
131 IOCON_PIO_MODE_INACT | /* No addition pin function */
132 IOCON_PIO_INV_DI | /* Input function is not inverted */
133 IOCON_PIO_DIGITAL_EN | /* Enables digital function */
134 IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
135 IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */
136 IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
137 );
138 IOCON_PinMuxSet(IOCON, PORT2_IDX, PIN10_IDX, port2_pin10_config); /* PORT2 PIN10 (coords: P1) is configured as SD_CARD_DET_N */
139 const uint32_t port2_pin3_config = (
140 IOCON_PIO_FUNC2 | /* Pin is configured as SD_CLK */
141 IOCON_PIO_MODE_INACT | /* No addition pin function */
142 IOCON_PIO_INV_DI | /* Input function is not inverted */
143 IOCON_PIO_DIGITAL_EN | /* Enables digital function */
144 IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
145 IOCON_PIO_SLEW_FAST | /* Fast mode, slew rate control is disabled */
146 IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
147 );
148 IOCON_PinMuxSet(IOCON, PORT2_IDX, PIN3_IDX, port2_pin3_config); /* PORT2 PIN3 (coords: B1) is configured as SD_CLK */
149 const uint32_t port2_pin4_config = (
150 IOCON_PIO_FUNC2 | /* Pin is configured as SD_CMD */
151 IOCON_PIO_MODE_INACT | /* No addition pin function */
152 IOCON_PIO_INV_DI | /* Input function is not inverted */
153 IOCON_PIO_DIGITAL_EN | /* Enables digital function */
154 IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
155 IOCON_PIO_SLEW_FAST | /* Fast mode, slew rate control is disabled */
156 IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
157 );
158 IOCON_PinMuxSet(IOCON, PORT2_IDX, PIN4_IDX, port2_pin4_config); /* PORT2 PIN4 (coords: D3) is configured as SD_CMD */
159 const uint32_t port2_pin5_config = (
160 IOCON_PIO_FUNC2 | /* Pin is configured as SD_POW_EN */
161 IOCON_PIO_MODE_INACT | /* No addition pin function */
162 IOCON_PIO_INV_DI | /* Input function is not inverted */
163 IOCON_PIO_DIGITAL_EN | /* Enables digital function */
164 IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
165 IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */
166 IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
167 );
168 IOCON_PinMuxSet(IOCON, PORT2_IDX, PIN5_IDX, port2_pin5_config); /* PORT2 PIN5 (coords: C1) is configured as SD_POW_EN */
169 const uint32_t port2_pin6_config = (
170 IOCON_PIO_FUNC2 | /* Pin is configured as SD_D(0) */
171 IOCON_PIO_MODE_INACT | /* No addition pin function */
172 IOCON_PIO_INV_DI | /* Input function is not inverted */
173 IOCON_PIO_DIGITAL_EN | /* Enables digital function */
174 IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
175 IOCON_PIO_SLEW_FAST | /* Fast mode, slew rate control is disabled */
176 IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
177 );
178 IOCON_PinMuxSet(IOCON, PORT2_IDX, PIN6_IDX, port2_pin6_config); /* PORT2 PIN6 (coords: F3) is configured as SD_D(0) */
179 const uint32_t port2_pin7_config = (
180 IOCON_PIO_FUNC2 | /* Pin is configured as SD_D(1) */
181 IOCON_PIO_MODE_INACT | /* No addition pin function */
182 IOCON_PIO_INV_DI | /* Input function is not inverted */
183 IOCON_PIO_DIGITAL_EN | /* Enables digital function */
184 IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
185 IOCON_PIO_SLEW_FAST | /* Fast mode, slew rate control is disabled */
186 IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
187 );
188 IOCON_PinMuxSet(IOCON, PORT2_IDX, PIN7_IDX, port2_pin7_config); /* PORT2 PIN7 (coords: J2) is configured as SD_D(1) */
189 const uint32_t port2_pin8_config = (
190 IOCON_PIO_FUNC2 | /* Pin is configured as SD_D(2) */
191 IOCON_PIO_MODE_INACT | /* No addition pin function */
192 IOCON_PIO_INV_DI | /* Input function is not inverted */
193 IOCON_PIO_DIGITAL_EN | /* Enables digital function */
194 IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
195 IOCON_PIO_SLEW_FAST | /* Fast mode, slew rate control is disabled */
196 IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
197 );
198 IOCON_PinMuxSet(IOCON, PORT2_IDX, PIN8_IDX, port2_pin8_config); /* PORT2 PIN8 (coords: F4) is configured as SD_D(2) */
199 const uint32_t port2_pin9_config = (
200 IOCON_PIO_FUNC2 | /* Pin is configured as SD_D(3) */
201 IOCON_PIO_MODE_INACT | /* No addition pin function */
202 IOCON_PIO_INV_DI | /* Input function is not inverted */
203 IOCON_PIO_DIGITAL_EN | /* Enables digital function */
204 IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
205 IOCON_PIO_SLEW_FAST | /* Fast mode, slew rate control is disabled */
206 IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
207 );
208 IOCON_PinMuxSet(IOCON, PORT2_IDX, PIN9_IDX, port2_pin9_config); /* PORT2 PIN9 (coords: K2) is configured as SD_D(3) */
209 const uint32_t port3_pin15_config = (
210 IOCON_PIO_FUNC2 | /* Pin is configured as SD_WR_PRT */
211 IOCON_PIO_MODE_INACT | /* No addition pin function */
212 IOCON_PIO_INV_DI | /* Input function is not inverted */
213 IOCON_PIO_DIGITAL_EN | /* Enables digital function */
214 IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
215 IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */
216 IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
217 );
218 IOCON_PinMuxSet(IOCON, PORT3_IDX, PIN15_IDX, port3_pin15_config); /* PORT3 PIN15 (coords: D2) is configured as SD_WR_PRT */
219 }
220
221 sd_card_t g_sd;
222
223 /*! @brief Data written to the card */
224 uint8_t g_dataWrite[FSL_SDMMC_DEFAULT_BLOCK_SIZE * 5U];
225 /*! @brief Data read from the card */
226 uint8_t g_dataRead[FSL_SDMMC_DEFAULT_BLOCK_SIZE * 5U];
227
mci_hw_init(const char * device_name)228 rt_err_t mci_hw_init(const char *device_name)
229 #if 0
230 {
231 sd_card_t *card = &g_sd;
232 bool isReadOnly;
233 bool failedFlag = false;
234 char ch = '0';
235
236 /* attach main clock to SDIF */
237 CLOCK_AttachClk(kMCLK_to_SDIO_CLK);
238 /* need call this function to clear the halt bit in clock divider register */
239 CLOCK_SetClkDiv(kCLOCK_DivSdioClk, 1U, true);
240
241 sdio_init_pins();
242
243 card->host.base = SDIF;
244 card->host.sourceClock_Hz = CLOCK_GetFreq(kCLOCK_SDio);
245
246 /* Init card. */
247 if (SD_Init(card))
248 {
249 rt_kprintf("\r\nSD card init failed.\r\n");
250 return -1;
251 }
252
253 rt_kprintf("\r\nRead/Write/Erase the card continuously until encounter error......\r\n");
254 /* Check if card is readonly. */
255 isReadOnly = SD_CheckReadOnly(card);
256 if (isReadOnly)
257 {
258 //while (true)
259 {
260 /*if (failedFlag || (ch == 'q'))
261 {
262 break;
263 }*/
264
265 rt_kprintf("\r\nRead one data block......\r\n");
266 if (kStatus_Success != SD_ReadBlocks(card, g_dataRead, 2U, 1U))
267 {
268 rt_kprintf("Read one data block failed.\r\n");
269 failedFlag = true;
270 //continue;
271 }
272
273 rt_kprintf("Read multiple data blocks......\r\n");
274 if (kStatus_Success != SD_ReadBlocks(card, g_dataRead, 2U, 5U))
275 {
276 rt_kprintf("Read multiple data blocks failed.\r\n");
277 failedFlag = true;
278 //continue;
279 }
280
281 rt_kprintf(
282 "\r\nInput 'q' to quit read process.\
283 \r\nInput other char to read data blocks again.\r\n");
284 //ch = GETCHAR();
285 //PUTCHAR(ch);
286 }
287 }
288 else
289 {
290 memset(g_dataWrite, 0x67U, sizeof(g_dataWrite));
291
292 //while (true)
293 {
294 /*if (failedFlag || (ch == 'q'))
295 {
296 break;
297 }*/
298
299 rt_kprintf("\r\nWrite/read one data block......\r\n");
300 if (kStatus_Success != SD_WriteBlocks(card, g_dataWrite, 2U, 1U))
301 {
302 rt_kprintf("Write one data block failed.\r\n");
303 failedFlag = true;
304 //continue;
305 }
306
307 memset(g_dataRead, 0U, sizeof(g_dataRead));
308 if (kStatus_Success != SD_ReadBlocks(card, g_dataRead, 2U, 1U))
309 {
310 rt_kprintf("Read one data block failed.\r\n");
311 failedFlag = true;
312 //continue;
313 }
314
315 rt_kprintf("Compare the read/write content......\r\n");
316 if (memcmp(g_dataRead, g_dataWrite, FSL_SDMMC_DEFAULT_BLOCK_SIZE))
317 {
318 rt_kprintf("The read/write content isn't consistent.\r\n");
319 failedFlag = true;
320 //continue;
321 }
322 rt_kprintf("The read/write content is consistent.\r\n");
323
324 rt_kprintf("Write/read multiple data blocks......\r\n");
325 if (kStatus_Success != SD_WriteBlocks(card, g_dataWrite, 2U, 5U))
326 {
327 rt_kprintf("Write multiple data blocks failed.\r\n");
328 failedFlag = true;
329 //continue;
330 }
331
332 memset(g_dataRead, 0U, sizeof(g_dataRead));
333
334 if (kStatus_Success != SD_ReadBlocks(card, g_dataRead, 2U, 5U))
335 {
336 rt_kprintf("Read multiple data blocks failed.\r\n");
337 failedFlag = true;
338 //continue;
339 }
340
341 rt_kprintf("Compare the read/write content......\r\n");
342 if (memcmp(g_dataRead, g_dataWrite, FSL_SDMMC_DEFAULT_BLOCK_SIZE))
343 {
344 rt_kprintf("The read/write content isn't consistent.\r\n");
345 failedFlag = true;
346 //continue;
347 }
348 rt_kprintf("The read/write content is consistent.\r\n");
349
350 rt_kprintf("Erase multiple data blocks......\r\n");
351 if (kStatus_Success != SD_EraseBlocks(card, 2U, 5U))
352 {
353 rt_kprintf("Erase multiple data blocks failed.\r\n");
354 failedFlag = true;
355 //continue;
356 }
357
358 rt_kprintf(
359 "\r\nInput 'q' to quit read/write/erase process.\
360 \r\nInput other char to read/write/erase data blocks again.\r\n");
361 //ch = GETCHAR();
362 //PUTCHAR(ch);
363 }
364 }
365 rt_kprintf("\r\nThe example will not read/write data blocks again.\r\n");
366
367 SD_Deinit(card);
368 }
369 #else
370 {
371 _mci_device = (struct mci_device *)rt_malloc(sizeof(struct mci_device));
372 if (_mci_device == RT_NULL)
373 {
374 rt_kprintf("mci_hw_init _mci_device rt_malloc failed!\n");
375 return -RT_ERROR;
376 }
377 rt_memset(_mci_device, 0, sizeof(struct mci_device));
378
379 /* attach main clock to SDIF */
380 CLOCK_AttachClk(kMCLK_to_SDIO_CLK);
381 /* need call this function to clear the halt bit in clock divider register */
382 CLOCK_SetClkDiv(kCLOCK_DivSdioClk, 1U, true);
383
384 sdio_init_pins();
385
386 /* Save host information. */
387 _mci_device->card.host.base = SDIF;
388 _mci_device->card.host.sourceClock_Hz = CLOCK_GetFreq(kCLOCK_SDio);
389
390 if (kStatus_Success != SD_Init(&_mci_device->card))
391 {
392 SD_Deinit(&_mci_device->card);
393 memset(&_mci_device->card, 0U, sizeof(_mci_device->card));
394 rt_kprintf("SD_Init failed!\n");
395 return -RT_ERROR;
396 }
397
398 /*
399 follow the page: https://community.nxp.com/thread/454769
400
401 The issue concerns sdmmc library bug (I finally solved) in SD_Init() in the file sdmmc/src/fsl_sd.c:SD_SelectBusTiming()
402 calls SD_SwitchFunction() which sets block size to 64bytes (512bits).Therefore SD_SetBlockSize(card, FSL_SDMMC_DEFAULT_BLOCK_SIZE)
403 should be called again before SD_Init() exits.
404 */
405
406 if (kStatus_Success != SDMMC_SetBlockSize(_mci_device->card.host.base, _mci_device->card.host.transfer, FSL_SDMMC_DEFAULT_BLOCK_SIZE))
407 {
408 SD_Deinit(&_mci_device->card);
409 memset(&_mci_device->card, 0U, sizeof(_mci_device->card));
410 rt_kprintf("SD_Init failed!\n");
411 return -RT_ERROR;
412 }
413
414 /* initialize mutex lock */
415 rt_mutex_init(&_mci_device->lock, device_name, RT_IPC_FLAG_PRIO);
416 /* create finish event */
417 _mci_device->finish_event = rt_event_create(device_name, RT_IPC_FLAG_FIFO);
418
419 /* register sdcard device */
420 _mci_device->parent.type = RT_Device_Class_Block;
421
422 _mci_device->geometry.bytes_per_sector = 0;
423 _mci_device->geometry.sector_count = 0;
424 _mci_device->geometry.block_size = 0;
425
426 _mci_device->parent.init = rt_mci_init;
427 _mci_device->parent.open = rt_mci_open;
428 _mci_device->parent.close = rt_mci_close;
429 _mci_device->parent.read = rt_mci_read;
430 _mci_device->parent.write = rt_mci_write;
431 _mci_device->parent.control = rt_mci_control;
432
433 /* no private, no callback */
434 _mci_device->parent.user_data = RT_NULL;
435 _mci_device->parent.rx_indicate = RT_NULL;
436 _mci_device->parent.tx_complete = RT_NULL;
437
438 rt_device_register(&_mci_device->parent, device_name,
439 RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE );
440 return RT_EOK;
441 }
442 #endif
443