Line data Source code
1 : /**
2 : * @file PC059IONode.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/PC059IONode.hpp"
10 :
11 : #include "logging/Logging.hpp"
12 :
13 : #include <string>
14 :
15 : namespace dunedaq {
16 : namespace timing {
17 :
18 0 : UHAL_REGISTER_DERIVED_NODE(PC059IONode)
19 :
20 : //-----------------------------------------------------------------------------
21 0 : PC059IONode::PC059IONode(const uhal::Node& node)
22 0 : : SFPMuxIONode(node, "i2c", "i2c", "SI5345", { "PLL", "CDR" }, { "usfp_i2c", "i2c" })
23 0 : {}
24 : //-----------------------------------------------------------------------------
25 :
26 : //-----------------------------------------------------------------------------
27 0 : PC059IONode::~PC059IONode() {}
28 : //-----------------------------------------------------------------------------
29 :
30 : //-----------------------------------------------------------------------------
31 : std::string
32 0 : PC059IONode::get_uid_address_parameter_name() const
33 : {
34 0 : return "FMC_UID_PROM";
35 : }
36 : //-----------------------------------------------------------------------------
37 :
38 : //-----------------------------------------------------------------------------
39 : std::string
40 0 : PC059IONode::get_status(bool print_out) const
41 : {
42 0 : std::stringstream status;
43 0 : auto subnodes = read_sub_nodes(getNode("csr.stat"));
44 0 : status << format_reg_table(subnodes, "PC059 IO state");
45 :
46 0 : if (print_out)
47 0 : TLOG() << std::endl << status.str();
48 0 : return status.str();
49 0 : }
50 : //-----------------------------------------------------------------------------
51 :
52 : //-----------------------------------------------------------------------------
53 : void
54 0 : PC059IONode::reset(const std::string& clock_config_file) const
55 : {
56 : // Soft reset
57 0 : write_soft_reset_register();
58 :
59 0 : millisleep(1000);
60 :
61 : // Reset PLL and I2C
62 0 : getNode("csr.ctrl.pll_rst").write(0x1);
63 0 : getNode("csr.ctrl.pll_rst").write(0x0);
64 :
65 0 : getNode("csr.ctrl.rst_i2c").write(0x1);
66 0 : getNode("csr.ctrl.rst_i2c").write(0x0);
67 :
68 0 : getNode("csr.ctrl.rst_i2cmux").write(0x1);
69 0 : getNode("csr.ctrl.rst_i2cmux").write(0x0);
70 :
71 0 : getClient().dispatch();
72 :
73 : // enclustra i2c switch stuff
74 0 : try {
75 0 : getNode<I2CMasterNode>(m_uid_i2c_bus).get_slave("AX3_Switch").write_i2c(0x01, 0x7f);
76 0 : } catch (const std::exception& e) {
77 0 : ers::warning(EnclustraSwitchFailure(ERS_HERE, e));
78 0 : }
79 :
80 : // Upload config file to PLL
81 0 : configure_pll(clock_config_file);
82 :
83 : // Reset mmcm
84 0 : getNode("csr.ctrl.rst").write(0x1);
85 0 : getNode("csr.ctrl.rst").write(0x0);
86 0 : getClient().dispatch();
87 :
88 0 : getNode("csr.ctrl.mux").write(0);
89 0 : getClient().dispatch();
90 :
91 0 : auto sfp_expander = get_i2c_device<I2CExpanderSlave>(m_uid_i2c_bus, "SFPExpander");
92 :
93 : // Set invert registers to default for both banks
94 0 : sfp_expander->set_inversion(0, 0x00);
95 0 : sfp_expander->set_inversion(1, 0x00);
96 :
97 : // Bank 0 output, bank 1 input
98 0 : sfp_expander->set_io(0, 0x00);
99 0 : sfp_expander->set_io(1, 0xff);
100 :
101 : // Bank 0 - enable all SFPGs (enable low)
102 0 : sfp_expander->set_outputs(0, 0x00);
103 0 : TLOG_DEBUG(0) << "SFPs 0-7 enabled";
104 :
105 : // To be removed from firmware address maps also
106 : //getNode("csr.ctrl.rst_lock_mon").write(0x1);
107 : //getNode("csr.ctrl.rst_lock_mon").write(0x0);
108 : //getClient().dispatch();
109 :
110 0 : TLOG() << "Reset done";
111 0 : }
112 : //-----------------------------------------------------------------------------
113 :
114 : //-----------------------------------------------------------------------------
115 : void
116 0 : PC059IONode::reset_pll() const
117 : {
118 0 : }
119 : //-----------------------------------------------------------------------------
120 :
121 : //-----------------------------------------------------------------------------
122 : void
123 0 : PC059IONode::switch_sfp_mux_channel(uint32_t mux_channel) const // NOLINT(build/unsigned)
124 : {
125 0 : getNode("csr.ctrl.mux").write(mux_channel);
126 0 : getClient().dispatch();
127 :
128 0 : TLOG_DEBUG(3) << "SFP input mux set to " << format_reg_value(read_active_sfp_mux_channel());
129 0 : }
130 : //-----------------------------------------------------------------------------
131 :
132 : //-----------------------------------------------------------------------------
133 : uint32_t // NOLINT(build/unsigned)
134 0 : PC059IONode::read_active_sfp_mux_channel() const
135 : {
136 0 : auto active_sfp_mux_channel = getNode("csr.ctrl.mux").read();
137 0 : getClient().dispatch();
138 0 : return active_sfp_mux_channel.value();
139 0 : }
140 : //-----------------------------------------------------------------------------
141 :
142 : //-----------------------------------------------------------------------------
143 : void
144 0 : PC059IONode::switch_sfp_i2c_mux_channel(uint32_t sfp_id) const // NOLINT(build/unsigned)
145 : {
146 :
147 0 : getNode("csr.ctrl.rst_i2cmux").write(0x1);
148 0 : getClient().dispatch();
149 0 : getNode("csr.ctrl.rst_i2cmux").write(0x0);
150 0 : getClient().dispatch();
151 0 : millisleep(100);
152 :
153 0 : uint8_t channel_select_byte = 1UL << sfp_id; // NOLINT(build/unsigned)
154 0 : getNode<I2CMasterNode>(m_pll_i2c_bus).get_slave("SFP_Switch").write_i2cPrimitive({ channel_select_byte });
155 0 : TLOG_DEBUG(3) << "PC059 SFP I2C mux set to " << format_reg_value(sfp_id);
156 0 : }
157 : //-----------------------------------------------------------------------------
158 :
159 : //-----------------------------------------------------------------------------
160 : std::string
161 0 : PC059IONode::get_sfp_status(uint32_t sfp_id, bool print_out) const // NOLINT(build/unsigned)
162 : {
163 : // on this board the upstream sfp has its own i2c bus, and the 8 downstream sfps are muxed onto the main i2c bus
164 0 : std::stringstream status;
165 0 : uint32_t sfp_bus_index; // NOLINT(build/unsigned)
166 0 : if (sfp_id == 0) {
167 0 : sfp_bus_index = 0;
168 0 : status << "Upstream SFP:" << std::endl;
169 0 : } else if (sfp_id > 0 && sfp_id < 9) {
170 0 : switch_sfp_i2c_mux_channel(sfp_id - 1);
171 0 : status << "Fanout SFP " << sfp_id - 1 << ":" << std::endl;
172 : sfp_bus_index = 1;
173 : } else {
174 0 : throw InvalidSFPId(ERS_HERE, format_reg_value(sfp_id));
175 : }
176 0 : auto sfp = get_i2c_device<I2CSFPSlave>(m_sfp_i2c_buses.at(sfp_bus_index), "SFP_EEProm");
177 :
178 0 : status << sfp->get_status();
179 :
180 0 : if (print_out)
181 0 : TLOG() << status.str();
182 0 : return status.str();
183 0 : }
184 : //-----------------------------------------------------------------------------
185 :
186 : //-----------------------------------------------------------------------------
187 : bool
188 0 : PC059IONode::clocks_ok() const
189 : {
190 0 : std::stringstream status;
191 :
192 0 : auto states = read_sub_nodes(getNode("csr.stat"));
193 0 : bool pll_ok = states.find("pll_ok")->second.value();
194 0 : bool mmcm_ok = states.find("mmcm_ok")->second.value();
195 :
196 0 : TLOG_DEBUG(5) << "pll ok: " << pll_ok << ", mmcm ok: " << mmcm_ok;
197 :
198 0 : return pll_ok && mmcm_ok;
199 0 : }
200 : //-----------------------------------------------------------------------------
201 :
202 : //-----------------------------------------------------------------------------
203 : void
204 0 : PC059IONode::switch_sfp_soft_tx_control_bit(uint32_t sfp_id, bool turn_on) const // NOLINT(build/unsigned)
205 : {
206 : // on this board the upstream sfp has its own i2c bus, and the 8 downstream sfps are muxed onto the main i2c bus
207 0 : uint32_t sfp_bus_index; // NOLINT(build/unsigned)
208 0 : if (sfp_id == 0) {
209 : sfp_bus_index = 0;
210 0 : } else if (sfp_id > 0 && sfp_id < 9) {
211 0 : switch_sfp_i2c_mux_channel(sfp_id - 1);
212 : sfp_bus_index = 1;
213 : } else {
214 0 : throw InvalidSFPId(ERS_HERE, format_reg_value(sfp_id));
215 : }
216 0 : auto sfp = get_i2c_device<I2CSFPSlave>(m_sfp_i2c_buses.at(sfp_bus_index), "SFP_EEProm");
217 0 : sfp->switch_soft_tx_control_bit(turn_on);
218 0 : }
219 : //-----------------------------------------------------------------------------
220 :
221 : //-----------------------------------------------------------------------------
222 : void
223 0 : PC059IONode::switch_sfp_tx(uint32_t sfp_id, bool turn_on) const { // NOLINT(build/unsigned)
224 :
225 0 : validate_sfp_id(sfp_id);
226 :
227 0 : auto sfp_expander = get_i2c_device<I2CExpanderSlave>(m_uid_i2c_bus, "SFPExpander");
228 0 : uint8_t current_sfp_tx_control_flags = sfp_expander->read_outputs_config(0); // NOLINT(build/unsigned)
229 :
230 0 : uint8_t new_sfp_tx_control_flags; // NOLINT(build/unsigned)
231 0 : if (turn_on)
232 : {
233 0 : new_sfp_tx_control_flags = current_sfp_tx_control_flags & ~(1UL << sfp_id);
234 : }
235 : else
236 : {
237 0 : new_sfp_tx_control_flags = current_sfp_tx_control_flags | (1UL << sfp_id);
238 : }
239 :
240 0 : sfp_expander->set_outputs(0, new_sfp_tx_control_flags);
241 0 : }
242 : //-----------------------------------------------------------------------------
243 :
244 : //-----------------------------------------------------------------------------
245 : void
246 0 : PC059IONode::validate_sfp_id(uint32_t sfp_id) const // NOLINT(build/unsigned)
247 : {
248 : // on this board we have 8 downstream SFPs
249 0 : if (sfp_id > 7)
250 : {
251 0 : throw InvalidSFPId(ERS_HERE, format_reg_value(sfp_id));
252 : }
253 0 : }
254 : //-----------------------------------------------------------------------------
255 :
256 : //-----------------------------------------------------------------------------
257 : // void
258 : // PC059IONode::get_info(timinghardwareinfo::TimingPC059MonitorData& mon_data) const
259 : // {
260 : // auto subnodes = read_sub_nodes(getNode("csr.stat"));
261 :
262 : // mon_data.cdr_lol = subnodes.at("cdr_lol").value();
263 : // mon_data.cdr_los = subnodes.at("cdr_los").value();
264 :
265 : // mon_data.mmcm_ok = subnodes.at("mmcm_ok").value();
266 : // mon_data.mmcm_sticky = subnodes.at("mmcm_sticky").value();
267 :
268 : // mon_data.pll_lol = subnodes.at("pll_lol").value();
269 : // mon_data.pll_ok = subnodes.at("pll_ok").value();
270 : // mon_data.pll_sticky = subnodes.at("pll_sticky").value();
271 :
272 : // mon_data.sfp_los = subnodes.at("sfp_los").value();
273 :
274 : // mon_data.ucdr_lol = subnodes.at("ucdr_lol").value();
275 : // mon_data.ucdr_los = subnodes.at("ucdr_los").value();
276 :
277 : // mon_data.usfp_flt = subnodes.at("usfp_flt").value();
278 : // mon_data.usfp_los = subnodes.at("usfp_los").value();
279 : // }
280 : //-----------------------------------------------------------------------------
281 :
282 : //-----------------------------------------------------------------------------
283 : // void
284 : // PC059IONode::get_info(opmonlib::InfoCollector& ci, int level) const
285 : // {
286 : // if (level >= 2)
287 : // {
288 : // timinghardwareinfo::TimingPLLMonitorData pll_mon_data;
289 : // this->get_pll()->get_info(pll_mon_data);
290 : // ci.add(pll_mon_data);
291 :
292 : // timinghardwareinfo::TimingSFPMonitorData upstream_sfp_mon_data;
293 : // auto upstream_sfp = get_i2c_device<I2CSFPSlave>(m_sfp_i2c_buses.at(0), "SFP_EEProm");
294 : // try {
295 : // upstream_sfp->get_info(upstream_sfp_mon_data);
296 : // opmonlib::InfoCollector upstream_sfp_ic;
297 : // upstream_sfp_ic.add(upstream_sfp_mon_data);
298 : // ci.add("upstream_sfp", upstream_sfp_ic);
299 : // }
300 : // catch (timing::SFPUnreachable& e) {
301 : // // It is valid that an SFP may not be installed, currently no good way of knowing whether they it should be
302 : // TLOG_DEBUG(2) << "Failed to communicate with upstream SFP on i2c bus" << m_sfp_i2c_buses.at(0);
303 : // }
304 :
305 :
306 : // for (uint sfp_id=0; sfp_id < 8; ++sfp_id) {
307 : // TLOG_DEBUG(5) << "checking sfp: " << sfp_id;
308 : // switch_sfp_i2c_mux_channel(sfp_id);
309 :
310 : // auto sfp = get_i2c_device<I2CSFPSlave>(m_sfp_i2c_buses.at(1), "SFP_EEProm");
311 : // timinghardwareinfo::TimingSFPMonitorData sfp_data;
312 :
313 : // try {
314 : // sfp->get_info(sfp_data);
315 : // } catch (timing::SFPUnreachable& e) {
316 : // // It is valid that an SFP may not be installed, currently no good way of knowing whether they it should be
317 : // TLOG_DEBUG(2) << "Failed to communicate with downstream SFP: " << sfp_id << " on i2c bus" << m_sfp_i2c_buses.at(1);
318 : // continue;
319 : // }
320 :
321 : // opmonlib::InfoCollector sfp_ic;
322 : // sfp_ic.add(sfp_data);
323 : // ci.add("sfp_"+std::to_string(sfp_id), sfp_ic);
324 : // }
325 : // }
326 :
327 : // if (level >= 1) {
328 : // timinghardwareinfo::TimingPC059MonitorData mon_data;
329 : // this->get_info(mon_data);
330 : // ci.add(mon_data);
331 : // }
332 : // }
333 : //-----------------------------------------------------------------------------
334 :
335 : } // namespace timing
336 : } // namespace dunedaq
|