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