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
|
//
// 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 <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:
/**************************************************************************
* 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 */
|