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