Added configurable block-size support
[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 static uint8 sdCrc7(uint8* chr, uint8 cnt, uint8 crc)\r
33 {\r
34         uint8 a;\r
35         for(a = 0; a < cnt; a++)\r
36         {\r
37                 uint8 Data = chr[a];\r
38                 uint8 i;\r
39                 for(i = 0; i < 8; i++)\r
40                 {\r
41                         crc <<= 1;\r
42                         if( (Data & 0x80) ^ (crc & 0x80) ) {crc ^= 0x09;}\r
43                         Data <<= 1;\r
44                 }\r
45         }\r
46         return crc & 0x7F;\r
47 }\r
48 \r
49 // Read and write 1 byte.\r
50 static uint8 sdSpiByte(uint8 value)\r
51 {\r
52         SDCard_WriteTxData(value);\r
53         while (!(SDCard_ReadRxStatus() & SDCard_STS_RX_FIFO_NOT_EMPTY)) {}\r
54         return SDCard_ReadRxData();\r
55 }\r
56 \r
57 static void sdSendCRCCommand(uint8 cmd, uint32 param)\r
58 {\r
59         uint8 send[6];\r
60 \r
61         send[0] = cmd | 0x40;\r
62         send[1] = param >> 24;\r
63         send[2] = param >> 16;\r
64         send[3] = param >> 8;\r
65         send[4] = param;\r
66         send[5] = (sdCrc7(send, 5, 0) << 1) | 1;\r
67 \r
68         for(cmd = 0; cmd < sizeof(send); cmd++)\r
69         {\r
70                 sdSpiByte(send[cmd]);\r
71         }\r
72         // Allow command to process before reading result code.\r
73         sdSpiByte(0xFF);\r
74 }\r
75 \r
76 static void sdSendCommand(uint8 cmd, uint32 param)\r
77 {\r
78         uint8 send[6];\r
79 \r
80         send[0] = cmd | 0x40;\r
81         send[1] = param >> 24;\r
82         send[2] = param >> 16;\r
83         send[3] = param >> 8;\r
84         send[4] = param;\r
85         send[5] = 0;\r
86 \r
87         for(cmd = 0; cmd < sizeof(send); cmd++)\r
88         {\r
89                 sdSpiByte(send[cmd]);\r
90         }\r
91         // Allow command to process before reading result code.\r
92         sdSpiByte(0xFF);\r
93 }\r
94 \r
95 static uint8 sdReadResp()\r
96 {\r
97         uint8 v;\r
98         uint8 i = 128;\r
99         do\r
100         {\r
101                 v = sdSpiByte(0xFF);\r
102         } while(i-- && (v & 0x80));\r
103         return v;\r
104 }\r
105 \r
106 static uint8 sdCommandAndResponse(uint8 cmd, uint32 param)\r
107 {\r
108         sdSpiByte(0xFF);\r
109         sdSendCommand(cmd, param);\r
110         return sdReadResp();\r
111 }\r
112 \r
113 static uint8 sdCRCCommandAndResponse(uint8 cmd, uint32 param)\r
114 {\r
115         sdSpiByte(0xFF);\r
116         sdSendCRCCommand(cmd, param);\r
117         return sdReadResp();\r
118 }\r
119 \r
120 // Clear the sticky status bits on error.\r
121 static void sdClearStatus()\r
122 {\r
123         uint8 r2hi = sdCRCCommandAndResponse(SD_SEND_STATUS, 0);\r
124         uint8 r2lo = sdSpiByte(0xFF);\r
125         (void) r2hi; (void) r2lo;\r
126 }\r
127 \r
128 \r
129 void sdPrepareRead()\r
130 {\r
131         uint8 v;\r
132         uint32 scsiLBA = (transfer.lba + transfer.currentBlock);\r
133         uint32 sdLBA = SCSISector2SD(scsiLBA);\r
134         \r
135         if (!sdDev.ccs)\r
136         {\r
137                 sdLBA = sdLBA * SD_SECTOR_SIZE;\r
138         }\r
139         v = sdCommandAndResponse(SD_READ_MULTIPLE_BLOCK, sdLBA);\r
140         if (v)\r
141         {\r
142                 scsiDiskReset();\r
143                 sdClearStatus();\r
144 \r
145                 scsiDev.status = CHECK_CONDITION;\r
146                 scsiDev.sense.code = HARDWARE_ERROR;\r
147                 scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
148                 scsiDev.phase = STATUS;\r
149         }\r
150         else\r
151         {\r
152                 transfer.inProgress = 1;\r
153         }\r
154 }\r
155 \r
156 static void doReadSector(uint32_t numBytes)\r
157 {\r
158         int prep, i, guard;\r
159 \r
160         // Wait for a start-block token.\r
161         // Don't wait more than 100ms, which is the timeout recommended\r
162         // in the standard.\r
163         //100ms @ 64Hz = 6400000\r
164         int maxWait = 6400000;\r
165         uint8 token = sdSpiByte(0xFF);\r
166         while (token != 0xFE && (maxWait-- > 0))\r
167         {\r
168                 token = sdSpiByte(0xFF);\r
169         }\r
170         if (token != 0xFE)\r
171         {\r
172                 if (transfer.multiBlock)\r
173                 {\r
174                         sdCompleteRead();\r
175                 }\r
176                 if (scsiDev.status != CHECK_CONDITION)\r
177                 {\r
178                         scsiDev.status = CHECK_CONDITION;\r
179                         scsiDev.sense.code = HARDWARE_ERROR;\r
180                         scsiDev.sense.asc = UNRECOVERED_READ_ERROR;\r
181                         scsiDev.phase = STATUS;\r
182                 }\r
183                 return;\r
184         }\r
185 \r
186         // Don't do a bus settle delay if we're already in the correct phase.\r
187         if (transfer.currentBlock == 0)\r
188         {\r
189                 scsiEnterPhase(DATA_IN);\r
190         }\r
191 \r
192         // Quickly seed the FIFO\r
193         prep = 4;\r
194         CY_SET_REG8(SDCard_TXDATA_PTR, 0xFF); // Put a byte in the FIFO\r
195         CY_SET_REG8(SDCard_TXDATA_PTR, 0xFF); // Put a byte in the FIFO\r
196         CY_SET_REG8(SDCard_TXDATA_PTR, 0xFF); // Put a byte in the FIFO\r
197         CY_SET_REG8(SDCard_TXDATA_PTR, 0xFF); // Put a byte in the FIFO\r
198 \r
199         i = 0;\r
200         guard = 0;\r
201 \r
202         // This loop is critically important for performance.\r
203         // We stream data straight from the SDCard fifos into the SCSI component\r
204         // FIFO's. If the loop isn't fast enough, the transmit FIFO's will empty,\r
205         // and performance will suffer. Every clock cycle counts.\r
206         while (i < numBytes && !scsiDev.resetFlag)\r
207         {\r
208                 uint8_t sdRxStatus = CY_GET_REG8(SDCard_RX_STATUS_PTR);\r
209                 uint8_t scsiStatus = CY_GET_REG8(scsiTarget_StatusReg__STATUS_REG);\r
210 \r
211                 // Read from the SPIM fifo if there is room to stream the byte to the\r
212                 // SCSI fifos\r
213                 if((sdRxStatus & SDCard_STS_RX_FIFO_NOT_EMPTY) &&\r
214                         (scsiDev.resetFlag || (scsiStatus & 1)) // SCSI TX FIFO NOT FULL\r
215                         )\r
216                 {\r
217                         uint8_t val = CY_GET_REG8(SDCard_RXDATA_PTR);\r
218                         CY_SET_REG8(scsiTarget_datapath__F0_REG, val);\r
219                         guard++;\r
220                 }\r
221 \r
222                 // Byte has been sent out the SCSI interface.\r
223                 if (scsiDev.resetFlag || (scsiStatus & 2)) // SCSI RX FIFO NOT EMPTY\r
224                 {\r
225                         CY_GET_REG8(scsiTarget_datapath__F1_REG);\r
226                         ++i;\r
227                 }\r
228 \r
229                 // How many bytes are in a 4-byte FIFO ? 5.  4 FIFO bytes PLUS one byte\r
230                 // being processed bit-by-bit. Artifically limit the number of bytes in the \r
231                 // "combined" SPIM TX and RX FIFOS to the individual FIFO size.\r
232                 // Unlike the SCSI component, SPIM doesn't check if there's room in\r
233                 // the output FIFO before starting to transmit.\r
234                 if ((prep - guard < 4) && (prep < numBytes))\r
235                 {\r
236                         CY_SET_REG8(SDCard_TXDATA_PTR, 0xFF); // Put a byte in the FIFO\r
237                         prep++;\r
238                 }\r
239         }\r
240 \r
241         // Read and discard remaining bytes.\r
242         while (i < SD_SECTOR_SIZE)\r
243         {\r
244                 uint8_t sdRxStatus = CY_GET_REG8(SDCard_RX_STATUS_PTR);\r
245                 if(sdRxStatus & SDCard_STS_RX_FIFO_NOT_EMPTY)\r
246                 {\r
247                         CY_GET_REG8(SDCard_RXDATA_PTR);\r
248                         guard++;\r
249                         i++;\r
250                 }\r
251 \r
252                 if ((prep - guard < 4) && (prep < SD_SECTOR_SIZE))\r
253                 {\r
254                         CY_SET_REG8(SDCard_TXDATA_PTR, 0xFF); // Put a byte in the FIFO\r
255                         prep++;\r
256                 }\r
257         }\r
258 \r
259         sdSpiByte(0xFF); // CRC\r
260         sdSpiByte(0xFF); // CRC\r
261         scsiDev.dataLen = numBytes;\r
262         scsiDev.dataPtr = numBytes;\r
263         \r
264         while (SCSI_ReadPin(SCSI_In_ACK) && !scsiDev.resetFlag) {}\r
265 }\r
266 \r
267 static void doReadSectorSingle(uint32 sdBlock, int sdBytes)\r
268 {\r
269         uint8 v;\r
270         if (!sdDev.ccs)\r
271         {\r
272                 sdBlock = sdBlock * SD_SECTOR_SIZE;\r
273         }       \r
274         v = sdCommandAndResponse(SD_READ_SINGLE_BLOCK, sdBlock);\r
275         if (v)\r
276         {\r
277                 scsiDiskReset();\r
278                 sdClearStatus();\r
279 \r
280                 scsiDev.status = CHECK_CONDITION;\r
281                 scsiDev.sense.code = HARDWARE_ERROR;\r
282                 scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
283                 scsiDev.phase = STATUS;\r
284         }\r
285         else\r
286         {\r
287                 doReadSector(sdBytes);\r
288         }\r
289 }\r
290 \r
291 \r
292 void sdReadSectorSingle()\r
293 {\r
294         uint32 scsiLBA = (transfer.lba + transfer.currentBlock);\r
295         uint32 sdLBA = SCSISector2SD(scsiLBA);\r
296         \r
297         int sdSectors = SDSectorsPerSCSISector();\r
298         int i;\r
299         for (i = 0; (i < sdSectors - 1) && (scsiDev.status != CHECK_CONDITION); ++i)\r
300         {\r
301                 doReadSectorSingle(sdLBA + i, SD_SECTOR_SIZE);\r
302         }\r
303 \r
304         if (scsiDev.status != CHECK_CONDITION)\r
305         {\r
306                 int remaining = config->bytesPerSector % SD_SECTOR_SIZE;\r
307                 if (remaining == 0) remaining = SD_SECTOR_SIZE; // Full sector needed.\r
308                 doReadSectorSingle(sdLBA + i, remaining);\r
309         }\r
310 }\r
311 \r
312 void sdReadSectorMulti()\r
313 {\r
314         // Pre: sdPrepareRead called.\r
315         int sdSectors = SDSectorsPerSCSISector();\r
316         int i;\r
317         for (i = 0; (i < sdSectors - 1) && (scsiDev.status != CHECK_CONDITION); ++i)\r
318         {\r
319                 doReadSector(SD_SECTOR_SIZE);\r
320         }\r
321 \r
322         if (scsiDev.status != CHECK_CONDITION)\r
323         {\r
324                 int remaining = config->bytesPerSector % SD_SECTOR_SIZE;\r
325                 if (remaining == 0) remaining = SD_SECTOR_SIZE; // Full sector needed.\r
326                 doReadSector(remaining);\r
327         }\r
328 }\r
329 \r
330 \r
331 void sdCompleteRead()\r
332 {\r
333         transfer.inProgress = 0;\r
334 \r
335         // We cannot send even a single "padding" byte, as we normally would when\r
336         // sending a command.  If we've just finished reading the very last block\r
337         // on the card, then reading an additional dummy byte will just trigger\r
338         // an error condition as we're trying to read past-the-end of the storage\r
339         // device.\r
340         // ie. do not use sdCommandAndResponse here.\r
341         uint8 r1b;\r
342         sdSendCommand(SD_STOP_TRANSMISSION, 0);\r
343         r1b = sdReadResp();\r
344 \r
345         if (r1b)\r
346         {\r
347                 // Try very hard to make sure the transmission stops\r
348                 int retries = 255;\r
349                 while (r1b && retries)\r
350                 {\r
351                         r1b = sdCommandAndResponse(SD_STOP_TRANSMISSION, 0);\r
352                         retries--;\r
353                 }\r
354 \r
355                 scsiDev.status = CHECK_CONDITION;\r
356                 scsiDev.sense.code = HARDWARE_ERROR;\r
357                 scsiDev.sense.asc = UNRECOVERED_READ_ERROR;\r
358                 scsiDev.phase = STATUS;\r
359         }\r
360 \r
361         // R1b has an optional trailing "busy" signal.\r
362         {\r
363                 uint8 busy;\r
364                 do\r
365                 {\r
366                         busy = sdSpiByte(0xFF);\r
367                 } while (busy == 0);\r
368         }\r
369 }\r
370 \r
371 static void sdWaitWriteBusy()\r
372 {\r
373         uint8 val;\r
374         do\r
375         {\r
376                 val = sdSpiByte(0xFF);\r
377         } while (val != 0xFF);\r
378 }\r
379 \r
380 static int doWriteSector(uint32_t numBytes)\r
381 {\r
382         int prep, i, guard;\r
383         int result, maxWait;\r
384         uint8 dataToken;\r
385 \r
386         // Don't do a bus settle delay if we're already in the correct phase.\r
387         if (transfer.currentBlock == 0)\r
388         {\r
389                 scsiEnterPhase(DATA_OUT);\r
390         }\r
391         \r
392         sdSpiByte(0xFC); // MULTIPLE byte start token\r
393         \r
394         prep = 0;\r
395         i = 0;\r
396         guard = 0;\r
397 \r
398         // This loop is critically important for performance.\r
399         // We stream data straight from the SCSI fifos into the SPIM component\r
400         // FIFO's. If the loop isn't fast enough, the transmit FIFO's will empty,\r
401         // and performance will suffer. Every clock cycle counts.       \r
402         while (i < numBytes && !scsiDev.resetFlag)\r
403         {\r
404                 uint8_t sdRxStatus = CY_GET_REG8(SDCard_RX_STATUS_PTR);\r
405                 uint8_t scsiStatus = CY_GET_REG8(scsiTarget_StatusReg__STATUS_REG);\r
406 \r
407                 // Read from the SCSI fifo if there is room to stream the byte to the\r
408                 // SPIM fifos\r
409                 // See sdReadSector for comment on guard (FIFO size is really 5)\r
410                 if((guard - i < 4) &&\r
411                         (scsiDev.resetFlag || (scsiStatus & 2))\r
412                         ) // SCSI RX FIFO NOT EMPTY\r
413                 {\r
414                         uint8_t val = CY_GET_REG8(scsiTarget_datapath__F1_REG);\r
415                         CY_SET_REG8(SDCard_TXDATA_PTR, val);\r
416                         guard++;\r
417                 }\r
418 \r
419                 // Byte has been sent out the SPIM interface.\r
420                 if (sdRxStatus & SDCard_STS_RX_FIFO_NOT_EMPTY)\r
421                 {\r
422                          CY_GET_REG8(SDCard_RXDATA_PTR);\r
423                         ++i;\r
424                 }\r
425 \r
426                 if (prep < numBytes &&\r
427                         (scsiDev.resetFlag || (scsiStatus & 1)) // SCSI TX FIFO NOT FULL\r
428                         )\r
429                 {\r
430                         // Trigger the SCSI component to read a byte\r
431                         CY_SET_REG8(scsiTarget_datapath__F0_REG, 0xFF);\r
432                         prep++;\r
433                 }\r
434         }\r
435         \r
436         // Write remaining bytes as 0x00\r
437         while (i < SD_SECTOR_SIZE)\r
438         {\r
439                 uint8_t sdRxStatus = CY_GET_REG8(SDCard_RX_STATUS_PTR);\r
440 \r
441                 if(guard - i < 4)\r
442                 {\r
443                         CY_SET_REG8(SDCard_TXDATA_PTR, 0x00);\r
444                         guard++;\r
445                 }\r
446 \r
447                 // Byte has been sent out the SPIM interface.\r
448                 if (sdRxStatus & SDCard_STS_RX_FIFO_NOT_EMPTY)\r
449                 {\r
450                          CY_GET_REG8(SDCard_RXDATA_PTR);\r
451                         ++i;\r
452                 }\r
453         }\r
454         \r
455         sdSpiByte(0x00); // CRC\r
456         sdSpiByte(0x00); // CRC\r
457 \r
458         // Don't wait more than 1s.\r
459         // My 2g Kingston micro-sd card doesn't respond immediately.\r
460         // My 16Gb card does.\r
461         maxWait = 1000000;\r
462         dataToken = sdSpiByte(0xFF); // Response\r
463         while (dataToken == 0xFF && maxWait-- > 0)\r
464         {\r
465                 CyDelayUs(1);\r
466                 dataToken = sdSpiByte(0xFF);\r
467         }\r
468         if (((dataToken & 0x1F) >> 1) != 0x2) // Accepted.\r
469         {\r
470                 uint8 r1b, busy;\r
471                 \r
472                 sdWaitWriteBusy();\r
473 \r
474                 r1b = sdCommandAndResponse(SD_STOP_TRANSMISSION, 0);\r
475                 (void) r1b;\r
476                 sdSpiByte(0xFF);\r
477 \r
478                 // R1b has an optional trailing "busy" signal.\r
479                 do\r
480                 {\r
481                         busy = sdSpiByte(0xFF);\r
482                 } while (busy == 0);\r
483 \r
484                 // Wait for the card to come out of busy.\r
485                 sdWaitWriteBusy();\r
486 \r
487                 transfer.inProgress = 0;\r
488                 scsiDiskReset();\r
489                 sdClearStatus();\r
490 \r
491                 scsiDev.status = CHECK_CONDITION;\r
492                 scsiDev.sense.code = HARDWARE_ERROR;\r
493                 scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
494                 scsiDev.phase = STATUS;\r
495                 result = 0;\r
496         }\r
497         else\r
498         {\r
499                 sdWaitWriteBusy();\r
500                 result = 1;\r
501         }\r
502 \r
503         while (SCSI_ReadPin(SCSI_In_ACK) && !scsiDev.resetFlag) {}\r
504 \r
505         return result;\r
506 }\r
507 \r
508 int sdWriteSector()\r
509 {\r
510         int result = 1;\r
511         // Pre: sdPrepareWrite called.\r
512         int sdSectors = SDSectorsPerSCSISector();\r
513         int i;\r
514         for (i = 0; result && (i < sdSectors - 1) && (scsiDev.status != CHECK_CONDITION); ++i)\r
515         {\r
516                 result = doWriteSector(SD_SECTOR_SIZE);\r
517         }\r
518 \r
519         if (result && scsiDev.status != CHECK_CONDITION)\r
520         {\r
521                 int remaining = config->bytesPerSector % SD_SECTOR_SIZE;\r
522                 if (remaining == 0) remaining = SD_SECTOR_SIZE; // Full sector needed.\r
523                 result = doWriteSector(remaining);\r
524         }\r
525         return result;\r
526 }\r
527 \r
528 void sdCompleteWrite()\r
529 {\r
530         transfer.inProgress = 0;\r
531 \r
532         uint8 r1, r2;\r
533 \r
534         sdSpiByte(0xFD); // STOP TOKEN\r
535         // Wait for the card to come out of busy.\r
536         sdWaitWriteBusy();\r
537 \r
538         r1 = sdCommandAndResponse(13, 0); // send status\r
539         r2 = sdSpiByte(0xFF);\r
540         if (r1 || r2)\r
541         {\r
542                 sdClearStatus();\r
543                 scsiDev.status = CHECK_CONDITION;\r
544                 scsiDev.sense.code = HARDWARE_ERROR;\r
545                 scsiDev.sense.asc = WRITE_ERROR_AUTO_REALLOCATION_FAILED;\r
546                 scsiDev.phase = STATUS;\r
547         }\r
548 }\r
549 \r
550 \r
551 // SD Version 2 (SDHC) support\r
552 static int sendIfCond()\r
553 {\r
554         int retries = 50;\r
555 \r
556         do\r
557         {\r
558                 uint8 status = sdCRCCommandAndResponse(SD_SEND_IF_COND, 0x000001AA);\r
559 \r
560                 if (status == SD_R1_IDLE)\r
561                 {\r
562                         // Version 2 card.\r
563                         sdDev.version = 2;\r
564                         // Read 32bit response. Should contain the same bytes that\r
565                         // we sent in the command parameter.\r
566                         sdSpiByte(0xFF);\r
567                         sdSpiByte(0xFF);\r
568                         sdSpiByte(0xFF);\r
569                         sdSpiByte(0xFF);\r
570                         break;\r
571                 }\r
572                 else if (status & SD_R1_ILLEGAL)\r
573                 {\r
574                         // Version 1 card.\r
575                         sdDev.version = 1;\r
576                         sdClearStatus();\r
577                         break;\r
578                 }\r
579 \r
580                 sdClearStatus();\r
581         } while (--retries > 0);\r
582 \r
583         return retries > 0;\r
584 }\r
585 \r
586 static int sdOpCond()\r
587 {\r
588         int retries = 50;\r
589 \r
590         uint8 status;\r
591         do\r
592         {\r
593                 CyDelay(33); // Spec says to retry for 1 second.\r
594 \r
595                 sdCRCCommandAndResponse(SD_APP_CMD, 0);\r
596                 // Host Capacity Support = 1 (SDHC/SDXC supported)\r
597                 status = sdCRCCommandAndResponse(SD_APP_SEND_OP_COND, 0x40000000);\r
598 \r
599                 sdClearStatus();\r
600         } while ((status != 0) && (--retries > 0));\r
601 \r
602         return retries > 0;\r
603 }\r
604 \r
605 static int sdReadOCR()\r
606 {\r
607         uint8 buf[4];\r
608         int i;\r
609         \r
610         uint8 status = sdCRCCommandAndResponse(SD_READ_OCR, 0);\r
611         if(status){goto bad;}\r
612 \r
613         for (i = 0; i < 4; ++i)\r
614         {\r
615                 buf[i] = sdSpiByte(0xFF);\r
616         }\r
617 \r
618         sdDev.ccs = (buf[0] & 0x40) ? 1 : 0;\r
619 \r
620         return 1;\r
621 bad:\r
622         return 0;\r
623 }\r
624 \r
625 static int sdReadCSD()\r
626 {\r
627         uint8 startToken;\r
628         int maxWait, i;\r
629         uint8 buf[16];\r
630         \r
631         uint8 status = sdCRCCommandAndResponse(SD_SEND_CSD, 0);\r
632         if(status){goto bad;}\r
633 \r
634         maxWait = 1023;\r
635         do\r
636         {\r
637                 startToken = sdSpiByte(0xFF);\r
638         } while(maxWait-- && (startToken != 0xFE));\r
639         if (startToken != 0xFE) { goto bad; }\r
640 \r
641         for (i = 0; i < 16; ++i)\r
642         {\r
643                 buf[i] = sdSpiByte(0xFF);\r
644         }\r
645         sdSpiByte(0xFF); // CRC\r
646         sdSpiByte(0xFF); // CRC\r
647 \r
648         if ((buf[0] >> 6) == 0x00)\r
649         {\r
650                 // CSD version 1\r
651                 // C_SIZE in bits [73:62]\r
652                 uint32 c_size = (((((uint32)buf[6]) & 0x3) << 16) | (((uint32)buf[7]) << 8) | buf[8]) >> 6;\r
653                 uint32 c_mult = (((((uint32)buf[9]) & 0x3) << 8) | ((uint32)buf[0xa])) >> 7;\r
654                 uint32 sectorSize = buf[5] & 0x0F;\r
655                 sdDev.capacity = ((c_size+1) * ((uint64)1 << (c_mult+2)) * ((uint64)1 << sectorSize)) / SD_SECTOR_SIZE;\r
656         }\r
657         else if ((buf[0] >> 6) == 0x01)\r
658         {\r
659                 // CSD version 2\r
660                 // C_SIZE in bits [69:48]\r
661 \r
662                 uint32 c_size =\r
663                         ((((uint32)buf[7]) & 0x3F) << 16) |\r
664                         (((uint32)buf[8]) << 8) |\r
665                         ((uint32)buf[7]);\r
666                 sdDev.capacity = (c_size + 1) * 1024;\r
667         }\r
668         else\r
669         {\r
670                 goto bad;\r
671         }\r
672 \r
673         return 1;\r
674 bad:\r
675         return 0;\r
676 }\r
677 \r
678 int sdInit()\r
679 {\r
680         int result = 0;\r
681         int i;\r
682         uint8 v;\r
683         \r
684         sdDev.version = 0;\r
685         sdDev.ccs = 0;\r
686         sdDev.capacity = 0;\r
687 \r
688         SD_CS_Write(1); // Set CS inactive (active low)\r
689         SD_Init_Clk_Start(); // Turn on the slow 400KHz clock\r
690         SD_Clk_Ctl_Write(0); // Select the 400KHz clock source.\r
691         SDCard_Start(); // Enable SPI hardware\r
692 \r
693         // Power on sequence. 74 clock cycles of a "1" while CS unasserted.\r
694         for (i = 0; i < 10; ++i)\r
695         {\r
696                 sdSpiByte(0xFF);\r
697         }\r
698 \r
699         SD_CS_Write(0); // Set CS active (active low)\r
700         CyDelayUs(1);\r
701 \r
702         v = sdCRCCommandAndResponse(SD_GO_IDLE_STATE, 0);\r
703         if(v != 1){goto bad;}\r
704 \r
705         ledOn();\r
706         if (!sendIfCond()) goto bad; // Sets V1 or V2 flag\r
707         if (!sdOpCond()) goto bad;\r
708         if (!sdReadOCR()) goto bad;\r
709 \r
710         // This command will be ignored if sdDev.ccs is set.\r
711         // SDHC and SDXC are always 512bytes.\r
712         v = sdCRCCommandAndResponse(SD_SET_BLOCKLEN, SD_SECTOR_SIZE); //Force sector size\r
713         if(v){goto bad;}\r
714         v = sdCRCCommandAndResponse(SD_CRC_ON_OFF, 0); //crc off\r
715         if(v){goto bad;}\r
716 \r
717         // now set the sd card up for full speed\r
718         // The SD Card spec says we can run SPI @ 25MHz\r
719         // But the PSoC 5LP SPIM datasheet says the most we can do is 18MHz.\r
720         // I've confirmed that no data is ever put into the RX FIFO when run at\r
721         // 20MHz or 25MHz.\r
722         // ... and then we get timing analysis failures if the BUS_CLK is over 62MHz.\r
723         // So we run the MASTER_CLK and BUS_CLK at 60MHz, and run the SPI clock at 30MHz\r
724         // (15MHz SPI transfer clock).\r
725         SDCard_Stop();\r
726         \r
727         // We can't run at full-speed with the pullup resistors enabled.\r
728         SD_MISO_SetDriveMode(SD_MISO_DM_DIG_HIZ);\r
729         SD_MOSI_SetDriveMode(SD_MOSI_DM_STRONG);\r
730         SD_SCK_SetDriveMode(SD_SCK_DM_STRONG);\r
731         \r
732         SD_Data_Clk_Start(); // Turn on the fast clock\r
733         SD_Clk_Ctl_Write(1); // Select the fast clock source.\r
734         SD_Init_Clk_Stop(); // Stop the slow clock.\r
735         CyDelayUs(1);\r
736         SDCard_Start();\r
737 \r
738         // Clear out rubbish data through clock change\r
739         CyDelayUs(1);\r
740         SDCard_ReadRxStatus();\r
741         SDCard_ReadTxStatus();\r
742         SDCard_ClearFIFO();\r
743 \r
744         if (!sdReadCSD()) goto bad;\r
745 \r
746         result = 1;\r
747         goto out;\r
748 \r
749 bad:\r
750         sdDev.capacity = 0;\r
751 \r
752 out:\r
753         sdClearStatus();\r
754         ledOff();\r
755         return result;\r
756 \r
757 }\r
758 \r
759 void sdPrepareWrite()\r
760 {\r
761         uint8 v;\r
762         \r
763         // Set the number of blocks to pre-erase by the multiple block write command\r
764         // We don't care about the response - if the command is not accepted, writes\r
765         // will just be a bit slower.\r
766         // Max 22bit parameter.\r
767         uint32_t sdBlocks = transfer.blocks * SDSectorsPerSCSISector();\r
768         uint32 blocks = sdBlocks > 0x7FFFFF ? 0x7FFFFF : sdBlocks;\r
769         sdCommandAndResponse(SD_APP_CMD, 0);\r
770         sdCommandAndResponse(SD_APP_SET_WR_BLK_ERASE_COUNT, blocks);\r
771 \r
772         uint32 scsiLBA = (transfer.lba + transfer.currentBlock);\r
773         uint32 sdLBA = SCSISector2SD(scsiLBA);\r
774         if (!sdDev.ccs)\r
775         {\r
776                 sdLBA = sdLBA * SD_SECTOR_SIZE;\r
777         }\r
778         v = sdCommandAndResponse(25, sdLBA);\r
779         if (v)\r
780         {\r
781                 scsiDiskReset();\r
782                 sdClearStatus();\r
783                 scsiDev.status = CHECK_CONDITION;\r
784                 scsiDev.sense.code = HARDWARE_ERROR;\r
785                 scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
786                 scsiDev.phase = STATUS;\r
787         }\r
788         else\r
789         {\r
790                 transfer.inProgress = 1;\r
791         }\r
792 }\r
793 \r