📄 gpif.c
字号:
//-----------------------------------------------------------------------------
// Copyright (c) 1999 Cypress Semiconductor, Inc. All rights reserved
//-----------------------------------------------------------------------------
//
// This file contains GPIF support code.
//
// $Archive: /USB/atapifx2/CY4611B/gpif.c $
// $Date: 4/06/05 10:46a $
// $Revision: 3 $
//-----------------------------------------------------------------------------
//#pragma ot(8,SPEED) // keep gpif.c at Optimization Level 8 (no re-ordering)
// This is because some DVD-RAM drives had a problem when a common
// subroutine was replaced. The problem appeared to be only a minor
// difference in timing. The DVD-RAM drive would fail if a subroutine
// call was added to readPIO8. It reported a residue of data after
// a prior transfer had been completed, and when that data was read,
// it was just a buffer filled with invalid (repeating) data.
// The problem appeared to be the fault of the DVD-ROM drive.
#include <scsi.h>
#include "fx2.h"
#include "fx2regs.h"
#include "gpif.h"
#include "globals.h"
//
// Do not edit the following waveform array! Use the GPIF utility to edit the file
// GPIFPIO4.C. Once modifications are made there, paste the resulting waveform
// array into this file.
//
// Don't forget that the IORDY signal can be produced at the drive up to 35ns after we
// drop RD or WR. It then takes 2 clocks for us to demet the signal (async input). The
// IORDY signal is available on the FIFTH clock edge after RD or WR is dropped.
// Edge 1) Drop RD/WR (start state 0)
// Edge 2) No action
// Edge 3) IORDY detected at first flop
// Edge 4) IORDY detected at second flop
// Edge 5) IORDY available as an input to IF/THEN statements. (start state 1)
//
//
//
const char code WaveDataPioUDMA[128+64] =
{
// Wave 0 (Write PIO0)
// State 0 -- Drive DIOW Low (output = FE), Drive data bus (opcode = 2), Length = 0xa (10 clocks = 210nsec)
// State 1 -- Drive DIOW Low (output = FE), Drive data bus (opcode = 2), Length = 0x2 (2 clocks = 41ns)
// State 2 -- Drive DIOW High (output = FF),Drive data bus (opcode = 2), Length = 0x12(18 clocks = 375ns)
// State 3 -- Branch to end, continue driving data, use FIFO flag as branch
/* LenBr */ 0x0a, 0x02, 0x12, 0x3F, /* PIO4 LENBR ges */ 0x03, 0x11, 0x01, 0x3f,
/* Opcode*/ 0x02, 0x02, 0x02, 0x07, /* Opcode Changes */ 0x02, 0x03, 0x02, 0x07,
/* Output*/ 0xFE, 0xFE, 0xFF, 0xFF, /* CF LenBr (unused) */ 0x07, 0x11, 0x01, 0x3f,
/* LFun */ 0x00, 0x00, 0x00, 0x36, /* CF Opcod (unused) */ 0x02, 0x03, 0x02, 0x07,
// Wave 1
/* LenBr */ 0x04, 0x04, 0x16, 0x3f, /* PIO4 LENBR */ 0x03, 0x11, 0x3f, 0x00,
/* Opcode*/ 0x00, 0x00, 0x06, 0x01, /* PIO4 opcode*/ 0x00, 0x01, 0x07, 0x00,
/* Output*/ 0xFD, 0xFD, 0xFF, 0xFF, /* CF LenBr (unused) */ 0x08, 0x11, 0x04, 0x3f,
/* LFun */ 0x00, 0x00, 0x00, 0x00, /* CF Opcod (unused) */ 0x00, 0x01, 0x06, 0x01,
// Wave 0 UDMA Write
/* LenBr */ 0x08, 0x01, 0x06, 0x1C, 0x25, 0x01, 0x02, 0x07,
/* Opcode*/ 0x01, 0x00, 0x02, 0x03, 0x01, 0x02, 0x26, 0x00,
/* Output*/ 0xFF, 0xFB, 0xFA, 0xFA, 0xd8, 0xFB, 0xFB, 0xFF,
/* LFun */ 0x09, 0x09, 0x12, 0xe9, 0x09, 0x2d, 0x36, 0x3F,
// | | | | | | |-- Drive CRC
// | | | | | |-- Assert STOP
// | | | | |-- Wait for drive to drop DMARQ. Float HSTROBE
// | | | |-- Data transfer state. Pause on DSTROBE, exit on RDY5 (TC)
// | | |-- Remove STOP
// | |-- Assert DMACK
// |-- Wait for drive to assert DMARQ. Branch to state 1 on DMARQ.
// Wave 1 UDMA Read
/* LenBr */ 0x08, 0x01, 0x13, 0x01, 0x25, 0x02, 0x01, 0x07,
/* Opcode*/ 0x01, 0x00, 0x01, 0x00, 0x01, 0x26, 0x26, 0x00,
/* Output*/ 0xFF, 0xFB, 0xF8, 0xFB, 0xFB, 0xFB, 0xFF, 0xFF,
/* LFun */ 0x09, 0x09, 0xE9, 0x1b, 0x09, 0x2D, 0x36, 0x3F,
// | | | | | | |-- Drive CRC. Done.
// | | | | | |-- Drive CRC
// | | | | |-- Wait for drive to drop DMARQ
// | | | |-- STOP ->1, HSTB->1
// | | |-- Data transfer state. STOP = 0, HSTB = 0, DMACK = 0. Exit on DMARQ or RDY5 (TC)
// | |-- Assert DMACK
// |-- Wait for drive to assert DMARQ. Branch to state 1 on DMARQ.
// Wave 2
/* LenBr */ 0x88, 0x8A, 0x03, 0xBC, 0x88, 0x01, 0x01, 0x07,
/* Opcode*/ 0x01, 0x03, 0x02, 0x03, 0x07, 0x02, 0x02, 0x00,
/* Output*/ 0xF7, 0xF2, 0xF2, 0xF3, 0xF3, 0xF3, 0xF3, 0xF7,
/* LFun */ 0x09, 0x36, 0x00, 0x2D, 0x09, 0x00, 0x00, 0x3F,
// Wave 3
/* LenBr */ 0x88, 0x8A, 0x03, 0xBC, 0x88, 0x01, 0x01, 0x07,
/* Opcode*/ 0x01, 0x01, 0x00, 0x07, 0x01, 0x00, 0x00, 0x00,
/* Output*/ 0xF7, 0xF1, 0xF1, 0xF3, 0xF3, 0xF3, 0xF3, 0xF7,
/* LFun */ 0x09, 0x36, 0x00, 0x2D, 0x09, 0x00, 0x00, 0x3F,
};
void hardwareReset()
{
OEA |= ATAPI_RESET_BIT; // Needed for revC board. Doesn't hurt for old pinout.
ATAPI_RESET_ = 0;
EZUSB_Delay(100);
ATAPI_RESET_ = 1;
#if REVC_4611_BOARD
OEA &= ~ATAPI_RESET_BIT;
#endif
}
void initUdmaRead()
{
// Only use flow state for UDMA, not for DMA
if (ActiveLunConfigData.udmaMode & TRANSFER_MODE_UDMA0)
{
FLOWLOGIC = 0x36;
FLOWEQ1CTL = 0x02;
FLOWSTB = 0xD0;
}
EP6FIFOCFG = 0x0D; // Turn on AUTO mode
IFCONFIG = 0xc2; // Make sure we're using 48Mhz interface clock
// EP6GPIFFLGSEL = 0; // Default -- Use programmable flag.
}
void initUdmaWrite()
{
// Only use flow state for UDMA, not for DMA
if (ActiveLunConfigData.udmaMode & TRANSFER_MODE_UDMA0)
{
FLOWLOGIC = 0x70;
FLOWEQ1CTL = 0x08; // Enable CTL3 signal for debugging
FLOWSTB = 0x11;
if(ActiveLunConfigData.udmaMode == TRANSFER_MODE_UDMA2)
FLOWSTBHPERIOD = 0x04; // for UDMA33
else
FLOWSTBHPERIOD = 0x02; // for UDMA66
IFCONFIG = 0x82; // Slow the clock to 30Mhz
}
EP2GPIFFLGSEL = 0x01; // Select empty flag
FIFORESET = bmNAKALL; // Set NAKALL bit
// Wait one packet time -- 50uS at full-speed, 10us at high-speed
{
BYTE count;
BYTE i;
if (EZUSB_HIGHSPEED())
count = 10;
else
count = 50;
for (; count; count--)
i = halfKBuffer[0];
}
// wait for the sector to show up
// commit the buffer(s) to the GPIF
while (!(EP2468STAT & bmEP2EMPTY))
EP2BCL = 0x00;
#if 0
{
WORD byteCount;
BYTE i;
// Special code for switching between auto/manual modes. Make sure that all of
// the buffers are full before switching.
for (i = 0, byteCount = 0; i < 4 && byteCount < dataTransferLen; i++, byteCount +=wPacketSize)
{
// wait for the sector to show up
while (EP2468STAT & bmEP2EMPTY)
;
// commit the buffer(s) to the GPIF
EP2BCL = 0x00;
WRITEDELAY();
}
}
#endif
EP2FIFOCFG = bmAUTOOUT | bmWORDWIDE;
FIFORESET = 0x00; // Clear NAKALL bit
}
// Write a single byte to the given disk register or buffer
void writePIO8(char addr, BYTE indata)
{
// make sure GPIF is not busy
while (!gpifIdle())
{
}
// Write the address/chip selects
OUTATAPI = addr | (~ATAPI_ADDR_MASK & ATAPI_IDLE_VALUE);
// trigger the GPIF
XGPIFSGLDATLX = indata; // Single bus transaction on the GPIF
// make sure GPIF is not busy
while (!gpifIdle())
{
}
// Clear the address/chip selects
OUTATAPI = ATAPI_IDLE_VALUE;
}
#if DEVICE_TYPE_IS_SCSI
// Write a single byte to the given disk register or buffer
void fastWritePIO8(char addr, BYTE indata)
{
// make sure GPIF is not busy
while (!gpifIdle())
{
}
// Write the address/chip selects
OUTATAPI = addr | (~ATAPI_ADDR_MASK & ATAPI_IDLE_VALUE);
// trigger the GPIF
XGPIFSGLDATLX = indata; // Single bus transaction on the GPIF
}
#endif
// Write the string to the data register
void writePIO16(WORD count)
{
int timeout = IORDY_TIMEOUT_RELOAD;
while (!gpifIdle())
;
GPIFWFSELECT = GPIFWFSELECT_DEFAULT | (0 << 2); // PIO write is waveform 0
// set up for GPIF transfer - wordwide, so count/2
{
GPIFTCB1 = MSB(count) >> 1;
// Write the address/chip selects here so we don't have to call WRITEDELAY();
OUTATAPI = (ATAPI_DATA_REG | (~ATAPI_ADDR_MASK & ATAPI_IDLE_VALUE));
GPIFTCB0 = LSB(count >> 1);
}
EP2GPIFTRIG = 0x00; // trigger the transfer
// GPIFTRIG = 0x00; // GPIFTRIG[2] = RD/WR BIT (1 = READ)
// xxxxxxxx
// ||||||00 b0/b1: EP bit code: 00=EP2, 01=EP4, 10=EP6, 11=EP6
// |||||0-- b3: R/W#: W=0, R=1
// 0------- b7: DONE
while (!gpifIdle())
;
}
// Read the status register. Added to save space.
BYTE readATAPI_STATUS_REG()
{
return(readPIO8(ATAPI_STATUS_REG));
}
// Read the alt status register. Added to save space.
BYTE readATAPI_ALT_STATUS_REG()
{
return(readPIO8(ATAPI_ALT_STATUS_REG));
}
// Read a string from the given disk register or buffer
BYTE readPIO8(char addr)
{
BYTE retval;
while (!gpifIdle());
// put out address of interest
OUTATAPI = addr | (~ATAPI_ADDR_MASK & ATAPI_IDLE_VALUE);
// trigger the GPIF
retval = XGPIFSGLDATLX; // Single bus transaction on the GPIF
while (!gpifIdle()); // wait till GPIF is done before getting real data
retval = XGPIFSGLDATLNOX; // get data from last GPIF transaction
OUTATAPI = ATAPI_IDLE_VALUE;
return(retval);
}
// Read a string from the given disk register or buffer
void readPIO16(WORD count)
{
// check for GPIF ready
while (!gpifIdle());
GPIFWFSELECT = GPIFWFSELECT_DEFAULT | (1); // PIO read is waveform 1
// set up for GPIF transfer - wordwide, so count/2
{
count++; // add 1 to count in case it's odd.
GPIFTCB1 = MSB(count) >> 1;
// Write the address/chip selects here so we don't have to call WRITEDELAY();
OUTATAPI = (ATAPI_DATA_REG | (~ATAPI_ADDR_MASK & ATAPI_IDLE_VALUE));
GPIFTCB0 = LSB(count >> 1);
}
// trigger GPIF. No longer wait 'til done
GPIFTRIG = 0x06; // GPIFTRIG[2] = RD/WR BIT (1 = READ)
// GPIFTRIG[1..0] = EP#, 00=ep2, 01=ep4, 10 = ep6, 11=ep8
}
void prepUDMA(BYTE b2, BYTE b1, BYTE b0)
{
// check for GPIF ready
while (!gpifIdle());
GPIFWFSELECT = GPIFWFSELECT_DEFAULT | (2 << 2) | 3; // UDMA write is waveform 2, UDMA read is waveform 3
// Write the address/chip selects -- Note that this is not the same register as the ATAPI_DATA_REG
OUTATAPI = CS(3) | DA(0) | (~ATAPI_ADDR_MASK & ATAPI_IDLE_VALUE);
// set up for GPIF transfer - wordwide
GPIFTCB2 = b2;
WRITEDELAY();
GPIFTCB1 = b1;
WRITEDELAY();
GPIFTCB0 = b0;
}
// read count WORDs using UDMA
void readUDMA()
{
bit retval = 0;
if (ActiveLunConfigData.udmaMode & TRANSFER_MODE_UDMA0)
FLOWSTATE = 0x82;
// trigger GPIF and wait till done
GPIFTRIG = 0x06; // GPIFTRIG[2] = RD/WR BIT (1 = READ)
// GPIFTRIG[1..0] = EP#, 00=ep2, 01=ep4, 10 = ep6, 11=ep8
// Wait for the drive interrupt or GPIF done
if (bCOMPLIANCE_MODE)
{
#if REVC_4611_BOARD
{
WAKEUPCS = bmWU | bmWUEN;
while((WAKEUPCS & 0x40) && !gpifIdle())
{WAKEUPCS = bmWU | bmWUEN;}
}
#else // AT2LP_PINOUT
{
while (!PA0 && !gpifIdle())
;
}
#endif
}
else
WAIT_FOR_INTRQ();
if (!gpifIdle())
{
abortGPIF();
}
FLOWSTATE = 0x00;
return;
}
// Wait for all of the bulk buffers to be full (or all of the data to be received)
// Switch to manual mode
// Write count WORDs using UDMA
// Return drive status
void writeUDMA()
{
BYTE drvstat=0;
if (ActiveLunConfigData.udmaMode & TRANSFER_MODE_UDMA0)
FLOWSTATE = 0x83;
// trigger GPIF and wait till done
EP2GPIFTRIG = 0;
// Wait for the drive interrupt.
// Wait for the drive interrupt.
// Wait for the drive interrupt or GPIF done
if (bCOMPLIANCE_MODE)
{
#if REVC_4611_BOARD
{
WAKEUPCS = bmWU | bmWUEN;
while((WAKEUPCS & 0x40) && !gpifIdle())
{WAKEUPCS = bmWU | bmWUEN;}
}
#else // AT2LP_PINOUT
{
while (!(IOA & 1) && !gpifIdle())
;
}
#endif
}
else
WAIT_FOR_INTRQ();
if (!gpifIdle())
{
abortGPIF();
}
FLOWSTATE = 0x00;
}
void abortGPIF()
{
FLOWSTATE = 0x00; // xro - take out of UDMA flowstate
GPIFABORT = 0xff;
// reset the transaction count state machine, in FX2 revs up to and
// including Rev D, there is a bug that prevents the GPIF state machine
// from properly reseting following an abort. The following code is a
// workaround for this problem. See the FX2 chip errata for details.
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -