You've already forked gitified_old_clb_svn
210 lines
5.4 KiB
C
210 lines
5.4 KiB
C
/*
|
|
|
|
WR Endpoint (WR-compatible Ethernet MAC driver
|
|
|
|
Tomasz Wlostowski/CERN 2011
|
|
|
|
LGPL 2.1
|
|
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <wrc.h>
|
|
|
|
#include "board.h"
|
|
#include "syscon.h"
|
|
#include <endpoint.h>
|
|
#include "eeprom.h"
|
|
|
|
#include <hw/endpoint_regs.h>
|
|
#include <hw/endpoint_mdio.h>
|
|
|
|
/* Length of a single bit on the gigabit serial link in picoseconds. Used for calculating deltaRx/deltaTx
|
|
from the serdes bitslip value */
|
|
#define PICOS_PER_SERIAL_BIT 800
|
|
|
|
/* Number of raw phase samples averaged by the DMTD detector in the Endpoint during single phase measurement.
|
|
The bigger, the better precision, but slower rate */
|
|
#define DMTD_AVG_SAMPLES 256
|
|
|
|
static int autoneg_enabled;
|
|
volatile struct EP_WB *EP;
|
|
|
|
/* functions for accessing PCS (MDIO) registers */
|
|
uint16_t pcs_read(int location) //VIP km3, before static
|
|
{
|
|
EP->MDIO_CR = EP_MDIO_CR_ADDR_W(location >> 2);
|
|
while ((EP->MDIO_ASR & EP_MDIO_ASR_READY) == 0) ;
|
|
return EP_MDIO_ASR_RDATA_R(EP->MDIO_ASR) & 0xffff;
|
|
}
|
|
|
|
void pcs_write(int location, int value) //VIP km3, before static
|
|
{
|
|
EP->MDIO_CR = EP_MDIO_CR_ADDR_W(location >> 2)
|
|
| EP_MDIO_CR_DATA_W(value)
|
|
| EP_MDIO_CR_RW;
|
|
|
|
while ((EP->MDIO_ASR & EP_MDIO_ASR_READY) == 0) ;
|
|
}
|
|
|
|
/* MAC address setting */
|
|
void set_mac_addr(uint8_t dev_addr[])
|
|
{
|
|
EP->MACL = ((uint32_t) dev_addr[2] << 24)
|
|
| ((uint32_t) dev_addr[3] << 16)
|
|
| ((uint32_t) dev_addr[4] << 8)
|
|
| ((uint32_t) dev_addr[5]);
|
|
|
|
EP->MACH = ((uint32_t) dev_addr[0] << 8)
|
|
| ((uint32_t) dev_addr[1]);
|
|
}
|
|
|
|
void get_mac_addr(uint8_t dev_addr[])
|
|
{
|
|
dev_addr[5] = (EP->MACL & 0x000000ff);
|
|
dev_addr[4] = (EP->MACL & 0x0000ff00) >> 8;
|
|
dev_addr[3] = (EP->MACL & 0x00ff0000) >> 16;
|
|
dev_addr[2] = (EP->MACL & 0xff000000) >> 24;
|
|
dev_addr[1] = (EP->MACH & 0x000000ff);
|
|
dev_addr[0] = (EP->MACH & 0x0000ff00) >> 8;
|
|
}
|
|
|
|
/* Initializes the endpoint and sets its local MAC address */
|
|
void ep_init(uint8_t mac_addr[])
|
|
{
|
|
EP = (volatile struct EP_WB *)BASE_EP;
|
|
set_mac_addr(mac_addr);
|
|
|
|
*(unsigned int *)(0x62000) = 0x2; // reset network stuff (cleanup required!)
|
|
*(unsigned int *)(0x62000) = 0;
|
|
|
|
EP->ECR = 0; /* disable Endpoint */
|
|
EP->VCR0 = EP_VCR0_QMODE_W(3); /* disable VLAN unit - not used by WRPC */
|
|
EP->RFCR = EP_RFCR_MRU_W(1518); /* Set the max RX packet size */
|
|
EP->TSCR = EP_TSCR_EN_TXTS | EP_TSCR_EN_RXTS; /* Enable timestamping */
|
|
|
|
/* Configure DMTD phase tracking */
|
|
EP->DMCR = EP_DMCR_EN | EP_DMCR_N_AVG_W(DMTD_AVG_SAMPLES);
|
|
}
|
|
|
|
/* Enables/disables transmission and reception. When autoneg is set to 1,
|
|
starts up 802.3 autonegotiation process */
|
|
int ep_enable(int enabled, int autoneg)
|
|
{
|
|
uint16_t mcr;
|
|
|
|
if (!enabled) {
|
|
EP->ECR = 0;
|
|
return 0;
|
|
}
|
|
|
|
/* Disable the endpoint */
|
|
EP->ECR = 0;
|
|
|
|
mprintf("ID: %x\n", EP->IDCODE);
|
|
EP->FCR = EP_FCR_RXPAUSE; /* enable processing of received Pause Frames */
|
|
|
|
/* Load default packet classifier rules - see ep_pfilter.c for details */
|
|
pfilter_init_default();
|
|
|
|
autoneg_enabled = autoneg;
|
|
|
|
/* Reset the GTP Transceiver - it's important to do the GTP phase alignment every time
|
|
we start up the software, otherwise the calibration RX/TX deltas may not be correct */
|
|
pcs_write(MDIO_REG_MCR, MDIO_MCR_PDOWN); /* reset the PHY */
|
|
timer_delay(200);
|
|
pcs_write(MDIO_REG_MCR, MDIO_MCR_RESET); /* reset the PHY */
|
|
pcs_write(MDIO_REG_MCR, 0); /* reset the PHY */
|
|
|
|
EP->ECR = EP_ECR_TX_EN;
|
|
|
|
/* wait for PHY to get synced and link_ok */
|
|
while ((pcs_read(MDIO_REG_MSR) & MDIO_MSR_LSTATUS) == 0);
|
|
|
|
/* Enable TX/RX paths, reset RMON counters */
|
|
EP->ECR = EP_ECR_TX_EN | EP_ECR_RX_EN | EP_ECR_RST_CNT;
|
|
|
|
/* Don't advertise anything - we don't want flow control */
|
|
pcs_write(MDIO_REG_ADVERTISE, 0);
|
|
|
|
mcr = MDIO_MCR_SPEED1000_MASK | MDIO_MCR_FULLDPLX_MASK;
|
|
if (autoneg)
|
|
mcr |= MDIO_MCR_ANENABLE | MDIO_MCR_ANRESTART;
|
|
|
|
pcs_write(MDIO_REG_MCR, mcr);
|
|
return 0;
|
|
}
|
|
|
|
/* Checks the link status. If the link is up, returns non-zero
|
|
and stores the Link Partner Ability (LPA) autonegotiation register at *lpa */
|
|
int ep_link_up(uint16_t * lpa)
|
|
{
|
|
|
|
uint16_t flags = MDIO_MSR_LSTATUS;
|
|
volatile uint16_t msr;
|
|
|
|
autoneg_enabled = ((uint16_t)pcs_read(MDIO_REG_MCR) & (0x1000));
|
|
|
|
if (autoneg_enabled)
|
|
flags |= MDIO_MSR_ANEGCOMPLETE;
|
|
|
|
msr = pcs_read(MDIO_REG_MSR);
|
|
msr = pcs_read(MDIO_REG_MSR); // Read this flag twice to make sure the status is updated
|
|
|
|
if (lpa)
|
|
*lpa = pcs_read(MDIO_REG_LPA);
|
|
|
|
return (msr & flags) == flags ? 1 : 0;
|
|
}
|
|
|
|
int ep_get_autonegotiation()
|
|
{
|
|
return ((uint16_t)pcs_read(MDIO_REG_MCR) & (0x1000));
|
|
}
|
|
|
|
int ep_get_bitslide()
|
|
{
|
|
return PICOS_PER_SERIAL_BIT *
|
|
MDIO_WR_SPEC_BSLIDE_R(pcs_read(MDIO_REG_WR_SPEC));
|
|
}
|
|
|
|
/* Returns the TX/RX latencies. They are valid only when the link is up. */
|
|
int ep_get_deltas(uint32_t * delta_tx, uint32_t * delta_rx)
|
|
{
|
|
/* fixme: these values should be stored in calibration block in the EEPROM on the FMC. Also, the TX/RX delays of a particular SFP
|
|
should be added here */
|
|
*delta_tx = sfp_deltaTx;
|
|
*delta_rx =
|
|
sfp_deltaRx +
|
|
PICOS_PER_SERIAL_BIT *
|
|
MDIO_WR_SPEC_BSLIDE_R(pcs_read(MDIO_REG_WR_SPEC));
|
|
return 0;
|
|
}
|
|
|
|
int ep_cal_pattern_enable()
|
|
{
|
|
uint32_t val;
|
|
val = pcs_read(MDIO_REG_WR_SPEC);
|
|
val |= MDIO_WR_SPEC_TX_CAL;
|
|
pcs_write(MDIO_REG_WR_SPEC, val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ep_cal_pattern_disable()
|
|
{
|
|
uint32_t val;
|
|
val = pcs_read(MDIO_REG_WR_SPEC);
|
|
val &= (~MDIO_WR_SPEC_TX_CAL);
|
|
pcs_write(MDIO_REG_WR_SPEC, val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ep_timestamper_cal_pulse()
|
|
{
|
|
EP->TSCR |= EP_TSCR_RX_CAL_START;
|
|
timer_delay(1);
|
|
return EP->TSCR & EP_TSCR_RX_CAL_RESULT ? 1 : 0;
|
|
}
|