diff options
author | Ashish Chaudhari <ashish@ettus.com> | 2015-07-22 17:54:17 -0700 |
---|---|---|
committer | Ashish Chaudhari <ashish@ettus.com> | 2015-07-22 17:54:17 -0700 |
commit | f76f599be281d773736940d53aafc6d7e9d536ca (patch) | |
tree | 51bbbfb2d7995c6de7a50671b929a054760c2765 | |
parent | dfedaf1726cd6ed1dbfc1c9d8c40716a557b05ed (diff) | |
download | uhd-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.h | 2 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_impl.cpp | 78 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_impl.hpp | 3 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_regs.hpp | 17 |
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) |