1 // Copyright (C) 2013 Michael McMaster <michael@codesrc.com>
3 // This file is part of SCSI2SD.
5 // SCSI2SD is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // SCSI2SD is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
17 #pragma GCC push_options
18 #pragma GCC optimize("-flto")
25 #define scsiTarget_AUX_CTL (* (reg8 *) scsiTarget_datapath__DP_AUX_CTL_REG)
27 // DMA controller can't handle any more bytes.
28 #define MAX_DMA_BYTES 4095
30 // Private DMA variables.
31 static int dmaInProgress
= 0;
32 // used when transferring > MAX_DMA_BYTES.
33 static uint8_t* dmaBuffer
= NULL
;
34 static uint32_t dmaSentCount
= 0;
35 static uint32_t dmaTotalCount
= 0;
37 static uint8 scsiDmaRxChan
= CY_DMA_INVALID_CHANNEL
;
38 static uint8 scsiDmaTxChan
= CY_DMA_INVALID_CHANNEL
;
41 static uint8 scsiDmaRxTd
[1] = { CY_DMA_INVALID_TD
};
42 static uint8 scsiDmaTxTd
[1] = { CY_DMA_INVALID_TD
};
44 // Source of dummy bytes for DMA reads
45 static uint8 dummyBuffer
= 0xFF;
47 volatile uint8_t scsiRxDMAComplete
;
48 volatile uint8_t scsiTxDMAComplete
;
50 CY_ISR_PROTO(scsiRxCompleteISR
);
51 CY_ISR(scsiRxCompleteISR
)
53 scsiRxDMAComplete
= 1;
56 CY_ISR_PROTO(scsiTxCompleteISR
);
57 CY_ISR(scsiTxCompleteISR
)
59 scsiTxDMAComplete
= 1;
62 CY_ISR_PROTO(scsiResetISR
);
65 scsiDev
.resetFlag
= 1;
72 (SCSI_ReadPin(SCSI_In_DBx_DB7
) << 7) |
73 (SCSI_ReadPin(SCSI_In_DBx_DB6
) << 6) |
74 (SCSI_ReadPin(SCSI_In_DBx_DB5
) << 5) |
75 (SCSI_ReadPin(SCSI_In_DBx_DB4
) << 4) |
76 (SCSI_ReadPin(SCSI_In_DBx_DB3
) << 3) |
77 (SCSI_ReadPin(SCSI_In_DBx_DB2
) << 2) |
78 (SCSI_ReadPin(SCSI_In_DBx_DB1
) << 1) |
79 SCSI_ReadPin(SCSI_In_DBx_DB0
);
85 while (unlikely(scsiPhyTxFifoFull()) && likely(!scsiDev
.resetFlag
)) {}
88 while (scsiPhyRxFifoEmpty() && likely(!scsiDev
.resetFlag
)) {}
89 uint8_t val
= scsiPhyRx();
90 scsiDev
.parityError
= scsiDev
.parityError
|| SCSI_Parity_Error_Read();
92 while (!(scsiPhyStatus() & SCSI_PHY_TX_COMPLETE
) && likely(!scsiDev
.resetFlag
)) {}
98 scsiReadPIO(uint8
* data
, uint32 count
)
103 while (i
< count
&& likely(!scsiDev
.resetFlag
))
105 uint8_t status
= scsiPhyStatus();
107 if (prep
< count
&& (status
& SCSI_PHY_TX_FIFO_NOT_FULL
))
112 if (status
& SCSI_PHY_RX_FIFO_NOT_EMPTY
)
114 data
[i
] = scsiPhyRx();
118 scsiDev
.parityError
= scsiDev
.parityError
|| SCSI_Parity_Error_Read();
119 while (!(scsiPhyStatus() & SCSI_PHY_TX_COMPLETE
) && likely(!scsiDev
.resetFlag
)) {}
123 doRxSingleDMA(uint8
* data
, uint32 count
)
125 // Prepare DMA transfer
128 CyDmaTdSetConfiguration(
131 CY_DMA_DISABLE_TD
, // Disable the DMA channel when TD completes count bytes
132 SCSI_TX_DMA__TD_TERMOUT_EN
// Trigger interrupt when complete
134 CyDmaTdSetConfiguration(
137 CY_DMA_DISABLE_TD
, // Disable the DMA channel when TD completes count bytes
139 SCSI_RX_DMA__TD_TERMOUT_EN
// Trigger interrupt when complete
144 LO16((uint32
)&dummyBuffer
),
145 LO16((uint32
)scsiTarget_datapath__F0_REG
));
148 LO16((uint32
)scsiTarget_datapath__F1_REG
),
152 CyDmaChSetInitialTd(scsiDmaTxChan
, scsiDmaTxTd
[0]);
153 CyDmaChSetInitialTd(scsiDmaRxChan
, scsiDmaRxTd
[0]);
155 // The DMA controller is a bit trigger-happy. It will retain
156 // a drq request that was triggered while the channel was
158 CyDmaClearPendingDrq(scsiDmaTxChan
);
159 CyDmaClearPendingDrq(scsiDmaRxChan
);
161 scsiTxDMAComplete
= 0;
162 scsiRxDMAComplete
= 0;
164 CyDmaChEnable(scsiDmaRxChan
, 1);
165 CyDmaChEnable(scsiDmaTxChan
, 1);
169 scsiReadDMA(uint8
* data
, uint32 count
)
172 dmaTotalCount
= count
;
175 uint32_t singleCount
= (count
> MAX_DMA_BYTES
) ? MAX_DMA_BYTES
: count
;
176 doRxSingleDMA(data
, singleCount
);
177 dmaSentCount
+= count
;
183 if (scsiTxDMAComplete
&& scsiRxDMAComplete
)
185 // Wait until our scsi signals are consistent. This should only be
187 while (!(scsiPhyStatus() & SCSI_PHY_TX_COMPLETE
)) {}
189 if (likely(dmaSentCount
== dmaTotalCount
))
192 scsiDev
.parityError
= scsiDev
.parityError
|| SCSI_Parity_Error_Read();
197 // Transfer was too large for a single DMA transfer. Continue
198 // to send remaining bytes.
199 uint32_t count
= dmaTotalCount
- dmaSentCount
;
200 if (unlikely(count
> MAX_DMA_BYTES
)) count
= MAX_DMA_BYTES
;
201 doRxSingleDMA(dmaBuffer
+ dmaSentCount
, count
);
202 dmaSentCount
+= count
;
213 scsiRead(uint8_t* data
, uint32_t count
)
217 scsiReadPIO(data
, count
);
221 scsiReadDMA(data
, count
);
223 // Wait for the next DMA interrupt (or the 1ms systick)
224 // It's beneficial to halt the processor to
225 // give the DMA controller more memory bandwidth to work with.
228 while (!scsiReadDMAPoll() && likely(!scsiDev
.resetFlag
)) {};
233 scsiWriteByte(uint8 value
)
235 while (unlikely(scsiPhyTxFifoFull()) && likely(!scsiDev
.resetFlag
)) {}
238 while (!(scsiPhyStatus() & SCSI_PHY_TX_COMPLETE
) && likely(!scsiDev
.resetFlag
)) {}
239 scsiPhyRxFifoClear();
243 scsiWritePIO(const uint8_t* data
, uint32_t count
)
247 while (i
< count
&& likely(!scsiDev
.resetFlag
))
249 if (!scsiPhyTxFifoFull())
256 while (!(scsiPhyStatus() & SCSI_PHY_TX_COMPLETE
) && likely(!scsiDev
.resetFlag
)) {}
257 scsiPhyRxFifoClear();
261 doTxSingleDMA(const uint8
* data
, uint32 count
)
263 // Prepare DMA transfer
266 CyDmaTdSetConfiguration(
269 CY_DMA_DISABLE_TD
, // Disable the DMA channel when TD completes count bytes
271 SCSI_TX_DMA__TD_TERMOUT_EN
// Trigger interrupt when complete
276 LO16((uint32
)scsiTarget_datapath__F0_REG
));
277 CyDmaChSetInitialTd(scsiDmaTxChan
, scsiDmaTxTd
[0]);
279 // The DMA controller is a bit trigger-happy. It will retain
280 // a drq request that was triggered while the channel was
282 CyDmaClearPendingDrq(scsiDmaTxChan
);
284 scsiTxDMAComplete
= 0;
285 scsiRxDMAComplete
= 1;
287 CyDmaChEnable(scsiDmaTxChan
, 1);
291 scsiWriteDMA(const uint8
* data
, uint32 count
)
294 dmaTotalCount
= count
;
297 uint32_t singleCount
= (count
> MAX_DMA_BYTES
) ? MAX_DMA_BYTES
: count
;
298 doTxSingleDMA(data
, singleCount
);
299 dmaSentCount
+= count
;
305 if (scsiTxDMAComplete
)
307 // Wait until our scsi signals are consistent. This should only be
309 while (!(scsiPhyStatus() & SCSI_PHY_TX_COMPLETE
)) {}
311 if (likely(dmaSentCount
== dmaTotalCount
))
313 scsiPhyRxFifoClear();
319 // Transfer was too large for a single DMA transfer. Continue
320 // to send remaining bytes.
321 uint32_t count
= dmaTotalCount
- dmaSentCount
;
322 if (unlikely(count
> MAX_DMA_BYTES
)) count
= MAX_DMA_BYTES
;
323 doTxSingleDMA(dmaBuffer
+ dmaSentCount
, count
);
324 dmaSentCount
+= count
;
335 scsiWrite(const uint8_t* data
, uint32_t count
)
339 scsiWritePIO(data
, count
);
343 scsiWriteDMA(data
, count
);
345 // Wait for the next DMA interrupt (or the 1ms systick)
346 // It's beneficial to halt the processor to
347 // give the DMA controller more memory bandwidth to work with.
350 while (!scsiWriteDMAPoll() && likely(!scsiDev
.resetFlag
)) {};
354 static inline void busSettleDelay(void)
356 // Data Release time (switching IO) = 400ns
357 // + Bus Settle time (switching phase) = 400ns.
358 CyDelayUs(1); // Close enough.
361 void scsiEnterPhase(int phase
)
363 int newPhase
= phase
> 0 ? phase
: 0;
364 if (newPhase
!= SCSI_CTL_PHASE_Read())
366 SCSI_CTL_PHASE_Write(phase
> 0 ? phase
: 0);
379 CyDmaChSetRequest(scsiDmaTxChan
, CY_DMA_CPU_TERM_CHAIN
);
380 CyDmaChSetRequest(scsiDmaRxChan
, CY_DMA_CPU_TERM_CHAIN
);
381 while (!(scsiTxDMAComplete
&& scsiRxDMAComplete
)) {}
383 CyDmaChDisable(scsiDmaTxChan
);
384 CyDmaChDisable(scsiDmaRxChan
);
387 // Set the Clear bits for both SCSI device FIFOs
388 scsiTarget_AUX_CTL
= scsiTarget_AUX_CTL
| 0x03;
390 // Trigger RST outselves. It is connected to the datapath and will
391 // ensure it returns to the idle state. The datapath runs at the BUS clk
392 // speed (ie. same as the CPU), so we can be sure it is active for a sufficient
394 SCSI_SetPin(SCSI_Out_RST
);
396 SCSI_CTL_PHASE_Write(0);
397 SCSI_ClearPin(SCSI_Out_ATN
);
398 SCSI_ClearPin(SCSI_Out_BSY
);
399 SCSI_ClearPin(SCSI_Out_ACK
);
400 SCSI_ClearPin(SCSI_Out_RST
);
401 SCSI_ClearPin(SCSI_Out_SEL
);
402 SCSI_ClearPin(SCSI_Out_REQ
);
404 // Allow the FIFOs to fill up again.
405 SCSI_ClearPin(SCSI_Out_RST
);
406 scsiTarget_AUX_CTL
= scsiTarget_AUX_CTL
& ~(0x03);
408 SCSI_Parity_Error_Read(); // clear sticky bits
411 static void scsiPhyInitDMA()
413 // One-time init only.
414 if (scsiDmaTxChan
== CY_DMA_INVALID_CHANNEL
)
417 SCSI_RX_DMA_DmaInitialize(
418 1, // Bytes per burst
419 1, // request per burst
420 HI16(CYDEV_PERIPH_BASE
),
421 HI16(CYDEV_SRAM_BASE
)
425 SCSI_TX_DMA_DmaInitialize(
426 1, // Bytes per burst
427 1, // request per burst
428 HI16(CYDEV_SRAM_BASE
),
429 HI16(CYDEV_PERIPH_BASE
)
432 CyDmaChDisable(scsiDmaRxChan
);
433 CyDmaChDisable(scsiDmaTxChan
);
435 scsiDmaRxTd
[0] = CyDmaTdAllocate();
436 scsiDmaTxTd
[0] = CyDmaTdAllocate();
438 SCSI_RX_DMA_COMPLETE_StartEx(scsiRxCompleteISR
);
439 SCSI_TX_DMA_COMPLETE_StartEx(scsiTxCompleteISR
);
448 SCSI_RST_ISR_StartEx(scsiResetISR
);
463 SCSI_Out_Ctl_Write(1); // Write bits manually.
464 SCSI_CTL_PHASE_Write(__scsiphase_io
); // Needed for parity generation
465 for (i
= 0; i
< 256; ++i
)
467 SCSI_Out_Bits_Write(i
);
469 if (scsiReadDBxPins() != (i
& 0xff))
473 if (Lookup_OddParity
[i
& 0xff] != SCSI_ReadPin(SCSI_In_DBP
))
478 SCSI_Out_Ctl_Write(0); // Write bits normally.
481 for (i
= 0; i
< 8; ++i
)
483 SCSI_CTL_PHASE_Write(i
);
486 if (SCSI_ReadPin(SCSI_In_MSG
) != !!(i
& __scsiphase_msg
))
490 if (SCSI_ReadPin(SCSI_In_CD
) != !!(i
& __scsiphase_cd
))
494 if (SCSI_ReadPin(SCSI_In_IO
) != !!(i
& __scsiphase_io
))
499 SCSI_CTL_PHASE_Write(0);
501 uint32_t signalsOut
[] = { SCSI_Out_ATN
, SCSI_Out_BSY
, SCSI_Out_RST
, SCSI_Out_SEL
};
502 uint32_t signalsIn
[] = { SCSI_Filt_ATN
, SCSI_Filt_BSY
, SCSI_Filt_RST
, SCSI_Filt_SEL
};
504 for (i
= 0; i
< 4; ++i
)
506 SCSI_SetPin(signalsOut
[i
]);
510 for (j
= 0; j
< 4; ++j
)
514 if (! SCSI_ReadFilt(signalsIn
[j
]))
521 if (SCSI_ReadFilt(signalsIn
[j
]))
527 SCSI_ClearPin(signalsOut
[i
]);
533 #pragma GCC pop_options