Add M460 EMAC driver

pull/15337/head
cyliangtw 2022-03-07 18:44:23 +08:00 committed by Chun-Chieh Li
parent 501aa00fa0
commit 877541d79d
8 changed files with 6410 additions and 0 deletions

View File

@ -0,0 +1,14 @@
# Copyright (c) 2020 ARM Limited. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
target_include_directories(mbed-emac
INTERFACE
.
)
target_sources(mbed-emac
INTERFACE
m460_eth.c
synopGMAC_Dev.c
synopGMAC_network_interface.c
)

View File

@ -0,0 +1,670 @@
/*
* Copyright (c) 2022 Nuvoton Technology Corp.
* Copyright (c) 2022 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Description: M460 MAC driver source file
*/
//#include <stdbool.h>
#include "m460_eth.h"
#include "mbed_toolchain.h"
//#define NU_TRACE
#include "numaker_eth_hal.h"
#include "synopGMAC_network_interface.h"
#ifdef NU_TRACE_ISR
#define NU_RAW_Debug(x) { mbed_error_printf x; }
#else
#define NU_RAW_Debug(x)
#endif
#define NU_M460_INTF 0 // Device EMAC Interface port
#define NU_M460_RMII_PIN_GRP 0 // Device EMAC RMII pin group 0 or 1
extern synopGMACdevice GMACdev[GMAC_CNT];
extern struct sk_buff tx_buf[GMAC_CNT][TRANSMIT_DESC_SIZE];
extern struct sk_buff rx_buf[GMAC_CNT][RECEIVE_DESC_SIZE];
eth_callback_t nu_eth_txrx_cb = NULL;
void *nu_userData = NULL;
extern void ack_emac_rx_isr(void);
void plat_delay(uint32_t delay)
{
volatile uint32_t loop = delay*200;
while (loop--);
}
static void mdio_write(int addr, int reg, int data)
{
synopGMACdevice *gmacdev = &GMACdev[NU_M460_INTF];
synopGMAC_write_phy_reg(gmacdev->MacBase, addr, reg, data);
}
static int mdio_read(int addr, int reg)
{
synopGMACdevice *gmacdev = &GMACdev[NU_M460_INTF];
uint16_t data;
synopGMAC_read_phy_reg(gmacdev->MacBase, addr, reg, &data);
return data;
}
static int reset_phy(void)
{
uint16_t reg;
uint32_t delayCnt;
int retVal = 0;
synopGMACdevice *gmacdev = &GMACdev[NU_M460_INTF];
mdio_write(CONFIG_PHY_ADDR, MII_BMCR, BMCR_RESET);
delayCnt = 2000;
while (delayCnt > 0) {
delayCnt--;
if ((mdio_read(CONFIG_PHY_ADDR, MII_BMCR) & BMCR_RESET) == 0) {
break;
}
}
if (delayCnt == 0) {
NU_DEBUGF(("Reset phy failed\n"));
return (-1);
}
delayCnt = 200000;
while (delayCnt > 0) {
delayCnt--;
if (numaker_eth_link_ok()) {
gmacdev->LinkState = LINKUP;
NU_DEBUGF(("Link Up\n"));
break;
}
}
if (delayCnt == 0) {
gmacdev->LinkState = LINKDOWN;
NU_DEBUGF(("Link Down\n"));
return (-1);
}
mdio_write(CONFIG_PHY_ADDR, MII_ADVERTISE, ADVERTISE_CSMA |
ADVERTISE_10HALF |
ADVERTISE_10FULL |
ADVERTISE_100HALF |
ADVERTISE_100FULL);
reg = mdio_read(CONFIG_PHY_ADDR, MII_BMCR);
mdio_write(CONFIG_PHY_ADDR, MII_BMCR, reg | BMCR_ANRESTART);
delayCnt = 200000;
while (delayCnt > 0) {
delayCnt--;
if ((mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS))
== (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) {
break;
}
}
if( delayCnt == 0 ) {
NU_DEBUGF(("AN failed. Set to 100 FULL\n"));
synopGMAC_set_full_duplex(gmacdev);
synopGMAC_set_mode(NU_M460_INTF, 1); // Set mode 1: 100Mbps; 2: 10Mbps
return (-1);
} else {
reg = mdio_read(CONFIG_PHY_ADDR, MII_LPA);
if (reg & ADVERTISE_100FULL) {
NU_DEBUGF(("100 full\n"));
gmacdev->DuplexMode = FULLDUPLEX;
gmacdev->Speed = SPEED100;
synopGMAC_set_full_duplex(gmacdev);
synopGMAC_set_mode(NU_M460_INTF, 1); // Set mode 1: 100Mbps; 2: 10Mbps
} else if (reg & ADVERTISE_100HALF) {
NU_DEBUGF(("100 half\n"));
gmacdev->DuplexMode = HALFDUPLEX;
gmacdev->Speed = SPEED100;
synopGMAC_set_half_duplex(gmacdev);
synopGMAC_set_mode(NU_M460_INTF, 1); // Set mode 1: 100Mbps; 2: 10Mbps
} else if (reg & ADVERTISE_10FULL) {
NU_DEBUGF(("10 full\n"));
gmacdev->DuplexMode = FULLDUPLEX;
gmacdev->Speed = SPEED10;
synopGMAC_set_full_duplex(gmacdev);
synopGMAC_set_mode(NU_M460_INTF, 2); // Set mode 1: 100Mbps; 2: 10Mbps
} else {
NU_DEBUGF(("10 half\n"));
gmacdev->DuplexMode = HALFDUPLEX;
gmacdev->Speed = SPEED10;
synopGMAC_set_half_duplex(gmacdev);
synopGMAC_set_mode(NU_M460_INTF, 2); // Set mode 1: 100Mbps; 2: 10Mbps
}
}
printf("PHY ID 1:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID1));
printf("PHY ID 2:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID2));
return (retVal);
}
void numaker_set_mac_addr(uint8_t *addr)
{
synopGMAC_set_mac_address(NU_M460_INTF, addr);
}
static void __set_mac_pins(uint32_t group)
{
if(group == 0)
{
SET_EMAC0_RMII_MDC_PE8();
SET_EMAC0_RMII_MDIO_PE9();
SET_EMAC0_RMII_TXD0_PE10();
SET_EMAC0_RMII_TXD1_PE11();
SET_EMAC0_RMII_TXEN_PE12();
SET_EMAC0_RMII_REFCLK_PC8();
SET_EMAC0_RMII_RXD0_PC7();
SET_EMAC0_RMII_RXD1_PC6();
SET_EMAC0_RMII_CRSDV_PA7();
SET_EMAC0_RMII_RXERR_PA6();
SET_EMAC0_PPS_PB6();
}
else
{
SET_EMAC0_RMII_MDC_PB11();
SET_EMAC0_RMII_MDIO_PB10();
SET_EMAC0_RMII_TXD0_PB9();
SET_EMAC0_RMII_TXD1_PB8();
SET_EMAC0_RMII_TXEN_PB7();
SET_EMAC0_RMII_REFCLK_PB5();
SET_EMAC0_RMII_RXD0_PB4();
SET_EMAC0_RMII_RXD1_PB3();
SET_EMAC0_RMII_CRSDV_PB2();
SET_EMAC0_RMII_RXERR_PB1();
SET_EMAC0_PPS_PE13();
}
}
static void __eth_clk_pin_init()
{
/* Unlock protected registers */
SYS_UnlockReg();
/* Enable IP clock */
CLK_EnableModuleClock(EMAC0_MODULE);
// Configure MDC clock rate
/* Update System Core Clock */
SystemCoreClockUpdate();
/*---------------------------------------------------------------------------------------------------------*/
/* Init I/O Multi-function */
/*---------------------------------------------------------------------------------------------------------*/
// Configure RMII pins
__set_mac_pins(NU_M460_RMII_PIN_GRP);
/* Lock protected registers */
SYS_LockReg();
}
void numaker_eth_init(uint8_t *mac_addr)
{
int status = 0;
int retval = 0;
int i;
uint32_t offload_needed = 0;
uint32_t dma_addr;
struct sk_buff *skb;
synopGMACdevice *gmacdev = &GMACdev[NU_M460_INTF];
NVIC_DisableIRQ(EMAC0_TXRX_IRQn);
/* init CLK & pins */
__eth_clk_pin_init();
/*Attach the device to MAC struct This will configure all the required base addresses
such as Mac base, configuration base, phy base address(out of 32 possible phys )*/
synopGMAC_attach(gmacdev, GMAC0MappedAddr + MACBASE, GMAC0MappedAddr + DMABASE, DEFAULT_PHY_BASE);
// Reset MAC
synopGMAC_reset(gmacdev);
gmacdev->Intf = NU_M460_INTF;
synopGMAC_read_version(gmacdev);
/*Check for Phy initialization*/
synopGMAC_set_mdc_clk_div(gmacdev,GmiiCsrClk5);
gmacdev->ClockDivMdc = synopGMAC_get_mdc_clk_div(gmacdev);
/*Reset PHY*/
//status = synopGMAC_check_phy_init(gmacdev);
status = reset_phy();
/*Set up the tx and rx descriptor queue/ring*/
synopGMAC_setup_tx_desc_queue(gmacdev,TRANSMIT_DESC_SIZE, RINGMODE);
synopGMAC_init_tx_desc_base(gmacdev); //Program the transmit descriptor base address in to DmaTxBase addr
synopGMAC_setup_rx_desc_queue(gmacdev,RECEIVE_DESC_SIZE, RINGMODE);
synopGMAC_init_rx_desc_base(gmacdev); //Program the transmit descriptor base address in to DmaTxBase addr
/*Initialize the dma interface*/
synopGMAC_dma_bus_mode_init(gmacdev, DmaBurstLength32 | DmaDescriptorSkip0/*DmaDescriptorSkip2*/ | DmaDescriptor8Words ); synopGMAC_dma_control_init(gmacdev,DmaStoreAndForward |DmaTxSecondFrame|DmaRxThreshCtrl128);
/*Initialize the mac interface*/
synopGMAC_mac_init(gmacdev);
synopGMAC_promisc_enable(gmacdev);
synopGMAC_pause_control(gmacdev); // This enables the pause control in Full duplex mode of operation
#if defined(NU_USING_HW_CHECKSUM)
/*IPC Checksum offloading is enabled for this driver. Should only be used if Full Ip checksumm offload engine is configured in the hardware*/
offload_needed = 1;
synopGMAC_enable_rx_chksum_offload(gmacdev); //Enable the offload engine in the receive path
synopGMAC_rx_tcpip_chksum_drop_enable(gmacdev); // This is default configuration, DMA drops the packets if error in encapsulated ethernet payload
#endif
for(i = 0; i < RECEIVE_DESC_SIZE; i ++) {
skb = &rx_buf[NU_M460_INTF][i];
synopGMAC_set_rx_qptr(gmacdev, (u32)((u64)(skb->data) & 0xFFFFFFFF), sizeof(skb->data), (u32)((u64)skb & 0xFFFFFFFF));
}
for(i = 0; i < TRANSMIT_DESC_SIZE; i ++) {
skb = &tx_buf[NU_M460_INTF][i];
synopGMAC_set_tx_qptr(gmacdev, (u32)((u64)(skb->data) & 0xFFFFFFFF), sizeof(skb->data), (u32)((u64)skb & 0xFFFFFFFF), offload_needed ,0);
}
numaker_set_mac_addr(mac_addr); // need to reconfigure hardware address 'cos we just RESET emc...
synopGMAC_clear_interrupt(gmacdev);
synopGMAC_enable_interrupt(gmacdev,DmaIntEnable);
synopGMAC_enable_dma_rx(gmacdev);
synopGMAC_enable_dma_tx(gmacdev);
synopGMAC_tx_enable(gmacdev);
synopGMAC_rx_enable(gmacdev);
NVIC_EnableIRQ(EMAC0_TXRX_IRQn);
}
void ETH_halt(void)
{
synopGMACdevice *gmacdev = &GMACdev[NU_M460_INTF];
synopGMAC_tx_disable(gmacdev);
synopGMAC_rx_disable(gmacdev);
}
unsigned int m_status;
/*----------------------------------------------------------------------------
EMAC IRQ Handler
*----------------------------------------------------------------------------*/
void EMAC0_IRQHandler(void)
{
synopGMACdevice * gmacdev = &GMACdev[0];
uint32_t interrupt,dma_status_reg, mac_status_reg;
int status;
uint32_t dma_addr;
// Check GMAC interrupt
mac_status_reg = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacInterruptStatus);
if(mac_status_reg & GmacTSIntSts) {
gmacdev->synopGMACNetStats.ts_int = 1;
status = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacTSStatus);
if(!(status & (1 << 1))) {
NU_RAW_Debug(("TS alarm flag not set??\n"));
} else {
NU_RAW_Debug(("TS alarm!!!!!!!!!!!!!!!!\n"));
}
}
if(mac_status_reg & GmacLPIIntSts) {
//NU_RAW_Debug("LPI\n");
//LPIStsChange = 1;
//LPIReg = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacLPICtrlSts);
;
}
if(mac_status_reg & GmacRgmiiIntSts) {
uint32_t volatile reg;
reg = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacRgmiiCtrlSts);
}
synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacInterruptStatus ,mac_status_reg);
/*Read the Dma interrupt status to know whether the interrupt got generated by our device or not*/
dma_status_reg = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaStatus);
NU_RAW_Debug(("i %08x %08x\n", mac_status_reg, dma_status_reg));
if(dma_status_reg == 0)
return;
synopGMAC_disable_interrupt_all(gmacdev);
NU_RAW_Debug(("%s:Dma Status Reg: 0x%08x\n",__FUNCTION__,dma_status_reg));
if(dma_status_reg & GmacPmtIntr) {
NU_RAW_Debug(("%s:: Interrupt due to PMT module\n",__FUNCTION__));
synopGMAC_powerup_mac(gmacdev);
}
if(dma_status_reg & GmacLineIntfIntr) {
NU_RAW_Debug(("%s:: Interrupt due to GMAC LINE module\n",__FUNCTION__));
}
/*Now lets handle the DMA interrupts*/
interrupt = synopGMAC_get_interrupt_type(gmacdev);
NU_RAW_Debug(("%s:Interrupts to be handled: 0x%08x\n",__FUNCTION__,interrupt));
if(interrupt & synopGMACDmaError) {
uint8_t hwaddr[6];
mbed_mac_address((char *)hwaddr);
NU_RAW_Debug(("%s::Fatal Bus Error Interrupt Seen\n",__FUNCTION__));
synopGMAC_disable_dma_tx(gmacdev);
synopGMAC_disable_dma_rx(gmacdev);
synopGMAC_take_desc_ownership_tx(gmacdev);
synopGMAC_take_desc_ownership_rx(gmacdev);
synopGMAC_init_tx_rx_desc_queue(gmacdev);
synopGMAC_reset(gmacdev);//reset the DMA engine and the GMAC ip
synopGMAC_set_mac_address(NU_M460_INTF, (uint8_t*)hwaddr);
synopGMAC_dma_bus_mode_init(gmacdev,DmaFixedBurstEnable| DmaBurstLength8 | DmaDescriptorSkip0/*DmaDescriptorSkip2*/ );
synopGMAC_dma_control_init(gmacdev,DmaStoreAndForward);
synopGMAC_init_rx_desc_base(gmacdev);
synopGMAC_init_tx_desc_base(gmacdev);
synopGMAC_mac_init(gmacdev);
synopGMAC_enable_dma_rx(gmacdev);
synopGMAC_enable_dma_tx(gmacdev);
}
if(interrupt & synopGMACDmaRxNormal) {
//NU_RAW_Debug(("rx\n"));
NU_RAW_Debug(("%s:: Rx Normal \r\n", __FUNCTION__));
// to handle received data
if (nu_eth_txrx_cb != NULL) {
nu_eth_txrx_cb('R', nu_userData);
}
}
if(interrupt & synopGMACDmaRxAbnormal) {
mbed_error_printf("%s::Abnormal Rx Interrupt Seen \r\n",__FUNCTION__);
gmacdev->synopGMACNetStats.rx_over_errors++;
if(gmacdev->GMAC_Power_down == 0) { // If Mac is not in powerdown
synopGMAC_resume_dma_rx(gmacdev);//To handle GBPS with 12 descriptors
}
}
if(interrupt & synopGMACDmaRxStopped) {
mbed_error_printf("%s::Receiver stopped seeing Rx interrupts \r\n",__FUNCTION__); //Receiver gone in to stopped state
if(gmacdev->GMAC_Power_down == 0) { // If Mac is not in powerdown
gmacdev->synopGMACNetStats.rx_over_errors++;
synopGMAC_enable_dma_rx(gmacdev);
}
}
if(interrupt & synopGMACDmaTxNormal) {
//NU_RAW_Debug(("rx\n"));
//xmit function has done its job
NU_RAW_Debug(("%s::Finished Normal Transmission \n",__FUNCTION__));
synop_handle_transmit_over(0);//Do whatever you want after the transmission is over
if (nu_eth_txrx_cb != NULL) {
nu_eth_txrx_cb('T', nu_userData);
}
}
if(interrupt & synopGMACDmaTxAbnormal) {
mbed_error_printf("%s::Abnormal Tx Interrupt Seen\n",__FUNCTION__);
if(gmacdev->GMAC_Power_down == 0) { // If Mac is not in powerdown
synop_handle_transmit_over(0);
if (nu_eth_txrx_cb != NULL) {
nu_eth_txrx_cb('T', nu_userData);
}
}
}
if(interrupt & synopGMACDmaTxStopped) {
mbed_error_printf("%s::Transmitter stopped sending the packets\n",__FUNCTION__);
if(gmacdev->GMAC_Power_down == 0) { // If Mac is not in powerdown
synopGMAC_disable_dma_tx(gmacdev);
synopGMAC_take_desc_ownership_tx(gmacdev);
synopGMAC_enable_dma_tx(gmacdev);
mbed_error_printf("%s::Transmission Resumed\n",__FUNCTION__);
}
}
/* Enable the interrupt before returning from ISR*/
// if( !(interrupt & synopGMACDmaRxNormal)) { /* RxNormal will enable INT in numaker_eth_trigger_rx */
synopGMAC_enable_interrupt(gmacdev,DmaIntEnable);
// }
return;
}
static void dump_desc(DmaDesc *desc)
{
#if 1
NU_DEBUGF(("###--- %s... Desc[0x%08x] status[0x%08x] ---###\r\n", __FUNCTION__, desc, desc->status));
synopGMACdevice *gmacdev = &GMACdev[NU_M460_INTF];
DmaDesc *tmp_desc;
#endif
#if 0
int i=0;
for ( i=0; i< RECEIVE_DESC_SIZE; i++ ) {
tmp_desc = gmacdev->RxDesc + i;
NU_DEBUGF(("### RX %s... desc[0x%08x] status[0x%08x] length[0x%08x] buffer1[0x%08x] buffer2[0x%08x]\r\n",
__FUNCTION__, tmp_desc, tmp_desc->status, tmp_desc->length, tmp_desc->buffer1, tmp_desc->buffer2));
//NU_DEBUGF(("### %s... length[0x%x]\r\n", __FUNCTION__, desc->length));
//NU_DEBUGF(("### %s... buffer1[0x%x]\r\n", __FUNCTION__, desc->buffer1));
//NU_DEBUGF(("### %s... buffer2[0x%x]\r\n", __FUNCTION__, desc->buffer2));
}
for ( i=0; i< TRANSMIT_DESC_SIZE; i++ ) {
tmp_desc = gmacdev->TxDesc + i;
NU_DEBUGF(("### TX %s... desc[0x%08x] status[0x%08x] length[0x%08x] buffer1[0x%08x] buffer2[0x%08x]\r\n",
__FUNCTION__, tmp_desc, tmp_desc->status, tmp_desc->length, tmp_desc->buffer1, tmp_desc->buffer2));
}
#endif
}
void numaker_eth_trigger_rx(void)
{
synopGMACdevice *gmacdev = &GMACdev[NU_M460_INTF];
NU_DEBUGF(("=== %s... ---Start---\r\n", __FUNCTION__));
dump_desc(gmacdev->RxBusyDesc);
/* Enable the interrupt */
synopGMAC_enable_interrupt(gmacdev,DmaIntEnable);
/* Trigger RX DMA */
synopGMAC_enable_dma_rx(gmacdev);
synopGMAC_resume_dma_rx(gmacdev);
NU_DEBUGF(("%s... resume RX DMA\r\n", __FUNCTION__));
NU_DEBUGF(("=== %s... ---End---\r\n", __FUNCTION__));
}
int numaker_eth_get_rx_buf(uint16_t *len, uint8_t **buf)
{
synopGMACdevice *gmacdev = &GMACdev[NU_M460_INTF];
NU_DEBUGF(("=== %s... ---Start---\r\n", __FUNCTION__));
DmaDesc * rxdesc = gmacdev->RxBusyDesc;
dump_desc(rxdesc);
if(synopGMAC_is_desc_owned_by_dma(rxdesc))
return -1;
if(synopGMAC_is_desc_empty(rxdesc))
return -1;
// synopGMAC_disable_dma_rx(gmacdev); // it will encounter DMA interrupt status as "Receiver stopped seeing Rx interrupts"
*len = synop_handle_received_data(NU_M460_INTF, buf);
dump_desc(gmacdev->RxBusyDesc);
if( *len <= 0 ) return -1; /* No available RX frame */
// length of payload should be <= 1514
if (*len > (NU_ETH_MAX_FLEN - 4)) {
NU_DEBUGF(("%s... unexpected long packet length=%d, buf=0x%x\r\n", __FUNCTION__, *len, *buf));
*len = 0; // Skip this unexpected long packet
}
NU_DEBUGF(("=== %s... ---End---\r\n", __FUNCTION__));
return 0;
}
void numaker_eth_rx_next(void)
{
NU_DEBUGF(("=== %s... ---Start---\r\n", __FUNCTION__));
/* Already did in synop_handle_received_data */
/* No-op at this stage */
#if 0
synopGMACdevice *gmacdev = &GMACdev[NU_M460_INTF];
DmaDesc * rxdesc = (gmacdev->RxBusyDesc - 1);
rxdesc->status = DescOwnByDma;
#endif
}
uint8_t *numaker_eth_get_tx_buf(void)
{
synopGMACdevice *gmacdev = &GMACdev[NU_M460_INTF];
DmaDesc * txdesc = gmacdev->TxNextDesc;
if(!synopGMAC_is_desc_empty(txdesc)) {
return (NULL);
}
if (synopGMAC_is_desc_owned_by_dma(txdesc))
{
return (NULL);
} else {
dump_desc(txdesc);
return (txdesc->buffer1);
}
}
void numaker_eth_trigger_tx(uint16_t length, void *p)
{
synopGMACdevice *gmacdev = &GMACdev[NU_M460_INTF];
DmaDesc * txdesc = gmacdev->TxNextDesc;
uint32_t txnext = gmacdev->TxNext;
#if defined(NU_USING_HW_CHECKSUM)
uint32_t offload_needed = 1;
#else
uint32_t offload_needed = 0;
#endif
(gmacdev->BusyTxDesc)++; //busy tx descriptor is incremented by one as it will be handed over to DMA
txdesc->length |= ((length <<DescSize1Shift) & DescSize1Mask);
txdesc->status |= (DescTxFirst | DescTxLast | DescTxIntEnable ); //ENH_DESC
if(offload_needed) {
/*
Make sure that the OS you are running supports the IP and TCP checksum offloading,
before calling any of the functions given below.
*/
synopGMAC_tx_checksum_offload_tcp_pseudo(gmacdev, txdesc);
} else {
synopGMAC_tx_checksum_offload_bypass(gmacdev, txdesc);
}
__DSB();
txdesc->status |= DescOwnByDma;//ENH_DESC
gmacdev->TxNext = synopGMAC_is_last_tx_desc(gmacdev,txdesc) ? 0 : txnext + 1;
gmacdev->TxNextDesc = synopGMAC_is_last_tx_desc(gmacdev,txdesc) ? gmacdev->TxDesc : (txdesc + 1);
/* Enable the interrupt */
synopGMAC_enable_interrupt(gmacdev,DmaIntEnable);
/* Trigger TX DMA */
synopGMAC_resume_dma_tx(gmacdev);
// synopGMAC_enable_dma_tx(gmacdev);
}
int numaker_eth_link_ok(void)
{
/* first, a dummy read to latch */
mdio_read(CONFIG_PHY_ADDR, MII_BMSR);
if (mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & BMSR_LSTATUS) {
return 1;
}
return 0;
}
void numaker_eth_set_cb(eth_callback_t eth_cb, void *userData)
{
nu_eth_txrx_cb = eth_cb;
nu_userData = userData;
}
// Override mbed_mac_address of mbed_interface.c to provide ethernet devices with a semi-unique MAC address
void mbed_mac_address(char *mac)
{
uint32_t uID1;
// Fetch word 0
uint32_t word0 = *(uint32_t *)0xFF804; // 2KB Data Flash at 0xFF800
// Fetch word 1
// we only want bottom 16 bits of word1 (MAC bits 32-47)
// and bit 9 forced to 1, bit 8 forced to 0
// Locally administered MAC, reduced conflicts
// http://en.wikipedia.org/wiki/MAC_address
uint32_t word1 = *(uint32_t *)0xFF800; // 2KB Data Flash at 0xFF800
if (word0 == 0xFFFFFFFF) { // Not burn any mac address at 1st 2 words of Data Flash
// with a semi-unique MAC address from the UUID
/* Enable FMC ISP function */
SYS_UnlockReg();
FMC_Open();
// = FMC_ReadUID(0);
uID1 = FMC_ReadUID(1);
word1 = (uID1 & 0x003FFFFF) | ((uID1 & 0x030000) << 6) >> 8;
word0 = ((FMC_ReadUID(0) >> 4) << 20) | ((uID1 & 0xFF) << 12) | (FMC_ReadUID(2) & 0xFFF);
/* Disable FMC ISP function */
FMC_Close();
/* Lock protected registers */
SYS_LockReg();
}
word1 |= 0x00000200;
word1 &= 0x0000FEFF;
mac[0] = (word1 & 0x0000ff00) >> 8;
mac[1] = (word1 & 0x000000ff);
mac[2] = (word0 & 0xff000000) >> 24;
mac[3] = (word0 & 0x00ff0000) >> 16;
mac[4] = (word0 & 0x0000ff00) >> 8;
mac[5] = (word0 & 0x000000ff);
NU_DEBUGF(("mac address %02x-%02x-%02x-%02x-%02x-%02x \r\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]));
}
void numaker_eth_enable_interrupts(void)
{
synopGMACdevice *gmacdev = &GMACdev[NU_M460_INTF];
/* Enable the interrupt */
synopGMAC_enable_interrupt(gmacdev,DmaIntEnable);
NVIC_EnableIRQ(EMAC0_TXRX_IRQn);
}
void numaker_eth_disable_interrupts(void)
{
NVIC_DisableIRQ(EMAC0_TXRX_IRQn);
}

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2022 Nuvoton Technology Corp.
* Copyright (c) 2022 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Description: M460 EMAC driver header file
*/
#include "numaker_emac_config.h"
#include "M460.h"
#ifndef _M460_ETH_
#define _M460_ETH_
/* Generic MII registers. */
#define MII_BMCR 0x00 /* Basic mode control register */
#define MII_BMSR 0x01 /* Basic mode status register */
#define MII_PHYSID1 0x02 /* PHYS ID 1 */
#define MII_PHYSID2 0x03 /* PHYS ID 2 */
#define MII_ADVERTISE 0x04 /* Advertisement control reg */
#define MII_LPA 0x05 /* Link partner ability reg */
#define MII_EXPANSION 0x06 /* Expansion register */
#define MII_DCOUNTER 0x12 /* Disconnect counter */
#define MII_FCSCOUNTER 0x13 /* False carrier counter */
#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */
#define MII_RERRCOUNTER 0x15 /* Receive error counter */
#define MII_SREVISION 0x16 /* Silicon revision */
#define MII_RESV1 0x17 /* Reserved... */
#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */
#define MII_PHYADDR 0x19 /* PHY address */
#define MII_RESV2 0x1a /* Reserved... */
#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */
#define MII_NCONFIG 0x1c /* Network interface config */
/* Basic mode control register. */
#define BMCR_RESV 0x007f /* Unused... */
#define BMCR_CTST 0x0080 /* Collision test */
#define BMCR_FULLDPLX 0x0100 /* Full duplex */
#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */
#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */
#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */
#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */
#define BMCR_SPEED100 0x2000 /* Select 100Mbps */
#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */
#define BMCR_RESET 0x8000 /* Reset the DP83840 */
/* Basic mode status register. */
#define BMSR_ERCAP 0x0001 /* Ext-reg capability */
#define BMSR_JCD 0x0002 /* Jabber detected */
#define BMSR_LSTATUS 0x0004 /* Link status */
#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */
#define BMSR_RFAULT 0x0010 /* Remote fault detected */
#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */
#define BMSR_RESV 0x07c0 /* Unused... */
#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */
#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */
#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */
#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */
#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */
/* Advertisement control register. */
#define ADVERTISE_SLCT 0x001f /* Selector bits */
#define ADVERTISE_CSMA 0x0001 /* Only selector supported */
#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */
#define ADVERTISE_RESV 0x1c00 /* Unused... */
#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */
#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */
#define ADVERTISE_NPAGE 0x8000 /* Next page bit */
#define PACKET_BUFFER_SIZE ( NU_ETH_MAX_FLEN + ((NU_ETH_MAX_FLEN%4) ? (4 - (NU_ETH_MAX_FLEN%4)) : 0) ) //For DMA 4 bytes alignment
#define CONFIG_PHY_ADDR 1
#endif /* _M460_ETH_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,942 @@
/* ===================================================================================
* Copyright (c) <2009> Synopsys, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software annotated with this license and associated documentation files
* (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* =================================================================================== */
/** \file
* This is the network dependent layer to handle network related functionality.
* This file is tightly coupled to neworking frame work of linux 2.6.xx kernel.
* The functionality carried out in this file should be treated as an example only
* if the underlying operating system is not Linux.
*
* \note Many of the functions other than the device specific functions
* changes for operating system other than Linux 2.6.xx
* \internal
*-----------------------------REVISION HISTORY-----------------------------------
* Synopsys 01/Aug/2007 Created
*/
#include "string.h"
#include "synopGMAC_network_interface.h"
synopGMACdevice GMACdev[GMAC_CNT];
static DmaDesc tx_desc[GMAC_CNT][TRANSMIT_DESC_SIZE] __attribute__ ((aligned (64)));
static DmaDesc rx_desc[GMAC_CNT][RECEIVE_DESC_SIZE] __attribute__ ((aligned (64)));
//static struct sk_buff tx_buf[GMAC_CNT][TRANSMIT_DESC_SIZE] __attribute__ ((aligned (64)));
//static struct sk_buff rx_buf[GMAC_CNT][RECEIVE_DESC_SIZE] __attribute__ ((aligned (64)));
struct sk_buff tx_buf[GMAC_CNT][TRANSMIT_DESC_SIZE] __attribute__ ((aligned (64)));
struct sk_buff rx_buf[GMAC_CNT][RECEIVE_DESC_SIZE] __attribute__ ((aligned (64)));
// These 2 are accessable from application
struct sk_buff txbuf[GMAC_CNT] __attribute__ ((aligned (64))); // set align to separate cacheable and non-cacheable data to different cache line.
struct sk_buff rxbuf[GMAC_CNT] __attribute__ ((aligned (64)));
u8 mac_addr0[6] = DEFAULT_MAC0_ADDRESS;
u8 mac_addr1[6] = DEFAULT_MAC1_ADDRESS;
//static struct timer_list synopGMAC_cable_unplug_timer;
//static u32 GMAC_Power_down; // This global variable is used to indicate the ISR whether the interrupts occured in the process of powering down the mac or not
/**
* Function used to detect the cable plugging and unplugging.
* This function gets scheduled once in every second and polls
* the PHY register for network cable plug/unplug. Once the
* connection is back the GMAC device is configured as per
* new Duplex mode and Speed of the connection.
* @param[in] u32 type but is not used currently.
* \return returns void.
* \note This function is tightly coupled with Linux 2.6.xx.
* \callgraph
*/
void synopGMAC_powerdown_mac(synopGMACdevice *gmacdev)
{
TR0("Put the GMAC to power down mode..\n");
// Disable the Dma engines in tx path
gmacdev->GMAC_Power_down = 1; // Let ISR know that Mac is going to be in the power down mode
synopGMAC_disable_dma_tx(gmacdev);
plat_delay(10000); //allow any pending transmission to complete
// Disable the Mac for both tx and rx
synopGMAC_tx_disable(gmacdev);
synopGMAC_rx_disable(gmacdev);
plat_delay(10000); //Allow any pending buffer to be read by host
//Disable the Dma in rx path
synopGMAC_disable_dma_rx(gmacdev);
//enable the power down mode
//synopGMAC_pmt_unicast_enable(gmacdev);
//prepare the gmac for magic packet reception and wake up frame reception
synopGMAC_magic_packet_enable(gmacdev);
//gate the application and transmit clock inputs to the code. This is not done in this driver :).
//enable the Mac for reception
synopGMAC_rx_enable(gmacdev);
//Enable the assertion of PMT interrupt
synopGMAC_pmt_int_enable(gmacdev);
//enter the power down mode
synopGMAC_power_down_enable(gmacdev);
return;
}
void synopGMAC_powerup_mac(synopGMACdevice *gmacdev)
{
gmacdev->GMAC_Power_down = 0; // Let ISR know that MAC is out of power down now
if( synopGMAC_is_magic_packet_received(gmacdev))
TR("GMAC wokeup due to Magic Pkt Received\n");
if(synopGMAC_is_wakeup_frame_received(gmacdev))
TR("GMAC wokeup due to Wakeup Frame Received\n");
//Disable the assertion of PMT interrupt
synopGMAC_pmt_int_disable(gmacdev);
//Enable the mac and Dma rx and tx paths
synopGMAC_rx_enable(gmacdev);
synopGMAC_enable_dma_rx(gmacdev);
synopGMAC_tx_enable(gmacdev);
synopGMAC_enable_dma_tx(gmacdev);
return;
}
/**
* This sets up the transmit Descriptor queue in ring or chain mode.
* This function is tightly coupled to the platform and operating system
* Device is interested only after the descriptors are setup. Therefore this function
* is not included in the device driver API. This function should be treated as an
* example code to design the descriptor structures for ring mode or chain mode.
* This function depends on the pcidev structure for allocation consistent dma-able memory in case of linux.
* This limitation is due to the fact that linux uses pci structure to allocate a dmable memory
* - Allocates the memory for the descriptors.
* - Initialize the Busy and Next descriptors indices to 0(Indicating first descriptor).
* - Initialize the Busy and Next descriptors to first descriptor address.
* - Initialize the last descriptor with the endof ring in case of ring mode.
* - Initialize the descriptors in chain mode.
* @param[in] pointer to synopGMACdevice.
* @param[in] pointer to pci_device structure.
* @param[in] number of descriptor expected in tx descriptor queue.
* @param[in] whether descriptors to be created in RING mode or CHAIN mode.
* \return 0 upon success. Error code upon failure.
* \note This function fails if allocation fails for required number of descriptors in Ring mode, but in chain mode
* function returns -ESYNOPGMACNOMEM in the process of descriptor chain creation. once returned from this function
* user should for gmacdev->TxDescCount to see how many descriptors are there in the chain. Should continue further
* only if the number of descriptors in the chain meets the requirements
*/
s32 synopGMAC_setup_tx_desc_queue(synopGMACdevice * gmacdev,u32 no_of_desc, u32 desc_mode)
{
s32 i;
DmaDesc *first_desc = &tx_desc[gmacdev->Intf][0];
dma_addr_t dma_addr;
gmacdev->TxDescCount = 0;
TR("Total size of memory required for Tx Descriptors in Ring Mode = 0x%08x\n",((sizeof(DmaDesc) * no_of_desc)));
gmacdev->TxDescCount = no_of_desc;
gmacdev->TxDesc = first_desc;
#ifdef CACHE_ON
gmacdev->TxDescDma = (DmaDesc *)((u64)first_desc | 0x100000000);
#else
gmacdev->TxDescDma = (DmaDesc *)((u64)first_desc);
#endif
for(i =0; i < gmacdev -> TxDescCount; i++) {
synopGMAC_tx_desc_init_ring(gmacdev->TxDescDma + i, i == gmacdev->TxDescCount-1);
TR("%02d %08x \n",i, (unsigned int)(gmacdev->TxDesc + i) );
}
gmacdev->TxNext = 0;
gmacdev->TxBusy = 0;
gmacdev->TxNextDesc = gmacdev->TxDesc;
gmacdev->TxBusyDesc = gmacdev->TxDesc;
gmacdev->BusyTxDesc = 0;
return 0;
}
/**
* This sets up the receive Descriptor queue in ring or chain mode.
* This function is tightly coupled to the platform and operating system
* Device is interested only after the descriptors are setup. Therefore this function
* is not included in the device driver API. This function should be treated as an
* example code to design the descriptor structures in ring mode or chain mode.
* This function depends on the pcidev structure for allocation of consistent dma-able memory in case of linux.
* This limitation is due to the fact that linux uses pci structure to allocate a dmable memory
* - Allocates the memory for the descriptors.
* - Initialize the Busy and Next descriptors indices to 0(Indicating first descriptor).
* - Initialize the Busy and Next descriptors to first descriptor address.
* - Initialize the last descriptor with the endof ring in case of ring mode.
* - Initialize the descriptors in chain mode.
* @param[in] pointer to synopGMACdevice.
* @param[in] pointer to pci_device structure.
* @param[in] number of descriptor expected in rx descriptor queue.
* @param[in] whether descriptors to be created in RING mode or CHAIN mode.
* \return 0 upon success. Error code upon failure.
* \note This function fails if allocation fails for required number of descriptors in Ring mode, but in chain mode
* function returns -ESYNOPGMACNOMEM in the process of descriptor chain creation. once returned from this function
* user should for gmacdev->RxDescCount to see how many descriptors are there in the chain. Should continue further
* only if the number of descriptors in the chain meets the requirements
*/
s32 synopGMAC_setup_rx_desc_queue(synopGMACdevice * gmacdev,u32 no_of_desc, u32 desc_mode)
{
s32 i;
DmaDesc *first_desc = &rx_desc[gmacdev->Intf][0];
dma_addr_t dma_addr;
gmacdev->RxDescCount = 0;
TR("total size of memory required for Rx Descriptors in Ring Mode = 0x%08x\n",((sizeof(DmaDesc) * no_of_desc)));
gmacdev->RxDescCount = no_of_desc;
gmacdev->RxDesc = first_desc;
#ifdef CACHE_ON
gmacdev->RxDescDma = (DmaDesc *)((u64)first_desc | 0x100000000);
#else
gmacdev->RxDescDma = (DmaDesc *)((u64)first_desc);
#endif
for(i =0; i < gmacdev -> RxDescCount; i++) {
synopGMAC_rx_desc_init_ring(gmacdev->RxDescDma + i, i == gmacdev->RxDescCount-1);
TR("%02d %08x \n",i, (unsigned int)(gmacdev->RxDesc + i));
}
gmacdev->RxNext = 0;
gmacdev->RxBusy = 0;
gmacdev->RxNextDesc = gmacdev->RxDesc;
gmacdev->RxBusyDesc = gmacdev->RxDesc;
gmacdev->BusyRxDesc = 0;
return 0;
}
/**
* This gives up the receive Descriptor queue in ring or chain mode.
* This function is tightly coupled to the platform and operating system
* Once device's Dma is stopped the memory descriptor memory and the buffer memory deallocation,
* is completely handled by the operating system, this call is kept outside the device driver Api.
* This function should be treated as an example code to de-allocate the descriptor structures in ring mode or chain mode
* and network buffer deallocation.
* This function depends on the pcidev structure for dma-able memory deallocation for both descriptor memory and the
* network buffer memory under linux.
* The responsibility of this function is to
* - Free the network buffer memory if any.
* - Fee the memory allocated for the descriptors.
* @param[in] pointer to synopGMACdevice.
* @param[in] pointer to pci_device structure.
* @param[in] number of descriptor expected in rx descriptor queue.
* @param[in] whether descriptors to be created in RING mode or CHAIN mode.
* \return 0 upon success. Error code upon failure.
* \note No referece should be made to descriptors once this function is called. This function is invoked when the device is closed.
*/
void synopGMAC_giveup_rx_desc_queue(synopGMACdevice * gmacdev, u32 desc_mode)
{
gmacdev->RxDesc = NULL;
gmacdev->RxDescDma = 0;
return;
}
/**
* This gives up the transmit Descriptor queue in ring or chain mode.
* This function is tightly coupled to the platform and operating system
* Once device's Dma is stopped the memory descriptor memory and the buffer memory deallocation,
* is completely handled by the operating system, this call is kept outside the device driver Api.
* This function should be treated as an example code to de-allocate the descriptor structures in ring mode or chain mode
* and network buffer deallocation.
* This function depends on the pcidev structure for dma-able memory deallocation for both descriptor memory and the
* network buffer memory under linux.
* The responsibility of this function is to
* - Free the network buffer memory if any.
* - Fee the memory allocated for the descriptors.
* @param[in] pointer to synopGMACdevice.
* @param[in] pointer to pci_device structure.
* @param[in] number of descriptor expected in tx descriptor queue.
* @param[in] whether descriptors to be created in RING mode or CHAIN mode.
* \return 0 upon success. Error code upon failure.
* \note No reference should be made to descriptors once this function is called. This function is invoked when the device is closed.
*/
void synopGMAC_giveup_tx_desc_queue(synopGMACdevice * gmacdev, u32 desc_mode)
{
gmacdev->TxDesc = NULL;
gmacdev->TxDescDma = 0;
return;
}
/**
* Function to handle housekeeping after a packet is transmitted over the wire.
* After the transmission of a packet DMA generates corresponding interrupt
* (if it is enabled). It takes care of returning the sk_buff to the linux
* kernel, updating the networking statistics and tracking the descriptors.
* @param[in] pointer to net_device structure.
* \return void.
* \note This function runs in interrupt context
*/
void synop_handle_transmit_over(int intf)
{
synopGMACdevice * gmacdev;
s32 desc_index;
u32 data1;
u32 status;
u32 length1;
u32 dma_addr1;
u32 ext_status;
//u16 time_stamp_higher;
u32 time_stamp_high;
u32 time_stamp_low;
gmacdev = &GMACdev[intf];
/*Handle the transmit Descriptors*/
do {
desc_index = synopGMAC_get_tx_qptr(gmacdev, &status, &dma_addr1, &length1, &data1,&ext_status,&time_stamp_high,&time_stamp_low);
//synopGMAC_TS_read_timestamp_higher_val(gmacdev, &time_stamp_higher);
if(desc_index >= 0 /*&& data1 != 0*/) {
TR("Finished Transmit at Tx Descriptor %d for skb 0x%08x and buffer = %08x whose status is %08x \n", desc_index,data1,dma_addr1,status);
if(synopGMAC_is_tx_ipv4header_checksum_error(gmacdev, status)) {
TR("Harware Failed to Insert IPV4 Header Checksum\n");
gmacdev->synopGMACNetStats.tx_ip_header_errors++;
}
if(synopGMAC_is_tx_payload_checksum_error(gmacdev, status)) {
TR("Harware Failed to Insert Payload Checksum\n");
gmacdev->synopGMACNetStats.tx_ip_payload_errors++;
}
if(synopGMAC_is_desc_valid(status)) {
gmacdev->synopGMACNetStats.tx_bytes += length1;
gmacdev->synopGMACNetStats.tx_packets++;
if(status & DescTxTSStatus) {
gmacdev->tx_sec = time_stamp_high;
gmacdev->tx_subsec = time_stamp_low;
} else {
gmacdev->tx_sec = 0;
gmacdev->tx_subsec = 0;
}
} else {
TR("Error in Status %08x\n",status);
gmacdev->synopGMACNetStats.tx_errors++;
gmacdev->synopGMACNetStats.tx_aborted_errors += synopGMAC_is_tx_aborted(status);
gmacdev->synopGMACNetStats.tx_carrier_errors += synopGMAC_is_tx_carrier_error(status);
}
}
gmacdev->synopGMACNetStats.collisions += synopGMAC_get_tx_collision_count(status);
} while(desc_index >= 0);
}
/**
* Function to Receive a packet from the interface.
* After Receiving a packet, DMA transfers the received packet to the system memory
* and generates corresponding interrupt (if it is enabled). This function prepares
* the sk_buff for received packet after removing the ethernet CRC, and hands it over
* to linux networking stack.
* - Updataes the networking interface statistics
* - Keeps track of the rx descriptors
* @param[in] pointer to net_device structure.
* \return void.
* \note This function runs in interrupt context.
*/
extern DmaDesc * prevtx; // for CRC test
s32 synop_handle_received_data(int intf, u8 **buf) // Chris, to get RX buffer pointer
{
synopGMACdevice * gmacdev;
s32 desc_index;
u32 data1;
u32 len = 0;
u32 status;
u32 dma_addr1;
u32 ext_status;
//u16 time_stamp_higher;
u32 time_stamp_high;
u32 time_stamp_low;
struct sk_buff *rb = &rxbuf[intf];
//struct sk_buff *skb; //This is the pointer to hold the received data
TR("%s\n",__FUNCTION__);
gmacdev = &GMACdev[intf];
/*Handle the Receive Descriptors*/
do {
desc_index = synopGMAC_get_rx_qptr(gmacdev, &status,
&dma_addr1, NULL, &data1,
&ext_status, &time_stamp_high, &time_stamp_low);
if(desc_index >0) {
//synopGMAC_TS_read_timestamp_higher_val(gmacdev, &time_stamp_higher);
//TR("S:%08x ES:%08x DA1:%08x d1:%08x TSH:%08x TSL:%08x TSHW:%08x \n",status,ext_status,dma_addr1, data1,time_stamp_high,time_stamp_low,time_stamp_higher);
TR("S:%08x ES:%08x DA1:%08x d1:%08x TSH:%08x TSL:%08x\n",status,ext_status,dma_addr1, data1,time_stamp_high,time_stamp_low);
}
if(desc_index >= 0 /*&& data1 != 0*/) {
TR("Received Data at Rx Descriptor %d for skb 0x%08x whose status is %08x\n",desc_index,data1,status);
//skb = (struct sk_buff *)((u64)data1);
if(1/*synopGMAC_is_rx_desc_valid(status)*/) {
// Always enter this loop. synopGMAC_is_rx_desc_valid() also report invalid descriptor
// if there's packet error generated by test code and drop it. But we need to execute ext_status
// check code to tell what's going on. --ya
len = synopGMAC_get_rx_desc_frame_length(status) - 4; //Not interested in Ethernet CRC bytes
// Now lets check for the IPC offloading
/* Since we have enabled the checksum offloading in hardware, lets inform the kernel
not to perform the checksum computation on the incoming packet. Note that ip header
checksum will be computed by the kernel immaterial of what we inform. Similary TCP/UDP/ICMP
pseudo header checksum will be computed by the stack. What we can inform is not to perform
payload checksum.
When CHECKSUM_UNNECESSARY is set kernel bypasses the checksum computation.
*/
TR("Checksum Offloading will be done now\n");
if(synopGMAC_is_ext_status(gmacdev, status)) { // extended status present indicates that the RDES4 need to be probed
TR("Extended Status present\n");
if(synopGMAC_ES_is_IP_header_error(gmacdev,ext_status)) { // IP header (IPV4) checksum error
//Linux Kernel doesnot care for ipv4 header checksum. So we will simply proceed by printing a warning ....
TR("(EXTSTS)Error in IP header error\n");
gmacdev->synopGMACNetStats.rx_ip_header_errors++;
}
if(synopGMAC_ES_is_rx_checksum_bypassed(gmacdev,ext_status)) { // Hardware engine bypassed the checksum computation/checking
TR("(EXTSTS)Hardware bypassed checksum computation\n");
}
if(synopGMAC_ES_is_IP_payload_error(gmacdev,ext_status)) { // IP payload checksum is in error (UDP/TCP/ICMP checksum error)
TR("(EXTSTS) Error in EP payload\n");
gmacdev->synopGMACNetStats.rx_ip_payload_errors++;
}
} else { // No extended status. So relevant information is available in the status itself
if(synopGMAC_is_rx_checksum_error(gmacdev, status) == RxNoChkError ) {
TR("Ip header and TCP/UDP payload checksum Bypassed <Chk Status = 4> \n");
}
if(synopGMAC_is_rx_checksum_error(gmacdev, status) == RxIpHdrChkError ) {
//Linux Kernel doesnot care for ipv4 header checksum. So we will simply proceed by printing a warning ....
TR(" Error in 16bit IPV4 Header Checksum <Chk Status = 6> \n");
gmacdev->synopGMACNetStats.rx_ip_header_errors++;
}
if(synopGMAC_is_rx_checksum_error(gmacdev, status) == RxLenLT600 ) {
TR("IEEE 802.3 type frame with Length field Lesss than 0x0600 <Chk Status = 0> \n");
}
if(synopGMAC_is_rx_checksum_error(gmacdev, status) == RxIpHdrPayLoadChkBypass ) {
TR("Ip header and TCP/UDP payload checksum Bypassed <Chk Status = 1>\n");
}
if(synopGMAC_is_rx_checksum_error(gmacdev, status) == RxChkBypass ) {
TR("Ip header and TCP/UDP payload checksum Bypassed <Chk Status = 3> \n");
}
if(synopGMAC_is_rx_checksum_error(gmacdev, status) == RxPayLoadChkError ) {
TR(" TCP/UDP payload checksum Error <Chk Status = 5> \n");
gmacdev->synopGMACNetStats.rx_ip_payload_errors++;
}
if(synopGMAC_is_rx_checksum_error(gmacdev, status) == RxIpHdrPayLoadChkError ) {
//Linux Kernel doesnot care for ipv4 header checksum. So we will simply proceed by printing a warning ....
TR(" Both IP header and Payload Checksum Error <Chk Status = 7> \n");
gmacdev->synopGMACNetStats.rx_ip_header_errors++;
gmacdev->synopGMACNetStats.rx_ip_payload_errors++;
}
}
#if 0
#ifdef CACHE_ON
memcpy((void *)rb->data, (void *)((u64)dma_addr1 | 0x100000000), len);
#else
memcpy((void *)rb->data, (void *)((u64)dma_addr1), len);
#endif
if(prevtx != NULL) {
#ifdef CACHE_ON
memcpy((void *)(rb->data + len), (void *)((u64)(dma_addr1 | 0x100000000) + len), 4);
#else
memcpy((void *)(rb->data + len), (void *)((u64)dma_addr1 + len), 4);
#endif
}
#else
*buf = (u32)((u64)dma_addr1);
#endif
rb->rdy = 1;
rb->len = len;
gmacdev->synopGMACNetStats.rx_packets++;
gmacdev->synopGMACNetStats.rx_bytes += len;
if(status & DescRxTSAvailable) {
gmacdev->rx_sec = time_stamp_high;
gmacdev->rx_subsec = time_stamp_low;
} else {
gmacdev->rx_sec = 0;
gmacdev->rx_subsec = 0;
}
} else {
/*Now the present skb should be set free*/
TR("s: %08x\n",status);
gmacdev->synopGMACNetStats.rx_errors++;
gmacdev->synopGMACNetStats.collisions += synopGMAC_is_rx_frame_collision(status);
gmacdev->synopGMACNetStats.rx_crc_errors += synopGMAC_is_rx_crc(status);
gmacdev->synopGMACNetStats.rx_frame_errors += synopGMAC_is_frame_dribbling_errors(status);
gmacdev->synopGMACNetStats.rx_length_errors += synopGMAC_is_rx_frame_length_errors(status);
}
}
} while(0); //while(desc_index >= 0);
return len;
}
u32 volatile LPIStsChange = 0;
u32 volatile LPIReg = 0;
/**
* Interrupt service routing.
* This is the function registered as ISR for device interrupts.
* @param[in] interrupt number.
* @param[in] void pointer to device unique structure (Required for shared interrupts in Linux).
* @param[in] pointer to pt_regs (not used).
* \return Returns IRQ_NONE if not device interrupts IRQ_HANDLED for device interrupts.
* \note This function runs in interrupt context
*
*/
void synopGMAC0_intr_handler(void)
{
synopGMACdevice * gmacdev = &GMACdev[0];
u32 interrupt,dma_status_reg, mac_status_reg;
s32 status;
u32 dma_addr;
// Check GMAC interrupt
mac_status_reg = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacInterruptStatus);
if(mac_status_reg & GmacTSIntSts) {
gmacdev->synopGMACNetStats.ts_int = 1;
status = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacTSStatus);
if(!(status & (1 << 1)))
printf("TS alarm flag not set??\n");
else
printf("TS alarm!!!!!!!!!!!!!!!!\n");
}
if(mac_status_reg & GmacLPIIntSts) {
//printf("LPI\n");
LPIStsChange = 1;
LPIReg = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacLPICtrlSts);
}
if(mac_status_reg & GmacRgmiiIntSts) {
u32 volatile reg;
reg = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacRgmiiCtrlSts);
}
synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacInterruptStatus ,mac_status_reg);
/*Read the Dma interrupt status to know whether the interrupt got generated by our device or not*/
dma_status_reg = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaStatus);
//printf("i");
//printf("i %08x %08x\n", mac_status_reg, dma_status_reg);
if(dma_status_reg == 0)
return;
synopGMAC_disable_interrupt_all(gmacdev);
TR("%s:Dma Status Reg: 0x%08x\n",__FUNCTION__,dma_status_reg);
if(dma_status_reg & GmacPmtIntr) {
TR("%s:: Interrupt due to PMT module\n",__FUNCTION__);
synopGMAC_powerup_mac(gmacdev);
}
if(dma_status_reg & GmacLineIntfIntr) {
TR("%s:: Interrupt due to GMAC LINE module\n",__FUNCTION__);
}
/*Now lets handle the DMA interrupts*/
interrupt = synopGMAC_get_interrupt_type(gmacdev);
TR("%s:Interrupts to be handled: 0x%08x\n",__FUNCTION__,interrupt);
if(interrupt & synopGMACDmaError) {
TR("%s::Fatal Bus Error Inetrrupt Seen\n",__FUNCTION__);
synopGMAC_disable_dma_tx(gmacdev);
synopGMAC_disable_dma_rx(gmacdev);
synopGMAC_take_desc_ownership_tx(gmacdev);
synopGMAC_take_desc_ownership_rx(gmacdev);
synopGMAC_init_tx_rx_desc_queue(gmacdev);
synopGMAC_reset(gmacdev);//reset the DMA engine and the GMAC ip
synopGMAC_set_mac_addr(gmacdev,GmacAddr0High,GmacAddr0Low, gmacdev->Intf == 0 ? mac_addr0 : mac_addr1);
synopGMAC_dma_bus_mode_init(gmacdev,DmaFixedBurstEnable| DmaBurstLength8 | DmaDescriptorSkip0/*DmaDescriptorSkip2*/ );
synopGMAC_dma_control_init(gmacdev,DmaStoreAndForward);
synopGMAC_init_rx_desc_base(gmacdev);
synopGMAC_init_tx_desc_base(gmacdev);
synopGMAC_mac_init(gmacdev);
synopGMAC_enable_dma_rx(gmacdev);
synopGMAC_enable_dma_tx(gmacdev);
}
if(interrupt & synopGMACDmaRxNormal) {
u8 **buf
//printf("rx\n");
TR("%s:: Rx Normal \n", __FUNCTION__);
synop_handle_received_data(0, buf); // Chris, to get RX buffer pointer
}
if(interrupt & synopGMACDmaRxAbnormal) {
TR("%s::Abnormal Rx Interrupt Seen\n",__FUNCTION__);
gmacdev->synopGMACNetStats.rx_over_errors++;
#if 1
if(gmacdev->GMAC_Power_down == 0) { // If Mac is not in powerdown
synopGMAC_resume_dma_rx(gmacdev);//To handle GBPS with 12 descriptors
}
#endif
}
if(interrupt & synopGMACDmaRxStopped) {
TR("%s::Receiver stopped seeing Rx interrupts\n",__FUNCTION__); //Receiver gone in to stopped state
#if 1
if(gmacdev->GMAC_Power_down == 0) { // If Mac is not in powerdown
gmacdev->synopGMACNetStats.rx_over_errors++;
synopGMAC_enable_dma_rx(gmacdev);
}
#endif
}
if(interrupt & synopGMACDmaTxNormal) {
//printf("tx\n");
//xmit function has done its job
TR("%s::Finished Normal Transmission \n",__FUNCTION__);
synop_handle_transmit_over(0);//Do whatever you want after the transmission is over
}
if(interrupt & synopGMACDmaTxAbnormal) {
TR("%s::Abnormal Tx Interrupt Seen\n",__FUNCTION__);
#if 1
if(gmacdev->GMAC_Power_down == 0) { // If Mac is not in powerdown
synop_handle_transmit_over(0);
}
#endif
}
if(interrupt & synopGMACDmaTxStopped) {
TR("%s::Transmitter stopped sending the packets\n",__FUNCTION__);
#if 1
if(gmacdev->GMAC_Power_down == 0) { // If Mac is not in powerdown
synopGMAC_disable_dma_tx(gmacdev);
synopGMAC_take_desc_ownership_tx(gmacdev);
synopGMAC_enable_dma_tx(gmacdev);
TR("%s::Transmission Resumed\n",__FUNCTION__);
}
#endif
}
/* Enable the interrupt before returning from ISR*/
synopGMAC_enable_interrupt(gmacdev,DmaIntEnable);
return;
}
void synopGMAC_set_speed(int intf)
{
synopGMACdevice *gmacdev = &GMACdev[intf];
switch (gmacdev->Speed) {
case SPEED1000:
synopGMACClearBits((u32 *)gmacdev->MacBase,GmacConfig,GmacMiiGmii);
break;
case SPEED100:
synopGMACSetBits((u32 *)gmacdev->MacBase,GmacConfig,GmacMiiGmii);
synopGMACSetBits((u32 *)gmacdev->MacBase,GmacConfig,GmacFESpeed100);
break;
case SPEED10:
synopGMACSetBits((u32 *)gmacdev->MacBase,GmacConfig,GmacMiiGmii);
synopGMACClearBits((u32 *)gmacdev->MacBase,GmacConfig,GmacFESpeed100);
default:
break;
}
}
/**
* Function used when the interface is opened for use.
* We register synopGMAC_linux_open function to linux open(). Basically this
* function prepares the the device for operation . This function is called whenever ifconfig (in Linux)
* activates the device (for example "ifconfig eth0 up"). This function registers
* system resources needed
* - Attaches device to device specific structure
* - Programs the MDC clock for PHY configuration
* - Check and initialize the PHY interface
* - ISR registration
* - Setup and initialize Tx and Rx descriptors
* - Initialize MAC and DMA
* - Allocate Memory for RX descriptors (The should be DMAable)
* - Initialize one second timer to detect cable plug/unplug
* - Configure and Enable Interrupts
* - Enable Tx and Rx
* - start the Linux network queue interface
* @param[in] pointer to net_device structure.
* \return Returns 0 on success and error status upon failure.
* \callgraph
*/
s32 synopGMAC_open(int intf)
{
//s32 status = 0;
s32 retval = 0;
s32 i;
//s32 reserve_len=2;
u32 dma_addr;
struct sk_buff *skb;
synopGMACdevice * gmacdev = &GMACdev[intf];
/*Attach the device to MAC struct This will configure all the required base addresses
such as Mac base, configuration base, phy base address(out of 32 possible phys )*/
if(intf == 0)
synopGMAC_attach(gmacdev, GMAC0MappedAddr + MACBASE, GMAC0MappedAddr + DMABASE, DEFAULT_PHY_BASE);
else
synopGMAC_attach(gmacdev, GMAC1MappedAddr + MACBASE, GMAC1MappedAddr + DMABASE, DEFAULT_PHY_BASE);
synopGMAC_reset(gmacdev); // Reset to make RGMII/RMII setting take affect --ya
gmacdev->Intf = intf;
/*Lets read the version of ip in to device structure*/
synopGMAC_read_version(gmacdev);
/*Check for Phy initialization*/
synopGMAC_set_mdc_clk_div(gmacdev,GmiiCsrClk5);
//synopGMAC_set_mdc_clk_div(gmacdev, (GmiiCsrClk2|BIT5));
gmacdev->ClockDivMdc = synopGMAC_get_mdc_clk_div(gmacdev);
//status = synopGMAC_check_phy_init(gmacdev);
synopGMAC_check_phy_init(gmacdev);
/*Set up the tx and rx descriptor queue/ring*/
synopGMAC_setup_tx_desc_queue(gmacdev,TRANSMIT_DESC_SIZE, RINGMODE);
synopGMAC_init_tx_desc_base(gmacdev); //Program the transmit descriptor base address in to DmaTxBase addr
synopGMAC_setup_rx_desc_queue(gmacdev,RECEIVE_DESC_SIZE, RINGMODE);
synopGMAC_init_rx_desc_base(gmacdev); //Program the transmit descriptor base address in to DmaTxBase addr
synopGMAC_dma_bus_mode_init(gmacdev, DmaBurstLength32 | DmaDescriptorSkip0/*DmaDescriptorSkip2*/ | DmaDescriptor8Words ); //pbl32 incr with rxthreshold 128 and Desc is 8 Words
synopGMAC_dma_control_init(gmacdev,DmaStoreAndForward |DmaTxSecondFrame|DmaRxThreshCtrl128);
/*Initialize the mac interface*/
synopGMAC_mac_init(gmacdev);
synopGMAC_promisc_enable(gmacdev);
synopGMAC_pause_control(gmacdev); // This enables the pause control in Full duplex mode of operation
#if 0
/*IPC Checksum offloading is enabled for this driver. Should only be used if Full Ip checksumm offload engine is configured in the hardware*/
synopGMAC_enable_rx_chksum_offload(gmacdev); //Enable the offload engine in the receive path
synopGMAC_rx_tcpip_chksum_drop_enable(gmacdev); // This is default configuration, DMA drops the packets if error in encapsulated ethernet payload
#endif
for(i = 0; i < RECEIVE_DESC_SIZE; i ++) {
skb = &rx_buf[intf][i];
synopGMAC_set_rx_qptr(gmacdev, (u32)((u64)(skb->data) & 0xFFFFFFFF), sizeof(skb->data), (u32)((u64)skb & 0xFFFFFFFF));
}
synopGMAC_clear_interrupt(gmacdev);
synopGMAC_enable_interrupt(gmacdev,DmaIntEnable);
synopGMAC_enable_dma_rx(gmacdev);
synopGMAC_enable_dma_tx(gmacdev);
synopGMAC_set_mac_address(intf, intf == 0 ? mac_addr0 : mac_addr1);
return 0;
}
/**
* Function used when the interface is closed.
*
* This function is registered to linux stop() function. This function is
* called whenever ifconfig (in Linux) closes the device (for example "ifconfig eth0 down").
* This releases all the system resources allocated during open call.
* system resources int needs
* - Disable the device interrupts
* - Stop the receiver and get back all the rx descriptors from the DMA
* - Stop the transmitter and get back all the tx descriptors from the DMA
* - Stop the Linux network queue interface
* - Free the irq (ISR registered is removed from the kernel)
* - Release the TX and RX descripor memory
* - De-initialize one second timer rgistered for cable plug/unplug tracking
* @param[in] pointer to net_device structure.
* \return Returns 0 on success and error status upon failure.
* \callgraph
*/
s32 synopGMAC_close(int intf)
{
synopGMACdevice * gmacdev = &GMACdev[intf];;
//TR0("%s\n",__FUNCTION__);
/*Disable all the interrupts*/
synopGMAC_disable_interrupt_all(gmacdev);
TR("the synopGMAC interrupt has been disabled\n");
/*Disable the reception*/
synopGMAC_disable_dma_rx(gmacdev);
synopGMAC_take_desc_ownership_rx(gmacdev);
TR("the synopGMAC Reception has been disabled\n");
/*Disable the transmission*/
synopGMAC_disable_dma_tx(gmacdev);
synopGMAC_take_desc_ownership_tx(gmacdev);
TR("the synopGMAC interrupt handler has been removed\n");
/*Free the Rx Descriptor contents*/
TR("Now calling synopGMAC_giveup_rx_desc_queue \n");
synopGMAC_giveup_rx_desc_queue(gmacdev, RINGMODE);
TR("Now calling synopGMAC_giveup_tx_desc_queue \n");
synopGMAC_giveup_tx_desc_queue(gmacdev, RINGMODE);
return 0;
}
/**
* Function to transmit a given packet on the wire.
* Whenever Linux Kernel has a packet ready to be transmitted, this function is called.
* The function prepares a packet and prepares the descriptor and
* enables/resumes the transmission.
* @param[in] pointer to sk_buff structure.
* @param[in] pointer to net_device structure.
* \return Returns 0 on success and Error code on failure.
* \note structure sk_buff is used to hold packet in Linux networking stacks.
*/
s32 synopGMAC_xmit_frames(struct sk_buff *skb, int intf, u32 offload_needed, u32 ts)
{
s32 status = 0;
u32 dma_addr = (u32)((u64)skb->data & 0xFFFFFFFF);
synopGMACdevice * gmacdev;
gmacdev = &GMACdev[intf];
/*Now we have skb ready and OS invoked this function. Lets make our DMA know about this*/
status = synopGMAC_set_tx_qptr(gmacdev, dma_addr, skb->len, (u32)((u64)skb & 0xFFFFFFFF), offload_needed, ts);
if(status < 0) {
TR0("%s No More Free Tx Descriptors\n",__FUNCTION__);
return -1;
}
/*Now force the DMA to start transmission*/
synopGMAC_resume_dma_tx(gmacdev);
return 0;
}
/**
* Function to set ethernet address of the NIC.
* @param[in] pointer to net_device structure.
* @param[in] pointer to an address structure.
* \return Returns 0 on success Errorcode on failure.
*/
s32 synopGMAC_set_mac_address(int intf, u8* macaddr)
{
synopGMACdevice * gmacdev = NULL;
gmacdev = &GMACdev[intf];
synopGMAC_set_mac_addr(gmacdev, GmacAddr0High, GmacAddr0Low, macaddr);
return 0;
}
// mode 0: 1000Mbps, 1: 100Mbps, 2: 10Mbps
void synopGMAC_set_mode(int intf, int mode)
{
synopGMACdevice *gmacdev = &GMACdev[intf];
// Must stop Tx/Rx before change speed/mode
synopGMAC_tx_disable(gmacdev);
synopGMAC_rx_disable(gmacdev);
switch (mode) {
case 0:
synopGMACClearBits((u32 *)gmacdev->MacBase,GmacConfig,GmacMiiGmii);
gmacdev->Speed = SPEED1000;
break;
case 1:
synopGMACSetBits((u32 *)gmacdev->MacBase,GmacConfig,GmacMiiGmii);
synopGMACSetBits((u32 *)gmacdev->MacBase,GmacConfig,GmacFESpeed100);
gmacdev->Speed = SPEED100;
break;
case 2:
synopGMACSetBits((u32 *)gmacdev->MacBase,GmacConfig,GmacMiiGmii);
synopGMACClearBits((u32 *)gmacdev->MacBase,GmacConfig,GmacFESpeed100);
gmacdev->Speed = SPEED10;
default:
break;
}
synopGMAC_tx_enable(gmacdev);
synopGMAC_rx_enable(gmacdev);
}

