PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
spi_sdcard_driver.c
1#include <bdm.h>
2#include <stdint.h>
3#include <thevent.h>
4#include <thbase.h>
5
6#include "spi_sdcard_driver.h"
7#include "spi_sdcard_crc7.h"
8#include "crc16.h"
9#include "mx4sio.h"
10#include "sio2regs.h"
11
12#include "module_debug.h"
13
14#define CMD0 (0 | 0x40) /* Reset */
15#define CMD1 (1 | 0x40) /* Send Operator Condition - SEND_OP_COND */
16#define CMD8 (8 | 0x40) /* Send Interface Condition - SEND_IF_COND */
17#define CMD9 (9 | 0x40) /* Read CSD */
18#define CMD10 (10 | 0x40) /* Read CID */
19#define CMD12 (12 | 0x40) /* Stop data transmit */
20#define CMD13 (13 | 0x40) /* SEND_STATUS */
21#define CMD16 (16 | 0x40) /* Set block size, should return 0x00 */
22#define CMD17 (17 | 0x40) /* Read single block */
23#define CMD18 (18 | 0x40) /* Read multi block */
24#define ACMD23 (23 | 0x40) /* Prepare erase N-blocks before multi block write */
25#define CMD24 (24 | 0x40) /* Write single block */
26#define CMD25 (25 | 0x40) /* Write multi block */
27#define ACMD41 (41 | 0x40) /* should return 0x00 */
28#define CMD55 (55 | 0x40) /* should return 0x01 */
29#define CMD58 (58 | 0x40) /* Read OCR */
30#define CMD59 (59 | 0x40) /* CRC disable/enable, should return 0x00 */
31
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)
40
41#define CMD_WAIT_RESP_TIMEOUT (100U)
42#define WAIT_IDLE_TIMEOUT (50U)
43#define MAX_RETRIES 4
44
45#define CMD_CRC_OFFSET 5
46#define CRC7_SHIFT_MASK(crc7) ((crc7) << 1U | 1U)
47
48/* globals */
49spisd_t sdcard;
50
51/* BDM interface */
52struct block_device bd = {
53 NULL, /* priv */
54 "sdc", /* name */
55 0, /* devNr */
56 0, /* parNr */
57 0x00, /* parId */
58 SECTOR_SIZE, /* sectorSize */
59 0, /* sectorOffset */
60 0, /* sectorCount */
61 spisd_read,
62 spisd_write,
63 spisd_flush,
64 spisd_stop };
65
66/* NOTE: SIO2 does *NOT* allow for direct control of /CS line.
67 * It's controlled by the SIO2 hardware and automatically asserted at the start
68 * of a transfer and deasserted at the end. This has lead to the need for some
69 * conditions surrounding dummy writes to avoid timing disruption. */
70static uint8_t spisd_send_cmd(uint8_t cmd, uint32_t arg)
71{
72 uint8_t response = 0xFF;
73
74 /* avoid disrupting CMD12 alignment */
75 if (cmd != CMD12 && cmd != CMD0)
76 mx_sio2_write_dummy();
77
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));
80
81 /* begin SIO2 PIO TX transfer */
82 mx_sio2_tx_pio(packet, sizeof(packet));
83
84 /* discard extra data on CMD12 */
85 if (cmd == CMD12)
86 mx_sio2_write_dummy();
87
88 /* wait for card to respond */
89 response = mx_sio2_wait_not_equal(0xFF, CMD_WAIT_RESP_TIMEOUT);
90
91 /* avoid disrupting alignment on commands with mutli byte responses */
92 if (cmd != CMD9 && cmd != CMD10 && cmd != CMD13 && cmd != CMD18 && cmd != CMD25) {
93 mx_sio2_write_dummy();
94 }
95
96 return response;
97}
98
99static uint8_t spisd_send_cmd_recv_data(uint8_t cmd, uint32_t arg, uint8_t *data, size_t size)
100{
101 uint8_t response = 0xFF;
102
103 mx_sio2_write_dummy();
104
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));
107
108 /* begin SIO2 PIO TX transfer */
109 mx_sio2_tx_pio(packet, sizeof(packet));
110
111 /* wait for card to respond */
112 response = mx_sio2_wait_not_equal(0xFF, CMD_WAIT_RESP_TIMEOUT);
113 if (response != 0xFF) {
114 /* start SIO2 PIO RX transfer */
115 mx_sio2_rx_pio(data, size);
116 }
117
118 mx_sio2_write_dummy();
119
120 return response;
121}
122
123static uint8_t spisd_read_register(uint8_t *buff, uint32_t len)
124{
125 uint8_t results = SPISD_RESULT_ERROR;
126
127 results = mx_sio2_wait_equal(0xFE, 2000);
128 if (results == SPISD_RESULT_OK) {
129 /* got read token, start SIO2 PIO RX transfer */
130 mx_sio2_rx_pio(buff, len);
131 }
132
133 return results;
134}
135
136/* TODO: use this to verify writes */
137uint16_t spisd_read_status_register()
138{
139 uint16_t response;
140
141 response = spisd_send_cmd(CMD13, 0) << 8;
142 response |= mx_sio2_write_dummy();
143
144 mx_sio2_write_dummy();
145
146 return response;
147}
148
149int spisd_init_card()
150{
151 uint16_t timeout = WAIT_IDLE_TIMEOUT;
152 uint8_t response = 0;
153 uint8_t buffer[6];
154
155 /* set baud to (400kHZ) for init */
156 mx_sio2_set_baud(SIO2_BAUD_DIV_SLOW);
157
158 /* send at least 74 dummy clocks */
159 /*
160 uint8_t dummy_clks[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
161 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
162
163 mx_sio2_tx_pio(dummy_clks, 10);*/
164
165 for (int i = 0; i < 16; i++) {
166 mx_sio2_write_dummy();
167 }
168
169 do {
170 response = spisd_send_cmd(CMD0, 0);
171 timeout--;
172 } while ((response != SPISD_R1_IDLE_FLAG) && timeout > 0);
173
174 if (!timeout) {
175 M_DEBUG("ERROR: CMD0 returned 0x%x, exp: 0x1\n", response);
176 return SPISD_RESULT_TIMEOUT;
177 }
178
179 /* send CMD8 with check pattern, store R3 response in buffer */
180 response = spisd_send_cmd_recv_data(CMD8, 0x1AA, buffer, sizeof(buffer));
181
182 /* if CMD8 response is idle, card is CSD v2 */
183 if (response == SPISD_R1_IDLE_FLAG) {
184
185 /* valid check pattern */
186 if (buffer[2] == 0x01 && buffer[3] == 0xAA) {
187 /* CMD55 / ACMD41 pairs */
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;
193 }
194
195 response = spisd_send_cmd(ACMD41, 0x40000000);
196 if (response == 0x00) {
197 break;
198 }
199 }
200
201 if (response != 0x00) {
202 M_DEBUG("ERROR: ACMD41 returned 0x%x, exp: 0x1\n", response);
203 return SPISD_RESULT_TIMEOUT;
204 }
205
206 /* read OCR by CMD58 */
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;
211 }
212
213 /* OCR -> CCS(bit30) 1: SDV2HC 0: SDV2 */
214 sdcard.card_type = (buffer[0] & 0x40) ? CARD_TYPE_SDV2HC : CARD_TYPE_SDV2;
215
216 /* set baud to 25MHz */
217 mx_sio2_set_baud(SIO2_BAUD_DIV_FAST);
218
219 } else {
220 M_DEBUG("ERROR: CMD8 check pattern failed, got 0x%x, 0x%x\n", buffer[2], buffer[3]);
221 return SPISD_RESULT_ERROR;
222 }
223
224 /* if CMD8 response is illegal, card is CSD v1 / MMC */
225 } else if (response & SPISD_R1_ILLEGAL_CMD_FLAG) {
226 M_DEBUG("CMD8 illegal, trying CSD v1.0 init\n");
227
228 /* end of CMD8, dummy write */
229 mx_sio2_write_dummy();
230
231 /* CMD55 / ACMD41 pairs */
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;
237 }
238
239 response = spisd_send_cmd(ACMD41, 0);
240 if (response == 0x00) {
241 break;
242 }
243 }
244
245 /* no response to CMD55 / ACMD41 means MMC card */
246 if (response != 0x00) {
247 for (int i = 0; i < 0xFFF; i++) {
248 response = spisd_send_cmd(CMD1, 0);
249 if (response == 0x00) {
250 break;
251 }
252 }
253
254 if (response != 0x00) {
255 M_DEBUG("ERROR: CMD1 returned 0x%x, exp 0x0\n", response);
256 return SPISD_RESULT_TIMEOUT;
257 }
258
259 sdcard.card_type = CARD_TYPE_MMC;
260 M_DEBUG("Card Type : MMC\r\n");
261 } else {
262 sdcard.card_type = CARD_TYPE_SDV1;
263 M_DEBUG("Card Type : CSD v1\r\n");
264 }
265
266 /* set baud to 25MHz */
267 mx_sio2_set_baud(SIO2_BAUD_DIV_FAST);
268
269 /* CRC disable */
270 response = spisd_send_cmd(CMD59, 0);
271
272 if (response != 0x00) {
273 M_DEBUG("Send CMD59 should return 0x00, response=0x%02x\r\n", response);
274 return SPISD_RESULT_TIMEOUT;
275 }
276
277 /* set the block size */
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;
282 }
283
284 /* CMD8 response invalid */
285 } else {
286 M_DEBUG("ERROR: CMD8 returned 0x%x, exp 0x1 or 0x4\n", response);
287 return SPISD_RESULT_ERROR;
288 }
289
290 return SPISD_RESULT_OK;
291}
292
293/* get card info and attach to bdm driver */
294int spisd_get_card_info()
295{
296 /* 16 bytes + 2 byte CRC16 */
297 uint8_t reg_data[18];
298
299 /* send CMD9, read CSD */
300 uint8_t result = spisd_send_cmd(CMD9, 0);
301 if (result != 0x0) {
302 return result;
303 }
304
305 result = spisd_read_register(sdcard.csd, sizeof(reg_data));
306
307 /* dummy write between reg reads */
308 mx_sio2_write_dummy();
309
310 if (result != 0x0) {
311 return SPISD_RESULT_ERROR;
312 }
313
314 /* send CMD10, read CID */
315 result = spisd_send_cmd(CMD10, 0);
316
317 if (result != 0x0) {
318 return SPISD_RESULT_ERROR;
319 }
320
321 result = spisd_read_register(reg_data, sizeof(reg_data));
322
323 mx_sio2_write_dummy();
324
325 if (result != 0x0) {
326 return SPISD_RESULT_ERROR;
327 }
328
329 sdcard.cid.ManufacturerID = reg_data[0];
330 /* Byte 1 */
331 sdcard.cid.OEM_AppliID = reg_data[1] << 8;
332 /* Byte 2 */
333 sdcard.cid.OEM_AppliID |= reg_data[2];
334 /* Byte 3 */
335 sdcard.cid.ProdName1 = reg_data[3] << 24;
336 /* Byte 4 */
337 sdcard.cid.ProdName1 |= reg_data[4] << 16;
338 /* Byte 5 */
339 sdcard.cid.ProdName1 |= reg_data[5] << 8;
340 /* Byte 6 */
341 sdcard.cid.ProdName1 |= reg_data[6];
342 /* Byte 7 */
343 sdcard.cid.ProdName2 = reg_data[7];
344 /* Byte 8 */
345 sdcard.cid.ProdRev = reg_data[8];
346 /* Byte 9 */
347 sdcard.cid.ProdSN = reg_data[9] << 24;
348 /* Byte 10 */
349 sdcard.cid.ProdSN |= reg_data[10] << 16;
350 /* Byte 11 */
351 sdcard.cid.ProdSN |= reg_data[11] << 8;
352 /* Byte 12 */
353 sdcard.cid.ProdSN |= reg_data[12];
354 /* Byte 13 */
355 sdcard.cid.Reserved1 |= (reg_data[13] & 0xF0) >> 4;
356 /* Byte 14 */
357 sdcard.cid.ManufactDate = (reg_data[13] & 0x0F) << 8;
358 /* Byte 15 */
359 sdcard.cid.ManufactDate |= reg_data[14];
360 /* Byte 16 */
361 sdcard.cid.CID_CRC = (reg_data[15] & 0xFE) >> 1;
362
363 struct t_csdVer1 *csdv1 = (struct t_csdVer1 *)sdcard.csd;
364 struct t_csdVer2 *csdv2 = (struct t_csdVer2 *)sdcard.csd;
365
366 /* CSD v1 - SDSC */
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;
373
374 bd.sectorCount = capacity / 512;
375
376 /* CSD v2 - SDHC, SDXC */
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;
380 }
381
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));
383
384 return SPISD_RESULT_OK;
385}
386
387int spisd_recover()
388{
389 int rv;
390 /* flush 256 bytes */
391 for (int i = 0; i < 64; i++)
392 mx_sio2_rx_pio((void *)&rv, 4);
393
394 if (spisd_init_card() != SPISD_RESULT_OK) {
395 M_DEBUG("recovery failed to reinit card!\n");
396 return SPISD_RESULT_ERROR;
397 }
398
399 if (spisd_get_card_info() != SPISD_RESULT_OK) {
400 M_DEBUG("recovery failed to get card info!\n");
401 return SPISD_RESULT_ERROR;
402 }
403
404 return SPISD_RESULT_OK;
405}
406
407/* read functions */
408static int spisd_read_multi_begin(uint32_t sector)
409{
410 uint8_t results = SPISD_RESULT_ERROR;
411 /* get idle */
412 results = mx_sio2_wait_equal(0xFF, 4000);
413
414 if (results == SPISD_RESULT_OK) {
415 /* non SDHC/SDXC are addressed in 1-byte units */
416 if (sdcard.card_type != CARD_TYPE_SDV2HC) {
417 sector = sector << 9;
418 }
419
420 /* send CMD18 to being multi block read */
421 results = spisd_send_cmd(CMD18, sector);
422 if (results == SPISD_RESULT_OK) {
423 /* wait for first read token (0xFE) */
424 results = mx_sio2_wait_equal(0xFE, 100000);
425 }
426 }
427
428 return results;
429}
430
431static int spisd_read_multi_do(void *buffer, uint16_t count)
432{
433 /* setup DMA cmd struct */
434 cmd.buffer = buffer;
435 cmd.sector_count = count;
436 cmd.sectors_transferred = 0;
437 cmd.sectors_reversed = 0;
438 cmd.response = SPISD_RESULT_OK;
439 cmd.abort = 0;
440
441 /* start first DMA transfer */
442 mx_sio2_start_rx_dma(buffer);
443
444 /* process events from DMA completion interrupt */
445 while (1) {
446 uint32_t resbits;
447
448 WaitEventFlag(sio2_event_flag, EF_SIO2_INTR_REVERSE | EF_SIO2_INTR_COMPLETE, 1, &resbits);
449
450 if (resbits & EF_SIO2_INTR_REVERSE) {
451 ClearEventFlag(sio2_event_flag, ~EF_SIO2_INTR_REVERSE);
452
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);
456
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) {
461 // CRC mismatch:
462 // - Signal ISR to stop reading
463 // - Wait for complete event from ISR
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;
466 }
467#endif
468 if (cmd.abort == 0)
469 cmd.sectors_reversed++;
470 }
471 }
472
473 if (resbits & EF_SIO2_INTR_COMPLETE) {
474 ClearEventFlag(sio2_event_flag, ~EF_SIO2_INTR_COMPLETE);
475 break;
476 }
477 }
478
479 return cmd.sectors_reversed;
480}
481
482static void spisd_read_multi_end()
483{
484 /* 0xFE token will be received in the ISR prior to this function being called
485 * ensuring the start of CMD12 is aligned with the end of 0xFE
486 * See 7.5.2.2 Stop Transmission Timing of the SD Physical Layer Specification
487 * for more details */
488 spisd_send_cmd(CMD12, 0);
489}
490
491/* write functions */
492static int spisd_write_multi_begin(uint32_t sector, uint16_t count)
493{
494 uint8_t results = SPISD_RESULT_ERROR;
495
496 /* get idle */
497 results = mx_sio2_wait_equal(0xFF, 4000);
498
499 if (results == SPISD_RESULT_OK) {
500 /* non SDHC/SDXC are addressed in 1-byte units */
501 if (sdcard.card_type != CARD_TYPE_SDV2HC) {
502 sector = sector << 9;
503 }
504
505 /* issue ACMD23 to pre-erase sectors on non MMC cards */
506 if (sdcard.card_type != CARD_TYPE_MMC) {
507 results = spisd_send_cmd(CMD55, 0);
508 results = spisd_send_cmd(ACMD23, count);
509 }
510
511 /* send CMD25 to begin multi block write */
512 results = spisd_send_cmd(CMD25, sector);
513 }
514
515 mx_sio2_write_dummy();
516 mx_sio2_write_dummy();
517 mx_sio2_write_dummy();
518
519 return results;
520}
521
522static int spisd_write_multi_do(void* buffer, uint16_t count)
523{
524 uint32_t resbits;
525
526 /* setup DMA cmd struct */
527 cmd.buffer = buffer;
528 cmd.sector_count = count;
529 cmd.sectors_transferred = 0;
530 cmd.sectors_reversed = 0;
531 cmd.response = SPISD_RESULT_OK;
532 cmd.abort = 0;
533
534 /* send initial write token */
535 mx_sio2_write_byte(0xFC);
536
537 /* start transfer */
538 mx_sio2_start_tx_dma(buffer);
539
540 /* wait for transfer to complete */
541 WaitEventFlag(sio2_event_flag, EF_SIO2_INTR_COMPLETE, 1, &resbits);
542
543 if (resbits & EF_SIO2_INTR_COMPLETE) {
544 ClearEventFlag(sio2_event_flag, ~EF_SIO2_INTR_COMPLETE);
545 }
546
547 return cmd.sectors_transferred;
548}
549
550static int spisd_write_multi_end()
551{
552 uint8_t results = SPISD_RESULT_ERROR;
553
554 /* issue stop transmission token */
555 results = mx_sio2_write_byte(0xFD);
556 if (results != 0x0) {
557 mx_sio2_write_dummy();
558 mx_sio2_write_dummy();
559
560 /* give card time to finish programming */
561 results = mx_sio2_wait_equal(0xFF, 0x800000);
562 if (results == SPISD_RESULT_OK) {
563 mx_sio2_write_dummy();
564 mx_sio2_write_dummy();
565 }
566 } else {
567 M_DEBUG("ERROR: failed to end write, 0xFD response 0x%x\n", results);
568 }
569
570 mx_sio2_write_dummy();
571
572 return results;
573}
574
575/*
576 * BDM interface:
577 * - BDM -> "spisd" library
578 */
579int spisd_read(struct block_device *bd, uint64_t sector, void *buffer, uint16_t count)
580{
581 uint16_t sectors_left = count;
582 uint16_t results = 0;
583 uint16_t retries = 0;
584
585 (void)bd;
586
587 if (count == 0)
588 return 0;
589
590 M_DEBUG("%s: sector %i, count: %i \n", __FUNCTION__, (u32)sector, count);
591
592 mx_sio2_lock(INTR_RX);
593
594 while (sectors_left > 0 && retries < MAX_RETRIES) {
595
596 /* issue CMD18 to begin transfer */
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");
600 break;
601 }
602
603 /* start reading blocks */
604 results = spisd_read_multi_do(buffer, sectors_left);
605 sectors_left = sectors_left - results;
606
607 /* fail condition */
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);
611
612 if (cmd.abort == CMD_ABORT_NO_READ_TOKEN) {
613 /* this can only be resolved by resetting the card */
614 if (spisd_recover() != SPISD_RESULT_OK) {
615 /* if recovery fails, do not try to continue */
616 break;
617 }
618 }
619 }
620 /* send CMD12, end transfer */
621 spisd_read_multi_end();
622
623 retries++;
624 }
625
626 sdcard.used = 1;
627
628 mx_sio2_unlock(INTR_RX);
629
630 return count - sectors_left;
631}
632
633int spisd_write(struct block_device *bd, uint64_t sector, const void *buffer, uint16_t count)
634{
635 (void)bd;
636
637 uint16_t sectors_left = count;
638 uint16_t results = 0;
639 uint16_t retries = 0;
640
641 if (count == 0)
642 return 0;
643
644 M_DEBUG("%s: sector %i, count: %i \n", __FUNCTION__, (u32)sector, count);
645
646 /* recast */
647 void *write_buffer = (uint32_t*)buffer;
648
649 /* pre-reverse the entire buffer */
650 reverse_buffer(write_buffer, ((count * SECTOR_SIZE) / 4));
651
652 mx_sio2_lock(INTR_TX);
653
654 while (sectors_left > 0 && retries < MAX_RETRIES) {
655
656 /* issue CMD25 to begin transfer */
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");
660 break;
661 }
662
663 /* start writing blocks */
664 results = spisd_write_multi_do(write_buffer, sectors_left);
665 sectors_left = sectors_left - results;
666
667 /* fail condition */
668 if (sectors_left > 0) {
669 write_buffer = (uint8_t *)write_buffer + (results * 512); /* update buffer for next attempt */
670 M_DEBUG("ERROR: failed to write all sectors, wrote: %i\n", results);
671 }
672
673 /* send 0xFD, end transfer */
674 results = spisd_write_multi_end();
675 if (results != SPISD_RESULT_OK) {
676 M_DEBUG("ERROR: failed to end multi-block write\n");
677 break;
678 }
679
680 retries++;
681 }
682
683 sdcard.used = 1;
684
685 mx_sio2_unlock(INTR_TX);
686
687 return count - sectors_left;
688}
689
690void spisd_flush(struct block_device *bd)
691{
692 (void)bd;
693 return;
694}
695
696int spisd_stop(struct block_device *bd)
697{
698 (void)bd;
699 return 0;
700}
u32 count
start sector of fragmented bd/file