📄 trmpc860.c
字号:
/*
* SOURCE FILE FOR Motorola MPC860 QUICC Sample Driver
*
* This device driver is derived from the Ethernet Bridge example from
* Motorola.
* It has been modified to interface to the Treck TCP/IP stack and to
* provide readability.
*
* Since it is a derived work, it remains the property of Motorola Corp.
*
* We have left the definintions of the mpc860 registers as they
* are in the QUICC user manual
*
* This is why they do not match TRECK coding standards.
*/
#include <trsocket.h>
#include <trmpc860.h>
/*
* IMPORTANT
* If the mpc860 device only receives a few frames and stops forever,
* make sure that you are calling the tfMpc860RefillScc1RecvPool()
* function from a low priority task
*/
/*
* Since we do not accept SHORT frames, we use the SHORT bit to
* mean that this frame has been notified
* IF THIS DRIVER IS CHANGED TO ALLOW SHORT FRAMES, ANOTHER BIT
* WILL NEED TO BE USED
*/
#define TM_MPC860_NOTIFIED TM_MPC860_RECV_E_SHORT
#define TM_MPC860_ERROR_RECV (TM_MPC860_RECV_ERROR & (~TM_MPC860_NOTIFIED))
/*
* Local Function Prototypes
*/
void tfMpc860CreateXmitPool(int channel, int maxBd);
void tfMpc860CreateRecvPool(int channel, int maxBd);
void tfMpc860IssueCommand(unsigned short command);
void tfMpc860Busy(ttUserInterface interfaceHandle, int channel);
void tfMpc860RecvFrame(ttUserInterface interfaceHandle,
int channel);
void tfMpc860XmitError(ttUserInterface interfaceHandle,int channel);
void tfMpc860Scc1SendComplete(ttUserInterface interfaceHandle);
void tfMpc860EtherUp(int channel);
void tfMpc860EtherScc1BoardInit(void);
void tfMpc860EtherScc1Init(void);
void tfMpc860RefillScc1RecvPool(void);
void tfMpc860Down(int channel);
int tfMpc860SerialClose(ttUserInterface interfaceHandle);
void tfMpc860SerialUp(int channel);
int tfMpc860SerialOpen(ttUserInterface interfaceHandle);
void tfMpc860SerialScc4BoardInit(void);
void tfMpc860SerialScc4Init(void);
static ttMpc860Ptr tlMpc860Ptr;
static ttMpc860BufDescPtr tlMpc860XmitBufDescPtr;
static ttMpc860BufDescPtr tlMpc860XmitIsrBufDescPtr;
static ttMpc860BufDescPtr tlMpc860XmitBufDescStartPtr;
static ttMpc860BufDescPtr tlMpc860RecvBufDescPtr;
static ttMpc860BufDescPtr tlMpc860RecvIsrBufDescPtr;
static ttMpc860BufDescPtr tlMpc860RecvBufDescStartPtr;
static ttMpc860BufDescPtr tlScatterBufferStart;
static ttMpc860BufDescPtr tlMpc860RecvRefillBufDescPtr;
unsigned long tvMpc860RecvErrorCount;
unsigned long tvMpc860RecvPacketCount;
unsigned long tvMpc860SendPacketCount;
unsigned long tvMpc860BusyPacketCount;
unsigned long tvMpc860XmitWait;
unsigned long tvMpc860IsrRecvErrorCount;
/*
* Four Interface handles for four SCC's
*/
static ttUserInterface tlInterfaceArray[4];
/*
* Table of ttUserBuffer Handles
*/
static ttUserBuffer tlUserBufferList[TM_MPC860_ETHER_MAX_RECV_BUFD];
/*
* Our index to the ttUserBuffer's
*/
static ttUserBufferPtr tlUserBufferPtr;
static ttUserBufferPtr tlUserRefillBufferPtr;
/*
* Return the Physical Address for the device
* For the MPC860, it should be read from EEPROM
* because every ethernet address is Unique
*
* THIS ROUTINE MUST BE MODIFIED!
*
* To get an ethernet address address block for
* your company, you need to contact IEEE Standards
* or visit http://standards.ieee.org/faqs/OUI.html
* for information on getting an Company ID/OUI
*/
int tfMpc860GetPhyAddr(ttUserInterface userInterface,
char *address)
{
/*
* We don't use the interface handle here, but we keep the compiler
* from complaining about unused formal parameters
*/
userInterface=userInterface;
address[0]=0x00;
address[1]=0xea;
address[2]=0xc0;
address[3]=0xf0;
address[4]=0x08;
address[5]=0x60;
return 0;
}
/*
* Initialize SCC1 to be an ethernet channel
*/
void tfMpc860EtherScc1Init()
{
char etherAddr[6];
struct ethernet_pram *enet_pram;
struct scc_regs *regs;
/* Retrieve the Ethernet Address */
tfMpc860GetPhyAddr((ttUserInterface)0,
etherAddr);
enet_pram = &tlMpc860Ptr->pram[0].enet_scc;
regs = &tlMpc860Ptr->scc_regs[0];
/* Disable transmit/receive */
regs->scc_gsmrl = 0;
/*
* Initialize paramater ram
*/
/* points to start of receiving ring */
enet_pram->rbase = TM_MPC860_SCC1_RECV_BASE;
/* points to start of transmiting ring */
enet_pram->tbase = TM_MPC860_SCC1_XMIT_BASE;
/* Function Codes for Transmit and Receive */
enet_pram->rfcr = TM_MPC860_SCC1_RECV_FUNC_CODE;
enet_pram->tfcr = TM_MPC860_SCC1_XMIT_FUNC_CODE;
/* We always receive a full ethernet frame so we set it to 1518 */
enet_pram->mrblr = TM_MPC860_SCC1_MAX_RECV_BUF_LEN;
/* A good ethernet CRC */
enet_pram->c_mask = TM_MPC860_ETHER_CRC_MASK;
/* The CRC we start with */
enet_pram->c_pres = TM_MPC860_ETHER_CRC_PRES;
/* These three registers are cleared for clarity sake */
enet_pram->crcec = TM_MPC860_ETHER_CRCEC;
enet_pram->alec = TM_MPC860_ETHER_ALEC;
enet_pram->disfc = TM_MPC860_ETHER_DISFC;
/* Pad Character */
enet_pram->pads = TM_MPC860_ETHER_PADS;
/* Max Retries when we have a collision */
enet_pram->ret_lim = TM_MPC860_ETHER_RETRY_LIMIT;
/* Maximum Ethernet Frame Length (Always 1518) */
enet_pram->mflr = TM_MPC860_ETHER_MAX_FRAME_LEN;
/* Minimum Ethernet Frame Length (Always 64) */
enet_pram->minflr = TM_MPC860_ETHER_MIN_FRAME_LEN;
/* Maximum DMA Counts */
enet_pram->maxd1 = TM_MPC860_ETHER_MAX_DMA1_COUNT;
enet_pram->maxd2 = TM_MPC860_ETHER_MAX_DMA2_COUNT;
/* Group Addresses */
enet_pram->gaddr1 = TM_MPC860_ETHER_GROUP_ADDR1;
enet_pram->gaddr2 = TM_MPC860_ETHER_GROUP_ADDR2;
enet_pram->gaddr3 = TM_MPC860_ETHER_GROUP_ADDR3;
enet_pram->gaddr4 = TM_MPC860_ETHER_GROUP_ADDR4;
/*
* Our physical (Ethernet) address (IN LITTLE ENDIAN)
* If the physical address is:
* 0x112233445566
*
* It is stored like this:
* paddr_l=0x2211
* paddr_m=0x4433
* paddr_h=0x6655
*
* If not done correctly, the MPC860 will NOT receive any packets
* with its destination address
*/
enet_pram->paddr_l = ((unsigned short)etherAddr[0] &0x00ff)|
((((unsigned short)etherAddr[1])<<8) &0xff00);
enet_pram->paddr_m = ((unsigned short)etherAddr[2] &0x00ff)|
((((unsigned short)etherAddr[3])<<8) &0xff00);
enet_pram->paddr_h = ((unsigned short)etherAddr[4] &0x00ff)|
((((unsigned short)etherAddr[5])<<8) &0xff00);
enet_pram->p_per = TM_MPC860_ETHER_P_PER;
/* Individual Hash Addresses */
enet_pram->iaddr1 = TM_MPC860_ETHER_INDV_ADDR1;
enet_pram->iaddr2 = TM_MPC860_ETHER_INDV_ADDR2;
enet_pram->iaddr3 = TM_MPC860_ETHER_INDV_ADDR3;
enet_pram->iaddr4 = TM_MPC860_ETHER_INDV_ADDR4;
/* Temp Registers */
enet_pram->taddr_h = TM_MPC860_ETHER_T_ADDR_H;
enet_pram->taddr_m = TM_MPC860_ETHER_T_ADDR_M;
enet_pram->taddr_l = TM_MPC860_ETHER_T_ADDR_L;
tvMpc860RecvPacketCount=0L;
tvMpc860SendPacketCount=0L;
tvMpc860XmitWait=0L;
tvMpc860RecvErrorCount=0L;
tvMpc860IsrRecvErrorCount=0L;
tlScatterBufferStart=(ttMpc860BufDescPtr)0;
/* Tell the CP to initialize our Recv/Xmit parameters */
tfMpc860IssueCommand(TM_MPC860_INIT_RXTX_SCC1);
}
/*
* Initialize SCC1 to be an ethernet channel
*/
void tfMpc860EtherScc1BoardInit()
{
unsigned char scc1Vector;
unsigned long scc1Location;
/* tlMpc860Ptr->sim_mcr = 0x608f; */
/*
* IMPLEMENTATION NOTE:
*
* This routine is very board specific
* In this example we use the Atlas Communications Engines
* DARWIN devlopment board for an example
* We assume the the ethernet is in SLOT 0 and at SCC1
* on the DARWIN
*
* Please refer to your boards design to modify this routine
*/
/* clear previous scc1 settings */
tlMpc860Ptr->si_sicr &= ~(0x3f);
/* Atlas DARWIN Setup */
tlMpc860Ptr->si_sicr |= TM_MPC860_SI_SCC1_RCS_CLK1 |
TM_MPC860_SI_SCC1_TCS_CLK2;
/* Disconnect the clock routing source */
tlMpc860Ptr->si_sicr &= ~TM_MPC860_SI_SCC1_CONNECT;
/* Make PortA Pins 6,7,14,15 for onchip use */
tlMpc860Ptr->pio_padir &= ~(TM_MPC860_PORTA_PA6 |
TM_MPC860_PORTA_PA7 |
TM_MPC860_PORTA_PA14 |
TM_MPC860_PORTA_PA15);
/*
* Use PortA pins 15,14 for SCC1 Ethernet RX/TX and
* pins 6,7 for Ethernet TCLK and RCLK
*/
tlMpc860Ptr->pio_papar |= TM_MPC860_PORTA_PA6 |
TM_MPC860_PORTA_PA7 |
TM_MPC860_PORTA_PA14 |
TM_MPC860_PORTA_PA15;
/* Turn off the Open Drain */
tlMpc860Ptr->pio_paodr &= ~TM_MPC860_PORTA_PA14;
/* Clear the pending and in-service registers */
tlMpc860Ptr->intr_cipr = TM_MPC860_SCC1_INT_MASK;
tlMpc860Ptr->intr_cisr = TM_MPC860_SCC1_INT_MASK;
/* Set the CP mask register to accept interrupts from SCC1 */
tlMpc860Ptr->intr_cimr |= TM_MPC860_SCC1_INT_MASK;
tlMpc860Ptr->sdma_sdcr=TM_MPC860_SDMA_ARB_ID;
/* PortC Pins 10 & 11 are onchip */
tlMpc860Ptr->pio_pcdir &= ~(TM_MPC860_PORTC_PC10 |
TM_MPC860_PORTC_PC11);
/* PortC Pins 10 & 11 are onchip */
tlMpc860Ptr->pio_pcpar &= ~(TM_MPC860_PORTC_PC10 |
TM_MPC860_PORTC_PC11);
/*
* Use Pins 10 and 11 (SCC1 CD and CTS) for Ethernet RENA and CLSN
*/
tlMpc860Ptr->pio_pcso|= TM_MPC860_PORTC_PC10 |
TM_MPC860_PORTC_PC11;
/* Clear the data register for pins 10 and 11 */
tlMpc860Ptr->pio_pcdat&= ~(TM_MPC860_PORTC_PC10 |
TM_MPC860_PORTC_PC11);
/*
* Port B External Signals
* PB14,PB15 are clock select
* PB26 is Link Enable
* PB27 Is Full Duplex Select
*/
tlMpc860Ptr->pip_pbdir |= TM_MPC860_PORTB_PB14 |
TM_MPC860_PORTB_PB15 |
TM_MPC860_PORTB_PB27 |
TM_MPC860_PORTB_PB26;
tlMpc860Ptr->pip_pbpar &= ~(TM_MPC860_PORTB_PB14 |
TM_MPC860_PORTB_PB15 |
TM_MPC860_PORTB_PB27 |
TM_MPC860_PORTB_PB26);
/* Set clock select to 00 */
tlMpc860Ptr->pip_pbdat &= ~(TM_MPC860_PORTB_PB14 |
TM_MPC860_PORTB_PB15);
/* Set Link Enable */
tlMpc860Ptr->pip_pbdat |= TM_MPC860_PORTB_PB26;
/* Turn OFF Full Duplex Mode */
tlMpc860Ptr->pip_pbdat &= ~TM_MPC860_PORTB_PB27;
/*
* IMPLEMENTATION NOTE:
*
* The Actual SCC1 ISR Wrapper Function in installed here
* It must call the tfMpc860Scc1HandlerIsr function
* This routine may be in "C" if it is supported
* or assembly if not. It is VERY RTOS dependent
* so it cannot be provided with the driver
*
* With some RTOS's a wrapper function may not be
* needed. All the driver cares about is that the
* function tfMpc860Scc1HandlerIsr function is called
* when the interrupt occurs.
*
*/
/* Port B pin 19 is Ethernet TENA for DARWIN */
tlMpc860Ptr->pip_pbpar |= TM_MPC860_PORTB_PB19;
tlMpc860Ptr->pip_pbdir |= TM_MPC860_PORTB_PB19;
/* Install the wrapper function */
tfKernelInstallIsrHandler(tfMpc860Scc1Isr,TM_MPC860_SCCA_INT);
}
/*
* Enable the SCC's to recieve and transmit
*/
void tfMpc860EtherUp(int channel)
{
struct scc_regs *regs;
regs = &tlMpc860Ptr->scc_regs[channel];
/* clear all events on the SCC event register and CP event reg*/
regs->scc_scce=0xffff;
/* Clear the appropriate bit in the CISR */
switch (channel)
{
case TM_MPC860_SCC1_CHANNEL:
tlMpc860Ptr->intr_cisr = TM_MPC860_SCC1_INT_MASK;
break;
case TM_MPC860_SCC2_CHANNEL:
tlMpc860Ptr->intr_cisr = TM_MPC860_SCC2_INT_MASK;
break;
case TM_MPC860_SCC3_CHANNEL:
tlMpc860Ptr->intr_cisr = TM_MPC860_SCC3_INT_MASK;
break;
case TM_MPC860_SCC4_CHANNEL:
tlMpc860Ptr->intr_cisr = TM_MPC860_SCC4_INT_MASK;
break;
default:
break;
}
/*
* mask the events we sich to interrupt on
*/
regs->scc_sccm =
/* An error in transmitting has occured */
TM_MPC860_INTR_ETHER_E_XMIT |
/* A buffer has completed transmitting */
TM_MPC860_INTR_ETHER_XMIT_B |
/* A ethernet frame has been received */
TM_MPC860_INTR_ETHER_RECV_F |
/* The busy condition has occured */
TM_MPC860_INTR_ETHER_BUSY;
/* SCC1 data sync reg (The pattern for Ethernet)*/
regs->scc_dsr= TM_MPC860_SCC_FRAME_SYNC_ETHER;
/* protocol specific mode register */
regs->scc_psmr =
/* To disable the reception of Broadcast packets uncomment this line */
/* TM_MPC860_ETHER_BROADCAST | */
/* Turn on the CRC for ethernet */
TM_MPC860_ETHER_ENABLE_CRC |
/* Ignore 22 bits for ethernet */
TM_MPC860_ETHER_NBITS_IGNORED;
/* SCC general mode reg */
regs->scc_gsmrh = 0;
/* SCC general mode reg */
regs->scc_gsmrl =
/* Transmit Clock Inversion */
TM_MPC860_XMIT_CLOCK_INV |
/* Preamble Bit Length (48 always for ethernet) */
TM_MPC860_PREAMBLE_48 |
/* Preamble Bit Pattern (Alternating '1' and '0' for ethernet */
TM_MPC860_PREAMBLE_PAT_10 |
/* Ethernet Mode */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -