Use DMA for SCSI and SD card transfers for a massive performance boost.
[SCSI2SD.git] / software / SCSI2SD / src / sd.c
1 //      Copyright (C) 2013 Michael McMaster <michael@codesrc.com>\r
2 //\r
3 //      This file is part of SCSI2SD.\r
4 //\r
5 //      SCSI2SD is free software: you can redistribute it and/or modify\r
6 //      it under the terms of the GNU General Public License as published by\r
7 //      the Free Software Foundation, either version 3 of the License, or\r
8 //      (at your option) any later version.\r
9 //\r
10 //      SCSI2SD is distributed in the hope that it will be useful,\r
11 //      but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 //      GNU General Public License for more details.\r
14 //\r
15 //      You should have received a copy of the GNU General Public License\r
16 //      along with SCSI2SD.  If not, see <http://www.gnu.org/licenses/>.\r
17 \r
18 #include "device.h"\r
19 #include "scsi.h"\r
20 #include "config.h"\r
21 #include "disk.h"\r
22 #include "sd.h"\r
23 #include "led.h"\r
24 \r
25 #include "scsiPhy.h"\r
26 \r
27 #include <string.h>\r
28 \r
29 // Global\r
30 SdDevice sdDev;\r
31 \r
32 // Private DMA variables.\r
33 static int dmaInProgress = 0;\r
34 static uint8 sdDMARxChan = CY_DMA_INVALID_CHANNEL;\r
35 static uint8 sdDMATxChan = CY_DMA_INVALID_CHANNEL;\r
36 \r
37 // DMA descriptors\r
38 static uint8 sdDMARxTd[1] = { CY_DMA_INVALID_TD };\r
39 static uint8 sdDMATxTd[1] = { CY_DMA_INVALID_TD };\r
40 \r
41 // Dummy location for DMA to send unchecked CRC bytes to\r
42 static uint8 discardBuffer;\r
43 \r
44 // Source of dummy SPI bytes for DMA\r
45 static uint8 dummyBuffer = 0xFF;\r
46 \r
47 volatile static uint8 rxDMAComplete;\r
48 volatile static uint8 txDMAComplete;\r
49 \r
50 CY_ISR_PROTO(sdRxISR);\r
51 CY_ISR(sdRxISR)\r
52 {\r
53         rxDMAComplete = 1;\r
54 }\r
55 CY_ISR_PROTO(sdTxISR);\r
56 CY_ISR(sdTxISR)\r
57 {\r
58         txDMAComplete = 1;\r
59 }\r
60 \r
61 static uint8 sdCrc7(uint8* chr, uint8 cnt, uint8 crc)\r
62 {\r
63         uint8 a;\r
64         for(a = 0; a < cnt; a++)\r
65         {\r
66                 uint8 Data = chr[a];\r
67                 uint8 i;\r
68                 for(i = 0; i < 8; i++)\r
69                 {\r
70                         crc <<= 1;\r
71                         if( (Data & 0x80) ^ (crc & 0x80) ) {crc ^= 0x09;}\r
72                         Data <<= 1;\r
73                 }\r
74         }\r
75         return crc & 0x7F;\r
76 }\r
77 \r
78 // Read and write 1 byte.\r
79 static uint8 sdSpiByte(uint8 value)\r
80 {\r
81         SDCard_WriteTxData(value);\r
82         while (!(SDCard_ReadRxStatus() & SDCard_STS_RX_FIFO_NOT_EMPTY)) {}\r
83         return SDCard_ReadRxData();\r
84 }\r
85 \r
86 static void sdSendCRCCommand(uint8 cmd, uint32 param)\r
87 {\r
88         uint8 send[6];\r
89 \r
90         send[0] = cmd | 0x40;\r
91         send[1] = param >> 24;\r
92         send[2] = param >> 16;\r
93         send[3] = param >> 8;\r
94         send[4] = param;\r
95         send[5] = (sdCrc7(send, 5, 0) << 1) | 1;\r
96 \r
97         for(cmd = 0; cmd < sizeof(send); cmd++)\r
98         {\r
99                 sdSpiByte(send[cmd]);\r
100         }\r
101         // Allow command to process before reading result code.\r
102         sdSpiByte(0xFF);\r
103 }\r
104 \r
105 static void sdSendCommand(uint8 cmd, uint32 param)\r
106 {\r
107         uint8 send[6];\r
108 \r
109         send[0] = cmd | 0x40;\r
110         send[1] = param >> 24;\r
111         send[2] = param >> 16;\r
112         send[3] = param >> 8;\r
113         send[4] = param;\r
114         send[5] = 0;\r
115 \r
116         for(cmd = 0; cmd < sizeof(send); cmd++)\r
117         {\r
118                 sdSpiByte(send[cmd]);\r
119         }\r
120         // Allow command to process before reading result code.\r
121         sdSpiByte(0xFF);\r
122 }\r
123 \r
124 static uint8 sdReadResp()\r
125 {\r
126         uint8 v;\r
127         uint8 i = 128;\r
128         do\r
129         {\r
130                 v = sdSpiByte(0xFF);\r
131         } while(i-- && (v & 0x80));\r
132         return v;\r
133 }\r
134 \r
135 static uint8 sdCommandAndResponse(uint8 cmd, uint32 param)\r
136 {\r
137         sdSpiByte(0xFF);\r
138         sdSendCommand(cmd, param);\r
139         return sdReadResp();\r
140 }\r
141 \r
142 static uint8 sdCRCCommandAndResponse(uint8 cmd, uint32 param)\r
143 {\r
144         sdSpiByte(0xFF);\r
145         sdSendCRCCommand(cmd, param);\r
146         return sdReadResp();\r
147 }\r
148 \r
149 // Clear the sticky status bits on error.\r
150 static void sdClearStatus()\r
151 {\r
152         uint8 r2hi = sdCRCCommandAndResponse(SD_SEND_STATUS, 0);\r
153         uint8 r2lo = sdSpiByte(0xFF);\r
154         (void) r2hi; (void) r2lo;\r
155 }\r
156 \r
157 \r
158 void\r
159 sdReadMultiSectorPrep()\r
160 {\r
161         uint8 v;\r
162         uint32 scsiLBA = (transfer.lba + transfer.currentBlock);\r
163         uint32 sdLBA = SCSISector2SD(scsiLBA);\r
164 \r
165         if (!sdDev.ccs)\r
166         {\r
167                 sdLBA = sdLBA * SD_SECTOR_SIZE;\r
168         }\r
169         v = sdCommandAndResponse(SD_READ_MULTIPLE_BLOCK, sdLBA);\r
170         if (v)\r
171         {\r
172                 scsiDiskReset();\r
173                 sdClearStatus();\r
174 \r
175                 scsiDev.status = CHECK_CONDITION;\r
176                 scsiDev.sense.code = HARDWARE_ERROR;\r
177                 scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
178                 scsiDev.phase = STATUS;\r
179         }\r
180         else\r
181         {\r
182                 transfer.inProgress = 1;\r
183         }\r
184 }\r
185 \r
186 static void\r
187 dmaReadSector(uint8_t* outputBuffer)\r
188 {\r
189         // Wait for a start-block token.\r
190         // Don't wait more than 100ms, which is the timeout recommended\r
191         // in the standard.\r
192         //100ms @ 64Hz = 6400000\r
193         int maxWait = 6400000;\r
194         uint8 token = sdSpiByte(0xFF);\r
195         while (token != 0xFE && (maxWait-- > 0))\r
196         {\r
197                 token = sdSpiByte(0xFF);\r
198         }\r
199         if (token != 0xFE)\r
200         {\r
201                 if (transfer.multiBlock)\r
202                 {\r
203                         sdCompleteRead();\r
204                 }\r
205                 if (scsiDev.status != CHECK_CONDITION)\r
206                 {\r
207                         scsiDev.status = CHECK_CONDITION;\r
208                         scsiDev.sense.code = HARDWARE_ERROR;\r
209                         scsiDev.sense.asc = UNRECOVERED_READ_ERROR;\r
210                         scsiDev.phase = STATUS;\r
211                 }\r
212                 return;\r
213         }\r
214 \r
215         CyDmaTdSetConfiguration(sdDMARxTd[0], SD_SECTOR_SIZE, CY_DMA_DISABLE_TD, TD_INC_DST_ADR | SD_RX_DMA__TD_TERMOUT_EN);\r
216         CyDmaTdSetAddress(sdDMARxTd[0], LO16((uint32)SDCard_RXDATA_PTR), LO16((uint32)outputBuffer));\r
217         CyDmaTdSetConfiguration(sdDMATxTd[0], SD_SECTOR_SIZE, CY_DMA_DISABLE_TD, SD_TX_DMA__TD_TERMOUT_EN);\r
218         CyDmaTdSetAddress(sdDMATxTd[0], LO16((uint32)&dummyBuffer), LO16((uint32)SDCard_TXDATA_PTR));\r
219 \r
220         dmaInProgress = 1;\r
221         // The DMA controller is a bit trigger-happy. It will retain\r
222         // a drq request that was triggered while the channel was\r
223         // disabled.\r
224         CyDmaClearPendingDrq(sdDMATxChan);\r
225         CyDmaClearPendingDrq(sdDMARxChan);\r
226 \r
227         txDMAComplete = 0;\r
228         rxDMAComplete = 0;\r
229 \r
230         // Re-loading the initial TD's here is very important, or else\r
231         // we'll be re-using the last-used TD, which would be the last\r
232         // in the chain (ie. CRC TD)\r
233         CyDmaChSetInitialTd(sdDMARxChan, sdDMARxTd[0]);\r
234         CyDmaChSetInitialTd(sdDMATxChan, sdDMATxTd[0]);\r
235 \r
236         // There is no flow control, so we must ensure we can read the bytes\r
237         // before we start transmitting\r
238         CyDmaChEnable(sdDMARxChan, 1);\r
239         CyDmaChEnable(sdDMATxChan, 1);\r
240 }\r
241 \r
242 int\r
243 sdReadSectorDMAPoll()\r
244 {\r
245         if (rxDMAComplete && txDMAComplete)\r
246         {\r
247                 // DMA transfer is complete\r
248                 dmaInProgress = 0;\r
249 \r
250                 sdSpiByte(0xFF); // CRC\r
251                 sdSpiByte(0xFF); // CRC\r
252 \r
253                 return 1;\r
254         }\r
255         else\r
256         {\r
257                 return 0;\r
258         }\r
259 }\r
260 \r
261 void sdReadSingleSectorDMA(uint32_t lba, uint8_t* outputBuffer)\r
262 {\r
263         uint8 v;\r
264         if (!sdDev.ccs)\r
265         {\r
266                 lba = lba * SD_SECTOR_SIZE;\r
267         }\r
268         v = sdCommandAndResponse(SD_READ_SINGLE_BLOCK, lba);\r
269         if (v)\r
270         {\r
271                 scsiDiskReset();\r
272                 sdClearStatus();\r
273 \r
274                 scsiDev.status = CHECK_CONDITION;\r
275                 scsiDev.sense.code = HARDWARE_ERROR;\r
276                 scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
277                 scsiDev.phase = STATUS;\r
278         }\r
279         else\r
280         {\r
281                 dmaReadSector(outputBuffer);\r
282         }\r
283 }\r
284 \r
285 void\r
286 sdReadMultiSectorDMA(uint8_t* outputBuffer)\r
287 {\r
288         // Pre: sdReadMultiSectorPrep called.\r
289         dmaReadSector(outputBuffer);\r
290 }\r
291 \r
292 \r
293 void sdCompleteRead()\r
294 {\r
295         if (dmaInProgress)\r
296         {\r
297                 // Not much choice but to wait until we've completed the transfer.\r
298                 // Cancelling the transfer can't be done as we have no way to reset\r
299                 // the SD card.\r
300                 while (!sdReadSectorDMAPoll()) { /* spin */ }\r
301         }\r
302 \r
303         transfer.inProgress = 0;\r
304 \r
305         // We cannot send even a single "padding" byte, as we normally would when\r
306         // sending a command.  If we've just finished reading the very last block\r
307         // on the card, then reading an additional dummy byte will just trigger\r
308         // an error condition as we're trying to read past-the-end of the storage\r
309         // device.\r
310         // ie. do not use sdCommandAndResponse here.\r
311         uint8 r1b;\r
312         sdSendCommand(SD_STOP_TRANSMISSION, 0);\r
313         r1b = sdReadResp();\r
314 \r
315         if (r1b)\r
316         {\r
317                 // Try very hard to make sure the transmission stops\r
318                 int retries = 255;\r
319                 while (r1b && retries)\r
320                 {\r
321                         r1b = sdCommandAndResponse(SD_STOP_TRANSMISSION, 0);\r
322                         retries--;\r
323                 }\r
324 \r
325                 scsiDev.status = CHECK_CONDITION;\r
326                 scsiDev.sense.code = HARDWARE_ERROR;\r
327                 scsiDev.sense.asc = UNRECOVERED_READ_ERROR;\r
328                 scsiDev.phase = STATUS;\r
329         }\r
330 \r
331         // R1b has an optional trailing "busy" signal.\r
332         {\r
333                 uint8 busy;\r
334                 do\r
335                 {\r
336                         busy = sdSpiByte(0xFF);\r
337                 } while (busy == 0);\r
338         }\r
339 }\r
340 \r
341 static void sdWaitWriteBusy()\r
342 {\r
343         uint8 val;\r
344         do\r
345         {\r
346                 val = sdSpiByte(0xFF);\r
347         } while (val != 0xFF);\r
348 }\r
349 \r
350 void\r
351 sdWriteMultiSectorDMA(uint8_t* outputBuffer)\r
352 {\r
353         sdSpiByte(0xFC); // MULTIPLE byte start token\r
354 \r
355         CyDmaTdSetConfiguration(sdDMATxTd[0], SD_SECTOR_SIZE, CY_DMA_DISABLE_TD, TD_INC_SRC_ADR | SD_TX_DMA__TD_TERMOUT_EN);\r
356         CyDmaTdSetAddress(sdDMATxTd[0], LO16((uint32)outputBuffer), LO16((uint32)SDCard_TXDATA_PTR));\r
357         CyDmaTdSetConfiguration(sdDMARxTd[0], SD_SECTOR_SIZE, CY_DMA_DISABLE_TD, SD_RX_DMA__TD_TERMOUT_EN);\r
358         CyDmaTdSetAddress(sdDMARxTd[0], LO16((uint32)SDCard_RXDATA_PTR), LO16((uint32)&discardBuffer));\r
359         \r
360         dmaInProgress = 1;\r
361         // The DMA controller is a bit trigger-happy. It will retain\r
362         // a drq request that was triggered while the channel was\r
363         // disabled.\r
364         CyDmaClearPendingDrq(sdDMATxChan);\r
365         CyDmaClearPendingDrq(sdDMARxChan);\r
366 \r
367         txDMAComplete = 0;\r
368         rxDMAComplete = 0;\r
369 \r
370         // Re-loading the initial TD's here is very important, or else\r
371         // we'll be re-using the last-used TD, which would be the last\r
372         // in the chain (ie. CRC TD)\r
373         CyDmaChSetInitialTd(sdDMARxChan, sdDMARxTd[0]);\r
374         CyDmaChSetInitialTd(sdDMATxChan, sdDMATxTd[0]);\r
375 \r
376         // There is no flow control, so we must ensure we can read the bytes\r
377         // before we start transmitting\r
378         CyDmaChEnable(sdDMARxChan, 1);\r
379         CyDmaChEnable(sdDMATxChan, 1);\r
380 }\r
381 \r
382 int\r
383 sdWriteSectorDMAPoll()\r
384 {\r
385         if (rxDMAComplete && txDMAComplete)\r
386         {\r
387                 // DMA transfer is complete\r
388                 dmaInProgress = 0;\r
389 \r
390                 sdSpiByte(0x00); // CRC\r
391                 sdSpiByte(0x00); // CRC\r
392 \r
393                 // Don't wait more than 1s.\r
394                 // My 2g Kingston micro-sd card doesn't respond immediately.\r
395                 // My 16Gb card does.\r
396                 int maxWait = 1000000;\r
397                 uint8_t dataToken = sdSpiByte(0xFF); // Response\r
398                 while (dataToken == 0xFF && maxWait-- > 0)\r
399                 {\r
400                         CyDelayUs(1);\r
401                         dataToken = sdSpiByte(0xFF);\r
402                 }\r
403                 if (((dataToken & 0x1F) >> 1) != 0x2) // Accepted.\r
404                 {\r
405                         uint8 r1b, busy;\r
406                 \r
407                         sdWaitWriteBusy();\r
408 \r
409                         r1b = sdCommandAndResponse(SD_STOP_TRANSMISSION, 0);\r
410                         (void) r1b;\r
411                         sdSpiByte(0xFF);\r
412 \r
413                         // R1b has an optional trailing "busy" signal.\r
414                         do\r
415                         {\r
416                                 busy = sdSpiByte(0xFF);\r
417                         } while (busy == 0);\r
418 \r
419                         // Wait for the card to come out of busy.\r
420                         sdWaitWriteBusy();\r
421 \r
422                         transfer.inProgress = 0;\r
423                         scsiDiskReset();\r
424                         sdClearStatus();\r
425 \r
426                         scsiDev.status = CHECK_CONDITION;\r
427                         scsiDev.sense.code = HARDWARE_ERROR;\r
428                         scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
429                         scsiDev.phase = STATUS;\r
430                 }\r
431                 else\r
432                 {\r
433                         sdWaitWriteBusy();\r
434                 }               \r
435 \r
436                 return 1;\r
437         }\r
438         else\r
439         {\r
440                 return 0;\r
441         }\r
442 }\r
443 \r
444 void sdCompleteWrite()\r
445 {\r
446         if (dmaInProgress)\r
447         {\r
448                 // Not much choice but to wait until we've completed the transfer.\r
449                 // Cancelling the transfer can't be done as we have no way to reset\r
450                 // the SD card.\r
451                 while (!sdWriteSectorDMAPoll()) { /* spin */ }\r
452         }\r
453         \r
454         transfer.inProgress = 0;\r
455 \r
456         uint8 r1, r2;\r
457 \r
458         sdSpiByte(0xFD); // STOP TOKEN\r
459         // Wait for the card to come out of busy.\r
460         sdWaitWriteBusy();\r
461 \r
462         r1 = sdCommandAndResponse(13, 0); // send status\r
463         r2 = sdSpiByte(0xFF);\r
464         if (r1 || r2)\r
465         {\r
466                 sdClearStatus();\r
467                 scsiDev.status = CHECK_CONDITION;\r
468                 scsiDev.sense.code = HARDWARE_ERROR;\r
469                 scsiDev.sense.asc = WRITE_ERROR_AUTO_REALLOCATION_FAILED;\r
470                 scsiDev.phase = STATUS;\r
471         }\r
472 }\r
473 \r
474 \r
475 // SD Version 2 (SDHC) support\r
476 static int sendIfCond()\r
477 {\r
478         int retries = 50;\r
479 \r
480         do\r
481         {\r
482                 uint8 status = sdCRCCommandAndResponse(SD_SEND_IF_COND, 0x000001AA);\r
483 \r
484                 if (status == SD_R1_IDLE)\r
485                 {\r
486                         // Version 2 card.\r
487                         sdDev.version = 2;\r
488                         // Read 32bit response. Should contain the same bytes that\r
489                         // we sent in the command parameter.\r
490                         sdSpiByte(0xFF);\r
491                         sdSpiByte(0xFF);\r
492                         sdSpiByte(0xFF);\r
493                         sdSpiByte(0xFF);\r
494                         break;\r
495                 }\r
496                 else if (status & SD_R1_ILLEGAL)\r
497                 {\r
498                         // Version 1 card.\r
499                         sdDev.version = 1;\r
500                         sdClearStatus();\r
501                         break;\r
502                 }\r
503 \r
504                 sdClearStatus();\r
505         } while (--retries > 0);\r
506 \r
507         return retries > 0;\r
508 }\r
509 \r
510 static int sdOpCond()\r
511 {\r
512         int retries = 50;\r
513 \r
514         uint8 status;\r
515         do\r
516         {\r
517                 CyDelay(33); // Spec says to retry for 1 second.\r
518 \r
519                 sdCRCCommandAndResponse(SD_APP_CMD, 0);\r
520                 // Host Capacity Support = 1 (SDHC/SDXC supported)\r
521                 status = sdCRCCommandAndResponse(SD_APP_SEND_OP_COND, 0x40000000);\r
522 \r
523                 sdClearStatus();\r
524         } while ((status != 0) && (--retries > 0));\r
525 \r
526         return retries > 0;\r
527 }\r
528 \r
529 static int sdReadOCR()\r
530 {\r
531         uint8 buf[4];\r
532         int i;\r
533         \r
534         uint8 status = sdCRCCommandAndResponse(SD_READ_OCR, 0);\r
535         if(status){goto bad;}\r
536 \r
537         for (i = 0; i < 4; ++i)\r
538         {\r
539                 buf[i] = sdSpiByte(0xFF);\r
540         }\r
541 \r
542         sdDev.ccs = (buf[0] & 0x40) ? 1 : 0;\r
543 \r
544         return 1;\r
545 bad:\r
546         return 0;\r
547 }\r
548 \r
549 static int sdReadCSD()\r
550 {\r
551         uint8 startToken;\r
552         int maxWait, i;\r
553         uint8 buf[16];\r
554         \r
555         uint8 status = sdCRCCommandAndResponse(SD_SEND_CSD, 0);\r
556         if(status){goto bad;}\r
557 \r
558         maxWait = 1023;\r
559         do\r
560         {\r
561                 startToken = sdSpiByte(0xFF);\r
562         } while(maxWait-- && (startToken != 0xFE));\r
563         if (startToken != 0xFE) { goto bad; }\r
564 \r
565         for (i = 0; i < 16; ++i)\r
566         {\r
567                 buf[i] = sdSpiByte(0xFF);\r
568         }\r
569         sdSpiByte(0xFF); // CRC\r
570         sdSpiByte(0xFF); // CRC\r
571 \r
572         if ((buf[0] >> 6) == 0x00)\r
573         {\r
574                 // CSD version 1\r
575                 // C_SIZE in bits [73:62]\r
576                 uint32 c_size = (((((uint32)buf[6]) & 0x3) << 16) | (((uint32)buf[7]) << 8) | buf[8]) >> 6;\r
577                 uint32 c_mult = (((((uint32)buf[9]) & 0x3) << 8) | ((uint32)buf[0xa])) >> 7;\r
578                 uint32 sectorSize = buf[5] & 0x0F;\r
579                 sdDev.capacity = ((c_size+1) * ((uint64)1 << (c_mult+2)) * ((uint64)1 << sectorSize)) / SD_SECTOR_SIZE;\r
580         }\r
581         else if ((buf[0] >> 6) == 0x01)\r
582         {\r
583                 // CSD version 2\r
584                 // C_SIZE in bits [69:48]\r
585 \r
586                 uint32 c_size =\r
587                         ((((uint32)buf[7]) & 0x3F) << 16) |\r
588                         (((uint32)buf[8]) << 8) |\r
589                         ((uint32)buf[7]);\r
590                 sdDev.capacity = (c_size + 1) * 1024;\r
591         }\r
592         else\r
593         {\r
594                 goto bad;\r
595         }\r
596 \r
597         return 1;\r
598 bad:\r
599         return 0;\r
600 }\r
601 \r
602 static void sdInitDMA()\r
603 {\r
604         // One-time init only.\r
605         if (sdDMATxChan == CY_DMA_INVALID_CHANNEL)\r
606         {\r
607                 sdDMATxChan =\r
608                         SD_TX_DMA_DmaInitialize(\r
609                                 1, // Bytes per burst\r
610                                 1, // request per burst\r
611                                 HI16(CYDEV_SRAM_BASE),\r
612                                 HI16(CYDEV_PERIPH_BASE)\r
613                                 );\r
614 \r
615                 sdDMARxChan =\r
616                         SD_RX_DMA_DmaInitialize(\r
617                                 1, // Bytes per burst\r
618                                 1, // request per burst\r
619                                 HI16(CYDEV_PERIPH_BASE),\r
620                                 HI16(CYDEV_SRAM_BASE)\r
621                                 );\r
622 \r
623                 CyDmaChDisable(sdDMATxChan);\r
624                 CyDmaChDisable(sdDMARxChan);\r
625 \r
626                 sdDMARxTd[0] = CyDmaTdAllocate();\r
627                 sdDMATxTd[0] = CyDmaTdAllocate();\r
628 \r
629                 SD_RX_DMA_COMPLETE_StartEx(sdRxISR);\r
630                 SD_TX_DMA_COMPLETE_StartEx(sdTxISR);\r
631         }\r
632 }\r
633 \r
634 int sdInit()\r
635 {\r
636         int result = 0;\r
637         int i;\r
638         uint8 v;\r
639         \r
640         sdDev.version = 0;\r
641         sdDev.ccs = 0;\r
642         sdDev.capacity = 0;\r
643 \r
644         sdInitDMA();\r
645 \r
646         SD_CS_Write(1); // Set CS inactive (active low)\r
647 \r
648         // Set the SPI clock for 400kHz transfers\r
649         // 25MHz / 400kHz approx factor of 63.\r
650         uint16_t clkDiv25MHz =  SD_Data_Clk_GetDividerRegister();\r
651         SD_Data_Clk_SetDivider(clkDiv25MHz * 63);\r
652         // Wait for the clock to settle.\r
653         CyDelayUs(1);\r
654 \r
655         SDCard_Start(); // Enable SPI hardware\r
656 \r
657         // Power on sequence. 74 clock cycles of a "1" while CS unasserted.\r
658         for (i = 0; i < 10; ++i)\r
659         {\r
660                 sdSpiByte(0xFF);\r
661         }\r
662 \r
663         SD_CS_Write(0); // Set CS active (active low)\r
664         CyDelayUs(1);\r
665 \r
666         v = sdCRCCommandAndResponse(SD_GO_IDLE_STATE, 0);\r
667         if(v != 1){goto bad;}\r
668 \r
669         ledOn();\r
670         if (!sendIfCond()) goto bad; // Sets V1 or V2 flag\r
671         if (!sdOpCond()) goto bad;\r
672         if (!sdReadOCR()) goto bad;\r
673 \r
674         // This command will be ignored if sdDev.ccs is set.\r
675         // SDHC and SDXC are always 512bytes.\r
676         v = sdCRCCommandAndResponse(SD_SET_BLOCKLEN, SD_SECTOR_SIZE); //Force sector size\r
677         if(v){goto bad;}\r
678         v = sdCRCCommandAndResponse(SD_CRC_ON_OFF, 0); //crc off\r
679         if(v){goto bad;}\r
680 \r
681         // now set the sd card back to full speed.\r
682         // The SD Card spec says we can run SPI @ 25MHz\r
683         SDCard_Stop();\r
684 \r
685         // We can't run at full-speed with the pullup resistors enabled.\r
686         SD_MISO_SetDriveMode(SD_MISO_DM_DIG_HIZ);\r
687         SD_MOSI_SetDriveMode(SD_MOSI_DM_STRONG);\r
688         SD_SCK_SetDriveMode(SD_SCK_DM_STRONG);\r
689 \r
690         SD_Data_Clk_SetDivider(clkDiv25MHz);\r
691         CyDelayUs(1);\r
692         SDCard_Start();\r
693 \r
694         // Clear out rubbish data through clock change\r
695         CyDelayUs(1);\r
696         SDCard_ReadRxStatus();\r
697         SDCard_ReadTxStatus();\r
698         SDCard_ClearFIFO();\r
699 \r
700         if (!sdReadCSD()) goto bad;\r
701 \r
702         result = 1;\r
703         goto out;\r
704 \r
705 bad:\r
706         sdDev.capacity = 0;\r
707 \r
708 out:\r
709         sdClearStatus();\r
710         ledOff();\r
711         return result;\r
712 \r
713 }\r
714 \r
715 void sdWriteMultiSectorPrep()\r
716 {\r
717         uint8 v;\r
718         \r
719         // Set the number of blocks to pre-erase by the multiple block write command\r
720         // We don't care about the response - if the command is not accepted, writes\r
721         // will just be a bit slower.\r
722         // Max 22bit parameter.\r
723         uint32_t sdBlocks = transfer.blocks * SDSectorsPerSCSISector();\r
724         uint32 blocks = sdBlocks > 0x7FFFFF ? 0x7FFFFF : sdBlocks;\r
725         sdCommandAndResponse(SD_APP_CMD, 0);\r
726         sdCommandAndResponse(SD_APP_SET_WR_BLK_ERASE_COUNT, blocks);\r
727 \r
728         uint32 scsiLBA = (transfer.lba + transfer.currentBlock);\r
729         uint32 sdLBA = SCSISector2SD(scsiLBA);\r
730         if (!sdDev.ccs)\r
731         {\r
732                 sdLBA = sdLBA * SD_SECTOR_SIZE;\r
733         }\r
734         v = sdCommandAndResponse(25, sdLBA);\r
735         if (v)\r
736         {\r
737                 scsiDiskReset();\r
738                 sdClearStatus();\r
739                 scsiDev.status = CHECK_CONDITION;\r
740                 scsiDev.sense.code = HARDWARE_ERROR;\r
741                 scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
742                 scsiDev.phase = STATUS;\r
743         }\r
744         else\r
745         {\r
746                 transfer.inProgress = 1;\r
747         }\r
748 }\r
749 \r