aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--firmware/usrp3/include/ethernet.h5
-rw-r--r--firmware/usrp3/lib/ethernet.c157
-rw-r--r--firmware/usrp3/x300/x300_defs.h1
-rw-r--r--firmware/usrp3/x300/x300_init.c34
-rw-r--r--firmware/usrp3/x300/x300_main.c4
-rw-r--r--host/lib/usrp/x300/x300_clock_ctrl.cpp7
-rw-r--r--host/lib/usrp/x300/x300_dac_ctrl.cpp16
-rw-r--r--host/lib/usrp/x300/x300_fw_common.h4
8 files changed, 127 insertions, 101 deletions
diff --git a/firmware/usrp3/include/ethernet.h b/firmware/usrp3/include/ethernet.h
index 52f14d05b..a6bacfcd0 100644
--- a/firmware/usrp3/include/ethernet.h
+++ b/firmware/usrp3/include/ethernet.h
@@ -31,7 +31,7 @@ typedef void (*ethernet_link_changed_callback_t)(int ethnum, int speed);
/*!
* \brief one time call to initialize ethernet
*/
-void xge_ethernet_init(const uint32_t eth);
+void ethernet_init(const uint32_t eth);
/*!
* \brief Return number of ethernet interfaces
@@ -44,8 +44,7 @@ void dump_mdio_regs(const uint8_t eth, uint32_t mdio_port);
/*!
* \brief Test status of SFP+ modules
*/
-void
-xge_poll_sfpp_status(const uint32_t eth);
+void poll_sfpp_status(const uint32_t eth);
//! get the link status of eth (true for link up)
bool ethernet_get_link_up(const uint32_t eth);
diff --git a/firmware/usrp3/lib/ethernet.c b/firmware/usrp3/lib/ethernet.c
index a15f56498..91efbfe1d 100644
--- a/firmware/usrp3/lib/ethernet.c
+++ b/firmware/usrp3/lib/ethernet.c
@@ -305,94 +305,111 @@ unknown:
return SFFP_TYPE_UNKNOWN;
}
-static void
-xge_mac_init(const uint32_t base)
+static void xge_mac_init(const uint32_t base)
{
- UHD_FW_TRACE(INFO, "Begining XGE MAC init sequence.");
- xge_regs->config = XGE_TX_ENABLE;
+ UHD_FW_TRACE(DEBUG, "Begining XGE MAC init sequence.");
+ xge_regs->config = XGE_TX_ENABLE;
}
// base is pointer to XGE MAC on Wishbone.
-static void
-xge_phy_init(const uint8_t eth, const uint32_t mdio_port)
+static void xge_phy_init(const uint8_t eth, const uint32_t mdio_port_arg)
{
- int x;
- // Read LASI Ctrl register to capture state.
- //y = xge_read_mdio(0x9002,XGE_MDIO_DEVICE_PMA,XGE_MDIO_ADDR_PHY_A);
- UHD_FW_TRACE(INFO, "Begining XGE PHY init sequence.");
- // Software reset
- x = read_mdio(eth, 0x0, XGE_MDIO_DEVICE_PMA,mdio_port);
- x = x | (1 << 15);
- write_mdio(eth, 0x0,XGE_MDIO_DEVICE_PMA,mdio_port,x);
- while(x&(1<<15))
- x = read_mdio(eth, 0x0,XGE_MDIO_DEVICE_PMA,mdio_port);
+ int x;
+ uint32_t mdio_port = eth==0 ? 1 : mdio_port_arg;
+ // Read LASI Ctrl register to capture state.
+ //y = xge_read_mdio(0x9002,XGE_MDIO_DEVICE_PMA,XGE_MDIO_ADDR_PHY_A);
+ UHD_FW_TRACE(DEBUG, "Begining XGE PHY init sequence.");
+ // Software reset
+ x = read_mdio(eth, 0x0, XGE_MDIO_DEVICE_PMA,mdio_port);
+ x = x | (1 << 15);
+ write_mdio(eth, 0x0,XGE_MDIO_DEVICE_PMA,mdio_port,x);
+ while(x&(1<<15)) {
+ x = read_mdio(eth, 0x0,XGE_MDIO_DEVICE_PMA,mdio_port);
+ }
}
-void
-xge_poll_sfpp_status(const uint32_t eth)
+void update_eth_state(const uint32_t eth)
{
- uint32_t x;
- // Has MODDET/MODAbS changed since we last looked?
- x = wb_peek32(SR_ADDR(RB0_BASE, (eth==0) ? RB_SFPP_STATUS0 : RB_SFPP_STATUS1 ));
-
- if (x & SFPP_STATUS_RXLOS_CHG)
- UHD_FW_TRACE_FSTR(INFO, "eth%1d RXLOS changed state: %d", eth, (x & SFPP_STATUS_RXLOS));
- if (x & SFPP_STATUS_TXFAULT_CHG)
- UHD_FW_TRACE_FSTR(INFO, "eth%1d TXFAULT changed state: %d", eth, ((x & SFPP_STATUS_TXFAULT) >> 1));
- if (x & SFPP_STATUS_MODABS_CHG)
- UHD_FW_TRACE_FSTR(INFO, "eth%1d MODABS changed state: %d", eth, ((x & SFPP_STATUS_MODABS) >> 2));
-
- if (x & (SFPP_STATUS_RXLOS_CHG|SFPP_STATUS_TXFAULT_CHG|SFPP_STATUS_MODABS_CHG))
- {
- if (( x & (SFPP_STATUS_RXLOS|SFPP_STATUS_TXFAULT|SFPP_STATUS_MODABS)) == 0)
- {
- if (wb_peek32(SR_ADDR(RB0_BASE, eth == 0 ? RB_ETH_TYPE0 : RB_ETH_TYPE1)) == 1)
- {
- xge_ethernet_init(eth);
- dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT);
- mdelay(100);
- dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT);
- mdelay(100);
- dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT);
- }
+ const bool old_link_up = links_up[eth];
+ const uint32_t status_reg_addr = (eth==0) ? RB_SFPP_STATUS0 : RB_SFPP_STATUS1;
+ const bool is_10g = (wb_peek32(SR_ADDR(RB0_BASE, eth == 0 ? RB_ETH_TYPE0 : RB_ETH_TYPE1)) == 1);
+
+ uint32_t sfpp_status = wb_peek32(SR_ADDR(RB0_BASE, status_reg_addr)) & 0xFFFF;
+ if ((sfpp_status & (SFPP_STATUS_RXLOS|SFPP_STATUS_TXFAULT|SFPP_STATUS_MODABS)) == 0) {
+ //SFP+ pin state changed. Reinitialize PHY and MAC
+ if (is_10g) {
+ xge_mac_init((eth==0) ? XGE0_BASE : XGE1_BASE);
+ xge_phy_init(eth ,MDIO_PORT);
+ } else {
+ //No-op for 1G
+ }
+
+ int8_t timeout = 100;
+ bool link_up = false;
+ do {
+ if (is_10g) {
+ link_up = ((read_mdio(eth, XGE_MDIO_STATUS1,XGE_MDIO_DEVICE_PMA,MDIO_PORT)) & (1 << 2)) != 0;
+ } else {
+ link_up = ((wb_peek32(SR_ADDR(RB0_BASE, status_reg_addr)) >> 16) & 0x1) != 0;
+ }
+ } while (!link_up && timeout-- > 0);
+
+ links_up[eth] = link_up;
}
- }
-
- if (x & SFPP_STATUS_MODABS_CHG) {
- // MODDET has changed state since last checked
- if (x & SFPP_STATUS_MODABS) {
- // MODDET is high, module currently removed.
- UHD_FW_TRACE_FSTR(INFO, "An SFP+ module has been removed from eth port %d.", eth);
- } else {
- // MODDET is low, module currently inserted.
- // Return status.
- UHD_FW_TRACE_FSTR(INFO, "A new SFP+ module has been inserted into eth port %d.", eth);
- xge_read_sfpp_type((eth==0) ? I2C0_BASE : I2C2_BASE,1);
+ else
+ {
+ links_up[eth] = false;
}
- }
- //update the link up status
- const bool old_link_up = links_up[eth];
- links_up[eth] = ((read_mdio(eth, XGE_MDIO_STATUS1,XGE_MDIO_DEVICE_PMA,MDIO_PORT)) & (1 << 2)) != 0;
- //The link became up, send a GARP so everyone knows our mac/ip association
if (!old_link_up && links_up[eth]) u3_net_stack_send_arp_request(eth, u3_net_stack_get_ip_addr(eth));
+ UHD_FW_TRACE_FSTR(INFO, "The link on eth port %u is %s", eth, links_up[eth]?"up":"down");
}
+void poll_sfpp_status(const uint32_t eth)
+{
+ uint32_t x;
+ // Has MODDET/MODAbS changed since we last looked?
+ x = wb_peek32(SR_ADDR(RB0_BASE, (eth==0) ? RB_SFPP_STATUS0 : RB_SFPP_STATUS1 ));
+
+ if (x & SFPP_STATUS_RXLOS_CHG)
+ UHD_FW_TRACE_FSTR(DEBUG, "eth%1d RXLOS changed state: %d", eth, (x & SFPP_STATUS_RXLOS));
+ if (x & SFPP_STATUS_TXFAULT_CHG)
+ UHD_FW_TRACE_FSTR(DEBUG, "eth%1d TXFAULT changed state: %d", eth, ((x & SFPP_STATUS_TXFAULT) >> 1));
+ if (x & SFPP_STATUS_MODABS_CHG)
+ UHD_FW_TRACE_FSTR(DEBUG, "eth%1d MODABS changed state: %d", eth, ((x & SFPP_STATUS_MODABS) >> 2));
-void
-xge_ethernet_init(const uint32_t eth)
+ //update the link up status
+ if ((x & SFPP_STATUS_RXLOS_CHG) || (x & SFPP_STATUS_TXFAULT_CHG) || (x & SFPP_STATUS_MODABS_CHG))
+ {
+ update_eth_state(eth);
+ }
+
+ if (x & SFPP_STATUS_MODABS_CHG) {
+ // MODDET has changed state since last checked
+ if (x & SFPP_STATUS_MODABS) {
+ // MODDET is high, module currently removed.
+ UHD_FW_TRACE_FSTR(INFO, "An SFP+ module has been removed from eth port %d.", eth);
+ } else {
+ // MODDET is low, module currently inserted.
+ // Return status.
+ UHD_FW_TRACE_FSTR(INFO, "A new SFP+ module has been inserted into eth port %d.", eth);
+ xge_read_sfpp_type((eth==0) ? I2C0_BASE : I2C2_BASE,1);
+ }
+ }
+}
+
+void ethernet_init(const uint32_t eth)
{
- xge_mac_init((eth==0) ? XGE0_BASE : XGE1_BASE);
- //xge_hard_phy_reset();
- xge_phy_init(eth ,MDIO_PORT);
#ifdef UHD_FW_TRACE_LEVEL
- uint32_t x = wb_peek32(SR_ADDR(RB0_BASE, (eth==0) ? RB_SFPP_STATUS0 : RB_SFPP_STATUS1 ));
- UHD_FW_TRACE_FSTR(INFO, "eth%1d SFP initial state: RXLOS: %d TXFAULT: %d MODABS: %d",
- eth,
- (x & SFPP_STATUS_RXLOS),
- ((x & SFPP_STATUS_TXFAULT) >> 1),
- ((x & SFPP_STATUS_MODABS) >> 2));
+ uint32_t x = wb_peek32(SR_ADDR(RB0_BASE, (eth==0) ? RB_SFPP_STATUS0 : RB_SFPP_STATUS1 ));
+ UHD_FW_TRACE_FSTR(DEBUG, "eth%1d SFP initial state: RXLOS: %d TXFAULT: %d MODABS: %d",
+ eth,
+ (x & SFPP_STATUS_RXLOS),
+ ((x & SFPP_STATUS_TXFAULT) >> 1),
+ ((x & SFPP_STATUS_MODABS) >> 2));
#endif
+ links_up[eth] = false;
+ update_eth_state(eth);
}
//
diff --git a/firmware/usrp3/x300/x300_defs.h b/firmware/usrp3/x300/x300_defs.h
index 65c5d5a23..c4011bd12 100644
--- a/firmware/usrp3/x300/x300_defs.h
+++ b/firmware/usrp3/x300/x300_defs.h
@@ -51,6 +51,7 @@ static const int RB_SPI_RDY = 1;
static const int RB_SPI_DATA = 2;
static const int RB_ETH_TYPE0 = 4;
static const int RB_ETH_TYPE1 = 5;
+static const int RB_FPGA_COMPAT = 6;
static const int RB_SFPP_STATUS0 = 8;
static const int RB_SFPP_STATUS1 = 9;
diff --git a/firmware/usrp3/x300/x300_init.c b/firmware/usrp3/x300/x300_init.c
index 480e68a14..ef97412a2 100644
--- a/firmware/usrp3/x300/x300_init.c
+++ b/firmware/usrp3/x300/x300_init.c
@@ -130,7 +130,11 @@ void x300_init(void)
//udp_uart_init(UART0_BASE, X300_GPSDO_UDP_PORT);
//now we can init the rest with prints
- UHD_FW_TRACE_FSTR(INFO, "[ZPU Init Begin -- CPU CLOCK is %d MHz]", (CPU_CLOCK/1000000));
+ UHD_FW_TRACE(INFO, "[ZPU Initializing]");
+ UHD_FW_TRACE_FSTR(INFO, "-- Firmware Compat Number: %u.%u", (int)X300_FW_COMPAT_MAJOR, (int)X300_FW_COMPAT_MINOR);
+ uint32_t fpga_compat = wb_peek32(SR_ADDR(SET0_BASE, RB_FPGA_COMPAT));
+ UHD_FW_TRACE_FSTR(INFO, "-- FPGA Compat Number: %u.%u", (fpga_compat>>16), (fpga_compat&0xFFFF));
+ UHD_FW_TRACE_FSTR(INFO, "-- Clock Frequency: %u MHz", (CPU_CLOCK/1000000));
//i2c rate init
wb_i2c_init(I2C0_BASE, CPU_CLOCK);
@@ -140,30 +144,26 @@ void x300_init(void)
//hold phy in reset
wb_poke32(SR_ADDR(SET0_BASE, SR_SW_RST), SW_RST_PHY);
- UHD_FW_TRACE_FSTR(INFO, "eth0 is %2dG", ((wb_peek32(SR_ADDR(RB0_BASE, RB_ETH_TYPE0))==1) ? 10 : 1));
- UHD_FW_TRACE_FSTR(INFO, "eth1 is %2dG", ((wb_peek32(SR_ADDR(RB0_BASE, RB_ETH_TYPE1))==1) ? 10 : 1));
-
//setup net stack and eth state machines
init_network();
//phy reset release
wb_poke32(SR_ADDR(SET0_BASE, SR_SW_RST), 0);
- // For eth interfaces, initialize the PHY's
- mdelay(100);
- if (wb_peek32(SR_ADDR(RB0_BASE, RB_ETH_TYPE0)) == 1) {
- xge_ethernet_init(0);
- }
- if (wb_peek32(SR_ADDR(RB0_BASE, RB_ETH_TYPE1)) == 1) {
- xge_ethernet_init(1);
- }
-
//print network summary
for (uint8_t e = 0; e < ethernet_ninterfaces(); e++)
{
- UHD_FW_TRACE_FSTR(INFO, " MAC%u: %s", (int)e, mac_addr_to_str(u3_net_stack_get_mac_addr(e)));
- UHD_FW_TRACE_FSTR(INFO, " IP%u: %s", (int)e, ip_addr_to_str(u3_net_stack_get_ip_addr(e)));
- UHD_FW_TRACE_FSTR(INFO, " SUBNET%u: %s", (int)e, ip_addr_to_str(u3_net_stack_get_subnet(e)));
- UHD_FW_TRACE_FSTR(INFO, " BCAST%u: %s", (int)e, ip_addr_to_str(u3_net_stack_get_bcast(e)));
+ uint32_t offset = SR_ADDR(RB0_BASE, ((e==1)?RB_ETH_TYPE1:RB_ETH_TYPE0));
+ UHD_FW_TRACE_FSTR(INFO, "Ethernet Port %u:", (int)e);
+ UHD_FW_TRACE_FSTR(INFO, "-- PHY: %s", ((wb_peek32(offset)==1) ? "10Gbps" : "1Gbps"));
+ UHD_FW_TRACE_FSTR(INFO, "-- MAC: %s", mac_addr_to_str(u3_net_stack_get_mac_addr(e)));
+ UHD_FW_TRACE_FSTR(INFO, "-- IP: %s", ip_addr_to_str(u3_net_stack_get_ip_addr(e)));
+ UHD_FW_TRACE_FSTR(INFO, "-- SUBNET: %s", ip_addr_to_str(u3_net_stack_get_subnet(e)));
+ UHD_FW_TRACE_FSTR(INFO, "-- BCAST: %s", ip_addr_to_str(u3_net_stack_get_bcast(e)));
}
+
+ // For eth interfaces, initialize the PHY's
+ mdelay(100);
+ ethernet_init(0);
+ ethernet_init(1);
}
diff --git a/firmware/usrp3/x300/x300_main.c b/firmware/usrp3/x300/x300_main.c
index b8c4fb41a..3b812a2c4 100644
--- a/firmware/usrp3/x300/x300_main.c
+++ b/firmware/usrp3/x300/x300_main.c
@@ -445,12 +445,12 @@ int main(void)
static const uint32_t tick_delta = CPU_CLOCK/1000;
if (ticks_passed > tick_delta)
{
+ poll_sfpp_status(0); // Every so often poll XGE Phy to look for SFP+ hotplug events.
+ poll_sfpp_status(1); // Every so often poll XGE Phy to look for SFP+ hotplug events.
handle_link_state(); //deal with router table update
handle_claim(); //deal with the host claim register
update_leds(); //run the link and activity leds
garp(); //send periodic garps
- xge_poll_sfpp_status(0); // Every so often poll XGE Phy to look for SFP+ hotplug events.
- xge_poll_sfpp_status(1); // Every so often poll XGE Phy to look for SFP+ hotplug events.
last_cronjob = wb_peek32(SR_ADDR(RB0_BASE, RB_COUNTER));
}
diff --git a/host/lib/usrp/x300/x300_clock_ctrl.cpp b/host/lib/usrp/x300/x300_clock_ctrl.cpp
index b59247d53..3aebfea68 100644
--- a/host/lib/usrp/x300/x300_clock_ctrl.cpp
+++ b/host/lib/usrp/x300/x300_clock_ctrl.cpp
@@ -287,6 +287,8 @@ void set_master_clock_rate(double clock_rate) {
this->write_regs(0);
_lmk04816_regs.CLKout0_1_DIV = vco_div;
_lmk04816_regs.CLKout0_ADLY_SEL = lmk04816_regs_t::CLKOUT0_ADLY_SEL_D_EV_X;
+ _lmk04816_regs.CLKout6_ADLY_SEL = lmk04816_regs_t::CLKOUT6_ADLY_SEL_D_BOTH;
+ _lmk04816_regs.CLKout7_ADLY_SEL = lmk04816_regs_t::CLKOUT7_ADLY_SEL_D_BOTH;
this->write_regs(0);
// Register 1
@@ -309,9 +311,12 @@ void set_master_clock_rate(double clock_rate) {
_lmk04816_regs.CLKout1_TYPE = lmk04816_regs_t::CLKOUT1_TYPE_P_DOWN; //CPRI feedback clock, use LVDS
_lmk04816_regs.CLKout2_TYPE = lmk04816_regs_t::CLKOUT2_TYPE_LVPECL_700MVPP; //DB_0_RX
_lmk04816_regs.CLKout3_TYPE = lmk04816_regs_t::CLKOUT3_TYPE_LVPECL_700MVPP; //DB_1_RX
- // Analog delay of 900ps to synchronize the radio clock with the source synchronous ADC clocks.
+ // Delay the FPGA_CLK by 900ps to ensure a safe ADC_SSCLK -> RADIO_CLK crossing.
+ // If the FPGA_CLK is delayed, we also need to delay the reference clocks going to the DAC
+ // because the data interface clock is generated from FPGA_CLK.
// This delay may need to vary due to temperature. Tested and verified at room temperature only.
_lmk04816_regs.CLKout0_1_ADLY = 0x10;
+ _lmk04816_regs.CLKout6_7_ADLY = _lmk04816_regs.CLKout0_1_ADLY;
// Register 7
_lmk04816_regs.CLKout4_TYPE = lmk04816_regs_t::CLKOUT4_TYPE_LVPECL_700MVPP; //DB_1_TX
diff --git a/host/lib/usrp/x300/x300_dac_ctrl.cpp b/host/lib/usrp/x300/x300_dac_ctrl.cpp
index d3bcb8644..bb41146b6 100644
--- a/host/lib/usrp/x300/x300_dac_ctrl.cpp
+++ b/host/lib/usrp/x300/x300_dac_ctrl.cpp
@@ -129,12 +129,16 @@ public:
_check_pll();
// Configure digital interface settings
- write_ad9146_reg(0x16, 0x02); // Skew DCI signal by 615ps to find stable data eye
- write_ad9146_reg(0x03, 0x00); // 2's comp, I first, byte wide interface
- //fpga wants I,Q in the sample word:
- //first transaction goes into low bits
- //second transaction goes into high bits
- //therefore, we want Q to go first (bit 6 == 1)
+ // Bypass DCI delay. We center the clock edge in the data
+ // valid window in the FPGA by phase shifting the DCI going
+ // to the DAC.
+ write_ad9146_reg(0x16, 0x04);
+ // 2's comp, I first, byte wide interface
+ write_ad9146_reg(0x03, 0x00);
+ // FPGA wants I,Q in the sample word:
+ // - First transaction goes into low bits
+ // - Second transaction goes into high bits
+ // therefore, we want Q to go first (bit 6 == 1)
write_ad9146_reg(0x03, (1 << 6)); //2s comp, i first, byte mode
// Configure interpolation filters
diff --git a/host/lib/usrp/x300/x300_fw_common.h b/host/lib/usrp/x300/x300_fw_common.h
index 42583f7f0..a526cabe5 100644
--- a/host/lib/usrp/x300/x300_fw_common.h
+++ b/host/lib/usrp/x300/x300_fw_common.h
@@ -29,9 +29,9 @@
extern "C" {
#endif
-#define X300_FW_COMPAT_MAJOR 3
+#define X300_FW_COMPAT_MAJOR 4
#define X300_FW_COMPAT_MINOR 0
-#define X300_FPGA_COMPAT_MAJOR 9
+#define X300_FPGA_COMPAT_MAJOR 10
//shared memory sections - in between the stack and the program space
#define X300_FW_SHMEM_BASE 0x6000