mirror of https://github.com/ARMmbed/mbed-os.git
Add M460 EMAC driver
parent
501aa00fa0
commit
877541d79d
|
@ -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
|
||||||
|
)
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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 */
|
|
@ -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
|
Loading…
Reference in New Issue