1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
|
//
// Copyright 2019 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
#ifndef INCLUDED_LIBUHD_X300_MB_CONTROLLER_HPP
#define INCLUDED_LIBUHD_X300_MB_CONTROLLER_HPP
#include "x300_clock_ctrl.hpp"
#include "x300_device_args.hpp"
#include "x300_radio_mbc_iface.hpp"
#include "x300_regs.hpp"
#include <uhd/rfnoc/mb_controller.hpp>
#include <uhd/types/sensors.hpp>
#include <uhd/types/wb_iface.hpp>
#include <uhd/usrp/gps_ctrl.hpp>
#include <uhdlib/features/discoverable_feature_registry.hpp>
#include <unordered_set>
namespace uhd { namespace rfnoc {
/*! X300-Specific version of the mb_controller
*
* Reminder: There is one of these per motherboard.
*
* The X300 motherboard controller is responsible for:
* - Controlling the timekeeper
* - Controlling all time- and clock-related settings
* - Initialize and hold the GPS control
*/
class x300_mb_controller : public mb_controller,
public ::uhd::features::discoverable_feature_registry
{
public:
/**************************************************************************
* Structors
*************************************************************************/
x300_mb_controller(const size_t hw_rev,
const std::string product_name,
uhd::i2c_iface::sptr zpu_i2c,
uhd::wb_iface::sptr zpu_ctrl,
x300_clock_ctrl::sptr clock_ctrl,
uhd::usrp::mboard_eeprom_t mb_eeprom,
uhd::usrp::x300::x300_device_args_t args);
~x300_mb_controller() override;
/**************************************************************************
* X300-Specific APIs
*************************************************************************/
//! Return reference to the ZPU-owned I2C controller
uhd::i2c_iface::sptr get_zpu_i2c()
{
return _zpu_i2c;
}
//! Reference to the ZPU peek/poke interface
uhd::wb_iface::sptr get_zpu_ctrl()
{
return _zpu_ctrl;
}
//! Return reference to LMK clock controller
x300_clock_ctrl::sptr get_clock_ctrl()
{
return _clock_ctrl;
}
void register_reset_codec_cb(std::function<void(void)>&& reset_cb)
{
_reset_cbs.push_back(std::move(reset_cb));
}
void set_initialization_done()
{
_initialization_done = true;
}
void register_radio(uhd::usrp::x300::x300_radio_mbc_iface* radio)
{
_radio_refs.push_back(radio);
}
/**************************************************************************
* Timekeeper API
*************************************************************************/
//! X300-specific version of the timekeeper controls
//
// The X300 controls timekeepers via the ZPU
class x300_timekeeper : public mb_controller::timekeeper
{
public:
x300_timekeeper(
const size_t tk_idx, uhd::wb_iface::sptr zpu_ctrl, const double tick_rate)
: _tk_idx(tk_idx), _zpu_ctrl(zpu_ctrl)
{
set_tick_rate(tick_rate);
}
uint64_t get_ticks_now() override;
uint64_t get_ticks_last_pps() override;
void set_ticks_now(const uint64_t ticks) override;
void set_ticks_next_pps(const uint64_t ticks) override;
void set_period(const uint64_t period_ns) override;
private:
uint32_t get_tk_addr(const uint32_t tk_addr);
const size_t _tk_idx;
uhd::wb_iface::sptr _zpu_ctrl;
}; /* x300_timekeeper */
/**************************************************************************
* Motherboard Control API (see mb_controller.hpp)
*************************************************************************/
void init() override;
std::string get_mboard_name() const override;
void set_time_source(const std::string& source) override;
std::string get_time_source() const override;
std::vector<std::string> get_time_sources() const override;
void set_clock_source(const std::string& source) override;
std::string get_clock_source() const override;
std::vector<std::string> get_clock_sources() const override;
void set_sync_source(
const std::string& clock_source, const std::string& time_source) override;
void set_sync_source(const device_addr_t& sync_source) override;
device_addr_t get_sync_source() const override;
std::vector<device_addr_t> get_sync_sources() override;
void set_clock_source_out(const bool enb) override;
void set_time_source_out(const bool enb) override;
sensor_value_t get_sensor(const std::string& name) override;
std::vector<std::string> get_sensor_names() override;
uhd::usrp::mboard_eeprom_t get_eeprom() override;
bool synchronize(std::vector<mb_controller::sptr>& mb_controllers,
const uhd::time_spec_t& time_spec = uhd::time_spec_t(0.0),
const bool quiet = false) override;
std::vector<std::string> get_gpio_banks() const override;
std::vector<std::string> get_gpio_srcs(const std::string&) const override;
std::vector<std::string> get_gpio_src(const std::string&) override;
void set_gpio_src(const std::string&, const std::vector<std::string>&) override;
private:
//! Return a string X300::MB_CTRL#N
std::string get_unique_id();
//! Init GPS
void init_gps();
//! Reset all registered DACs and ADCs
void reset_codecs();
//! Wait until reference clock locks, or a timeout occurs
//
// \returns lock status
bool wait_for_clk_locked(uint32_t which, double timeout);
//! Returns true if a PPS signal is detected
bool is_pps_present();
//! Return LMK lock status
bool get_ref_locked();
/*! Calibrate the ADC transfer delay
*
* This will try various clock delay settings to the ADC, and pick the one
* with the best BER performance.
*/
void self_cal_adc_xfer_delay(const bool apply_delay);
void extended_adc_test(double duration_s);
/**************************************************************************
* Attributes
*************************************************************************/
//! Hardware revision
const size_t _hw_rev;
//! Product name (X310, X300)
const std::string _product_name;
//! Reference to the ZPU-owned I2C controller
uhd::i2c_iface::sptr _zpu_i2c;
//! Reference to the ZPU peek/poke interface
uhd::wb_iface::sptr _zpu_ctrl;
//! Reference to LMK clock controller
x300_clock_ctrl::sptr _clock_ctrl;
//! State of the MB EEPROM
uhd::usrp::mboard_eeprom_t _mb_eeprom;
//! Copy of the device args
uhd::usrp::x300::x300_device_args_t _args;
//! Reference to clock control register
uhd::usrp::x300::fw_regmap_t::sptr _fw_regmap;
//! Reference to GPS control
uhd::gps_ctrl::sptr _gps;
//! Reference to all callbacks to reset the ADCs/DACs
std::vector<std::function<void(void)>> _reset_cbs;
//! Current clock source (external, internal, gpsdo)
std::string _current_refclk_src;
//! Current time source (external, internal, gpsdo)
std::string _current_time_src;
//! Reference to radios on this motherboard
std::vector<uhd::usrp::x300::x300_radio_mbc_iface*> _radio_refs;
//! List of available sensors
std::unordered_set<std::string> _sensors{"ref_locked"};
//! Flag to tell us if initialization is complete. Some functions behave
// differently after initialization.
bool _initialization_done = false;
};
}} // namespace uhd::rfnoc
#endif /* INCLUDED_LIBUHD_X300_MB_CONTROLLER_HPP */
|