cpld: Virtualize CpldLatticeManager for XO3/XO5 separation
This change makes `CpldLatticeManager` a virtual base class, allowing
other classes to inherit from it. This refactoring enables a cleaner
separation of XO3 and XO5 implementations while sharing common CPLD
management logic.
Test on harma:
```
1. Check firmware info
curl -k -u root:0penBmc -X GET
https://10.10.15.8/redfish/v1/UpdateService/FirmwareInventory/Harma_MB_CPLD_5688
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/Harma_MB_CPLD_5688",
"@odata.type": "#SoftwareInventory.v1_1_0.SoftwareInventory",
"Description": "Unknown image",
"Id": "Harma_MB_CPLD_5688",
"Name": "Software Inventory",
"Status": {
"Health": "OK",
"HealthRollup": "OK",
"State": "Enabled"
},
"Updateable": true,
"Version": "00000220"
}
2. Trigger Update
curl -k -u root:0penBmc \
-H "Content-Type:multipart/form-data" \
-X POST \
-F UpdateParameters="{\"Targets\":[\"${targetpath}\"], \
\"@Redfish.OperationApplyTime\":\"Immediate\"};type=application/json" \
-F "UpdateFile=@${fwpath};type=application/octet-stream" \
https://${bmc}/redfish/v1/UpdateService/update-multipart
{
"@odata.id": "/redfish/v1/TaskService/Tasks/0",
"@odata.type": "#Task.v1_4_3.Task",
"HidePayload": false,
"Id": "0",
"Messages": [
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "The task with Id '0' has started.",
"MessageArgs": [
"0"
],
"MessageId": "TaskEvent.1.0.TaskStarted",
"MessageSeverity": "OK",
"Resolution": "None."
}
],
"Name": "Task 0",
"Payload": {
"HttpHeaders": [],
"HttpOperation": "POST",
"TargetUri": "/redfish/v1/UpdateService/update-multipart"
},
"PercentComplete": 0,
"StartTime": "2025-08-13T07:22:06+00:00",
"TaskMonitor": "/redfish/v1/TaskService/TaskMonitors/0",
"TaskState": "Running",
"TaskStatus": "OK"
}
3. After AC cycle check firmware info again
curl -k -u root:0penBmc -X GET
https://10.10.15.8/redfish/v1/UpdateService/FirmwareInventory/Harma_MB_CPLD_5688
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/Harma_MB_CPLD_5688",
"@odata.type": "#SoftwareInventory.v1_1_0.SoftwareInventory",
"Description": "Unknown image",
"Id": "Harma_MB_CPLD_5688",
"Name": "Software Inventory",
"Status": {
"Health": "OK",
"HealthRollup": "OK",
"State": "Enabled"
},
"Updateable": true,
"Version": "00000224"
}
```
Change-Id: Ic7265dbeeb9f93d4f466cba75ca38fc86342c689
Signed-off-by: Daniel Hsu <Daniel-Hsu@quantatw.com>
diff --git a/cpld/lattice/lattice_cpld_factory.cpp b/cpld/lattice/lattice_cpld_factory.cpp
new file mode 100644
index 0000000..ab0cb85
--- /dev/null
+++ b/cpld/lattice/lattice_cpld_factory.cpp
@@ -0,0 +1,91 @@
+#include "lattice_cpld_factory.hpp"
+
+#include "lattice_xo3_cpld.hpp"
+
+#include <phosphor-logging/lg2.hpp>
+
+namespace phosphor::software::cpld
+{
+
+std::unique_ptr<LatticeBaseCPLD> LatticeCPLDFactory::getLatticeCPLD()
+{
+ if (supportedDeviceMap.find(chipEnum) == supportedDeviceMap.end())
+ {
+ // invalid
+ lg2::error("Unsupported Lattice CPLD chip enum: {CHIPENUM}", "CHIPENUM",
+ chipEnum);
+ return nullptr;
+ }
+
+ auto chipFamily = supportedDeviceMap.at(chipEnum).chipFamily;
+ auto chipModelStr =
+ getLatticeChipStr(chipEnum, latticeStringType::modelString);
+ switch (chipFamily)
+ {
+ case latticeChipFamily::XO2:
+ case latticeChipFamily::XO3:
+ return std::make_unique<LatticeXO3CPLD>(
+ CPLDInterface::ctx, CPLDInterface::bus, CPLDInterface::address,
+ chipModelStr, "CFG0", false);
+ default:
+ lg2::error("Unsupported Lattice CPLD chip family: {CHIPMODEL}",
+ "CHIPMODEL", chipModelStr);
+ return nullptr;
+ }
+}
+
+sdbusplus::async::task<bool> LatticeCPLDFactory::updateFirmware(
+ bool /*force*/, const uint8_t* image, size_t imageSize,
+ std::function<bool(int)> progressCallBack)
+{
+ lg2::info("Updating Lattice CPLD firmware");
+ auto cpldManager = getLatticeCPLD();
+ if (cpldManager == nullptr)
+ {
+ lg2::error("CPLD manager is not initialized.");
+ co_return false;
+ }
+ co_return co_await cpldManager->updateFirmware(image, imageSize,
+ progressCallBack);
+}
+
+sdbusplus::async::task<bool> LatticeCPLDFactory::getVersion(
+ std::string& version)
+{
+ lg2::info("Getting Lattice CPLD version");
+ auto cpldManager = getLatticeCPLD();
+ if (cpldManager == nullptr)
+ {
+ lg2::error("CPLD manager is not initialized.");
+ co_return false;
+ }
+ co_return co_await cpldManager->getVersion(version);
+}
+
+} // namespace phosphor::software::cpld
+
+// Factory function to create lattice CPLD device
+namespace
+{
+using namespace phosphor::software::cpld;
+
+// Register all the CPLD type with the CPLD factory
+const bool vendorRegistered = [] {
+ for (const auto& [chipEnum, info] : supportedDeviceMap)
+ {
+ auto typeStr =
+ getLatticeChipStr(chipEnum, latticeStringType::typeString);
+ CPLDFactory::instance().registerCPLD(
+ typeStr, [chipEnum](sdbusplus::async::context& ctx,
+ const std::string& chipName, uint16_t bus,
+ uint8_t address) {
+ // Create and return a LatticeCPLD instance
+ // Pass the parameters to the constructor
+ return std::make_unique<LatticeCPLDFactory>(
+ ctx, chipName, chipEnum, bus, address);
+ });
+ }
+ return true;
+}();
+
+} // namespace