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