View File

@ -0,0 +1,63 @@
/* ===================================================================================
* Copyright (c) <2009> Synopsys, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software annotated with this license and associated documentation files
* (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* =================================================================================== */
/** \file
* Header file for the nework dependent functionality.
* The function prototype listed here are linux dependent.
*
* \internal
* ---------------------------REVISION HISTORY-------------------
* Synopsys 01/Aug/2007 Created
*/
#include "synopGMAC_Dev.h"
#ifndef SYNOP_GMAC_NETWORK_INTERFACE_H
#define SYNOP_GMAC_NETWORK_INTERFACE_H 1
//#define EMULATION
//#define TEST_RGMII
#define TEST_RMII
//#define CACHE_ON
s32 synopGMAC_open(int intf);
s32 synopGMAC_open_selftest(int intf);
s32 synopGMAC_close(int intf);
s32 synopGMAC_xmit_frames(struct sk_buff *, int intf, u32 offload_needed, u32 ts);
void synopGMAC_set_multicast_list(int intf);
s32 synopGMAC_set_mac_address(int intf, u8*);
s32 synopGMAC_change_mtu(int intf,s32);
void synop_handle_transmit_over(int intf);
//void synop_handle_received_data(int intf);
s32 synop_handle_received_data(int intf, u8 **buf); // Chris, to get RX buffer pointer
void synopGMAC_set_mode(int intf, int mode);
void synopGMAC_powerup_mac(synopGMACdevice *gmacdev);
void synopGMAC_powerdown_mac(synopGMACdevice *gmacdev);
s32 synopGMAC_setup_tx_desc_queue(synopGMACdevice * gmacdev,u32 no_of_desc, u32 desc_mode);
s32 synopGMAC_setup_rx_desc_queue(synopGMACdevice * gmacdev,u32 no_of_desc, u32 desc_mode);
#endif /* End of file */

