Line data Source code
1 : /**
2 : * @file FIBIONode.cpp
3 : *
4 : * This is part of the DUNE DAQ Software Suite, copyright 2020.
5 : * Licensing/copyright details are in the COPYING file that you should have
6 : * received with this code.
7 : */
8 :
9 : #include "timing/FIBIONode.hpp"
10 :
11 : #include <map>
12 : #include <string>
13 : #include <utility>
14 : #include <vector>
15 :
16 : namespace dunedaq {
17 : namespace timing {
18 :
19 0 : UHAL_REGISTER_DERIVED_NODE(FIBIONode)
20 :
21 : //-----------------------------------------------------------------------------
22 0 : FIBIONode::FIBIONode(const uhal::Node& aNode) :
23 0 : SFPMuxIONode(aNode, "i2c", "i2c", "SI5345", {"PLL", "BKP DATA"}, {"i2c_sfp0", "i2c_sfp1", "i2c_sfp2", "i2c_sfp3", "i2c_sfp4", "i2c_sfp5", "i2c_sfp6", "i2c_sfp7"}) {
24 0 : }
25 : //-----------------------------------------------------------------------------
26 :
27 :
28 : //-----------------------------------------------------------------------------
29 0 : FIBIONode::~FIBIONode() {
30 0 : }
31 : //-----------------------------------------------------------------------------
32 :
33 : //-----------------------------------------------------------------------------
34 : std::string
35 0 : FIBIONode::get_uid_address_parameter_name() const
36 : {
37 0 : return "UID_PROM";
38 : }
39 : //-----------------------------------------------------------------------------
40 :
41 : //-----------------------------------------------------------------------------
42 : std::string
43 0 : FIBIONode::get_status(bool print_out) const {
44 0 : std::stringstream status;
45 0 : auto subnodes = read_sub_nodes(getNode("csr.stat"));
46 :
47 0 : uint32_t sfp_los_flags = read_sfp_los_flags(); // NOLINT(build/unsigned)
48 0 : uint32_t sfp_fault_flags = read_sfp_fault_flags(); // NOLINT(build/unsigned)
49 :
50 0 : std::vector<std::pair<std::string, std::string>> sfps_summary;
51 0 : sfps_summary.push_back(std::make_pair("SFP LOS flags", format_reg_value(sfp_los_flags, 16)));
52 0 : sfps_summary.push_back(std::make_pair("SFP fault flags", format_reg_value(sfp_fault_flags, 16)));
53 :
54 0 : status << format_reg_table(subnodes, "FIB IO state") << std::endl;
55 0 : status << format_reg_table(sfps_summary, "FIB SFPs state");
56 :
57 0 : if (print_out)
58 0 : TLOG() << status.str();
59 :
60 0 : return status.str();
61 0 : }
62 : //-----------------------------------------------------------------------------
63 :
64 :
65 : //-----------------------------------------------------------------------------
66 : void
67 0 : FIBIONode::reset(const std::string& clock_config_file) const {
68 :
69 : // Soft reset
70 0 : write_soft_reset_register();
71 :
72 0 : millisleep(1000);
73 :
74 : // Reset I2C
75 0 : getNode("csr.ctrl.rstb_i2c").write(0x1);
76 0 : getNode("csr.ctrl.rstb_i2c").write(0x0);
77 :
78 0 : getNode("csr.ctrl.rst").write(0x1);
79 0 : getNode("csr.ctrl.rst").write(0x0);
80 :
81 0 : getClient().dispatch();
82 :
83 0 : const CarrierType carrier_type = convert_value_to_carrier_type(read_carrier_type());
84 :
85 0 : if (carrier_type == kCarrierEnclustraA35) {
86 : // enclustra i2c switch stuff
87 0 : try {
88 0 : getNode<I2CMasterNode>(m_uid_i2c_bus).get_slave("AX3_Switch").write_i2c(0x01, 0x7f);
89 0 : } catch (const std::exception& e) {
90 0 : ers::warning(EnclustraSwitchFailure(ERS_HERE, e));
91 0 : }
92 : }
93 :
94 : // Configure I2C IO expanders
95 0 : auto ic_10 = get_i2c_device<I2CExpanderSlave>(m_uid_i2c_bus, "Expander1");
96 0 : auto ic_23 = get_i2c_device<I2CExpanderSlave>(m_uid_i2c_bus, "Expander2");
97 :
98 : // Bank 0
99 0 : ic_10->set_inversion(0, 0x00);
100 :
101 : // all out, sfp tx disable
102 0 : ic_10->set_io(0, 0x00);
103 : // sfp laser on by default
104 0 : ic_10->set_outputs(0, 0x00);
105 :
106 : // Bank 1
107 0 : ic_10->set_inversion(1, 0x00);
108 : // all inputs, sfp fault
109 0 : ic_10->set_io(1, 0xff);
110 :
111 : // Bank 0
112 0 : ic_23->set_inversion(0, 0x00);
113 : // pin 0 - out: pll rst, pins 1-4 pll and cdr flags
114 0 : ic_23->set_io(0, 0xfe);
115 0 : ic_23->set_outputs(0, 0x01);
116 :
117 : // Bank 1
118 0 : ic_23->set_inversion(1, 0x00);
119 : // all inputs, sfp los
120 0 : ic_23->set_io(1, 0xff);
121 :
122 : // reset pll via I2C IO expanders
123 0 : reset_pll();
124 :
125 : // Upload config file to PLL
126 0 : configure_pll(clock_config_file);
127 :
128 : //getNode("csr.ctrl.inmux").write(0);
129 : //getClient().dispatch();
130 :
131 : // To be removed from firmware address maps also
132 : // getNode("csr.ctrl.rst_lock_mon").write(0x1);
133 : // getNode("csr.ctrl.rst_lock_mon").write(0x0);
134 : // getClient().dispatch();
135 :
136 0 : TLOG() << "Reset done";
137 0 : }
138 : //-----------------------------------------------------------------------------
139 : //-----------------------------------------------------------------------------
140 : void
141 0 : FIBIONode::switch_sfp_mux_channel(uint32_t mux_channel) const { // NOLINT(build/unsigned)
142 0 : validate_sfp_id(mux_channel);
143 0 : getNode("csr.ctrl.inmux").write(mux_channel);
144 0 : getClient().dispatch();
145 0 : TLOG_DEBUG(0) << "SFP input mux set to " << read_active_sfp_mux_channel();
146 0 : }
147 : //-----------------------------------------------------------------------------
148 :
149 :
150 : //-----------------------------------------------------------------------------
151 : uint32_t // NOLINT(build/unsigned)
152 0 : FIBIONode::read_active_sfp_mux_channel() const {
153 0 : auto active_sfp_mux_channel = getNode("csr.ctrl.inmux").read();
154 0 : getClient().dispatch();
155 0 : return active_sfp_mux_channel.value();
156 0 : }
157 : //-----------------------------------------------------------------------------
158 :
159 :
160 : //-----------------------------------------------------------------------------
161 : std::string
162 0 : FIBIONode::get_sfp_status(uint32_t sfp_id, bool print_out) const { // NOLINT(build/unsigned)
163 0 : std::stringstream status;
164 :
165 0 : validate_sfp_id(sfp_id);
166 :
167 0 : std::string sfp_i2c_bus = "i2c_sfp" + std::to_string(sfp_id);
168 0 : auto sfp = get_i2c_device<I2CSFPSlave>(sfp_i2c_bus, "SFP_EEProm");
169 0 : status << "Fanout SFP " << sfp_id << ":" << std::endl;
170 0 : status << sfp->get_status();
171 :
172 0 : if (print_out)
173 0 : TLOG() << status.str();
174 :
175 0 : return status.str();
176 0 : }
177 : //-----------------------------------------------------------------------------
178 :
179 :
180 : //-----------------------------------------------------------------------------
181 : void
182 0 : FIBIONode::switch_sfp_soft_tx_control_bit(uint32_t sfp_id, bool turn_on) const { // NOLINT(build/unsigned)
183 0 : validate_sfp_id(sfp_id);
184 :
185 : // on this board the 8 downstream sfps have their own i2c bus
186 0 : std::string sfp_i2c_bus = "i2c_sfp" + std::to_string(sfp_id);
187 0 : auto sfp = get_i2c_device<I2CSFPSlave>(sfp_i2c_bus, "SFP_EEProm");
188 0 : sfp->switch_soft_tx_control_bit(turn_on);
189 0 : }
190 : //-----------------------------------------------------------------------------
191 :
192 :
193 : //-----------------------------------------------------------------------------
194 : void
195 0 : FIBIONode::reset_pll() const {
196 0 : auto ic_23 = get_i2c_device<I2CExpanderSlave>(m_uid_i2c_bus, "Expander2");
197 0 : ic_23->set_outputs(0, 0x00);
198 0 : ic_23->set_outputs(0, 0x01);
199 0 : }
200 : //-----------------------------------------------------------------------------
201 :
202 : //-----------------------------------------------------------------------------
203 : uint8_t // NOLINT(build/unsigned)
204 0 : FIBIONode::read_sfp_los_flags() const {
205 0 : auto ic_23 = get_i2c_device<I2CExpanderSlave>(m_uid_i2c_bus, "Expander2");
206 :
207 0 : uint8_t sfp_los_flags = ic_23->read_inputs(0x01); // NOLINT(build/unsigned)
208 0 : return sfp_los_flags;
209 0 : }
210 : //-----------------------------------------------------------------------------
211 :
212 :
213 : //-----------------------------------------------------------------------------
214 : uint8_t // NOLINT(build/unsigned)
215 0 : FIBIONode::read_sfp_fault_flags() const {
216 0 : auto ic_10 = get_i2c_device<I2CExpanderSlave>(m_uid_i2c_bus, "Expander1");
217 :
218 0 : uint8_t sfp_fault_flags = ic_10->read_inputs(0x01); // NOLINT(build/unsigned)
219 0 : return sfp_fault_flags;
220 0 : }
221 : //-----------------------------------------------------------------------------
222 :
223 : //-----------------------------------------------------------------------------
224 : uint8_t // NOLINT(build/unsigned)
225 0 : FIBIONode::read_sfp_los_flag(uint32_t sfp_id) const { // NOLINT(build/unsigned)
226 0 : return read_sfp_los_flags() & (1UL << sfp_id);
227 : }
228 : //-----------------------------------------------------------------------------
229 :
230 :
231 : //-----------------------------------------------------------------------------
232 : uint8_t // NOLINT(build/unsigned)
233 0 : FIBIONode::read_sfp_fault_flag(uint32_t sfp_id) const { // NOLINT(build/unsigned)
234 0 : return read_sfp_fault_flags() & (1UL << sfp_id);
235 : }
236 : //-----------------------------------------------------------------------------
237 :
238 :
239 : //-----------------------------------------------------------------------------
240 : void
241 0 : FIBIONode::switch_sfp_tx(uint32_t sfp_id, bool turn_on) const { // NOLINT(build/unsigned)
242 0 : validate_sfp_id(sfp_id);
243 :
244 0 : auto ic_10 = get_i2c_device<I2CExpanderSlave>(m_uid_i2c_bus, "Expander1");
245 0 : uint8_t current_sfp_tx_control_flags = ic_10->read_outputs_config(0); // NOLINT(build/unsigned)
246 :
247 0 : uint8_t new_sfp_tx_control_flags; // NOLINT(build/unsigned)
248 0 : if (turn_on)
249 : {
250 0 : new_sfp_tx_control_flags = current_sfp_tx_control_flags & ~(1UL << sfp_id);
251 : }
252 : else
253 : {
254 0 : new_sfp_tx_control_flags = current_sfp_tx_control_flags | (1UL << sfp_id);
255 : }
256 :
257 0 : ic_10->set_outputs(0, new_sfp_tx_control_flags);
258 0 : }
259 : //-----------------------------------------------------------------------------
260 :
261 : //-----------------------------------------------------------------------------
262 : bool
263 0 : FIBIONode::clocks_ok() const
264 : {
265 0 : std::stringstream status;
266 :
267 0 : auto states = read_sub_nodes(getNode("csr.stat"));
268 0 : bool pll_ok = states.find("pll_ok")->second.value();
269 0 : bool mmcm_ok = states.find("mmcm_ok")->second.value();
270 :
271 0 : TLOG_DEBUG(5) << "pll ok: " << pll_ok << ", mmcm ok: " << mmcm_ok;
272 :
273 0 : return pll_ok && mmcm_ok;
274 0 : }
275 : //-----------------------------------------------------------------------------
276 :
277 : //-----------------------------------------------------------------------------
278 : void
279 0 : FIBIONode::validate_sfp_id(uint32_t sfp_id) const { // NOLINT(build/unsigned)
280 : // on this board we have 8 downstream SFPs
281 0 : if (sfp_id > 7) {
282 0 : throw InvalidSFPId(ERS_HERE, format_reg_value(sfp_id));
283 : }
284 0 : }
285 : //-----------------------------------------------------------------------------
286 :
287 : //-----------------------------------------------------------------------------
288 : //void
289 : //FIBIONode::get_info(timinghardwareinfo::TimingFIBMonitorData& mon_data) const
290 : //{
291 :
292 : // auto stat_subnodes = read_sub_nodes(getNode("csr.stat"));
293 : // auto ctrl_subnodes = read_sub_nodes(getNode("csr.ctrl"));
294 :
295 : // mon_data.mmcm_ok = stat_subnodes.at("mmcm_ok").value();
296 : // mon_data.mmcm_sticky = stat_subnodes.at("mmcm_sticky").value();
297 :
298 : // mon_data.pll_ok = stat_subnodes.at("pll_ok").value();
299 : // mon_data.pll_sticky = stat_subnodes.at("pll_sticky").value();
300 :
301 : // mon_data.active_sfp_mux = ctrl_subnodes.at("inmux").value();
302 :
303 : // //mon_data.sfp_los_flags = read_sfp_los_flags();
304 : // //mon_data.sfp_fault_flags = read_sfp_fault_flags();
305 : // }
306 : //-----------------------------------------------------------------------------
307 :
308 : //-----------------------------------------------------------------------------
309 : // void
310 : // FIBIONode::get_info(opmonlib::InfoCollector& ci, int level) const
311 : // {
312 :
313 : // if (level >= 2) {
314 : // timinghardwareinfo::TimingPLLMonitorData pll_mon_data;
315 : // get_pll()->get_info(pll_mon_data);
316 : // ci.add(pll_mon_data);
317 :
318 : // for (uint i=0; i < 8; ++i)
319 : // {
320 : // opmonlib::InfoCollector sfp_ic;
321 :
322 : // std::string sfp_i2c_bus = "i2c_sfp" + std::to_string(i);
323 : // auto sfp = get_i2c_device<I2CSFPSlave>(sfp_i2c_bus, "SFP_EEProm");
324 :
325 : // try
326 : // {
327 : // sfp->get_info(sfp_ic, level);
328 : // }
329 : // catch (timing::SFPUnreachable& e)
330 : // {
331 : // // It is valid that an SFP may not be installed, currently no good way of knowing whether they it should be
332 : // TLOG_DEBUG(2) << "Failed to communicate with SFP " << i << " on I2C switch channel " << (1UL << i) << " on i2c bus" << m_sfp_i2c_buses.at(0);
333 : // continue;
334 : // }
335 : // ci.add("sfp_"+std::to_string(i),sfp_ic);
336 : // }
337 : // }
338 : // if (level >= 1) {
339 : // timinghardwareinfo::TimingFIBMonitorData mon_data;
340 : // this->get_info(mon_data);
341 : // ci.add(mon_data);
342 : // }
343 : // }
344 : //-----------------------------------------------------------------------------
345 : } // namespace timing
346 : } // namespace dunedaq
|