blob: 6a7fbf95cf3a5202728e2b11ecfb1f6c57d5e21e [file] [log] [blame]
Angel Pons8a3453f2020-04-02 23:48:19 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Xiang Wangb1349452019-08-27 15:57:23 +08002#include <stdint.h>
3#include <string.h>
4#include <spi-generic.h>
5#include <spi_sdcard.h>
6#include <crc_byte.h>
7#include <commonlib/helpers.h>
8#include <console/console.h>
9
Arthur Heymanse19d33b2023-05-19 12:16:07 +020010#define SPI_SDCARD_DEBUG 0
Xiang Wangb1349452019-08-27 15:57:23 +080011
Xiang Wangb1349452019-08-27 15:57:23 +080012#define dprintk(fmt, args...) \
Arthur Heymanse19d33b2023-05-19 12:16:07 +020013 do { if (SPI_SDCARD_DEBUG) { printk(BIOS_DEBUG, fmt, ##args); }} while (0)
Xiang Wangb1349452019-08-27 15:57:23 +080014
15#define SDCARD_TYPE_SDSC 1
16#define SDCARD_TYPE_SDHC 2
17#define SDCARD_TYPE_SDXC 3
18
19/* CMD */
20#define GO_IDLE_STATE 0
21#define SEND_OP_COND 1
22#define SWITCH_FUNC 6
23#define SEND_IF_COND 8
24#define SEND_CSD 9
25#define SEND_CID 10
26#define STOP_TRANSMISSION 12
27#define SEND_STATUS 13
28#define SET_BLOCKLEN 16
29#define READ_SINGLE_BLOCK 17
30#define READ_MULTIPLEBLOCK 18
31#define WRITE_BLOCK 24
32#define WRITE_MULTIPLEBLOCK 25
33#define PROGRAM_CSD 27
34#define SET_WRITE_PROT 28
35#define CLR_WRITE_PROT 29
36#define SEND_WRITE_PROT 30
37#define ERASE_WR_BLK_START_ADDR 32
38#define ERASE_WR_BLK_END_ADDR 33
39#define ERASE 38
40#define LOCK_UNLOCK 42
41#define APP_CMD 55
42#define GEN_CMD 56
43#define READ_OCR 58
44#define CRC_ON_OFF 59
45
46/* ACMD */
47#define SD_STATUS 13
48#define SEND_NUM_WR_BLOCKS 22
49#define SET_WR_BLK_ERASE_COUNT 23
50#define SD_SEND_OP_COND 41
51#define SET_CLR_CARD_DETECT 42
52#define SEND_SCR 51
53
54/* control tokens */
55#define CT_BLOCK_START 0xfe
56#define CT_MULTIPLE_BLOCK_START 0xfc
57#define CT_MULTIPLE_BLOCK_STOP 0xfd
58#define CT_RESPONSE_MASK 0x1f
59#define CT_RESPONSE_ACCEPTED 0x05
60#define CT_RESPONSE_REJECTED_CRC 0x0b
61#define CT_RESPONSE_REJECTED_WRITE_ERR 0x0d
62
63/* response type */
64#define RSP_R1 0
65#define RSP_R1b 1
66#define RSP_R2 2
67#define RSP_R3 3
68#define RSP_R4 4
69#define RSP_R5 5
70#define RSP_R7 7
71
72#define RSP_ERR_CARD_IS_LOCKED (1 << 0)
73#define RSP_ERR_WP_ERASE_SKIP (1 << 1)
74#define RSP_ERR_GENERAL (1 << 2)
75#define RSP_ERR_CC (1 << 3)
76#define RSP_ERR_ECC (1 << 4)
77#define RSP_ERR_WP_VIOLATION (1 << 5)
78#define RSP_ERR_ERASE_PARAM (1 << 6)
79#define RSP_ERR_OUT_OF_RANGE (1 << 7)
80#define RSP_ERR_IN_IDLE (1 << 8)
81#define RSP_ERR_ERASE_RESET (1 << 9)
82#define RSP_ERR_ILLEGAL_COMMAND (1 << 10)
83#define RSP_ERR_COM_CRC (1 << 11)
84#define RSP_ERR_ERASE_SEQUENCE (1 << 12)
85#define RSP_ERR_ADDRESS (1 << 13)
86#define RSP_ERR_PARAMETER (1 << 14)
87
88#define BLOCK_SIZE 512
89
90static unsigned long long extract_bits(uint8_t *buff,
91 int width, int start, int end)
92{
93 unsigned long long r = 0;
94 for (int i = end; i >= start; i--) {
95 int bitpos = width - i - 1;
96 int b = bitpos / 8;
97 int shift = 7 - bitpos % 8;
98 r = (r << 1) | ((buff[b] >> shift) & 1);
99 }
100 return r;
101}
102
103static void spi_sdcard_enable_cs(const struct spi_sdcard *card)
104{
105 spi_claim_bus(&card->slave);
106}
107
108static void spi_sdcard_disable_cs(const struct spi_sdcard *card)
109{
110 spi_release_bus(&card->slave);
111}
112
113static void spi_sdcard_sendbyte(const struct spi_sdcard *card, uint8_t b)
114{
115 dprintk("sdcard -> %#x\n", b);
116 spi_xfer(&card->slave, &b, 1, NULL, 0);
117}
118
119static uint8_t spi_sdcard_recvbyte(const struct spi_sdcard *card)
120{
121 uint8_t b, t = 0xff;
122 spi_xfer(&card->slave, &t, 1, &b, 1);
123 dprintk("sdcard <- %#x\n", b);
124 return b;
125}
126
127static uint8_t spi_sdcard_calculate_command_crc(uint8_t cmd, uint32_t argument)
128{
129 uint8_t crc = 0;
130 crc = crc7_byte(crc, (cmd | 0x40) & 0x7f);
131 crc = crc7_byte(crc, (argument >> (3 * 8)) & 0xff);
132 crc = crc7_byte(crc, (argument >> (2 * 8)) & 0xff);
133 crc = crc7_byte(crc, (argument >> (1 * 8)) & 0xff);
134 crc = crc7_byte(crc, (argument >> (0 * 8)) & 0xff);
135 return crc | 1;
136}
137
138static int lookup_cmd_response_type(uint8_t cmd)
139{
140 switch (cmd) {
141 case GO_IDLE_STATE:
142 case SEND_OP_COND:
143 case SWITCH_FUNC:
144 case SEND_CSD:
145 case SEND_CID:
146 case SET_BLOCKLEN:
147 case READ_SINGLE_BLOCK:
148 case READ_MULTIPLEBLOCK:
149 case WRITE_BLOCK:
150 case WRITE_MULTIPLEBLOCK:
151 case PROGRAM_CSD:
152 case SEND_WRITE_PROT:
153 case ERASE_WR_BLK_START_ADDR:
154 case ERASE_WR_BLK_END_ADDR:
155 case LOCK_UNLOCK:
156 case APP_CMD:
157 case GEN_CMD:
158 case CRC_ON_OFF:
159 return RSP_R1;
160 case STOP_TRANSMISSION:
161 case SET_WRITE_PROT:
162 case CLR_WRITE_PROT:
163 case ERASE:
164 return RSP_R1b;
165 case SEND_STATUS:
166 return RSP_R2;
167 case READ_OCR:
168 return RSP_R3;
169 case SEND_IF_COND:
170 return RSP_R7;
171 }
172 return -1;
173}
174
175static int lookup_acmd_response_type(uint8_t cmd)
176{
177 switch (cmd) {
178 case SEND_NUM_WR_BLOCKS:
179 case SET_WR_BLK_ERASE_COUNT:
180 case SD_SEND_OP_COND:
181 case SET_CLR_CARD_DETECT:
182 case SEND_SCR:
183 return RSP_R1;
184 case SD_STATUS:
185 return RSP_R2;
186 }
187 return -1;
188}
189
190static int lookup_response_length(int response_type)
191{
192 switch (response_type) {
193 case RSP_R1:
194 case RSP_R1b:
195 return 1;
196 case RSP_R2:
197 return 2;
198 case RSP_R3:
199 case RSP_R7:
200 return 5;
201 }
202 return -1;
203}
204
205static int response_resolve(int response_type, uint8_t *response,
206 uint32_t *out_register)
207{
Bill XIEac1362502022-07-08 16:53:21 +0800208 __maybe_unused static const char * const sd_err[] = {
Xiang Wangb1349452019-08-27 15:57:23 +0800209 "Card is locked",
Martin Roth3e25f852023-09-04 15:37:07 -0600210 "wp erase skip | lock/unlock cmd failed",
Xiang Wangb1349452019-08-27 15:57:23 +0800211 "error",
212 "CC error",
213 "card err failed",
214 "wp violation",
215 "erase param",
216 "out of range | csd overwrite",
217 "in idle state",
218 "erase reset",
219 "illegal command",
220 "com crc error",
221 "erase sequence error",
222 "address error",
223 "parameter error"
224 };
225 uint8_t r1 = 0, r2 = 0;
226
227 if ((response_type == RSP_R1)
228 || (response_type == RSP_R1b)
229 || (response_type == RSP_R2)
230 || (response_type == RSP_R3)
231 || (response_type == RSP_R7))
232 r1 = response[0];
233
234 if (response_type == RSP_R2)
235 r2 = response[1];
236
237 if (((response_type == RSP_R3) || (response_type == RSP_R7))
238 && (out_register != NULL)) {
239 *out_register = 0;
240 *out_register = (*out_register << 8) | response[1];
241 *out_register = (*out_register << 8) | response[2];
242 *out_register = (*out_register << 8) | response[3];
243 *out_register = (*out_register << 8) | response[4];
244 }
245
246 if (r1 != 0 || r2 != 0) {
247 int i = 0;
248 uint16_t r = (r1 << 8) | r2;
249 while (r) {
250 if (r & 1)
251 dprintk("SDCARD ERROR: %s\n", sd_err[i]);
252 r = r >> 1;
253 i++;
254 }
255 return (r1 << 8) | r2;
256 }
257
258 return 0;
259}
260
261static int spi_sdcard_do_command_help(const struct spi_sdcard *card,
262 int is_acmd,
263 uint8_t cmd,
264 uint32_t argument,
265 uint32_t *out_register)
266{
267 int ret, type, length, wait;
268 uint8_t crc, c, response[5];
269
270 /* calculate crc for command */
271 crc = spi_sdcard_calculate_command_crc(cmd, argument);
272
273 if (is_acmd)
274 dprintk("\nsdcard execute acmd%d, argument = %#x, crc = %#x\n",
275 cmd, argument, crc);
276 else
277 dprintk("\nsdcard execute cmd%d, argument = %#x, crc = %#x\n",
278 cmd, argument, crc);
279
280 /* lookup response type of command */
281 if (!is_acmd)
282 type = lookup_cmd_response_type(cmd);
283 else
284 type = lookup_acmd_response_type(cmd);
285
286 /* lookup response length of command */
287 length = lookup_response_length(type);
288
289 /* enable cs */
290 spi_sdcard_enable_cs(card);
291
292 /* just delay 8 clocks */
293 spi_sdcard_recvbyte(card);
294
295 /* send command */
296 spi_sdcard_sendbyte(card, (cmd | 0x40) & 0x7f);
297 /* send argument */
298 spi_sdcard_sendbyte(card, (argument >> (8 * 3)) & 0xff);
299 spi_sdcard_sendbyte(card, (argument >> (8 * 2)) & 0xff);
300 spi_sdcard_sendbyte(card, (argument >> (8 * 1)) & 0xff);
301 spi_sdcard_sendbyte(card, (argument >> (8 * 0)) & 0xff);
302 /* send crc */
303 spi_sdcard_sendbyte(card, crc);
304
Martin Roth3e25f852023-09-04 15:37:07 -0600305 /* waiting for response */
Xiang Wangb1349452019-08-27 15:57:23 +0800306 wait = 0xffff;
307 while (((c = spi_sdcard_recvbyte(card)) & 0x80) && --wait)
308 ;
309 if (!wait) {
310 spi_sdcard_disable_cs(card);
311 return -1; /* timeout */
312 }
313
314 /* obtain response */
315 for (int i = 0; i < length; i++) {
316 response[i] = c;
317 c = spi_sdcard_recvbyte(card);
318 }
319
320 if (type == RSP_R1b) {
Martin Roth3e25f852023-09-04 15:37:07 -0600321 /* waiting done */
Xiang Wangb1349452019-08-27 15:57:23 +0800322 wait = 0xffffff;
323 while (c == 0 && --wait)
324 c = spi_sdcard_recvbyte(card);
325 if (!wait) {
326 spi_sdcard_disable_cs(card);
327 return -1; /* timeout */
328 }
329 }
330
331 spi_sdcard_disable_cs(card);
332
333 ret = response_resolve(type, response, out_register);
334
335 return ret;
336}
337
338static int spi_sdcard_do_command(const struct spi_sdcard *card,
339 uint8_t cmd,
340 uint32_t argument,
341 uint32_t *out_register)
342{
343 return spi_sdcard_do_command_help(card, 0, cmd, argument, out_register);
344}
345
346static int spi_sdcard_do_app_command(const struct spi_sdcard *card,
347 uint8_t cmd,
348 uint32_t argument,
349 uint32_t *out_register)
350{
351 /* CMD55 */
John Zhao19e22f52020-09-22 11:12:37 -0700352 if (spi_sdcard_do_command(card, APP_CMD, 0, NULL))
353 return -1;
354
Xiang Wangb1349452019-08-27 15:57:23 +0800355 return spi_sdcard_do_command_help(card, 1, cmd, argument, out_register);
356}
357
Xiang Wangb1349452019-08-27 15:57:23 +0800358size_t spi_sdcard_size(const struct spi_sdcard *card)
359{
360 int wait;
361 uint8_t csd[16];
362 uint16_t c = 0;
363
364 /* CMD9, send csd (128bits register) */
365 if (spi_sdcard_do_command(card, SEND_CSD, 0, NULL))
366 return -1;
367
368 /* enable CS */
369 spi_sdcard_enable_cs(card);
370
Martin Roth3e25f852023-09-04 15:37:07 -0600371 /* waiting start block token */
Xiang Wangb1349452019-08-27 15:57:23 +0800372 wait = 0xffff;
373 while ((spi_sdcard_recvbyte(card) != CT_BLOCK_START) && --wait)
374 ;
375 if (!wait) {
376 spi_sdcard_disable_cs(card);
377 return -1;
378 }
379
380 /* receive data */
381 for (int i = 0; i < 16; i++) {
382 csd[i] = spi_sdcard_recvbyte(card);
383 c = crc16_byte(c, csd[i]);
384 }
385
386 /* receive crc and verify check sum */
387 if (((c >> 8) & 0xff) != spi_sdcard_recvbyte(card)) {
388 spi_sdcard_disable_cs(card);
389 return -1;
390 }
391 if (((c >> 0) & 0xff) != spi_sdcard_recvbyte(card)) {
392 spi_sdcard_disable_cs(card);
393 return -1;
394 }
395
396 /* disable cs */
397 spi_sdcard_disable_cs(card);
398
399 if (extract_bits(csd, 128, 126, 127) == 0) {
400 /* csd version 1.0 */
401 size_t c_size = extract_bits(csd, 128, 62, 73);
402 size_t mult = extract_bits(csd, 128, 47, 49);
403 size_t read_bl_len = extract_bits(csd, 128, 80, 83);
404 return (c_size + 1) * mult * (1 << read_bl_len);
405 }
406
407 if (extract_bits(csd, 128, 126, 127) == 1) {
408 /* csd version 2.0 */
409 size_t c_size = extract_bits(csd, 128, 48, 69);
410 return (c_size + 1) * 512 * 1024;
411 }
412
413 return -1;
414}
415
416int spi_sdcard_init(struct spi_sdcard *card,
417 const unsigned int bus, const unsigned int cs)
418{
419 int resolve, wait;
420 uint32_t ocr;
421
422 /* initialize spi controller */
423 spi_setup_slave(bus, cs, &card->slave);
424
425 /* must wait at least 74 clock ticks after reset
426 * disable cs pin to enter spi mode */
427 spi_sdcard_disable_cs(card);
428 for (int i = 0; i < 10; i++)
429 spi_sdcard_sendbyte(card, 0xff);
430
431 /* CMD0, reset sdcard */
432 wait = 0xffff;
433 while ((spi_sdcard_do_command(card, GO_IDLE_STATE, 0, NULL)
434 != RSP_ERR_IN_IDLE) && --wait)
435 ;
436 if (!wait)
437 return -1; /* timeout */
438
439 /* CMD8 */
440 resolve = spi_sdcard_do_command(card, SEND_IF_COND, 0x1aa, NULL);
441 if (resolve & RSP_ERR_ILLEGAL_COMMAND) {
442 /* ACMD41, initialize card */
443 wait = 0xffff;
444 while ((resolve = spi_sdcard_do_app_command(card,
445 SD_SEND_OP_COND, 0, NULL)) && --wait)
446 ;
447 if ((resolve & RSP_ERR_ILLEGAL_COMMAND) || !wait) {
448 wait = 0xffff;
449 /* CMD1, initialize card for 2.1mm SD Memory Card */
450 while (spi_sdcard_do_app_command(card, SEND_OP_COND,
451 0, NULL) && --wait)
452 ;
453 if (!wait)
454 return -1; /* unknown card */
455 }
456 } else {
457 /* ACMD41, initialize card */
458 wait = 0xffff;
459 while (spi_sdcard_do_app_command(card, SD_SEND_OP_COND,
460 0x40000000, NULL) && --wait)
461 ;
462 if (!wait)
463 return -1;
464 }
465
466 /* CMD58, read ocr register */
467 if (spi_sdcard_do_command(card, READ_OCR, 0, &ocr))
468 return -1;
469
470 /* CMD16, set block length to 512 bytes */
471 if (spi_sdcard_do_command(card, SET_BLOCKLEN, 512, NULL))
472 return -1;
473
474 /* CCS is bit30 of ocr register
475 * CCS = 0 -> SDSC
476 * CCS = 1 -> SDHC/SDXC
477 * */
478 if ((ocr & 0x40000000) == 0)
479 card->type = SDCARD_TYPE_SDSC;
480 else {
481 /* size > 32G -> SDXC */
482 if (spi_sdcard_size(card) > 32LL * 1024 * 1024 * 1024)
483 card->type = SDCARD_TYPE_SDXC;
484 else
485 card->type = SDCARD_TYPE_SDHC;
486 }
487
488 return 0;
489}
490
491int spi_sdcard_single_read(const struct spi_sdcard *card,
492 size_t block_address,
493 void *buff)
494{
495 int wait;
496 uint16_t c = 0;
497
498 if (card->type == SDCARD_TYPE_SDSC)
499 block_address = block_address * 512;
500
501 /* CMD17, start single block read */
502 if (spi_sdcard_do_command(card, READ_SINGLE_BLOCK, block_address, NULL))
503 return -1;
504
505 /* enable cs */
506 spi_sdcard_enable_cs(card);
507
Martin Roth3e25f852023-09-04 15:37:07 -0600508 /* waiting start block token */
Xiang Wangb1349452019-08-27 15:57:23 +0800509 wait = 0xffff;
510 while ((spi_sdcard_recvbyte(card) != CT_BLOCK_START) && --wait)
511 ;
512 if (!wait) { /* timeout */
513 spi_sdcard_disable_cs(card);
514 return -1;
515 }
516
517 /* receive data */
518 for (int i = 0; i < 512; i++) {
519 ((uint8_t *)buff)[i] = spi_sdcard_recvbyte(card);
520 c = crc16_byte(c, ((uint8_t *)buff)[i]);
521 }
522
523 /* receive crc and verify check sum */
524 if (((c >> 8) & 0xff) != spi_sdcard_recvbyte(card)) {
525 spi_sdcard_disable_cs(card);
526 return -1;
527 }
528 if (((c >> 0) & 0xff) != spi_sdcard_recvbyte(card)) {
529 spi_sdcard_disable_cs(card);
530 return -1;
531 }
532
533 /* disable cs */
534 spi_sdcard_disable_cs(card);
535
536 return 0;
537}
538
539int spi_sdcard_multiple_read(const struct spi_sdcard *card,
540 size_t start_block_address,
541 size_t end_block_address,
542 void *buff)
543{
544 int wait;
545 int block_num = end_block_address - start_block_address + 1;
546 if (card->type == SDCARD_TYPE_SDSC) {
547 start_block_address = start_block_address * 512;
548 end_block_address = end_block_address * 512;
549 }
550 /* CMD18, start multiple block read */
551 if (spi_sdcard_do_command(card,
552 READ_MULTIPLEBLOCK, start_block_address, NULL))
553 return -1;
554
555 /* enable cs */
556 spi_sdcard_enable_cs(card);
557
558 for (int i = 0; i < block_num; i++) {
559 uint16_t c = 0;
560
Martin Roth3e25f852023-09-04 15:37:07 -0600561 /* waiting start block token */
Xiang Wangb1349452019-08-27 15:57:23 +0800562 wait = 0xffff;
563 while ((spi_sdcard_recvbyte(card) != CT_BLOCK_START) && --wait)
564 ;
565 if (!wait) { /* timeout */
566 spi_sdcard_disable_cs(card);
567 return -1;
568 }
569
570 /* receive data */
571 for (int k = 0; k < 512; k++) {
572 uint8_t tmp = spi_sdcard_recvbyte(card);
573 ((uint8_t *)buff)[512 * i + k] = tmp;
574 c = crc16_byte(c, tmp);
575 }
576
577 /* receive crc and verify check sum */
578 if (((c >> 8) & 0xff) != spi_sdcard_recvbyte(card)) {
579 spi_sdcard_disable_cs(card);
580 return -1;
581 }
582 if (((c >> 0) & 0xff) != spi_sdcard_recvbyte(card)) {
583 spi_sdcard_disable_cs(card);
584 return -1;
585 }
586 }
587
588 /* disable cs */
589 spi_sdcard_disable_cs(card);
590
591 if (spi_sdcard_do_command(card, STOP_TRANSMISSION, 0, NULL))
592 if (spi_sdcard_do_command(card, SEND_STATUS, 0, NULL))
593 return -1;
594
595 return 0;
596}
597
598int spi_sdcard_read(const struct spi_sdcard *card,
599 void *dest,
600 size_t offset,
601 size_t count)
602{
603 size_t start_block_address = offset / BLOCK_SIZE;
604 size_t end_block_address = (offset + count - 1) / BLOCK_SIZE;
605 size_t has_begin = !!(offset % BLOCK_SIZE);
606 size_t has_end = !!((offset + count) % BLOCK_SIZE);
607
608 if (start_block_address == end_block_address) {
609 uint8_t tmp[BLOCK_SIZE];
610 size_t o = offset % BLOCK_SIZE;
611 size_t l = count;
612 if (spi_sdcard_single_read(card, start_block_address, tmp))
613 return -1;
614 memcpy(dest, tmp + o, l);
615 return 0;
616 }
617
618 if (has_begin) {
619 uint8_t tmp[BLOCK_SIZE];
620 size_t o = offset % BLOCK_SIZE;
621 size_t l = BLOCK_SIZE - o;
622 if (spi_sdcard_single_read(card, start_block_address, tmp))
623 return -1;
624 memcpy(dest, tmp + o, l);
625 }
626
627 if (start_block_address + has_begin <= end_block_address - has_end) {
628 size_t start_lba = start_block_address + has_begin;
629 size_t end_lba = end_block_address - has_end;
630 size_t o = has_begin ? BLOCK_SIZE - offset % BLOCK_SIZE : 0;
631 if (start_lba < end_lba) {
632 if (spi_sdcard_multiple_read(card, start_lba, end_lba,
633 dest + o))
634 return -1;
635 } else {
636 if (spi_sdcard_single_read(card, start_lba, dest + o))
637 return -1;
638 }
639 }
640
641 if (has_end) {
642 uint8_t tmp[BLOCK_SIZE];
643 size_t o = 0;
644 size_t l = (offset + count) % BLOCK_SIZE;
645 if (spi_sdcard_single_read(card, end_block_address, tmp))
646 return -1;
647 memcpy(dest + count - l, tmp + o, l);
648 }
649
650 return 0;
651}
652
653int spi_sdcard_single_write(const struct spi_sdcard *card,
654 size_t block_address,
655 void *buff)
656{
657 int wait;
658 uint16_t c = 0;
659 if (card->type == SDCARD_TYPE_SDSC)
660 block_address = block_address * 512;
661
662 if (spi_sdcard_do_command(card, WRITE_BLOCK, block_address, NULL))
663 return -1;
664
Martin Roth3e25f852023-09-04 15:37:07 -0600665 /* enable cs */
Xiang Wangb1349452019-08-27 15:57:23 +0800666 spi_sdcard_enable_cs(card);
667
668 /* send start block token */
669 spi_sdcard_sendbyte(card, CT_BLOCK_START);
670
671 /* send data */
672 for (int i = 0; i < 512; i++) {
673 spi_sdcard_sendbyte(card, ((uint8_t *)buff)[i]);
674 c = crc16_byte(c, ((uint8_t *)buff)[i]);
675 }
676
677 /* send crc check sum */
678 spi_sdcard_sendbyte(card, 0xff & (c >> 8));
679 spi_sdcard_sendbyte(card, 0xff & (c >> 0));
680
Martin Roth0949e732021-10-01 14:28:22 -0600681 /* receive and verify data response token */
Xiang Wangb1349452019-08-27 15:57:23 +0800682 c = spi_sdcard_recvbyte(card);
683 if ((c & CT_RESPONSE_MASK) != CT_RESPONSE_ACCEPTED) {
684 spi_sdcard_disable_cs(card);
685 return -1;
686 }
687
688 wait = 0xffff;
689 while ((spi_sdcard_recvbyte(card) == 0) && --wait)
690 ;/* wait for complete */
691 if (!wait) {
692 spi_sdcard_disable_cs(card);
693 return -1;
694 }
695
696 /* disable cs */
697 spi_sdcard_disable_cs(card);
698
699 return 0;
700}
701
702int spi_sdcard_multiple_write(const struct spi_sdcard *card,
703 size_t start_block_address,
704 size_t end_block_address,
705 void *buff)
706{
707 int wait, ret = 0;
708 int block_num = end_block_address - start_block_address + 1;
709 if (card->type == SDCARD_TYPE_SDSC) {
710 start_block_address = start_block_address * 512;
711 end_block_address = end_block_address * 512;
712 }
713
714 if (spi_sdcard_do_command(card, WRITE_MULTIPLEBLOCK,
715 start_block_address, NULL))
716 return -1;
717
718 /* enable cs */
719 spi_sdcard_enable_cs(card);
720
721 for (int i = 0; i < block_num; i++) {
722 uint16_t c = 0;
723
724 ret = -1;
725
726 /* send start block token */
727 spi_sdcard_sendbyte(card, CT_MULTIPLE_BLOCK_START);
728
729 /* send data */
730 for (int k = 0; k < 512; k++) {
731 uint8_t tmp = ((uint8_t *)buff)[512 * i + k];
732 spi_sdcard_sendbyte(card, tmp);
733 c = crc16_byte(c, tmp);
734 }
735
736 /* send crc check sum */
737 spi_sdcard_sendbyte(card, 0xff & (c >> 8));
738 spi_sdcard_sendbyte(card, 0xff & (c >> 0));
739
Martin Roth0949e732021-10-01 14:28:22 -0600740 /* receive and verify data response token */
Xiang Wangb1349452019-08-27 15:57:23 +0800741 c = spi_sdcard_recvbyte(card);
742 if ((c & CT_RESPONSE_MASK) != CT_RESPONSE_ACCEPTED)
743 break;
744
745 wait = 0xffff;
746 while ((spi_sdcard_recvbyte(card) == 0) && --wait)
747 ;/* wait for complete */
748 if (!wait)
749 break;
750
751 ret = 0;
752 }
753
754 /* send stop transmission token */
755 spi_sdcard_sendbyte(card, CT_MULTIPLE_BLOCK_STOP);
756
757 /* disable cs */
758 spi_sdcard_disable_cs(card);
759
760 if (spi_sdcard_do_command(card, STOP_TRANSMISSION, 0, NULL))
761 if (spi_sdcard_do_command(card, SEND_STATUS, 0, NULL))
762 return -1;
763
764 return ret;
765}
766
767int spi_sdcard_erase(const struct spi_sdcard *card,
768 size_t start_block_address,
769 size_t end_block_address)
770{
771 if (card->type == SDCARD_TYPE_SDSC) {
772 start_block_address = start_block_address * 512;
773 end_block_address = end_block_address * 512;
774 }
775
776 /* CMD32, set erase start address */
777 if (spi_sdcard_do_command(card, ERASE_WR_BLK_START_ADDR,
778 start_block_address, NULL))
779 return -1;
780
781 /* CMD33, set erase end address */
782 if (spi_sdcard_do_command(card, ERASE_WR_BLK_END_ADDR,
783 end_block_address, NULL))
784 return -1;
785
786 /* CMD38, erase */
787 if (spi_sdcard_do_command(card, ERASE, 0, NULL))
788 return -1;
789
790 return 0;
791}
792
793int spi_sdcard_erase_all(const struct spi_sdcard *card)
794{
795 return spi_sdcard_erase(card, 0, spi_sdcard_size(card) / BLOCK_SIZE);
796}