xref: /openbmc/phosphor-bmc-code-mgmt/eeprom-device/eeprom_device_software_manager.cpp (revision 37a301437cd5dfcd36dc8ecb1769163b262493b4)
1 #include "eeprom_device_software_manager.hpp"
2 
3 #include "common/include/dbus_helper.hpp"
4 #include "eeprom_device.hpp"
5 
6 #include <phosphor-logging/lg2.hpp>
7 #include <sdbusplus/async.hpp>
8 #include <xyz/openbmc_project/ObjectMapper/client.hpp>
9 
10 #include <fstream>
11 #include <optional>
12 #include <sstream>
13 
14 PHOSPHOR_LOG2_USING;
15 
16 namespace SoftwareInf = phosphor::software;
17 
18 const std::vector<std::string> emConfigTypes = {"PT5161LFirmware"};
19 
20 void EEPROMDeviceSoftwareManager::start()
21 {
22     std::vector<std::string> configIntfs;
23     configIntfs.reserve(emConfigTypes.size());
24 
25     std::transform(emConfigTypes.begin(), emConfigTypes.end(),
26                    std::back_inserter(configIntfs),
27                    [](const std::string& type) {
28                        return "xyz.openbmc_project.Configuration." + type;
29                    });
30 
31     ctx.spawn(initDevices(configIntfs));
32     ctx.run();
33 }
34 
35 sdbusplus::async::task<bool> EEPROMDeviceSoftwareManager::initDevice(
36     const std::string& service, const std::string& path, SoftwareConfig& config)
37 {
38     const std::string configIface =
39         "xyz.openbmc_project.Configuration." + config.configType;
40 
41     std::optional<uint64_t> bus = co_await dbusGetRequiredProperty<uint64_t>(
42         ctx, service, path, configIface, "Bus");
43 
44     std::optional<uint64_t> address =
45         co_await dbusGetRequiredProperty<uint64_t>(ctx, service, path,
46                                                    configIface, "Address");
47 
48     std::optional<std::string> type =
49         co_await dbusGetRequiredProperty<std::string>(ctx, service, path,
50                                                       configIface, "Type");
51 
52     std::optional<std::string> fwDevice =
53         co_await dbusGetRequiredProperty<std::string>(
54             ctx, service, path, configIface, "FirmwareDevice");
55 
56     if (!bus.has_value() || !address.has_value() || !type.has_value() ||
57         !fwDevice.has_value())
58     {
59         error("Missing EEPROM device config property");
60         co_return false;
61     }
62 
63     debug("EEPROM Device: Bus={BUS}, Address={ADDR}, Type={TYPE}, "
64           "Firmware Device={DEVICE}",
65           "BUS", bus.value(), "ADDR", address.value(), "TYPE", type.value(),
66           "DEVICE", fwDevice.value());
67 
68     std::unique_ptr<DeviceVersion> deviceVersion =
69         getVersionProvider(type.value(), bus.value(), address.value());
70 
71     if (!deviceVersion)
72     {
73         error("Failed to get version provider for chip type: {CHIP}", "CHIP",
74               type.value());
75         co_return false;
76     }
77 
78     std::string version = deviceVersion->getVersion();
79 
80     using ObjectMapper =
81         sdbusplus::client::xyz::openbmc_project::ObjectMapper<>;
82 
83     auto mapper = ObjectMapper(ctx)
84                       .service(ObjectMapper::default_service)
85                       .path(ObjectMapper::instance_path);
86 
87     auto res =
88         co_await mapper.get_sub_tree("/xyz/openbmc_project/inventory", 0, {});
89 
90     bus.reset();
91     address.reset();
92     type.reset();
93 
94     for (auto& [p, v] : res)
95     {
96         if (!p.ends_with(fwDevice.value()))
97         {
98             continue;
99         }
100 
101         for (auto& [s, ifaces] : v)
102         {
103             for (std::string& iface : ifaces)
104             {
105                 if (iface.starts_with("xyz.openbmc_project.Configuration."))
106                 {
107                     bus = co_await dbusGetRequiredProperty<uint64_t>(
108                         ctx, s, p, iface, "Bus");
109 
110                     address = co_await dbusGetRequiredProperty<uint64_t>(
111                         ctx, s, p, iface, "Address");
112 
113                     type = co_await dbusGetRequiredProperty<std::string>(
114                         ctx, s, p, iface, "Type");
115                     break;
116                 }
117             }
118             if (bus.has_value() && address.has_value() && type.has_value())
119             {
120                 break;
121             }
122         }
123         break;
124     }
125 
126     if (!bus.has_value() || !address.has_value() || !type.has_value())
127     {
128         error("Missing EEPROM config property");
129         co_return false;
130     }
131 
132     debug("EEPROM: Bus={BUS}, Address={ADDR}, Type={TYPE}", "BUS", bus.value(),
133           "ADDR", address.value(), "TYPE", type.value());
134 
135     const std::string configIfaceMux = configIface + ".MuxOutputs";
136     std::vector<std::string> gpioLines;
137     std::vector<bool> gpioPolarities;
138 
139     for (size_t i = 0; true; i++)
140     {
141         const std::string iface = configIfaceMux + std::to_string(i);
142 
143         std::optional<std::string> name =
144             co_await dbusGetRequiredProperty<std::string>(ctx, service, path,
145                                                           iface, "Name");
146 
147         std::optional<std::string> polarity =
148             co_await dbusGetRequiredProperty<std::string>(ctx, service, path,
149                                                           iface, "Polarity");
150 
151         if (!name.has_value() || !polarity.has_value())
152         {
153             break;
154         }
155 
156         gpioLines.push_back(name.value());
157         gpioPolarities.push_back(polarity.value() == "High");
158     }
159 
160     for (size_t i = 0; i < gpioLines.size(); i++)
161     {
162         debug("Mux gpio {NAME} polarity = {VALUE}", "NAME", gpioLines[i],
163               "VALUE", gpioPolarities[i]);
164     }
165 
166     auto eepromDevice = std::make_unique<EEPROMDevice>(
167         ctx, static_cast<uint16_t>(bus.value()),
168         static_cast<uint8_t>(address.value()), type.value(), gpioLines,
169         gpioPolarities, std::move(deviceVersion), config, this);
170 
171     std::unique_ptr<SoftwareInf::Software> software =
172         std::make_unique<SoftwareInf::Software>(ctx, *eepromDevice);
173 
174     software->setVersion(version.empty() ? "Unknown" : version);
175 
176     std::set<RequestedApplyTimes> allowedApplyTimes = {
177         RequestedApplyTimes::Immediate, RequestedApplyTimes::OnReset};
178 
179     software->enableUpdate(allowedApplyTimes);
180 
181     eepromDevice->softwareCurrent = std::move(software);
182 
183     devices.insert({config.objectPath, std::move(eepromDevice)});
184 
185     co_return true;
186 }
187 
188 int main()
189 {
190     sdbusplus::async::context ctx;
191 
192     EEPROMDeviceSoftwareManager eepromDeviceSoftwareManager(ctx);
193 
194     eepromDeviceSoftwareManager.start();
195     return 0;
196 }
197