|
@@ -30,6 +30,13 @@ static const char *g_scsi_phy_mode_names[] = {
|
|
|
"Unknown", "PIO", "DMA_TIMER", "GREENPAK_PIO", "GREENPAK_DMA"
|
|
"Unknown", "PIO", "DMA_TIMER", "GREENPAK_PIO", "GREENPAK_DMA"
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+// State of polling write request
|
|
|
|
|
+static struct {
|
|
|
|
|
+ const uint8_t *data;
|
|
|
|
|
+ uint32_t count;
|
|
|
|
|
+ bool use_sync_mode;
|
|
|
|
|
+} g_scsi_writereq;
|
|
|
|
|
+
|
|
|
static void init_irqs();
|
|
static void init_irqs();
|
|
|
|
|
|
|
|
/***********************/
|
|
/***********************/
|
|
@@ -170,6 +177,7 @@ extern "C" void scsiPhyReset(void)
|
|
|
|
|
|
|
|
g_scsi_sts_selection = 0;
|
|
g_scsi_sts_selection = 0;
|
|
|
g_scsi_ctrl_bsy = 0;
|
|
g_scsi_ctrl_bsy = 0;
|
|
|
|
|
+ g_scsi_writereq.count = 0;
|
|
|
init_irqs();
|
|
init_irqs();
|
|
|
|
|
|
|
|
#ifdef SCSI_SYNC_MODE_AVAILABLE
|
|
#ifdef SCSI_SYNC_MODE_AVAILABLE
|
|
@@ -300,21 +308,15 @@ extern "C" void scsiWrite(const uint8_t* data, uint32_t count)
|
|
|
scsiFinishWrite();
|
|
scsiFinishWrite();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static struct {
|
|
|
|
|
- const uint8_t *data;
|
|
|
|
|
- uint32_t count;
|
|
|
|
|
-} g_scsi_writereq;
|
|
|
|
|
-
|
|
|
|
|
extern "C" void scsiStartWrite(const uint8_t* data, uint32_t count)
|
|
extern "C" void scsiStartWrite(const uint8_t* data, uint32_t count)
|
|
|
{
|
|
{
|
|
|
scsiLogDataIn(data, count);
|
|
scsiLogDataIn(data, count);
|
|
|
|
|
|
|
|
- if (g_scsi_phase == DATA_IN && scsiDev.target->syncOffset > 0)
|
|
|
|
|
- {
|
|
|
|
|
- // Synchronous data transfer
|
|
|
|
|
- scsi_accel_sync_startWrite(data, count, &scsiDev.resetFlag);
|
|
|
|
|
- }
|
|
|
|
|
- else if (g_scsi_phy_mode == PHY_MODE_PIO || g_scsi_phy_mode == PHY_MODE_GREENPAK_PIO)
|
|
|
|
|
|
|
+ g_scsi_writereq.use_sync_mode = (g_scsi_phase == DATA_IN && scsiDev.target->syncOffset > 0);
|
|
|
|
|
+
|
|
|
|
|
+ if (g_scsi_phy_mode == PHY_MODE_PIO
|
|
|
|
|
+ || g_scsi_phy_mode == PHY_MODE_GREENPAK_PIO
|
|
|
|
|
+ || g_scsi_writereq.use_sync_mode)
|
|
|
{
|
|
{
|
|
|
// Software based bit-banging.
|
|
// Software based bit-banging.
|
|
|
// Write requests are queued and then executed in isWriteFinished() callback.
|
|
// Write requests are queued and then executed in isWriteFinished() callback.
|
|
@@ -356,20 +358,28 @@ static void processPollingWrite(uint32_t count)
|
|
|
|
|
|
|
|
const uint8_t *data = g_scsi_writereq.data;
|
|
const uint8_t *data = g_scsi_writereq.data;
|
|
|
uint32_t count_words = count / 4;
|
|
uint32_t count_words = count / 4;
|
|
|
- if (count_words * 4 == count)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if (g_scsi_writereq.use_sync_mode)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Synchronous mode transfer
|
|
|
|
|
+ scsi_accel_sync_send(data, count, &scsiDev.resetFlag);
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (count_words * 4 == count)
|
|
|
{
|
|
{
|
|
|
- // Use accelerated subroutine
|
|
|
|
|
if (g_scsi_phy_mode == PHY_MODE_GREENPAK_PIO)
|
|
if (g_scsi_phy_mode == PHY_MODE_GREENPAK_PIO)
|
|
|
{
|
|
{
|
|
|
|
|
+ // GreenPAK PIO accelerated asynchronous transfer
|
|
|
scsi_accel_greenpak_send((const uint32_t*)data, count_words, &scsiDev.resetFlag);
|
|
scsi_accel_greenpak_send((const uint32_t*)data, count_words, &scsiDev.resetFlag);
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
|
|
+ // Assembler optimized asynchronous transfer
|
|
|
scsi_accel_asm_send((const uint32_t*)data, count_words, &scsiDev.resetFlag);
|
|
scsi_accel_asm_send((const uint32_t*)data, count_words, &scsiDev.resetFlag);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
|
|
+ // Use simple loop for unaligned transfers
|
|
|
for (uint32_t i = 0; i < count; i++)
|
|
for (uint32_t i = 0; i < count; i++)
|
|
|
{
|
|
{
|
|
|
if (scsiDev.resetFlag) break;
|
|
if (scsiDev.resetFlag) break;
|
|
@@ -407,47 +417,37 @@ static bool isPollingWriteFinished(const uint8_t *data)
|
|
|
|
|
|
|
|
extern "C" bool scsiIsWriteFinished(const uint8_t *data)
|
|
extern "C" bool scsiIsWriteFinished(const uint8_t *data)
|
|
|
{
|
|
{
|
|
|
- if (g_scsi_phase == DATA_IN && scsiDev.target->syncOffset > 0)
|
|
|
|
|
|
|
+ // Check if there is still a polling transfer in progress
|
|
|
|
|
+ if (!isPollingWriteFinished(data))
|
|
|
{
|
|
{
|
|
|
- return scsi_accel_sync_isWriteFinished(data);
|
|
|
|
|
|
|
+ // Process the transfer piece-by-piece while waiting
|
|
|
|
|
+ // for SD card to react.
|
|
|
|
|
+ processPollingWrite(256);
|
|
|
|
|
+ return isPollingWriteFinished(data);
|
|
|
}
|
|
}
|
|
|
- else if (g_scsi_phy_mode == PHY_MODE_DMA_TIMER || g_scsi_phy_mode == PHY_MODE_GREENPAK_DMA)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if (g_scsi_phy_mode == PHY_MODE_DMA_TIMER || g_scsi_phy_mode == PHY_MODE_GREENPAK_DMA)
|
|
|
{
|
|
{
|
|
|
return scsi_accel_dma_isWriteFinished(data);
|
|
return scsi_accel_dma_isWriteFinished(data);
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
- // Check if there is still a polling transfer in progress
|
|
|
|
|
- if (!isPollingWriteFinished(data))
|
|
|
|
|
- {
|
|
|
|
|
- // Process the transfer piece-by-piece while waiting
|
|
|
|
|
- // for SD card to react.
|
|
|
|
|
- processPollingWrite(256);
|
|
|
|
|
- return isPollingWriteFinished(data);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
extern "C" void scsiFinishWrite()
|
|
extern "C" void scsiFinishWrite()
|
|
|
{
|
|
{
|
|
|
- if (g_scsi_phase == DATA_IN && scsiDev.target->syncOffset > 0)
|
|
|
|
|
|
|
+ if (g_scsi_writereq.count)
|
|
|
{
|
|
{
|
|
|
- return scsi_accel_sync_finishWrite(&scsiDev.resetFlag);
|
|
|
|
|
|
|
+ // Finish previously started polling write request.
|
|
|
|
|
+ processPollingWrite(g_scsi_writereq.count);
|
|
|
}
|
|
}
|
|
|
- else if (g_scsi_phy_mode == PHY_MODE_DMA_TIMER || g_scsi_phy_mode == PHY_MODE_GREENPAK_DMA)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if (g_scsi_phy_mode == PHY_MODE_DMA_TIMER || g_scsi_phy_mode == PHY_MODE_GREENPAK_DMA)
|
|
|
{
|
|
{
|
|
|
scsi_accel_dma_finishWrite(&scsiDev.resetFlag);
|
|
scsi_accel_dma_finishWrite(&scsiDev.resetFlag);
|
|
|
}
|
|
}
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- // Finish previously started polling write request.
|
|
|
|
|
- if (g_scsi_writereq.count)
|
|
|
|
|
- {
|
|
|
|
|
- processPollingWrite(g_scsi_writereq.count);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*********************/
|
|
/*********************/
|
|
@@ -483,7 +483,7 @@ extern "C" void scsiRead(uint8_t* data, uint32_t count, int* parityError)
|
|
|
if (g_scsi_phase == DATA_OUT && scsiDev.target->syncOffset > 0)
|
|
if (g_scsi_phase == DATA_OUT && scsiDev.target->syncOffset > 0)
|
|
|
{
|
|
{
|
|
|
// Synchronous data transfer
|
|
// Synchronous data transfer
|
|
|
- scsi_accel_sync_read(data, count, parityError, &scsiDev.resetFlag);
|
|
|
|
|
|
|
+ scsi_accel_sync_recv(data, count, parityError, &scsiDev.resetFlag);
|
|
|
}
|
|
}
|
|
|
else if (count_words * 4 == count && count_words >= 2 && use_greenpak)
|
|
else if (count_words * 4 == count && count_words >= 2 && use_greenpak)
|
|
|
{
|
|
{
|