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 * Read the PHY state register to determine link state and speed
93 ed_check_phy_state(void)
95 int lansr = eth_mac_miim_read(PHY_LINK_AN);
96 eth_link_state_t new_state = LS_UNKNOWN;
97 int new_speed = S_UNKNOWN;
104 if (lansr & LANSR_LINK_GOOD){ // link's up
109 switch (lansr & LANSR_SPEED_MASK){
114 case LANSR_SPEED_100:
118 case LANSR_SPEED_1000:
123 new_speed = S_UNKNOWN;
127 else { // link's down
129 puts(" NOT LINK_GOOD");
132 new_speed = S_UNKNOWN;
135 if (new_state != ed_state.link_state){
136 ed_state.link_state = new_state; // remember new state
137 if (new_state == LS_UP)
138 ed_link_up(new_speed);
139 else if (new_state == LS_DOWN)
142 else if (new_state == LS_UP && new_speed != ed_state.link_speed){
143 ed_state.link_speed = new_speed; // remember new speed
144 ed_link_speed_change(new_speed);
149 * This is fired when the ethernet PHY state changes
152 eth_phy_irq_handler(unsigned irq)
154 ed_check_phy_state();
155 eth_mac_miim_write(PHY_INT_CLEAR, ~0); // clear all ints
161 eth_mac_init(ethernet_mac_addr());
163 ed_state.link_state = LS_UNKNOWN;
164 ed_state.link_speed = S_UNKNOWN;
166 // initialize MAC registers
167 eth_mac->tx_hwmark = 0x1e;
168 eth_mac->tx_lwmark = 0x19;
170 eth_mac->crc_chk_en = 1;
171 eth_mac->rx_max_length = 2048;
173 // configure PAUSE frame stuff
174 eth_mac->tx_pause_en = 1; // pay attn to pause frames sent to us
176 eth_mac->pause_quanta_set = 38; // a bit more than 1 max frame 16kb/512 + fudge
177 eth_mac->pause_frame_send_en = 1; // enable sending pause frames
180 // setup PHY to interrupt on changes
183 (PHY_INT_AN_CMPL // auto-neg completed
184 | PHY_INT_NO_LINK // no link after auto-neg
185 | PHY_INT_NO_HCD // no highest common denominator
186 | PHY_INT_MAS_SLA_ERR // couldn't resolve master/slave
187 | PHY_INT_PRL_DET_FLT // parallel detection fault
188 | PHY_INT_LNK_CNG // link established or broken
189 | PHY_INT_SPD_CNG // speed changed
192 eth_mac_miim_write(PHY_INT_CLEAR, ~0); // clear all pending interrupts
193 eth_mac_miim_write(PHY_INT_MASK, mask); // enable the ones we want
195 pic_register_handler(IRQ_PHY, eth_phy_irq_handler);
197 // Advertise that we handle PAUSE frames and asymmetric pause direction.
198 int t = eth_mac_miim_read(PHY_AUTONEG_ADV);
199 eth_mac_miim_write(PHY_AUTONEG_ADV, t | NWAY_AR_PAUSE | NWAY_AR_ASM_DIR);
201 // Restart autonegotation.
202 // We want to ensure that we're advertising our PAUSE capabilities.
203 t = eth_mac_miim_read(PHY_CTRL);
204 eth_mac_miim_write(PHY_CTRL, t | MII_CR_RESTART_AUTO_NEG);
208 unprogrammed(const u2_mac_addr_t *t)
211 bool all_zeros = true;
212 bool all_ones = true;
213 for (i = 0; i < 6; i++){
214 all_zeros &= t->addr[i] == 0x00;
215 all_ones &= t->addr[i] == 0xff;
217 return all_ones | all_zeros;
220 static int8_t src_addr_initialized = false;
221 static u2_mac_addr_t src_addr = {{
222 0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff
225 const u2_mac_addr_t *
226 ethernet_mac_addr(void)
228 if (!src_addr_initialized){ // fetch from eeprom
229 src_addr_initialized = true;
231 // if we're simulating, don't read the EEPROM model, it's REALLY slow
232 if (hwconfig_simulation_p())
236 bool ok = eeprom_read(I2C_ADDR_MBOARD, MBOARD_MAC_ADDR, &tmp.addr[0], 6);
237 if (!ok || unprogrammed(&tmp)){
248 ethernet_set_mac_addr(const u2_mac_addr_t *t)
250 bool ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_MAC_ADDR, &t->addr[0], 6);
253 src_addr_initialized = true;
261 ethernet_check_errors(void)
263 // these registers are reset when read
266 if (eth_mac_read_rmon(0x05) != 0)
268 if (eth_mac_read_rmon(0x06) != 0)
269 r |= RME_RX_FIFO_FULL;
270 if (eth_mac_read_rmon(0x07) != 0)
271 r |= RME_RX_2SHORT_2LONG;
273 if (eth_mac_read_rmon(0x25) != 0)
274 r |= RME_TX_JAM_DROP;
275 if (eth_mac_read_rmon(0x26) != 0)
276 r |= RME_TX_FIFO_UNDER;
277 if (eth_mac_read_rmon(0x27) != 0)
278 r |= RME_TX_FIFO_OVER;