diff options
author | Nick Foster <nick@nerdnetworks.org> | 2010-07-27 19:18:48 -0700 |
---|---|---|
committer | Nick Foster <nick@nerdnetworks.org> | 2010-07-27 19:18:48 -0700 |
commit | 06b0fc51c92a933d2641395c0b3974bb95df18d0 (patch) | |
tree | 252e15861d555a201998100dc5b105f971ac0349 /firmware/microblaze | |
parent | 41a36699e6e5f892a19586cde1b72fa6767c2888 (diff) | |
download | uhd-06b0fc51c92a933d2641395c0b3974bb95df18d0.tar.gz uhd-06b0fc51c92a933d2641395c0b3974bb95df18d0.tar.bz2 uhd-06b0fc51c92a933d2641395c0b3974bb95df18d0.zip |
Ethernet PHY re-do.
Diffstat (limited to 'firmware/microblaze')
-rw-r--r-- | firmware/microblaze/lib/Makefile.inc | 1 | ||||
-rw-r--r-- | firmware/microblaze/lib/eth_mac.c | 8 | ||||
-rw-r--r-- | firmware/microblaze/usrp2/Makefile.am | 3 | ||||
-rw-r--r-- | firmware/microblaze/usrp2/eth_phy.h (renamed from firmware/microblaze/lib/eth_phy.h) | 0 | ||||
-rw-r--r-- | firmware/microblaze/usrp2/ethernet.c (renamed from firmware/microblaze/lib/ethernet.c) | 2 | ||||
-rw-r--r-- | firmware/microblaze/usrp2p/Makefile.am | 3 | ||||
-rw-r--r-- | firmware/microblaze/usrp2p/eth_phy.h | 210 | ||||
-rw-r--r-- | firmware/microblaze/usrp2p/ethernet.c | 388 |
8 files changed, 603 insertions, 12 deletions
diff --git a/firmware/microblaze/lib/Makefile.inc b/firmware/microblaze/lib/Makefile.inc index 0e88298b8..02a267d35 100644 --- a/firmware/microblaze/lib/Makefile.inc +++ b/firmware/microblaze/lib/Makefile.inc @@ -25,7 +25,6 @@ COMMON_SRCS = \ $(top_srcdir)/lib/buffer_pool.c \ $(top_srcdir)/lib/dbsm.c \ $(top_srcdir)/lib/eeprom.c \ - $(top_srcdir)/lib/ethernet.c \ $(top_srcdir)/lib/eth_mac.c \ $(top_srcdir)/lib/_exit.c \ $(top_srcdir)/lib/exit.c \ diff --git a/firmware/microblaze/lib/eth_mac.c b/firmware/microblaze/lib/eth_mac.c index 375d3f4d4..cd0179deb 100644 --- a/firmware/microblaze/lib/eth_mac.c +++ b/firmware/microblaze/lib/eth_mac.c @@ -83,14 +83,6 @@ eth_mac_read_rmon(int addr) int eth_mac_miim_read(int addr) { - if (hwconfig_simulation_p()){ - switch(addr){ - case PHY_LINK_AN: - return LANSR_MASTER | LANSR_LINK_GOOD | LANSR_SPEED_1000; - default: - return 0; - } - } int phy_addr = PHY_ADDR; eth_mac->miiaddress = ((addr & 0x1f) << 8) | phy_addr; diff --git a/firmware/microblaze/usrp2/Makefile.am b/firmware/microblaze/usrp2/Makefile.am index 859ded9e5..b45d2481b 100644 --- a/firmware/microblaze/usrp2/Makefile.am +++ b/firmware/microblaze/usrp2/Makefile.am @@ -34,7 +34,8 @@ noinst_LIBRARIES = libusrp2.a libusrp2_a_SOURCES = \ $(COMMON_SRCS) \ clocks.c \ - sd.c + sd.c \ + ethernet.c noinst_PROGRAMS = \ usrp2_txrx_uhd.elf diff --git a/firmware/microblaze/lib/eth_phy.h b/firmware/microblaze/usrp2/eth_phy.h index 6c16f97b7..6c16f97b7 100644 --- a/firmware/microblaze/lib/eth_phy.h +++ b/firmware/microblaze/usrp2/eth_phy.h diff --git a/firmware/microblaze/lib/ethernet.c b/firmware/microblaze/usrp2/ethernet.c index 2d7c4d7bd..d60d7dc4c 100644 --- a/firmware/microblaze/lib/ethernet.c +++ b/firmware/microblaze/usrp2/ethernet.c @@ -27,7 +27,7 @@ #include "i2c.h" #include "usrp2/fw_common.h" -#define VERBOSE 0 +#define VERBOSE 1 static ethernet_t ed_state; static ethernet_link_changed_callback_t ed_callback = 0; diff --git a/firmware/microblaze/usrp2p/Makefile.am b/firmware/microblaze/usrp2p/Makefile.am index eff544294..86affc1f3 100644 --- a/firmware/microblaze/usrp2p/Makefile.am +++ b/firmware/microblaze/usrp2p/Makefile.am @@ -49,7 +49,8 @@ libusrp2p_a_SOURCES = \ spif.c \ spi_flash.c \ spi_flash_read.c \ - bootloader_utils.c + bootloader_utils.c \ + ethernet.c noinst_PROGRAMS = \ usrp2p_txrx_uhd.elf \ diff --git a/firmware/microblaze/usrp2p/eth_phy.h b/firmware/microblaze/usrp2p/eth_phy.h new file mode 100644 index 000000000..9328debee --- /dev/null +++ b/firmware/microblaze/usrp2p/eth_phy.h @@ -0,0 +1,210 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* Much of this was extracted from the Linux e1000_hw.h file */ + +#ifndef INCLUDED_ETH_PHY_H +#define INCLUDED_ETH_PHY_H + +/* PHY 1000 MII Register/Bit Definitions */ +/* PHY Registers defined by IEEE */ + +#define PHY_CTRL 0x00 /* Control Register */ +#define PHY_STATUS 0x01 /* Status Regiser */ +#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ +#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ +#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ +#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ +#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */ +#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */ +#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */ +#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ +#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ +#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */ + +/* PHY 1000 MII Register additions in ET1011C */ +#define PHY_INT_MASK 24 +#define PHY_INT_STATUS 25 +#define PHY_PHY_STATUS 26 + +/* Bit definitions for some of the registers above */ + +/* PHY Control Register (PHY_CTRL) */ +#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ +#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ +#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ +#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */ +#define MII_CR_POWER_DOWN 0x0800 /* Power down */ +#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ +#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ +#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ + +/* PHY Status Register (PHY_STATUS) */ +#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ +#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */ +#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ +#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ +#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ +#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ +#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ +#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ +#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ +#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ +#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ +#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ +#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ +#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ +#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ + +/* Autoneg Advertisement Register (PHY_AUTONEG_ADV) */ +#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */ +#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ +#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ +#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ +#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ +#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */ +#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */ +#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ +#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */ +#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */ + +/* Link Partner Ability Register (Base Page) (PHY_LP_ABILITY) */ +#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */ +#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */ +#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */ +#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */ +#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */ +#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */ +#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */ +#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */ +#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */ +#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */ +#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */ + +/* Autoneg Expansion Register (PHY_AUTONEG_EXP) */ +#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */ +#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */ +#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */ +#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */ +#define NWAY_ER_PAR_DETECT_FAULT 0x0010 /* LP is 100TX Full Duplex Capable */ + +/* Next Page TX Register (PHY_NEXT_PAGE_TX) */ +#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */ +#define NPTX_TOGGLE 0x0800 /* Toggles between exchanges + * of different NP + */ +#define NPTX_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg + * 0 = cannot comply with msg + */ +#define NPTX_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */ +#define NPTX_NEXT_PAGE 0x8000 /* 1 = addition NP will follow + * 0 = sending last NP + */ + +/* Link Partner Next Page Register (PHY_LP_NEXT_PAGE) */ +#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */ +#define LP_RNPR_TOGGLE 0x0800 /* Toggles between exchanges + * of different NP + */ +#define LP_RNPR_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg + * 0 = cannot comply with msg + */ +#define LP_RNPR_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */ +#define LP_RNPR_ACKNOWLDGE 0x4000 /* 1 = ACK / 0 = NO ACK */ +#define LP_RNPR_NEXT_PAGE 0x8000 /* 1 = addition NP will follow + * 0 = sending last NP + */ + +/* 1000BASE-T Control Register (PHY_1000T_CTRL) */ +#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */ +#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ +#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ +#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */ + /* 0=DTE device */ +#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */ + /* 0=Configure PHY as Slave */ +#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */ + /* 0=Automatic Master/Slave config */ +#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */ +#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */ +#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */ +#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */ +#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */ + +/* 1000BASE-T Status Register (PHY_1000T_STATUS) */ +#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */ +#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */ +#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */ +#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */ +#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ +#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ +#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */ +#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */ +#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12 +#define SR_1000T_LOCAL_RX_STATUS_SHIFT 13 +#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5 +#define FFE_IDLE_ERR_COUNT_TIMEOUT_20 20 +#define FFE_IDLE_ERR_COUNT_TIMEOUT_100 100 + +/* Extended Status Register (PHY_EXT_STATUS) */ +#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */ +#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */ +#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */ +#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */ + +#define PHY_TX_POLARITY_MASK 0x0100 /* register 10h bit 8 (polarity bit) */ +#define PHY_TX_NORMAL_POLARITY 0 /* register 10h bit 8 (normal polarity) */ + +#define AUTO_POLARITY_DISABLE 0x0010 /* register 11h bit 4 */ + /* (0=enable, 1=disable) */ + +/* PHY Status Register (PHY_PHY_STATUS) */ +#define PHYSTAT_ASYMMETRIC (1 << 0) +#define PHYSTAT_PAUSE (1 << 1) +#define PHYSTAT_AUTONEG_EN (1 << 2) +#define PHYSTAT_COLLISION (1 << 3) +#define PHYSTAT_RXSTAT (1 << 4) +#define PHYSTAT_TXSTAT (1 << 5) +#define PHYSTAT_LINK (1 << 6) +#define PHYSTAT_DUPLEX (1 << 7) +#define PHYSTAT_SPEED_MASK ((1 << 8) | (1 << 9)) +#define PHYSTAT_SPEED_1000 (1 << 9) +#define PHYSTAT_SPEED_100 (1 << 8) +#define PHYSTAT_SPEED_10 0 +#define PHYSTAT_POLARITY (1 << 10) +#define PHYSTAT_MDIX (1 << 11) +#define PHYSTAT_AUTONEG_STAT (1 << 12) +#define PHYSTAT_STANDBY (1 << 13) + +/* Interrupt status, mask and clear regs (PHY_INT_{STATUS,MASK,CLEAR}) */ +#define PHY_INT_ENABLE (1 << 0) +#define PHY_INT_DOWNSHIFT (1 << 1) +#define PHY_INT_LINK_STATUS_CHANGE (1 << 2) +#define PHY_INT_RX_STATUS_CHANGE (1 << 3) +#define PHY_INT_FIFO_ERROR (1 << 4) +#define PHY_INT_ERR_CTR_FULL (1 << 5) +#define PHY_INT_NEXT_PAGE_RX (1 << 6) +#define PHY_INT_CRC_ERROR (1 << 7) +#define PHY_INT_AUTONEG_STATUS_CHANGE (1 << 8) +#define PHY_INT_MDIO_SYNC_LOST (1 << 9) +#define PHY_INT_TDR_IP_PHONE (1 << 10) + +#endif /* INCLUDED_ETH_PHY_H */ diff --git a/firmware/microblaze/usrp2p/ethernet.c b/firmware/microblaze/usrp2p/ethernet.c new file mode 100644 index 000000000..134650326 --- /dev/null +++ b/firmware/microblaze/usrp2p/ethernet.c @@ -0,0 +1,388 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +//Changes for USRP2P: status registers different (ethernet.h) + +#include "ethernet.h" +#include "memory_map.h" +#include "eth_phy.h" +#include <eth_mac.h> +#include <eth_mac_regs.h> +#include <pic.h> +#include <hal_io.h> +#include <nonstdio.h> +#include <stdbool.h> +#include <i2c.h> +#include "usrp2/fw_common.h" + +#define VERBOSE 1 + +static ethernet_t ed_state; +static ethernet_link_changed_callback_t ed_callback = 0; + +void +ethernet_register_link_changed_callback(ethernet_link_changed_callback_t new_callback) +{ + ed_callback = new_callback; +} + + +static void +ed_set_mac_speed(int speed) +{ + printf("Speed set to %d\n",speed); + /* + switch(speed){ + case 10: + eth_mac->speed = 1; + break; + case 100: + eth_mac->speed = 2; + break; + case 1000: + eth_mac->speed = 4; + break; + default: + break; + } + */ +} + +static void +ed_link_up(int speed) +{ + // putstr("ed_link_up: "); puthex16_nl(speed); + + ed_set_mac_speed(speed); + + if (ed_callback) // fire link changed callback + (*ed_callback)(speed); +} + +static void +ed_link_down(void) +{ + // putstr("ed_link_down\n"); + + if (ed_callback) // fire link changed callback + (*ed_callback)(0); +} + + +static void +ed_link_speed_change(int speed) +{ + ed_link_down(); + ed_link_up(speed); +} + +static void +print_flow_control(int flow_control) +{ + static const char *flow_control_msg[4] = { + "NONE", "WE_TX", "WE_RX", "SYMMETRIC" + }; + putstr("ethernet flow control: "); + puts(flow_control_msg[flow_control & 0x3]); +} + +static void +check_flow_control_resolution(void) +{ + static const unsigned char table[16] = { + // index = {local_asm, local_pause, partner_asm, partner_pause} + FC_NONE, FC_NONE, FC_NONE, FC_NONE, + FC_NONE, FC_SYMM, FC_NONE, FC_SYMM, + FC_NONE, FC_NONE, FC_NONE, FC_WE_TX, + FC_NONE, FC_SYMM, FC_WE_RX, FC_SYMM + }; + + int us = eth_mac_miim_read(PHY_AUTONEG_ADV); + int lp = eth_mac_miim_read(PHY_LP_ABILITY); + int index = (((us >> 10) & 0x3) << 2) | ((lp >> 10) & 0x3); + ed_state.flow_control = table[index]; + + if (1) + print_flow_control(ed_state.flow_control); +} + +/* + * Read the PHY state register to determine link state and speed + */ +static void +ed_check_phy_state(void) +{ + int phystat = eth_mac_miim_read(PHY_PHY_STATUS); + eth_link_state_t new_state = LS_UNKNOWN; + int new_speed = S_UNKNOWN; + + if (VERBOSE){ + putstr("PHYSTAT: "); + puthex16_nl(phystat); + } + + if (phystat & PHYSTAT_LINK){ // link's up + if (VERBOSE) + puts(" LINK_GOOD"); + + new_state = LS_UP; + switch (phystat & PHYSTAT_SPEED_MASK){ + case PHYSTAT_SPEED_10: + new_speed = 10; + break; + + case PHYSTAT_SPEED_100: + new_speed = 100; + break; + + case PHYSTAT_SPEED_1000: + new_speed = 1000; + break; + + default: + new_speed = S_UNKNOWN; + break; + } + + check_flow_control_resolution(); + } + else { // link's down + if (VERBOSE) + puts(" NOT LINK_GOOD"); + + new_state = LS_DOWN; + new_speed = S_UNKNOWN; + } + + if (new_state != ed_state.link_state){ + ed_state.link_state = new_state; // remember new state + if (new_state == LS_UP) + ed_link_up(new_speed); + else if (new_state == LS_DOWN) + ed_link_down(); + } + else if (new_state == LS_UP && new_speed != ed_state.link_speed){ + ed_state.link_speed = new_speed; // remember new speed + ed_link_speed_change(new_speed); + } +} + +/* + * This is fired when the ethernet PHY state changes + */ +static void +eth_phy_irq_handler(unsigned irq) +{ + ed_check_phy_state(); + eth_mac_miim_read(PHY_INT_STATUS); +// eth_mac_miim_write(PHY_INT_CLEAR, ~0); // clear all ints +} + +void +ethernet_init(void) +{ + eth_mac_init(ethernet_mac_addr()); + + ed_state.link_state = LS_UNKNOWN; + ed_state.link_speed = S_UNKNOWN; + + // initialize MAC registers + // eth_mac->tx_hwmark = 0x1e; + //eth_mac->tx_lwmark = 0x19; + + //eth_mac->crc_chk_en = 1; + //eth_mac->rx_max_length = 2048; + + // configure PAUSE frame stuff + //eth_mac->tx_pause_en = 1; // pay attn to pause frames sent to us + + //eth_mac->pause_quanta_set = 38; // a bit more than 1 max frame 16kb/512 + fudge + //eth_mac->pause_frame_send_en = 1; // enable sending pause frames + + + // setup PHY to interrupt on changes + + unsigned mask = + (PHY_INT_ENABLE //master interrupt enable + | PHY_INT_LINK_STATUS_CHANGE + | PHY_INT_RX_STATUS_CHANGE + ); + + eth_mac_miim_read(PHY_INT_STATUS); + eth_mac_miim_write(PHY_INT_MASK, mask); // enable the ones we want + + pic_register_handler(IRQ_PHY, eth_phy_irq_handler); + + // Advertise our flow control configuation. + // + // We and the link partner each specify two bits in the base page + // related to autoconfiguration: NWAY_AR_PAUSE and NWAY_AR_ASM_DIR. + // The bits say what a device is "willing" to do, not what may actually + // happen as a result of the negotiation. There are 4 cases: + // + // PAUSE ASM_DIR + // + // 0 0 I have no flow control capability. + // + // 1 0 I both assert and respond to flow control. + // + // 0 1 I assert flow control, but cannot respond. That is, + // I want to be able to send PAUSE frames, but will ignore any + // you send to me. (This is our configuration.) + // + // 1 1 I can both assert and respond to flow control AND I am willing + // to operate symmetrically OR asymmetrically in EITHER direction. + // (We hope the link partner advertises this, otherwise we don't + // get what we want.) + + int t = eth_mac_miim_read(PHY_AUTONEG_ADV); + t &= ~(NWAY_AR_PAUSE | NWAY_AR_ASM_DIR); + t |= NWAY_AR_ASM_DIR; + + // Say we can't to 10BASE-T or 100BASE-TX, half or full duplex + t &= ~(NWAY_AR_10T_HD_CAPS | NWAY_AR_10T_FD_CAPS | NWAY_AR_100TX_HD_CAPS | NWAY_AR_100TX_FD_CAPS); + + eth_mac_miim_write(PHY_AUTONEG_ADV, t); + int r = eth_mac_miim_read(PHY_AUTONEG_ADV); // DEBUG, read back + if (t != r){ + printf("PHY_AUTONEG_ADV: wrote 0x%x, got 0x%x\n", t, r); + } + + // Restart autonegotation. + // We want to ensure that we're advertising our PAUSE capabilities. + t = eth_mac_miim_read(PHY_CTRL); + eth_mac_miim_write(PHY_CTRL, t | MII_CR_RESTART_AUTO_NEG); +} + +static bool +unprogrammed(const void *t, size_t len) +{ + int i; + uint8_t *p = (uint8_t *)t; + bool all_zeros = true; + bool all_ones = true; + for (i = 0; i < len; i++){ + all_zeros &= p[i] == 0x00; + all_ones &= p[i] == 0xff; + } + return all_ones | all_zeros; +} + +//////////////////// MAC Addr Stuff /////////////////////// + +static int8_t src_mac_addr_initialized = false; +static eth_mac_addr_t src_mac_addr = {{ + 0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff + }}; + +const eth_mac_addr_t * +ethernet_mac_addr(void) +{ + if (!src_mac_addr_initialized){ // fetch from eeprom + src_mac_addr_initialized = true; + + // if we're simulating, don't read the EEPROM model, it's REALLY slow + if (hwconfig_simulation_p()) + return &src_mac_addr; + + eth_mac_addr_t tmp; + bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, &tmp, sizeof(tmp)); + if (!ok || unprogrammed(&tmp, sizeof(tmp))){ + // use the default + } + else + src_mac_addr = tmp; + } + + return &src_mac_addr; +} + +bool +ethernet_set_mac_addr(const eth_mac_addr_t *t) +{ + bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, t, sizeof(eth_mac_addr_t)); + if (ok){ + src_mac_addr = *t; + src_mac_addr_initialized = true; + //eth_mac_set_addr(t); //this breaks the link + } + + return ok; +} + +//////////////////// IP Addr Stuff /////////////////////// + +static int8_t src_ip_addr_initialized = false; +static struct ip_addr src_ip_addr = { + (192 << 24 | 168 << 16 | 10 << 8 | 2 << 0) +}; + + +const struct ip_addr *get_ip_addr(void) +{ + if (!src_ip_addr_initialized){ // fetch from eeprom + src_ip_addr_initialized = true; + + // if we're simulating, don't read the EEPROM model, it's REALLY slow + if (hwconfig_simulation_p()) + return &src_ip_addr; + + struct ip_addr tmp; + bool ok = eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, &tmp, sizeof(tmp)); + if (!ok || unprogrammed(&tmp, sizeof(tmp))){ + // use the default + } + else + src_ip_addr = tmp; + } + + return &src_ip_addr; +} + +bool set_ip_addr(const struct ip_addr *t){ + bool ok = eeprom_write(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, t, sizeof(struct ip_addr)); + if (ok){ + src_ip_addr = *t; + src_ip_addr_initialized = true; + } + + return ok; +} + +int +ethernet_check_errors(void) +{ + // these registers are reset when read + + int r = 0; + /* + if (eth_mac_read_rmon(0x05) != 0) + r |= RME_RX_CRC; + if (eth_mac_read_rmon(0x06) != 0) + r |= RME_RX_FIFO_FULL; + if (eth_mac_read_rmon(0x07) != 0) + r |= RME_RX_2SHORT_2LONG; + + if (eth_mac_read_rmon(0x25) != 0) + r |= RME_TX_JAM_DROP; + if (eth_mac_read_rmon(0x26) != 0) + r |= RME_TX_FIFO_UNDER; + if (eth_mac_read_rmon(0x27) != 0) + r |= RME_TX_FIFO_OVER; + */ + return r; +} |