1 #pragma once
2 
3 #include "pmbus.hpp"
4 #include "types.hpp"
5 #include "utility.hpp"
6 
7 #include <sdbusplus/bus/match.hpp>
8 
9 #include <stdexcept>
10 
11 namespace phosphor::power::psu
12 {
13 
14 #ifdef IBM_VPD
15 // PMBus device driver "file name" to read for CCIN value.
16 constexpr auto CCIN = "ccin";
17 constexpr auto PART_NUMBER = "part_number";
18 constexpr auto FRU_NUMBER = "fru";
19 constexpr auto SERIAL_HEADER = "header";
20 constexpr auto SERIAL_NUMBER = "serial_number";
21 constexpr auto FW_VERSION = "fw_version";
22 
23 // The D-Bus property name to update with the CCIN value.
24 constexpr auto MODEL_PROP = "Model";
25 constexpr auto PN_PROP = "PartNumber";
26 constexpr auto SN_PROP = "SerialNumber";
27 constexpr auto VERSION_PROP = "Version";
28 
29 // ipzVPD Keyword sizes
30 static constexpr auto FL_KW_SIZE = 20;
31 #endif
32 
33 /**
34  * @class PowerSupply
35  * Represents a PMBus power supply device.
36  */
37 class PowerSupply
38 {
39   public:
40     PowerSupply() = delete;
41     PowerSupply(const PowerSupply&) = delete;
42     PowerSupply(PowerSupply&&) = delete;
43     PowerSupply& operator=(const PowerSupply&) = delete;
44     PowerSupply& operator=(PowerSupply&&) = delete;
45     ~PowerSupply() = default;
46 
47     /**
48      * @param[in] invpath - String for inventory path to use
49      * @param[in] i2cbus - The bus number this power supply is on
50      * @param[in] i2caddr - The 16-bit I2C address of the power supply
51      */
52     PowerSupply(sdbusplus::bus::bus& bus, const std::string& invpath,
53                 std::uint8_t i2cbus, const std::string& i2caddr) :
54         bus(bus),
55         inventoryPath(invpath),
56         pmbusIntf(phosphor::pmbus::createPMBus(i2cbus, i2caddr))
57     {
58         if (inventoryPath.empty())
59         {
60             throw std::invalid_argument{"Invalid empty inventoryPath"};
61         }
62 
63         // Setup the functions to call when the D-Bus inventory path for the
64         // Present property changes.
65         presentMatch = std::make_unique<sdbusplus::bus::match_t>(
66             bus,
67             sdbusplus::bus::match::rules::propertiesChanged(inventoryPath,
68                                                             INVENTORY_IFACE),
69             [this](auto& msg) { this->inventoryChanged(msg); });
70         presentAddedMatch = std::make_unique<sdbusplus::bus::match_t>(
71             bus,
72             sdbusplus::bus::match::rules::interfacesAdded() +
73                 sdbusplus::bus::match::rules::path_namespace(inventoryPath),
74             [this](auto& msg) { this->inventoryChanged(msg); });
75         // Get the current state of the Present property.
76         updatePresence();
77     }
78 
79     phosphor::pmbus::PMBusBase& getPMBus()
80     {
81         return *pmbusIntf;
82     }
83 
84     /**
85      * Power supply specific function to analyze for faults/errors.
86      *
87      * Various PMBus status bits will be checked for fault conditions.
88      * If a certain fault bits are on, the appropriate error will be
89      * committed.
90      */
91     void analyze();
92 
93     /**
94      * Write PMBus ON_OFF_CONFIG
95      *
96      * This function will be called to cause the PMBus device driver to send the
97      * ON_OFF_CONFIG command. Takes one byte of data.
98      *
99      * @param[in] data - The ON_OFF_CONFIG data byte mask.
100      */
101     void onOffConfig(uint8_t data);
102 
103     /**
104      * Write PMBus CLEAR_FAULTS
105      *
106      * This function will be called in various situations in order to clear
107      * any fault status bits that may have been set, in order to start over
108      * with a clean state. Presence changes and power state changes will
109      * want to clear any faults logged.
110      */
111     void clearFaults();
112 
113     /**
114      * @brief Adds properties to the inventory.
115      *
116      * Reads the values from the device and writes them to the
117      * associated power supply D-Bus inventory object.
118      *
119      * This needs to be done on startup, and each time the presence
120      * state changes.
121      *
122      * Properties added:
123      * - Serial Number
124      * - Part Number
125      * - CCIN (Customer Card Identification Number) - added as the Model
126      * - Firmware version
127      */
128     void updateInventory();
129 
130     /**
131      * @brief Accessor function to indicate present status
132      */
133     bool isPresent() const
134     {
135         return present;
136     }
137 
138     /**
139      * @brief Returns true if a fault was found.
140      */
141     bool isFaulted() const
142     {
143         return faultFound;
144     }
145 
146     /**
147      * @brief Returns true if INPUT fault occurred.
148      */
149     bool hasInputFault() const
150     {
151         return inputFault;
152     }
153 
154     /**
155      * @brief Returns true if MFRSPECIFIC occurred.
156      */
157     bool hasMFRFault() const
158     {
159         return mfrFault;
160     }
161 
162     /**
163      * @brief Returns true if VIN_UV_FAULT occurred.
164      */
165     bool hasVINUVFault() const
166     {
167         return vinUVFault;
168     }
169 
170   private:
171     /** @brief systemd bus member */
172     sdbusplus::bus::bus& bus;
173 
174     /** @brief True if a fault has already been found and not cleared */
175     bool faultFound = false;
176 
177     /** @brief True if bit 5 of STATUS_WORD high byte is on. */
178     bool inputFault = false;
179 
180     /** @brief True if bit 4 of STATUS_WORD high byte is on. */
181     bool mfrFault = false;
182 
183     /** @brief True if bit 3 of STATUS_WORD low byte is on. */
184     bool vinUVFault = false;
185 
186     /**
187      * @brief D-Bus path to use for this power supply's inventory status.
188      **/
189     std::string inventoryPath;
190 
191     /** @brief True if the power supply is present. */
192     bool present = false;
193 
194     /** @brief D-Bus match variable used to subscribe to Present property
195      * changes.
196      **/
197     std::unique_ptr<sdbusplus::bus::match_t> presentMatch;
198 
199     /** @brief D-Bus match variable used to subscribe for Present property
200      * interface added.
201      */
202     std::unique_ptr<sdbusplus::bus::match_t> presentAddedMatch;
203 
204     /**
205      * @brief Pointer to the PMBus interface
206      *
207      * Used to read or write to/from PMBus power supply devices.
208      */
209     std::unique_ptr<phosphor::pmbus::PMBusBase> pmbusIntf;
210 
211     /**
212      *  @brief Updates the presence status by querying D-Bus
213      *
214      * The D-Bus inventory properties for this power supply will be read to
215      * determine if the power supply is present or not and update this
216      * object's present member variable to reflect current status.
217      **/
218     void updatePresence();
219 
220     /**
221      * @brief Callback for inventory property changes
222      *
223      * Process change of Present property for power supply.
224      *
225      * @param[in]  msg - Data associated with Present change signal
226      **/
227     void inventoryChanged(sdbusplus::message::message& msg);
228 };
229 
230 } // namespace phosphor::power::psu
231