blob: 6f9883fcb43646ef737015d30238a1ef21f1dc61 [file] [log] [blame]
Andy YF Wang40247cc2019-09-06 18:30:56 +08001#include "config.h"
2
3#include "mihawk-cpld.hpp"
4
5#include "gpio.hpp"
6#include "utility.hpp"
7
8#include <errno.h>
9#include <fcntl.h>
10#include <sys/ioctl.h>
11#include <unistd.h>
12
13#include <elog-errors.hpp>
14#include <org/open_power/Witherspoon/Fault/error.hpp>
15#include <phosphor-logging/elog.hpp>
Andy YF Wang40247cc2019-09-06 18:30:56 +080016#include <xyz/openbmc_project/Common/Device/error.hpp>
17
18#include <chrono>
19#include <iostream>
20#include <map>
21#include <memory>
22#include <string>
23
24// i2c bus & i2c slave address of Mihawk's CPLD_register
25static constexpr uint8_t busId = 11;
26static constexpr uint8_t slaveAddr = 0x40;
27
AndyYFWangb464b152021-02-01 11:39:48 +080028// SMLink Status Register(PSU status Register)
29static constexpr size_t StatusReg_0 = 0x05;
30
Andy YF Wang40247cc2019-09-06 18:30:56 +080031// SMLink Status Register(Interrupt-control-bit Register)
32static constexpr size_t StatusReg_1 = 0x20;
33
34// SMLink Status Register(Power-on error code Register)
35static constexpr size_t StatusReg_2 = 0x21;
36
37// SMLink Status Register(Power-ready error code Register)
38static constexpr size_t StatusReg_3 = 0x22;
39
40using namespace std;
41
42namespace phosphor
43{
44namespace power
45{
46const auto DEVICE_NAME = "MihawkCPLD"s;
47
48namespace fs = std::filesystem;
49using namespace phosphor::logging;
50
51using namespace sdbusplus::org::open_power::Witherspoon::Fault::Error;
52
Patrick Williams7354ce62022-07-22 19:26:56 -050053MihawkCPLD::MihawkCPLD(size_t instance, sdbusplus::bus_t& bus) :
Andy YF Wang40247cc2019-09-06 18:30:56 +080054 Device(DEVICE_NAME, instance), bus(bus)
Adriana Kobylak0c9a33d2021-09-13 18:05:09 +000055{}
Andy YF Wang40247cc2019-09-06 18:30:56 +080056
57void MihawkCPLD::onFailure()
58{
59 bool poweronError = checkPoweronFault();
60
61 // If the interrupt of power_on_error is switch on,
62 // read CPLD_register error code to analyze
63 // and report the error log event.
64 if (poweronError)
65 {
66 ErrorCode code;
67 code = static_cast<ErrorCode>(readFromCPLDErrorCode(StatusReg_2));
68
69 switch (code)
70 {
71 case ErrorCode::_1:
72 report<ErrorCode1>();
73 break;
74 case ErrorCode::_2:
75 report<ErrorCode2>();
76 break;
77 case ErrorCode::_3:
78 report<ErrorCode3>();
79 break;
80 case ErrorCode::_4:
81 report<ErrorCode4>();
82 break;
83 case ErrorCode::_5:
84 report<ErrorCode5>();
85 break;
86 case ErrorCode::_6:
87 report<ErrorCode6>();
88 break;
89 case ErrorCode::_7:
90 report<ErrorCode7>();
91 break;
92 case ErrorCode::_8:
93 report<ErrorCode8>();
94 break;
95 case ErrorCode::_9:
96 report<ErrorCode9>();
97 break;
98 case ErrorCode::_10:
99 report<ErrorCode10>();
100 break;
101 case ErrorCode::_11:
102 report<ErrorCode11>();
103 break;
104 case ErrorCode::_12:
105 report<ErrorCode12>();
106 break;
107 case ErrorCode::_13:
108 report<ErrorCode13>();
109 break;
110 case ErrorCode::_14:
111 report<ErrorCode14>();
112 break;
113 case ErrorCode::_15:
114 report<ErrorCode15>();
115 break;
116 case ErrorCode::_16:
117 report<ErrorCode16>();
118 break;
119 case ErrorCode::_17:
120 report<ErrorCode17>();
121 break;
122 case ErrorCode::_18:
123 report<ErrorCode18>();
124 break;
125 case ErrorCode::_19:
126 report<ErrorCode19>();
127 break;
128 case ErrorCode::_20:
129 report<ErrorCode20>();
130 break;
131 case ErrorCode::_21:
132 report<ErrorCode21>();
133 break;
134 case ErrorCode::_22:
135 report<ErrorCode22>();
136 break;
137 case ErrorCode::_23:
138 report<ErrorCode23>();
139 break;
140 case ErrorCode::_24:
141 report<ErrorCode24>();
142 break;
143 case ErrorCode::_25:
144 report<ErrorCode25>();
145 break;
146 case ErrorCode::_26:
147 report<ErrorCode26>();
148 break;
149 case ErrorCode::_27:
150 report<ErrorCode27>();
151 break;
152 case ErrorCode::_28:
153 report<ErrorCode28>();
154 break;
155 case ErrorCode::_29:
156 report<ErrorCode29>();
157 break;
158 case ErrorCode::_30:
159 report<ErrorCode30>();
160 break;
161 case ErrorCode::_31:
162 report<ErrorCode31>();
163 break;
164 case ErrorCode::_32:
165 report<ErrorCode32>();
166 break;
167 case ErrorCode::_33:
168 report<ErrorCode33>();
169 break;
170 case ErrorCode::_34:
171 report<ErrorCode34>();
172 break;
173 case ErrorCode::_35:
174 report<ErrorCode35>();
175 break;
176 case ErrorCode::_36:
177 report<ErrorCode36>();
178 break;
179 default:
180 // If the errorcode isn't 1~36,
181 // it indicates that the CPLD register
182 // has a reading issue,
183 // so the errorcode0 error is reported.
184 report<ErrorCode0>();
185 break;
186 }
187 clearCPLDregister();
188 }
189}
190
191void MihawkCPLD::analyze()
192{
193 bool powerreadyError = checkPowerreadyFault();
194
195 // Use the function of GPIO class to check
196 // GPIOF0(CPLD uses).
197 using namespace phosphor::gpio;
198 GPIO gpio{"/dev/gpiochip0", static_cast<gpioNum_t>(40), Direction::input};
199
200 // Check GPIOFO pin whether is switched off.
201 // if GPIOF0 has been switched off,
202 // check CPLD's errorcode & report error.
203 if (gpio.read() == Value::low)
204 {
205 // If the interrupt of power_ready_error is switch on,
206 // read CPLD_register error code to analyze and
207 // report the error event.
208 if (powerreadyError)
209 {
210 ErrorCode code;
211 code = static_cast<ErrorCode>(readFromCPLDErrorCode(StatusReg_3));
212
213 if (!errorcodeMask)
214 {
215 // Check the errorcodeMask & errorcode whether
216 // are the same value to avoid to report the
217 // same error again.
218 switch (code)
219 {
220 case ErrorCode::_1:
221 report<ErrorCode1>();
222 errorcodeMask = 1;
223 break;
224 case ErrorCode::_2:
225 report<ErrorCode2>();
226 errorcodeMask = 1;
227 break;
228 case ErrorCode::_3:
229 report<ErrorCode3>();
230 errorcodeMask = 1;
231 break;
232 case ErrorCode::_4:
233 report<ErrorCode4>();
234 errorcodeMask = 1;
235 break;
236 case ErrorCode::_5:
237 report<ErrorCode5>();
238 errorcodeMask = 1;
239 break;
240 case ErrorCode::_6:
241 report<ErrorCode6>();
242 errorcodeMask = 1;
243 break;
244 case ErrorCode::_7:
245 report<ErrorCode7>();
246 errorcodeMask = 1;
247 break;
248 case ErrorCode::_8:
249 report<ErrorCode8>();
250 errorcodeMask = 1;
251 break;
252 case ErrorCode::_9:
253 report<ErrorCode9>();
254 errorcodeMask = 1;
255 break;
256 case ErrorCode::_10:
257 report<ErrorCode10>();
258 errorcodeMask = 1;
259 break;
260 case ErrorCode::_11:
261 report<ErrorCode11>();
262 errorcodeMask = 1;
263 break;
264 case ErrorCode::_12:
265 report<ErrorCode12>();
266 errorcodeMask = 1;
267 break;
268 case ErrorCode::_13:
269 report<ErrorCode13>();
270 errorcodeMask = 1;
271 break;
272 case ErrorCode::_14:
273 report<ErrorCode14>();
274 errorcodeMask = 1;
275 break;
276 case ErrorCode::_15:
277 report<ErrorCode15>();
278 errorcodeMask = 1;
279 break;
280 case ErrorCode::_16:
281 report<ErrorCode16>();
282 errorcodeMask = 1;
283 break;
284 case ErrorCode::_17:
285 report<ErrorCode17>();
286 errorcodeMask = 1;
287 break;
288 case ErrorCode::_18:
289 report<ErrorCode18>();
290 errorcodeMask = 1;
291 break;
292 case ErrorCode::_19:
293 report<ErrorCode19>();
294 errorcodeMask = 1;
295 break;
296 case ErrorCode::_20:
297 report<ErrorCode20>();
298 errorcodeMask = 1;
299 break;
300 case ErrorCode::_21:
301 report<ErrorCode21>();
302 errorcodeMask = 1;
303 break;
304 case ErrorCode::_22:
305 report<ErrorCode22>();
306 errorcodeMask = 1;
307 break;
308 case ErrorCode::_23:
309 report<ErrorCode23>();
310 errorcodeMask = 1;
311 break;
312 case ErrorCode::_24:
313 report<ErrorCode24>();
314 errorcodeMask = 1;
315 break;
316 case ErrorCode::_25:
317 report<ErrorCode25>();
318 errorcodeMask = 1;
319 break;
320 case ErrorCode::_26:
321 report<ErrorCode26>();
322 errorcodeMask = 1;
323 break;
324 case ErrorCode::_27:
325 report<ErrorCode27>();
326 errorcodeMask = 1;
327 break;
328 case ErrorCode::_28:
329 report<ErrorCode28>();
330 errorcodeMask = 1;
331 break;
332 case ErrorCode::_29:
333 report<ErrorCode29>();
334 errorcodeMask = 1;
335 break;
336 case ErrorCode::_30:
337 report<ErrorCode30>();
338 errorcodeMask = 1;
339 break;
340 case ErrorCode::_31:
341 report<ErrorCode31>();
342 errorcodeMask = 1;
343 break;
344 case ErrorCode::_32:
345 report<ErrorCode32>();
346 errorcodeMask = 1;
347 break;
348 case ErrorCode::_33:
349 report<ErrorCode33>();
350 errorcodeMask = 1;
351 break;
352 case ErrorCode::_34:
353 report<ErrorCode34>();
354 errorcodeMask = 1;
355 break;
356 case ErrorCode::_35:
357 report<ErrorCode35>();
358 errorcodeMask = 1;
359 break;
360 case ErrorCode::_36:
361 report<ErrorCode36>();
362 errorcodeMask = 1;
363 break;
364 default:
365 // If the errorcode is not 1~36,
366 // it indicates that the CPLD register
367 // has a reading issue, so the
368 // errorcode0 error is reported.
369 report<ErrorCode0>();
370 errorcodeMask = 1;
371 break;
372 }
Andy YF Wang40247cc2019-09-06 18:30:56 +0800373 }
AndyYFWangb464b152021-02-01 11:39:48 +0800374 clearCPLDregister();
Andy YF Wang40247cc2019-09-06 18:30:56 +0800375 }
376 }
377
378 if (gpio.read() == Value::high)
379 {
380 // If there isn't an error(GPIOF0
381 // which CPLD uses is switched on),
382 // we clear errorcodeMask.
383 errorcodeMask = 0;
384 }
385}
386
387// Check for PoweronFault
388bool MihawkCPLD::checkPoweronFault()
389{
390 uint16_t statusValue_1;
391 bool result;
392
393 if (!i2c)
394 {
395 openCPLDDevice();
396 }
397 i2c->read(StatusReg_1, statusValue_1);
398
399 if (statusValue_1 < 0)
400 {
401 std::cerr << "i2c->read() reads data failed \n";
402 result = 0;
403 }
404
405 if ((statusValue_1 >> 5) & 1)
406 {
407 // If power_on-interrupt-bit is read as 1,
408 // switch on the flag.
409 result = 1;
410 }
411 else
412 {
413 result = 0;
414 }
415
416 // Return the flag.
417 return result;
418}
419
420// Read CPLD_register error code and return the result to analyze.
421int MihawkCPLD::readFromCPLDErrorCode(int statusReg)
422{
423 uint16_t statusValue_2;
424
425 if (!i2c)
426 {
427 openCPLDDevice();
428 }
429 i2c->read(statusReg, statusValue_2);
430
431 if (statusValue_2 < 0 ||
432 ((statusValue_2 > static_cast<int>(ErrorCode::_35)) &&
433 (statusValue_2 != static_cast<int>(ErrorCode::_36))))
434 {
435 statusValue_2 = 0;
436 }
437
438 // Return the data via i2c->read().
439 return statusValue_2;
440}
441
442// Check for PowerreadyFault
443bool MihawkCPLD::checkPowerreadyFault()
444{
445 uint16_t statusValue_3;
446 bool result;
447
448 if (!i2c)
449 {
450 openCPLDDevice();
451 }
452 i2c->read(StatusReg_1, statusValue_3);
453
454 if (statusValue_3 < 0)
455 {
456 std::cerr << "i2c->read() reads data failed \n";
457 result = 0;
458 }
459
460 if ((statusValue_3 >> 6) & 1)
461 {
462 // If power_ready-interrupt-bit is read as 1,
463 // switch on the flag.
464 result = 1;
465 }
466 else
467 {
468 result = 0;
469 }
470
471 // Return the flag.
472 return result;
473}
474
475// Clear CPLD_register after reading.
476void MihawkCPLD::clearCPLDregister()
477{
478 uint16_t data = 0x01;
AndyYFWangb464b152021-02-01 11:39:48 +0800479 uint16_t checkpsu;
Andy YF Wang40247cc2019-09-06 18:30:56 +0800480
481 if (!i2c)
482 {
483 openCPLDDevice();
484 }
485
AndyYFWangb464b152021-02-01 11:39:48 +0800486 // check psu pgood status.
487 i2c->read(StatusReg_0, checkpsu);
488
489 // check one of both psus pgood status before
490 // clear CPLD_register.
491 if (((checkpsu >> 1) & 1) || ((checkpsu >> 2) & 1))
492 {
493 // Write 0x01 to StatusReg_1 for clearing
494 // CPLD_register.
495 i2c->write(StatusReg_1, data);
496 }
Andy YF Wang40247cc2019-09-06 18:30:56 +0800497}
498
499// Open i2c device(CPLD_register)
500void MihawkCPLD::openCPLDDevice()
501{
502 i2c = i2c::create(busId, slaveAddr);
503}
504
505} // namespace power
506} // namespace phosphor