endpoint.c 4.97 KB
Newer Older
1 2
/*

3
WR Endpoint (WR-compatible Ethernet MAC driver
4 5 6 7 8 9 10

Tomasz Wlostowski/CERN 2011

LGPL 2.1

*/

Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
11
#include <stdio.h>
12
#include <wrc.h>
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
13 14

#include "board.h"
Grzegorz Daniluk's avatar
Grzegorz Daniluk committed
15
#include "syscon.h"
16
#include <endpoint.h>
17
#include "eeprom.h"
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
18 19 20 21

#include <hw/endpoint_regs.h>
#include <hw/endpoint_mdio.h>

22 23 24 25 26 27
/* 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 */
28
#define DMTD_AVG_SAMPLES 256
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
29 30

static int autoneg_enabled;
31
volatile struct EP_WB *EP;
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
32

33
/* functions for accessing PCS (MDIO) registers */
34
static uint16_t pcs_read(int location)
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
35
{
36 37 38
	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;
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
39 40
}

41
static void pcs_write(int location, int value)
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
42
{
43
	EP->MDIO_CR = EP_MDIO_CR_ADDR_W(location >> 2)
44 45
	    | EP_MDIO_CR_DATA_W(value)
	    | EP_MDIO_CR_RW;
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
46

47
	while ((EP->MDIO_ASR & EP_MDIO_ASR_READY) == 0) ;
48
}
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
49

50
/* MAC address setting */
51
void set_mac_addr(uint8_t dev_addr[])
52
{
53
	EP->MACL = ((uint32_t) dev_addr[2] << 24)
54 55 56
	    | ((uint32_t) dev_addr[3] << 16)
	    | ((uint32_t) dev_addr[4] << 8)
	    | ((uint32_t) dev_addr[5]);
57

58
	EP->MACH = ((uint32_t) dev_addr[0] << 8)
59
	    | ((uint32_t) dev_addr[1]);
Grzegorz Daniluk's avatar
Grzegorz Daniluk committed
60
}
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
61

Grzegorz Daniluk's avatar
Grzegorz Daniluk committed
62 63
void get_mac_addr(uint8_t dev_addr[])
{
64 65 66 67 68 69
	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;
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
70 71
}

72
/* Initializes the endpoint and sets its local MAC address */
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
73 74
void ep_init(uint8_t mac_addr[])
{
75 76
	EP = (volatile struct EP_WB *)BASE_EP;
	set_mac_addr(mac_addr);
77

78 79
	*(unsigned int *)(0x62000) = 0x2;	// reset network stuff (cleanup required!)
	*(unsigned int *)(0x62000) = 0;
80

81 82 83 84
	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 */
85 86

/* Configure DMTD phase tracking */
87
	EP->DMCR = EP_DMCR_EN | EP_DMCR_N_AVG_W(DMTD_AVG_SAMPLES);
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
88 89
}

90 91
/* Enables/disables transmission and reception. When autoneg is set to 1,
   starts up 802.3 autonegotiation process */
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
92 93
int ep_enable(int enabled, int autoneg)
{
94
	uint16_t mcr;
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
95

96 97 98 99
	if (!enabled) {
		EP->ECR = 0;
		return 0;
	}
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
100

101
/* Disable the endpoint */
102
	EP->ECR = 0;
103

104
	mprintf("ID: %x\n", EP->IDCODE);
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
105

106
/* Load default packet classifier rules - see ep_pfilter.c for details */
107
	pfilter_init_default();
108 109

/* Enable TX/RX paths, reset RMON counters */
110
	EP->ECR = EP_ECR_TX_EN | EP_ECR_RX_EN | EP_ECR_RST_CNT;
111

112
	autoneg_enabled = autoneg;
113 114 115

/* 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 */
116 117 118 119
	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 */
120 121

/* Don't advertise anything - we don't want flow control */
122
	pcs_write(MDIO_REG_ADVERTISE, 0);
123

124 125 126
	mcr = MDIO_MCR_SPEED1000_MASK | MDIO_MCR_FULLDPLX_MASK;
	if (autoneg)
		mcr |= MDIO_MCR_ANENABLE | MDIO_MCR_ANRESTART;
127

128 129
	pcs_write(MDIO_REG_MCR, mcr);
	return 0;
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
130 131
}

132 133
/* Checks the link status. If the link is up, returns non-zero
   and stores the Link Partner Ability (LPA) autonegotiation register at *lpa */
134
int ep_link_up(uint16_t * lpa)
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
135
{
136 137
	uint16_t flags = MDIO_MSR_LSTATUS;
	volatile uint16_t msr;
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
138

139 140
	if (autoneg_enabled)
		flags |= MDIO_MSR_ANEGCOMPLETE;
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
141

142 143
	msr = pcs_read(MDIO_REG_MSR);
	msr = pcs_read(MDIO_REG_MSR);	/* Read this flag twice to make sure the status is updated */
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
144

145 146
	if (lpa)
		*lpa = pcs_read(MDIO_REG_LPA);
147

148
	return (msr & flags) == flags ? 1 : 0;
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
149 150
}

151 152 153
int ep_get_bitslide()
{
	return PICOS_PER_SERIAL_BIT *
154
	    MDIO_WR_SPEC_BSLIDE_R(pcs_read(MDIO_REG_WR_SPEC));
155 156
}

157
/* Returns the TX/RX latencies. They are valid only when the link is up. */
158
int ep_get_deltas(uint32_t * delta_tx, uint32_t * delta_rx)
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
159
{
160 161
	/* 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 */
162
	*delta_tx = sfp_deltaTx;
163 164 165 166
	*delta_rx =
	    sfp_deltaRx +
	    PICOS_PER_SERIAL_BIT *
	    MDIO_WR_SPEC_BSLIDE_R(pcs_read(MDIO_REG_WR_SPEC));
167
	return 0;
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
168 169
}

Grzegorz Daniluk's avatar
Grzegorz Daniluk committed
170 171
int ep_cal_pattern_enable()
{
172 173 174 175
	uint32_t val;
	val = pcs_read(MDIO_REG_WR_SPEC);
	val |= MDIO_WR_SPEC_TX_CAL;
	pcs_write(MDIO_REG_WR_SPEC, val);
Grzegorz Daniluk's avatar
Grzegorz Daniluk committed
176

177
	return 0;
Grzegorz Daniluk's avatar
Grzegorz Daniluk committed
178 179 180 181
}

int ep_cal_pattern_disable()
{
182 183 184 185
	uint32_t val;
	val = pcs_read(MDIO_REG_WR_SPEC);
	val &= (~MDIO_WR_SPEC_TX_CAL);
	pcs_write(MDIO_REG_WR_SPEC, val);
Grzegorz Daniluk's avatar
Grzegorz Daniluk committed
186

187
	return 0;
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
188
}
189 190 191 192 193 194 195

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;
}