fx2/firmware/lib/gpif.c

199 lines
5.1 KiB
C

/**
* Copyright (C) 2009 Ubixum, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
**/
#include <fx2regs.h>
#include <fx2macros.h>
#include <delay.h>
#include <gpif.h>
#define SYNCDELAY SYNCDELAY4
void
gpif_init(BYTE * wavedata, BYTE * initdata)
{
BYTE i;
// Registers which require a synchronization delay, see section 15.14
// FIFORESET FIFOPINPOLAR
// INPKTEND OUTPKTEND
// EPxBCH:L REVCTL
// GPIFTCB3 GPIFTCB2
// GPIFTCB1 GPIFTCB0
// EPxFIFOPFH:L EPxAUTOINLENH:L
// EPxFIFOCFG EPxGPIFFLGSEL
// PINFLAGSxx EPxFIFOIRQ
// EPxFIFOIE GPIFIRQ
// GPIFIE GPIFADRH:L
// UDMACRCH:L EPxGPIFTRIG
// GPIFTRIG
// Note: The pre-REVE EPxGPIFTCH/L register are affected, as well...
// ...these have been replaced by GPIFTC[B3:B0] registers
// 8051 doesn't have access to waveform memories 'til
// the part is in GPIF mode.
// IFCLKSRC=1 , FIFOs executes on internal clk source
// xMHz=1 , 48MHz internal clk rate
// IFCLKOE=0 , Don't drive IFCLK pin signal at 48MHz
// IFCLKPOL=0 , Don't invert IFCLK pin signal from internal clk
// ASYNC=1 , master samples asynchronous
// GSTATE=1 , Drive GPIF states out on PORTE[2:0], debug WF
// IFCFG[1:0]=10, FX2 in GPIF master mode IFCONFIG
IFCONFIG &= ~0x03; // turn off IFCFG[1:0]
IFCONFIG |= 0x02; // set's IFCFG[1:0] to 10 to put in GPIF master mode.
GPIFABORT = 0xFF; // abort any waveforms pending
GPIFREADYCFG = initdata[0];
GPIFCTLCFG = initdata[1];
GPIFIDLECS = initdata[2];
GPIFIDLECTL = initdata[3];
GPIFWFSELECT = initdata[5];
GPIFREADYSTAT = initdata[6];
// use dual autopointer feature...
AUTOPTRSETUP = 0x07; // inc both pointers,
// ...warning: this introduces pdata hole(s)
// ...at E67B (XAUTODAT1) and E67C (XAUTODAT2)
// source
AUTOPTRH1 = MSB((WORD) wavedata);
AUTOPTRL1 = LSB((WORD) wavedata);
// destination
AUTOPTRH2 = 0xE4;
AUTOPTRL2 = 0x00;
// transfer
for (i = 0x00; i < 128; i++) {
EXTAUTODAT2 = EXTAUTODAT1;
}
// Configure GPIF Address pins, output initial value,
// these instructions don't do anything on the
// smaller chips (e.g., 56 pin model only has ports a,b,d)
PORTCCFG = 0xFF; // [7:0] as alt. func. GPIFADR[7:0]
OEC = 0xFF; // and as outputs
PORTECFG |= 0x80; // [8] as alt. func. GPIFADR[8]
OEE |= 0x80; // and as output
// ...OR... tri-state GPIFADR[8:0] pins
// PORTCCFG = 0x00; // [7:0] as port I/O
// OEC = 0x00; // and as inputs
// PORTECFG &= 0x7F; // [8] as port I/O
// OEE &= 0x7F; // and as input
// GPIF address pins update when GPIFADRH/L written
SYNCDELAY; //
GPIFADRH = 0x00; // bits[7:1] always 0
SYNCDELAY; //
GPIFADRL = 0x00; // point to PERIPHERAL address 0x0000
// set the initial flowstates to be all 0 in case flow states are not used
FLOWSTATE = 0;
FLOWLOGIC = 0;
FLOWEQ0CTL = 0;
FLOWEQ1CTL = 0;
FLOWHOLDOFF = 0;
FLOWSTB = 0;
FLOWSTBEDGE = 0;
FLOWSTBHPERIOD = 0;
}
void
gpif_setflowstate(BYTE * flowstates, BYTE bank)
{
BYTE base = 9 * bank;
FLOWSTATE = flowstates[base];
FLOWLOGIC = flowstates[base + 1];
FLOWEQ0CTL = flowstates[base + 2];
FLOWEQ1CTL = flowstates[base + 3];
FLOWHOLDOFF = flowstates[base + 4];
FLOWSTB = flowstates[base + 5];
FLOWSTBEDGE = flowstates[base + 6];
FLOWSTBHPERIOD = flowstates[base + 7];
}
void
gpif_set_tc32(DWORD tc)
{
GPIFTCB3 = MSB(MSW(tc));
SYNCDELAY;
GPIFTCB2 = LSB(MSW(tc));
SYNCDELAY;
GPIFTCB1 = MSB(LSW(tc));
SYNCDELAY;
GPIFTCB0 = LSB(LSW(tc));
}
void
gpif_set_tc16(WORD tc)
{
GPIFTCB1 = MSB(tc);
SYNCDELAY;
GPIFTCB0 = LSB(tc);
}
void
gpif_single_read16(WORD * res, WORD len)
{
BYTE c;
while (!(GPIFTRIG & 0x80)); // wait done
// dummy read to trigger real read
res[0] = XGPIFSGLDATLX;
for (c = 0; c < len; ++c) {
while (!(GPIFTRIG & 0x80)); // wait done
// real read
res[c] = GPIFSGLDATH << 8;
// whether or not to do another transfer is controlled by GPIFSGLDATLNOX or ..DATLX
res[c] |= c == len - 1 ? GPIFSGLDATLNOX : GPIFSGLDATLX;
}
}
void
gpif_single_write16(WORD * dat, WORD len)
{
BYTE c;
for (c = 0; c < len; ++c) {
while (!(GPIFTRIG & 0x80));
XGPIFSGLDATH = MSB(dat[c]);
XGPIFSGLDATLX = LSB(dat[c]);
}
}
void
gpif_fifo_read(GPIF_EP_NUM ep_num)
{
while (!(GPIFTRIG & 0x80)); // wait until things are finished
GPIFTRIG = GPIFTRGRD | ep_num;
}
void
gpif_fifo_write(GPIF_EP_NUM ep_num)
{
while (!(GPIFTRIG & 0x80)); // wait until things are finished
GPIFTRIG = ep_num; // R/W=0, E[1:0] = ep_num
}