blob: cf4c2bb537ea8e89aa1e560c21b9369ff96c7c3b [file] [log] [blame]
Brandon Wymana0f33ce2019-10-17 18:32:29 -05001#pragma once
2
Brandon Wyman8d195772020-01-27 15:03:51 -06003#include "pmbus.hpp"
Brandon Wymanaed1f752019-11-25 18:10:52 -06004#include "types.hpp"
B. J. Wyman681b2a32021-04-20 22:31:22 +00005#include "util.hpp"
Brandon Wyman3f1242f2020-01-28 13:11:25 -06006#include "utility.hpp"
Brandon Wymanaed1f752019-11-25 18:10:52 -06007
B. J. Wyman681b2a32021-04-20 22:31:22 +00008#include <gpiod.hpp>
Brandon Wymanaed1f752019-11-25 18:10:52 -06009#include <sdbusplus/bus/match.hpp>
10
B. J. Wyman681b2a32021-04-20 22:31:22 +000011#include <filesystem>
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050012#include <stdexcept>
13
Brandon Wymana0f33ce2019-10-17 18:32:29 -050014namespace phosphor::power::psu
15{
Brandon Wyman3f1242f2020-01-28 13:11:25 -060016
Chanh Nguyenc12c53b2021-04-06 17:24:47 +070017#if IBM_VPD
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050018// PMBus device driver "file name" to read for CCIN value.
19constexpr auto CCIN = "ccin";
20constexpr auto PART_NUMBER = "part_number";
21constexpr auto FRU_NUMBER = "fru";
22constexpr auto SERIAL_HEADER = "header";
23constexpr auto SERIAL_NUMBER = "serial_number";
24constexpr auto FW_VERSION = "fw_version";
25
26// The D-Bus property name to update with the CCIN value.
27constexpr auto MODEL_PROP = "Model";
28constexpr auto PN_PROP = "PartNumber";
29constexpr auto SN_PROP = "SerialNumber";
30constexpr auto VERSION_PROP = "Version";
31
32// ipzVPD Keyword sizes
33static constexpr auto FL_KW_SIZE = 20;
34#endif
35
Brandon Wymanf65c4062020-08-19 13:15:53 -050036constexpr auto LOG_LIMIT = 3;
37
Brandon Wymana0f33ce2019-10-17 18:32:29 -050038/**
39 * @class PowerSupply
40 * Represents a PMBus power supply device.
41 */
42class PowerSupply
43{
44 public:
Brandon Wymanaed1f752019-11-25 18:10:52 -060045 PowerSupply() = delete;
Brandon Wymana0f33ce2019-10-17 18:32:29 -050046 PowerSupply(const PowerSupply&) = delete;
47 PowerSupply(PowerSupply&&) = delete;
48 PowerSupply& operator=(const PowerSupply&) = delete;
49 PowerSupply& operator=(PowerSupply&&) = delete;
50 ~PowerSupply() = default;
51
52 /**
Brandon Wymanc63941c2020-01-27 16:49:33 -060053 * @param[in] invpath - String for inventory path to use
54 * @param[in] i2cbus - The bus number this power supply is on
55 * @param[in] i2caddr - The 16-bit I2C address of the power supply
B. J. Wyman681b2a32021-04-20 22:31:22 +000056 * @param[in] gpioLineName - The gpio-line-name to read for presence. See
57 * https://github.com/openbmc/docs/blob/master/designs/device-tree-gpio-naming.md
Brandon Wymanaed1f752019-11-25 18:10:52 -060058 */
Brandon Wymanc63941c2020-01-27 16:49:33 -060059 PowerSupply(sdbusplus::bus::bus& bus, const std::string& invpath,
B. J. Wyman681b2a32021-04-20 22:31:22 +000060 std::uint8_t i2cbus, const std::uint16_t i2caddr,
61 const std::string& gpioLineName);
Brandon Wymanaed1f752019-11-25 18:10:52 -060062
Brandon Wyman3f1242f2020-01-28 13:11:25 -060063 phosphor::pmbus::PMBusBase& getPMBus()
64 {
65 return *pmbusIntf;
66 }
67
Adriana Kobylak3ca062a2021-10-20 15:27:23 +000068 GPIOInterfaceBase* getPresenceGPIO()
B. J. Wyman681b2a32021-04-20 22:31:22 +000069 {
70 return presenceGPIO.get();
71 }
72
B. J. Wymand8b8cb12021-07-15 22:03:34 +000073 std::string getPresenceGPIOName() const
74 {
75 if (presenceGPIO != nullptr)
76 {
77 return presenceGPIO->getName();
78 }
79 else
80 {
81 return std::string();
82 }
83 }
84
Brandon Wymanaed1f752019-11-25 18:10:52 -060085 /**
Brandon Wymana0f33ce2019-10-17 18:32:29 -050086 * Power supply specific function to analyze for faults/errors.
87 *
88 * Various PMBus status bits will be checked for fault conditions.
89 * If a certain fault bits are on, the appropriate error will be
90 * committed.
91 */
Brandon Wyman3f1242f2020-01-28 13:11:25 -060092 void analyze();
Brandon Wymana0f33ce2019-10-17 18:32:29 -050093
94 /**
Brandon Wyman59a35792020-06-04 12:37:40 -050095 * Write PMBus ON_OFF_CONFIG
96 *
97 * This function will be called to cause the PMBus device driver to send the
98 * ON_OFF_CONFIG command. Takes one byte of data.
99 *
100 * @param[in] data - The ON_OFF_CONFIG data byte mask.
101 */
102 void onOffConfig(uint8_t data);
103
104 /**
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500105 * Write PMBus CLEAR_FAULTS
106 *
107 * This function will be called in various situations in order to clear
108 * any fault status bits that may have been set, in order to start over
109 * with a clean state. Presence changes and power state changes will
110 * want to clear any faults logged.
111 */
Brandon Wyman3c208462020-05-13 16:25:58 -0500112 void clearFaults();
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500113
114 /**
115 * @brief Adds properties to the inventory.
116 *
117 * Reads the values from the device and writes them to the
118 * associated power supply D-Bus inventory object.
119 *
120 * This needs to be done on startup, and each time the presence
121 * state changes.
122 *
123 * Properties added:
124 * - Serial Number
125 * - Part Number
126 * - CCIN (Customer Card Identification Number) - added as the Model
127 * - Firmware version
128 */
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500129 void updateInventory();
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500130
Brandon Wymanaed1f752019-11-25 18:10:52 -0600131 /**
132 * @brief Accessor function to indicate present status
133 */
134 bool isPresent() const
135 {
136 return present;
137 }
138
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600139 /**
Brandon Wymanfed0ba22020-09-26 20:02:51 -0500140 * @brief Returns the last read value from STATUS_WORD.
141 */
142 uint64_t getStatusWord() const
143 {
144 return statusWord;
145 }
146
147 /**
Brandon Wymanf07bc792021-10-12 19:00:35 +0000148 * @brief Returns the last read value from STATUS_INPUT.
149 */
150 uint64_t getStatusInput() const
151 {
152 return statusInput;
153 }
154
155 /**
Jay Meyer10d94052020-11-30 14:41:21 -0600156 * @brief Returns the last read value from STATUS_MFR.
157 */
158 uint64_t getMFRFault() const
159 {
160 return statusMFR;
161 }
162
163 /**
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000164 * @brief Returns the last read value from STATUS_CML.
165 */
166 uint64_t getStatusCML() const
167 {
168 return statusCML;
169 }
170
171 /**
Brandon Wyman6710ba22021-10-27 17:39:31 +0000172 * @brief Returns the last read value from STATUS_VOUT.
173 */
174 uint64_t getStatusVout() const
175 {
176 return statusVout;
177 }
178
179 /**
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000180 * @brief Returns the last value read from STATUS_IOUT.
181 */
182 uint64_t getStatusIout() const
183 {
184 return statusIout;
185 }
186
187 /**
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000188 * @brief Returns the last value read from STATUS_FANS_1_2.
189 */
190 uint64_t getStatusFans12() const
191 {
192 return statusFans12;
193 }
194
195 /**
Brandon Wyman96893a42021-11-05 19:56:57 +0000196 * @brief Returns the last value read from STATUS_TEMPERATURE.
197 */
198 uint64_t getStatusTemperature() const
199 {
200 return statusTemperature;
201 }
202
203 /**
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600204 * @brief Returns true if a fault was found.
205 */
206 bool isFaulted() const
207 {
Brandon Wyman9ddc6222021-10-28 17:28:01 +0000208 return (hasCommFault() || vinUVFault || inputFault || voutOVFault ||
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000209 ioutOCFault || voutUVFault || fanFault || tempFault ||
210 pgoodFault || mfrFault);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600211 }
212
213 /**
Brandon Wymanb76ab242020-09-16 18:06:06 -0500214 * @brief Return whether a fault has been logged for this power supply
215 */
216 bool isFaultLogged() const
217 {
218 return faultLogged;
219 }
220
221 /**
222 * @brief Called when a fault for this power supply has been logged.
223 */
224 void setFaultLogged()
225 {
226 faultLogged = true;
227 }
228
229 /**
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600230 * @brief Returns true if INPUT fault occurred.
231 */
232 bool hasInputFault() const
233 {
234 return inputFault;
235 }
236
237 /**
238 * @brief Returns true if MFRSPECIFIC occurred.
239 */
240 bool hasMFRFault() const
241 {
242 return mfrFault;
243 }
244
245 /**
246 * @brief Returns true if VIN_UV_FAULT occurred.
247 */
248 bool hasVINUVFault() const
249 {
250 return vinUVFault;
251 }
252
Brandon Wymanc9efe412020-10-09 15:42:50 -0500253 /**
Brandon Wyman6710ba22021-10-27 17:39:31 +0000254 * @brief Returns true if VOUT_OV_FAULT occurred.
255 */
256 bool hasVoutOVFault() const
257 {
258 return voutOVFault;
259 }
260
261 /**
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000262 * @brief Returns true if IOUT_OC fault occurred (bit 4 STATUS_BYTE).
263 */
264 bool hasIoutOCFault() const
265 {
266 return ioutOCFault;
267 }
268
269 /**
Brandon Wyman2cf46942021-10-28 19:09:16 +0000270 * @brief Returns true if VOUT_UV_FAULT occurred.
271 */
272 bool hasVoutUVFault() const
273 {
274 return voutUVFault;
275 }
276
277 /**
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000278 *@brief Returns true if fan fault occurred.
279 */
280 bool hasFanFault() const
281 {
282 return fanFault;
283 }
284
285 /**
Brandon Wyman96893a42021-11-05 19:56:57 +0000286 * @brief Returns true if TEMPERATURE fault occurred.
287 */
288 bool hasTempFault() const
289 {
290 return tempFault;
291 }
292
293 /**
Brandon Wyman2916ea52021-11-06 03:31:18 +0000294 * @brief Returns true if there is a PGood fault (PGOOD# inactive, or OFF
295 * bit on).
296 */
297 bool hasPgoodFault() const
298 {
299 return pgoodFault;
300 }
301
302 /**
Brandon Wymanc9efe412020-10-09 15:42:50 -0500303 * @brief Returns the device path
304 *
305 * This can be used for error call outs.
306 * Example: /sys/bus/i2c/devices/3-0068
307 */
Brandon Wyman4176d6b2020-10-07 17:41:06 -0500308 const std::string getDevicePath() const
309 {
310 return pmbusIntf->path();
311 }
312
Brandon Wymanc9efe412020-10-09 15:42:50 -0500313 /**
314 * @brief Returns this power supplies inventory path.
315 *
316 * This can be used for error call outs.
317 * Example:
318 * /xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply1
319 */
Brandon Wyman7e495272020-09-26 19:57:46 -0500320 const std::string& getInventoryPath() const
321 {
322 return inventoryPath;
323 }
324
Brandon Wymanc9efe412020-10-09 15:42:50 -0500325 /**
326 * @brief Returns the firmware revision version read from the power supply
327 */
328 const std::string& getFWVersion() const
329 {
330 return fwVersion;
331 }
332
Adriana Kobylak572a9052021-03-30 15:58:07 +0000333 /**
334 * @brief Returns the model name of the power supply
335 */
336 const std::string& getModelName() const
337 {
338 return modelName;
339 }
340
Brandon Wymanf65c4062020-08-19 13:15:53 -0500341 /** @brief Returns true if the number of failed reads exceeds limit
342 * TODO: or CML bit on.
343 */
344 bool hasCommFault() const
345 {
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000346 return ((readFail >= LOG_LIMIT) || (cmlFault));
Brandon Wymanf65c4062020-08-19 13:15:53 -0500347 }
348
Adriana Kobylak4175ffb2021-08-02 14:51:05 +0000349 /**
350 * @brief Reads the pmbus input voltage and returns that actual voltage
351 * reading and the calculated input voltage based on thresholds.
352 * @param[out] actualInputVoltage - The actual voltage reading, in Volts.
353 * @param[out] inputVoltage - A rounded up/down value of the actual input
354 * voltage based on thresholds, in Volts.
355 */
356 void getInputVoltage(double& actualInputVoltage, int& inputVoltage) const;
357
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500358 private:
Brandon Wymanaed1f752019-11-25 18:10:52 -0600359 /** @brief systemd bus member */
360 sdbusplus::bus::bus& bus;
361
Brandon Wyman9564e942020-11-10 14:01:42 -0600362 /** @brief Will be updated to the latest/lastvalue read from STATUS_WORD.*/
Brandon Wymanfed0ba22020-09-26 20:02:51 -0500363 uint64_t statusWord = 0;
364
Brandon Wymanf07bc792021-10-12 19:00:35 +0000365 /** @brief Will be updated to the latest/lastvalue read from STATUS_INPUT.*/
366 uint64_t statusInput = 0;
367
Jay Meyer10d94052020-11-30 14:41:21 -0600368 /** @brief Will be updated to the latest/lastvalue read from STATUS_MFR.*/
369 uint64_t statusMFR = 0;
370
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000371 /** @brief Will be updated to the latest/last value read from STATUS_CML.*/
372 uint64_t statusCML = 0;
373
Brandon Wyman6710ba22021-10-27 17:39:31 +0000374 /** @brief Will be updated to the latest/last value read from STATUS_VOUT.*/
375 uint64_t statusVout = 0;
376
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000377 /** @brief Will be updated to the latest/last value read from STATUS_IOUT.*/
378 uint64_t statusIout = 0;
379
Brandon Wyman96893a42021-11-05 19:56:57 +0000380 /** @brief Will be updated to the latest/last value read from
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000381 * STATUS_FANS_1_2. */
382 uint64_t statusFans12 = 0;
383
384 /** @brief Will be updated to the latest/last value read from
Brandon Wyman96893a42021-11-05 19:56:57 +0000385 * STATUS_TEMPERATURE.*/
386 uint64_t statusTemperature = 0;
387
Brandon Wymanb76ab242020-09-16 18:06:06 -0500388 /** @brief True if an error for a fault has already been logged. */
389 bool faultLogged = false;
390
Brandon Wyman96893a42021-11-05 19:56:57 +0000391 /** @brief True if bit 1 of STATUS_WORD low byte is on. */
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000392 bool cmlFault = false;
393
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600394 /** @brief True if bit 5 of STATUS_WORD high byte is on. */
395 bool inputFault = false;
396
397 /** @brief True if bit 4 of STATUS_WORD high byte is on. */
398 bool mfrFault = false;
399
400 /** @brief True if bit 3 of STATUS_WORD low byte is on. */
401 bool vinUVFault = false;
402
Brandon Wyman6710ba22021-10-27 17:39:31 +0000403 /** @brief True if bit 5 of STATUS_WORD low byte is on. */
404 bool voutOVFault = false;
405
Brandon Wymanb10b3be2021-11-09 22:12:15 +0000406 /** @brief True if bit 4 of STATUS_WORD low byte is on. */
407 bool ioutOCFault = false;
408
Brandon Wyman2cf46942021-10-28 19:09:16 +0000409 /** @brief True if bit 7 of STATUS_WORD high byte is on and bit 5 (VOUT_OV)
410 * of low byte is off. */
411 bool voutUVFault = false;
412
Brandon Wyman7ee4d7e2021-11-19 20:48:23 +0000413 /** @brief True if FANS fault/warn bit on in STATUS_WORD. */
414 bool fanFault = false;
415
Brandon Wyman96893a42021-11-05 19:56:57 +0000416 /** @brief True if bit 2 of STATUS_WORD low byte is on. */
417 bool tempFault = false;
418
Brandon Wyman2cf46942021-10-28 19:09:16 +0000419 /**
420 * @brief True if bit 11 or 6 of STATUS_WORD is on. PGOOD# is inactive, or
Brandon Wyman2916ea52021-11-06 03:31:18 +0000421 * the unit is off.
422 */
423 bool pgoodFault = false;
424
Brandon Wymanf65c4062020-08-19 13:15:53 -0500425 /** @brief Count of the number of read failures. */
426 size_t readFail = 0;
427
Brandon Wymanaed1f752019-11-25 18:10:52 -0600428 /**
429 * @brief D-Bus path to use for this power supply's inventory status.
430 **/
431 std::string inventoryPath;
432
B. J. Wyman681b2a32021-04-20 22:31:22 +0000433 /**
434 * @brief The libgpiod object for monitoring PSU presence
435 */
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000436 std::unique_ptr<GPIOInterfaceBase> presenceGPIO = nullptr;
B. J. Wyman681b2a32021-04-20 22:31:22 +0000437
Brandon Wymanaed1f752019-11-25 18:10:52 -0600438 /** @brief True if the power supply is present. */
439 bool present = false;
440
Adriana Kobylak572a9052021-03-30 15:58:07 +0000441 /** @brief Power supply model name. */
442 std::string modelName;
443
Brandon Wymanaed1f752019-11-25 18:10:52 -0600444 /** @brief D-Bus match variable used to subscribe to Present property
445 * changes.
446 **/
447 std::unique_ptr<sdbusplus::bus::match_t> presentMatch;
448
449 /** @brief D-Bus match variable used to subscribe for Present property
450 * interface added.
451 */
452 std::unique_ptr<sdbusplus::bus::match_t> presentAddedMatch;
453
454 /**
Brandon Wyman8d195772020-01-27 15:03:51 -0600455 * @brief Pointer to the PMBus interface
456 *
457 * Used to read or write to/from PMBus power supply devices.
458 */
Brandon Wyman9564e942020-11-10 14:01:42 -0600459 std::unique_ptr<phosphor::pmbus::PMBusBase> pmbusIntf = nullptr;
Brandon Wyman8d195772020-01-27 15:03:51 -0600460
Brandon Wymanc9efe412020-10-09 15:42:50 -0500461 /** @brief Stored copy of the firmware version/revision string */
462 std::string fwVersion;
463
Brandon Wyman8d195772020-01-27 15:03:51 -0600464 /**
B. J. Wyman681b2a32021-04-20 22:31:22 +0000465 * @brief The file system path used for binding the device driver.
466 */
467 const std::filesystem::path bindPath;
468
469 /* @brief The string to pass in for binding the device driver. */
470 std::string bindDevice;
471
472 /**
473 * @brief Binds or unbinds the power supply device driver
474 *
475 * Called when a presence change is detected to either bind the device
476 * driver for the power supply when it is installed, or unbind the device
477 * driver when the power supply is removed.
478 *
479 * Writes <device> to <path>/bind (or unbind)
480 *
481 * @param present - when true, will bind the device driver
482 * when false, will unbind the device driver
483 */
484 void bindOrUnbindDriver(bool present);
485
486 /**
Brandon Wymanaed1f752019-11-25 18:10:52 -0600487 * @brief Updates the presence status by querying D-Bus
488 *
489 * The D-Bus inventory properties for this power supply will be read to
490 * determine if the power supply is present or not and update this
491 * object's present member variable to reflect current status.
492 **/
493 void updatePresence();
494
495 /**
B. J. Wyman681b2a32021-04-20 22:31:22 +0000496 * @brief Updates the power supply presence by reading the GPIO line.
497 */
498 void updatePresenceGPIO();
499
500 /**
Brandon Wymanaed1f752019-11-25 18:10:52 -0600501 * @brief Callback for inventory property changes
502 *
503 * Process change of Present property for power supply.
504 *
B. J. Wyman681b2a32021-04-20 22:31:22 +0000505 * This is used if we are watching the D-Bus properties instead of reading
506 * the GPIO presence line ourselves.
507 *
Brandon Wymanaed1f752019-11-25 18:10:52 -0600508 * @param[in] msg - Data associated with Present change signal
509 **/
510 void inventoryChanged(sdbusplus::message::message& msg);
Brandon Wyman9a507db2021-02-25 16:15:22 -0600511
512 /**
513 * @brief Callback for inventory property added.
514 *
515 * Process add of the interface with the Present property for power supply.
516 *
B. J. Wyman681b2a32021-04-20 22:31:22 +0000517 * This is used if we are watching the D-Bus properties instead of reading
518 * the GPIO presence line ourselves.
519 *
Brandon Wyman9a507db2021-02-25 16:15:22 -0600520 * @param[in] msg - Data associated with Present add signal
521 **/
522 void inventoryAdded(sdbusplus::message::message& msg);
Brandon Wymana0f33ce2019-10-17 18:32:29 -0500523};
524
525} // namespace phosphor::power::psu