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