aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAshish Chaudhari <ashish@ettus.com>2015-07-22 17:54:17 -0700
committerAshish Chaudhari <ashish@ettus.com>2015-07-22 17:54:17 -0700
commitf76f599be281d773736940d53aafc6d7e9d536ca (patch)
tree51bbbfb2d7995c6de7a50671b929a054760c2765
parentdfedaf1726cd6ed1dbfc1c9d8c40716a557b05ed (diff)
downloaduhd-f76f599be281d773736940d53aafc6d7e9d536ca.tar.gz
uhd-f76f599be281d773736940d53aafc6d7e9d536ca.tar.bz2
uhd-f76f599be281d773736940d53aafc6d7e9d536ca.zip
x300: Added a comprehensive radio reset sequence
- Everytime the LMK is configured, we do the following: - Reset all LMK regs - Wait for LMK lock - Reset radio_clk PLL in FPGA - Wait for FPGA PLL to lock - Assert radio_rst which resets downstream radio logic - This address the intermittent self-cal failures due to uncalibrated IDELAY taps - Bumped FPGA compat to 12
-rw-r--r--host/lib/usrp/x300/x300_fw_common.h2
-rw-r--r--host/lib/usrp/x300/x300_impl.cpp78
-rw-r--r--host/lib/usrp/x300/x300_impl.hpp3
-rw-r--r--host/lib/usrp/x300/x300_regs.hpp17
4 files changed, 68 insertions, 32 deletions
diff --git a/host/lib/usrp/x300/x300_fw_common.h b/host/lib/usrp/x300/x300_fw_common.h
index 63dbd1d32..e137b916b 100644
--- a/host/lib/usrp/x300/x300_fw_common.h
+++ b/host/lib/usrp/x300/x300_fw_common.h
@@ -33,7 +33,7 @@ extern "C" {
#define X300_REVISION_MIN 2
#define X300_FW_COMPAT_MAJOR 4
#define X300_FW_COMPAT_MINOR 0
-#define X300_FPGA_COMPAT_MAJOR 11
+#define X300_FPGA_COMPAT_MAJOR 12
//shared memory sections - in between the stack and the program space
#define X300_FW_SHMEM_BASE 0x6000
diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp
index aa38c8463..ef6e41a83 100644
--- a/host/lib/usrp/x300/x300_impl.cpp
+++ b/host/lib/usrp/x300/x300_impl.cpp
@@ -787,8 +787,7 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)
////////////////////////////////////////////////////////////////////
_tree->create<std::string>(mb_path / "clock_source" / "value")
.set("internal")
- .subscribe(boost::bind(&x300_impl::update_clock_source, this, boost::ref(mb), _1))
- .subscribe(boost::bind(&x300_impl::reset_radios, this, boost::ref(mb)));
+ .subscribe(boost::bind(&x300_impl::update_clock_source, this, boost::ref(mb), _1));
static const std::vector<std::string> clock_source_options = boost::assign::list_of("internal")("external")("gpsdo");
_tree->create<std::vector<std::string> >(mb_path / "clock_source" / "options").set(clock_source_options);
@@ -1405,7 +1404,8 @@ void x300_impl::update_clock_source(mboard_members_t &mb, const std::string &sou
//Optimize for the case when the current source is internal and we are trying
//to set it to internal. This is the only case where we are guaranteed that
//the clock has not gone away so we can skip setting the MUX and reseting the LMK.
- if (not (mb.current_refclk_src == "internal" and source == "internal")) {
+ const bool reconfigure_clks = (mb.current_refclk_src != "internal") or (source != "internal");
+ if (reconfigure_clks) {
//Update the clock MUX on the motherboard to select the requested source
mb.clock_control_regs_clock_source = 0;
mb.clock_control_regs_tcxo_enb = 0;
@@ -1434,10 +1434,10 @@ void x300_impl::update_clock_source(mboard_members_t &mb, const std::string &sou
//The programming code in x300_clock_ctrl is not compatible with revs <= 4 and may
//lead to locking issues. So, disable the ref-locked check for older (unsupported) boards.
if (mb.hw_rev > 4) {
- if (not wait_for_ref_locked(mb.zpu_ctrl, timeout)) {
+ if (not wait_for_clk_locked(mb.zpu_ctrl, ZPU_RB_CLK_STATUS_LMK_LOCK, timeout)) {
//failed to lock on reference
if (mb.initialization_done) {
- throw uhd::runtime_error((boost::format("Reference Clock failed to lock to %s source.") % source).str());
+ throw uhd::runtime_error((boost::format("Reference Clock PLL failed to lock to %s source.") % source).str());
} else {
//TODO: Re-enable this warning when we figure out a reliable lock time
//UHD_MSG(warning) << "Reference clock failed to lock to " + source + " during device initialization. " <<
@@ -1446,6 +1446,41 @@ void x300_impl::update_clock_source(mboard_members_t &mb, const std::string &sou
}
}
+ if (reconfigure_clks) {
+ //Reset the radio clock PLL in the FPGA
+ mb.zpu_ctrl->poke32(SR_ADDR(SET0_BASE, ZPU_SR_SW_RST), ZPU_SR_SW_RST_RADIO_CLK_PLL);
+ mb.zpu_ctrl->poke32(SR_ADDR(SET0_BASE, ZPU_SR_SW_RST), 0);
+
+ //Wait for radio clock PLL to lock
+ if (not wait_for_clk_locked(mb.zpu_ctrl, ZPU_RB_CLK_STATUS_RADIO_CLK_LOCK, 0.01)) {
+ throw uhd::runtime_error((boost::format("Reference Clock PLL in FPGA failed to lock to %s source.") % source).str());
+ }
+
+ //Reset the logic in the radio clock domain
+ mb.zpu_ctrl->poke32(SR_ADDR(SET0_BASE, ZPU_SR_SW_RST), ZPU_SR_SW_RST_RADIO_RST);
+ mb.zpu_ctrl->poke32(SR_ADDR(SET0_BASE, ZPU_SR_SW_RST), 0);
+
+ //Wait for the ADC IDELAYCTRL to be ready
+ if (not wait_for_clk_locked(mb.zpu_ctrl, ZPU_RB_CLK_STATUS_IDELAYCTRL_LOCK, 0.01)) {
+ throw uhd::runtime_error((boost::format("ADC Calibration Clock in FPGA failed to lock to %s source.") % source).str());
+ }
+
+ // Reset ADCs and DACs
+ for (size_t r = 0; r < mboard_members_t::NUM_RADIOS; r++) {
+ radio_perifs_t &perif = mb.radio_perifs[r];
+ if (perif.misc_outs && r==0) { //ADC/DAC reset lines only exist in Radio0
+ perif.misc_outs->set(radio_misc_outs_reg::ADC_RESET, 1);
+ perif.misc_outs->set(radio_misc_outs_reg::DAC_RESET_N, 0);
+ perif.misc_outs->flush();
+ perif.misc_outs->set(radio_misc_outs_reg::ADC_RESET, 0);
+ perif.misc_outs->set(radio_misc_outs_reg::DAC_RESET_N, 1);
+ perif.misc_outs->flush();
+ }
+ if (perif.adc) perif.adc->reset();
+ if (perif.dac) perif.dac->reset();
+ }
+ }
+
//Update cache value
mb.current_refclk_src = source;
}
@@ -1472,24 +1507,29 @@ void x300_impl::update_time_source(mboard_members_t &mb, const std::string &sour
}
}
-bool x300_impl::wait_for_ref_locked(wb_iface::sptr ctrl, double timeout)
+static bool get_clk_locked(wb_iface::sptr ctrl, boost::uint32_t which)
+{
+ return (ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_CLK_STATUS)) & which) != 0;
+}
+
+bool x300_impl::wait_for_clk_locked(wb_iface::sptr ctrl, boost::uint32_t which, double timeout)
{
boost::system_time timeout_time = boost::get_system_time() + boost::posix_time::milliseconds(timeout * 1000.0);
- do
- {
- if (get_ref_locked(ctrl).to_bool())
+ do {
+ if (get_clk_locked(ctrl, which))
return true;
boost::this_thread::sleep(boost::posix_time::milliseconds(1));
} while (boost::get_system_time() < timeout_time);
//Check one last time
- return get_ref_locked(ctrl).to_bool();
+ return get_clk_locked(ctrl, which);
}
sensor_value_t x300_impl::get_ref_locked(wb_iface::sptr ctrl)
{
- boost::uint32_t clk_status = ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_CLK_STATUS));
- const bool lock = ((clk_status & ZPU_RB_CLK_STATUS_LMK_LOCK) != 0);
+ const bool lock = get_clk_locked(ctrl, ZPU_RB_CLK_STATUS_LMK_LOCK) &&
+ get_clk_locked(ctrl, ZPU_RB_CLK_STATUS_RADIO_CLK_LOCK) &&
+ get_clk_locked(ctrl, ZPU_RB_CLK_STATUS_IDELAYCTRL_LOCK);
return sensor_value_t("Ref", lock, "locked", "unlocked");
}
@@ -1512,16 +1552,6 @@ bool x300_impl::is_pps_present(wb_iface::sptr ctrl)
* reset and synchronization logic
**********************************************************************/
-void x300_impl::reset_radios(mboard_members_t &mb)
-{
- // Reset ADCs and DACs
- BOOST_FOREACH (radio_perifs_t& perif, mb.radio_perifs)
- {
- perif.adc->reset();
- perif.dac->reset();
- }
-}
-
void x300_impl::synchronize_dacs(const std::vector<radio_perifs_t*>& radios)
{
if (radios.size() < 2) return; //Nothing to synchronize
@@ -1999,7 +2029,7 @@ double x300_impl::self_cal_adc_xfer_delay(mboard_members_t& mb, bool apply_delay
for (size_t i = 0; i < NUM_DELAY_STEPS; i++) {
//Delay the ADC clock (will set both Ch0 and Ch1 delays)
double delay = mb.clock->set_clock_delay(X300_CLOCK_WHICH_ADC0, delay_incr*i + delay_start);
- wait_for_ref_locked(mb.zpu_ctrl, 0.1);
+ wait_for_clk_locked(mb.zpu_ctrl, ZPU_RB_CLK_STATUS_LMK_LOCK, 0.1);
boost::uint32_t err_code = 0;
for (size_t r = 0; r < mboard_members_t::NUM_RADIOS; r++) {
@@ -2091,7 +2121,7 @@ double x300_impl::self_cal_adc_xfer_delay(mboard_members_t& mb, bool apply_delay
UHD_MSG(status) << "Validating..." << std::flush;
//Apply delay
win_center = mb.clock->set_clock_delay(X300_CLOCK_WHICH_ADC0, win_center); //Sets ADC0 and ADC1
- wait_for_ref_locked(mb.zpu_ctrl, 0.1);
+ wait_for_clk_locked(mb.zpu_ctrl, ZPU_RB_CLK_STATUS_LMK_LOCK, 0.1);
//Validate
self_test_adcs(mb, 2000);
} else {
diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp
index ad1c802ee..20cd4d754 100644
--- a/host/lib/usrp/x300/x300_impl.hpp
+++ b/host/lib/usrp/x300/x300_impl.hpp
@@ -390,10 +390,9 @@ private:
void set_time_source_out(mboard_members_t&, const bool);
void update_clock_source(mboard_members_t&, const std::string &);
void update_time_source(mboard_members_t&, const std::string &);
- void reset_radios(mboard_members_t&);
uhd::sensor_value_t get_ref_locked(uhd::wb_iface::sptr);
- bool wait_for_ref_locked(uhd::wb_iface::sptr, double timeout = 0.0);
+ bool wait_for_clk_locked(uhd::wb_iface::sptr, boost::uint32_t which, double timeout);
bool is_pps_present(uhd::wb_iface::sptr);
void set_db_eeprom(uhd::i2c_iface::sptr i2c, const size_t, const uhd::usrp::dboard_eeprom_t &);
diff --git a/host/lib/usrp/x300/x300_regs.hpp b/host/lib/usrp/x300/x300_regs.hpp
index f41afeb23..fb3a42172 100644
--- a/host/lib/usrp/x300/x300_regs.hpp
+++ b/host/lib/usrp/x300/x300_regs.hpp
@@ -63,13 +63,18 @@ localparam BL_DATA = 1;
#define SR_ADDR(base, offset) ((base) + (offset)*4)
localparam ZPU_SR_LEDS = 00;
-localparam ZPU_SR_PHY_RST = 01;
+localparam ZPU_SR_SW_RST = 01;
localparam ZPU_SR_CLOCK_CTRL = 02;
localparam ZPU_SR_XB_LOCAL = 03;
localparam ZPU_SR_SPI = 32;
localparam ZPU_SR_ETHINT0 = 40;
localparam ZPU_SR_ETHINT1 = 56;
+//reset bits
+#define ZPU_SR_SW_RST_ETH_PHY (1<<0)
+#define ZPU_SR_SW_RST_RADIO_RST (1<<1)
+#define ZPU_SR_SW_RST_RADIO_CLK_PLL (1<<2)
+
//clock controls
#define ZPU_SR_CLOCK_CTRL_CLK_SRC_EXTERNAL 0x00
#define ZPU_SR_CLOCK_CTRL_CLK_SRC_INTERNAL 0x02
@@ -85,10 +90,12 @@ localparam ZPU_RB_ETH_TYPE0 = 4;
localparam ZPU_RB_ETH_TYPE1 = 5;
//clock status
-#define ZPU_RB_CLK_STATUS_LMK_STATUS (0x3 << 0)
-#define ZPU_RB_CLK_STATUS_LMK_LOCK (0x1 << 2)
-#define ZPU_RB_CLK_STATUS_LMK_HOLDOVER (0x1 << 3)
-#define ZPU_RB_CLK_STATUS_PPS_DETECT (0x1 << 4)
+#define ZPU_RB_CLK_STATUS_LMK_STATUS (0x3 << 0)
+#define ZPU_RB_CLK_STATUS_LMK_LOCK (0x1 << 2)
+#define ZPU_RB_CLK_STATUS_LMK_HOLDOVER (0x1 << 3)
+#define ZPU_RB_CLK_STATUS_PPS_DETECT (0x1 << 4)
+#define ZPU_RB_CLK_STATUS_RADIO_CLK_LOCK (0x1 << 5)
+#define ZPU_RB_CLK_STATUS_IDELAYCTRL_LOCK (0x1 << 6)
//spi slaves on radio
#define DB_DAC_SEN (1 << 7)