endpoint.c 4.94 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/*

WR Endpoint (WR-compatible Ethernet MAC driver 

Tomasz Wlostowski/CERN 2011

LGPL 2.1

*/

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

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

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

21 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
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
void pcs_write(int location, int value)
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
42
{
43 44 45
    EP->MDIO_CR = EP_MDIO_CR_ADDR_W(location >> 2)
                |  EP_MDIO_CR_DATA_W(value)
                | EP_MDIO_CR_RW;
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
46

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

50
/* MAC address setting */
51
void set_mac_addr(uint8_t dev_addr[])
52 53 54 55 56 57 58 59
{
     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]);
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
}


73
/* Initializes the endpoint and sets its local MAC address */
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
74 75
void ep_init(uint8_t mac_addr[])
{
76
    EP = (volatile struct EP_WB *) BASE_EP;
77 78 79 80 81 82 83 84 85 86 87 88
    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);        
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
89 90
}

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

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

103 104 105
/* Disable the endpoint */
    EP->ECR = 0;

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

108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
/* Load default packet classifier rules - see ep_pfilter.c for details */
    pfilter_init_default();

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

    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 */

/* 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;
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
132 133
}

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

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

144 145
    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
146

147
    if(lpa) *lpa = pcs_read(MDIO_REG_LPA);
148

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

Grzegorz Daniluk's avatar
Grzegorz Daniluk committed
152

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

Grzegorz Daniluk's avatar
Grzegorz Daniluk committed
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179

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);
Grzegorz Daniluk's avatar
Grzegorz Daniluk committed
180 181

  return 0;
Tomasz Wlostowski's avatar
Tomasz Wlostowski committed
182
}