2 * Copyright 2007 Free Software Foundation, Inc.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "memory_map.h"
22 #include "eth_mac_regs.h"
28 #include "usrp2_i2c_addr.h"
33 static ethernet_t ed_state;
34 static ethernet_link_changed_callback_t ed_callback = 0;
37 ethernet_register_link_changed_callback(ethernet_link_changed_callback_t new_callback)
39 ed_callback = new_callback;
44 ed_set_mac_speed(int speed)
46 printf("Speed set to %d\n",speed);
67 // putstr("ed_link_up: "); puthex16_nl(speed);
69 ed_set_mac_speed(speed);
71 if (ed_callback) // fire link changed callback
72 (*ed_callback)(speed);
78 // putstr("ed_link_down\n");
80 if (ed_callback) // fire link changed callback
86 ed_link_speed_change(int speed)
93 print_flow_control(int flow_control)
95 static const char *flow_control_msg[4] = {
96 "NONE", "WE_TX", "WE_RX", "SYMMETRIC"
98 putstr("ethernet flow control: ");
99 puts(flow_control_msg[flow_control & 0x3]);
103 check_flow_control_resolution(void)
105 static const unsigned char table[16] = {
106 // index = {local_asm, local_pause, partner_asm, partner_pause}
107 FC_NONE, FC_NONE, FC_NONE, FC_NONE,
108 FC_NONE, FC_SYMM, FC_NONE, FC_SYMM,
109 FC_NONE, FC_NONE, FC_NONE, FC_WE_TX,
110 FC_NONE, FC_SYMM, FC_WE_RX, FC_SYMM
113 int us = eth_mac_miim_read(PHY_AUTONEG_ADV);
114 int lp = eth_mac_miim_read(PHY_LP_ABILITY);
115 int index = (((us >> 10) & 0x3) << 2) | ((lp >> 10) & 0x3);
116 ed_state.flow_control = table[index];
119 print_flow_control(ed_state.flow_control);
123 * Read the PHY state register to determine link state and speed
126 ed_check_phy_state(void)
128 int lansr = eth_mac_miim_read(PHY_LINK_AN);
129 eth_link_state_t new_state = LS_UNKNOWN;
130 int new_speed = S_UNKNOWN;
137 if (lansr & LANSR_LINK_GOOD){ // link's up
142 switch (lansr & LANSR_SPEED_MASK){
147 case LANSR_SPEED_100:
151 case LANSR_SPEED_1000:
156 new_speed = S_UNKNOWN;
160 check_flow_control_resolution();
162 else { // link's down
164 puts(" NOT LINK_GOOD");
167 new_speed = S_UNKNOWN;
170 if (new_state != ed_state.link_state){
171 ed_state.link_state = new_state; // remember new state
172 if (new_state == LS_UP)
173 ed_link_up(new_speed);
174 else if (new_state == LS_DOWN)
177 else if (new_state == LS_UP && new_speed != ed_state.link_speed){
178 ed_state.link_speed = new_speed; // remember new speed
179 ed_link_speed_change(new_speed);
184 * This is fired when the ethernet PHY state changes
187 eth_phy_irq_handler(unsigned irq)
189 ed_check_phy_state();
190 eth_mac_miim_write(PHY_INT_CLEAR, ~0); // clear all ints
196 eth_mac_init(ethernet_mac_addr());
198 ed_state.link_state = LS_UNKNOWN;
199 ed_state.link_speed = S_UNKNOWN;
201 // initialize MAC registers
202 // eth_mac->tx_hwmark = 0x1e;
203 //eth_mac->tx_lwmark = 0x19;
205 //eth_mac->crc_chk_en = 1;
206 //eth_mac->rx_max_length = 2048;
208 // configure PAUSE frame stuff
209 //eth_mac->tx_pause_en = 1; // pay attn to pause frames sent to us
211 //eth_mac->pause_quanta_set = 38; // a bit more than 1 max frame 16kb/512 + fudge
212 //eth_mac->pause_frame_send_en = 1; // enable sending pause frames
215 // setup PHY to interrupt on changes
218 (PHY_INT_AN_CMPL // auto-neg completed
219 | PHY_INT_NO_LINK // no link after auto-neg
220 | PHY_INT_NO_HCD // no highest common denominator
221 | PHY_INT_MAS_SLA_ERR // couldn't resolve master/slave
222 | PHY_INT_PRL_DET_FLT // parallel detection fault
223 | PHY_INT_LNK_CNG // link established or broken
224 | PHY_INT_SPD_CNG // speed changed
227 eth_mac_miim_write(PHY_INT_CLEAR, ~0); // clear all pending interrupts
228 eth_mac_miim_write(PHY_INT_MASK, mask); // enable the ones we want
230 pic_register_handler(IRQ_PHY, eth_phy_irq_handler);
232 // Advertise our flow control configuation.
234 // We and the link partner each specify two bits in the base page
235 // related to autoconfiguration: NWAY_AR_PAUSE and NWAY_AR_ASM_DIR.
236 // The bits say what a device is "willing" to do, not what may actually
237 // happen as a result of the negotiation. There are 4 cases:
241 // 0 0 I have no flow control capability.
243 // 1 0 I both assert and respond to flow control.
245 // 0 1 I assert flow control, but cannot respond. That is,
246 // I want to be able to send PAUSE frames, but will ignore any
247 // you send to me. (This is our configuration.)
249 // 1 1 I can both assert and respond to flow control AND I am willing
250 // to operate symmetrically OR asymmetrically in EITHER direction.
251 // (We hope the link partner advertises this, otherwise we don't
252 // get what we want.)
254 int t = eth_mac_miim_read(PHY_AUTONEG_ADV);
255 t &= ~(NWAY_AR_PAUSE | NWAY_AR_ASM_DIR);
256 t |= NWAY_AR_ASM_DIR;
258 // Say we can't to 10BASE-T or 100BASE-TX, half or full duplex
259 t &= ~(NWAY_AR_10T_HD_CAPS | NWAY_AR_10T_FD_CAPS | NWAY_AR_100TX_HD_CAPS | NWAY_AR_100TX_FD_CAPS);
261 eth_mac_miim_write(PHY_AUTONEG_ADV, t);
262 int r = eth_mac_miim_read(PHY_AUTONEG_ADV); // DEBUG, read back
264 printf("PHY_AUTONEG_ADV: wrote 0x%x, got 0x%x\n", t, r);
267 // Restart autonegotation.
268 // We want to ensure that we're advertising our PAUSE capabilities.
269 t = eth_mac_miim_read(PHY_CTRL);
270 eth_mac_miim_write(PHY_CTRL, t | MII_CR_RESTART_AUTO_NEG);
274 unprogrammed(const u2_mac_addr_t *t)
277 bool all_zeros = true;
278 bool all_ones = true;
279 for (i = 0; i < 6; i++){
280 all_zeros &= t->addr[i] == 0x00;
281 all_ones &= t->addr[i] == 0xff;
283 return all_ones | all_zeros;
286 static int8_t src_addr_initialized = false;
287 static u2_mac_addr_t src_addr = {{
288 0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff
291 const u2_mac_addr_t *
292 ethernet_mac_addr(void)
294 if (!src_addr_initialized){ // fetch from eeprom
295 src_addr_initialized = true;
297 // if we're simulating, don't read the EEPROM model, it's REALLY slow
298 if (hwconfig_simulation_p())
302 bool ok = eeprom_read(I2C_ADDR_MBOARD, MBOARD_MAC_ADDR, &tmp.addr[0], 6);
303 if (!ok || unprogrammed(&tmp)){
314 ethernet_set_mac_addr(const u2_mac_addr_t *t)
316 bool ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_MAC_ADDR, &t->addr[0], 6);
319 src_addr_initialized = true;
327 ethernet_check_errors(void)
329 // these registers are reset when read
333 if (eth_mac_read_rmon(0x05) != 0)
335 if (eth_mac_read_rmon(0x06) != 0)
336 r |= RME_RX_FIFO_FULL;
337 if (eth_mac_read_rmon(0x07) != 0)
338 r |= RME_RX_2SHORT_2LONG;
340 if (eth_mac_read_rmon(0x25) != 0)
341 r |= RME_TX_JAM_DROP;
342 if (eth_mac_read_rmon(0x26) != 0)
343 r |= RME_TX_FIFO_UNDER;
344 if (eth_mac_read_rmon(0x27) != 0)
345 r |= RME_TX_FIFO_OVER;