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)
70static uint8_t spisd_send_cmd(uint8_t cmd, uint32_t arg)
72 uint8_t response = 0xFF;
75 if (cmd != CMD12 && cmd != CMD0)
76 mx_sio2_write_dummy();
78 uint8_t packet[] = {cmd, arg >> 24, arg >> 16, arg >> 8, arg, 0};
79 packet[CMD_CRC_OFFSET] = CRC7_SHIFT_MASK(crc7(packet, CMD_CRC_OFFSET));
82 mx_sio2_tx_pio(packet,
sizeof(packet));
86 mx_sio2_write_dummy();
89 response = mx_sio2_wait_not_equal(0xFF, CMD_WAIT_RESP_TIMEOUT);
92 if (cmd != CMD9 && cmd != CMD10 && cmd != CMD13 && cmd != CMD18 && cmd != CMD25) {
93 mx_sio2_write_dummy();
99static uint8_t spisd_send_cmd_recv_data(uint8_t cmd, uint32_t arg, uint8_t *data,
size_t size)
101 uint8_t response = 0xFF;
103 mx_sio2_write_dummy();
105 uint8_t packet[] = {cmd, arg >> 24, arg >> 16, arg >> 8, arg, 0};
106 packet[CMD_CRC_OFFSET] = CRC7_SHIFT_MASK(crc7(packet, CMD_CRC_OFFSET));
109 mx_sio2_tx_pio(packet,
sizeof(packet));
112 response = mx_sio2_wait_not_equal(0xFF, CMD_WAIT_RESP_TIMEOUT);
113 if (response != 0xFF) {
115 mx_sio2_rx_pio(data, size);
118 mx_sio2_write_dummy();
123static uint8_t spisd_read_register(uint8_t *buff, uint32_t len)
125 uint8_t results = SPISD_RESULT_ERROR;
127 results = mx_sio2_wait_equal(0xFE, 2000);
128 if (results == SPISD_RESULT_OK) {
130 mx_sio2_rx_pio(buff, len);
137uint16_t spisd_read_status_register()
141 response = spisd_send_cmd(CMD13, 0) << 8;
142 response |= mx_sio2_write_dummy();
144 mx_sio2_write_dummy();
151 uint16_t timeout = WAIT_IDLE_TIMEOUT;
152 uint8_t response = 0;
156 mx_sio2_set_baud(SIO2_BAUD_DIV_SLOW);
165 for (
int i = 0; i < 16; i++) {
166 mx_sio2_write_dummy();
170 response = spisd_send_cmd(CMD0, 0);
172 }
while ((response != SPISD_R1_IDLE_FLAG) && timeout > 0);
175 M_DEBUG(
"ERROR: CMD0 returned 0x%x, exp: 0x1\n", response);
176 return SPISD_RESULT_TIMEOUT;
180 response = spisd_send_cmd_recv_data(CMD8, 0x1AA, buffer,
sizeof(buffer));
183 if (response == SPISD_R1_IDLE_FLAG) {
186 if (buffer[2] == 0x01 && buffer[3] == 0xAA) {
188 for (
int i = 0; i < 0xFFF; i++) {
189 response = spisd_send_cmd(CMD55, 0);
190 if (response != 0x01) {
191 M_DEBUG(
"ERROR: CMD55 returned 0x%x, exp: 0x1\n", response);
192 return SPISD_RESULT_TIMEOUT;
195 response = spisd_send_cmd(ACMD41, 0x40000000);
196 if (response == 0x00) {
201 if (response != 0x00) {
202 M_DEBUG(
"ERROR: ACMD41 returned 0x%x, exp: 0x1\n", response);
203 return SPISD_RESULT_TIMEOUT;
207 response = spisd_send_cmd_recv_data(CMD58, 0, buffer,
sizeof(buffer));
208 if (response != 0x00) {
209 M_DEBUG(
"ERROR: CMD58 returned 0x%x, exp 0x0\n", response);
210 return SPISD_RESULT_TIMEOUT;
214 sdcard.card_type = (buffer[0] & 0x40) ? CARD_TYPE_SDV2HC : CARD_TYPE_SDV2;
217 mx_sio2_set_baud(SIO2_BAUD_DIV_FAST);
220 M_DEBUG(
"ERROR: CMD8 check pattern failed, got 0x%x, 0x%x\n", buffer[2], buffer[3]);
221 return SPISD_RESULT_ERROR;
225 }
else if (response & SPISD_R1_ILLEGAL_CMD_FLAG) {
226 M_DEBUG(
"CMD8 illegal, trying CSD v1.0 init\n");
229 mx_sio2_write_dummy();
232 for (
int i = 0; i < 0xFFF; i++) {
233 response = spisd_send_cmd(CMD55, 0);
234 if (response != 0x01) {
235 M_DEBUG(
"ERROR: CMD55 returned 0x%x, exp 0x1\n", response);
236 return SPISD_RESULT_TIMEOUT;
239 response = spisd_send_cmd(ACMD41, 0);
240 if (response == 0x00) {
246 if (response != 0x00) {
247 for (
int i = 0; i < 0xFFF; i++) {
248 response = spisd_send_cmd(CMD1, 0);
249 if (response == 0x00) {
254 if (response != 0x00) {
255 M_DEBUG(
"ERROR: CMD1 returned 0x%x, exp 0x0\n", response);
256 return SPISD_RESULT_TIMEOUT;
259 sdcard.card_type = CARD_TYPE_MMC;
260 M_DEBUG(
"Card Type : MMC\r\n");
262 sdcard.card_type = CARD_TYPE_SDV1;
263 M_DEBUG(
"Card Type : CSD v1\r\n");
267 mx_sio2_set_baud(SIO2_BAUD_DIV_FAST);
270 response = spisd_send_cmd(CMD59, 0);
272 if (response != 0x00) {
273 M_DEBUG(
"Send CMD59 should return 0x00, response=0x%02x\r\n", response);
274 return SPISD_RESULT_TIMEOUT;
278 response = spisd_send_cmd(CMD16, 512);
279 if (response != 0x00) {
280 M_DEBUG(
"ERROR: CMD16 returned 0x%x, exp 0x0\n", response);
281 return SPISD_RESULT_TIMEOUT;
286 M_DEBUG(
"ERROR: CMD8 returned 0x%x, exp 0x1 or 0x4\n", response);
287 return SPISD_RESULT_ERROR;
290 return SPISD_RESULT_OK;
294int spisd_get_card_info()
297 uint8_t reg_data[18];
300 uint8_t result = spisd_send_cmd(CMD9, 0);
305 result = spisd_read_register(sdcard.csd,
sizeof(reg_data));
308 mx_sio2_write_dummy();
311 return SPISD_RESULT_ERROR;
315 result = spisd_send_cmd(CMD10, 0);
318 return SPISD_RESULT_ERROR;
321 result = spisd_read_register(reg_data,
sizeof(reg_data));
323 mx_sio2_write_dummy();
326 return SPISD_RESULT_ERROR;
329 sdcard.cid.ManufacturerID = reg_data[0];
331 sdcard.cid.OEM_AppliID = reg_data[1] << 8;
333 sdcard.cid.OEM_AppliID |= reg_data[2];
335 sdcard.cid.ProdName1 = reg_data[3] << 24;
337 sdcard.cid.ProdName1 |= reg_data[4] << 16;
339 sdcard.cid.ProdName1 |= reg_data[5] << 8;
341 sdcard.cid.ProdName1 |= reg_data[6];
343 sdcard.cid.ProdName2 = reg_data[7];
345 sdcard.cid.ProdRev = reg_data[8];
347 sdcard.cid.ProdSN = reg_data[9] << 24;
349 sdcard.cid.ProdSN |= reg_data[10] << 16;
351 sdcard.cid.ProdSN |= reg_data[11] << 8;
353 sdcard.cid.ProdSN |= reg_data[12];
355 sdcard.cid.Reserved1 |= (reg_data[13] & 0xF0) >> 4;
357 sdcard.cid.ManufactDate = (reg_data[13] & 0x0F) << 8;
359 sdcard.cid.ManufactDate |= reg_data[14];
361 sdcard.cid.CID_CRC = (reg_data[15] & 0xFE) >> 1;
367 if (csdv1->csd_structure == 0) {
368 unsigned int c_size_mult = (csdv1->c_size_multHi << 1) | csdv1->c_size_multLo;
369 unsigned int c_size = (csdv1->c_sizeHi << 10) | (csdv1->c_sizeMd << 2) | csdv1->c_sizeLo;
370 unsigned int blockNr = (c_size + 1) << (c_size_mult + 2);
371 unsigned int blockLen = 1 << csdv1->read_bl_len;
372 unsigned int capacity = blockNr * blockLen;
374 bd.sectorCount = capacity / 512;
377 }
else if (csdv1->csd_structure == 1) {
378 unsigned int c_size = (csdv2->c_sizeHi << 16) | (csdv2->c_sizeMd << 8) | csdv2->c_sizeLo;
379 bd.sectorCount = (c_size + 1) * 1024;
382 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));
384 return SPISD_RESULT_OK;
391 for (
int i = 0; i < 64; i++)
392 mx_sio2_rx_pio((
void *)&rv, 4);
394 if (spisd_init_card() != SPISD_RESULT_OK) {
395 M_DEBUG(
"recovery failed to reinit card!\n");
396 return SPISD_RESULT_ERROR;
399 if (spisd_get_card_info() != SPISD_RESULT_OK) {
400 M_DEBUG(
"recovery failed to get card info!\n");
401 return SPISD_RESULT_ERROR;
404 return SPISD_RESULT_OK;
408static int spisd_read_multi_begin(uint32_t sector)
410 uint8_t results = SPISD_RESULT_ERROR;
412 results = mx_sio2_wait_equal(0xFF, 4000);
414 if (results == SPISD_RESULT_OK) {
416 if (sdcard.card_type != CARD_TYPE_SDV2HC) {
417 sector = sector << 9;
421 results = spisd_send_cmd(CMD18, sector);
422 if (results == SPISD_RESULT_OK) {
424 results = mx_sio2_wait_equal(0xFE, 100000);
431static int spisd_read_multi_do(
void *buffer, uint16_t
count)
435 cmd.sector_count =
count;
436 cmd.sectors_transferred = 0;
437 cmd.sectors_reversed = 0;
438 cmd.response = SPISD_RESULT_OK;
442 mx_sio2_start_rx_dma(buffer);
448 WaitEventFlag(sio2_event_flag, EF_SIO2_INTR_REVERSE | EF_SIO2_INTR_COMPLETE, 1, &resbits);
450 if (resbits & EF_SIO2_INTR_REVERSE) {
451 ClearEventFlag(sio2_event_flag, ~EF_SIO2_INTR_REVERSE);
453 while (cmd.sectors_reversed < cmd.sectors_transferred && cmd.abort == 0) {
454 void *buf = (uint32_t *)&cmd.buffer[cmd.sectors_reversed * SECTOR_SIZE];
455 reverse_buffer(buf, SECTOR_SIZE / 4);
457#ifdef CONFIG_USE_CRC16
458 uint16_t crc_a = crc16(buf, SECTOR_SIZE);
459 uint16_t crc_b = cmd.crc[cmd.sectors_reversed];
460 if (crc_a != crc_b) {
464 M_DEBUG(
"CRC mismatch on sector %i, got: 0x%x, exp 0x%x\n", cmd.sectors_reversed, crc_b, crc_a);
465 cmd.abort = CMD_ERROR_CRC16_INVALID;
469 cmd.sectors_reversed++;
473 if (resbits & EF_SIO2_INTR_COMPLETE) {
474 ClearEventFlag(sio2_event_flag, ~EF_SIO2_INTR_COMPLETE);
479 return cmd.sectors_reversed;
482static void spisd_read_multi_end()
488 spisd_send_cmd(CMD12, 0);
492static int spisd_write_multi_begin(uint32_t sector, uint16_t
count)
494 uint8_t results = SPISD_RESULT_ERROR;
497 results = mx_sio2_wait_equal(0xFF, 4000);
499 if (results == SPISD_RESULT_OK) {
501 if (sdcard.card_type != CARD_TYPE_SDV2HC) {
502 sector = sector << 9;
506 if (sdcard.card_type != CARD_TYPE_MMC) {
507 results = spisd_send_cmd(CMD55, 0);
508 results = spisd_send_cmd(ACMD23,
count);
512 results = spisd_send_cmd(CMD25, sector);
515 mx_sio2_write_dummy();
516 mx_sio2_write_dummy();
517 mx_sio2_write_dummy();
522static int spisd_write_multi_do(
void* buffer, uint16_t
count)
528 cmd.sector_count =
count;
529 cmd.sectors_transferred = 0;
530 cmd.sectors_reversed = 0;
531 cmd.response = SPISD_RESULT_OK;
535 mx_sio2_write_byte(0xFC);
538 mx_sio2_start_tx_dma(buffer);
541 WaitEventFlag(sio2_event_flag, EF_SIO2_INTR_COMPLETE, 1, &resbits);
543 if (resbits & EF_SIO2_INTR_COMPLETE) {
544 ClearEventFlag(sio2_event_flag, ~EF_SIO2_INTR_COMPLETE);
547 return cmd.sectors_transferred;
550static int spisd_write_multi_end()
552 uint8_t results = SPISD_RESULT_ERROR;
555 results = mx_sio2_write_byte(0xFD);
556 if (results != 0x0) {
557 mx_sio2_write_dummy();
558 mx_sio2_write_dummy();
561 results = mx_sio2_wait_equal(0xFF, 0x800000);
562 if (results == SPISD_RESULT_OK) {
563 mx_sio2_write_dummy();
564 mx_sio2_write_dummy();
567 M_DEBUG(
"ERROR: failed to end write, 0xFD response 0x%x\n", results);
570 mx_sio2_write_dummy();
579int spisd_read(
struct block_device *bd, uint64_t sector,
void *buffer, uint16_t
count)
581 uint16_t sectors_left =
count;
582 uint16_t results = 0;
583 uint16_t retries = 0;
590 M_DEBUG(
"%s: sector %i, count: %i \n", __FUNCTION__, (u32)sector,
count);
592 mx_sio2_lock(INTR_RX);
594 while (sectors_left > 0 && retries < MAX_RETRIES) {
597 results = spisd_read_multi_begin((uint32_t)sector);
598 if (results != SPISD_RESULT_OK) {
599 M_DEBUG(
"ERROR: failed to start multi-block read\n");
604 results = spisd_read_multi_do(buffer, sectors_left);
605 sectors_left = sectors_left - results;
608 if (sectors_left > 0) {
609 buffer = (uint8_t *)buffer + (results * 512);
610 M_DEBUG(
"ERROR: failed to read all sectors, read:%i, abort:%i\n", sectors_left, cmd.abort);
612 if (cmd.abort == CMD_ABORT_NO_READ_TOKEN) {
614 if (spisd_recover() != SPISD_RESULT_OK) {
621 spisd_read_multi_end();
628 mx_sio2_unlock(INTR_RX);
630 return count - sectors_left;
633int spisd_write(
struct block_device *bd, uint64_t sector,
const void *buffer, uint16_t
count)
637 uint16_t sectors_left =
count;
638 uint16_t results = 0;
639 uint16_t retries = 0;
644 M_DEBUG(
"%s: sector %i, count: %i \n", __FUNCTION__, (u32)sector,
count);
647 void *write_buffer = (uint32_t*)buffer;
650 reverse_buffer(write_buffer, ((
count * SECTOR_SIZE) / 4));
652 mx_sio2_lock(INTR_TX);
654 while (sectors_left > 0 && retries < MAX_RETRIES) {
657 results = spisd_write_multi_begin(sector,
count);
658 if (results != SPISD_RESULT_OK) {
659 M_DEBUG(
"ERROR: failed to start multi-block write\n");
664 results = spisd_write_multi_do(write_buffer, sectors_left);
665 sectors_left = sectors_left - results;
668 if (sectors_left > 0) {
669 write_buffer = (uint8_t *)write_buffer + (results * 512);
670 M_DEBUG(
"ERROR: failed to write all sectors, wrote: %i\n", results);
674 results = spisd_write_multi_end();
675 if (results != SPISD_RESULT_OK) {
676 M_DEBUG(
"ERROR: failed to end multi-block write\n");
685 mx_sio2_unlock(INTR_TX);
687 return count - sectors_left;
u32 count
start sector of fragmented bd/file