ca3b494ad5692f605c95e13306286f571f69b5d9
[SCSI2SD-V6.git] / src / firmware / scsiPhy.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 "stm32f2xx.h"\r
19 #include "stm32f2xx_hal.h"\r
20 #include "stm32f2xx_hal_dma.h"\r
21 \r
22 #include "scsi.h"\r
23 #include "scsiPhy.h"\r
24 #include "trace.h"\r
25 #include "time.h"\r
26 #include "fpga.h"\r
27 #include "led.h"\r
28 \r
29 #include <string.h>\r
30 \r
31 // Slowest timing. Aim for 1.5MB/s, but it's likely to be faster.\r
32 // Assumes a 96MHz fpga clock.\r
33 #define SCSI_SCSI1_DESKEW 0x7\r
34 #define SCSI_SCSI1_TIMING ((0x7 << 4) | 0xF)\r
35 \r
36 // 5MB/s sync and async.\r
37 // Assumes a 96MHz fpga clock.\r
38 // 2:0 Deskew count, 55ns\r
39 // 6:4 Hold count, 53ns\r
40 // 3:0 Assertion count, 80ns\r
41 #define SCSI_SCSI2_DESKEW 0x6\r
42 #define SCSI_SCSI2_TIMING ((0x5 << 4) | 0x8)\r
43 \r
44 // 10MB/s\r
45 // 2:0 Deskew count, 25ns\r
46 // 6:4 Hold count, 33ns\r
47 // 3:0 Assertion count, 30ns\r
48 #define SCSI_FAST10_DESKEW 3\r
49 #define SCSI_FAST10_TIMING ((0x3 << 4) | 0x3)\r
50 \r
51 // 20MB/s\r
52 // 2:0 Deskew count, 12ns\r
53 // 6:4 Hold count, 17ns\r
54 // 3:0 Assertion count, 15ns\r
55 #define SCSI_FAST20_DESKEW 2\r
56 #define SCSI_FAST20_TIMING ((0x2 << 4) | 0x2)\r
57 \r
58 // Private DMA variables.\r
59 static int dmaInProgress = 0;\r
60 \r
61 static DMA_HandleTypeDef memToFSMC;\r
62 static DMA_HandleTypeDef fsmcToMem;\r
63 \r
64 \r
65 volatile uint8_t scsiRxDMAComplete;\r
66 volatile uint8_t scsiTxDMAComplete;\r
67 \r
68 #if 0\r
69 CY_ISR_PROTO(scsiRxCompleteISR);\r
70 CY_ISR(scsiRxCompleteISR)\r
71 {\r
72         traceIrq(trace_scsiRxCompleteISR);\r
73         scsiRxDMAComplete = 1;\r
74 }\r
75 \r
76 CY_ISR_PROTO(scsiTxCompleteISR);\r
77 CY_ISR(scsiTxCompleteISR)\r
78 {\r
79         traceIrq(trace_scsiTxCompleteISR);\r
80         scsiTxDMAComplete = 1;\r
81 }\r
82 #endif\r
83 \r
84 uint8_t scsiPhyFifoSel = 0; // global\r
85 \r
86 // scsi IRQ handler is initialised by the STM32 HAL. Connected to\r
87 // PE4\r
88 // Note: naming is important to ensure this function is listed in the\r
89 // vector table.\r
90 void EXTI4_IRQHandler()\r
91 {\r
92         traceIrq(trace_scsiResetISR);\r
93 \r
94         // Make sure that interrupt flag is set\r
95         if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_4) != RESET) {\r
96 \r
97                 // Clear interrupt flag\r
98                 __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_4);\r
99 \r
100                 scsiDev.resetFlag = scsiDev.resetFlag || scsiStatusRST();\r
101                 // TODO grab SEL status as well\r
102 \r
103         }\r
104 }\r
105 \r
106 static void assertFail()\r
107 {\r
108         while (1)\r
109         {\r
110                 s2s_ledOn();\r
111                 s2s_delay_ms(100);\r
112                 s2s_ledOff();\r
113                 s2s_delay_ms(100);\r
114         }\r
115 }\r
116 \r
117 void\r
118 scsiSetDataCount(uint32_t count)\r
119 {\r
120         *SCSI_DATA_CNT_HI = count >> 8;\r
121         *SCSI_DATA_CNT_LO = count & 0xff;\r
122         *SCSI_DATA_CNT_SET = 1;\r
123 }\r
124 \r
125 uint8_t\r
126 scsiReadByte(void)\r
127 {\r
128 #if FIFODEBUG\r
129         if (!scsiPhyFifoAltEmpty()) {\r
130                 // Force a lock-up.\r
131                 assertFail();\r
132         }\r
133 #endif\r
134         scsiSetDataCount(1);\r
135 \r
136         trace(trace_spinPhyRxFifo);\r
137         while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {}\r
138         scsiPhyFifoFlip();\r
139         uint8_t val = scsiPhyRx();\r
140         // TODO scsiDev.parityError = scsiDev.parityError || SCSI_Parity_Error_Read();\r
141 \r
142 #if FIFODEBUG\r
143         if (!scsiPhyFifoEmpty()) {\r
144                 int j = 0;\r
145                 uint8_t k __attribute((unused));\r
146                 while (!scsiPhyFifoEmpty()) { k = scsiPhyRx(); ++j; }\r
147 \r
148                 // Force a lock-up.\r
149                 assertFail();\r
150         }\r
151 #endif\r
152         return val;\r
153 }\r
154 \r
155 \r
156 static void\r
157 scsiReadPIO(uint8_t* data, uint32_t count)\r
158 {\r
159         uint16_t* fifoData = (uint16_t*)data;\r
160         for (int i = 0; i < (count + 1) / 2; ++i)\r
161         {\r
162                 fifoData[i] = scsiPhyRx(); // TODO ASSUMES LITTLE ENDIAN\r
163         }\r
164         // TODO scsiDev.parityError = scsiDev.parityError || SCSI_Parity_Error_Read();\r
165 }\r
166 \r
167 void\r
168 scsiReadDMA(uint8_t* data, uint32_t count)\r
169 {\r
170         // Prepare DMA transfer\r
171         dmaInProgress = 1;\r
172         trace(trace_doRxSingleDMA);\r
173 \r
174         scsiTxDMAComplete = 1; // TODO not used much\r
175         scsiRxDMAComplete = 0; // TODO not used much\r
176 \r
177         HAL_DMA_Start(\r
178                 &fsmcToMem,\r
179                 (uint32_t) SCSI_FIFO_DATA,\r
180                 (uint32_t) data,\r
181                 (count + 1) / 2);\r
182 }\r
183 \r
184 int\r
185 scsiReadDMAPoll()\r
186 {\r
187         int complete = __HAL_DMA_GET_COUNTER(&fsmcToMem) == 0;\r
188         complete = complete && (HAL_DMA_PollForTransfer(&fsmcToMem, HAL_DMA_FULL_TRANSFER, 0xffffffff) == HAL_OK);\r
189         if (complete)\r
190         {\r
191                 scsiTxDMAComplete = 1; // TODO MM FIX IRQ\r
192                 scsiRxDMAComplete = 1;\r
193 \r
194                 dmaInProgress = 0;\r
195 #if 0\r
196                 // TODO MM scsiDev.parityError = scsiDev.parityError || SCSI_Parity_Error_Read();\r
197 #endif\r
198                 return 1;\r
199 \r
200         }\r
201         else\r
202         {\r
203                 return 0;\r
204         }\r
205 }\r
206 \r
207 void\r
208 scsiRead(uint8_t* data, uint32_t count)\r
209 {\r
210         int i = 0;\r
211 \r
212 \r
213         uint32_t chunk = ((count - i) > SCSI_FIFO_DEPTH)\r
214                 ? SCSI_FIFO_DEPTH : (count - i);\r
215 #ifdef SCSI_FSMC_DMA\r
216         if (chunk >= 16)\r
217         {\r
218                 // DMA is doing 32bit transfers.\r
219                 chunk = chunk & 0xFFFFFFF8;\r
220         }\r
221 #endif\r
222         scsiSetDataCount(chunk);\r
223 \r
224         while (i < count && likely(!scsiDev.resetFlag))\r
225         {\r
226                 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {}\r
227                 scsiPhyFifoFlip();\r
228 \r
229                 uint32_t nextChunk = ((count - i - chunk) > SCSI_FIFO_DEPTH)\r
230                         ? SCSI_FIFO_DEPTH : (count - i - chunk);\r
231 #ifdef SCSI_FSMC_DMA\r
232                 if (nextChunk >= 16)\r
233                 {\r
234                         nextChunk = nextChunk & 0xFFFFFFF8;\r
235                 }\r
236 #endif\r
237                 if (nextChunk > 0)\r
238                 {\r
239                         scsiSetDataCount(nextChunk);\r
240                 }\r
241 \r
242 #ifdef SCSI_FSMC_DMA\r
243                 if (chunk < 16)\r
244 #endif\r
245                 {\r
246                         scsiReadPIO(data + i, chunk);\r
247                 }\r
248 #ifdef SCSI_FSMC_DMA\r
249                 else\r
250                 {\r
251                         scsiReadDMA(data + i, chunk);\r
252 \r
253                         trace(trace_spinReadDMAPoll);\r
254 \r
255                         while (!scsiReadDMAPoll() && likely(!scsiDev.resetFlag))\r
256                         {\r
257                         };\r
258                 }\r
259 #endif\r
260 \r
261 \r
262                 i += chunk;\r
263                 chunk = nextChunk;\r
264         }\r
265 #if FIFODEBUG\r
266                 if (!scsiPhyFifoEmpty() || !scsiPhyFifoAltEmpty()) {\r
267                         int j = 0;\r
268                         while (!scsiPhyFifoEmpty()) { scsiPhyRx(); ++j; }\r
269                         scsiPhyFifoFlip();\r
270                         int k = 0;\r
271                         while (!scsiPhyFifoEmpty()) { scsiPhyRx(); ++k; }\r
272                         // Force a lock-up.\r
273                         assertFail();\r
274                 }\r
275 #endif\r
276 }\r
277 \r
278 void\r
279 scsiWriteByte(uint8_t value)\r
280 {\r
281 #if FIFODEBUG\r
282         if (!scsiPhyFifoEmpty()) {\r
283                 // Force a lock-up.\r
284                 assertFail();\r
285         }\r
286 #endif\r
287         trace(trace_spinPhyTxFifo);\r
288         scsiPhyTx(value);\r
289         scsiPhyFifoFlip();\r
290 \r
291         scsiSetDataCount(1);\r
292 \r
293         trace(trace_spinTxComplete);\r
294         while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {}\r
295 \r
296 #if FIFODEBUG\r
297         if (!scsiPhyFifoAltEmpty()) {\r
298                 // Force a lock-up.\r
299                 assertFail();\r
300         }\r
301 #endif\r
302 }\r
303 \r
304 static void\r
305 scsiWritePIO(const uint8_t* data, uint32_t count)\r
306 {\r
307         uint16_t* fifoData = (uint16_t*)data;\r
308         for (int i = 0; i < (count + 1) / 2; ++i)\r
309         {\r
310                 scsiPhyTx(fifoData[i]);\r
311         }\r
312 }\r
313 \r
314 void\r
315 scsiWriteDMA(const uint8_t* data, uint32_t count)\r
316 {\r
317         // Prepare DMA transfer\r
318         dmaInProgress = 1;\r
319         trace(trace_doTxSingleDMA);\r
320 \r
321         scsiTxDMAComplete = 0;\r
322         scsiRxDMAComplete = 1;\r
323 \r
324         HAL_DMA_Start(\r
325                 &memToFSMC,\r
326                 (uint32_t) data,\r
327                 (uint32_t) SCSI_FIFO_DATA,\r
328                 count / 4);\r
329 }\r
330 \r
331 int\r
332 scsiWriteDMAPoll()\r
333 {\r
334         int complete = __HAL_DMA_GET_COUNTER(&memToFSMC) == 0;\r
335         complete = complete && (HAL_DMA_PollForTransfer(&memToFSMC, HAL_DMA_FULL_TRANSFER, 0xffffffff) == HAL_OK);\r
336         if (complete)\r
337         {\r
338                 scsiTxDMAComplete = 1; // TODO MM FIX IRQ\r
339                 scsiRxDMAComplete = 1;\r
340 \r
341                 dmaInProgress = 0;\r
342                 return 1;\r
343         }\r
344         else\r
345         {\r
346                 return 0;\r
347         }\r
348 }\r
349 \r
350 void\r
351 scsiWrite(const uint8_t* data, uint32_t count)\r
352 {\r
353         int i = 0;\r
354         while (i < count && likely(!scsiDev.resetFlag))\r
355         {\r
356                 uint32_t chunk = ((count - i) > SCSI_FIFO_DEPTH)\r
357                         ? SCSI_FIFO_DEPTH : (count - i);\r
358 \r
359 #if FIFODEBUG\r
360                 if (!scsiPhyFifoEmpty()) {\r
361                         // Force a lock-up.\r
362                         assertFail();\r
363                 }\r
364 #endif\r
365 \r
366 #ifdef SCSI_FSMC_DMA\r
367                 if (chunk < 16)\r
368 #endif\r
369                 {\r
370                         scsiWritePIO(data + i, chunk);\r
371                 }\r
372 #ifdef SCSI_FSMC_DMA\r
373                 else\r
374                 {\r
375                         // DMA is doing 32bit transfers.\r
376                         chunk = chunk & 0xFFFFFFF8;\r
377                         scsiWriteDMA(data + i, chunk);\r
378 \r
379                         trace(trace_spinReadDMAPoll);\r
380 \r
381                         while (!scsiWriteDMAPoll() && likely(!scsiDev.resetFlag))\r
382                         {\r
383                         }\r
384                 }\r
385 #endif\r
386 \r
387                 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))\r
388                 {\r
389                 }\r
390 \r
391 #if FIFODEBUG\r
392                 if (!scsiPhyFifoAltEmpty()) {\r
393                         // Force a lock-up.\r
394                         assertFail();\r
395                 }\r
396 #endif\r
397 \r
398                 scsiPhyFifoFlip();\r
399                 scsiSetDataCount(chunk);\r
400                 i += chunk;\r
401         }\r
402         while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))\r
403         {\r
404         }\r
405 \r
406 #if FIFODEBUG\r
407         if (!scsiPhyFifoAltEmpty()) {\r
408                 // Force a lock-up.\r
409                 assertFail();\r
410         }\r
411 #endif\r
412 }\r
413 \r
414 static inline void busSettleDelay(void)\r
415 {\r
416         // Data Release time (switching IO) = 400ns\r
417         // + Bus Settle time (switching phase) = 400ns.\r
418         s2s_delay_us(1); // Close enough.\r
419 }\r
420 \r
421 void scsiEnterBusFree()\r
422 {\r
423         *SCSI_CTRL_BSY = 0x00;\r
424         // We now have a Bus Clear Delay of 800ns to release remaining signals.\r
425         *SCSI_CTRL_PHASE = 0;\r
426 }\r
427 \r
428 void scsiEnterPhase(int phase)\r
429 {\r
430         // ANSI INCITS 362-2002 SPI-3 10.7.1:\r
431         // Phase changes are not allowed while REQ or ACK is asserted.\r
432         while (likely(!scsiDev.resetFlag) && scsiStatusACK()) {}\r
433 \r
434         int newPhase = phase > 0 ? phase : 0;\r
435         int oldPhase = *SCSI_CTRL_PHASE;\r
436 \r
437         if (!scsiDev.resetFlag && (!scsiPhyFifoEmpty() || !scsiPhyFifoAltEmpty())) {\r
438                 // Force a lock-up.\r
439                 assertFail();\r
440         }\r
441         if (newPhase != oldPhase)\r
442         {\r
443                 if ((newPhase == DATA_IN || newPhase == DATA_OUT) &&\r
444                         scsiDev.target->syncOffset)\r
445                 {\r
446                         if (scsiDev.target->syncPeriod == 12)\r
447                         {\r
448                                 // SCSI2 FAST-20 Timing. 20MB/s.\r
449                                 *SCSI_CTRL_DESKEW = SCSI_FAST20_DESKEW;\r
450                                 *SCSI_CTRL_TIMING = SCSI_FAST20_TIMING;\r
451                         }\r
452                         else if (scsiDev.target->syncPeriod == 25)\r
453                         {\r
454                                 // SCSI2 FAST Timing. 10MB/s.\r
455                                 *SCSI_CTRL_DESKEW = SCSI_FAST10_DESKEW;\r
456                                 *SCSI_CTRL_TIMING = SCSI_FAST10_TIMING;\r
457                         } else {\r
458                                 // 5MB/s Timing\r
459                                 *SCSI_CTRL_DESKEW = SCSI_SCSI2_DESKEW;\r
460                                 *SCSI_CTRL_TIMING = SCSI_SCSI2_TIMING;\r
461                         }\r
462 \r
463                         *SCSI_CTRL_SYNC_OFFSET = scsiDev.target->syncOffset;\r
464                 } else {\r
465                         *SCSI_CTRL_SYNC_OFFSET = 0;\r
466 \r
467                         if (scsiDev.compatMode >= COMPAT_SCSI2) {\r
468                                 // 5MB/s Timing\r
469                                 *SCSI_CTRL_DESKEW = SCSI_SCSI2_DESKEW;\r
470                                 *SCSI_CTRL_TIMING = SCSI_SCSI2_TIMING;\r
471                         } else {\r
472                                 *SCSI_CTRL_DESKEW = SCSI_SCSI1_DESKEW;\r
473                                 *SCSI_CTRL_TIMING = SCSI_SCSI1_TIMING;\r
474                         }\r
475                 }\r
476 \r
477                 *SCSI_CTRL_PHASE = newPhase;\r
478                 busSettleDelay();\r
479 \r
480                 if (scsiDev.compatMode < COMPAT_SCSI2)\r
481                 {\r
482                         s2s_delay_us(100);\r
483                 }\r
484 \r
485         }\r
486 }\r
487 \r
488 void scsiPhyReset()\r
489 {\r
490         trace(trace_scsiPhyReset);\r
491         if (dmaInProgress)\r
492         {\r
493                 trace(trace_spinDMAReset);\r
494                 HAL_DMA_Abort(&memToFSMC);\r
495                 HAL_DMA_Abort(&fsmcToMem);\r
496 \r
497                 dmaInProgress = 0;\r
498         }\r
499 \r
500         *SCSI_CTRL_PHASE = 0x00;\r
501         *SCSI_CTRL_BSY = 0x00;\r
502         s2s_fpgaReset(); // Clears fifos etc.\r
503 \r
504         scsiPhyFifoSel = 0;\r
505         *SCSI_FIFO_SEL = 0;\r
506         *SCSI_CTRL_DBX = 0;\r
507 \r
508         *SCSI_CTRL_SYNC_OFFSET = 0;\r
509         *SCSI_CTRL_DESKEW = SCSI_SCSI1_DESKEW;\r
510         *SCSI_CTRL_TIMING = SCSI_SCSI1_TIMING;\r
511 \r
512         // DMA Benchmark code\r
513         // Currently 11MB/s.\r
514         #ifdef DMA_BENCHMARK\r
515         while(1)\r
516         {\r
517                 s2s_ledOn();\r
518                 // 100MB\r
519                 for (int i = 0; i < (100LL * 1024 * 1024 / SCSI_FIFO_DEPTH); ++i)\r
520                 {\r
521                         HAL_DMA_Start(\r
522                                 &memToFSMC,\r
523                                 (uint32_t) &scsiDev.data[0],\r
524                                 (uint32_t) SCSI_FIFO_DATA,\r
525                                 SCSI_FIFO_DEPTH / 4);\r
526 \r
527                         HAL_DMA_PollForTransfer(\r
528                                 &memToFSMC,\r
529                                 HAL_DMA_FULL_TRANSFER,\r
530                                 0xffffffff);\r
531 \r
532                         s2s_fpgaReset();\r
533                 }\r
534                 s2s_ledOff();\r
535 \r
536                 for(int i = 0; i < 10; ++i) s2s_delay_ms(1000);\r
537         }\r
538         #endif\r
539 \r
540         // FPGA comms test code\r
541         #ifdef FPGA_TEST\r
542         while(1)\r
543         {\r
544                 for (int j = 0; j < SCSI_FIFO_DEPTH; ++j)\r
545                 {\r
546                         scsiDev.data[j] = j;\r
547                 }\r
548 \r
549                 if (!scsiPhyFifoEmpty())\r
550                 {\r
551                         assertFail();\r
552                 }\r
553 \r
554                 *SCSI_CTRL_PHASE = DATA_IN;\r
555                 HAL_DMA_Start(\r
556                         &memToFSMC,\r
557                         (uint32_t) &scsiDev.data[0],\r
558                         (uint32_t) SCSI_FIFO_DATA,\r
559                         SCSI_FIFO_DEPTH / 4);\r
560 \r
561                 HAL_DMA_PollForTransfer(\r
562                         &memToFSMC,\r
563                         HAL_DMA_FULL_TRANSFER,\r
564                         0xffffffff);\r
565 \r
566                 if (!scsiPhyFifoFull())\r
567                 {\r
568                         assertFail();\r
569                 }\r
570 \r
571                 memset(&scsiDev.data[0], 0, SCSI_FIFO_DEPTH);\r
572 \r
573                 *SCSI_CTRL_PHASE = DATA_OUT;\r
574                 HAL_DMA_Start(\r
575                         &fsmcToMem,\r
576                         (uint32_t) SCSI_FIFO_DATA,\r
577                         (uint32_t) &scsiDev.data[0],\r
578                         SCSI_FIFO_DEPTH / 2);\r
579 \r
580                 HAL_DMA_PollForTransfer(\r
581                         &fsmcToMem,\r
582                         HAL_DMA_FULL_TRANSFER,\r
583                         0xffffffff);\r
584 \r
585                 if (!scsiPhyFifoEmpty())\r
586                 {\r
587                         assertFail();\r
588                 }\r
589 \r
590 \r
591                 for (int j = 0; j < SCSI_FIFO_DEPTH; ++j)\r
592                 {\r
593                         if (scsiDev.data[j] != (uint8_t) j)\r
594                         {\r
595                                 assertFail();\r
596                         }\r
597                 }\r
598 \r
599                 s2s_fpgaReset();\r
600 \r
601         }\r
602         #endif\r
603 \r
604 }\r
605 \r
606 static void scsiPhyInitDMA()\r
607 {\r
608         // One-time init only.\r
609         static uint8_t init = 0;\r
610         if (init == 0)\r
611         {\r
612                 init = 1;\r
613 \r
614                 // Memory to memory transfers can only be done using DMA2\r
615                 __DMA2_CLK_ENABLE();\r
616 \r
617                 // Transmit SCSI data. The source data is treated as the\r
618                 // peripheral (even though this is memory-to-memory)\r
619                 memToFSMC.Instance = DMA2_Stream0;\r
620                 memToFSMC.Init.Channel = DMA_CHANNEL_0;\r
621                 memToFSMC.Init.Direction = DMA_MEMORY_TO_MEMORY;\r
622                 memToFSMC.Init.PeriphInc = DMA_PINC_ENABLE;\r
623                 memToFSMC.Init.MemInc = DMA_MINC_DISABLE;\r
624                 memToFSMC.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;\r
625                 memToFSMC.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;\r
626                 memToFSMC.Init.Mode = DMA_NORMAL;\r
627                 memToFSMC.Init.Priority = DMA_PRIORITY_LOW;\r
628                 // FIFO mode is needed to allow conversion from 32bit words to the\r
629                 // 16bit FSMC interface.\r
630                 memToFSMC.Init.FIFOMode = DMA_FIFOMODE_ENABLE;\r
631 \r
632                 // We only use 1 word (4 bytes) in the fifo at a time. Normally it's\r
633                 // better to let the DMA fifo fill up then do burst transfers, but\r
634                 // bursting out the FSMC interface will be very slow and may starve\r
635                 // other (faster) transfers. We don't want to risk the SDIO transfers\r
636                 // from overrun/underrun conditions.\r
637                 memToFSMC.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;\r
638                 memToFSMC.Init.MemBurst = DMA_MBURST_SINGLE;\r
639                 memToFSMC.Init.PeriphBurst = DMA_PBURST_SINGLE;\r
640                 HAL_DMA_Init(&memToFSMC);\r
641 \r
642                 // Receive SCSI data. The source data (fsmc) is treated as the\r
643                 // peripheral (even though this is memory-to-memory)\r
644                 fsmcToMem.Instance = DMA2_Stream1;\r
645                 fsmcToMem.Init.Channel = DMA_CHANNEL_0;\r
646                 fsmcToMem.Init.Direction = DMA_MEMORY_TO_MEMORY;\r
647                 fsmcToMem.Init.PeriphInc = DMA_PINC_DISABLE;\r
648                 fsmcToMem.Init.MemInc = DMA_MINC_ENABLE;\r
649                 fsmcToMem.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;\r
650                 fsmcToMem.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;\r
651                 fsmcToMem.Init.Mode = DMA_NORMAL;\r
652                 fsmcToMem.Init.Priority = DMA_PRIORITY_LOW;\r
653                 fsmcToMem.Init.FIFOMode = DMA_FIFOMODE_ENABLE;\r
654                 fsmcToMem.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;\r
655                 fsmcToMem.Init.MemBurst = DMA_MBURST_SINGLE;\r
656                 fsmcToMem.Init.PeriphBurst = DMA_PBURST_SINGLE;\r
657                 HAL_DMA_Init(&fsmcToMem);\r
658 \r
659                 // TODO configure IRQs\r
660         }\r
661 }\r
662 \r
663 \r
664 void scsiPhyInit()\r
665 {\r
666         scsiPhyInitDMA();\r
667 \r
668         *SCSI_CTRL_IDMASK = 0x00; // Reset in scsiPhyConfig\r
669         *SCSI_CTRL_PHASE = 0x00;\r
670         *SCSI_CTRL_BSY = 0x00;\r
671         scsiPhyFifoSel = 0;\r
672         *SCSI_FIFO_SEL = 0;\r
673         *SCSI_CTRL_DBX = 0;\r
674 \r
675         *SCSI_CTRL_SYNC_OFFSET = 0;\r
676         *SCSI_CTRL_DESKEW = SCSI_SCSI1_DESKEW;\r
677         *SCSI_CTRL_TIMING = SCSI_SCSI1_TIMING;\r
678 \r
679 }\r
680 \r
681 void scsiPhyConfig()\r
682 {\r
683         if (scsiDev.boardCfg.flags6 & S2S_CFG_ENABLE_TERMINATOR)\r
684         {\r
685                 HAL_GPIO_WritePin(nTERM_EN_GPIO_Port, nTERM_EN_Pin, GPIO_PIN_RESET);\r
686         }\r
687         else\r
688         {\r
689                 HAL_GPIO_WritePin(nTERM_EN_GPIO_Port, nTERM_EN_Pin, GPIO_PIN_SET);\r
690         }\r
691 \r
692 \r
693         uint8_t idMask = 0;\r
694         for (int i = 0; i < 8; ++i)\r
695         {\r
696                 const S2S_TargetCfg* cfg = s2s_getConfigById(i);\r
697                 if (cfg && (cfg->scsiId & S2S_CFG_TARGET_ENABLED))\r
698                 {\r
699                         idMask |= (1 << i);\r
700                 }\r
701         }\r
702         *SCSI_CTRL_IDMASK = idMask;\r
703 \r
704         *SCSI_CTRL_FLAGS =\r
705                 (scsiDev.boardCfg.flags & S2S_CFG_DISABLE_GLITCH) ? 1 : 0;\r
706 \r
707 }\r
708 \r
709 \r
710 // 1 = DBx error\r
711 // 2 = Parity error\r
712 // 4 = MSG error\r
713 // 8 = CD error\r
714 // 16 = IO error\r
715 // 32 = other error\r
716 int scsiSelfTest()\r
717 {\r
718         if (scsiDev.phase != BUS_FREE)\r
719         {\r
720                 return 32;\r
721         }\r
722 \r
723         // Acquire the SCSI bus.\r
724         for (int i = 0; i < 100; ++i)\r
725         {\r
726                 if (scsiStatusBSY())\r
727                 {\r
728                         s2s_delay_ms(1);\r
729                 }\r
730         }\r
731         if (scsiStatusBSY())\r
732         {\r
733                 // Error, couldn't acquire scsi bus\r
734                 return 32;\r
735         }\r
736         *SCSI_CTRL_BSY = 1;\r
737         if (! scsiStatusBSY())\r
738         {\r
739                 // Error, BSY doesn't work.\r
740                 return 32;\r
741         }\r
742 \r
743         // Should be safe to use the bus now.\r
744 \r
745         int result = 0;\r
746 \r
747         // TEST DBx\r
748         // TODO test DBp\r
749         int i;\r
750         for (i = 0; i < 256; ++i)\r
751         {\r
752                 *SCSI_CTRL_DBX = i;\r
753                 busSettleDelay();\r
754                 if (*SCSI_STS_DBX != (i & 0xff))\r
755                 {\r
756                         result |= 1;\r
757                 }\r
758                 /*if (Lookup_OddParity[i & 0xff] != SCSI_ReadPin(SCSI_In_DBP))\r
759                 {\r
760                         result |= 2;\r
761                 }*/\r
762         }\r
763         *SCSI_CTRL_DBX = 0;\r
764 \r
765         // TEST MSG, CD, IO\r
766         /* TODO\r
767         for (i = 0; i < 8; ++i)\r
768         {\r
769                 SCSI_CTL_PHASE_Write(i);\r
770                 scsiDeskewDelay();\r
771 \r
772                 if (SCSI_ReadPin(SCSI_In_MSG) != !!(i & __scsiphase_msg))\r
773                 {\r
774                         result |= 4;\r
775                 }\r
776                 if (SCSI_ReadPin(SCSI_In_CD) != !!(i & __scsiphase_cd))\r
777                 {\r
778                         result |= 8;\r
779                 }\r
780                 if (SCSI_ReadPin(SCSI_In_IO) != !!(i & __scsiphase_io))\r
781                 {\r
782                         result |= 16;\r
783                 }\r
784         }\r
785         SCSI_CTL_PHASE_Write(0);\r
786 \r
787         uint32_t signalsOut[] = { SCSI_Out_ATN, SCSI_Out_BSY, SCSI_Out_RST, SCSI_Out_SEL };\r
788         uint32_t signalsIn[] = { SCSI_Filt_ATN, SCSI_Filt_BSY, SCSI_Filt_RST, SCSI_Filt_SEL };\r
789 \r
790         for (i = 0; i < 4; ++i)\r
791         {\r
792                 SCSI_SetPin(signalsOut[i]);\r
793                 scsiDeskewDelay();\r
794 \r
795                 int j;\r
796                 for (j = 0; j < 4; ++j)\r
797                 {\r
798                         if (i == j)\r
799                         {\r
800                                 if (! SCSI_ReadFilt(signalsIn[j]))\r
801                                 {\r
802                                         result |= 32;\r
803                                 }\r
804                         }\r
805                         else\r
806                         {\r
807                                 if (SCSI_ReadFilt(signalsIn[j]))\r
808                                 {\r
809                                         result |= 32;\r
810                                 }\r
811                         }\r
812                 }\r
813                 SCSI_ClearPin(signalsOut[i]);\r
814         }\r
815         */\r
816 \r
817         *SCSI_CTRL_BSY = 0;\r
818         return result;\r
819 }\r
820 \r