6#include "spi_sdcard_driver.h"
7#include "spi_sdcard_crc7.h"
12#include "module_debug.h"
14#define CMD0 (0 | 0x40)
15#define CMD1 (1 | 0x40)
16#define CMD8 (8 | 0x40)
17#define CMD9 (9 | 0x40)
18#define CMD10 (10 | 0x40)
19#define CMD12 (12 | 0x40)
20#define CMD13 (13 | 0x40)
21#define CMD16 (16 | 0x40)
22#define CMD17 (17 | 0x40)
23#define CMD18 (18 | 0x40)
24#define ACMD23 (23 | 0x40)
25#define CMD24 (24 | 0x40)
26#define CMD25 (25 | 0x40)
27#define ACMD41 (41 | 0x40)
28#define CMD55 (55 | 0x40)
29#define CMD58 (58 | 0x40)
30#define CMD59 (59 | 0x40)
32#define SPISD_R1_IDLE_FLAG (0x01)
33#define SPISD_R1_ERASE_RESET_FLAG (0x02)
34#define SPISD_R1_ILLEGAL_CMD_FLAG (0x04)
35#define SPISD_R1_CMD_CRC_FLAG (0x08)
36#define SPISD_R1_ERASE_SEQ_ERROR_FLAG (0x10)
37#define SPISD_R1_ADDR_ERROR_FLAG (0x20)
38#define SPISD_R1_PARAM_ERROR_FLAG (0x40)
39#define SPISD_R1_ZERO_FLAG (0x80)
41#define CMD_WAIT_RESP_TIMEOUT (100U)
42#define WAIT_IDLE_TIMEOUT (50U)
45#define CMD_CRC_OFFSET 5
46#define CRC7_SHIFT_MASK(crc7) ((crc7) << 1U | 1U)
71static uint8_t spisd_send_cmd(uint8_t cmd, uint32_t arg)
73 uint8_t response = 0xFF;
76 if (cmd != CMD12 && cmd != CMD0)
77 mx_sio2_write_dummy();
79 uint8_t packet[] = {cmd, arg >> 24, arg >> 16, arg >> 8, arg, 0};
80 packet[CMD_CRC_OFFSET] = CRC7_SHIFT_MASK(crc7(packet, CMD_CRC_OFFSET));
83 mx_sio2_tx_pio(packet,
sizeof(packet));
87 mx_sio2_write_dummy();
90 response = mx_sio2_wait_not_equal(0xFF, CMD_WAIT_RESP_TIMEOUT);
93 if (cmd != CMD9 && cmd != CMD10 && cmd != CMD13 && cmd != CMD18 && cmd != CMD25) {
94 mx_sio2_write_dummy();
100static uint8_t spisd_send_cmd_recv_data(uint8_t cmd, uint32_t arg, uint8_t *data,
size_t size)
102 uint8_t response = 0xFF;
104 mx_sio2_write_dummy();
106 uint8_t packet[] = {cmd, arg >> 24, arg >> 16, arg >> 8, arg, 0};
107 packet[CMD_CRC_OFFSET] = CRC7_SHIFT_MASK(crc7(packet, CMD_CRC_OFFSET));
110 mx_sio2_tx_pio(packet,
sizeof(packet));
113 response = mx_sio2_wait_not_equal(0xFF, CMD_WAIT_RESP_TIMEOUT);
114 if (response != 0xFF) {
116 mx_sio2_rx_pio(data, size);
119 mx_sio2_write_dummy();
124static uint8_t spisd_read_register(uint8_t *buff, uint32_t len)
126 uint8_t results = SPISD_RESULT_ERROR;
128 results = mx_sio2_wait_equal(0xFE, 2000);
129 if (results == SPISD_RESULT_OK) {
131 mx_sio2_rx_pio(buff, len);
138uint16_t spisd_read_status_register()
142 response = spisd_send_cmd(CMD13, 0) << 8;
143 response |= mx_sio2_write_dummy();
145 mx_sio2_write_dummy();
152 uint16_t timeout = WAIT_IDLE_TIMEOUT;
153 uint8_t response = 0;
157 mx_sio2_set_baud(SIO2_BAUD_DIV_SLOW);
166 for (
int i = 0; i < 16; i++) {
167 mx_sio2_write_dummy();
171 response = spisd_send_cmd(CMD0, 0);
173 }
while ((response != SPISD_R1_IDLE_FLAG) && timeout > 0);
176 M_DEBUG(
"ERROR: CMD0 returned 0x%x, exp: 0x1\n", response);
177 return SPISD_RESULT_TIMEOUT;
181 response = spisd_send_cmd_recv_data(CMD8, 0x1AA, buffer,
sizeof(buffer));
184 if (response == SPISD_R1_IDLE_FLAG) {
187 if (buffer[2] == 0x01 && buffer[3] == 0xAA) {
189 for (
int i = 0; i < 0xFFF; i++) {
190 response = spisd_send_cmd(CMD55, 0);
191 if (response != 0x01) {
192 M_DEBUG(
"ERROR: CMD55 returned 0x%x, exp: 0x1\n", response);
193 return SPISD_RESULT_TIMEOUT;
196 response = spisd_send_cmd(ACMD41, 0x40000000);
197 if (response == 0x00) {
202 if (response != 0x00) {
203 M_DEBUG(
"ERROR: ACMD41 returned 0x%x, exp: 0x1\n", response);
204 return SPISD_RESULT_TIMEOUT;
208 response = spisd_send_cmd_recv_data(CMD58, 0, buffer,
sizeof(buffer));
209 if (response != 0x00) {
210 M_DEBUG(
"ERROR: CMD58 returned 0x%x, exp 0x0\n", response);
211 return SPISD_RESULT_TIMEOUT;
215 sdcard.card_type = (buffer[0] & 0x40) ? CARD_TYPE_SDV2HC : CARD_TYPE_SDV2;
218 mx_sio2_set_baud(SIO2_BAUD_DIV_FAST);
221 M_DEBUG(
"ERROR: CMD8 check pattern failed, got 0x%x, 0x%x\n", buffer[2], buffer[3]);
222 return SPISD_RESULT_ERROR;
226 }
else if (response & SPISD_R1_ILLEGAL_CMD_FLAG) {
227 M_DEBUG(
"CMD8 illegal, trying CSD v1.0 init\n");
230 mx_sio2_write_dummy();
233 for (
int i = 0; i < 0xFFF; i++) {
234 response = spisd_send_cmd(CMD55, 0);
235 if (response != 0x01) {
236 M_DEBUG(
"ERROR: CMD55 returned 0x%x, exp 0x1\n", response);
237 return SPISD_RESULT_TIMEOUT;
240 response = spisd_send_cmd(ACMD41, 0);
241 if (response == 0x00) {
247 if (response != 0x00) {
248 for (
int i = 0; i < 0xFFF; i++) {
249 response = spisd_send_cmd(CMD1, 0);
250 if (response == 0x00) {
255 if (response != 0x00) {
256 M_DEBUG(
"ERROR: CMD1 returned 0x%x, exp 0x0\n", response);
257 return SPISD_RESULT_TIMEOUT;
260 sdcard.card_type = CARD_TYPE_MMC;
261 M_DEBUG(
"Card Type : MMC\r\n");
263 sdcard.card_type = CARD_TYPE_SDV1;
264 M_DEBUG(
"Card Type : CSD v1\r\n");
268 mx_sio2_set_baud(SIO2_BAUD_DIV_FAST);
271 response = spisd_send_cmd(CMD59, 0);
273 if (response != 0x00) {
274 M_DEBUG(
"Send CMD59 should return 0x00, response=0x%02x\r\n", response);
275 return SPISD_RESULT_TIMEOUT;
279 response = spisd_send_cmd(CMD16, 512);
280 if (response != 0x00) {
281 M_DEBUG(
"ERROR: CMD16 returned 0x%x, exp 0x0\n", response);
282 return SPISD_RESULT_TIMEOUT;
287 M_DEBUG(
"ERROR: CMD8 returned 0x%x, exp 0x1 or 0x4\n", response);
288 return SPISD_RESULT_ERROR;
291 return SPISD_RESULT_OK;
295int spisd_get_card_info()
298 uint8_t reg_data[18];
301 uint8_t result = spisd_send_cmd(CMD9, 0);
306 result = spisd_read_register(sdcard.csd,
sizeof(reg_data));
309 mx_sio2_write_dummy();
312 return SPISD_RESULT_ERROR;
316 result = spisd_send_cmd(CMD10, 0);
319 return SPISD_RESULT_ERROR;
322 result = spisd_read_register(reg_data,
sizeof(reg_data));
324 mx_sio2_write_dummy();
327 return SPISD_RESULT_ERROR;
330 sdcard.cid.ManufacturerID = reg_data[0];
332 sdcard.cid.OEM_AppliID = reg_data[1] << 8;
334 sdcard.cid.OEM_AppliID |= reg_data[2];
336 sdcard.cid.ProdName1 = reg_data[3] << 24;
338 sdcard.cid.ProdName1 |= reg_data[4] << 16;
340 sdcard.cid.ProdName1 |= reg_data[5] << 8;
342 sdcard.cid.ProdName1 |= reg_data[6];
344 sdcard.cid.ProdName2 = reg_data[7];
346 sdcard.cid.ProdRev = reg_data[8];
348 sdcard.cid.ProdSN = reg_data[9] << 24;
350 sdcard.cid.ProdSN |= reg_data[10] << 16;
352 sdcard.cid.ProdSN |= reg_data[11] << 8;
354 sdcard.cid.ProdSN |= reg_data[12];
356 sdcard.cid.Reserved1 |= (reg_data[13] & 0xF0) >> 4;
358 sdcard.cid.ManufactDate = (reg_data[13] & 0x0F) << 8;
360 sdcard.cid.ManufactDate |= reg_data[14];
362 sdcard.cid.CID_CRC = (reg_data[15] & 0xFE) >> 1;
368 if (csdv1->csd_structure == 0) {
369 unsigned int c_size_mult = (csdv1->c_size_multHi << 1) | csdv1->c_size_multLo;
370 unsigned int c_size = (csdv1->c_sizeHi << 10) | (csdv1->c_sizeMd << 2) | csdv1->c_sizeLo;
371 unsigned int blockNr = (c_size + 1) << (c_size_mult + 2);
372 unsigned int blockLen = 1 << csdv1->read_bl_len;
373 unsigned int capacity = blockNr * blockLen;
375 bd.sectorCount = capacity / 512;
378 }
else if (csdv1->csd_structure == 1) {
379 unsigned int c_size = (csdv2->c_sizeHi << 16) | (csdv2->c_sizeMd << 8) | csdv2->c_sizeLo;
380 bd.sectorCount = (c_size + 1) * 1024;
383 M_PRINTF(
"%lu %u-byte logical blocks: (%luMB / %luMiB)\n", (u32)bd.sectorCount, bd.sectorSize, (u32)bd.sectorCount / ((1000 * 1000) / bd.sectorSize), (u32)bd.sectorCount / ((1024 * 1024) / bd.sectorSize));
385 return SPISD_RESULT_OK;
392 for (
int i = 0; i < 64; i++)
393 mx_sio2_rx_pio((
void *)&rv, 4);
395 if (spisd_init_card() != SPISD_RESULT_OK) {
396 M_DEBUG(
"recovery failed to reinit card!\n");
397 return SPISD_RESULT_ERROR;
400 if (spisd_get_card_info() != SPISD_RESULT_OK) {
401 M_DEBUG(
"recovery failed to get card info!\n");
402 return SPISD_RESULT_ERROR;
405 return SPISD_RESULT_OK;
409static int spisd_read_multi_begin(uint32_t sector)
411 uint8_t results = SPISD_RESULT_ERROR;
413 results = mx_sio2_wait_equal(0xFF, 4000);
415 if (results == SPISD_RESULT_OK) {
417 if (sdcard.card_type != CARD_TYPE_SDV2HC) {
418 sector = sector << 9;
422 results = spisd_send_cmd(CMD18, sector);
423 if (results == SPISD_RESULT_OK) {
425 results = mx_sio2_wait_equal(0xFE, 100000);
432static int spisd_read_multi_do(
void *buffer, uint16_t
count)
436 cmd.sector_count =
count;
437 cmd.sectors_transferred = 0;
438 cmd.sectors_reversed = 0;
439 cmd.response = SPISD_RESULT_OK;
443 mx_sio2_start_rx_dma(buffer);
449 WaitEventFlag(sio2_event_flag, EF_SIO2_INTR_REVERSE | EF_SIO2_INTR_COMPLETE, 1, &resbits);
451 if (resbits & EF_SIO2_INTR_REVERSE) {
452 ClearEventFlag(sio2_event_flag, ~EF_SIO2_INTR_REVERSE);
454 while (cmd.sectors_reversed < cmd.sectors_transferred && cmd.abort == 0) {
455 void *buf = (uint32_t *)&cmd.buffer[cmd.sectors_reversed * SECTOR_SIZE];
456 reverse_buffer(buf, SECTOR_SIZE / 4);
458#ifdef CONFIG_USE_CRC16
459 uint16_t crc_a = crc16(buf, SECTOR_SIZE);
460 uint16_t crc_b = cmd.crc[cmd.sectors_reversed];
461 if (crc_a != crc_b) {
465 M_DEBUG(
"CRC mismatch on sector %i, got: 0x%x, exp 0x%x\n", cmd.sectors_reversed, crc_b, crc_a);
466 cmd.abort = CMD_ERROR_CRC16_INVALID;
470 cmd.sectors_reversed++;
474 if (resbits & EF_SIO2_INTR_COMPLETE) {
475 ClearEventFlag(sio2_event_flag, ~EF_SIO2_INTR_COMPLETE);
480 return cmd.sectors_reversed;
483static void spisd_read_multi_end()
489 spisd_send_cmd(CMD12, 0);
493static int spisd_write_multi_begin(uint32_t sector, uint16_t
count)
495 uint8_t results = SPISD_RESULT_ERROR;
498 results = mx_sio2_wait_equal(0xFF, 4000);
500 if (results == SPISD_RESULT_OK) {
502 if (sdcard.card_type != CARD_TYPE_SDV2HC) {
503 sector = sector << 9;
507 if (sdcard.card_type != CARD_TYPE_MMC) {
508 results = spisd_send_cmd(CMD55, 0);
509 results = spisd_send_cmd(ACMD23,
count);
513 results = spisd_send_cmd(CMD25, sector);
516 mx_sio2_write_dummy();
517 mx_sio2_write_dummy();
518 mx_sio2_write_dummy();
523static int spisd_write_multi_do(
void* buffer, uint16_t
count)
529 cmd.sector_count =
count;
530 cmd.sectors_transferred = 0;
531 cmd.sectors_reversed = 0;
532 cmd.response = SPISD_RESULT_OK;
536 mx_sio2_write_byte(0xFC);
539 mx_sio2_start_tx_dma(buffer);
542 WaitEventFlag(sio2_event_flag, EF_SIO2_INTR_COMPLETE, 1, &resbits);
544 if (resbits & EF_SIO2_INTR_COMPLETE) {
545 ClearEventFlag(sio2_event_flag, ~EF_SIO2_INTR_COMPLETE);
548 return cmd.sectors_transferred;
551static int spisd_write_multi_end()
553 uint8_t results = SPISD_RESULT_ERROR;
556 results = mx_sio2_write_byte(0xFD);
557 if (results != 0x0) {
558 mx_sio2_write_dummy();
559 mx_sio2_write_dummy();
562 results = mx_sio2_wait_equal(0xFF, 0x800000);
563 if (results == SPISD_RESULT_OK) {
564 mx_sio2_write_dummy();
565 mx_sio2_write_dummy();
568 M_DEBUG(
"ERROR: failed to end write, 0xFD response 0x%x\n", results);
571 mx_sio2_write_dummy();
580int spisd_read(
struct block_device *bd, uint64_t sector,
void *buffer, uint16_t
count)
582 uint16_t sectors_left =
count;
583 uint16_t results = 0;
584 uint16_t retries = 0;
591 M_DEBUG(
"%s: sector %i, count: %i \n", __FUNCTION__, (u32)sector,
count);
593 mx_sio2_lock(INTR_RX);
595 while (sectors_left > 0 && retries < MAX_RETRIES) {
598 results = spisd_read_multi_begin((uint32_t)sector);
599 if (results != SPISD_RESULT_OK) {
600 M_DEBUG(
"ERROR: failed to start multi-block read\n");
605 results = spisd_read_multi_do(buffer, sectors_left);
606 sectors_left = sectors_left - results;
609 if (sectors_left > 0) {
610 buffer = (uint8_t *)buffer + (results * 512);
611 M_DEBUG(
"ERROR: failed to read all sectors, read:%i, abort:%i\n", sectors_left, cmd.abort);
613 if (cmd.abort == CMD_ABORT_NO_READ_TOKEN) {
615 if (spisd_recover() != SPISD_RESULT_OK) {
622 spisd_read_multi_end();
629 mx_sio2_unlock(INTR_RX);
631 return count - sectors_left;
634int spisd_write(
struct block_device *bd, uint64_t sector,
const void *buffer, uint16_t
count)
638 uint16_t sectors_left =
count;
639 uint16_t results = 0;
640 uint16_t retries = 0;
645 M_DEBUG(
"%s: sector %i, count: %i \n", __FUNCTION__, (u32)sector,
count);
648 void *write_buffer = (uint32_t*)buffer;
651 reverse_buffer(write_buffer, ((
count * SECTOR_SIZE) / 4));
653 mx_sio2_lock(INTR_TX);
655 while (sectors_left > 0 && retries < MAX_RETRIES) {
658 results = spisd_write_multi_begin(sector,
count);
659 if (results != SPISD_RESULT_OK) {
660 M_DEBUG(
"ERROR: failed to start multi-block write\n");
665 results = spisd_write_multi_do(write_buffer, sectors_left);
666 sectors_left = sectors_left - results;
669 if (sectors_left > 0) {
670 write_buffer = (uint8_t *)write_buffer + (results * 512);
671 M_DEBUG(
"ERROR: failed to write all sectors, wrote: %i\n", results);
675 results = spisd_write_multi_end();
676 if (results != SPISD_RESULT_OK) {
677 M_DEBUG(
"ERROR: failed to end multi-block write\n");
686 mx_sio2_unlock(INTR_TX);
688 return count - sectors_left;
u32 count
start sector of fragmented bd/file