fw-update: cpld code updater
This commit introduces a code updater for CPLD.
The Key features of this updater include:
- configuring chip vendor and name
- update CPLD through I2C
1. Display the fw inventory
curl ... -X GET
https://localhost/redfish/v1/UpdateService/FirmwareInventory
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory",
"@odata.type":
"#SoftwareInventoryCollection.SoftwareInventoryCollection",
"Members": [
...
{
"@odata.id": ".../LCMXO3LF_4300C_6194"
},
...
],
"Members@odata.count": 26,
"Name": "Software Inventory Collection"
}
2. Query CPLD version
curl ... -X GET
https://localhost/redfish/v1
/UpdateService/FirmwareInventory/LCMXO3LF_4300C_6194
{
"@odata.id": "/.../LCMXO3LF_4300C_6194",
"@odata.type":
"#SoftwareInventory.v1_1_0.SoftwareInventory",
"Description": "Unknown image",
"Id": "LCMXO3LF_4300C_6194",
"Name": "Software Inventory",
"Status": {
"Health": "Warning",
"HealthRollup": "OK",
"State": "Disabled"
},
"Updateable": false,
"Version": "00000220"
}
3. Trigger the fw update via redfish
curl -k
-H "X-Auth-Token: $token"
-H "Content-Type:multipart/form-data"
-X POST
-F UpdateParameters="{\"Targets\":
[\"/redfish/v1/UpdateService/FirmwareInventory/LCMXO3LF_4300C_6194\"],
\"@Redfish.OperationApplyTime\":\"Immediate\"};type=application/json"
-F "UpdateFile=@testcpld.pldm;type=application/octet-stream"
https://${bmc}/redfish/v1/UpdateService/update
{
"@odata.id": "/redfish/v1/TaskService/Tasks/0",
"@odata.type": "#Task.v1_4_3.Task",
"Id": "0",
"TaskState": "Running",
"TaskStatus": "OK"
}
4. Query Task status
curl ... -X GET
https://localhost/redfish/v1/TaskService/Tasks/0
{
"@odata.id": "/redfish/v1/TaskService/Tasks/0",
"@odata.type": "#Task.v1_4_3.Task",
"EndTime": "2025-05-28T08:10:22+00:00",
"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."
},
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "... progress 15 percent complete.",
"MessageArgs": [
"0",
"15"
],
"MessageId": "TaskEvent.1.0.TaskProgressChanged",
"MessageSeverity": "OK",
"Resolution": "None."
},
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "... progress 20 percent complete.",
"MessageArgs": [
"0",
"20"
],
"MessageId": "TaskEvent.1.0.TaskProgressChanged",
"MessageSeverity": "OK",
"Resolution": "None."
},
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "... progress 25 percent complete.",
"MessageArgs": [
"0",
"25"
],
"MessageId": "TaskEvent.1.0.TaskProgressChanged",
"MessageSeverity": "OK",
"Resolution": "None."
},
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "... progress 30 percent complete.",
"MessageArgs": [
"0",
"30"
],
"MessageId": "TaskEvent.1.0.TaskProgressChanged",
"MessageSeverity": "OK",
"Resolution": "None."
},
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "... progress 40 percent complete.",
"MessageArgs": [
"0",
"40"
],
"MessageId": "TaskEvent.1.0.TaskProgressChanged",
"MessageSeverity": "OK",
"Resolution": "None."
},
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "... progress 50 percent complete.",
"MessageArgs": [
"0",
"50"
],
"MessageId": "TaskEvent.1.0.TaskProgressChanged",
"MessageSeverity": "OK",
"Resolution": "None."
},
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "... progress 60 percent complete.",
"MessageArgs": [
"0",
"60"
],
"MessageId": "TaskEvent.1.0.TaskProgressChanged",
"MessageSeverity": "OK",
"Resolution": "None."
},
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "... progress 70 percent complete.",
"MessageArgs": [
"0",
"70"
],
"MessageId": "TaskEvent.1.0.TaskProgressChanged",
"MessageSeverity": "OK",
"Resolution": "None."
},
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "... progress 80 percent complete.",
"MessageArgs": [
"0",
"80"
],
"MessageId": "TaskEvent.1.0.TaskProgressChanged",
"MessageSeverity": "OK",
"Resolution": "None."
},
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "... progress 90 percent complete.",
"MessageArgs": [
"0",
"90"
],
"MessageId": "TaskEvent.1.0.TaskProgressChanged",
"MessageSeverity": "OK",
"Resolution": "None."
},
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "... progress 100 percent complete.",
"MessageArgs": [
"0",
"100"
],
"MessageId": "TaskEvent.1.0.TaskProgressChanged",
"MessageSeverity": "OK",
"Resolution": "None."
},
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "The task with Id '0' has completed.",
"MessageArgs": [
"0"
],
"MessageId": "TaskEvent.1.0.TaskCompletedOK",
"MessageSeverity": "OK",
"Resolution": "None."
}
],
"Name": "Task 0",
"Payload": {
"HttpHeaders": [],
"HttpOperation": "POST",
"JsonBody": "null",
"TargetUri": "/redfish/v1/UpdateService/update"
},
"PercentComplete": 100,
"StartTime": "2025-05-28T08:10:06+00:00",
"TaskMonitor": "/redfish/v1/TaskService/TaskMonitors/0",
"TaskState": "Completed",
"TaskStatus": "OK"
}
5. Display the fw inventory with newly updated fw.
curl ... -X GET
https://localhost/redfish/v1/UpdateService/FirmwareInventory
{
"@odata.id": "/redfish/v1/UpdateService/FirmwareInventory",
"@odata.type":
"#SoftwareInventoryCollection.SoftwareInventoryCollection",
"Members": [
...
{
"@odata.id": ".../LCMXO3LF_4300C_1571"
},
...
],
"Members@odata.count": 26,
"Name": "Software Inventory Collection"
}
6. Query CPLD version again
After AC cycle ..., so the number would be different.
curl ... -X GET
https://localhost/redfish/v1
/UpdateService/FirmwareInventory/LCMXO3LF_4300C_4643
{
"@odata.id": "/.../LCMXO3LF_4300C_4643",
"@odata.type": "#SoftwareInventory.v1_1_0.SoftwareInventory",
"Description": "Unknown image",
"Id": "LCMXO3LF_4300C_4643",
"Name": "Software Inventory",
"Status": {
"Health": "Warning",
"HealthRollup": "OK",
"State": "Disabled"
},
"Updateable": false,
"Version": "00000224"
}
Change-Id: Ife8e30a00bfbb307e6e4eb55838a397c8a8162bd
Signed-off-by: Daniel Hsu <Daniel-Hsu@quantatw.com>
diff --git a/cpld/lattice/interface.cpp b/cpld/lattice/interface.cpp
new file mode 100644
index 0000000..21663f0
--- /dev/null
+++ b/cpld/lattice/interface.cpp
@@ -0,0 +1,63 @@
+#include "interface.hpp"
+
+#include "lattice.hpp"
+
+#include <phosphor-logging/lg2.hpp>
+
+namespace phosphor::software::cpld
+{
+
+const std::vector<std::string> supportedTypes = {
+ "LatticeXO2Firmware",
+ "LatticeXO3Firmware",
+};
+
+sdbusplus::async::task<bool> LatticeCPLD::updateFirmware(
+ bool /*force*/, const uint8_t* image, size_t imageSize,
+ std::function<bool(int)> progressCallBack)
+{
+ lg2::info("Updating Lattice CPLD firmware");
+
+ std::replace(chipname.begin(), chipname.end(), '_', '-');
+ auto cpldManager = std::make_unique<CpldLatticeManager>(
+ ctx, bus, address, image, imageSize, chipname, "CFG0", false);
+
+ co_return co_await cpldManager->updateFirmware(progressCallBack);
+}
+
+sdbusplus::async::task<bool> LatticeCPLD::getVersion(std::string& version)
+{
+ lg2::info("Getting Lattice CPLD version");
+
+ std::replace(chipname.begin(), chipname.end(), '_', '-');
+ auto cpldManager = std::make_unique<CpldLatticeManager>(
+ ctx, bus, address, nullptr, 0, chipname, "CFG0", 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& type : supportedTypes)
+ {
+ CPLDFactory::instance().registerCPLD(
+ type,
+ [](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<LatticeCPLD>(ctx, chipname, bus,
+ address);
+ });
+ }
+ return true;
+}();
+
+} // namespace