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