📄 cs8900.c
字号:
/*
* Copyright 2001, Metro Link, Inc.
* All Rights Reserved
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Metro Link, Inc. and may
* contain proprietary, confidential and trade secret information of
* Metro Link, Inc. and/or its partners.
*
* The contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Metro Link, Inc.
*
*/
/*
* File : cs8900.c
*
* Description : Driver file for the crystal ethernet controller.
*
* Copyright 2004, ZiLOG Inc.
* All Rights Reserved
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of ZiLOG Inc., and might
* contain proprietary, confidential and trade secret information of
* ZiLOG, our partners and parties from which this code has been licensed.
*
* The contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of ZiLOG Inc.
*/
#include <stdio.h>
#include "ZSysgen.h"
#include "ZTypes.h"
#include "ZThread.h"
#include "ZMessageQ.h"
#include "ZInterrupt.h"
#include "ZSemaphore.h"
#include "EtherMgr.h"
#include "cs8900a.h"
#include "_ez80.h"
#define TX_WAITING 2
#define TX_DONE 1
#define PKTTOOBIG -2
#define EMAC_POLL_THD_STACK_SIZE 1024
#define CS8900_LINK_OK 0x80
extern void PutToQueue(QUEUE_REF_t *refnode, QUEUE_NODE_t *node) ;
extern QUEUE_NODE_t *GetFromQueue(QUEUE_REF_t *refnode) ;
extern UINT8 EMAC_Task_Stack[] ;
extern UINT8 EMAC_TASK_PRIO ;
extern UINT EMAC_THD_STACK_SIZE ;
extern void emacisr(void) ;
extern RZK_MESSAGEQHANDLE_t rxQueueHandle ; /* receive queue handle */
void CS8900IntTask( void );
void cs8900PollTask(void) ;
RZK_THREADHANDLE_t emacInterruptThdHdl ; /* emac interrupt thread handle */
RZK_THREADHANDLE_t emacPollThdHdl ; /* emac poll thread handle */
UINT8 EMAC_Poll_Task_Stack[EMAC_POLL_THD_STACK_SIZE] ;
IORegExt16 p_emac_base = (IORegExt16) 0x300; // IO Base address for CS8900A
INT8 xinu_eth_irq = IV_PD4; // Use IV_NULL if no NIC Irq line.
UINT32 emac_isr_count = 0;
INT8 doing_tx = RZK_FALSE;
INT8 tx_q_size = 0;
QUEUE_REF_t mac_tx_q;
#define CS8900A_INTRQ0 0x00
#define CS8900A_INTRQ1 0x01
#define CS8900A_INTRQ2 0x02
#define CS8900A_INTRQ3 0x03
#define CS8900A_DISABLE_INTRQ 0x04
#define HASH_TABLE_SIZE 4
ETH_DEV_STRUCT_t emac[1];
void (*rxnotifyfunc)(void);
EMAC_FRAME_t * txbuffnext = 0;
ETH_PKT_t * tx_pep_next;
UINT16 CRCErrors,
RuntErrors,
ExcessLengthErrors,
RxMissCount,
TxColCount;
INT8 bRegistersInitialized = RZK_FALSE;
IORegExt16 pDataPort0;
IORegExt16 pTxCmd;
IORegExt16 pTxLength;
IORegExt16 pISQ;
IORegExt16 pPktPagePtr;
IORegExt16 pPktPageData0;
IORegExt8 pDataPortL0;
IORegExt8 pDataPortH0;
UINT16 RxFilter = IndividualA | BroadcastA | RxOKA;
UINT16 HashTable[ HASH_TABLE_SIZE ] = {0,0,0,0};
INT8 b_mc_count = 0x00;
RZK_SEMAPHOREHANDLE_t g_MacSem;
/*
* Function prototypes.
*/
extern void RxFunc(void);
extern void
nic_read
(
UINT16 Length,
INT8 * pBuf,
IORegExt16 p_io_base
);
extern void
nic_discard
(
UINT16 Length,
IORegExt16 p_io_base
);
extern void
nic_write
(
UINT16 Length,
INT8 * pBuf,
IORegExt16 p_io_base
);
void ETHMADDFUNC
(
INT8 * pAddr
);
INT8
MulticastHash
(
INT8 * ether_addr
);
static DDF_STATUS_t DataPathChk(void);
RZK_SEMAPHOREHANDLE_t g_MacSem;
/*
* ===========================================================================
* =
*/
void
setup_registers
(
IORegExt16 pIOBase
)
{
if( bRegistersInitialized == RZK_FALSE )
{
pDataPort0 = pIOBase + 0x00;
pTxCmd = pIOBase + 0x02;
pTxLength = pIOBase + 0x03;
pISQ = pIOBase + 0x04;
pPktPagePtr = pIOBase + 0x05;
pPktPageData0 = pIOBase + 0x06;
pDataPortL0 = (IORegExt8)pIOBase + 0x00;
pDataPortH0 = (IORegExt8)pIOBase + 0x01;
bRegistersInitialized = RZK_TRUE;
}
}
void
EmacEnableIrq
(
void
)
{
setup_registers( p_emac_base );
PKTPAGEPTR = BUSCTL;
PKTPAGEDATA0 = ADDR_BUSCTL | ENABLE_IRQ;
}
void
EmacDisableIrq
(
void
)
{
setup_registers( p_emac_base );
PKTPAGEPTR = BUSCTL;
PKTPAGEDATA0 = ADDR_BUSCTL;
}
void
EmacReset
(
void
)
{
volatile INT8 bData;
//kprintf("R+");
/*
* Setup internal register used to access the CS8900A in IO mode.
*/
setup_registers( p_emac_base );
/*
* Read a byte from an odd memory location to make sure CS8900 internal 8bit
* state machine is synchronized to the driver.
*/
bData = DATAPORTH0;
/*
* Issue a software reset to CS8900S. This will put the device into a known
* initial state.
*/
PKTPAGEPTR = SELFCTL;
PKTPAGEDATA0 = ADDR_SELFCTL | RESETBIT;
PKTPAGEPTR = SELFST;
while( !(PKTPAGEDATA0 & INITDONE) )//changed
{
/*
* Wait till CS8900A init is complete
*/
}
/*
* Note that the Reset will Clear all interrupt enables and leave the CS8900A
* interrupt request lines in high impedance. This may cause a voltage to
* appear on the GPIO interrupt pin and generate spurious interrupts.
* Therefore, we always enable the Interrupt line of the CS8900A immediately
* after the reset is finished. This will ensure that the IRQ line is driven
* low and since no interrupt enable bits have been set, no interrupts will
* be generated.
*/
/*
* Enable IRQ0 (active high)
*/
PKTPAGEPTR = IRQNUMBER;
PKTPAGEDATA0 = CS8900A_INTRQ0;
PKTPAGEPTR = BUSCTL;
PKTPAGEDATA0 = ADDR_BUSCTL; // | ENABLE_IRQ;
//kprintf("R-");
}
/*----------------------------------------------------------------------------*/
DDF_STATUS_t
EthInitFunc
(
INT8 * ieeeaddr,
void (*rxnotify)(void)
)
/*
* ieeeaddr is pointer to a char array containing 6 bytes of MAC ID which is
* this MAC's ethernet ID. rxnotify is the address of a function which this
* driver will call on reception of a packet. rxnotify is the address of a
* function which must be called every time a receive frame is available in HW.
*
* Return value 0 - successful initialization
*
*/
{
extern INT8 b_poll_emac;
UINT16 i,j;
CRCErrors = RuntErrors = ExcessLengthErrors = RxMissCount = TxColCount = 0;
g_MacSem = RZKCreateSemaphore((RZK_NAME_t*)"g_MacSem",1,RECV_ORDER_PRIORITY);
if(g_MacSem == NULL)
printf("\nEmac Semaphore creation error");
EmacReset();
/* Check if we can read the CS8900A ID */
PKTPAGEPTR = PRODUCTCODE;
if( PKTPAGEDATA0 != CS8900ID )
{
printf("\r\nCS8900 not found ");
return (CS8900_NOTFOUND);
};
/* Databus path checkout */
if ((i = DataPathChk()) != 0)
{
printf("\r\nDatapath problem detected\n");
return (CS8900_DIAGFAIL1);
}
/* Setup our 6 byte (48 bit) IEEE MAC address */
for (i = 0; i < 3; i++)
{
// PKTPAGEPTR = (unsigned short)IEEEADDR + i * 2;
j = IEEEADDR + i * 2;
PKTPAGEPTR = j;
PKTPAGEDATA0 = *(UINT16 *)ieeeaddr;
ieeeaddr += 2;
}
/* Create Interrupt thread */
emacInterruptThdHdl = RZKCreateThreadEnhanced((RZK_NAME_t*)"EMACIT",
(RZK_PTR_t)CS8900IntTask,
NULL,
EMAC_THD_STACK_SIZE,
EMAC_TASK_PRIO,
2,
RZK_THREAD_INTERRUPT|RZK_THREAD_PREEMPTION,
0 ) ;
if( emacInterruptThdHdl == NULL )
{
return EMACDEV_ERR_RESOURCE_NOT_CREATED ;
}
/* Create Interrupt thread */
emacPollThdHdl = RZKCreateThreadEnhanced((RZK_NAME_t*)"EMACpoll",
(RZK_PTR_t)cs8900PollTask,
NULL,
EMAC_POLL_THD_STACK_SIZE,
EMAC_TASK_PRIO,
2,
RZK_THREAD_PREEMPTION|RZK_THREAD_AUTOSTART,
0 ) ;
if( emacPollThdHdl == NULL )
{
return EMACDEV_ERR_RESOURCE_NOT_CREATED ;
}
/* Install interrupt Handler */
#ifndef _EZ80190
RZKInstallInterruptHandler( (RZK_FNP_ISR)emacisr, 0x58) ;
#else
RZKInstallInterruptHandler( (RZK_FNP_ISR)emacisr, 0x4E) ;
#endif
PKTPAGEPTR = BUSCTL;
PKTPAGEDATA0 = ADDR_BUSCTL | ENABLE_IRQ;
/*
* Save the interrupt callback addresses
*/
rxnotifyfunc = rxnotify;
if( rxnotifyfunc == 0 )
{
return (ILLEGAL_CALLBACKS);
}
/*
* Start the mac poll thread if requested by user.
*/
PKTPAGEPTR = LINECTL;
PKTPAGEDATA0 = SerTxON | SerRxON | ADDR_LINECTL;
SetRxFilter(RxFilter, (INT8 *) &HashTable[0]);
PKTPAGEPTR = TXCFG;
PKTPAGEDATA0 = ADDR_TXCFG | ENABLE_ALLTXCFG; /* Enable Tx completion INTR */
PKTPAGEPTR = BUFCFG;
PKTPAGEDATA0 = ADDR_BUFCFG | ENABLE_RDY4TXINT | 0x400; // | 0x8800; /* Enable Rdy4Tx notifications */
PKTPAGEPTR = RXCFG;
PKTPAGEDATA0 = ADDR_RXCFG | BIT_RXOK;//RXALLEVENTS; /* Enable RxOK and Err bits */
return (EMACDEV_ERR_PEMAC_INIT_DONE);}
/*----------------------------------------------------------------------------*/
static DDF_STATUS_t
DataPathChk(void)
{
PKTPAGEPTR = IEEEADDR;
PKTPAGEDATA0 = 0x5555;
if( PKTPAGEDATA0 != 0x5555)
return (0x5555 ^ PKTPAGEDATA0);
PKTPAGEPTR = (IEEEADDR + 2);
PKTPAGEDATA0 = 0xAAAA;
if( PKTPAGEDATA0 != 0xAAAA)
return (0xAAAA ^ PKTPAGEDATA0);
return (0);}
/*----------------------------------------------------------------------------*/
static void
SetRxFilter(UINT16 rxflags, INT8 *cHashbits)
{
UINT16 *Hashbits = (UINT16 *) cHashbits;
UINT16 i;
UINT16 temp;
PKTPAGEPTR = LINECTL;
PKTPAGEDATA0 &= ~SerRxON; /* Disable serial recv */
if (Hashbits != 0)
{
/* Not NULL if a valid hash index field is given */
for (i = 0; i < HASH_TABLE_SIZE; i++)
{
// PKTPAGEPTR = LAFILTER + (i<<1);
temp = i<<1;
temp += LAFILTER;
PKTPAGEPTR = temp;
PKTPAGEDATA0 = Hashbits[i];
}
}
/* mask user flag word for valid bits and update RXCTL */
PKTPAGEPTR = RXCTL;
PKTPAGEDATA0 = rxflags | ADDR_RXCTL;
PKTPAGEPTR = LINECTL;
PKTPAGEDATA0 |= SerRxON;
}
UINT16
TransmitNextPkt
(
void
)
/*
* Assumes interrupts or off.
*/
{
UINT16 BufAvail = RZK_FALSE;
UINTRMASK intmask ;
// kprintf( "Do Next Tx @ %x\n", SysUpTime );
if( doing_tx == RZK_FALSE )
{
/* Deque from the queue */
tx_pep_next = (ETH_PKT_t *) GetFromQueue( &mac_tx_q );
if( tx_pep_next )
{
intmask = RZKDisableInterrupts() ;
doing_tx = RZK_TRUE;
// tx_q_size--;
txbuffnext = (EMAC_FRAME_t *) &tx_pep_next->ethPktOrder;
TXCMD = 0x00C0;
TXLENGTH = txbuffnext->length;
PKTPAGEPTR = BUSST;
BufAvail = PKTPAGEDATA0 & RDY4TXNOW;
RZKEnableInterrupts(intmask) ;
}
}
return( BufAvail );
}
//UINT16 max_queued = 0;
DDF_STATUS_t
EthPktTransmit
(
ETH_PKT_t * pep
)
{
DDF_STATUS_t status;
RZK_STATE_t CritFlag;
if( pep->ethPktLen <= MAXFRAMESIZE )
{
status = EMACDEV_ERR_TX_WAITING; // CR6168 - MSS
/* Queue the packet to the Tx Queue */
// CritFlag = RZKDisablePreemption() ;
RZKAcquireSemaphore(g_MacSem,MAX_INFINITE_SUSPEND);
PutToQueue( &mac_tx_q, &pep->link ); //Moved after disable preemption
if( TransmitNextPkt() )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -