1 /*
2 * Copyright (c) 2022 Winner Microelectronics Co., Ltd. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "wm_sdio_host.h"
17 #include "wm_debug.h"
18 #include "wm_mem.h"
19 #include "wm_dma.h"
20 #include "wm_cpu.h"
21
22 #define TEST_DEBUG_EN 0
23 #if TEST_DEBUG_EN
24 #define TEST_DEBUG(fmt, ...) printf("%s: "fmt, __func__, ##__VA_ARGS__)
25 #else
26 #define TEST_DEBUG(fmt, ...)
27 #endif
28
29 SD_CardInfo_t SDCardInfo;
30 extern void delay_cnt(int count);
sh_dumpBuffer(char * name,char * buffer,int len)31 static void sh_dumpBuffer(char *name, char* buffer, int len)
32 {
33 #if TEST_DEBUG_EN
34 int i = 0;
35 printf("%s:\n", name);
36 for (; i < len; i++) {
37 printf("%02X, ", buffer[i]);
38 if ((i + 1) % 16 == 0) { // 16:byte alignment
39 printf("\n");
40 }
41 }
42 printf("\n");
43 #endif
44 }
45
wm_sdh_send_cmd(uint8_t cmdnum,uint32_t cmdarg,uint8_t mmcio)46 void wm_sdh_send_cmd(uint8_t cmdnum, uint32_t cmdarg, uint8_t mmcio)
47 {
48 SDIO_HOST->CMD_BUF[4] = cmdnum | 0x40;
49 SDIO_HOST->CMD_BUF[3] = (cmdarg >> 24) & 0xFF; // 24:byte alignment
50 SDIO_HOST->CMD_BUF[2] = (cmdarg >> 16) & 0xFF; // 16:byte alignment
51 SDIO_HOST->CMD_BUF[1] = (cmdarg >> 8) & 0xFF; // 8:byte alignment
52 SDIO_HOST->CMD_BUF[0] = (cmdarg & 0xFF);
53 SDIO_HOST->MMC_INT_SRC |= 0x7ff; // clear all firstly
54 SDIO_HOST->MMC_IO = mmcio;
55 }
56
wm_sdh_get_response(uint32_t * respbuf,uint32_t buflen)57 void wm_sdh_get_response(uint32_t * respbuf, uint32_t buflen)
58 {
59 int i = 0;
60 for (i = 0; i < buflen; i++) {
61 respbuf[i] = (SDIO_HOST->CMD_BUF[i * 4 + 3] << 24) | // 4:byte alignment, 3:byte alignment, 24:byte alignment
62 (SDIO_HOST->CMD_BUF[i * 4 + 2] << 16) | // 4:byte alignment, 2:byte alignment, 16:byte alignment
63 (SDIO_HOST->CMD_BUF[i * 4 + 1] << 8) | // 4:byte alignment, 8:byte alignment
64 (SDIO_HOST->CMD_BUF[i * 4]); // 4:byte alignment
65 }
66 }
67
sm_sdh_wait_interrupt(uint8_t srcbit,int timeout)68 static int sm_sdh_wait_interrupt(uint8_t srcbit, int timeout)
69 {
70 int ret = 0;
71 unsigned int tmp = (1 << srcbit);
72 volatile int vtimeout = timeout;
73
74 if (vtimeout == -1) {
75 vtimeout = 0x7FFFF;
76 }
77
78 while (1) {
79 if (SDIO_HOST->MMC_INT_SRC & tmp) {
80 SDIO_HOST->MMC_INT_SRC |= tmp;
81 if (SDIO_HOST->MMC_INT_SRC) {
82 TEST_DEBUG("Err Int 0x%x\n", SDIO_HOST->MMC_INT_SRC);
83 }
84 break;
85 }
86 vtimeout--;
87 if ((vtimeout == 0) || (vtimeout < 0)) {
88 ret = 1; // timeout, err
89 break;
90 }
91 delay_cnt(1);
92 }
93 return ret;
94 }
95
wm_sdh_config(void)96 int wm_sdh_config(void)
97 {
98 tls_sys_clk sysclk;
99
100 tls_sys_clk_get(&sysclk);
101 SDIO_HOST->MMC_CARDSEL = 0xC0 | (sysclk.cpuclk / 2 - 1); // 0xd3; // enable module, enable mmcclk
102 SDIO_HOST->MMC_CTL = 0xD3; // 0xC3; // 4bits, low speed, 1/4 divider, auto transfer, mmc mode.
103 SDIO_HOST->MMC_INT_MASK = 0x100; // unmask sdio data interrupt.
104 SDIO_HOST->MMC_CRCCTL = 0xC0;
105 SDIO_HOST->MMC_TIMEOUTCNT = 0xff;
106 return 0;
107 }
108
wm_sd_card_initialize(uint32_t * rca)109 int wm_sd_card_initialize(uint32_t *rca)
110 {
111 int ret = -1;
112 uint32_t respCmd[4];
113 int recnt = 5; // 5:byte alignment
114
115 wm_sdh_config();
116 // ======================================================
117 // set up
118 // Test: Init sequence, With response check
119 // CMD 0 Reset Card
120 // CMD 8 Get voltage (Only 2.0 Card response to this)
121 // CMD55 Indicate Next Command are Application specific
122 // ACMD41 Get Voltage windows
123 // CMD 2 CID reg
124 // CMD 3 Get RCA.
125 // ======================================================
126 begin:
127 wm_sdh_send_cmd(0, 0, 0x04); // Send CMD0
128 sm_sdh_wait_interrupt(0, -1);
129 delay_cnt(1000); // 1000:time
130 wm_sdh_send_cmd(8, 0x1AA, 0x44); // 8:Send CMD8
131 sm_sdh_wait_interrupt(0, -1);
132 wm_sdh_get_response(respCmd, 2); // 2:bufLen
133 sh_dumpBuffer("CMD8 respCmd", (char *)respCmd, 5); // 5:len
134 if (respCmd[0] != 0x1AA || (respCmd[1] & 0xFF) != 8) { // 8:byte alignment
135 TEST_DEBUG("CMD8 Error\n");
136 if (recnt--) {
137 goto begin;
138 }
139 goto end;
140 }
141 while (1) {
142 wm_sdh_send_cmd(55, 0, 0x44); // Send CMD55
143 sm_sdh_wait_interrupt(0, -1);
144 wm_sdh_get_response(respCmd, 2); // 2:bufLen
145 sh_dumpBuffer("CMD55 respCmd", (char *)respCmd, 5); // 5:len
146 if ((respCmd[1] & 0xFF) != 55) // 55:byte alignment
147 goto end;
148
149 wm_sdh_send_cmd(41, 0xC0100000, 0x44); // 41:Send ACMD41
150 sm_sdh_wait_interrupt(0, -1);
151 sm_sdh_wait_interrupt(3, 1000); // 3:srcbit, 1000:time
152 wm_sdh_get_response(respCmd, 2); // 2:buflen
153 sh_dumpBuffer("ACMD41 respCmd", (char *)respCmd, 5); // 5:len
154 if ((respCmd[1] & 0xFF) != 0x3F)
155 goto end;
156 if ((respCmd[0] >> 31) & 0x1) { // 31:byte alignment
157 TEST_DEBUG("card is ready\n");
158 break;
159 }
160 }
161
162 wm_sdh_send_cmd(2, 0, 0x54); // 2:Send CMD2
163 sm_sdh_wait_interrupt(0, -1);
164 sm_sdh_wait_interrupt(3, 1000); // 3:srcbit, 1000:time
165 wm_sdh_get_response(respCmd, 4); // 4:buflen
166 sh_dumpBuffer("CMD2 respCmd", (char *)respCmd, 16); // 16:len
167 if (((respCmd[3] >> 24) & 0xFF) != 0x3F) // 24:byte alignment, 3:byte alignment
168 goto end;
169 wm_sdh_send_cmd(3, 0, 0x44); // 3:Send CMD3
170 sm_sdh_wait_interrupt(0, -1);
171 wm_sdh_get_response(respCmd, 2); // 2:buflen
172 sh_dumpBuffer("CMD3 respCmd", (char *)respCmd, 5); // 5:len
173 if ((respCmd[1] & 0xFF) != 3) // 3:byte alignment
174 goto end;
175 *rca = respCmd[0] >> 16; // 16:byte alignment
176 TEST_DEBUG("RCA = %x\n", *rca);
177
178 ret = 0;
179 end:
180 return ret;
181 }
182
SD_GetCapacity(uint8_t * csd,SD_CardInfo_t * SDCardInfo)183 static uint32_t SD_GetCapacity(uint8_t *csd, SD_CardInfo_t *SDCardInfo)
184 {
185 uint32_t Capacity;
186 uint32_t csize;
187
188 if ((csd[0]&0xC0)==0x40) {
189 csize = csd[9] + ((uint32_t)csd[8] << 8) + // 8:byte alignment
190 ((uint32_t)(csd[7] & 63) << 16) + 1; // 16:byte alignment, 63:byte alignment
191 Capacity = csize << 9; // 9:byte alignment
192 SDCardInfo->CardCapacity = (long long)Capacity * 1024; // 1024:byte alignment
193 SDCardInfo->CardBlockSize = 512; // 512:byte alignment
194 } else {
195 uint16_t n = (csd[5] & 0x0F) + ((csd[10] & 0x80) >> 7) + // 7:byte alignment
196 ((csd[9] & 0x03) << 1) + 2; // 2:byte alignment
197 csize = (csd[8] >> 6) + ((uint16_t)csd[7] << 2) + // 6:byte alignment, 2:byte alignment
198 ((uint16_t)(csd[6] & 0x03) << 10) + 1; // 10:byte alignment
199 Capacity = (uint32_t)csize << (n - 10); // 10:byte alignment
200 SDCardInfo->CardCapacity = (long long)Capacity * 1024; // 1024:byte alignment
201 SDCardInfo->CardBlockSize = 1 << (csd[5] & 0x0F);
202 }
203 return Capacity;
204 }
205
wm_sd_card_query_csd(uint32_t rca)206 int wm_sd_card_query_csd(uint32_t rca)
207 {
208 int ret = -1, i;
209 uint32_t respCmd[4];
210 char adjustResp[16];
211
212 wm_sdh_send_cmd(9, rca<<16, 0x54); // 9:Send CMD9
213 sm_sdh_wait_interrupt(0, -1);
214 sm_sdh_wait_interrupt(3, 1000); // 3:srcbit, 1000:time
215 wm_sdh_get_response(respCmd, 4); // 4:buflen
216 for (i = 0; i < 16; i++) adjustResp[15 - i] = SDIO_HOST->CMD_BUF[i]; // 16:byte alignment, 15:byte alignment
217 SD_GetCapacity((uint8_t*)&adjustResp[1], &SDCardInfo);
218 sh_dumpBuffer("CMD9 respCmd", adjustResp, 16); // 16:len
219 if (((respCmd[3] >> 24) & 0xFF) != 0x3F) // 24:byte alignment, 3:array element
220 goto end;
221 ret = 0;
222 end:
223 return ret;
224 }
225
wm_sd_card_set_blocklen(uint32_t blocklen)226 int wm_sd_card_set_blocklen(uint32_t blocklen)
227 {
228 int ret = -1;
229 uint32_t respCmd[2];
230 wm_sdh_send_cmd(16, blocklen, 0x44); // 16:Send CMD16
231 sm_sdh_wait_interrupt(0, -1);
232 wm_sdh_get_response(respCmd, 2); // 2:buflen
233 sh_dumpBuffer("CMD16 respCmd", (char *)respCmd, 5); // 5:len
234 if ((respCmd[1] & 0xFF) != 16) // 16:byte alignment
235 goto end;
236 ret = 0;
237 end:
238 return ret;
239 }
240
wm_sd_card_select(uint32_t rca)241 int wm_sd_card_select(uint32_t rca)
242 {
243 int ret = -1;
244 uint32_t respCmd[2];
245 wm_sdh_send_cmd(7, rca << 16, 0x44); // 7:Send CMD7, 16:byte alignment
246 sm_sdh_wait_interrupt(0, -1);
247 wm_sdh_get_response(respCmd, 2); // 2:buflen
248 sh_dumpBuffer("CMD7 respCmd", (char *)respCmd, 5); // 5:len
249 if ((respCmd[1] & 0xFF) != 7) // 7:byte alignment
250 goto end;
251 ret = 0;
252 end:
253 return ret;
254 }
255
wm_sd_card_deselect(void)256 void wm_sd_card_deselect(void)
257 {
258 wm_sdh_send_cmd(7, 0, 0x04); // 7:Send CMD7
259 sm_sdh_wait_interrupt(0, -1);
260 }
261
wm_sd_card_query_status(uint32_t rca,uint32_t * respCmd0)262 int wm_sd_card_query_status(uint32_t rca, uint32_t *respCmd0)
263 {
264 int ret = -1;
265 #if TEST_DEBUG_EN
266 uint8_t current_state = 0;
267 uint8_t error_state = 0;
268 #endif
269 uint32_t respCmd[2];
270 wm_sdh_send_cmd(13, rca << 16, 0x44); // 13:Send CMD13, 16:byte alignment
271 sm_sdh_wait_interrupt(0, -1);
272 wm_sdh_get_response(respCmd, 2); // 2:buflen
273 sh_dumpBuffer("CMD13 respCmd", (char *)respCmd, 5); // 5:len
274 if ((respCmd[1] & 0xFF) != 13) { // 13:byte alignment
275 goto end;
276 }
277 if (respCmd0) {
278 *respCmd0 = respCmd[0];
279 }
280 #if TEST_DEBUG_EN
281 (current_state = respCmd[0] >> 9) & 0xF; // 9:byte alignment
282 (error_state = respCmd[0] >> 19) & 0x1; // 19:byte alignment
283 TEST_DEBUG("current_state %d, error_state %d\n", current_state, error_state);
284 #endif
285 ret = 0;
286 end:
287 return ret;
288 }
289
290 /*
291 * speed_mode: 0: low speed; 1: high speed;
292 * */
wm_sd_card_switch_func(uint8_t speed_mode)293 int wm_sd_card_switch_func(uint8_t speed_mode)
294 {
295 int ret = -1;
296 int i;
297 uint32_t respCmd[2];
298
299 wm_sdh_send_cmd(6, 0x00fffff1, 0x44); // 6:Send CMD6
300 sm_sdh_wait_interrupt(0, -1);
301 wm_sdh_get_response(respCmd, 2); // 2:buflen
302 sh_dumpBuffer("CMD6 respCmd", (char *)respCmd, 5); // 5:len
303 if ((respCmd[1] & 0xFF) != 6) // 6:byte alignment
304 goto end;
305 SDIO_HOST->BUF_CTL = 0x4020; // disable dma, read sd card
306 SDIO_HOST->MMC_INT_SRC |= 0x7ff; // clear all firstly
307 SDIO_HOST->MMC_IO = 0x3; // !!!read data, auto transfer
308 sm_sdh_wait_interrupt(1, -1);
309 TEST_DEBUG("read complete\n");
310 for (i = 0; i < 128; i++) { // 128:byte alignment
311 respCmd[0] = SDIO_HOST->DATA_BUF[0];
312 if (i == 4) { // 4:byte alignment
313 respCmd[1] = respCmd[0];
314 }
315 printf("0x%x, ", respCmd[0]);
316 if (i % 4 == 3) { // 4:byte alignment, 3:byte alignment
317 printf("\n");
318 }
319 }
320 TEST_DEBUG("the value of byte 17~20 is 0x%x\n", respCmd[1]);
321 if (respCmd[1] & 0xF) { // support high speed
322 wm_sdh_send_cmd(6, 0x80fffff0 | speed_mode, 0x44); // Send CMD6
323 sm_sdh_wait_interrupt(0, -1);
324 wm_sdh_get_response(respCmd, 2); // 2:buflen
325 sh_dumpBuffer("CMD6 respCmd", (char *)respCmd, 5); // 5:len
326 if ((respCmd[1] & 0xFF) != 6) // 6:byte alignment
327 goto end;
328 SDIO_HOST->BUF_CTL = 0x4020; // disable dma, read sd card
329 SDIO_HOST->MMC_INT_SRC |= 0x7ff; // clear all firstly
330 SDIO_HOST->MMC_IO = 0x3; // !!!read data, auto transfer
331 sm_sdh_wait_interrupt(1, -1);
332 TEST_DEBUG("read complete\n");
333 for (i = 0; i < 128; i++) { // 128:byte alignment
334 respCmd[0] = SDIO_HOST->DATA_BUF[0];
335 if (i == 4) { // 4:byte alignment
336 respCmd[1] = respCmd[0];
337 }
338 printf("0x%x, ", respCmd[0]);
339 if (i % 4 == 3) { // 4:byte alignment, 3:byte alignment
340 printf("\n");
341 }
342 }
343 TEST_DEBUG("the value of byte 17~20 is 0x%x\n", respCmd[1]);
344 if ((respCmd[1] & 0xF) == speed_mode) {
345 if (speed_mode == 1) {
346 SDIO_HOST->MMC_CTL |= (1 << 6); // 6:byte alignment
347 } else {
348 SDIO_HOST->MMC_CTL &= ~(1 << 6); // 6:byte alignment
349 }
350 TEST_DEBUG("switch speed_mode %d success\n", speed_mode);
351 }
352 }
353 ret = 0;
354 end:
355 return ret;
356 }
357
358 /*
359 * bus_width: 0:1bit; 2:4bits
360 * */
wm_sd_card_set_bus_width(uint32_t rca,uint8_t bus_width)361 int wm_sd_card_set_bus_width(uint32_t rca, uint8_t bus_width)
362 {
363 int ret = -1;
364 uint32_t respCmd[2];
365 if (bus_width != 0 && bus_width != 2) { // 2:byte alignment
366 TEST_DEBUG("bus width parameter error\n");
367 goto end;
368 }
369 if (bus_width == 2) { // 2:byte alignment
370 SDIO_HOST->MMC_CTL |= (1 << 7); // 7:byte alignment
371 } else {
372 SDIO_HOST->MMC_CTL &= ~(1 << 7); // 7:byte alignment
373 }
374 wm_sdh_send_cmd(55, rca << 16, 0x44); // 55:Send CMD55, 16:byte alignment
375 sm_sdh_wait_interrupt(0, -1);
376 wm_sdh_get_response(respCmd, 2); // 2:buflen
377 sh_dumpBuffer("CMD55 respCmd", (char *)respCmd, 5); // 5:len
378 if ((respCmd[1] & 0xFF) != 55) // 55:byte alignment
379 goto end;
380 wm_sdh_send_cmd(6, bus_width, 0x44); // 6:Send ACMD6
381 sm_sdh_wait_interrupt(0, -1);
382 wm_sdh_get_response(respCmd, 2); // 2:buflen
383 sh_dumpBuffer("ACMD6 respCmd", (char *)respCmd, 5); // 5:len
384 if ((respCmd[1] & 0xFF) != 6) // 6:byte alignment
385 goto end;
386 ret = 0;
387 end:
388 return ret;
389 }
390
wm_sd_card_stop_trans(void)391 int wm_sd_card_stop_trans(void)
392 {
393 int ret;
394 uint32_t respCmd[2];
395 wm_sdh_send_cmd(12, 0, 0x44); // 12:Send CMD12
396 ret = sm_sdh_wait_interrupt(0, -1);
397 if (ret) {
398 goto end;
399 }
400 wm_sdh_get_response(respCmd, 2); // 2:buflen
401 sh_dumpBuffer("CMD12 respCmd", (char *)respCmd, 5); // 5:len
402 if ((respCmd[1] & 0xFF) != 12) { // 12:byte alignment
403 goto end;
404 }
405 ret = 0;
406 end:
407 return ret;
408 }
409
sdio_host_reset(void)410 static void sdio_host_reset(void)
411 {
412 tls_bitband_write(HR_CLK_RST_CTL, 27, 0); // 27:value of bit
413
414 tls_bitband_write(HR_CLK_RST_CTL, 27, 1); // 27:value of bit
415 while (tls_bitband_read(HR_CLK_RST_CTL, 27) == 0); // 27:value of bit
416 }
417
sdh_card_init(uint32_t * rca_ref)418 int sdh_card_init(uint32_t *rca_ref)
419 {
420 int ret;
421 uint32_t rca = 0;
422
423 sdio_host_reset();
424
425 ret = wm_sd_card_initialize(&rca);
426 if (ret) {
427 goto end;
428 }
429 ret = wm_sd_card_query_csd(rca);
430 if (ret) {
431 goto end;
432 }
433 ret = wm_sd_card_query_status(rca, NULL);
434 if (ret) {
435 goto end;
436 }
437 ret = wm_sd_card_select(rca);
438 if (ret) {
439 goto end;
440 }
441 ret = wm_sd_card_query_status(rca, NULL);
442 if (ret) {
443 goto end;
444 }
445 *rca_ref = rca;
446 ret = 0;
447 end:
448 TEST_DEBUG("ret %d\n", ret);
449 return ret;
450 }
451
452 /* buf's len must >= 512 */
wm_sd_card_block_read(uint32_t rca,uint32_t sd_addr,char * buf)453 int wm_sd_card_block_read(uint32_t rca, uint32_t sd_addr, char *buf)
454 {
455 int ret = -1;
456 int i;
457 uint32_t respCmd[2];
458 wm_sdh_send_cmd(17, sd_addr, 0x44); // 17:Send CMD17
459 sm_sdh_wait_interrupt(0, -1);
460 wm_sdh_get_response(respCmd, 2); // 2:byte alignment
461 sh_dumpBuffer("CMD17 respCmd", (char *)respCmd, 5); // 5:buflen
462 if ((respCmd[1] & 0xFF) != 17) // 17:byte alignment
463 goto end;
464 SDIO_HOST->BUF_CTL = 0x4020; // disable dma, read sd card
465 SDIO_HOST->MMC_INT_SRC |= 0x7ff; // clear all firstly
466 SDIO_HOST->MMC_IO = 0x3; // !!!read data, auto transfer
467 sm_sdh_wait_interrupt(1, -1);
468 TEST_DEBUG("read complete\n");
469 for (i = 0; i < 128; i++) { // 128:byte alignment
470 *((uint32_t*)(buf + 4 * i)) = SDIO_HOST->DATA_BUF[0]; // 4:byte alignment
471 }
472 ret = 0;
473 end:
474 return ret;
475 }
476
477 /* buf's len must be 512 */
wm_sd_card_block_write(uint32_t rca,uint32_t sd_addr,char * buf)478 int wm_sd_card_block_write(uint32_t rca, uint32_t sd_addr, char *buf)
479 {
480 int i;
481 int ret = -1;
482 uint32_t respCmd[2];
483 uint8_t current_state = 0;
484 uint8_t error_state = 0;
485
486 wm_sdh_send_cmd(24, sd_addr, 0x44); // 24:Send CMD24
487 sm_sdh_wait_interrupt(0, -1);
488 wm_sdh_get_response(respCmd, 2); // 2:buflen
489 sh_dumpBuffer("CMD24 respCmd", (char *)respCmd, 5); // 5:len
490 if ((respCmd[1] & 0xFF) != 24) // 24:byte alignment
491 goto end;
492
493 SDIO_HOST->BUF_CTL = 0x4820; // disable dma, write sd card
494 for (i = 0; i < 128; i++) { // 128:byte alignment
495 SDIO_HOST->DATA_BUF[i] = *((uint32*)(buf + 4 * i)); // 4:byte alignment
496 }
497 SDIO_HOST->MMC_BYTECNTL = 512; // 512:byte alignment
498 SDIO_HOST->MMC_INT_SRC |= 0x7ff; // clear all firstly
499 SDIO_HOST->MMC_IO = 0x1; // !!!write data, auto transfer
500 sm_sdh_wait_interrupt(1, -1);
501
502 while (true) {
503 ret = wm_sd_card_query_status(rca, &respCmd[0]);
504 if (ret)
505 goto end;
506 (current_state = respCmd[0] >> 9) & 0xF; // 9:byte alignment
507 (error_state = respCmd[0] >> 19) & 0x1; // 19:byte alignment
508 if (current_state == 4) { // 4:tran
509 break;
510 }
511 if (error_state) {
512 ret = -1;
513 goto end;
514 }
515 }
516
517 ret = 0;
518 end:
519 TEST_DEBUG("write complete err %d\n", ret);
520 return ret;
521 }
522
523 /* dir: 1, write; 0, read */
wm_sd_card_dma_config(u32 * mbuf,u32 bufsize,u8 dir)524 int wm_sd_card_dma_config(u32 *mbuf, u32 bufsize, u8 dir)
525 {
526 int ch;
527 u32 addr_inc = 0;
528
529 ch = tls_dma_request(0, NULL);
530 DMA_CHNLCTRL_REG(ch) = DMA_CHNL_CTRL_CHNL_OFF;
531
532 if (dir) {
533 DMA_SRCADDR_REG(ch) = (unsigned int)mbuf;
534 DMA_DESTADDR_REG(ch) = (unsigned int)SDIO_HOST->DATA_BUF;
535 addr_inc = (1 << 1);
536 } else {
537 DMA_SRCADDR_REG(ch) = (unsigned int)SDIO_HOST->DATA_BUF;
538 DMA_DESTADDR_REG(ch) = (unsigned int)mbuf;
539 addr_inc = (1 << 3); // 3:byte alignment
540 }
541 DMA_CTRL_REG(ch) = addr_inc | (2 << 5) | (bufsize << 8); // 2:byte alignment, 5:byte alignment, 8:byte alignment
542 DMA_MODE_REG(ch) = DMA_MODE_SEL_SDIOHOST | DMA_MODE_HARD_MODE;
543 DMA_CHNLCTRL_REG(ch) = DMA_CHNL_CTRL_CHNL_ON;
544
545 return ch;
546 }
547
wm_sdh_wait_blocks_done(void)548 static int wm_sdh_wait_blocks_done(void)
549 {
550 int ret = 0;
551 uint32_t timeout = 0x7FFFF * 8; // 8:byte alignment
552
553 while (1) {
554 if ((SDIO_HOST->MMC_IO_MBCTL & 0x01) == 0x00) {
555 break;
556 }
557
558 if (timeout == 0) {
559 ret = -1;
560 tls_os_time_delay(HZ);
561 } else {
562 delay_cnt(1);
563 timeout--;
564 }
565 }
566
567 return ret;
568 }
569
570 /* read blocks by dma
571 * buflen must be integer multiple of 512
572 * */
wm_sd_card_blocks_read(uint32_t rca,uint32_t sd_addr,char * buf,uint32_t buflen)573 int wm_sd_card_blocks_read(uint32_t rca, uint32_t sd_addr, char *buf, uint32_t buflen)
574 {
575 int ret = -1, dma_channel = 0xFF, retresp = -100; // -100:byte alignment
576 uint32_t respCmd[2];
577 int block_cnt = buflen / 512; // 512:byte alignment
578 uint8_t current_state = 0;
579 uint8_t error_state = 0;
580
581 wm_sdh_send_cmd(18, sd_addr, 0x44); // 18:Send CMD18
582 sm_sdh_wait_interrupt(0, -1);
583 wm_sdh_get_response(respCmd, 2); // 2:buflen
584 sh_dumpBuffer("CMD18 respCmd", (char *)respCmd, 5); // 5:len
585 if ((respCmd[1] & 0xFF) != 18) // 18:byte alignment
586 goto end;
587
588 SDIO_HOST->BUF_CTL = 0x4000; // disable dma,
589 dma_channel = wm_sd_card_dma_config((u32*)buf, 512*block_cnt, 0);
590 SDIO_HOST->BUF_CTL = 0x404; // enable dma, read sd card
591 SDIO_HOST->MMC_BLOCKCNT = block_cnt;
592 SDIO_HOST->MMC_INT_SRC |= 0x7ff; // clear all firstly
593 SDIO_HOST->MMC_IO_MBCTL = 0xa3; // read data, enable multi blocks data transfer
594 ret = wm_sdh_wait_blocks_done();
595 if (ret) {
596 TEST_DEBUG("wm_sd_card_blocks_read: timeout error\n");
597 goto end;
598 }
599 TEST_DEBUG("read complete\n");
600 ret = wm_sd_card_stop_trans();
601 if (ret) {
602 goto end;
603 }
604
605 /* waiting for card to trans state */
606 do {
607 ret = wm_sd_card_query_status(rca, &respCmd[0]);
608 if (ret)
609 break;
610 (current_state = respCmd[0] >> 9) & 0xF; // 9:byte alignment
611 (error_state = respCmd[0] >> 19) & 0x1; // 19:byte alignment
612 if (error_state) {
613 ret = -1;
614 break;
615 }
616 } while (current_state != 4); // 4:byte alignment
617 if (ret) {
618 TEST_DEBUG("mr blocks:%x\r\n", error_state);
619 goto end;
620 }
621 ret = 0;
622 end:
623 if (ret) {
624 wm_sd_card_stop_trans();
625 do {
626 retresp = wm_sd_card_query_status(rca, &respCmd[0]);
627 if (retresp)
628 break;
629 (current_state = respCmd[0] >> 9) & 0xF; // 9:byte alignment
630 (error_state = respCmd[0] >> 19) & 0x1; // 19:byte alignment
631 if (error_state) {
632 ret = -1;
633 break;
634 }
635 } while (current_state != 4); // 4:byte alignment
636 }
637 tls_dma_free(dma_channel);
638
639 return ret;
640 }
641
642 /* write blocks by dma
643 * buflen must be integer multiple of 512
644 * */
wm_sd_card_blocks_write(uint32_t rca,uint32_t sd_addr,char * buf,uint32_t buflen)645 int wm_sd_card_blocks_write(uint32_t rca, uint32_t sd_addr, char *buf, uint32_t buflen)
646 {
647 int dma_channel = 0xFF;
648 int ret, retresp = -100; // -100:byte alignment
649 uint32_t respCmd[2];
650 int block_cnt = buflen / 512; // 512:byte alignment
651 uint8_t current_state = 0;
652 uint8_t error_state = 0;
653
654 wm_sdh_send_cmd(25, sd_addr, 0x44); // 25:Send CMD25
655 ret = sm_sdh_wait_interrupt(0, -1);
656 if (ret) {
657 goto end;
658 }
659 wm_sdh_get_response(respCmd, 2); // 2:buflen
660 sh_dumpBuffer("CMD25 respCmd", (char *)respCmd, 5); // 5:len
661 if ((respCmd[1] & 0xFF) != 25) { // 25:byte alignment
662 ret = -1;
663 goto end;
664 }
665
666 SDIO_HOST->BUF_CTL = 0x4000; // disable dma,
667 dma_channel = wm_sd_card_dma_config((u32*)buf, 512 * block_cnt, 1);
668 SDIO_HOST->BUF_CTL = 0xC20; // enable dma, write sd card
669 SDIO_HOST->MMC_BLOCKCNT = block_cnt;
670 SDIO_HOST->MMC_INT_SRC |= 0x7ff; // clear all firstly
671 SDIO_HOST->MMC_IO_MBCTL = 0xa1; // write data, enable multi blocks data transfer
672 ret = wm_sdh_wait_blocks_done();
673 if (ret) {
674 goto end;
675 }
676 ret = wm_sd_card_stop_trans();
677 if (ret) {
678 goto end;
679 }
680 /* waiting for card to trans state */
681 do {
682 ret = wm_sd_card_query_status(rca, &respCmd[0]);
683 if (ret)
684 break;
685 (current_state = respCmd[0] >> 9) & 0xF; // 9:byte alignment
686 (error_state = respCmd[0] >> 19) & 0x1; // 19:byte alignment
687 if (error_state) {
688 ret = -1;
689 break;
690 }
691 } while (current_state != 4); // 4:byte alignment
692 if (ret) {
693 TEST_DEBUG("mw blocks:%x\r\n", error_state);
694 goto end;
695 }
696 TEST_DEBUG("write complete\n");
697 ret = 0;
698 end:
699 if (ret) {
700 wm_sd_card_stop_trans();
701 do {
702 retresp = wm_sd_card_query_status(rca, &respCmd[0]);
703 if (retresp)
704 break;
705 (current_state = respCmd[0] >> 9) & 0xF; // 9:byte alignment
706 (error_state = respCmd[0] >> 19) & 0x1; // 19:byte alignment
707 if (error_state) {
708 ret = -1;
709 break;
710 }
711 } while (current_state != 4); // 4:byte alignment
712 }
713
714 tls_dma_free(dma_channel);
715
716 return ret;
717 }