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)
64 // putstr("ed_link_up: "); puthex16_nl(speed);
66 ed_set_mac_speed(speed);
68 if (ed_callback) // fire link changed callback
69 (*ed_callback)(speed);
75 // putstr("ed_link_down\n");
77 if (ed_callback) // fire link changed callback
83 ed_link_speed_change(int speed)
90 print_flow_control(int flow_control)
92 static const char *flow_control_msg[4] = {
93 "NONE", "WE_TX", "WE_RX", "SYMMETRIC"
95 putstr("ethernet flow control: ");
96 puts(flow_control_msg[flow_control & 0x3]);
100 check_flow_control_resolution(void)
102 static const unsigned char table[16] = {
103 // index = {local_asm, local_pause, partner_asm, partner_pause}
104 FC_NONE, FC_NONE, FC_NONE, FC_NONE,
105 FC_NONE, FC_SYMM, FC_NONE, FC_SYMM,
106 FC_NONE, FC_NONE, FC_NONE, FC_WE_TX,
107 FC_NONE, FC_SYMM, FC_WE_RX, FC_SYMM
110 int us = eth_mac_miim_read(PHY_AUTONEG_ADV);
111 int lp = eth_mac_miim_read(PHY_LP_ABILITY);
112 int index = (((us >> 10) & 0x3) << 2) | ((lp >> 10) & 0x3);
113 ed_state.flow_control = table[index];
116 print_flow_control(ed_state.flow_control);
120 * Read the PHY state register to determine link state and speed
123 ed_check_phy_state(void)
125 int lansr = eth_mac_miim_read(PHY_LINK_AN);
126 eth_link_state_t new_state = LS_UNKNOWN;
127 int new_speed = S_UNKNOWN;
134 if (lansr & LANSR_LINK_GOOD){ // link's up
139 switch (lansr & LANSR_SPEED_MASK){
144 case LANSR_SPEED_100:
148 case LANSR_SPEED_1000:
153 new_speed = S_UNKNOWN;
157 check_flow_control_resolution();
159 else { // link's down
161 puts(" NOT LINK_GOOD");
164 new_speed = S_UNKNOWN;
167 if (new_state != ed_state.link_state){
168 ed_state.link_state = new_state; // remember new state
169 if (new_state == LS_UP)
170 ed_link_up(new_speed);
171 else if (new_state == LS_DOWN)
174 else if (new_state == LS_UP && new_speed != ed_state.link_speed){
175 ed_state.link_speed = new_speed; // remember new speed
176 ed_link_speed_change(new_speed);
181 * This is fired when the ethernet PHY state changes
184 eth_phy_irq_handler(unsigned irq)
186 ed_check_phy_state();
187 eth_mac_miim_write(PHY_INT_CLEAR, ~0); // clear all ints
193 eth_mac_init(ethernet_mac_addr());
195 ed_state.link_state = LS_UNKNOWN;
196 ed_state.link_speed = S_UNKNOWN;
198 // initialize MAC registers
199 eth_mac->tx_hwmark = 0x1e;
200 eth_mac->tx_lwmark = 0x19;
202 eth_mac->crc_chk_en = 1;
203 eth_mac->rx_max_length = 2048;
205 // configure PAUSE frame stuff
206 eth_mac->tx_pause_en = 1; // pay attn to pause frames sent to us
208 eth_mac->pause_quanta_set = 38; // a bit more than 1 max frame 16kb/512 + fudge
209 eth_mac->pause_frame_send_en = 1; // enable sending pause frames
212 // setup PHY to interrupt on changes
215 (PHY_INT_AN_CMPL // auto-neg completed
216 | PHY_INT_NO_LINK // no link after auto-neg
217 | PHY_INT_NO_HCD // no highest common denominator
218 | PHY_INT_MAS_SLA_ERR // couldn't resolve master/slave
219 | PHY_INT_PRL_DET_FLT // parallel detection fault
220 | PHY_INT_LNK_CNG // link established or broken
221 | PHY_INT_SPD_CNG // speed changed
224 eth_mac_miim_write(PHY_INT_CLEAR, ~0); // clear all pending interrupts
225 eth_mac_miim_write(PHY_INT_MASK, mask); // enable the ones we want
227 pic_register_handler(IRQ_PHY, eth_phy_irq_handler);
229 // Advertise our flow control configuation.
231 // We and the link partner each specify two bits in the base page
232 // related to autoconfiguration: NWAY_AR_PAUSE and NWAY_AR_ASM_DIR.
233 // The bits say what a device is "willing" to do, not what may actually
234 // happen as a result of the negotiation. There are 4 cases:
238 // 0 0 I have no flow control capability.
240 // 1 0 I both assert and respond to flow control.
242 // 0 1 I assert flow control, but cannot respond. That is,
243 // I want to be able to send PAUSE frames, but will ignore any
244 // you send to me. (This is our configuration.)
246 // 1 1 I can both assert and respond to flow control AND I am willing
247 // to operate symmetrically OR asymmetrically in EITHER direction.
248 // (We hope the link partner advertises this, otherwise we don't
249 // get what we want.)
251 int t = eth_mac_miim_read(PHY_AUTONEG_ADV);
252 t &= ~(NWAY_AR_PAUSE | NWAY_AR_ASM_DIR);
253 t |= NWAY_AR_ASM_DIR;
255 // Say we can't to 10BASE-T or 100BASE-TX, half or full duplex
256 t &= ~(NWAY_AR_10T_HD_CAPS | NWAY_AR_10T_FD_CAPS | NWAY_AR_100TX_HD_CAPS | NWAY_AR_100TX_FD_CAPS);
258 eth_mac_miim_write(PHY_AUTONEG_ADV, t);
260 // Restart autonegotation.
261 // We want to ensure that we're advertising our PAUSE capabilities.
262 t = eth_mac_miim_read(PHY_CTRL);
263 eth_mac_miim_write(PHY_CTRL, t | MII_CR_RESTART_AUTO_NEG);
267 unprogrammed(const u2_mac_addr_t *t)
270 bool all_zeros = true;
271 bool all_ones = true;
272 for (i = 0; i < 6; i++){
273 all_zeros &= t->addr[i] == 0x00;
274 all_ones &= t->addr[i] == 0xff;
276 return all_ones | all_zeros;
279 static int8_t src_addr_initialized = false;
280 static u2_mac_addr_t src_addr = {{
281 0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff
284 const u2_mac_addr_t *
285 ethernet_mac_addr(void)
287 if (!src_addr_initialized){ // fetch from eeprom
288 src_addr_initialized = true;
290 // if we're simulating, don't read the EEPROM model, it's REALLY slow
291 if (hwconfig_simulation_p())
295 bool ok = eeprom_read(I2C_ADDR_MBOARD, MBOARD_MAC_ADDR, &tmp.addr[0], 6);
296 if (!ok || unprogrammed(&tmp)){
307 ethernet_set_mac_addr(const u2_mac_addr_t *t)
309 bool ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_MAC_ADDR, &t->addr[0], 6);
312 src_addr_initialized = true;
320 ethernet_check_errors(void)
322 // these registers are reset when read
325 if (eth_mac_read_rmon(0x05) != 0)
327 if (eth_mac_read_rmon(0x06) != 0)
328 r |= RME_RX_FIFO_FULL;
329 if (eth_mac_read_rmon(0x07) != 0)
330 r |= RME_RX_2SHORT_2LONG;
332 if (eth_mac_read_rmon(0x25) != 0)
333 r |= RME_TX_JAM_DROP;
334 if (eth_mac_read_rmon(0x26) != 0)
335 r |= RME_TX_FIFO_UNDER;
336 if (eth_mac_read_rmon(0x27) != 0)
337 r |= RME_TX_FIFO_OVER;