View File

@ -0,0 +1,183 @@
/* ===================================================================================
* Copyright (c) <2009> Synopsys, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software annotated with this license and associated documentation files
* (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* =================================================================================== */
/**\file
* This file serves as the wrapper for the platform/OS dependent functions
* It is needed to modify these functions accordingly based on the platform and the
* OS. Whenever the synopsys GMAC driver ported on to different platform, this file
* should be handled at most care.
* The corresponding function definitions for non-inline functions are available in
* synopGMAC_plat.c file.
* \internal
* -------------------------------------REVISION HISTORY---------------------------
* Synopsys 01/Aug/2007 Created
*/
#ifndef SYNOP_GMAC_PLAT_H
#define SYNOP_GMAC_PLAT_H 1
#include <stdio.h>
#include "NuMicro.h"
#define TR0(fmt, args...) printf("SynopGMAC: " fmt, ##args)
//#define DEBUG
#ifdef DEBUG
#undef TR
# define TR(fmt, args...) printf("SynopGMAC: " fmt, ##args)
#else
# define TR(fmt, args...) /* not debugging: nothing */
#endif
typedef unsigned char u8; ///< Define 8-bit unsigned data type
typedef unsigned short u16; ///< Define 16-bit unsigned data type
typedef unsigned int u32; ///< Define 32-bit unsigned data type
typedef signed int s32; ///< Define 32-bit signed data type
//typedef unsigned long long u64;
typedef unsigned int u64;
typedef int bool;
enum synopGMAC_boolean {
false = 0,
true = 1
};
#define DEFAULT_DELAY_VARIABLE 10
#define DEFAULT_LOOP_VARIABLE 10000
/* There are platform related endian conversions
*
*/
#define LE32_TO_CPU __le32_to_cpu
#define BE32_TO_CPU __be32_to_cpu
#define CPU_TO_LE32 __cpu_to_le32
/* Error Codes */
#define ESYNOPGMACNOERR 0
#define ESYNOPGMACNOMEM 1
#define ESYNOPGMACPHYERR 2
#define ESYNOPGMACBUSY 3
/**
* These are the wrapper function prototypes for OS/platform related routines
*/
extern void plat_delay(uint32_t ticks);
/**
* The Low level function to read register contents from Hardware.
*
* @param[in] pointer to the base of register map
* @param[in] Offset from the base
* \return Returns the register contents
*/
static u32 __INLINE synopGMACReadReg(u32 *RegBase, u32 RegOffset)
{
u64 addr = (u64)RegBase + RegOffset;
u32 data = inp32((void *)addr);
return data;
}
/**
* The Low level function to write to a register in Hardware.
*
* @param[in] pointer to the base of register map
* @param[in] Offset from the base
* @param[in] Data to be written
* \return void
*/
static void __INLINE synopGMACWriteReg(u32 *RegBase, u32 RegOffset, u32 RegData)
{
u64 addr = (u64)RegBase + RegOffset;
if(RegOffset == 0)
plat_delay(1);
outp32((void *)addr, RegData);
return;
}
/**
* The Low level function to set bits of a register in Hardware.
*
* @param[in] pointer to the base of register map
* @param[in] Offset from the base
* @param[in] Bit mask to set bits to logical 1
* \return void
*/
static void __INLINE synopGMACSetBits(u32 *RegBase, u32 RegOffset, u32 BitPos)
{
u64 addr = (u64)RegBase + RegOffset;
u32 data = inp32((void *)addr);
data |= BitPos;
outp32((void *)addr, data);
return;
}
/**
* The Low level function to clear bits of a register in Hardware.
*
* @param[in] pointer to the base of register map
* @param[in] Offset from the base
* @param[in] Bit mask to clear bits to logical 0
* \return void
*/
static void __INLINE synopGMACClearBits(u32 *RegBase, u32 RegOffset, u32 BitPos)
{
u64 addr = (u64)RegBase + RegOffset;
u32 data = inp32((void *)addr);
data &= (~BitPos);
outp32((void *)addr, data);
return;
}
/**
* The Low level function to Check the setting of the bits.
*
* @param[in] pointer to the base of register map
* @param[in] Offset from the base
* @param[in] Bit mask to set bits to logical 1
* \return returns TRUE if set to '1' returns FALSE if set to '0'. Result undefined there are no bit set in the BitPos argument.
*
*/
static bool __INLINE synopGMACCheckBits(u32 *RegBase, u32 RegOffset, u32 BitPos)
{
u64 addr = (u64)RegBase + RegOffset;
u32 data = inp32((void *)addr);
data &= BitPos;
if(data) return true;
else return false;
}
#endif