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