xref: /openbmc/phosphor-power/phosphor-power-sequencer/test/ucd90160_device_tests.cpp (revision 7b7a5632c594d60f4620ca14379a766a56faf846)
1 /**
2  * Copyright © 2024 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "mock_pmbus.hpp"
18 #include "mock_services.hpp"
19 #include "pmbus.hpp"
20 #include "rail.hpp"
21 #include "services.hpp"
22 #include "ucd90160_device.hpp"
23 
24 #include <cstdint>
25 #include <map>
26 #include <memory>
27 #include <optional>
28 #include <string>
29 #include <utility>
30 #include <vector>
31 
32 #include <gmock/gmock.h>
33 #include <gtest/gtest.h>
34 
35 using namespace phosphor::power::sequencer;
36 using namespace phosphor::pmbus;
37 
38 using ::testing::Return;
39 
40 /**
41  * Creates a Rail object that checks for a pgood fault using a GPIO.
42  *
43  * @param name Unique name for the rail
44  * @param gpio GPIO line to read to determine the pgood status of the rail
45  * @return Rail object
46  */
47 static std::unique_ptr<Rail> createRail(const std::string& name,
48                                         unsigned int gpioLine)
49 {
50     std::optional<std::string> presence{};
51     std::optional<uint8_t> page{};
52     bool isPowerSupplyRail{false};
53     bool checkStatusVout{false};
54     bool compareVoltageToLimit{false};
55     bool activeLow{false};
56     std::optional<PgoodGPIO> gpio{PgoodGPIO{gpioLine, activeLow}};
57     return std::make_unique<Rail>(name, presence, page, isPowerSupplyRail,
58                                   checkStatusVout, compareVoltageToLimit, gpio);
59 }
60 
61 TEST(UCD90160DeviceTests, Constructor)
62 {
63     MockServices services;
64 
65     uint8_t bus{3};
66     uint16_t address{0x72};
67     std::string powerControlGPIOName{"power-chassis-control"};
68     std::string powerGoodGPIOName{"power-chassis-good"};
69     std::vector<std::unique_ptr<Rail>> rails;
70     rails.emplace_back(createRail("VDD", 5));
71     rails.emplace_back(createRail("VIO", 7));
72     UCD90160Device device{bus,
73                           address,
74                           powerControlGPIOName,
75                           powerGoodGPIOName,
76                           std::move(rails),
77                           services};
78 
79     EXPECT_EQ(device.getName(), "UCD90160");
80     EXPECT_EQ(device.getBus(), bus);
81     EXPECT_EQ(device.getAddress(), address);
82     EXPECT_EQ(device.getPowerControlGPIOName(), powerControlGPIOName);
83     EXPECT_EQ(device.getPowerGoodGPIOName(), powerGoodGPIOName);
84     EXPECT_EQ(device.getRails().size(), 2);
85     EXPECT_EQ(device.getRails()[0]->getName(), "VDD");
86     EXPECT_EQ(device.getRails()[1]->getName(), "VIO");
87     EXPECT_EQ(device.getDriverName(), "ucd9000");
88     EXPECT_EQ(device.getInstance(), 0);
89     EXPECT_NE(&(device.getPMBusInterface()), nullptr);
90 }
91 
92 TEST(UCD90160DeviceTests, StoreGPIOValues)
93 {
94     // This is a protected method and cannot be called directly from a gtest.
95     // Call findPgoodFault() which calls storeGPIOValues().
96 
97     // Test where works
98     {
99         std::vector<int> gpioValues{
100             1, 0, 0, 1, // group 1 in journal
101             1, 1, 0, 0, // group 2 in journal
102             1, 0, 1, 1, // group 3 in journal
103             0, 0, 1, 1, // group 4 in journal
104             1, 0, 0, 0, // group 5 in journal
105             1, 0, 0, 1, // group 6 in journal
106             1, 1        // group 7 in journal
107         };
108 
109         MockServices services;
110         EXPECT_CALL(services, getGPIOValues("ucd90160"))
111             .Times(1)
112             .WillOnce(Return(gpioValues));
113         EXPECT_CALL(services, logInfoMsg("Device UCD90160 GPIO values:"))
114             .Times(1);
115         EXPECT_CALL(services,
116                     logInfoMsg(
117                         "[FPWM1_GPIO5, FPWM2_GPIO6, FPWM3_GPIO7, FPWM4_GPIO8]: "
118                         "[1, 0, 0, 1]"))
119             .Times(1);
120         EXPECT_CALL(
121             services,
122             logInfoMsg(
123                 "[FPWM5_GPIO9, FPWM6_GPIO10, FPWM7_GPIO11, FPWM8_GPIO12]: "
124                 "[1, 1, 0, 0]"))
125             .Times(1);
126         EXPECT_CALL(services,
127                     logInfoMsg("[GPI1_PWM1, GPI2_PWM2, GPI3_PWM3, GPI4_PWM4]: "
128                                "[1, 0, 1, 1]"))
129             .Times(1);
130         EXPECT_CALL(services,
131                     logInfoMsg("[GPIO14, GPIO15, TDO_GPIO20, TCK_GPIO19]: "
132                                "[0, 0, 1, 1]"))
133             .Times(1);
134         EXPECT_CALL(services,
135                     logInfoMsg("[TMS_GPIO22, TDI_GPIO21, GPIO1, GPIO2]: "
136                                "[1, 0, 0, 0]"))
137             .Times(1);
138         EXPECT_CALL(services, logInfoMsg("[GPIO3, GPIO4, GPIO13, GPIO16]: "
139                                          "[1, 0, 0, 1]"))
140             .Times(1);
141         EXPECT_CALL(services, logInfoMsg("[GPIO17, GPIO18]: "
142                                          "[1, 1]"))
143             .Times(1);
144         EXPECT_CALL(services,
145                     logInfoMsg("Device UCD90160 MFR_STATUS: 0x123456789abc"))
146             .Times(1);
147         EXPECT_CALL(
148             services,
149             logErrorMsg(
150                 "Pgood fault found in rail monitored by device UCD90160"))
151             .Times(1);
152         EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD"))
153             .Times(1);
154         EXPECT_CALL(
155             services,
156             logErrorMsg(
157                 "Rail VDD pgood GPIO line offset 2 has inactive value 0"))
158             .Times(1);
159 
160         uint8_t bus{3};
161         uint16_t address{0x72};
162         std::string powerControlGPIOName{"power-chassis-control"};
163         std::string powerGoodGPIOName{"power-chassis-good"};
164         std::vector<std::unique_ptr<Rail>> rails;
165         rails.emplace_back(createRail("VDD", 2));
166         UCD90160Device device{bus,
167                               address,
168                               powerControlGPIOName,
169                               powerGoodGPIOName,
170                               std::move(rails),
171                               services};
172 
173         MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
174         EXPECT_CALL(pmbus, getPath(Type::Hwmon))
175             .Times(1)
176             .WillOnce(Return("/tmp"));
177         EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true))
178             .Times(1)
179             .WillOnce(Return(0x123456789abcull));
180 
181         // Call findPgoodFault() which calls storeGPIOValues()
182         std::string powerSupplyError{};
183         std::map<std::string, std::string> additionalData{};
184         std::string error =
185             device.findPgoodFault(services, powerSupplyError, additionalData);
186         EXPECT_EQ(error,
187                   "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
188         EXPECT_EQ(additionalData.size(), 31);
189         EXPECT_EQ(additionalData["MFR_STATUS"], "0x123456789abc");
190         EXPECT_EQ(additionalData["DEVICE_NAME"], "UCD90160");
191         EXPECT_EQ(additionalData["FPWM1_GPIO5"], "1");
192         EXPECT_EQ(additionalData["FPWM2_GPIO6"], "0");
193         EXPECT_EQ(additionalData["FPWM3_GPIO7"], "0");
194         EXPECT_EQ(additionalData["FPWM4_GPIO8"], "1");
195         EXPECT_EQ(additionalData["FPWM5_GPIO9"], "1");
196         EXPECT_EQ(additionalData["FPWM6_GPIO10"], "1");
197         EXPECT_EQ(additionalData["FPWM7_GPIO11"], "0");
198         EXPECT_EQ(additionalData["FPWM8_GPIO12"], "0");
199         EXPECT_EQ(additionalData["GPI1_PWM1"], "1");
200         EXPECT_EQ(additionalData["GPI2_PWM2"], "0");
201         EXPECT_EQ(additionalData["GPI3_PWM3"], "1");
202         EXPECT_EQ(additionalData["GPI4_PWM4"], "1");
203         EXPECT_EQ(additionalData["GPIO14"], "0");
204         EXPECT_EQ(additionalData["GPIO15"], "0");
205         EXPECT_EQ(additionalData["TDO_GPIO20"], "1");
206         EXPECT_EQ(additionalData["TCK_GPIO19"], "1");
207         EXPECT_EQ(additionalData["TMS_GPIO22"], "1");
208         EXPECT_EQ(additionalData["TDI_GPIO21"], "0");
209         EXPECT_EQ(additionalData["GPIO1"], "0");
210         EXPECT_EQ(additionalData["GPIO2"], "0");
211         EXPECT_EQ(additionalData["GPIO3"], "1");
212         EXPECT_EQ(additionalData["GPIO4"], "0");
213         EXPECT_EQ(additionalData["GPIO13"], "0");
214         EXPECT_EQ(additionalData["GPIO16"], "1");
215         EXPECT_EQ(additionalData["GPIO17"], "1");
216         EXPECT_EQ(additionalData["GPIO18"], "1");
217         EXPECT_EQ(additionalData["RAIL_NAME"], "VDD");
218         EXPECT_EQ(additionalData["GPIO_LINE"], "2");
219         EXPECT_EQ(additionalData["GPIO_VALUE"], "0");
220     }
221 
222     // Test where there are the wrong number of GPIOs (27 instead of 26)
223     {
224         std::vector<int> gpioValues{
225             1, 0, 0, 1, // group 1 in journal
226             1, 1, 0, 0, // group 2 in journal
227             1, 0, 1, 1, // group 3 in journal
228             0, 0, 1, 1, // group 4 in journal
229             1, 0, 0, 0, // group 5 in journal
230             1, 0, 0, 1, // group 6 in journal
231             1, 1, 0     // group 7 in journal + extra value
232         };
233 
234         MockServices services;
235         EXPECT_CALL(services, getGPIOValues("ucd90160"))
236             .Times(1)
237             .WillOnce(Return(gpioValues));
238         EXPECT_CALL(services,
239                     logInfoMsg("Device UCD90160 GPIO values: ["
240                                "1, 0, 0, 1, "
241                                "1, 1, 0, 0, "
242                                "1, 0, 1, 1, "
243                                "0, 0, 1, 1, "
244                                "1, 0, 0, 0, "
245                                "1, 0, 0, 1, "
246                                "1, 1, 0]"))
247             .Times(1);
248         EXPECT_CALL(services,
249                     logInfoMsg("Device UCD90160 MFR_STATUS: 0x123456789abc"))
250             .Times(1);
251         EXPECT_CALL(
252             services,
253             logErrorMsg(
254                 "Pgood fault found in rail monitored by device UCD90160"))
255             .Times(1);
256         EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD"))
257             .Times(1);
258         EXPECT_CALL(
259             services,
260             logErrorMsg(
261                 "Rail VDD pgood GPIO line offset 2 has inactive value 0"))
262             .Times(1);
263 
264         uint8_t bus{3};
265         uint16_t address{0x72};
266         std::string powerControlGPIOName{"power-chassis-control"};
267         std::string powerGoodGPIOName{"power-chassis-good"};
268         std::vector<std::unique_ptr<Rail>> rails;
269         rails.emplace_back(createRail("VDD", 2));
270         UCD90160Device device{bus,
271                               address,
272                               powerControlGPIOName,
273                               powerGoodGPIOName,
274                               std::move(rails),
275                               services};
276 
277         MockPMBus& pmbus = static_cast<MockPMBus&>(device.getPMBusInterface());
278         EXPECT_CALL(pmbus, getPath(Type::Hwmon))
279             .Times(1)
280             .WillOnce(Return("/tmp"));
281         EXPECT_CALL(pmbus, read("mfr_status", Type::HwmonDeviceDebug, true))
282             .Times(1)
283             .WillOnce(Return(0x123456789abcull));
284 
285         // Call findPgoodFault() which calls storeGPIOValues()
286         std::string powerSupplyError{};
287         std::map<std::string, std::string> additionalData{};
288         std::string error =
289             device.findPgoodFault(services, powerSupplyError, additionalData);
290         EXPECT_EQ(error,
291                   "xyz.openbmc_project.Power.Error.PowerSequencerVoltageFault");
292         EXPECT_EQ(additionalData.size(), 6);
293         EXPECT_EQ(additionalData["MFR_STATUS"], "0x123456789abc");
294         EXPECT_EQ(additionalData["DEVICE_NAME"], "UCD90160");
295         EXPECT_EQ(additionalData["GPIO_VALUES"],
296                   "[1, 0, 0, 1, "
297                   "1, 1, 0, 0, "
298                   "1, 0, 1, 1, "
299                   "0, 0, 1, 1, "
300                   "1, 0, 0, 0, "
301                   "1, 0, 0, 1, "
302                   "1, 1, 0]");
303         EXPECT_EQ(additionalData["RAIL_NAME"], "VDD");
304         EXPECT_EQ(additionalData["GPIO_LINE"], "2");
305         EXPECT_EQ(additionalData["GPIO_VALUE"], "0");
306     }
307 }
308