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