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