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