Performance fixes, scsi2sd-util crash fixes, scsi2 config option.
[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 #pragma GCC push_options\r
18 #pragma GCC optimize("-flto")\r
19 \r
20 #include "device.h"\r
21 #include "scsi.h"\r
22 #include "config.h"\r
23 #include "disk.h"\r
24 #include "sd.h"\r
25 #include "led.h"\r
26 #include "time.h"\r
27 #include "trace.h"\r
28 \r
29 #include "scsiPhy.h"\r
30 \r
31 #include <string.h>\r
32 \r
33 // Global\r
34 SdDevice sdDev;\r
35 \r
36 enum SD_IO_STATE { SD_DMA, SD_ACCEPTED, SD_BUSY, SD_IDLE };\r
37 static int sdIOState = SD_IDLE;\r
38 \r
39 // Private DMA variables.\r
40 static uint8 sdDMARxChan = CY_DMA_INVALID_CHANNEL;\r
41 static uint8 sdDMATxChan = CY_DMA_INVALID_CHANNEL;\r
42 \r
43 // Dummy location for DMA to send unchecked CRC bytes to\r
44 static uint8 discardBuffer __attribute__((aligned(4)));\r
45 \r
46 // 2 bytes CRC, response, 8bits to close the clock..\r
47 // "NCR" time is up to 8 bytes.\r
48 static uint8_t writeResponseBuffer[8]  __attribute__((aligned(4)));\r
49 \r
50 // Padded with a dummy byte just to allow the tx DMA channel to\r
51 // use 2-byte bursts for performance.\r
52 static uint8_t writeStartToken[2]  __attribute__((aligned(4))) = {0xFF, 0xFC};\r
53 \r
54 // Source of dummy SPI bytes for DMA\r
55 static uint8_t dummyBuffer[2]  __attribute__((aligned(4))) = {0xFF, 0xFF};\r
56 \r
57 volatile uint8_t sdRxDMAComplete;\r
58 volatile uint8_t sdTxDMAComplete;\r
59 \r
60 CY_ISR_PROTO(sdRxISR);\r
61 CY_ISR(sdRxISR)\r
62 {\r
63         sdRxDMAComplete = 1;\r
64 }\r
65 CY_ISR_PROTO(sdTxISR);\r
66 CY_ISR(sdTxISR)\r
67 {\r
68         sdTxDMAComplete = 1;\r
69 }\r
70 \r
71 static uint8 sdCrc7(uint8* chr, uint8 cnt, uint8 crc)\r
72 {\r
73         uint8 a;\r
74         for(a = 0; a < cnt; a++)\r
75         {\r
76                 uint8 Data = chr[a];\r
77                 uint8 i;\r
78                 for(i = 0; i < 8; i++)\r
79                 {\r
80                         crc <<= 1;\r
81                         if( (Data & 0x80) ^ (crc & 0x80) ) {crc ^= 0x09;}\r
82                         Data <<= 1;\r
83                 }\r
84         }\r
85         return crc & 0x7F;\r
86 }\r
87 \r
88 // Read and write 1 byte.\r
89 static uint8_t sdSpiByte(uint8_t value)\r
90 {\r
91         SDCard_WriteTxData(value);\r
92         trace(trace_spinSpiByte);\r
93         while (!(SDCard_ReadRxStatus() & SDCard_STS_RX_FIFO_NOT_EMPTY)) {}\r
94         trace(trace_sdSpiByte);\r
95         return SDCard_ReadRxData();\r
96 }\r
97 \r
98 static uint16_t sdDoCommand(\r
99         uint8_t cmd,\r
100         uint32_t param,\r
101         int useCRC,\r
102         int use2byteResponse)\r
103 {\r
104         int waitWhileBusy = (cmd != SD_GO_IDLE_STATE) && (cmd != SD_STOP_TRANSMISSION);\r
105 \r
106         // "busy" probe. We'll examine the results later.\r
107         if (waitWhileBusy)\r
108         {\r
109                 SDCard_WriteTxData(0xFF);\r
110         }\r
111 \r
112         // send is static as the address must remain consistent for the static\r
113         // DMA descriptors to work.\r
114         // Size must be divisible by 2 to suit 2-byte-burst TX DMA channel.\r
115         static uint8_t send[6] __attribute__((aligned(4)));\r
116         send[0] = cmd | 0x40;\r
117         send[1] = param >> 24;\r
118         send[2] = param >> 16;\r
119         send[3] = param >> 8;\r
120         send[4] = param;\r
121         if (unlikely(useCRC))\r
122         {\r
123                 send[5] = (sdCrc7(send, 5, 0) << 1) | 1;\r
124         }\r
125         else\r
126         {\r
127                 send[5] = 1; // stop bit\r
128         }\r
129 \r
130         static uint8_t dmaRxTd = CY_DMA_INVALID_TD;\r
131         static uint8_t dmaTxTd = CY_DMA_INVALID_TD;\r
132         if (unlikely(dmaRxTd == CY_DMA_INVALID_TD))\r
133         {\r
134                 dmaRxTd = CyDmaTdAllocate();\r
135                 dmaTxTd = CyDmaTdAllocate();\r
136                 CyDmaTdSetConfiguration(dmaTxTd, sizeof(send), CY_DMA_DISABLE_TD, TD_INC_SRC_ADR|SD_TX_DMA__TD_TERMOUT_EN);\r
137                 CyDmaTdSetAddress(dmaTxTd, LO16((uint32)&send), LO16((uint32)SDCard_TXDATA_PTR));\r
138                 CyDmaTdSetConfiguration(dmaRxTd, sizeof(send), CY_DMA_DISABLE_TD, SD_RX_DMA__TD_TERMOUT_EN);\r
139                 CyDmaTdSetAddress(dmaRxTd, LO16((uint32)SDCard_RXDATA_PTR), LO16((uint32)&discardBuffer));\r
140         }\r
141 \r
142         sdTxDMAComplete = 0;\r
143         sdRxDMAComplete = 0;\r
144 \r
145         CyDmaChSetInitialTd(sdDMARxChan, dmaRxTd);\r
146         CyDmaChSetInitialTd(sdDMATxChan, dmaTxTd);\r
147 \r
148         // Some Samsung cards enter a busy-state after single-sector reads.\r
149         // But we also need to wait for R1B to complete from the multi-sector\r
150         // reads.\r
151         if (waitWhileBusy)\r
152         {\r
153                 trace(trace_spinSDRxFIFO);\r
154                 while (!(SDCard_ReadRxStatus() & SDCard_STS_RX_FIFO_NOT_EMPTY)) {}\r
155                 int busy = SDCard_ReadRxData() != 0xFF;\r
156                 if (unlikely(busy))\r
157                 {\r
158                         trace(trace_spinSDBusy);\r
159                         while (sdSpiByte(0xFF) != 0xFF) {}\r
160                 }\r
161         }\r
162 \r
163         // The DMA controller is a bit trigger-happy. It will retain\r
164         // a drq request that was triggered while the channel was\r
165         // disabled.\r
166         CyDmaChSetRequest(sdDMATxChan, CY_DMA_CPU_REQ);\r
167         CyDmaClearPendingDrq(sdDMARxChan);\r
168 \r
169         // There is no flow control, so we must ensure we can read the bytes\r
170         // before we start transmitting\r
171         CyDmaChEnable(sdDMARxChan, 1);\r
172         CyDmaChEnable(sdDMATxChan, 1);\r
173 \r
174         trace(trace_spinSDDMA);\r
175         while (!(sdTxDMAComplete && sdRxDMAComplete)) { __WFI(); }\r
176 \r
177         uint16_t response = sdSpiByte(0xFF); // Result code or stuff byte\r
178         if (unlikely(cmd == SD_STOP_TRANSMISSION))\r
179         {\r
180                 // Stuff byte is required for this command only.\r
181                 // Part 1 Simplified standard 3.01\r
182                 // "The stop command has an execution delay due to the serial command\r
183                 // transmission."\r
184                 response = sdSpiByte(0xFF);\r
185         }\r
186 \r
187         uint32_t start = getTime_ms();\r
188 \r
189         trace(trace_spinSDBusy);\r
190         while ((response & 0x80) && likely(elapsedTime_ms(start) <= 200))\r
191         {\r
192                 response = sdSpiByte(0xFF);\r
193         }\r
194         if (unlikely(use2byteResponse))\r
195         {\r
196                 response = (response << 8) | sdSpiByte(0xFF);\r
197         }\r
198         return response;\r
199 }\r
200 \r
201 \r
202 static inline uint16_t sdCommandAndResponse(uint8_t cmd, uint32_t param)\r
203 {\r
204         return sdDoCommand(cmd, param, 0, 0);\r
205 }\r
206 \r
207 static inline uint16_t sdCRCCommandAndResponse(uint8_t cmd, uint32_t param)\r
208 {\r
209         return sdDoCommand(cmd, param, 1, 0);\r
210 }\r
211 \r
212 // Clear the sticky status bits on error.\r
213 static void sdClearStatus()\r
214 {\r
215         sdSpiByte(0xFF);\r
216         uint16_t r2 = sdDoCommand(SD_SEND_STATUS, 0, 1, 1);\r
217         (void) r2;\r
218 }\r
219 \r
220 void\r
221 sdReadMultiSectorPrep()\r
222 {\r
223         uint8 v;\r
224         uint32 scsiLBA = (transfer.lba + transfer.currentBlock);\r
225         uint32 sdLBA =\r
226                 SCSISector2SD(\r
227                         scsiDev.target->cfg->sdSectorStart,\r
228                         scsiDev.target->liveCfg.bytesPerSector,\r
229                         scsiLBA);\r
230 \r
231         if (!sdDev.ccs)\r
232         {\r
233                 sdLBA = sdLBA * SD_SECTOR_SIZE;\r
234         }\r
235         v = sdCommandAndResponse(SD_READ_MULTIPLE_BLOCK, sdLBA);\r
236         if (unlikely(v))\r
237         {\r
238                 scsiDiskReset();\r
239                 sdClearStatus();\r
240 \r
241                 scsiDev.status = CHECK_CONDITION;\r
242                 scsiDev.target->sense.code = HARDWARE_ERROR;\r
243                 scsiDev.target->sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
244                 scsiDev.phase = STATUS;\r
245         }\r
246         else\r
247         {\r
248                 transfer.inProgress = 1;\r
249         }\r
250 }\r
251 \r
252 static void\r
253 dmaReadSector(uint8_t* outputBuffer)\r
254 {\r
255         // Wait for a start-block token.\r
256         // Don't wait more than 200ms.  The standard recommends 100ms.\r
257         uint32_t start = getTime_ms();\r
258         uint8_t token = sdSpiByte(0xFF);\r
259         trace(trace_spinSDBusy);\r
260         while (token != 0xFE && likely(elapsedTime_ms(start) <= 200))\r
261         {\r
262                 if (unlikely(token && ((token & 0xE0) == 0)))\r
263                 {\r
264                         // Error token!\r
265                         break;\r
266                 }\r
267                 token = sdSpiByte(0xFF);\r
268         }\r
269         if (unlikely(token != 0xFE))\r
270         {\r
271                 if (transfer.multiBlock)\r
272                 {\r
273                         sdCompleteRead();\r
274                 }\r
275                 if (scsiDev.status != CHECK_CONDITION)\r
276                 {\r
277                         scsiDev.status = CHECK_CONDITION;\r
278                         scsiDev.target->sense.code = HARDWARE_ERROR;\r
279                         scsiDev.target->sense.asc = UNRECOVERED_READ_ERROR;\r
280                         scsiDev.phase = STATUS;\r
281                 }\r
282                 sdClearStatus();\r
283                 return;\r
284         }\r
285 \r
286         static uint8_t dmaRxTd[2] = { CY_DMA_INVALID_TD, CY_DMA_INVALID_TD};\r
287         static uint8_t dmaTxTd = CY_DMA_INVALID_TD;\r
288         if (unlikely(dmaRxTd[0] == CY_DMA_INVALID_TD))\r
289         {\r
290                 dmaRxTd[0] = CyDmaTdAllocate();\r
291                 dmaRxTd[1] = CyDmaTdAllocate();\r
292                 dmaTxTd = CyDmaTdAllocate();\r
293                 \r
294                 // Receive 512 bytes of data and then 2 bytes CRC.\r
295                 CyDmaTdSetConfiguration(dmaRxTd[0], SD_SECTOR_SIZE, dmaRxTd[1], TD_INC_DST_ADR);\r
296                 CyDmaTdSetConfiguration(dmaRxTd[1], 2, CY_DMA_DISABLE_TD, SD_RX_DMA__TD_TERMOUT_EN);\r
297                 CyDmaTdSetAddress(dmaRxTd[1], LO16((uint32)SDCard_RXDATA_PTR), LO16((uint32)&discardBuffer));\r
298         \r
299                 CyDmaTdSetConfiguration(dmaTxTd, SD_SECTOR_SIZE + 2, CY_DMA_DISABLE_TD, SD_TX_DMA__TD_TERMOUT_EN);\r
300                 CyDmaTdSetAddress(dmaTxTd, LO16((uint32)&dummyBuffer), LO16((uint32)SDCard_TXDATA_PTR));\r
301 \r
302         }\r
303         CyDmaTdSetAddress(dmaRxTd[0], LO16((uint32)SDCard_RXDATA_PTR), LO16((uint32)outputBuffer));\r
304 \r
305         sdIOState = SD_DMA;\r
306         sdTxDMAComplete = 0;\r
307         sdRxDMAComplete = 0;\r
308 \r
309         // Re-loading the initial TD's here is very important, or else\r
310         // we'll be re-using the last-used TD, which would be the last\r
311         // in the chain (ie. CRC TD)\r
312         CyDmaChSetInitialTd(sdDMARxChan, dmaRxTd[0]);\r
313         CyDmaChSetInitialTd(sdDMATxChan, dmaTxTd);\r
314 \r
315         // The DMA controller is a bit trigger-happy. It will retain\r
316         // a drq request that was triggered while the channel was\r
317         // disabled.\r
318         CyDmaChSetRequest(sdDMATxChan, CY_DMA_CPU_REQ);\r
319         CyDmaClearPendingDrq(sdDMARxChan);\r
320 \r
321         // There is no flow control, so we must ensure we can read the bytes\r
322         // before we start transmitting\r
323         CyDmaChEnable(sdDMARxChan, 1);\r
324         CyDmaChEnable(sdDMATxChan, 1);\r
325 }\r
326 \r
327 int\r
328 sdReadSectorDMAPoll()\r
329 {\r
330         if (sdRxDMAComplete && sdTxDMAComplete)\r
331         {\r
332                 // DMA transfer is complete\r
333                 sdIOState = SD_IDLE;\r
334                 return 1;\r
335         }\r
336         else\r
337         {\r
338                 return 0;\r
339         }\r
340 }\r
341 \r
342 void sdReadSingleSectorDMA(uint32_t lba, uint8_t* outputBuffer)\r
343 {\r
344         uint8 v;\r
345         if (!sdDev.ccs)\r
346         {\r
347                 lba = lba * SD_SECTOR_SIZE;\r
348         }\r
349         v = sdCommandAndResponse(SD_READ_SINGLE_BLOCK, lba);\r
350         if (unlikely(v))\r
351         {\r
352                 scsiDiskReset();\r
353                 sdClearStatus();\r
354 \r
355                 scsiDev.status = CHECK_CONDITION;\r
356                 scsiDev.target->sense.code = HARDWARE_ERROR;\r
357                 scsiDev.target->sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
358                 scsiDev.phase = STATUS;\r
359         }\r
360         else\r
361         {\r
362                 dmaReadSector(outputBuffer);\r
363         }\r
364 }\r
365 \r
366 void\r
367 sdReadMultiSectorDMA(uint8_t* outputBuffer)\r
368 {\r
369         // Pre: sdReadMultiSectorPrep called.\r
370         dmaReadSector(outputBuffer);\r
371 }\r
372 \r
373 \r
374 void sdCompleteRead()\r
375 {\r
376         if (unlikely(sdIOState != SD_IDLE))\r
377         {\r
378                 // Not much choice but to wait until we've completed the transfer.\r
379                 // Cancelling the transfer can't be done as we have no way to reset\r
380                 // the SD card.\r
381                 trace(trace_spinSDCompleteRead);\r
382                 while (!sdReadSectorDMAPoll()) { /* spin */ }\r
383         }\r
384         \r
385         if (transfer.inProgress)\r
386         {\r
387                 transfer.inProgress = 0;\r
388                 uint8 r1b = sdCommandAndResponse(SD_STOP_TRANSMISSION, 0);\r
389 \r
390                 if (unlikely(r1b))\r
391                 {\r
392                         scsiDev.status = CHECK_CONDITION;\r
393                         scsiDev.target->sense.code = HARDWARE_ERROR;\r
394                         scsiDev.target->sense.asc = UNRECOVERED_READ_ERROR;\r
395                         scsiDev.phase = STATUS;\r
396                 }\r
397         }\r
398 \r
399         // R1b has an optional trailing "busy" signal, but we defer waiting on this.\r
400         // The next call so sdCommandAndResponse will wait for the busy state to\r
401         // clear.\r
402 }\r
403 \r
404 static void sdWaitWriteBusy()\r
405 {\r
406         uint8 val;\r
407         do\r
408         {\r
409                 val = sdSpiByte(0xFF);\r
410         } while (val != 0xFF);\r
411 }\r
412 \r
413 void\r
414 sdWriteMultiSectorDMA(uint8_t* outputBuffer)\r
415 {\r
416         static uint8_t dmaRxTd[2] = { CY_DMA_INVALID_TD, CY_DMA_INVALID_TD};\r
417         static uint8_t dmaTxTd[3] = { CY_DMA_INVALID_TD, CY_DMA_INVALID_TD, CY_DMA_INVALID_TD};\r
418         if (unlikely(dmaRxTd[0] == CY_DMA_INVALID_TD))\r
419         {\r
420                 dmaRxTd[0] = CyDmaTdAllocate();\r
421                 dmaRxTd[1] = CyDmaTdAllocate();\r
422                 dmaTxTd[0] = CyDmaTdAllocate();\r
423                 dmaTxTd[1] = CyDmaTdAllocate();\r
424                 dmaTxTd[2] = CyDmaTdAllocate();\r
425                 \r
426                 // Transmit 512 bytes of data and then 2 bytes CRC, and then get the response byte\r
427                 // We need to do this without stopping the clock\r
428                 CyDmaTdSetConfiguration(dmaTxTd[0], 2, dmaTxTd[1], TD_INC_SRC_ADR);\r
429                 CyDmaTdSetAddress(dmaTxTd[0], LO16((uint32)&writeStartToken), LO16((uint32)SDCard_TXDATA_PTR));\r
430 \r
431                 CyDmaTdSetConfiguration(dmaTxTd[1], SD_SECTOR_SIZE, dmaTxTd[2], TD_INC_SRC_ADR);\r
432 \r
433                 CyDmaTdSetConfiguration(dmaTxTd[2], 2 + sizeof(writeResponseBuffer), CY_DMA_DISABLE_TD, SD_TX_DMA__TD_TERMOUT_EN);\r
434                 CyDmaTdSetAddress(dmaTxTd[2], LO16((uint32)&dummyBuffer), LO16((uint32)SDCard_TXDATA_PTR));\r
435 \r
436                 CyDmaTdSetConfiguration(dmaRxTd[0], SD_SECTOR_SIZE + 4, dmaRxTd[1], 0);\r
437                 CyDmaTdSetAddress(dmaRxTd[0], LO16((uint32)SDCard_RXDATA_PTR), LO16((uint32)&discardBuffer));\r
438                 CyDmaTdSetConfiguration(dmaRxTd[1], sizeof(writeResponseBuffer), CY_DMA_DISABLE_TD, SD_RX_DMA__TD_TERMOUT_EN|TD_INC_DST_ADR);\r
439                 CyDmaTdSetAddress(dmaRxTd[1], LO16((uint32)SDCard_RXDATA_PTR), LO16((uint32)&writeResponseBuffer));\r
440         }\r
441         CyDmaTdSetAddress(dmaTxTd[1], LO16((uint32)outputBuffer), LO16((uint32)SDCard_TXDATA_PTR));\r
442 \r
443 \r
444         sdIOState = SD_DMA;\r
445         // The DMA controller is a bit trigger-happy. It will retain\r
446         // a drq request that was triggered while the channel was\r
447         // disabled.\r
448         CyDmaChSetRequest(sdDMATxChan, CY_DMA_CPU_REQ);\r
449         CyDmaClearPendingDrq(sdDMARxChan);\r
450 \r
451         sdTxDMAComplete = 0;\r
452         sdRxDMAComplete = 0;\r
453 \r
454         // Re-loading the initial TD's here is very important, or else\r
455         // we'll be re-using the last-used TD, which would be the last\r
456         // in the chain (ie. CRC TD)\r
457         CyDmaChSetInitialTd(sdDMARxChan, dmaRxTd[0]);\r
458         CyDmaChSetInitialTd(sdDMATxChan, dmaTxTd[0]);\r
459 \r
460         // There is no flow control, so we must ensure we can read the bytes\r
461         // before we start transmitting\r
462         CyDmaChEnable(sdDMARxChan, 1);\r
463         CyDmaChEnable(sdDMATxChan, 1);\r
464 }\r
465 \r
466 int\r
467 sdWriteSectorDMAPoll(int sendStopToken)\r
468 {\r
469         if (sdRxDMAComplete && sdTxDMAComplete)\r
470         {\r
471                 if (sdIOState == SD_DMA)\r
472                 {\r
473                         // Retry a few times. The data token format is:\r
474                         // XXX0AAA1\r
475                         int i = 0;\r
476                         uint8_t dataToken;\r
477                         do\r
478                         {\r
479                                 dataToken = writeResponseBuffer[i]; // Response\r
480                                 ++i;\r
481                         } while (((dataToken & 0x0101) != 1) && (i < sizeof(writeResponseBuffer)));\r
482 \r
483                         // At this point we should either have an accepted token, or we'll\r
484                         // timeout and proceed into the error case below.\r
485                         if (unlikely(((dataToken & 0x1F) >> 1) != 0x2)) // Accepted.\r
486                         {\r
487                                 sdIOState = SD_IDLE;\r
488 \r
489                                 sdWaitWriteBusy();\r
490                                 sdSpiByte(0xFD); // STOP TOKEN\r
491                                 sdWaitWriteBusy();\r
492 \r
493                                 transfer.inProgress = 0;\r
494                                 scsiDiskReset();\r
495                                 sdClearStatus();\r
496 \r
497                                 scsiDev.status = CHECK_CONDITION;\r
498                                 scsiDev.target->sense.code = HARDWARE_ERROR;\r
499                                 scsiDev.target->sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
500                                 scsiDev.phase = STATUS;\r
501                         }\r
502                         else\r
503                         {\r
504                                 sdIOState = SD_ACCEPTED;\r
505                         }\r
506                 }\r
507 \r
508                 if (sdIOState == SD_ACCEPTED)\r
509                 {\r
510                         // Wait while the SD card is busy\r
511                         if (sdSpiByte(0xFF) == 0xFF)\r
512                         {\r
513                                 if (sendStopToken)\r
514                                 {\r
515                                         sdIOState = SD_BUSY;\r
516                                         transfer.inProgress = 0;\r
517 \r
518                                         sdSpiByte(0xFD); // STOP TOKEN\r
519                                 }\r
520                                 else\r
521                                 {\r
522                                         sdIOState = SD_IDLE;\r
523                                 }\r
524                         }\r
525                 }\r
526 \r
527                 if (sdIOState == SD_BUSY)\r
528                 {\r
529                         // Wait while the SD card is busy\r
530                         if (sdSpiByte(0xFF) == 0xFF)\r
531                         {\r
532                                 sdIOState = SD_IDLE;\r
533                         }\r
534                 }\r
535 \r
536                 return sdIOState == SD_IDLE;\r
537         }\r
538         else\r
539         {\r
540                 return 0;\r
541         }\r
542 }\r
543 \r
544 void sdCompleteWrite()\r
545 {\r
546         if (unlikely(sdIOState != SD_IDLE))\r
547         {\r
548                 // Not much choice but to wait until we've completed the transfer.\r
549                 // Cancelling the transfer can't be done as we have no way to reset\r
550                 // the SD card.\r
551                 trace(trace_spinSDCompleteWrite);\r
552                 while (!sdWriteSectorDMAPoll(1)) { /* spin */ }\r
553         }\r
554 \r
555         if (transfer.inProgress && likely(scsiDev.phase == DATA_OUT))\r
556         {\r
557                 uint16_t r2 = sdDoCommand(SD_SEND_STATUS, 0, 0, 1);\r
558                 if (unlikely(r2))\r
559                 {\r
560                         sdClearStatus();\r
561                         scsiDev.status = CHECK_CONDITION;\r
562                         scsiDev.target->sense.code = HARDWARE_ERROR;\r
563                         scsiDev.target->sense.asc = WRITE_ERROR_AUTO_REALLOCATION_FAILED;\r
564                         scsiDev.phase = STATUS;\r
565                 }\r
566         }\r
567         transfer.inProgress = 0;\r
568 }\r
569 \r
570 \r
571 // SD Version 2 (SDHC) support\r
572 static int sendIfCond()\r
573 {\r
574         int retries = 50;\r
575 \r
576         do\r
577         {\r
578                 // 11:8 Host voltage. 1 = 2.7-3.6V\r
579                 // 7:0 Echo bits. Ignore.\r
580                 uint8 status = sdCRCCommandAndResponse(SD_SEND_IF_COND, 0x000001AA);\r
581 \r
582                 if (status == SD_R1_IDLE)\r
583                 {\r
584                         // Version 2 card.\r
585                         sdDev.version = 2;\r
586                         // Read 32bit response. Should contain the same bytes that\r
587                         // we sent in the command parameter.\r
588                         sdSpiByte(0xFF);\r
589                         sdSpiByte(0xFF);\r
590                         sdSpiByte(0xFF);\r
591                         sdSpiByte(0xFF);\r
592                         break;\r
593                 }\r
594                 else if (status & SD_R1_ILLEGAL)\r
595                 {\r
596                         // Version 1 card.\r
597                         sdDev.version = 1;\r
598                         sdClearStatus();\r
599                         break;\r
600                 }\r
601 \r
602                 sdClearStatus();\r
603         } while (--retries > 0);\r
604 \r
605         return retries > 0;\r
606 }\r
607 \r
608 static int sdOpCond()\r
609 {\r
610         uint32_t start = getTime_ms();\r
611 \r
612         uint8 status;\r
613         do\r
614         {\r
615                 sdCRCCommandAndResponse(SD_APP_CMD, 0);\r
616                 // Host Capacity Support = 1 (SDHC/SDXC supported)\r
617                 status = sdCRCCommandAndResponse(SD_APP_SEND_OP_COND, 0x40000000);\r
618 \r
619                 sdClearStatus();\r
620 \r
621         // Spec says to poll for 1 second.\r
622         } while ((status != 0) && (elapsedTime_ms(start) < 1000));\r
623 \r
624         return status == 0;\r
625 }\r
626 \r
627 static int sdReadOCR()\r
628 {\r
629         uint32_t start = getTime_ms();\r
630         int complete;\r
631         uint8 status;\r
632 \r
633         do\r
634         {\r
635                 uint8 buf[4];\r
636                 int i;\r
637 \r
638                 status = sdCRCCommandAndResponse(SD_READ_OCR, 0);\r
639                 if(status) { break; }\r
640 \r
641                 for (i = 0; i < 4; ++i)\r
642                 {\r
643                         buf[i] = sdSpiByte(0xFF);\r
644                 }\r
645 \r
646                 sdDev.ccs = (buf[0] & 0x40) ? 1 : 0;\r
647                 complete = (buf[0] & 0x80);\r
648 \r
649         } while (!status &&\r
650                 !complete &&\r
651                 (elapsedTime_ms(start) < 1000));\r
652 \r
653         return (status == 0) && complete;\r
654 }\r
655 \r
656 static void sdReadCID()\r
657 {\r
658         uint8 startToken;\r
659         int maxWait, i;\r
660 \r
661         uint8 status = sdCRCCommandAndResponse(SD_SEND_CID, 0);\r
662         if(status){return;}\r
663 \r
664         maxWait = 1023;\r
665         do\r
666         {\r
667                 startToken = sdSpiByte(0xFF);\r
668         } while(maxWait-- && (startToken != 0xFE));\r
669         if (startToken != 0xFE) { return; }\r
670 \r
671         for (i = 0; i < 16; ++i)\r
672         {\r
673                 sdDev.cid[i] = sdSpiByte(0xFF);\r
674         }\r
675         sdSpiByte(0xFF); // CRC\r
676         sdSpiByte(0xFF); // CRC\r
677 }\r
678 \r
679 static int sdReadCSD()\r
680 {\r
681         uint8 startToken;\r
682         int maxWait, i;\r
683 \r
684         uint8 status = sdCRCCommandAndResponse(SD_SEND_CSD, 0);\r
685         if(status){goto bad;}\r
686 \r
687         maxWait = 1023;\r
688         do\r
689         {\r
690                 startToken = sdSpiByte(0xFF);\r
691         } while(maxWait-- && (startToken != 0xFE));\r
692         if (startToken != 0xFE) { goto bad; }\r
693 \r
694         for (i = 0; i < 16; ++i)\r
695         {\r
696                 sdDev.csd[i] = sdSpiByte(0xFF);\r
697         }\r
698         sdSpiByte(0xFF); // CRC\r
699         sdSpiByte(0xFF); // CRC\r
700 \r
701         if ((sdDev.csd[0] >> 6) == 0x00)\r
702         {\r
703                 // CSD version 1\r
704                 // C_SIZE in bits [73:62]\r
705                 uint32 c_size = (((((uint32)sdDev.csd[6]) & 0x3) << 16) | (((uint32)sdDev.csd[7]) << 8) | sdDev.csd[8]) >> 6;\r
706                 uint32 c_mult = (((((uint32)sdDev.csd[9]) & 0x3) << 8) | ((uint32)sdDev.csd[0xa])) >> 7;\r
707                 uint32 sectorSize = sdDev.csd[5] & 0x0F;\r
708                 sdDev.capacity = ((c_size+1) * ((uint64)1 << (c_mult+2)) * ((uint64)1 << sectorSize)) / SD_SECTOR_SIZE;\r
709         }\r
710         else if ((sdDev.csd[0] >> 6) == 0x01)\r
711         {\r
712                 // CSD version 2\r
713                 // C_SIZE in bits [69:48]\r
714 \r
715                 uint32 c_size =\r
716                         ((((uint32)sdDev.csd[7]) & 0x3F) << 16) |\r
717                         (((uint32)sdDev.csd[8]) << 8) |\r
718                         ((uint32)sdDev.csd[7]);\r
719                 sdDev.capacity = (c_size + 1) * 1024;\r
720         }\r
721         else\r
722         {\r
723                 goto bad;\r
724         }\r
725 \r
726         return 1;\r
727 bad:\r
728         return 0;\r
729 }\r
730 \r
731 static void sdInitDMA()\r
732 {\r
733         // One-time init only.\r
734         if (sdDMATxChan == CY_DMA_INVALID_CHANNEL)\r
735         {\r
736                 sdDMATxChan =\r
737                         SD_TX_DMA_DmaInitialize(\r
738                                 2, // Bytes per burst\r
739                                 1, // request per burst\r
740                                 HI16(CYDEV_SRAM_BASE),\r
741                                 HI16(CYDEV_PERIPH_BASE)\r
742                                 );\r
743 \r
744                 sdDMARxChan =\r
745                         SD_RX_DMA_DmaInitialize(\r
746                                 1, // Bytes per burst\r
747                                 1, // request per burst\r
748                                 HI16(CYDEV_PERIPH_BASE),\r
749                                 HI16(CYDEV_SRAM_BASE)\r
750                                 );\r
751 \r
752                 CyDmaChDisable(sdDMATxChan);\r
753                 CyDmaChDisable(sdDMARxChan);\r
754 \r
755                 SD_RX_DMA_COMPLETE_StartEx(sdRxISR);\r
756                 SD_TX_DMA_COMPLETE_StartEx(sdTxISR);\r
757         }\r
758 }\r
759 \r
760 int sdInit()\r
761 {\r
762         int result = 0;\r
763         int i;\r
764         uint8 v;\r
765 \r
766         sdDev.version = 0;\r
767         sdDev.ccs = 0;\r
768         sdDev.capacity = 0;\r
769         memset(sdDev.csd, 0, sizeof(sdDev.csd));\r
770         memset(sdDev.cid, 0, sizeof(sdDev.cid));\r
771 \r
772         sdInitDMA();\r
773 \r
774         SD_CS_SetDriveMode(SD_CS_DM_STRONG);\r
775         SD_CS_Write(1); // Set CS inactive (active low)\r
776 \r
777         // Set the SPI clock for 400kHz transfers\r
778         // 25MHz / 400kHz approx factor of 63.\r
779         // The register contains (divider - 1)\r
780         uint16_t clkDiv25MHz =  SD_Data_Clk_GetDividerRegister();\r
781         SD_Data_Clk_SetDivider(((clkDiv25MHz + 1) * 63) - 1);\r
782         // Wait for the clock to settle.\r
783         CyDelayUs(1);\r
784 \r
785         SDCard_Start(); // Enable SPI hardware\r
786 \r
787         // Power on sequence. 74 clock cycles of a "1" while CS unasserted.\r
788         for (i = 0; i < 10; ++i)\r
789         {\r
790                 sdSpiByte(0xFF);\r
791         }\r
792 \r
793         SD_CS_Write(0); // Set CS active (active low)\r
794         CyDelayUs(1);\r
795 \r
796         sdSpiByte(0xFF);\r
797         v = sdDoCommand(SD_GO_IDLE_STATE, 0, 1, 0);\r
798         if(v != 1){goto bad;}\r
799 \r
800         ledOn();\r
801         if (!sendIfCond()) goto bad; // Sets V1 or V2 flag  CMD8\r
802         if (!sdOpCond()) goto bad; // ACMD41. Wait for init completes.\r
803         if (!sdReadOCR()) goto bad; // CMD58. Get CCS flag. Only valid after init.\r
804 \r
805         // This command will be ignored if sdDev.ccs is set.\r
806         // SDHC and SDXC are always 512bytes.\r
807         v = sdCRCCommandAndResponse(SD_SET_BLOCKLEN, SD_SECTOR_SIZE); //Force sector size\r
808         if(v){goto bad;}\r
809         v = sdCRCCommandAndResponse(SD_CRC_ON_OFF, 0); //crc off\r
810         if(v){goto bad;}\r
811 \r
812         // now set the sd card back to full speed.\r
813         // The SD Card spec says we can run SPI @ 25MHz\r
814         SDCard_Stop();\r
815 \r
816         // We can't run at full-speed with the pullup resistors enabled.\r
817         SD_MISO_SetDriveMode(SD_MISO_DM_DIG_HIZ);\r
818         SD_MOSI_SetDriveMode(SD_MOSI_DM_STRONG);\r
819         SD_SCK_SetDriveMode(SD_SCK_DM_STRONG);\r
820 \r
821         SD_Data_Clk_SetDivider(clkDiv25MHz);\r
822         CyDelayUs(1);\r
823         SDCard_Start();\r
824 \r
825         // Clear out rubbish data through clock change\r
826         CyDelayUs(1);\r
827         SDCard_ReadRxStatus();\r
828         SDCard_ReadTxStatus();\r
829         SDCard_ClearFIFO();\r
830 \r
831         if (!sdReadCSD()) goto bad;\r
832         sdReadCID();\r
833 \r
834         result = 1;\r
835         goto out;\r
836 \r
837 bad:\r
838         SD_Data_Clk_SetDivider(clkDiv25MHz); // Restore the clock for our next retry\r
839         sdDev.capacity = 0;\r
840 \r
841 out:\r
842         sdClearStatus();\r
843         ledOff();\r
844         return result;\r
845 \r
846 }\r
847 \r
848 void sdWriteMultiSectorPrep()\r
849 {\r
850         uint8 v;\r
851 \r
852         // Set the number of blocks to pre-erase by the multiple block write command\r
853         // We don't care about the response - if the command is not accepted, writes\r
854         // will just be a bit slower.\r
855         // Max 22bit parameter.\r
856         uint32_t sdBlocks =\r
857                 transfer.blocks *\r
858                         SDSectorsPerSCSISector(scsiDev.target->liveCfg.bytesPerSector);\r
859         uint32 blocks = sdBlocks > 0x7FFFFF ? 0x7FFFFF : sdBlocks;\r
860         sdCommandAndResponse(SD_APP_CMD, 0);\r
861         sdCommandAndResponse(SD_APP_SET_WR_BLK_ERASE_COUNT, blocks);\r
862 \r
863         uint32 scsiLBA = (transfer.lba + transfer.currentBlock);\r
864         uint32 sdLBA =\r
865                 SCSISector2SD(\r
866                         scsiDev.target->cfg->sdSectorStart,\r
867                         scsiDev.target->liveCfg.bytesPerSector,\r
868                         scsiLBA);\r
869         if (!sdDev.ccs)\r
870         {\r
871                 sdLBA = sdLBA * SD_SECTOR_SIZE;\r
872         }\r
873         v = sdCommandAndResponse(SD_WRITE_MULTIPLE_BLOCK, sdLBA);\r
874         if (unlikely(v))\r
875         {\r
876                 scsiDiskReset();\r
877                 sdClearStatus();\r
878                 scsiDev.status = CHECK_CONDITION;\r
879                 scsiDev.target->sense.code = HARDWARE_ERROR;\r
880                 scsiDev.target->sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
881                 scsiDev.phase = STATUS;\r
882         }\r
883         else\r
884         {\r
885                 transfer.inProgress = 1;\r
886         }\r
887 }\r
888 \r
889 void sdPoll()\r
890 {\r
891         // Check if there's an SD card present.\r
892         if ((scsiDev.phase == BUS_FREE) &&\r
893                 (sdIOState == SD_IDLE))\r
894         {\r
895                 // The CS line is pulled high by the SD card.\r
896                 // De-assert the line, and check if it's high.\r
897                 // This isn't foolproof as it'll be left floating without\r
898                 // an SD card. We can't use the built-in pull-down resistor as it will\r
899                 // overpower the SD pullup resistor.\r
900                 SD_CS_Write(0);\r
901                 SD_CS_SetDriveMode(SD_CS_DM_DIG_HIZ);\r
902 \r
903                 // Delay extended to work with 60cm cables running cards at 2.85V\r
904                 CyDelayCycles(128);\r
905                 uint8_t cs = SD_CS_Read();\r
906                 SD_CS_SetDriveMode(SD_CS_DM_STRONG)     ;\r
907 \r
908                 if (cs && !(blockDev.state & DISK_PRESENT))\r
909                 {\r
910                         static int firstInit = 1;\r
911 \r
912                         // Debounce\r
913                         CyDelay(250);\r
914 \r
915                         if (sdInit())\r
916                         {\r
917                                 blockDev.state |= DISK_PRESENT | DISK_INITIALISED;\r
918 \r
919                                 if (!firstInit)\r
920                                 {\r
921                                         int i;\r
922                                         for (i = 0; i < MAX_SCSI_TARGETS; ++i)\r
923                                         {\r
924                                                 scsiDev.targets[i].unitAttention = PARAMETERS_CHANGED;\r
925                                         }\r
926                                 }\r
927                                 firstInit = 0;\r
928                         }\r
929                 }\r
930                 else if (!cs && (blockDev.state & DISK_PRESENT))\r
931                 {\r
932                         sdDev.capacity = 0;\r
933                         blockDev.state &= ~DISK_PRESENT;\r
934                         blockDev.state &= ~DISK_INITIALISED;\r
935                         int i;\r
936                         for (i = 0; i < MAX_SCSI_TARGETS; ++i)\r
937                         {\r
938                                 scsiDev.targets[i].unitAttention = PARAMETERS_CHANGED;\r
939                         }\r
940                 }\r
941         }\r
942 }\r
943 \r
944 #pragma GCC pop_options\r