#include "config.h" #include "mihawk-cpld.hpp" #include "gpio.hpp" #include "utility.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include // i2c bus & i2c slave address of Mihawk's CPLD_register static constexpr uint8_t busId = 11; static constexpr uint8_t slaveAddr = 0x40; // SMLink Status Register(PSU status Register) static constexpr size_t StatusReg_0 = 0x05; // SMLink Status Register(Interrupt-control-bit Register) static constexpr size_t StatusReg_1 = 0x20; // SMLink Status Register(Power-on error code Register) static constexpr size_t StatusReg_2 = 0x21; // SMLink Status Register(Power-ready error code Register) static constexpr size_t StatusReg_3 = 0x22; using namespace std; namespace phosphor { namespace power { const auto DEVICE_NAME = "MihawkCPLD"s; namespace fs = std::filesystem; using namespace phosphor::logging; using namespace sdbusplus::org::open_power::Witherspoon::Fault::Error; MihawkCPLD::MihawkCPLD(size_t instance, sdbusplus::bus_t& bus) : Device(DEVICE_NAME, instance), bus(bus) {} void MihawkCPLD::onFailure() { bool poweronError = checkPoweronFault(); // If the interrupt of power_on_error is switch on, // read CPLD_register error code to analyze // and report the error log event. if (poweronError) { ErrorCode code; code = static_cast(readFromCPLDErrorCode(StatusReg_2)); switch (code) { case ErrorCode::_1: report(); break; case ErrorCode::_2: report(); break; case ErrorCode::_3: report(); break; case ErrorCode::_4: report(); break; case ErrorCode::_5: report(); break; case ErrorCode::_6: report(); break; case ErrorCode::_7: report(); break; case ErrorCode::_8: report(); break; case ErrorCode::_9: report(); break; case ErrorCode::_10: report(); break; case ErrorCode::_11: report(); break; case ErrorCode::_12: report(); break; case ErrorCode::_13: report(); break; case ErrorCode::_14: report(); break; case ErrorCode::_15: report(); break; case ErrorCode::_16: report(); break; case ErrorCode::_17: report(); break; case ErrorCode::_18: report(); break; case ErrorCode::_19: report(); break; case ErrorCode::_20: report(); break; case ErrorCode::_21: report(); break; case ErrorCode::_22: report(); break; case ErrorCode::_23: report(); break; case ErrorCode::_24: report(); break; case ErrorCode::_25: report(); break; case ErrorCode::_26: report(); break; case ErrorCode::_27: report(); break; case ErrorCode::_28: report(); break; case ErrorCode::_29: report(); break; case ErrorCode::_30: report(); break; case ErrorCode::_31: report(); break; case ErrorCode::_32: report(); break; case ErrorCode::_33: report(); break; case ErrorCode::_34: report(); break; case ErrorCode::_35: report(); break; case ErrorCode::_36: report(); break; default: // If the errorcode isn't 1~36, // it indicates that the CPLD register // has a reading issue, // so the errorcode0 error is reported. report(); break; } clearCPLDregister(); } } void MihawkCPLD::analyze() { bool powerreadyError = checkPowerreadyFault(); // Use the function of GPIO class to check // GPIOF0(CPLD uses). using namespace phosphor::gpio; GPIO gpio{"/dev/gpiochip0", static_cast(40), Direction::input}; // Check GPIOFO pin whether is switched off. // if GPIOF0 has been switched off, // check CPLD's errorcode & report error. if (gpio.read() == Value::low) { // If the interrupt of power_ready_error is switch on, // read CPLD_register error code to analyze and // report the error event. if (powerreadyError) { ErrorCode code; code = static_cast(readFromCPLDErrorCode(StatusReg_3)); if (!errorcodeMask) { // Check the errorcodeMask & errorcode whether // are the same value to avoid to report the // same error again. switch (code) { case ErrorCode::_1: report(); errorcodeMask = 1; break; case ErrorCode::_2: report(); errorcodeMask = 1; break; case ErrorCode::_3: report(); errorcodeMask = 1; break; case ErrorCode::_4: report(); errorcodeMask = 1; break; case ErrorCode::_5: report(); errorcodeMask = 1; break; case ErrorCode::_6: report(); errorcodeMask = 1; break; case ErrorCode::_7: report(); errorcodeMask = 1; break; case ErrorCode::_8: report(); errorcodeMask = 1; break; case ErrorCode::_9: report(); errorcodeMask = 1; break; case ErrorCode::_10: report(); errorcodeMask = 1; break; case ErrorCode::_11: report(); errorcodeMask = 1; break; case ErrorCode::_12: report(); errorcodeMask = 1; break; case ErrorCode::_13: report(); errorcodeMask = 1; break; case ErrorCode::_14: report(); errorcodeMask = 1; break; case ErrorCode::_15: report(); errorcodeMask = 1; break; case ErrorCode::_16: report(); errorcodeMask = 1; break; case ErrorCode::_17: report(); errorcodeMask = 1; break; case ErrorCode::_18: report(); errorcodeMask = 1; break; case ErrorCode::_19: report(); errorcodeMask = 1; break; case ErrorCode::_20: report(); errorcodeMask = 1; break; case ErrorCode::_21: report(); errorcodeMask = 1; break; case ErrorCode::_22: report(); errorcodeMask = 1; break; case ErrorCode::_23: report(); errorcodeMask = 1; break; case ErrorCode::_24: report(); errorcodeMask = 1; break; case ErrorCode::_25: report(); errorcodeMask = 1; break; case ErrorCode::_26: report(); errorcodeMask = 1; break; case ErrorCode::_27: report(); errorcodeMask = 1; break; case ErrorCode::_28: report(); errorcodeMask = 1; break; case ErrorCode::_29: report(); errorcodeMask = 1; break; case ErrorCode::_30: report(); errorcodeMask = 1; break; case ErrorCode::_31: report(); errorcodeMask = 1; break; case ErrorCode::_32: report(); errorcodeMask = 1; break; case ErrorCode::_33: report(); errorcodeMask = 1; break; case ErrorCode::_34: report(); errorcodeMask = 1; break; case ErrorCode::_35: report(); errorcodeMask = 1; break; case ErrorCode::_36: report(); errorcodeMask = 1; break; default: // If the errorcode is not 1~36, // it indicates that the CPLD register // has a reading issue, so the // errorcode0 error is reported. report(); errorcodeMask = 1; break; } } clearCPLDregister(); } } if (gpio.read() == Value::high) { // If there isn't an error(GPIOF0 // which CPLD uses is switched on), // we clear errorcodeMask. errorcodeMask = 0; } } // Check for PoweronFault bool MihawkCPLD::checkPoweronFault() { uint16_t statusValue_1; bool result; if (!i2c) { openCPLDDevice(); } i2c->read(StatusReg_1, statusValue_1); if (statusValue_1 < 0) { std::cerr << "i2c->read() reads data failed \n"; result = 0; } if ((statusValue_1 >> 5) & 1) { // If power_on-interrupt-bit is read as 1, // switch on the flag. result = 1; } else { result = 0; } // Return the flag. return result; } // Read CPLD_register error code and return the result to analyze. int MihawkCPLD::readFromCPLDErrorCode(int statusReg) { uint16_t statusValue_2; if (!i2c) { openCPLDDevice(); } i2c->read(statusReg, statusValue_2); if (statusValue_2 < 0 || ((statusValue_2 > static_cast(ErrorCode::_35)) && (statusValue_2 != static_cast(ErrorCode::_36)))) { statusValue_2 = 0; } // Return the data via i2c->read(). return statusValue_2; } // Check for PowerreadyFault bool MihawkCPLD::checkPowerreadyFault() { uint16_t statusValue_3; bool result; if (!i2c) { openCPLDDevice(); } i2c->read(StatusReg_1, statusValue_3); if (statusValue_3 < 0) { std::cerr << "i2c->read() reads data failed \n"; result = 0; } if ((statusValue_3 >> 6) & 1) { // If power_ready-interrupt-bit is read as 1, // switch on the flag. result = 1; } else { result = 0; } // Return the flag. return result; } // Clear CPLD_register after reading. void MihawkCPLD::clearCPLDregister() { uint16_t data = 0x01; uint16_t checkpsu; if (!i2c) { openCPLDDevice(); } // check psu pgood status. i2c->read(StatusReg_0, checkpsu); // check one of both psus pgood status before // clear CPLD_register. if (((checkpsu >> 1) & 1) || ((checkpsu >> 2) & 1)) { // Write 0x01 to StatusReg_1 for clearing // CPLD_register. i2c->write(StatusReg_1, data); } } // Open i2c device(CPLD_register) void MihawkCPLD::openCPLDDevice() { i2c = i2c::create(busId, slaveAddr); } } // namespace power } // namespace phosphor