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