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