• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }