1 #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
26 static constexpr uint8_t busId = 11;
27 static constexpr uint8_t slaveAddr = 0x40;
28 
29 // SMLink Status Register(PSU status Register)
30 static constexpr size_t StatusReg_0 = 0x05;
31 
32 // SMLink Status Register(Interrupt-control-bit Register)
33 static constexpr size_t StatusReg_1 = 0x20;
34 
35 // SMLink Status Register(Power-on error code Register)
36 static constexpr size_t StatusReg_2 = 0x21;
37 
38 // SMLink Status Register(Power-ready error code Register)
39 static constexpr size_t StatusReg_3 = 0x22;
40 
41 using namespace std;
42 
43 namespace phosphor
44 {
45 namespace power
46 {
47 const auto DEVICE_NAME = "MihawkCPLD"s;
48 
49 namespace fs = std::filesystem;
50 using namespace phosphor::logging;
51 
52 using namespace sdbusplus::org::open_power::Witherspoon::Fault::Error;
53 
54 MihawkCPLD::MihawkCPLD(size_t instance, sdbusplus::bus::bus& bus) :
55     Device(DEVICE_NAME, instance), bus(bus)
56 {}
57 
58 void 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 
192 void 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                 }
374             }
375             clearCPLDregister();
376         }
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
389 bool 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.
422 int 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
444 bool 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.
477 void MihawkCPLD::clearCPLDregister()
478 {
479     uint16_t data = 0x01;
480     uint16_t checkpsu;
481 
482     if (!i2c)
483     {
484         openCPLDDevice();
485     }
486 
487     // 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     }
498 }
499 
500 // Open i2c device(CPLD_register)
501 void MihawkCPLD::openCPLDDevice()
502 {
503     i2c = i2c::create(busId, slaveAddr);
504 }
505 
506 } // namespace power
507 } // namespace phosphor
508